def __init__(self, succgen, query): self.succgen = succgen self.query = query self.query_type = None #Short-circuit, if no query: if query == "": self.isGoal = lambda s: False return #Parse query, and compile goal status query XXX self.query_type = query.strip()[:3] if self.query_type == "E<>": #form: E<> some_expression query = (query.strip()[3:]).strip() query_ast = expressionParser.parse_expression(query) self.goal_func_python = util.expression_to_python(query_ast, self.succgen) logger.info('Goal func: %s', self.goal_func_python) self.goal_expr = compile(self.goal_func_python, "<goal func>", 'eval') self.isGoal = self.isGoal_reachability elif self.query_type == "sup": #form: sup: some_expression self.sup_val = None query = (query.strip()[4:]).strip() query_ast = expressionParser.parse_expression(query) self.sup_expr_python = util.expression_to_python(query_ast, self.succgen) logger.info('sup expr.: %s', self.sup_expr_python) self.sup_expr = compile(self.sup_expr_python, "<goal func>", 'eval') self.isGoal = self.isGoal_sup else: raise IllegalQueryException( 'Sorry, only reachability ("E<>") and sup supported for now')
def bounds_for_type(self, someType): if someType.type == 'NodeTypedef': someType = someType.children[0] assert someType.type == 'TypeInt' #TODO other types lowerexpr = util.expression_to_python(someType.children[0].children[0]) upperexpr = util.expression_to_python(someType.children[1].children[0]) lower = eval(lowerexpr, {}, self.constants) upper = eval(upperexpr, {}, self.constants) return (lower, upper)
def parse_and_calculate_constants(self): self.lex = lexer.lexer try: self.pars = parser.Parser(self.nta.declaration, self.lex) except Exception: opaal.util.emergencyExitUppaalCParser( "Error in parsing the model to calculation constants.") self.declvisitor = parser.DeclVisitor(self.pars) self.declvisitor.visit(self.pars.AST) self.constants = {} #constant overrides for (cident, cval) in self.constant_overrides.iteritems(): #XXX assumes expression is already python self.constants[cident] = eval(cval, {}, self.constants) #evaluate constants to values for (cident, cval) in self.declvisitor.constants.iteritems(): if not cident in self.constants: self.constants[cident] = eval(util.expression_to_python(cval), {}, self.constants) try: #evaluate VarDecl expressions for vdecl in self.declvisitor.variables: util.eval_vardecl_expressions(vdecl, self.constants) except Exception: opaal.util.emergencyExitUppaalCParser( "Error in evaluating variable properties (e.g. array dimensions), for '%s'." % (vdecl.identifier))
def parse_and_calculate_constants(self): self.lex = lexer.lexer try: self.pars = parser.Parser(self.nta.declaration, self.lex) except Exception: opaal.util.emergencyExitUppaalCParser("Error parsing the model for calculating constants.") self.declvisitor = parser.DeclVisitor(self.pars) self.declvisitor.visit(self.pars.AST) self.constants = {} #constant overrides for (cident, cval) in self.constant_overrides.iteritems(): #XXX assumes expression is already python self.constants[cident] = eval(cval, {}, self.constants) #evaluate constants to values for (cident, cval) in self.declvisitor.constants.iteritems(): if not cident in self.constants: self.constants[cident] = eval(util.expression_to_python(cval), {}, self.constants)
def _lu_collect_comparisons(self, node, t_idx, l_idx, lower_eq_graph, upper_eq_graph): if node.type in ('Greater', 'GreaterEqual', 'Less', 'LessEqual', 'Equal', 'NotEqual'): idents = [n for n in node.children if n.type == 'Identifier'] clockside = None #is left side clock? if node.children[0].type == 'Identifier' and \ node.children[1].type != 'Identifier': clockident = node.children[0] exprnode = node.children[1] clockside = "left" #is right side clock? elif node.children[1].type == 'Identifier' and \ node.children[0].type != 'Identifier': clockident = node.children[1] exprnode = node.children[0] clockside = "right" if clockident.children[0] in self._clocks: assert False, "Clock on the right of comparison not supported (%s, %s)" % ( clockident, exprnode) else: #not a clock return True #comparing two clocks? elif node.children[0].type == 'Identifier' and \ node.children[1].type == 'Identifier': clockident1 = node.children[0] clockident2 = node.children[1] #comparing clocks do not affect the max constants if clockident1.children[ 0] in self._clocks and clockident2.children[ 0] in self._clocks: return True elif clockident1.children[0] in self._clocks: #left side clock, right side some expression clockident = clockident1 exprnode = node.children[1] clockside = "left" elif clockident2.children[0] in self._clocks: #right side clock, left side some expression clockident = clockident2 exprnode = node.children[0] clockside = "right" assert False, "Clock on the right of comparison not supported" else: #comparing two non-clocks return True else: #Some expression we don't know about logger.warning("Unknown expression: %s", node) return True if not clockident.children[0] in self._clocks: return True #try to calc expression, might be constant try: constant = eval(util.expression_to_python(exprnode), {}, self.constants) except: #variables in expression a = util.range_for_expression(exprnode, self.declvisitor, self.constants) constant = a[1] logger.debug(" found comparison of %s to %d", clockident.children[0], constant) # lower bound if node.type in ('Greater', 'GreaterEqual', 'Equal', 'NotEqual') and clockside == "left": lower_eq_graph[self._calc_index(t_idx, l_idx, clockident.children[0])][0] = \ max(constant, lower_eq_graph[self._calc_index(t_idx, l_idx, clockident.children[0])][0]) # upper bound -- not an elif! if node.type in ('Less', 'LessEqual', 'Equal', 'NotEqual') and clockside == "left": upper_eq_graph[self._calc_index(t_idx, l_idx, clockident.children[0])][0] = \ max(constant, upper_eq_graph[self._calc_index(t_idx, l_idx, clockident.children[0])][0]) return True
def expand_system_declaration(self): """Expand the model according to the system declaration: * For each automaton in the system create a unique template, converting parameters to local variables. * Promote local variables to uniquely named global vars. """ nta = self.nta ret = pyuppaal.NTA(declaration=nta.declaration) try: parser = systemdec_parser.SystemDeclarationParser(nta.system) res = parser.AST except Exception: opaal.util.emergencyExitSytemDecl("In the simplyfication phase a parsing error occurred when the system declaration in your model was being parsed.") #res.visit() # Instantiate process assignments for c in res.children: if c.type == 'ProcessAssignment': ident = c.leaf.children[0] tname = c.children[0].leaf.children[0] try: template = [t for t in nta.templates if t.name == tname][0] except IndexError: raise util.PyuppaalError("Template '%s' for instantiating '%s' not found!" % (tname, ident)) inst_parameters = c.children[0].children #XXX copy over logic for implicit instantiation below on when to inline and when to convert #(convert'ing will fail for e.g. train-gate because of mis-parsing the sync's) formal_parameters = [p.strip() for p in template.parameter.split(',')] formal_parameter_idents = [] for p in formal_parameters: if p: pident = p.split(' ')[-1] formal_parameter_idents += [pident] if len(inst_parameters) != len(formal_parameter_idents): raise util.PyuppaalError("Incorrect number of parameters for template '%s' for instantiating '%s'" % (tname, ident)) if len(inst_parameters) == 0: instantiated_template = copy.deepcopy(template) else: #make parameters local variables instantiated_template = copy.deepcopy(template) for (formal_param, pnode) in zip(formal_parameters, inst_parameters): instantiated_template.declaration = formal_param + " = " + \ str(eval(util.expression_to_python(pnode), {}, self.constants)) + ";\n" + \ instantiated_template.declaration instantiated_template.parameter = '' instantiated_template.name = ident #add to templates nta.templates += [instantiated_template] systemsnode = [c for c in res.children if c.type == 'System'][0] #systemsnode.visit() #print nta.templates retsystems = [] prevprio = -1 for inst in systemsnode.children: prio = inst.priority ident = inst.leaf tname = ident.children[0] temp = [t for t in nta.templates if t.name == tname][0] if prevprio == -1: #first process separator = "" else: separator = (prio != prevprio) and " < " or ", " prevprio = prio #case with no pars if temp.parameter.strip() == '': self.add_template_promote_local_vars(ret, temp) retsystems += [separator, temp.name] #case where we instantiate based on possible parameter values else: comb_temps = [copy.deepcopy(temp)] comb_temps[0].parameter = '' for par in [p.strip() for p in temp.parameter.split(',')]: par_parts = par.split(' ') if len(par_parts) == 2: (constness, typename, ident) = ("", par_parts[0], par_parts[1]) else: (constness, typename, ident) = par_parts someType = self.pars.getType(typename) lower, upper = self.bounds_for_type(someType.children[0]) new_temps = [] for oldtemp in comb_temps: for x in range(lower, upper+1): if constness: #inline const parameters new_temp = self.inline_var_in_temp(oldtemp, ident, x) new_temp.name += '_' + str(x) new_temps += [new_temp] else: #make variable parameters local vars new_temp = copy.deepcopy(oldtemp) new_temp.declaration = constness + " " + typename + " " + ident + " = " + str(x) + ";\n" + \ new_temp.declaration new_temp.name += '_' + str(x) new_temps += [new_temp] comb_temps = new_temps for temp in comb_temps: self.add_template_promote_local_vars(ret, temp) retsystems += [separator, temp.name] separator = ", " #TODO other cases ret.system = "system " + "".join(retsystems) + ";" self.nta = ret