Esempio n. 1
0
 def resolve_to_signature(
     self, node: parser.Node, scope: "emitter.Scopes",
     generic_type_context: Optional[GenericTypeContext]
 ) -> "emitter.MethodSignature":
     if util.get_flattened(
             node
     ) is not None and self.program.get_method_signature_optional(
             util.nonnull(util.get_flattened(node))) is not None:
         return self.program.get_method_signature(
             util.nonnull(util.get_flattened(node)))
     if node.i("ident"):
         node.compile_error(
             "Attempt to call an identifier that doesn't resolve to a method"
         )
         # Unreachable
         return None  # type: ignore
     elif node.i("."):
         typ = self.decide_type(node[0], scope, generic_type_context)
         if not node[1].i("ident"):
             raise ValueError("This is a compiler bug")
         if not isinstance(typ, AbstractCallableType):
             node.compile_error(
                 "Attempt to call a member of something that isn't callable"
             )
         return typ.method_signature_strict(node[1].data_strict, node)
     else:
         node.compile_error(
             "Attempt to call something that can't be called")
         # Unreachable
         return None  # type: ignore
Esempio n. 2
0
 def resolve(self,
             node: parser.Node,
             generic_type_context: Optional[GenericTypeContext],
             fail_silent: bool = False,
             allow_raw: bool = False) -> Optional[AbstractType]:
     for typ in self.types:
         if typ.resolves(node, self.program):
             if not allow_raw and isinstance(
                     typ, ClazzType) and typ.signature.is_raw_type:
                 node.compile_error("Cannot use raw types directly")
             return typ
     if node.i("["):
         element_type = self.resolve(node[0],
                                     generic_type_context,
                                     fail_silent=fail_silent)
         if element_type is None:
             if not fail_silent:
                 # TypeSystem.resolve will never return None if fail_silent == True
                 raise ValueError("This is a compiler bug")
             return None
         return self.get_array_type(element_type)
     elif node.i("<>"):
         # We've got to create a new specialization of the class signature
         # because evidently the required one doesn't exist.
         generic_class_type = self.resolve(node[0],
                                           generic_type_context,
                                           fail_silent=fail_silent,
                                           allow_raw=True)
         if generic_class_type is None:
             # We know fail_silent == True
             return None
         if not isinstance(generic_class_type, ClazzType):
             # Yes, I really mean isinstance, not .is_class()
             node.compile_error(
                 "Cannot provide generic type arguments to a type that isn't a class"
             )
         type_arguments: List[AbstractType] = []
         for type_argument_node in node.children[1:]:
             argument = self.resolve(type_argument_node,
                                     generic_type_context,
                                     fail_silent=fail_silent)
             if argument is None:
                 # We know fail_silent == True
                 return None
             type_arguments.append(argument)
         return generic_class_type.specialize(type_arguments, node)
     if generic_type_context is not None:
         ret = generic_type_context.resolve_optional(node, self.program)
         if ret is not None:
             return ret
     if not fail_silent:
         raise TypingError(
             node, "Could not resolve type: '%s' ('%s')" %
             (node, util.get_flattened(node)))
     else:
         return None
Esempio n. 3
0
    def resolves(self, node: parser.Node, program: "emitter.Program") -> bool:
        def flatten_qualified(nod: parser.Node) -> str:
            if nod.i("ident"):
                return nod.data_strict
            else:
                return "%s.%s" % (flatten_qualified(
                    nod[0]), flatten_qualified(nod[1]))

        if not node.i("ident") and not node.i("."):
            return False

        name = flatten_qualified(node)

        for search_path in program.search_paths:
            if "%s%s" % (search_path, name) == self.name:
                return True
        return False
Esempio n. 4
0
 def resolves(self, node: parser.Node, program: "emitter.Program") -> bool:
     if node.i("ident") or node.i("."):
         return any([
             self.name == path + util.nonnull(util.get_flattened(node))
             for path in program.search_paths
         ])
     if self.signature.generic_type_context is None:
         return False
     if not node.i("<>"):
         return False
     if not any([
             self.name == path + util.nonnull(util.get_flattened(node[0]))
             for path in program.search_paths
     ]):
         return False
     for i in range(len(node) - 1):
         if not self.signature.generic_type_context.arguments[i].resolves(
                 node[i + 1], program):
             return False
     return True
