visitUnaryExpr method

  1. @override
Object? visitUnaryExpr(
  1. UnaryExpr expr
)
override

Implementation

@override
Object? visitUnaryExpr(UnaryExpr expr) {
  final op = expr.prefix.type;
  final rhs = expr.rhs.accept(this);

  if (op == TokenType.kHash) {
    if (rhs is LuaObject) {
      final mm = rhs.readMetatable('__len')?.as<LuaObject>();

      final v = rhs.value;
      if (v is! String && mm != null) {
        return callLuaFunction(mm, args: [rhs]);
      }

      if (v is String) {
        return v.length;
      }

      if (rhs.isNotTable) {
        throw 'Length operator # used on a value.';
      }

      return rhs.tableSize;
    } else if (rhs == null) {
      throw 'Length operator # used on nil value.';
    }
    // else ...
    throw 'Length operator # used on type ${rhs.runtimeType}.';
  } else if (op == TokenType.kBitNot) {
    String type = rhs.runtimeType.toString();
    Object? v = rhs;
    if (rhs is LuaObject) {
      type = rhs.luaTypeInfo;

      if (rhs.isTable) {
        final mm = rhs.readMetatable('__bnot')?.as<LuaObject>();
        if (mm != null) {
          return callLuaFunction(mm, args: [rhs]);
        }
      } else {
        v = rhs.value;
      }
    }

    // ... else
    return switch (v) {
      final num n => ~n.toInt(),
      _ => throw 'Unsupported bitwise NOT on $type.',
    };
  } else if (op == TokenType.kSub) {
    String type = rhs.runtimeType.toString();
    Object? v = rhs;
    if (rhs is LuaObject) {
      type = rhs.luaTypeInfo;

      if (rhs.isTable) {
        final mm = rhs.readMetatable('__unm')?.as<LuaObject>();
        if (mm != null) {
          return callLuaFunction(mm, args: [rhs, rhs]);
        }
      } else {
        v = rhs.value;
      }
    }

    // ... else
    return switch (v) {
      final num n => -n,
      _ => throw 'Unsupported negation on $type.',
    };
  }

  throw 'Unsupported unary operator ${op.toString()}';
}