Beispiel #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
Beispiel #2
0
 def from_method(
         method: "emitter.MethodSegment",
         program: "emitter.Program") -> "HeaderMethodRepresentation":
     entrypoint_id = util.nonnull(
         program.get_entrypoint()).id if program.has_entrypoint() else None
     return HeaderMethodRepresentation(
         method.signature.name, [
             HeaderMethodArgumentRepresentation.from_argument(arg, argtype)
             for arg, argtype in zip(method.signature.argnames,
                                     method.signature.args)
         ],
         method.signature.returntype.bytecode_name,
         method.signature.containing_class.name
         if method.signature.containing_class is not None else None,
         method.signature.containing_interface.name
         if method.signature.containing_interface is not None else None,
         is_ctor=method.signature.is_ctor,
         entrypoint=entrypoint_id == method.signature.id,
         is_override=method.signature.is_override,
         is_abstract=method.signature.is_abstract,
         type_params=[
             HeaderGenericParameterRepresentation.
             from_generic_type_parameter(argument)
             for argument in method.signature.generic_type_context.arguments
         ] if method.signature.generic_type_context is not None else [])
Beispiel #3
0
 def emit(self, segment: emitter.MetadataSegment) -> bytes:
     ret = SegmentEmitter.emit(self, segment)
     body = None
     if segment.has_entrypoint():
         body = encode_str(util.nonnull(segment.entrypoint).name)
     else:
         body = struct.pack("!I", 0)
     headers_serialized = json.dumps(segment.headers.serialize(), separators=(",", ":"))
     body += encode_str(headers_serialized)
     return ret + body
Beispiel #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
Beispiel #5
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."
            )