Esempio n. 5
0
 def eval_expr(self, node: parser.Node) -> InterpreterValueAny:
     # TODO: Support referencing other static variables
     # Bitmask for 64-bit computation
     bitmask = 0xffffffffffffffff
     if node.i("number"):
         return self.create_int_value(int(node.data_strict))
     elif node.i("true"):
         return self.true
     elif node.i("false"):
         return self.false
     elif node.i("null"):
         return self.null
     elif node.of("+", "*", "^", "&", "|"):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueInteger) or not isinstance(
                 rhs, InterpreterValueInteger):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform arithmetic on something that isn't an integers"
             )
         if node.i("+"):
             ret = lhs.value + rhs.value
         elif node.i("*"):
             ret = lhs.value * rhs.value
         elif node.i("^"):
             ret = lhs.value ^ rhs.value
         elif node.i("&"):
             ret = lhs.value & rhs.value
         elif node.i("|"):
             ret = lhs.value | rhs.value
         return self.create_int_value(ret & bitmask)
     elif node.of("and", "or"):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueBoolean) or not isinstance(
                 rhs, InterpreterValueBoolean):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform logical operation on something that isn't an integers"
             )
         if node.i("and"):
             ret = lhs.value and rhs.value
         elif node.i("or"):
             ret = lhs.value or rhs.value
         return self.true if ret else self.false
     elif node.i("not"):
         val = self.eval_expr(node[0])
         if not isinstance(val, InterpreterValueBoolean):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform logical operation on something that isn't an integers"
             )
         return self.false if val.value else self.true
     elif node.of(">=", "<=", "<", ">"):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueInteger) or not isinstance(
                 rhs, InterpreterValueInteger):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform arithmetic on something that isn't an integers"
             )
         lhs_value = self.normalize_negative(lhs.value)
         rhs_value = self.normalize_negative(rhs.value)
         if node.i(">="):
             ret = lhs_value >= rhs_value
         elif node.i("<="):
             ret = lhs_value <= rhs_value
         elif node.i("<"):
             ret = lhs_value < rhs_value
         elif node.i(">"):
             ret = lhs_value > rhs_value
         else:
             raise ValueError("This is a compiler bug")
         return self.true if ret else self.false
     elif node.of("==", "!="):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not lhs.type.is_assignable_to(
                 rhs.type) and not rhs.type.is_assignable_to(lhs.type):
             raise typesys.TypingError(
                 node,
                 "Incomparable types: '%s' and '%s'" % (lhs.type, rhs.type))
         return self.true if lhs.equals(rhs) ^ (
             True if node.i("!=") else False) else self.false
     elif node.i("-") and len(node) == 2:
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueInteger) or not isinstance(
                 rhs, InterpreterValueInteger):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform arithmetic on something that isn't an integers"
             )
         return self.create_int_value((lhs.value - rhs.value) & bitmask)
     elif (node.i("-") and len(node) == 1) or node.i("~"):
         val = self.eval_expr(node[0])
         if not isinstance(val, InterpreterValueInteger):
             raise typesys.TypingError(
                 node, "Attempt to negate something that isn't an integer")
         return self.create_int_value(
             (-val.value if node.i("-") else ~val.value) & bitmask)
     elif node.i("/"):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueInteger) or not isinstance(
                 rhs, InterpreterValueInteger):
             raise typesys.TypingError(
                 node,
                 "Attempt to perform arithmetic on something that isn't an integers"
             )
         lhs_value = lhs.value
         rhs_value = rhs.value
         # Make sure, if our value is negative, we're dividing by a
         # negative rather than a very large value (due to two's
         # complement)
         lhs_value = self.normalize_negative(lhs_value)
         rhs_value = self.normalize_negative(rhs_value)
         res = lhs_value // rhs_value
         if res * rhs.value != lhs.value:
             # Python rounds toward negative infinity, whereas C
             # (and thus our language) rounds toward 0.
             if res < 0:
                 res += 1
         return self.create_int_value(res & bitmask)
     elif node.i("["):
         typ = self.program.types.decide_type(node, emitter.Scopes(), None)
         if not isinstance(typ, typesys.ArrayType):
             raise ValueError("This is a compiler bug.")
         # All of our typechecking has already been taken care of in
         # the logic in typesys there
         result_values: List[AbstractInterpreterValue] = []
         for child in node:
             result_values.append(self.eval_expr(child))
         return self.create_array_value(typ, result_values)
     elif node.i("arrinst"):
         typ = self.program.types.decide_type(node, emitter.Scopes(), None)
         if not isinstance(typ, typesys.ArrayType):
             raise ValueError("This is a compiler bug.")
         # Same thing, all of our typechecking is delegated to typesys
         array_len = self.eval_expr(node[1])
         if not isinstance(array_len, InterpreterValueInteger):
             raise typesys.TypingError(
                 node[1], "Type of array length must be an integer")
         if array_len.value > 1024:
             node.warn(
                 "Statically creating a very large array, this will make your bytecode file very large: %d"
                 % array_len.value)
         arrinst_result_values: List[AbstractInterpreterValue]
         if isinstance(typ.parent_type, typesys.IntType):
             arrinst_result_values = [self.create_int_value(0)
                                      ] * array_len.value
         elif isinstance(typ.parent_type, typesys.BoolType):
             arrinst_result_values = [self.false] * array_len.value
         else:
             arrinst_result_values = [self.null] * array_len.value
         return self.create_array_value(typ, arrinst_result_values)
     elif node.i("#"):
         val = self.eval_expr(node[0])
         if not isinstance(val, InterpreterValueArray):
             raise typesys.TypingError(
                 node[0],
                 "Cannot find length of something that isn't an array")
         return self.create_int_value(len(val.value))
     elif node.i("access"):
         lhs = self.eval_expr(node[0])
         rhs = self.eval_expr(node[1])
         if not isinstance(lhs, InterpreterValueArray):
             raise typesys.TypingError(
                 node[0],
                 "Can't access an element of something that isn't an array")
         if not isinstance(rhs, InterpreterValueInteger):
             raise typesys.TypingError(node[1],
                                       "Array indices must be integers")
         return lhs.value[rhs.value]
     else:
         node.compile_error("Cannot evaluate expression at compile-time")
