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
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 [])
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
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
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." )