def test_source(self): """ Make sure that the given source file is parsed and emitted correctly. To do this, we parse & emit two times. The first and second emission, should be exactly the same. """ input = open(file).read() output1 = api.load(input).accept(Dumper()) output2 = api.load(output1).accept(Dumper()) if output1 != output2: for line in unified_diff(output1.split("\n"), output2.split("\n")): print_stderr(line) assert False, "Roundtripping of " + file + "failed."
def test_property_as_obj_for_method_call(self): src = """module test function t1(node) { node.queue.remove() }""" model = api.load(src) self.assertEqual(model.accept(Dumper()), src)
def after_visit_Parameter(self, parameter): if not isinstance(parameter.type, UnknownType): return parents = list(reversed(self.stack)) function = parents[1] env = parents[2] if isinstance(env, Module): # case 2: it's a global function declaration, but with a reference # from the first case, so we try to convert the environment # to an ExecutionStrategy for execution in env.executions: func = execution.executed if isinstance(func, FunctionExp) and func.name == function.name: env = execution break else: # case 3: it's a global function and is referenced from another # function. Here we have no reference to use to infer the type. This # will be handled by the calling side, who will infer its argument types # upon these parameters pass # we reached this point so we found an env that can tell us the signature # of our function if isinstance(env, ExecutionStrategy): # case 1: function declaration for exection in an ExecutionStrategy => # it's a handler and we should be able to match the function's # signature to that of the scope of the strategy # An ExecutionStrategy can have an event (When) or not (Every) # An event is a FunctionExp executed within the Scope. if isinstance(env, When): func = env.scope.get_function(env.event.name) else: func = env.scope.get_function() type = None try: # try to extract the param information for the same indexed parameter index = function.parameters.index(parameter) type = func.parameters[index].type except: pass if not type is None: self.success( "Found ExecutionStrategy with Scope providing info. " + "Inferring parameter", parameter.name, "to", type.accept(Dumper())) parameter.type = type else: self.fail("Couldn't extract parameter typing info from " + \ "ExecutionStrategy environment for parameter", parameter.name)
def after_visit_ListLiteralExp(self, lst): if not isinstance(lst.type, ManyType): return if not isinstance(lst.type.subtype, UnknownType): return # determine the best matching type of the expressions in the list type = UnknownType() has_atoms = False for exp in lst.expressions: # no AtomType, it is converted to different other types on need-to basis if isinstance(exp.type, AtomType): has_atoms = True continue # init on first non-UnknownType if isinstance(type, UnknownType): type = exp.type next # make sure that all types are compatible with detected type # when we're dealing with ManyType, look into subtype if isinstance(type, ManyType): type_class = type.subtype.__class__.__name__ next_class = type.subtype.__class__.__name__ else: type_class = type.__class__.__name__ next_class = exp.type.__class__.__name__ # if we're already dealing with bytes, we can always convert to byte if type_class == "ByteType": continue # otherwise: lower the type restrictions if next_class == "ByteType": type = exp.type continue # if there the same, obviously if type_class == next_class: continue # self.fail("Couldn't determine best matching type for ListLiteral.", # "Ended up with", type_class, "and", next_class) # TODO: undo this short-cut someday ;-) # we can't easily come to a single type to deal with this, and further on # during code generation we will handle these situations differently # anyway, so let's mark it as MixedType for now type = MixedType() break if has_atoms and isinstance(type, UnknownType): type = AtomType() # type is best matching type for all expressions in ListLiteral # apply it to the subtype of the ListLiteral's ManyType lst.type.subtype = type self.success( "Inferred type of ListLiteral from list's expressions' types.", "Inferred type to", lst.type.accept(Dumper()))
def after_visit_Constant(self, constant): """ Infers the type of the constant if it is unknown. """ if isinstance(constant.type, UnknownType): try: new_type = { 'IntegerLiteralExp': IntegerType, 'FloatLiteralExp': FloatType, 'BooleanLiteralExp': BooleanType }[constant.value.__class__.__name__] self.success("unknown constant type for", constant.name, \ "inferred to", new_type().accept(Dumper())) constant.type = new_type() except KeyError: self.fail("Failed to infer constant type based on value of " + \ constant.name)
def after_visit_VariableExp(self, variable): # original : self._type = UnknownType() # we need to move up the stack to find the declaration and reuse that; # variables can be declared in FunctionDecl, might be a Constant, or as # part of an assignment, then we can also reuse the type of the value part # of the assignment # simplest case, it's in the environment if variable.name in self.env: variable.type = self.env[variable.name].type self.success("VariableExp referenced the environment.", variable.name, "Inferred type to", variable.type) # the type might be Unknown, but inference below should fix this if not isinstance(variable.type, UnknownType): # we might have got type information, but maybe it's incomplete if isinstance(variable.type, ObjectType): if variable.type.provides.values() == []: # we don't do typedefs (yet), be we have domains that export custom # object-types, let's see if OUR module's domain exports it # TODO: add utility functions/properties for this to SemanticChecker # e.g: self.my_module().domains for domain in self.stack[1].domains: try: variable.type = domain.get_type( variable.type.name) self.success( "Retrieved missing type information from domain", domain.name, variable.type.name) return except: pass self.fail( "Couldn't retrieve custom object-type info from domain", variable.type.name) return parents = list(reversed(self.stack)) # TODO: too specific (for contains) AND wrong !! :-( # special case: if the VarExp is part of a ListLiteral as argument to # FuncCallExp that is part of a CaseStmt, it takes the subtype of the # Manytype that the Provided method carries. if isinstance(parents[1], ListLiteralExp) and \ isinstance(parents[2], FunctionCallExp) and \ isinstance(parents[3], CaseStmt): variable.type = parents[3].expression.type.provides[ parents[2].name].parameters[0].type.subtype self.success("VariableExp ", variable.name, "is a VariableDecl for data of type", variable.type.accept(Dumper())) return # a VarExp in a consequences Stmt of a CaseStmt can look for a same-name # VarExp in the corresponding cases FunctionCallExp of the CaseStmt for index in range(0, len(parents)): if isinstance(parents[index], CaseStmt): case = parents[index] consequence = parents[index - 1] consequence_index = case.consequences.index(consequence) functioncall = case.cases[consequence_index] for argument in functioncall.arguments: if isinstance( argument, VariableExp) and argument.name == variable.name: self.success("Found CaseFuncCall with decl for", variable.name, "Inferring to", str(parameter.type)) variable.type = parameter.type return if isinstance(argument, ListLiteralExp): for item in argument.expressions: if isinstance(item, VariableExp ) and item.name == variable.name: self.success( "Found CaseFuncCall in list with decl for", variable.name, "Inferring to", str(item.type)) variable.type = item.type return
def dump_foo(args, model=None): if model is None: model = load(args) if args.verbose: print "foo: generating FOO" print model.accept(Dumper())
# expressions.py # author: Christophe VG # unit tests for foo-lang expressions import unittest from foo_lang.semantic.model import * from foo_lang.semantic.dumper import Dumper dumper = Dumper() def dump(model): return model.accept(dumper) class TestExpressions(unittest.TestCase): def test_and_exp(self): exp = AndExp(BooleanLiteralExp("true"), BooleanLiteralExp("false")) self.assertEqual(dump(exp), "( true and false )") def test_or_exp(self): exp = OrExp(BooleanLiteralExp("true"), BooleanLiteralExp("false")) self.assertEqual(dump(exp), "( true or false )") def test_eq_exp(self): exp = EqualsExp(BooleanLiteralExp("true"), BooleanLiteralExp("false")) self.assertEqual(dump(exp), "( true == false )") def test_ne_exp(self):