Esempio n. 6
0
    def decide_type(
            self,
            expr: parser.Node,
            scope: "emitter.Scopes",
            generic_type_context: Optional[GenericTypeContext],
            suppress_coercing_void_warning: bool = False) -> AbstractType:
        if expr.i("as"):
            return self.resolve_strict(expr[1], generic_type_context)
        elif expr.i("instanceof"):
            return self.bool_type
        elif expr.of("+", "*", "-", "^", "&", "|", "%",
                     "/") and len(expr) == 2:
            lhs_type = self.decide_type(expr[0], scope, generic_type_context)
            rhs_type = self.decide_type(expr[1], scope, generic_type_context)
            if not lhs_type.is_numerical():
                raise TypingError(expr[0],
                                  "Type %s is not numerical" % lhs_type)

            if not rhs_type.is_numerical():
                raise TypingError(expr[1],
                                  "Type %s is not numerical" % rhs_type)

            if not lhs_type.is_assignable_from(
                    rhs_type) or not lhs_type.is_assignable_to(rhs_type):
                raise TypingError(
                    expr,
                    "Types %s and %s are incompatible for arithmetic operation"
                    % (lhs_type, rhs_type))

            return lhs_type
        elif expr.of(">=", "<=", ">", "<"):
            lhs_type = self.decide_type(expr[0], scope, generic_type_context)
            rhs_type = self.decide_type(expr[1], scope, generic_type_context)
            if not lhs_type.is_numerical():
                raise TypingError(expr[0],
                                  "Type %s is not numerical" % lhs_type)

            if not rhs_type.is_numerical():
                raise TypingError(expr[1],
                                  "Type %s is not numerical" % rhs_type)

            if not lhs_type.is_assignable_from(
                    rhs_type) or not lhs_type.is_assignable_to(rhs_type):
                raise TypingError(
                    expr,
                    "Types %s and %s are incompatible for arithmetic comparison"
                    % (lhs_type, rhs_type))

            return self.bool_type
        elif expr.of("==", "!="):
            lhs_type = self.decide_type(expr[0], scope, generic_type_context)
            rhs_type = self.decide_type(expr[1], scope, generic_type_context)
            if not lhs_type.is_assignable_to(
                    rhs_type) and not rhs_type.is_assignable_to(lhs_type):
                raise TypingError(
                    expr,
                    "Incomparable types: '%s' and '%s'" % (lhs_type, rhs_type))
            return self.bool_type
        elif expr.i("number"):
            return self.int_type
        elif expr.of("and", "or"):
            lhs_type = self.decide_type(expr[0], scope, generic_type_context)
            rhs_type = self.decide_type(expr[1], scope, generic_type_context)
            if not lhs_type.is_boolean():
                raise TypingError(expr[0], "Type %s is not boolean" % lhs_type)

            if not rhs_type.is_boolean():
                raise TypingError(expr[0], "Type %s is not boolean" % rhs_type)

            return self.bool_type
        elif expr.i("not"):
            type = self.decide_type(expr[0], scope, generic_type_context)
            if not type.is_boolean():
                raise TypingError(expr[0], "Type %s is not boolean" % type)
            return self.bool_type
        elif expr.of("~", "-") and len(expr) == 1:
            type = self.decide_type(expr[0], scope, generic_type_context)
            if not type.is_numerical():
                raise TypingError(expr[0], "Type %s is not numerical" % type)
            return self.int_type
        elif expr.of("ident", ".") \
                and util.get_flattened(expr) is not None \
                and self.program.static_variables.has_variable(util.nonnull(util.get_flattened(expr))):
            return self.program.static_variables.resolve_variable(
                util.nonnull(util.get_flattened(expr))).type
        elif expr.i("ident"):
            return scope.resolve(expr.data_strict, expr).type
        elif expr.of("true", "false"):
            return self.bool_type
        elif expr.i("null"):
            return self.void_type
        elif expr.i("["):
            # For now, everything must be the same type, except for nulls
            # interspersed. Later this will change.
            current_type = None
            if len(expr) == 0:
                expr.compile_error(
                    "Zero-length arrays must be instantiated with the arbitrary-length instantiation syntax"
                )
            for child in expr:
                current_child_type: AbstractType = self.decide_type(
                    child, scope, generic_type_context)
                if current_type is None:
                    if not current_child_type.is_void():
                        current_type = current_child_type
                    else:
                        continue

                # This is to make the typechecker happy
                # We know this is safe because of the previous if-statement
                current_type_not_none: AbstractType = current_type

                while current_type_not_none.get_supertype(
                ) is not None and not current_child_type.is_assignable_to(
                        current_type_not_none):
                    current_type = current_type_not_none.get_supertype()
                if not current_child_type.is_assignable_to(
                        current_type_not_none):
                    raise TypingError(
                        child,
                        "Could not reconcile type %s" % (current_child_type))

            if current_type is None:
                expr.compile_error(
                    "Cannot have an array literal comprising only null values, use arbitrary-length instantiation syntax instead"
                )
                # Unreachable
                return None  # type: ignore
            else:
                return self.get_array_type(current_type)
        elif expr.i("arrinst"):
            return self.get_array_type(
                self.resolve_strict(expr[0], generic_type_context))
        elif expr.i("#"):
            if not self.decide_type(expr[0], scope,
                                    generic_type_context).is_array():
                raise TypingError(
                    expr[0],
                    "Can't decide length of something that isn't an array")
            return self.int_type
        elif expr.i("access"):
            lhs_type = self.decide_type(expr[0], scope, generic_type_context)
            if not lhs_type.is_array():
                raise TypingError(
                    expr,
                    "Attempt to access element of something that isn't an array"
                )
            assert isinstance(lhs_type, ArrayType)
            return lhs_type.parent_type
        elif expr.i("call"):
            # TODO: Move method call typechecking in here from emitter.py.
            signature = self.resolve_to_signature(expr[0], scope,
                                                  generic_type_context)
            if len(expr["typeargs"]) != (
                    len(signature.generic_type_context.arguments)
                    if signature.generic_type_context is not None else 0):
                expr.compile_error(
                    "Wrong number of type arguments (expected %s, got %s)" %
                    (len(signature.generic_type_context.arguments)
                     if signature.generic_type_context is not None else 0,
                     len(expr["typeargs"])))
            signature = signature.specialize([
                self.resolve_strict(typ, generic_type_context)
                for typ in expr["typeargs"]
            ], self.program, expr["typeargs"])
            if signature is not None:
                if (not suppress_coercing_void_warning) and isinstance(
                        signature.returntype, VoidType):
                    expr.warn("Coercing void")
                return signature.returntype
            if expr[0].i("."):
                dot_node = expr[0]
                lhs_type = self.decide_type(dot_node[0], scope)
                if not lhs_type.is_clazz():
                    raise TypingError(
                        dot_node[1],
                        "Attempt to call a method on non-class type '%s'" %
                        lhs_type)
                signature = lhs_type.method_signature(dot_node[1].data)
            if signature is None:
                expr.compile_error("Unknown method name '%s'" % expr[0].data)
            if (not suppress_coercing_void_warning) and isinstance(
                    signature.returntype, VoidType):
                expr.warn("Coercing void")
            return signature.returntype
        elif expr.i("new"):
            ret = self.resolve_strict(expr[0],
                                      generic_type_context,
                                      allow_raw=True)
            # Why not .is_class()? Because we can't instantiate generic type parameters.
            if not isinstance(ret, ClazzType):
                raise TypingError(expr[0], "Type %s is not a class" % ret)
            type_arguments: List[AbstractType] = []
            for argument in expr["typeargs"]:
                type_arguments.append(
                    self.resolve_strict(argument, generic_type_context))
            ret = ret.specialize(type_arguments, expr)
            return ret
        elif expr.i("."):
            # Ternary operator to satisfy typechecker (if-else statement would effectively require phi node which is ugly)
            lhs_typ: AbstractType = \
                (scope.resolve(expr[0].data_strict, expr[0]).type) if expr[0].i("ident") \
                else self.decide_type(expr[0], scope, generic_type_context)
            if not lhs_typ.is_clazz():
                expr.compile_error(
                    "Attempt to access an attribute of something that isn't a class"
                )
            assert isinstance(lhs_typ, ClazzType)
            return lhs_typ.type_of_property(expr[1].data_strict, expr)
        elif expr.i("string"):
            string_type = self.get_string_type()
            if string_type is None:
                expr.compile_error(
                    "Cannot use string literal without an implementation of stdlib.String"
                )
            return string_type
        elif expr.i("super"):
            # TODO: This is horribly ugly
            typ = scope.resolve("this", expr).type
            if not isinstance(typ, ClazzType):
                expr.compile_error("Variable `this` isn't a class type")
            parent_type = typ.get_supertype()
            if parent_type is None:
                expr.compile_error(
                    "Attempt to reference superclass in a class without a superclass"
                )
            return parent_type
        else:
            raise ValueError(
                "Expression not accounted for in typesys. This is a compiler bug."
            )
Esempio n. 7
0
 def flatten_qualified(nod: parser.Node) -> str:
     if nod.i("ident"):
         return nod.data_strict
     else:
         return "%s.%s" % (flatten_qualified(
             nod[0]), flatten_qualified(nod[1]))
Esempio n. 8
0
 def resolves(self, node: parser.Node, program: "emitter.Program") -> bool:
     return node.i("[]") and self.parent_type.resolves(node[0], program)