def test_StatementVisitor__visit_NodeCompileStmt__code_generation_1(): #IGNORE:C01111 #py.test.skip('Test StatementVisitor.visit_NodeCompileStmt') print 'Test StatementVisitor.visit_NodeCompileStmt:' from freeode.interpreter import (Interpreter, IFloat, SimlFunction) from freeode.ast import (DotName) prog_text = \ ''' class A: data b: Float func dynamic(this): b = 2 compile A ''' #create the interpreter intp = Interpreter() #run program intp.interpret_module_string(prog_text, None, 'test') #print intp.modules['test'] #print intp.get_compiled_objects()[0] #there must be one compiled object present assert len(intp.get_compiled_objects()) == 1 comp_obj = intp.get_compiled_objects()[0] #the attributes b and dynamic must exist assert isinstance(comp_obj.get_attribute(DotName('b')), IFloat) assert isinstance(comp_obj.get_attribute(DotName('dynamic')), SimlFunction) assert len(comp_obj.get_attribute(DotName('dynamic')).statements) == 1
def test_ProgramGenerator__create_program_2(): msg = \ ''' Test ProgramGenerator.create_program: Test program with additional initialization function. Load program as module and test init_*** function. ''' #skip_test(msg) print msg import os from freeode.pygenerator import ProgramGenerator from freeode.interpreter import Interpreter prog_text = \ ''' class A: data x: Float data b: Float param #This is the additional initialization function. func init_b(this, in_b): b = in_b #set parameter x = 0 #set initial value #10 func initialize(this): b = 0.1 #set parameter x = 0 #set initial value func dynamic(this): $x = b compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, 'foo.siml', '__main__') #create the output text pg = ProgramGenerator() pg.create_program('foo.siml', intp.get_compiled_objects()) #print pg.get_buffer() #write the buffer into a file, import the file as a module progname = 'testprog_ProgramGenerator__create_program_2' prog_text_file = open(progname + '.py','w') prog_text_file.write(pg.get_buffer()) prog_text_file.close() module = __import__(progname) #test the generated module A = module.A a = A() #call generated init_b(...) function a.init_b(42) assert a.param.b == 42 #clean up os.remove(progname + '.py') os.remove(progname + '.pyc')
def test_graph_function_1(): #IGNORE:C01111 #py.test.skip('Test the print function. - code generation for: user defined class.') print 'Test the print function. - code generation for: user defined class.' from freeode.interpreter import Interpreter from freeode.ast import DotName prog_text = \ ''' class A: data c: Float func final(this): graph(c) compile A ''' #create the interpreter intp = Interpreter() #run mini program intp.interpret_module_string(prog_text, None, 'test') # print # print 'module after interpreter run: ---------------------------------' # print intp.modules['test'] #get flattened object sim = intp.get_compiled_objects()[0] #print sim #get the final function with the generated code final = sim.get_attribute(DotName('final')) assert len(final.statements) == 1
def test_ProgramGenerator__create_program(): msg = ''' Test ProgramGenerator.create_program: Just see if function does not crash. ''' #py.test.skip(msg) print msg from freeode.pygenerator import ProgramGenerator from freeode.interpreter import Interpreter prog_text = \ ''' class A: data a: Float data b: Float param func initialize(this): b = 1 func dynamic(this): $a = b compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, 'foo.siml', '__main__') #create the output text pg = ProgramGenerator() pg.create_program('foo.siml', intp.get_compiled_objects()) print pg.get_buffer()
def test_ProgramGenerator__create_program_1(): msg = \ ''' Test ProgramGenerator.create_program: Test basic functions of the compiler. Loads generated program as module. ''' #skip_test(msg) print msg import os from freeode.pygenerator import ProgramGenerator from freeode.interpreter import Interpreter prog_text = \ ''' class A: data x: Float data b: Float param func initialize(this): x = 0 b = 1 solution_parameters(duration = 30, reporting_interval = 0.1) func dynamic(this): $x = b compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, 'foo.siml', '__main__') #create the output text pg = ProgramGenerator() pg.create_program('foo.siml', intp.get_compiled_objects()) #print pg.get_buffer() #write the buffer into a file, import the file as a module progname = 'testprog_ProgramGenerator__create_program_1' prog_text_file = open(progname + '.py','w') prog_text_file.write(pg.get_buffer()) prog_text_file.close() module = __import__(progname) #test the generated module A = module.A a = A() #call generated initialize(...) function a.initialize() assert a.param.b == 1 #solve (trivial) ODE and test solution a.simulateDynamic() x_vals = a.getResults()['x'] assert abs(x_vals[-1] - 30) < 1e-6 #clean up os.remove(progname + '.py') os.remove(progname + '.pyc')
def test_unknown_const_1(): #IGNORE:C01111 msg = '''Test correct treatment of unknown constants.''' py.test.skip(msg) print msg from freeode.optimizer import MakeDataFlowDecorations, DataFlowChecker from freeode.interpreter import (Interpreter, IFloat) from freeode.ast import DotName, NodeAssignment prog_text = \ ''' data c1: Float const class A: data a, b: Float data c2: Float const func dynamic(this): a = c1 b = c2 compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #get the flattened version of the A class sim = intp.get_compiled_objects()[0] #print sim #get attributes a = sim.get_attribute(DotName('a')) b = sim.get_attribute(DotName('b')) # c = sim.get_attribute(DotName('c1')) # c = sim.get_attribute(DotName('c2')) #get generated main function dyn = sim.get_attribute(DotName('dynamic')) hexid = lambda x: hex(id(x)) print 'a:', hexid(a), ' b:', hexid(b)#, ' c2:', hexid(c) #create the input and output decorations on each statement of the #function dd = MakeDataFlowDecorations() dd.decorate_simulation_object(sim) #check data flow of all functions fc = DataFlowChecker() fc.set_sim_object(sim) assert False, 'This program should raise an exceptions because unknown const attributes were used'
def test_interpreter_dollar_operator_2(): #IGNORE:C01111 msg = ''' Test "$" operator. Bug: $ operator did not work with attributes of user defined classes. Background: Class instantiation did not get parent refferences right. ''' #py.test.skip(msg) print msg from freeode.interpreter import Interpreter, CallableObject, IFloat from freeode.ast import DotName, RoleStateVariable, RoleTimeDifferential prog_text = \ ''' class A: data z: Float func dynamic(this): $z = z class B: data a: A func dynamic(this): a.dynamic() compile B ''' #create the interpreter intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #print intp.modules['test'] #print intp.get_compiled_objects()[0] #TODO: Assertions #get flattened object sim = intp.get_compiled_objects()[0] #get the attributes that we have defined az = sim.get_attribute(DotName('a.z')) az_dt = sim.get_attribute(DotName('a.z$time')) #implicitly defined by $ operator dynamic = sim.get_attribute(DotName('dynamic')) #test some facts about the attributes assert isinstance(az, IFloat) #a1 is state variable, because it assert az.role == RoleStateVariable #has derivative assert isinstance(az_dt, IFloat) assert az_dt.role == RoleTimeDifferential # $a1 is time differential assert isinstance(dynamic, CallableObject) #test if assignment really is 'a1$time' = 'a1' assign = dynamic.statements[0] assert assign.target is az_dt assert assign.expression is az
def test_function_return_value_roles_1(): #IGNORE:C01111 ''' User defined functions can be called from constant and from variable environments. Test the roles of their return values. This test only involves fundamental types. ''' #py.test.skip('Test roles of return values of user defined functions.') print 'Test roles of return values of user defined functions.' from freeode.interpreter import Interpreter from freeode.ast import (DotName, RoleConstant, RoleAlgebraicVariable) prog_text = \ ''' func plus2(x): data r: Float r = x + 2 return r data ac,bc: Float const ac = 3 bc = plus2(ac) class B: data av,bv: Float func dynamic(this): bv = plus2(av) compile B ''' #create the interpreter intp = Interpreter() #run mini program intp.interpret_module_string(prog_text, None, 'test') # print mod = intp.modules['test'] # print 'module after interpreter run: ---------------------------------' # print mod ac = mod.get_attribute(DotName('ac')) bc = mod.get_attribute(DotName('bc')) assert ac.role == RoleConstant assert bc.role == RoleConstant assert ac.value == 3 assert bc.value == 5 # #get flattened object sim = intp.get_compiled_objects()[0] # print 'Flattened object: ---------------------------------' # print sim av = sim.get_attribute(DotName('av')) bv = sim.get_attribute(DotName('bv')) assert av.role == RoleAlgebraicVariable assert bv.role == RoleAlgebraicVariable
def test_compile_statement_1(): #IGNORE:C01111 msg = ''' Test the compile statement - Flattening and storage of functions' local variables''' #py.test.skip(msg) print msg from freeode.interpreter import Interpreter, IFloat, CallableObject from freeode.ast import DotName prog_text = \ ''' class A: data a1: Float func foo(this, x): return x func dynamic(this): data b,c: Float b = foo(a1) c = foo(a1 + b) $a1 = b compile A ''' #create the interpreter intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #print intp.modules['test'] #print intp.get_compiled_objects()[0] #get flattened object sim = intp.get_compiled_objects()[0] #get the attributes that we have defined a1 = sim.get_attribute(DotName('a1')) a1_dt = sim.get_attribute(DotName('a1$time')) dynamic = sim.get_attribute(DotName('dynamic')) #test some facts about the attributes assert isinstance(a1, IFloat) assert isinstance(a1_dt, IFloat) assert isinstance(dynamic, CallableObject) #check number of attributes, most are automatically generated #attributes: initialize, dynamic, final, #instance variables: a1, $a1, #local variables: A.dynamic.b, A.dynamic.c, #intermediate result: A.foo.x, (2nd call) assert len(sim.attributes) == 8
def test_user_defined_class_roles_1(): #IGNORE:C01111 ''' The role keywords (const, param, variable, ...) should work with user defined classes too. ''' #py.test.skip('Test user defined classes with different roles.') print 'Test user defined classes with different roles.' from freeode.interpreter import Interpreter from freeode.ast import (DotName, RoleConstant, RoleAlgebraicVariable) prog_text = \ ''' class A: data a: Float #use the class as a constant data ac: A const ac.a = 2 class B: #use the class as a variable data av: A data v: Float func dynamic(this): av.a = v compile B ''' #create the interpreter intp = Interpreter() #run mini program intp.interpret_module_string(prog_text, None, 'test') # print mod = intp.modules['test'] # print 'module after interpreter run: ---------------------------------' # print mod ac = mod.get_attribute(DotName('ac')) a = ac.get_attribute(DotName('a')) assert a.role == RoleConstant # #get flattened object sim = intp.get_compiled_objects()[0] # print 'Flattened object: ---------------------------------' # print sim av_a = sim.get_attribute(DotName('av.a')) assert av_a.role == RoleAlgebraicVariable
def test_interpreter_expression_statement_1(): #IGNORE:C01111 ''' Unevaluated expressions also generate code. ''' #py.test.skip('Test expression statement - code generation.') print 'Test expression statement - code generation.' from freeode.interpreter import Interpreter, IFloat, CallableObject from freeode.ast import DotName, NodeExpressionStmt prog_text = \ ''' class A: data a,b: Float func dynamic(this): 1+2 a+b compile A ''' #create the interpreter and interpret the mini-program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #print intp.modules['test'] #print intp.get_compiled_objects()[0] #get flattened object sim = intp.get_compiled_objects()[0] #get the attributes that we have defined a = sim.get_attribute(DotName('a')) b = sim.get_attribute(DotName('b')) dynamic = sim.get_attribute(DotName('dynamic')) #test some facts about the attributes assert isinstance(a, IFloat) assert isinstance(b, IFloat) assert isinstance(dynamic, CallableObject) #only one statement is collected (a+b) assert len(dynamic.statements) == 1 stmt0 = dynamic.statements[0] assert isinstance(stmt0, NodeExpressionStmt) assert stmt0.expression.operator == '+'
def test_interpreter_dollar_operator_1(): #IGNORE:C01111 msg = 'Test "$" operator. Basic capabililities.' #py.test.skip(msg) print msg from freeode.interpreter import Interpreter, IFloat, CallableObject from freeode.ast import DotName, RoleStateVariable, RoleTimeDifferential prog_text = \ ''' class A: data a1: Float func dynamic(this): $a1 = a1 compile A ''' #create the interpreter intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #print intp.modules['test'] #print intp.get_compiled_objects()[0] #get flattened object sim = intp.get_compiled_objects()[0] #get the attributes that we have defined a1 = sim.get_attribute(DotName('a1')) a1_dt = sim.get_attribute(DotName('a1$time')) #implicitly defined by $ operator dynamic = sim.get_attribute(DotName('dynamic')) #test some facts about the attributes assert isinstance(a1, IFloat) #a1 is state variable, because it assert a1.role == RoleStateVariable #has derivative assert isinstance(a1_dt, IFloat) assert a1_dt.role == RoleTimeDifferential # $a1 is a time differential assert isinstance(dynamic, CallableObject) #test if assignment really is 'a1$time' = 'a1' assign = dynamic.statements[0] assert assign.target is a1_dt assert assign.expression is a1
def test_SimulationClassGenerator__create_sim_class_1(): msg = ''' Test SimulationClassGenerator.create_sim_class: Just see if function does not crash. ''' #py.test.skip(msg) print msg import cStringIO from freeode.pygenerator import SimulationClassGenerator from freeode.interpreter import Interpreter #from freeode.simulatorbase import SimulatorBase prog_text = \ ''' class A: data a:Float data b: Float data c: Float param func initialize(this): a = 1 c = 2 print(a) func dynamic(this): b = c $a = b * sin(a) func final(this): graph(a) compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, 'foo.siml', '__main__') flat_o = intp.get_compiled_objects()[0] #create the Python class definition as text buf = cStringIO.StringIO() cg = SimulationClassGenerator(buf) cg.create_sim_class('A', flat_o) cls_txt = buf.getvalue() print cls_txt
def test_print_function_4(): #IGNORE:C01111 #py.test.skip('Test the print function. - code generation for: user defined class.') print 'Test the print function. - code generation for: user defined class.' from freeode.interpreter import Interpreter from freeode.ast import DotName prog_text = \ ''' #print user defined class class C: data a: Float data b: String func __str__(this): return a.__str__() + ' and ' + b.__str__() #return ' and ' + b.__str__() class A: data c: C func dynamic(this): print(c) compile A ''' #create the interpreter intp = Interpreter() #run mini program intp.interpret_module_string(prog_text, None, 'test') # print # print 'module after interpreter run: ---------------------------------' # print intp.modules['test'] #get flattened object sim = intp.get_compiled_objects()[0] #print sim #get the dynamic function with the generated code dynamic = sim.get_attribute(DotName('dynamic')) assert len(dynamic.statements) == 1
def test_print_function_3(): #IGNORE:C01111 #py.test.skip('Test the print function. - code generation for: Float, String') print 'Test the print function. - code generation for: Float, String' from freeode.interpreter import Interpreter from freeode.ast import DotName prog_text = \ ''' class A: data a,b,foo: Float data bar: String func dynamic(this): #print known constants print(23) print('hello ',2, ' the world!') #print unknown value print(foo) print(bar) #print unevaluated expression print(a+b) compile A ''' #create the interpreter intp = Interpreter() #run mini program intp.interpret_module_string(prog_text, None, 'test') # print # print 'module after interpreter run: ---------------------------------' # print intp.modules['test'] #get flattened object sim = intp.get_compiled_objects()[0] #print sim #get the dynamic function with the generated code dynamic = sim.get_attribute(DotName('dynamic')) assert len(dynamic.statements) == 5
def test_MakeDataFlowDecorations_1(): #IGNORE:C01111 msg = '''Test the creation of data flow annotations.''' #py.test.skip(msg) print msg from freeode.optimizer import MakeDataFlowDecorations from freeode.interpreter import (Interpreter, IFloat) from freeode.ast import DotName, NodeAssignment prog_text = \ ''' class A: data p1,p2: Float param data a,b,c,d: Float func dynamic(this): a = p1 b = a - p2 if a > p1: c = p1 d = p1 else: c = p2 d = p2 compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #get the flattened version of the A class sim = intp.get_compiled_objects()[0] #print sim #get attributes a = sim.get_attribute(DotName('a')) b = sim.get_attribute(DotName('b')) c = sim.get_attribute(DotName('c')) d = sim.get_attribute(DotName('d')) p1 = sim.get_attribute(DotName('p1')) p2 = sim.get_attribute(DotName('p2')) #get generated main function dyn = sim.get_attribute(DotName('dynamic')) #print object ids in hex (for easier manual testing) hexid = lambda x: hex(id(x)) print 'a:', hexid(a), ' b:', hexid(b), ' c:', hexid(c), ' d:', hexid(d), \ ' p1:', hexid(p1), ' p2:', hexid(p2) #------- the test ------------------- #create the input and output decorations on each statement of the #function dd = MakeDataFlowDecorations() dd.decorate_simulation_object(sim) #dd.decorate_main_function(dyn) #see if the inputs and outputs were detected correctly # a = p1 stmt = dyn.statements[0] assert stmt.inputs == set([p1]) assert stmt.outputs == set([a]) # b = a - p2 stmt = dyn.statements[1] assert stmt.inputs == set([a, p2]) assert stmt.outputs == set([b]) #'if' statement stmt = dyn.statements[2] #look at inputs assert stmt.inputs.issuperset(set([a, p1, p2])) #there is an additional constant IFloat(1) in the condition of the else one_set = stmt.inputs - set([a, p1, p2]) assert len(one_set) == 1 one_obj = one_set.pop() assert one_obj == IFloat(1) #look at outputs assert stmt.outputs == set([c, d]) #the dynamic function assert dyn.inputs == set([p1, p2, one_obj]) assert dyn.outputs == set([a, b, c, d])
def test_ProgramGenerator__all_variables_visible(): msg = \ ''' Tests if all variables are visible in all main functions. Especially tests for existence an correct treatment of the variable 'time'. Runs the generated program as an external program. References: Fixed bug #598632 https://bugs.launchpad.net/freeode/+bug/598632 Blueprint: https://blueprints.launchpad.net/freeode/+spec/final-main-function-specification ''' #skip_test(msg) print msg import os from subprocess import Popen, PIPE from freeode.pygenerator import ProgramGenerator from freeode.interpreter import Interpreter prog_text = \ ''' class A: data x: Float data b: Float param func initialize(this): x = 0 b = 1 solution_parameters(duration = 30, reporting_interval = 0.1) print("initial-values: ", b, x, $x, time) func dynamic(this): $x = b if abs(x - time) > 1e-6: print('dynamic-error: x = ', x, ', time = ', time) else: pass func final(this): print("final-values: ", b, x, $x, time) compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, '--no-file-name--', '__main__') #create the output text pg = ProgramGenerator() pg.create_program('foo.siml', intp.get_compiled_objects()) #print pg.get_buffer() #write the buffer into a file progname = 'prog_test_ProgramGenerator__all_variables_visible' prog_text_file = open(progname + '.py','w') prog_text_file.write(pg.get_buffer()) prog_text_file.close() #run the generated program sim = Popen('python ' + progname + '.py', shell=True, stdout=PIPE) res_txt, _ = sim.communicate() # print 'Program output: \n', res_txt # print 'Return code: ', sim.returncode #the program must say that it terminated successfully assert sim.returncode == 0 #TODO: do the following with search_result_lines #Scan the program's output to check if it's working. init_vals, final_vals = [], [] dyn_error = False for line in res_txt.split('\n'): if line.startswith('initial-values:'): vals = line.split()[1:] init_vals = map(float, vals) elif line.startswith('final-values:'): vals = line.split()[1:] final_vals = map(float, vals) elif line.startswith('dynamic-error:'): dyn_error = True #Test if the values that the program returns are correct b, x, d_x, time = init_vals assert b == 1 and x == 0 and d_x == 0 and time == 0 b, x, d_x, time = final_vals assert b == 1 and x == 30 and d_x == 0 and time == 30 assert dyn_error == False, 'Error in dynamic function detected' #clean up os.remove(progname + '.py')
def test_interpreter_user_defined_operators_1(): #IGNORE:C01111 ''' User defined operators must be converted into multiple statements, that contain only operations on fundamental types. Intermediate results are kept in function local variables, that are stored by the compile statement. The used Siml class simulates a geometric vector class. ''' #py.test.skip('Test user defined operators - code generation.') print 'Test user defined operators - code generation.' from freeode.interpreter import Interpreter, IFloat, CallableObject from freeode.ast import DotName prog_text = \ ''' class Vec1D: data x: Float role_unknown func __add__(this, other): data res: Vec1D res.x = x + other.x return res func __assign__(this, other): x = other.x class A: data a,b,c: Vec1D func dynamic(this): #--- invoke the operators ---- c=a+b compile A ''' #create the interpreter and interpret the mini-program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #print intp.modules['test'] #print intp.get_compiled_objects()[0] #get flattened object sim = intp.get_compiled_objects()[0] #get the attributes that we have defined a_x = sim.get_attribute(DotName('a.x')) b_x = sim.get_attribute(DotName('b.x')) c_x = sim.get_attribute(DotName('c.x')) dynamic = sim.get_attribute(DotName('dynamic')) #test some facts about the attributes assert isinstance(a_x, IFloat) assert isinstance(b_x, IFloat) assert isinstance(c_x, IFloat) assert isinstance(dynamic, CallableObject) assert len(dynamic.statements) == 2 stmt0 = dynamic.statements[0] stmt1 = dynamic.statements[1] #first statement (res.x = 2*(x + other.x)) assigns to function local variable assert stmt0.target not in [a_x, b_x, c_x] assert stmt0.expression.operator == '+' #second statement (c=a+b) assigns to c.x assert stmt1.target is c_x #second statement assigns temporary result of previous computation to attribute c.x assert stmt0.target is stmt1.expression
def test_VariableUsageChecker_1(): #IGNORE:C01111 msg = '''Test checking of variable usage. Provoke all errors at least once.''' #skip_test(msg) print msg from freeode.optimizer import MakeDataFlowDecorations, VariableUsageChecker from freeode.interpreter import Interpreter from freeode.util import DotName, UserException#, aa_make_tree prog_text = \ ''' class A: data p1,p2: Float param data a,b,c: Float #illegal read of parameter p1 func init_1(this): p2 = p1 a = 0 #illegal write to derivative $a func init_2(this): $a = 1 p1 = 1 p2 = 1 a = 0 #Missing assignment to parameter p1 func init_3(this): p2 = 1 a = 0 #illegal write to state variable a func dynamic(this): a = 2 $a = p1 b = a - p2 c = p1 #illegal write to state variable a func final(this): a = 2 b = 1 print(a, b, p1) compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #get the flattened version of the A class sim = intp.get_compiled_objects()[0] #aa_make_tree(sim) #create the input and output decorations on each statement of the #function dd = MakeDataFlowDecorations() dd.decorate_simulation_object(sim) #Find all input and output variables vu = VariableUsageChecker() vu.set_annotated_sim_object(sim) #illegal read of parameter p1 initialize = vu.main_funcs[DotName('init_1')] #vu.check_initialize_function(initialize) assert_raises(UserException, 4500100, vu.check_initialize_function, initialize) #illegal write to derivative $a initialize = vu.main_funcs[DotName('init_2')] #vu.check_initialize_function(initialize) assert_raises(UserException, 4500200, vu.check_initialize_function, initialize) #Missing assignment to parameter p1 initialize = vu.main_funcs[DotName('init_3')] #vu.check_initialize_function(initialize) assert_raises(UserException, 4500300, vu.check_initialize_function, initialize) #illegal write to state variable a dynamic = vu.main_funcs[DotName('dynamic')] #vu.check_dynamic_function(dynamic) assert_raises(UserException, 4500200, vu.check_dynamic_function, dynamic) #illegal write to state variable a final = vu.main_funcs[DotName('final')] #vu.check_final_function(final) assert_raises(UserException, 4500200, vu.check_final_function, final)
def test_VariableUsageChecker_1(): #IGNORE:C01111 msg = '''Test checking of variable usage. Simple program with no errors. Use individual checking functions. These are the rules: Constants (rules enforced in the interpreter): - All constants must be known. - No assignments to constants. Parameters: - All must be assigned in all init**** function. - No assignment to parameters elsewhere. Variables: - All derivatives must be assigned in dynamic function. - No states must be assigned in dynamic function. - All states must be assigned initial values in init*** function. ''' #skip_test(msg) print msg from freeode.optimizer import MakeDataFlowDecorations, VariableUsageChecker from freeode.interpreter import Interpreter from freeode.util import DotName#, aa_make_tree prog_text = \ ''' class A: data p1,p2: Float param data a,b,c: Float func init_1(this, ext1, ext2): ext2 = 1 #not useful but legal for simplicity p1 = ext1 p2 = 1 a = 0 func initialize(this): p1 = 1 p2 = 1 a = 0 print(time) data lo: Float lo = p1 func dynamic(this): $a = p1 b = a - p2 if a > p1: c = p1 else: c = p2 data lo: Float variable lo = p1 func final(this): b = 1 print(a, b, p1) data lo: Float variable lo = p1 compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #get the flattened version of the A class sim = intp.get_compiled_objects()[0] #print aa_make_tree(sim) #print aa_make_tree(sim.func_locals) #create the input and output decorations on each statement of the #function dd = MakeDataFlowDecorations() dd.decorate_simulation_object(sim) #Find all input and output variables vu = VariableUsageChecker() vu.set_annotated_sim_object(sim) #Check the usage of the variables init_1 = vu.main_funcs[DotName('init_1')] vu.check_initialize_function(init_1) initialize = vu.main_funcs[DotName('initialize')] vu.check_initialize_function(initialize) dynamic = vu.main_funcs[DotName('dynamic')] vu.check_dynamic_function(dynamic) final = vu.main_funcs[DotName('final')] vu.check_final_function(final)
def test_pass_statement_1(): #IGNORE:C01111 msg = ''' Test the pass statement. Try the normal use case. - The pass statement does nothing it is necessary to create empty functions and classes. ''' #py.test.skip(msg) print msg from freeode.interpreter import (Interpreter, siml_isinstance, CallableObject, TypeObject, IFloat) from freeode.ast import DotName prog_text = \ ''' #empty class body class Dummy: pass data d: Dummy const #empty function body func f_dummy(): pass f_dummy() #call class with pass statement in compiled code class A: data x: Float data d: Dummy func foo(this): pass func dynamic(this): foo() $x = 1 compile A ''' #create the interpreter intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') print #test the module a bit mod = intp.modules['test'] #print mod class_Dummy = mod.get_attribute(DotName('Dummy')) d = mod.get_attribute(DotName('d')) f_dummy = mod.get_attribute(DotName('f_dummy')) class_A = mod.get_attribute(DotName('A')) assert siml_isinstance(d, class_Dummy) assert isinstance(f_dummy, CallableObject) assert isinstance(class_A, TypeObject) #Test the compiled object flat_A = intp.get_compiled_objects()[0] #print flat_A x = flat_A.get_attribute(DotName('x')) x_time = flat_A.get_attribute(DotName('x$time')) assert isinstance(x, IFloat) assert isinstance(x_time, IFloat) assert len(flat_A.attributes) == 5
def test_check_simulation_objects_1(): #IGNORE:C01111 msg = '''Test checking of variable usage. Simple program with no errors. Use high level checking function. ''' #skip_test(msg) print msg from freeode.optimizer import check_simulation_objects from freeode.interpreter import Interpreter # from freeode.util import aa_make_tree prog_text = \ ''' class A: data p1,p2: Float param data a,b,c: Float func init_1(this, ext1, ext2): ext2 = 1 #not useful but legal for simplicity p1 = ext1 p2 = 1 a = 0 func initialize(this): p1 = 1 p2 = 1 a = 0 data lo: Float lo = p1 func dynamic(this): $a = p1 b = a - p2 if a > p1: c = p1 else: c = p2 data lo: Float variable lo = p1 func final(this): b = 1 print(a, b, p1) data lo: Float variable lo = p1 compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #do the checks check_simulation_objects(intp.get_compiled_objects())
def test_ProgramGenerator__create_program_3(): msg = \ ''' Test ProgramGenerator.create_program: Test most common language features. ''' #py.test.skip(msg) print msg import os from freeode.pygenerator import ProgramGenerator from freeode.interpreter import Interpreter prog_text = \ ''' class A: data x: Float data a, b, c, d, e: Float param func initialize(this): a = 2 * (3 + 4) # = 14, test brackets b = a**0 / 0.1 % 9 - -a/a # = 2, arithmetic operators #if statement should reduce to single assignment if -2**-3 == -(2 ** (-3)): # tricky operator precedence c = 1 # c = 1 else: c = 0 #if statement, comparison and logical operators if (a != 1 and not a == 1 or a == 1) and (a < 1 or a > 1): d = 1 # d = 1 e = sin(d * 3.1415) # close to 0 #test function call else: d = 0 e = sin(d * 3.1415) # = 0 #test function call x = 0 #set initial value func dynamic(this): $x = b compile A ''' #interpret the compile time code intp = Interpreter() intp.interpret_module_string(prog_text, 'foo.siml', '__main__') #create the output text pg = ProgramGenerator() pg.create_program('foo.siml', intp.get_compiled_objects()) print pg.get_buffer() #write the buffer into a file, import the file as a module #progname must be unique! otherwise race condition! progname = 'testprog_ProgramGenerator__create_program_3' prog_text_file = open(progname + '.py','w') prog_text_file.write(pg.get_buffer()) prog_text_file.close() module = __import__(progname) #test the generated module A = module.A a = A() #call generated init_b(...) function a.initialize() assert a.param.a == 14 assert a.param.b == 2 assert a.param.c == 1 assert a.param.d == 1 assert abs(a.param.e) < 0.001 #close to 0 #clean up os.remove(progname + '.py')
def test_MakeDataFlowDecorations_1(): #IGNORE:C01111 msg = '''Test the creation of data flow annotations.''' #skip_test(msg) print msg from freeode.optimizer import MakeDataFlowDecorations from freeode.interpreter import Interpreter, IFloat #from freeode.ast import NodeAssignment from freeode.util import DotName prog_text = \ ''' class A: data p1,p2: Float param data a,b,c,d: Float #5 func dynamic(this): a = p1 b = a - p2 if a > p1: c = p1 #10 d = p1 else: c = p2 d = p2 print(a) compile A ''' #interpret the program intp = Interpreter() intp.interpret_module_string(prog_text, None, 'test') #the module #mod = intp.modules['test'] #print mod #get the flattened version of the A class sim = intp.get_compiled_objects()[0] #print sim #get attributes a = sim.get_attribute(DotName('a')) b = sim.get_attribute(DotName('b')) c = sim.get_attribute(DotName('c')) d = sim.get_attribute(DotName('d')) p1 = sim.get_attribute(DotName('p1')) p2 = sim.get_attribute(DotName('p2')) #get generated main function dyn = sim.get_attribute(DotName('dynamic')) #print object ids in hex (for easier manual testing) hexid = lambda x: hex(id(x)) print 'a:', hexid(a), ' b:', hexid(b), ' c:', hexid(c), ' d:', hexid(d), \ ' p1:', hexid(p1), ' p2:', hexid(p2) #------- the test ------------------- #create the input and output decorations on each statement of the #function dd = MakeDataFlowDecorations() dd.decorate_simulation_object(sim) #dd.decorate_main_function(dyn) #see if the inputs and outputs were detected correctly # a = p1-------------------------------------- stmt0 = dyn.statements[0] assert stmt0.inputs == set([p1]) assert stmt0.outputs == set([a]) # b = a - p2 -------------------------------- stmt1 = dyn.statements[1] assert stmt1.inputs == set([a, p2]) assert stmt1.outputs == set([b]) #'if' statement ------------------------------ stmt2 = dyn.statements[2] #look at inputs assert stmt2.inputs.issuperset(set([a, p1, p2])) #there is an additional constant IFloat(1) in the condition of the else one_set = stmt2.inputs - set([a, p1, p2]) assert len(one_set) == 1 one_obj = one_set.pop() assert one_obj == IFloat(1) #look at outputs assert stmt2.outputs == set([c, d]) #print(a) ------------------------------------- stmt3 = dyn.statements[3] assert stmt3.inputs == set([a]) assert stmt3.outputs == set() #the dynamic function as a whole -------------- assert dyn.inputs == set([p1, p2, one_obj]) assert dyn.outputs == set([a, b, c, d]) #The input_locs, output_locs mappings for creating error messages #Parameter p1 assert p1 not in dyn.output_locs #p1 is written nowhere p1_in_locs = dyn.input_locs[p1] assert len(p1_in_locs) == 4 #p1 read in 4 places assert p1_in_locs[0].line_no() == stmt0.loc.line_no() #read in statement 0 assert p1_in_locs[1].line_no() == stmt2.loc.line_no() #read in 'if' statement # + read in two lines in body of 'if' statement # for loc in p1_in_locs: # print loc #Variable a a_out_loc = dyn.output_locs[a] assert len(a_out_loc) == 1 #a written in 1 place assert a_out_loc[0].line_no() == stmt0.loc.line_no() #written in statement 0 a_in_loc = dyn.input_locs[a] assert len(a_in_loc) == 3 #a read in 3 places assert a_in_loc[0].line_no() == stmt1.loc.line_no() assert a_in_loc[1].line_no() == stmt2.loc.line_no() assert a_in_loc[2].line_no() == stmt3.loc.line_no()