def function_statement(self, tree, scope): """ Create a new scope _without_ a parent scope for this function. Prepopulate the scope with symbols from the function arguments. """ scope = Scope.root() return_type = NoneType.instance() args = {} for c in tree.children[2:]: if isinstance(c, Tree) and c.data == "typed_argument": name = c.child(0) e_sym = self.resolver.types(c.types) c.expect( e_sym.type() != ObjectType.instance(), "arg_type_no_object", arg=name, type=e_sym.type(), ) sym = Symbol.from_path(name, e_sym.type()) scope.insert(sym) args[sym.name()] = sym # add function to the function table function_name = tree.child(1).value tree.expect( self.module.function_table.resolve(function_name) is None, "function_redeclaration", name=function_name, ) output = tree.function_output if output is not None: return_type = self.resolver.types(output.types).type() tree.expect(return_type != ObjectType.instance(), "return_type_no_object") self.module.function_table.insert(function_name, args, return_type) return scope, return_type
def service_block(self, tree, scope): service_name = tree.service.path.child(0).value name = scope.resolve(service_name) if name is not None and name.type() != ObjectType.instance(): tree.expect(tree.service.service_fragment.output is None, 'mutation_nested') tree.expect(tree.nested_block is None, 'mutation_nested') # resolve to perform checks self.resolver.service(tree.service) return tree.scope = Scope(parent=scope) self.update_scope(tree.scope) self.implicit_output(tree) output = tree.service.service_fragment.output if output is not None: output.expect(len(output.children) == 1, 'output_type_only_one', target='service') name = output.children[0] resolved = tree.scope.resolve(name) output.expect(resolved is None, 'output_unique', name=resolved.name() if resolved else None) sym = Symbol(name, ObjectType.instance()) tree.scope.insert(sym) if tree.nested_block: tree.expect(not self.in_service_block, 'nested_service_block') self.in_service_block = True for c in tree.nested_block.children: self.visit_children(c, scope=tree.scope) self.in_service_block = False
def service(self, tree): # unknown for now if tree.service_fragment.output is not None: tree.service_fragment.output.expect( 0, 'service_no_inline_output') command = tree.service_fragment.command tree.expect(command is not None, 'service_without_command') self.check_service_fragment_arguments(tree.service_fragment) t = None try: # check whether variable exists t = self.path(tree.path) except CompilerError: # ignore invalid variables (not existent or invalid) # -> must be a service return base_symbol(self.resolve_service(tree)) # variable exists -> event-based service if t.type() == ObjectType.instance(): # In case of event-based service resolve using output_sym. return base_symbol(self.resolve_service(tree, t)) var_name = tree.path.child(0).value tree.path.expect(0, 'service_name_not_var', var=var_name)
def base_type(self, tree): """ Resolves a base type expression to a type """ assert tree.data == 'base_type' tok = tree.first_child() if tok.type == 'BOOLEAN_TYPE': return base_symbol(BooleanType.instance()) elif tok.type == 'INT_TYPE': return base_symbol(IntType.instance()) elif tok.type == 'FLOAT_TYPE': return base_symbol(FloatType.instance()) elif tok.type == 'STRING_TYPE': return base_symbol(StringType.instance()) elif tok.type == 'ANY_TYPE': return base_symbol(AnyType.instance()) elif tok.type == 'OBJECT_TYPE': return base_symbol(ObjectType.instance()) elif tok.type == 'FUNCTION_TYPE': return base_symbol(AnyType.instance()) elif tok.type == 'TIME_TYPE': return base_symbol(TimeType.instance()) else: assert tok.type == 'REGEXP_TYPE' return base_symbol(RegExpType.instance())
def service_block(self, tree, scope): service_name = tree.service.path.child(0).value name = scope.resolve(service_name) if name is not None and name.type() != ObjectType.instance(): tree.expect(tree.service.service_fragment.output is None, 'mutation_nested') tree.expect(tree.nested_block is None, 'mutation_nested') # resolve to perform checks self.resolver.service(tree.service) return tree.scope = Scope(parent=scope) with self.create_scope(tree.scope): self.implicit_output(tree) output = tree.service.service_fragment.output if output is not None: self.check_output(tree, output, target='service') if tree.nested_block: tree.expect(not self.in_service_block, 'nested_service_block') self.in_service_block = True for c in tree.nested_block.children: self.visit_children(c, scope=tree.scope) self.in_service_block = False
def service_block(self, tree, scope): service_name = tree.service.path.child(0).value name = scope.resolve(service_name) if name is not None and name.type() != ObjectType.instance(): tree.expect(tree.service.service_fragment.output is None, 'mutation_nested') tree.expect(tree.nested_block is None, 'mutation_nested') # resolve to perform checks self.resolver.service(tree.service) return tree.scope = Scope(parent=scope) self.implicit_output(tree) output = tree.service.service_fragment.output if output is not None: self.check_output(tree, output, target='service') args = tree.service.service_fragment.arguments if args is not None: # only look at value nodes (argname, (2) expr, argname, (4) expr) for arg in args.children[1::2]: self.resolver.expression(arg) if tree.nested_block: with self.create_scope(tree.scope): tree.expect(not self.in_service_block, 'nested_service_block') self.in_service_block = True for c in tree.nested_block.children: self.visit_children(c, scope=tree.scope) self.in_service_block = False else: tree.service.service_fragment.expect(output is None, 'service_no_inline_output')
def resolve_mutation(self, t, tree): """ Resolve a mutation on t with the MutationTable, instantiate it and check the caller arguments. """ # a mutation on 'object' returns 'any' (for now) if t == ObjectType.instance(): return AnyType.instance() name = tree.mutation_fragment.child(0).value args = self.build_arguments(tree.mutation_fragment, name, fn_type='Mutation') # a mutation on 'any' returns 'any' overloads = self.mutation_table.resolve(t, name) tree.expect(overloads is not None, 'mutation_invalid_name', name=name) ms = overloads.match(args.keys()) if ms is None: # if there's only one overload, use this for a better error # message single = overloads.single() if single is None: self.show_available_mutation_overloads(tree, overloads) else: ms = [single] if len(ms) > 1: # a mutation on any might have matched multiple overloads return AnyType.instance() else: assert len(ms) == 1 m = ms[0] m = m.instantiate(t) m.check_call(tree.mutation_fragment, args) return m.output()
def when_block(self, tree, scope): tree.scope = Scope(parent=scope) with self.create_scope(tree.scope): self.implicit_output(tree) output = tree.service.service_fragment.output output.expect(len(output.children) == 1, 'output_type_only_one', target='when') name = output.children[0] resolved = tree.scope.resolve(name) output.expect(resolved is None, 'output_unique', name=resolved.name() if resolved else None) sym = Symbol.from_path(name, ObjectType.instance(), storage_class=StorageClass.read) tree.scope.insert(sym) tree.expect(not self.in_when_block, 'nested_when_block') self.in_when_block = True for c in tree.nested_block.children: self.visit_children(c, scope=tree.scope) self.in_when_block = False
def as_expression(self, tree, expr): assert tree.child(1).data == 'as_operator' # check for compatibility t = self.visitor.types(tree.child(1).types) tree.expect(t.type() != ObjectType.instance(), 'object_no_as') tree.expect(explicit_cast(expr.type(), t.type()), 'type_operation_cast_incompatible', left=expr.type(), right=t.type()) return t
def root(cls): """ Creates a root scope. """ scope = cls(parent=None) # insert global symbols app = Symbol(name='app', type_=ObjectType.instance()) scope.insert(app) return scope
def check_output(self, tree, output, target): output.expect(len(output.children) == 1, 'output_type_only_one', target=target) name = output.children[0] resolved = tree.scope.resolve(name) output.expect(resolved is None, 'output_unique', name=resolved.name() if resolved else None) sym = Symbol.from_path(name, ObjectType.instance(), storage_class=StorageClass.rebindable()) tree.scope.insert(sym)