def compile_target( self, context: CompilationBuffer) -> Tuple[Reference, CompilationBuffer]: assert isinstance(self.target, NamedAccess) target_buffer = context.optional( ) # This buffer holds a push down operation for the target instance if isinstance(self.target[0], CallSite): assert not self.stack_target inner_target = self.target[0].compile(target_buffer) target = context.resolve( NamedAccess([inner_target.type, self.target[1]], tokens=self.target)) else: target = context.resolve(self.target.root) for ext, _ in self.target.extensions: target = context.resolve( NamedAccess([target.type, ext], tokens=self.target)) if target.kind != Symbol.METHOD: raise TargetNotCallable() if not target.static and not self.constructing_call and not self.stack_target: self.target.compile(target_buffer, without_last=True) return target, target_buffer
def test_chained_call(): call = parse_local('counter.increment().add(10)') validate_types(call.arguments, [NumericValue]) assert call.target == NamedAccess([ MethodCall(NamedAccess([ Identifier('counter'), Identifier('increment') ])), Identifier('add') ])
def compile(self, context: CompilationBuffer): if not self.values: return buffer = context.optional() ref = self[0].compile(buffer) # TODO: remove unnecessary recompilation of first element (used to infer type) list_type = GenericIdentifier(Identifier('list'), (ref.type,)) last_call = MethodCall(NamedAccess([list_type, Identifier.constructor()])).deriving_from(self) for value in self: # TODO: validate list is homogeneous, and descend to lowest common type last_call = MethodCall(NamedAccess([last_call, Identifier("append")]), ArgumentList([value])).deriving_from(self) return last_call.compile(context)
def compile_arguments(self, context: CompilationBuffer, ref: ElementReference): argument_selector = ref.element.selector(context) compiled_arguments = [] for idx, arg in enumerate(self.arguments): buffer = context.optional() compiled_target = arg if self.stack_args and isinstance( arg, Reference) else arg.compile( buffer) # Deals with implicit casts argument_selector.constraint(compiled_target) compiled_arguments.append(CompiledArgument(compiled_target, buffer)) selected = argument_selector.disambiguate(self.source_ref) ref.element = selected.symbol for (compiled_target, buffer), expected_type in zip(compiled_arguments, selected.symbol.arguments or []): if not argument_selector.inheritance_match(expected_type, compiled_target): MethodCall(NamedAccess([compiled_target.type, CastTag(expected_type)]), stack_target=True, is_captured=True)\ .deriving_from(self)\ .compile(buffer) return ref, compiled_arguments
def entry(self) -> Reference: """ Get the index of the program's entry point """ return self.resolve( NamedAccess([Identifier('Program'), Identifier.constructor()]), {})
def compile(self, context): if self.redundant(context): return self.value.compile(context) return MethodCall(NamedAccess.extend(self.value, CastTag(self.target_type)), stack_args=self.stack_args, stack_target=self.stack_target).compile(context)
def compile( self, context: CompilationBuffer ): # TODO: we should probably reparse the maps into identifiers method_call = MethodCall( NamedAccess.extend(self.lhs, Identifier(self.operator.serialize())), [self.rhs]) return method_call.compile(context)
def __init__(self, target: Identifier, target_type: Identifier, collection: ValueType): super().__init__(None, (target, target_type, collection)) self.target, self.target_type, self.collection = target, target_type, collection self.iterator_id = next(IterationLoop.TRANSIENT_COUNTER) self.iterator = self.iterator_container_name[0] self.continuation_check = MethodCall( NamedAccess.extend(self.iterator, Identifier('has_next'))).deriving_from(self) self.continuation_next = MethodCall( NamedAccess.extend(self.iterator, Identifier('next'))).deriving_from(self) self.value = self.continuation_check if isinstance(self.collection, MethodCall): self.collection.is_captured = True
def compile(self, context: CompilationBuffer): iterator_name, iterator_type = self.iterator_container_name AssignmentOperation( AssignmentOperation.REASSIGNMENT, iterator_name, MethodCall(NamedAccess.extend(self.collection, Identifier('iterator')), is_captured=True).deriving_from(self), iterator_type, ).deriving_from(self).compile(context) super().compile(context)
def finalize(self): if not self.is_constructor(): return super().finalize() for descendant in self.descendants: if isinstance( descendant, MethodCall) and descendant.target[0] == Identifier.super(): descendant.replace( AssignmentOperation( AssignmentOperation.REASSIGNMENT, NamedAccess([Identifier.self(), Identifier.super()]), MethodCall(NamedAccess( [self.parent.extends, Identifier.constructor()]), descendant.arguments, is_captured=True).deriving_from( self)).deriving_from(descendant)) super().finalize()
def validate_method_call(node, target, argument_types): assert isinstance(node, MethodCall) assert node.target == NamedAccess([Identifier(t) for t in target]) validate_types(node.arguments, argument_types, MethodCall, lambda x: x.arguments)
def assignment(self, value): return MethodCall(NamedAccess.extend(self.target, Identifier('set')), ArgumentList([self.index, value]), is_captured=False) \ .deriving_from(self)
def compile(self, context: CompilationBuffer): return MethodCall(NamedAccess.extend(self.target, Identifier('get')), ArgumentList([self.index])) \ .deriving_from(self) \ .compile(context)
def parse_instantiating_call(target: Identifier, arguments: 'ParenthesesVector'): return MethodCall(NamedAccess.extend(target, Identifier.constructor()), ArgumentList(arguments))
def test_constructing_call(): method = parse_local('Empty(1)') assert method.target == NamedAccess([Identifier('Empty'), Identifier.constructor()]) validate_types(method.arguments, [NumericValue], MethodCall, lambda x: x.arguments) assert method.constructing_call
thing A does overloaded with Container1 container does overloaded with Container2 container does overloaded with Container2Child container does overloaded with Container1 c1, Container2 c2 does overloaded with Container1 c1, Container2Child c2 ''' # TODO: verify no cast to base type! # TODO: we probably don't want implicit casts to text SYMBOLS = get_symbols(SOURCE_OVERLOADING) CONTEXT = CompilationContext(SYMBOLS) BASE = SYMBOLS.resolve(NamedAccess.auto('A.overloaded')) def get_selection(*target_types): selector = BASE.element.selector(CONTEXT) for target_type in target_types: selector.constraint(Reference(Identifier(target_type))) return selector.disambiguate(None) def verify_selection(target_type, expected_index, expected_match): target = get_selection(*target_type) assert target.symbol.index == expected_index
def test_call_via_indexed_access(): call = parse_local('a_inst[1].me()') assert call.target == NamedAccess([ IndexedAccess(Identifier('a_inst'), NumericValue(1)), Identifier('me') ])