def __init__( self, params=[], eqc=lambda w, p: 0, name="", pNames="", jac=[], constraints=[]): """Constructor for a CircuitTree node params: a list of numerical values eqc: frequency dependent equivalent circuit function name: name of the element pNames: names of the elements' parameters jac: elements jacobian vector of parameters """ Node.__init__(self) self.p = params self.eqc = eqc self.name = name self.pNames = pNames self.jac = jac self.constraints = constraints
def verify_valid_arguments(self, node: parser.Node) -> None: for i in range(self.num_params): if not self.context.arguments[i].is_satisfied_by( self.parameters[i]): node.compile_error( "Could not reify generic method: '%s' does not satisfy '%s'" % (self.parameters[i], self.context.arguments[i]))
def setup_class(self): # Constants self.int_node_one = Node(vtype=v.INTEGER_VALUE, syn_value=1) self.int_node_two = Node(vtype=v.INTEGER_VALUE, syn_value=2) self.int_node_three = Node(vtype=v.INTEGER_VALUE, syn_value=3) # Variables self.x = Node(vtype=v.IDENTIFIER, symbol='x') self.y = Node(vtype=v.IDENTIFIER, symbol='y') self.z = Node(vtype=v.IDENTIFIER, symbol='z') # z = x + y self.int_node_add = Node(vtype=v.ADD, children=(self.x, self.y)) self.assignment_node = Node(vtype=v.ASSIGNMENT, children=[self.z, self.int_node_add]) # return z self.z_statement = Node(vtype=v.STATEMENT, children=[self.z,]) self.return_node = Node(vtype=v.RETURN_STATEMENT, syn_value=self.z_statement) # Functions self.sum_function = Function(return_type=v.INTEGER_VALUE, symbol='sum', parameter_pairs=((self.x, v.INTEGER_VALUE), (self.y, v.INTEGER_VALUE)), statements=[self.assignment_node]) self.sum_with_return_function = Function(return_type=v.INTEGER_VALUE, symbol='sum_with_return', parameter_pairs=((self.x, v.INTEGER_VALUE), (self.y, v.INTEGER_VALUE)), statements=[self.assignment_node, self.return_node, ])
def test_assignment(self): x_node = Node(vtype=v.IDENTIFIER, symbol='x') val_node = self.int_node_two assignment_node = Node(vtype=v.ASSIGNMENT, children=[x_node, val_node]) backend.walk_ast(assignment_node) symbol_record = backend.scopes[-1][x_node.symbol] eq_(symbol_record, val_node)
def method_signature_strict( self, name: str, node: parser.Node) -> "emitter.MethodSignature": ret = self.method_signature_optional(name) if ret is None: node.compile_error("Invalid member method name '%s'" % name) assert ret is not None return ret
def test_boolean_op_or(self): node = Node(vtype=v.OR, children=[self.int_node_zero, self.int_node_neg_one]) backend.walk_ast(node) eq_(node.syn_value, True) node = Node(vtype=v.OR, children=[self.int_node_zero, self.int_node_zero]) backend.walk_ast(node) eq_(node.syn_value, False)
def test_boolean_op_not(self): node = Node(vtype=v.NOT, children=[self.int_node_zero]) backend.walk_ast(node) eq_(node.syn_value, True) node = Node(vtype=v.NOT, children=[self.string_node_empty]) backend.walk_ast(node) eq_(node.syn_value, True) node = Node(vtype=v.NOT, children=[self.float_node_neg_one]) backend.walk_ast(node) eq_(node.syn_value, False)
def resolve_interface_strict( self, node: parser.Node, generic_type_context: Optional[GenericTypeContext], allow_raw: bool = False) -> InterfaceType: ret = self.resolve_strict(node, generic_type_context, allow_raw=allow_raw) if not isinstance(ret, InterfaceType): node.compile_error( "Type resolves to %s where an interface was expected" % ret) return ret
def resolve_to_signature( self, node: parser.Node, scope: "emitter.Scopes", generic_type_context: Optional[GenericTypeContext] ) -> "emitter.MethodSignature": if util.get_flattened( node ) is not None and self.program.get_method_signature_optional( util.nonnull(util.get_flattened(node))) is not None: return self.program.get_method_signature( util.nonnull(util.get_flattened(node))) if node.i("ident"): node.compile_error( "Attempt to call an identifier that doesn't resolve to a method" ) # Unreachable return None # type: ignore elif node.i("."): typ = self.decide_type(node[0], scope, generic_type_context) if not node[1].i("ident"): raise ValueError("This is a compiler bug") if not isinstance(typ, AbstractCallableType): node.compile_error( "Attempt to call a member of something that isn't callable" ) return typ.method_signature_strict(node[1].data_strict, node) else: node.compile_error( "Attempt to call something that can't be called") # Unreachable return None # type: ignore
def setup_class(self): # Constants self.int_node_one = Node(vtype=v.INTEGER_VALUE, syn_value=1) self.int_node_two = Node(vtype=v.INTEGER_VALUE, syn_value=2) self.int_node_three = Node(vtype=v.INTEGER_VALUE, syn_value=3) # Variables self.x = Node(vtype=v.IDENTIFIER, symbol='x') self.y = Node(vtype=v.IDENTIFIER, symbol='y') self.z = Node(vtype=v.IDENTIFIER, symbol='z') # z = x + y self.int_node_add = Node(vtype=v.ADD, children=(self.x, self.y)) self.assignment_node = Node(vtype=v.ASSIGNMENT, children=[self.z, self.int_node_add]) # Functions self.sum_function = Function(return_type=v.INTEGER_VALUE, parameter_pairs=((self.x, v.INTEGER_VALUE), (self.y, v.INTEGER_VALUE)), expressions=[ self.assignment_node, ])
def test_scopeless_add(self): scopeless_add_node = Node(vtype=v.ADD, children=(self.int_node_one, self.int_node_two)) scopeless_add_function = Function(return_type=v.INTEGER_VALUE, symbol="add", parameter_pairs=(), statements=[scopeless_add_node,]) scopeless_add_function.execute()
def test_int_add(self): int_node_add = Node(vtype=v.ADD, children=[self.int_node_one, self.int_node_two]) backend.walk_ast(int_node_add) eq_(int_node_add.syn_value, 3) int_node_neg_two = Node( vtype=v.ADD, children=[self.int_node_neg_one, self.int_node_neg_one]) int_node_neg_four = Node(vtype=v.ADD, children=[int_node_neg_two, int_node_neg_two]) int_node_four = Node(vtype=v.ADD, children=[self.int_node_two, self.int_node_two]) int_node_result = Node(vtype=v.ADD, children=[int_node_four, int_node_neg_four]) backend.walk_ast(int_node_result) eq_(int_node_result.syn_value, 0)
def resolves(self, node: parser.Node, program: "emitter.Program") -> bool: def flatten_qualified(nod: parser.Node) -> str: if nod.i("ident"): return nod.data_strict else: return "%s.%s" % (flatten_qualified( nod[0]), flatten_qualified(nod[1])) if not node.i("ident") and not node.i("."): return False name = flatten_qualified(node) for search_path in program.search_paths: if "%s%s" % (search_path, name) == self.name: return True return False
def node(name): """ >>> document() Node(name='document', attrs={}, elems=[]) >>> document('a', 'b', 'c') Node(name='document', attrs={}, elems=['a', 'b', 'c']) """ return lambda *elems: Node(name, elems=list(elems))
def parse(self): # print(self.text_box.get()) scanner(self.text_box.get()) lst_tokens = tokenizer(file='output.txt') init_node = Node() parser = Parser(lst_tokens) parser.parents.append(init_node.index) parser.program() parser.draw_tree()
def add_type_argument_from_node(self, node: parser.Node) -> None: extends: Optional[ClazzType] = None if node.has_child("extends"): extends_uncasted = self.types.resolve_strict( node["extends"][0], self) if not isinstance(extends_uncasted, ClazzType): node["extends"].compile_error( "Cannot add an extends constraint of something that isn't a class" ) extends = extends_uncasted implements: List[InterfaceType] = [] if node.has_child("implements"): for interface in node["implements"]: resolved_type = self.types.resolve_strict(interface, self) if not isinstance(resolved_type, InterfaceType): interface.compile_error( "Cannot add an implements constraint of something that isn't a class" ) implements.append(resolved_type) self.add_type_argument(node["ident"].data_strict, extends, implements)
def resolves(self, node: parser.Node, program: "emitter.Program") -> bool: if node.i("ident") or node.i("."): return any([ self.name == path + util.nonnull(util.get_flattened(node)) for path in program.search_paths ]) if self.signature.generic_type_context is None: return False if not node.i("<>"): return False if not any([ self.name == path + util.nonnull(util.get_flattened(node[0])) for path in program.search_paths ]): return False for i in range(len(node) - 1): if not self.signature.generic_type_context.arguments[i].resolves( node[i + 1], program): return False return True
def resolve(self, node: parser.Node, generic_type_context: Optional[GenericTypeContext], fail_silent: bool = False, allow_raw: bool = False) -> Optional[AbstractType]: for typ in self.types: if typ.resolves(node, self.program): if not allow_raw and isinstance( typ, ClazzType) and typ.signature.is_raw_type: node.compile_error("Cannot use raw types directly") return typ if node.i("["): element_type = self.resolve(node[0], generic_type_context, fail_silent=fail_silent) if element_type is None: if not fail_silent: # TypeSystem.resolve will never return None if fail_silent == True raise ValueError("This is a compiler bug") return None return self.get_array_type(element_type) elif node.i("<>"): # We've got to create a new specialization of the class signature # because evidently the required one doesn't exist. generic_class_type = self.resolve(node[0], generic_type_context, fail_silent=fail_silent, allow_raw=True) if generic_class_type is None: # We know fail_silent == True return None if not isinstance(generic_class_type, ClazzType): # Yes, I really mean isinstance, not .is_class() node.compile_error( "Cannot provide generic type arguments to a type that isn't a class" ) type_arguments: List[AbstractType] = [] for type_argument_node in node.children[1:]: argument = self.resolve(type_argument_node, generic_type_context, fail_silent=fail_silent) if argument is None: # We know fail_silent == True return None type_arguments.append(argument) return generic_class_type.specialize(type_arguments, node) if generic_type_context is not None: ret = generic_type_context.resolve_optional(node, self.program) if ret is not None: return ret if not fail_silent: raise TypingError( node, "Could not resolve type: '%s' ('%s')" % (node, util.get_flattened(node))) else: return None
def get_targets(self): """Return a disctionary representing the access request of the query. :return: A dictionary of the table-column pairs the query accesses. """ def _back_to_common_state(root, node): if not root: return node node.state.cols.extend(root.state.cols) node.state.tables.extend(root.state.tables) for child in root.childs: _back_to_common_state(child, node) return node node = _back_to_common_state(self.root, Node()) known_tables = {table.normalized for table in node.state.tables} return to_dict(node, known_tables)
def complete(self, prefix): """ Try to complete a given prefix """ self._log.debug("complete: '%s'" % prefix) #proposals = [LaTeXTemplateProposal(Template("Hello[${One}][${Two}][${Three}]"), "Hello[Some]"), LaTeXProposal("\\world")] fragment = Node(Node.DOCUMENT) parser = PrefixParser() try: parser.parse(prefix, fragment) modelParser = PrefixModelParser(self._language_model) proposals = modelParser.parse(fragment) self._log.debug("Generated %s proposals" % len(proposals)) return proposals except Exception, e: self._log.debug(e)
def parse(self, s = None, row = 1, col = 1): def updatePos(s, row, col): rows = s.count("\n") if rows: row += rows col = len(s[s.rfind("\n") + 1:]) else: col += len(s) return row, col assert self.startDelimiter assert self.endDelimiter assert self.startBlock assert self.altBlock assert self.endBlock assert self.startBlock != self.endBlock block = Node("tblock") blocks = [] while s: #print("s = %r" %s) start = s.find(self.startDelimiter) if start < 0: break end = s.find(self.endDelimiter, start + len(self.startDelimiter)) if end < 0: break if start > 0: row, col = updatePos(s[:start], row, col) block.children.append(Node("tstring", s[:start])) start += len(self.startDelimiter) expr = s[start:end] end += len(self.endDelimiter) if self.replaceCharRefs: for find, repl in { ">": ">", "<": "<" }.items(): expr = expr.replace(find, repl) #print("expr = %r %d %d" % (expr, row, col)) if expr.startswith(self.startBlock): row, col = updatePos(self.startDelimiter, row, col) expr = expr[len(self.startBlock):] try: node = super(Template, self).parse(expr) except ParseException as e: raise ParseException(row + e.row - 1, col + e.col - 1, e.expecting) blocks.append((node, block, None)) block = Node("tblock") elif expr.startswith(self.altBlock): if not blocks: raise ParseException(row, col, "Alternative block without opening block") node, nblock, ablock = blocks[-1] if ablock: raise ParseException(row, col, "Multiple alternative blocks are not allowed") blocks[-1] = (node, nblock, block) row, col = updatePos(self.startDelimiter + expr, row, col) block = Node("tblock") elif expr.startswith(self.endBlock): if not blocks: raise ParseException(row, col, "Closing block without opening block") row, col = updatePos(self.startDelimiter + expr, row, col) node, nblock, ablock = blocks.pop() if ablock: nblock.children.append(Node("tloop", children=[node, ablock, block])) else: nblock.children.append(Node("tloop", children=[node, block, None])) block = nblock else: row, col = updatePos(self.startDelimiter, row, col) try: node = super(Template, self).parse(expr) except ParseException as e: raise ParseException(row + e.row - 1, col + e.col - 1, e.expecting) row, col = updatePos(expr, row, col) block.children.append(node) row, col = updatePos(self.endDelimiter, row, col) s = s[end:] if blocks: raise ParseException(row, col, "%d blocks are still open, expecting %s" % (len(blocks), "".join([("%s%s%s" % (self.startDelimiter, self.endBlock, self.endDelimiter)) for b in blocks]))) if s: block.children.append(Node("tstring", s)) self.ast = block
def test_defaults(self): assert Node('') == Node('', {}, [])
def flatten_qualified(nod: parser.Node) -> str: if nod.i("ident"): return nod.data_strict else: return "%s.%s" % (flatten_qualified( nod[0]), flatten_qualified(nod[1]))
def resolves(self, node: parser.Node, program: "emitter.Program") -> bool: return node.i("[]") and self.parent_type.resolves(node[0], program)
def constructUVWRecurse(node,uvw): """Recursive build function for the LTL->UVW translation. Returns a pair of UVW set of starting states and an "EXIT" condition in BDD form. The latter can be None if this is undefined. """ # Cache lookup thisNodePolish = node.toPolishLTL() if thisNodePolish in uvw.labelToStateAndActivatingMapper: return uvw.labelToStateAndActivatingMapper[thisNodePolish] # Case Missing: F(a & F b) # 1. See if this is non-temporal nt = parseNonTemporalSubformula(node,uvw) if not nt is None: if nt!=uvw.ddMgr.false: newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),node) uvw.transitions.append([(0,~nt)]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],nt) return ([newStateNo],nt) else: uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([0],nt) return ([0],nt) # 2. Cover the "Globally something case" -> Phi if node.value == NodeTypes.GLOBALLY: assert len(node.children)==1 (uvwSubnodes,exitCondition) = constructUVWRecurse(node.children[0],uvw) newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),False) uvw.transitions.append([(a,b) for k in uvwSubnodes for (a,b) in uvw.transitions[k]]+[(newStateNo,uvw.ddMgr.true)]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],None) return ([newStateNo],None) # 3. Cover the "Next something case" -> Phi if node.value == NodeTypes.NEXT: assert len(node.children)==1 (uvwSubnodes,exitCondition) = constructUVWRecurse(node.children[0],uvw) newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),False) uvw.transitions.append([(a,uvw.ddMgr.true) for a in uvwSubnodes]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],None) return ([newStateNo],None) # 4. Cover the "And" case -- not atomic --> Phi if node.value == NodeTypes.AND: newStates = reduce(lambda x,y: (x[0]+y[0],x[1]), [constructUVWRecurse(a,uvw) for a in node.children])[0] uvw.labelToStateAndActivatingMapper[thisNodePolish] = (newStates,None) return (newStates,None) # 4. Cover the "Or" case -- could be Phi or Psi if node.value == NodeTypes.OR: # Operate pairwise if len(node.children)==1: return constructUVWRecurse(node.children[0],uvw) (initialA,filterA) = constructUVWRecurse(node.children[0],uvw) if len(node.children)==2: (initialB,filterB) = constructUVWRecurse(node.children[1],uvw) else: (initialB,filterB) = constructUVWRecurse(Node(NodeTypes.OR,node.children[1:]),uvw) # Product -- Init todo = [(a,b) for a in initialA for b in initialB] mapper = {} for (a,b) in todo: mapper[(a,b)] = uvw.addStateButNotNewListOfTransitionsForTheNewState("|| "+uvw.stateNames[a]+" "+uvw.stateNames[b],uvw.rejecting[a] and uvw.rejecting[b]) # Product -- iterate through todo list. while len(todo)>0: thisOne = todo[0] todo = todo[1:] # Go through all products outTrans = [] for (targetA,condA) in uvw.transitions[thisOne[0]]: for (targetB,condB) in uvw.transitions[thisOne[1]]: if (condA & condB)!=uvw.ddMgr.false: if not (targetA,targetB) in mapper: mapper[(targetA,targetB)] = uvw.addStateButNotNewListOfTransitionsForTheNewState("|| "+uvw.stateNames[targetA]+" "+uvw.stateNames[targetB],uvw.rejecting[targetA] and uvw.rejecting[targetB]) todo.append((targetA,targetB)) outTrans.append((mapper[(targetA,targetB)],condA & condB)) uvw.transitions.append(outTrans) # Done! if (filterA is None) or (filterB is None): uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([mapper[(a,b)] for a in initialA for b in initialB],None) return ([mapper[(a,b)] for a in initialA for b in initialB],None) else: uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([mapper[(a,b)] for a in initialA for b in initialB],filterA | filterB) return ([mapper[(a,b)] for a in initialA for b in initialB],filterA | filterB) # 5. Finally if node.value == NodeTypes.FINALLY: (subnodes,activator) = constructUVWRecurse(node.children[0],uvw) newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),True) uvw.transitions.append([(newStateNo,~activator)]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],activator) return ([newStateNo],activator) # 5. Until if node.value == NodeTypes.UNTIL: (rightPartNodes,rightPartActivator) = constructUVWRecurse(node.children[1],uvw) (leftPartNodes,leftPartActivator) = constructUVWRecurse(Node(NodeTypes.OR,[node.children[0],node.children[1]]),uvw) if not rightPartActivator is None: # Could be a "Maidl's grammar extension" newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),True) uvw.transitions.append([(newStateNo,~rightPartActivator)]+[(a,b) for k in leftPartNodes for (a,b) in uvw.transitions[k]]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],rightPartActivator) return ([newStateNo],rightPartActivator) # 5. Release if node.value == NodeTypes.RELEASE: # In a release node, when the release happens, the guarded condition still needs to hold. (leftPartNodes,leftPartActivator) = constructUVWRecurse(node.children[0],uvw) (leftPartNodes,doesnotMatter) = constructUVWRecurse(node.children[1],uvw) # (leftPartNodes,leftPartActivatorIgnored) = constructUVWRecurse(Node(NodeTypes.AND,[node.children[0],node.children[1]]),uvw) # TODO: Check if we can just use the leftPartNodesa (rightPartNodes,rightPartActivator) = constructUVWRecurse(Node(NodeTypes.OR,[node.children[0],node.children[1]]),uvw) assert not leftPartActivator is None newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),False) uvw.transitions.append([(newStateNo,~leftPartActivator)]+[(a,b) for k in rightPartNodes for (a,b) in uvw.transitions[k]]+[(a,b & leftPartActivator) for k in leftPartNodes for (a,b) in uvw.transitions[k]]) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],leftPartActivator) return ([newStateNo],leftPartActivator) # 6. Cover Maidl's (p & Phi) U (!p & Phi) case if node.value == NodeTypes.UNTIL: # Restructure childrenA if node.children[0].value == NodeTypes.AND: allChildrenA = [constructUVWRecurse(a,uvw) for a in node.children[0].children] else: allChildrenA = [constructUVWRecurse(node.children[0],uvw)] if node.children[1].value == NodeTypes.AND: # Let's see if we can use Maidl's case allChildrenB = [constructUVWRecurse(a,uvw) for a in node.children[1].children] # Merge into the relevant cases nonTemporalA = None nonTemporalB = None failed = False # If matching has failed activA = uvw.ddMgr.true activB = uvw.ddMgr.true # Handle Children A for (uvwSubnodes,exitCondition) in allChildrenA: isTemporal = True for subnode in uvwSubnodes: if len(uvw.transitions[subnode])==0: return constructUVWRecurse(node.children[1],uvw) elif len(uvw.transitions[subnode])==1: (k,l) = uvw.transitions[subnode][0] if k!=0: isTemporal = False else: activA &= ~l if not isTemporal: if nonTemporalA is None: nonTemporalA = (uvwSubnodes,exitCondition) else: failed = True # Handle Children B for (uvwSubnodes,exitCondition) in allChildrenB: isTemporal = True for subnode in uvwSubnodes: if len(uvw.transitions[subnode])==0: return constructUVWRecurse([0],None) # Cannot exit elif len(uvw.transitions[subnode])==1: (k,l) = uvw.transitions[subnode][0] if k!=0: isTemporal = False else: activB &= ~l if not isTemporal: if nonTemporalB is None: nonTemporalB = (uvwSubnodes,exitCondition) else: failed = True # Did we get a split? if (not failed) and ((activA & activB)==uvw.ddMgr.false): # Then build new node! newStateNo = uvw.addStateButNotNewListOfTransitionsForTheNewState(node.toPolishLTL(),True) uvw.transitions.append([(newStateNo,activA)]) if not (((~activA) & (~activB))==uvw.ddMgr.false): uvw.transitions[-1].append((0,(~activA) & (~activB))) for (uvwSubnodes,exitCondition) in allChildrenA: for subnode in uvwSubnodes: for (target,cond) in uvw.transitions[subnode]: # print ("L",target,(cond & ~activB).to_expr()) uvw.transitions[-1].append((target,cond & activA)) for (uvwSubnodes,exitCondition) in allChildrenB: for subnode in uvwSubnodes: for (target,cond) in uvw.transitions[subnode]: # print ("K",target,(cond & activB).to_expr()) uvw.transitions[-1].append((target,cond & activB)) # print("Final Transitions:") # for (a,b) in uvw.transitions[-1]: # print (a,b.to_expr()) uvw.labelToStateAndActivatingMapper[thisNodePolish] = ([newStateNo],None) return ([newStateNo],None) raise Exception("Unsupported Node Type for to UVW translation: "+str(node.value))
concatenation = Node("concatenation" , Seq(ident_or_term_or_groups, NotNeed(","), TRef("rhs", grammar=cur_grammar, flat=True)) , flat_eq_name=True, grammar=cur_grammar) alteration = Node("alteration" , Seq(ident_or_term_or_groups, NotNeed("|"), TRef("rhs", grammar=cur_grammar, flat=True)) , flat_eq_name=True, grammar=cur_grammar) rhs = Node("rhs", Or( concatenation , alteration , groups , ident_or_term) , grammar=cur_grammar) rule = Node("rule", Seq(lhs, NotNeed("="), rhs, NotNeed(";")), grammar=cur_grammar) grammar = Node("ebnf_grammar", ZeroOrMore(rule), grammar=cur_grammar) if __name__ == '__main__': space = Node("space", Concat(OneOrMore(Or(" ", "\t", "\n"))), skip=True) comment = Node("comment", Seq("(", "*" , Node("text", Concat(ZeroOrMore(Not(Seq("*", ")"))))) , "*", ")") , skip=True) skip_pattern = OneOrMore(Or(space, comment)) tr = TextReader(open("ebnf_test.txt"), skip_pattern=skip_pattern) #SetRecursionLimit(5000) rslt = grammar.read_from(tr)
def eval_expr(self, node: parser.Node) -> InterpreterValueAny: # TODO: Support referencing other static variables # Bitmask for 64-bit computation bitmask = 0xffffffffffffffff if node.i("number"): return self.create_int_value(int(node.data_strict)) elif node.i("true"): return self.true elif node.i("false"): return self.false elif node.i("null"): return self.null elif node.of("+", "*", "^", "&", "|"): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueInteger) or not isinstance( rhs, InterpreterValueInteger): raise typesys.TypingError( node, "Attempt to perform arithmetic on something that isn't an integers" ) if node.i("+"): ret = lhs.value + rhs.value elif node.i("*"): ret = lhs.value * rhs.value elif node.i("^"): ret = lhs.value ^ rhs.value elif node.i("&"): ret = lhs.value & rhs.value elif node.i("|"): ret = lhs.value | rhs.value return self.create_int_value(ret & bitmask) elif node.of("and", "or"): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueBoolean) or not isinstance( rhs, InterpreterValueBoolean): raise typesys.TypingError( node, "Attempt to perform logical operation on something that isn't an integers" ) if node.i("and"): ret = lhs.value and rhs.value elif node.i("or"): ret = lhs.value or rhs.value return self.true if ret else self.false elif node.i("not"): val = self.eval_expr(node[0]) if not isinstance(val, InterpreterValueBoolean): raise typesys.TypingError( node, "Attempt to perform logical operation on something that isn't an integers" ) return self.false if val.value else self.true elif node.of(">=", "<=", "<", ">"): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueInteger) or not isinstance( rhs, InterpreterValueInteger): raise typesys.TypingError( node, "Attempt to perform arithmetic on something that isn't an integers" ) lhs_value = self.normalize_negative(lhs.value) rhs_value = self.normalize_negative(rhs.value) if node.i(">="): ret = lhs_value >= rhs_value elif node.i("<="): ret = lhs_value <= rhs_value elif node.i("<"): ret = lhs_value < rhs_value elif node.i(">"): ret = lhs_value > rhs_value else: raise ValueError("This is a compiler bug") return self.true if ret else self.false elif node.of("==", "!="): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not lhs.type.is_assignable_to( rhs.type) and not rhs.type.is_assignable_to(lhs.type): raise typesys.TypingError( node, "Incomparable types: '%s' and '%s'" % (lhs.type, rhs.type)) return self.true if lhs.equals(rhs) ^ ( True if node.i("!=") else False) else self.false elif node.i("-") and len(node) == 2: lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueInteger) or not isinstance( rhs, InterpreterValueInteger): raise typesys.TypingError( node, "Attempt to perform arithmetic on something that isn't an integers" ) return self.create_int_value((lhs.value - rhs.value) & bitmask) elif (node.i("-") and len(node) == 1) or node.i("~"): val = self.eval_expr(node[0]) if not isinstance(val, InterpreterValueInteger): raise typesys.TypingError( node, "Attempt to negate something that isn't an integer") return self.create_int_value( (-val.value if node.i("-") else ~val.value) & bitmask) elif node.i("/"): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueInteger) or not isinstance( rhs, InterpreterValueInteger): raise typesys.TypingError( node, "Attempt to perform arithmetic on something that isn't an integers" ) lhs_value = lhs.value rhs_value = rhs.value # Make sure, if our value is negative, we're dividing by a # negative rather than a very large value (due to two's # complement) lhs_value = self.normalize_negative(lhs_value) rhs_value = self.normalize_negative(rhs_value) res = lhs_value // rhs_value if res * rhs.value != lhs.value: # Python rounds toward negative infinity, whereas C # (and thus our language) rounds toward 0. if res < 0: res += 1 return self.create_int_value(res & bitmask) elif node.i("["): typ = self.program.types.decide_type(node, emitter.Scopes(), None) if not isinstance(typ, typesys.ArrayType): raise ValueError("This is a compiler bug.") # All of our typechecking has already been taken care of in # the logic in typesys there result_values: List[AbstractInterpreterValue] = [] for child in node: result_values.append(self.eval_expr(child)) return self.create_array_value(typ, result_values) elif node.i("arrinst"): typ = self.program.types.decide_type(node, emitter.Scopes(), None) if not isinstance(typ, typesys.ArrayType): raise ValueError("This is a compiler bug.") # Same thing, all of our typechecking is delegated to typesys array_len = self.eval_expr(node[1]) if not isinstance(array_len, InterpreterValueInteger): raise typesys.TypingError( node[1], "Type of array length must be an integer") if array_len.value > 1024: node.warn( "Statically creating a very large array, this will make your bytecode file very large: %d" % array_len.value) arrinst_result_values: List[AbstractInterpreterValue] if isinstance(typ.parent_type, typesys.IntType): arrinst_result_values = [self.create_int_value(0) ] * array_len.value elif isinstance(typ.parent_type, typesys.BoolType): arrinst_result_values = [self.false] * array_len.value else: arrinst_result_values = [self.null] * array_len.value return self.create_array_value(typ, arrinst_result_values) elif node.i("#"): val = self.eval_expr(node[0]) if not isinstance(val, InterpreterValueArray): raise typesys.TypingError( node[0], "Cannot find length of something that isn't an array") return self.create_int_value(len(val.value)) elif node.i("access"): lhs = self.eval_expr(node[0]) rhs = self.eval_expr(node[1]) if not isinstance(lhs, InterpreterValueArray): raise typesys.TypingError( node[0], "Can't access an element of something that isn't an array") if not isinstance(rhs, InterpreterValueInteger): raise typesys.TypingError(node[1], "Array indices must be integers") return lhs.value[rhs.value] else: node.compile_error("Cannot evaluate expression at compile-time")
def test_ints_equal(self): int_node_equal = Node(vtype=v.EQUAL, children=[self.int_node_one, self.int_node_one]) backend.walk_ast(int_node_equal) eq_(int_node_equal.syn_value, True)
def walk_ast(self, root, siblings=None, parent=None): # not popping b/c we only pop when *destroying* scope # (here we are just modifying) scope = backend.scopes[-1] # this is obviously not extentable since the content of an arg for a function # can be an arbitrary expression, this is just to get something working # --- # Another issue is that this won't work recurssively --> we have to think a # little bit more about how we should recursively evaulate this function # what should it return / how should it interact with syn_value # --- # Here we're evaluating all the children that are stored in a node before we # evaluate the node itself, doing a proper post-order traversal of the nodes. # Also, since we are iterating through the nodes of the tree using the 'in' # operator, we are doing a L-attributed evaluation as well, letting us get # inherited as well as syntysized values. # The only issue here is that we have to have some mechanism to know who the # children are at out level (and our parent) for the inherited attributes, # so we'll probably pass them in. if root != None: if root.vtype == v.FUNCTION_DEFINITION: scope[root.symbol] = root # root.syn_value = evaluate_function(f=root, scope=scope, # args=[child.syn_value for child in root.children]) elif root.vtype == v.FUNCTION_CALL: scp = backend.find(root.symbol) if not scp: raise NameError, "Function '{}' does not exist".format( root.symbol) # evaluating expressions passed into function before calling function for child in root.children: backend.walk_ast(child) func = scp[root.symbol] if func.vtype == v.AGENT: agent = copy.deepcopy(func) self.agent_list.append(agent) backend.scopes.append(agent.scope) for st in agent.statements: backend.walk_ast(st) agent.create.execute(*root.children) root.syn_value = agent backend.scopes.pop() else: root.syn_value = func.execute(*root.children) elif root.vtype == v.RETURN_STATEMENT: if root.children: backend.walk_ast(root.children[0]) root.syn_value = root.children[0].syn_value else: root.syn_value = None elif root.vtype in first_order_ops: for kid in root.children: backend.walk_ast(kid) root.syn_value = first_order_ops[root.vtype]( *[child.syn_value for child in root.children]) root.syn_vtype = root.children[0].syn_vtype elif root.vtype in boolean_ops: for kid in root.children: backend.walk_ast(kid) root.syn_value = boolean_ops[root.vtype]( *[child.syn_value for child in root.children]) root.syn_vtype = root.children[0].syn_vtype elif root.vtype in equality_ops: for kid in root.children: backend.walk_ast(kid) root.syn_value = equality_ops[root.vtype](*[ child.syn_value for child in root.children ]) # does this break for len(root.children) > 2? root.syn_vtype = root.children[0].syn_vtype # Assignment elif root.vtype == v.ASSIGNMENT: if root.children[0].vtype == v.IMPLICIT_PARAM: obj = root.children[0].children[0] inner = root.children[0].children[1] scp = backend.find(obj.symbol) val_scp = scp[obj.symbol].scope backend.walk_ast(root.children[1]) assign(val_scp, (inner, root.children[1])) else: scp = backend.find(root.children[0].symbol) if not scp: raise NameError, "Variable '{}' does not exist".format( root.children[0].symbol) for child in root.children: backend.walk_ast(child) # this should have been disambiguated in the frontend try: # list assignment grandchild = root.children[0].children[0] for child in grandchild.children: backend.walk_ast(child) assert grandchild.vtype == v.BRACKET_ACCESS depths = grandchild.syn_value list_assign(scp, root.children) except IndexError: # not a list assignment assign( scp, root.children) # scopes modified via side effect elif root.vtype == v.IDENTIFIER: scp = backend.find(root.symbol) for kid in root.children: backend.walk_ast(kid) # list access try: root.children[0].vtype == v.BRACKET_ACCESS # identifier as index iden = root.children[0].children[0] backend.walk_ast(iden) root.children[0].syn_value = [iden.syn_value] item = scp[root.symbol].get( indexes=root.children[0].syn_value) root.syn_value = item.syn_value root.syn_vtype = item.syn_vtype # simple element access except IndexError: # scp[root.symbol]: root.syn_value = scp[root.symbol].syn_value root.syn_vtype = scp[root.symbol].syn_vtype # Declaration elif root.vtype == v.DECLARATION: scp = backend.find(root.symbol) # if scp: # raise Exception, "Symbol '{}' cannot be re-declared".format(root.symbol) from parser import Node, List # We store different Node types acc. to the root syn_vtype if root.syn_vtype == v.LIST_TYPE: depths = [] for d in root.children[1].depths: if isinstance(d, int): depths.append(d) else: scp = backend.find(d) depths.append(scp[d].syn_value) syn_vtype = root.children[1].syn_vtype none_obj = List(symbol=root.symbol, depths=depths, syn_vtype=syn_vtype) elif len(root.children) == 0: # inside declaration assignment # sorry, this is necessary b/c of wonkiness in the AST: none_obj = Node(symbol=root.symbol, vtype=v.IDENTIFIER, syn_vtype=root.syn_vtype, syn_value=None) else: assert len(root.children) > 0 identifier = root.children[0] none_obj = Node(symbol=identifier.symbol, vtype=identifier.vtype, syn_vtype=root.syn_vtype, syn_value=None) scope[root.symbol] = none_obj elif root.vtype == v.DECLARATION_ASSIGNMENT: for child in root.children: backend.walk_ast(child) elif root.vtype == v.IF: root.execute_if() elif root.vtype == v.PIF: root.execute_pif() elif root.vtype == v.WHILE: root.execute_while() elif root.vtype == v.REPEAT: root.execute_repeat() elif root.vtype == v.PROGRAM: for kid in root.children: backend.walk_ast(kid) elif root.vtype == v.STATEMENT_LIST: for kid in root.children: backend.walk_ast(kid) elif root.vtype == v.STATEMENT: for kid in root.children: backend.walk_ast(kid) # for debugging # print root.children, backend.scopes elif root.vtype in v.RETURN_STATEMENT: root.syn_value = backend.walk_ast(root.children) elif root.vtype == v.BRACKET_ACCESS: pass elif root.vtype == v.AGENT_LIST: if root.children: for child in root.children: backend.walk_ast(child) elif root.vtype == v.AGENT: backend.scopes[-1][root.symbol] = root elif root.vtype == v.ENVIRONMENT: for child in root.children: backend.walk_ast(child) elif root.vtype == v.POPULATE: backend.populate = root elif root.vtype == v.ACTION: backend.action = root elif root.vtype == v.TERMINATE: if root.children: for child in root.children: backend.walk_ast(child) elif root.vtype == v.INVARIANT_CLAUSE: freq = root.syn_value backend.invariants[freq].append(root) elif root.vtype == v.ANALYSIS: self.analysis = root elif root.vtype == v.WEIGHTED_VALUE_STAT: for kid in root.children: backend.walk_ast(kid.children[1]) root.syn_value = weighted_value( [k.children[0].syn_value for k in root.children], [k.children[1] for k in root.children]).syn_value elif root.vtype == v.IMPLICIT_PARAM: obj = root.children[0] inner = root.children[1] scp = backend.find(obj.symbol) val_scp = scp[obj.symbol].scope val = val_scp[inner.symbol] backend.scopes.append(val_scp) if inner.vtype == v.FUNCTION_CALL: backend.walk_ast(inner) root.syn_value = inner.syn_value else: root.syn_value = val.syn_value backend.scopes.pop() else: pass # @todo return root.syn_value
def decide_type( self, expr: parser.Node, scope: "emitter.Scopes", generic_type_context: Optional[GenericTypeContext], suppress_coercing_void_warning: bool = False) -> AbstractType: if expr.i("as"): return self.resolve_strict(expr[1], generic_type_context) elif expr.i("instanceof"): return self.bool_type elif expr.of("+", "*", "-", "^", "&", "|", "%", "/") and len(expr) == 2: lhs_type = self.decide_type(expr[0], scope, generic_type_context) rhs_type = self.decide_type(expr[1], scope, generic_type_context) if not lhs_type.is_numerical(): raise TypingError(expr[0], "Type %s is not numerical" % lhs_type) if not rhs_type.is_numerical(): raise TypingError(expr[1], "Type %s is not numerical" % rhs_type) if not lhs_type.is_assignable_from( rhs_type) or not lhs_type.is_assignable_to(rhs_type): raise TypingError( expr, "Types %s and %s are incompatible for arithmetic operation" % (lhs_type, rhs_type)) return lhs_type elif expr.of(">=", "<=", ">", "<"): lhs_type = self.decide_type(expr[0], scope, generic_type_context) rhs_type = self.decide_type(expr[1], scope, generic_type_context) if not lhs_type.is_numerical(): raise TypingError(expr[0], "Type %s is not numerical" % lhs_type) if not rhs_type.is_numerical(): raise TypingError(expr[1], "Type %s is not numerical" % rhs_type) if not lhs_type.is_assignable_from( rhs_type) or not lhs_type.is_assignable_to(rhs_type): raise TypingError( expr, "Types %s and %s are incompatible for arithmetic comparison" % (lhs_type, rhs_type)) return self.bool_type elif expr.of("==", "!="): lhs_type = self.decide_type(expr[0], scope, generic_type_context) rhs_type = self.decide_type(expr[1], scope, generic_type_context) if not lhs_type.is_assignable_to( rhs_type) and not rhs_type.is_assignable_to(lhs_type): raise TypingError( expr, "Incomparable types: '%s' and '%s'" % (lhs_type, rhs_type)) return self.bool_type elif expr.i("number"): return self.int_type elif expr.of("and", "or"): lhs_type = self.decide_type(expr[0], scope, generic_type_context) rhs_type = self.decide_type(expr[1], scope, generic_type_context) if not lhs_type.is_boolean(): raise TypingError(expr[0], "Type %s is not boolean" % lhs_type) if not rhs_type.is_boolean(): raise TypingError(expr[0], "Type %s is not boolean" % rhs_type) return self.bool_type elif expr.i("not"): type = self.decide_type(expr[0], scope, generic_type_context) if not type.is_boolean(): raise TypingError(expr[0], "Type %s is not boolean" % type) return self.bool_type elif expr.of("~", "-") and len(expr) == 1: type = self.decide_type(expr[0], scope, generic_type_context) if not type.is_numerical(): raise TypingError(expr[0], "Type %s is not numerical" % type) return self.int_type elif expr.of("ident", ".") \ and util.get_flattened(expr) is not None \ and self.program.static_variables.has_variable(util.nonnull(util.get_flattened(expr))): return self.program.static_variables.resolve_variable( util.nonnull(util.get_flattened(expr))).type elif expr.i("ident"): return scope.resolve(expr.data_strict, expr).type elif expr.of("true", "false"): return self.bool_type elif expr.i("null"): return self.void_type elif expr.i("["): # For now, everything must be the same type, except for nulls # interspersed. Later this will change. current_type = None if len(expr) == 0: expr.compile_error( "Zero-length arrays must be instantiated with the arbitrary-length instantiation syntax" ) for child in expr: current_child_type: AbstractType = self.decide_type( child, scope, generic_type_context) if current_type is None: if not current_child_type.is_void(): current_type = current_child_type else: continue # This is to make the typechecker happy # We know this is safe because of the previous if-statement current_type_not_none: AbstractType = current_type while current_type_not_none.get_supertype( ) is not None and not current_child_type.is_assignable_to( current_type_not_none): current_type = current_type_not_none.get_supertype() if not current_child_type.is_assignable_to( current_type_not_none): raise TypingError( child, "Could not reconcile type %s" % (current_child_type)) if current_type is None: expr.compile_error( "Cannot have an array literal comprising only null values, use arbitrary-length instantiation syntax instead" ) # Unreachable return None # type: ignore else: return self.get_array_type(current_type) elif expr.i("arrinst"): return self.get_array_type( self.resolve_strict(expr[0], generic_type_context)) elif expr.i("#"): if not self.decide_type(expr[0], scope, generic_type_context).is_array(): raise TypingError( expr[0], "Can't decide length of something that isn't an array") return self.int_type elif expr.i("access"): lhs_type = self.decide_type(expr[0], scope, generic_type_context) if not lhs_type.is_array(): raise TypingError( expr, "Attempt to access element of something that isn't an array" ) assert isinstance(lhs_type, ArrayType) return lhs_type.parent_type elif expr.i("call"): # TODO: Move method call typechecking in here from emitter.py. signature = self.resolve_to_signature(expr[0], scope, generic_type_context) if len(expr["typeargs"]) != ( len(signature.generic_type_context.arguments) if signature.generic_type_context is not None else 0): expr.compile_error( "Wrong number of type arguments (expected %s, got %s)" % (len(signature.generic_type_context.arguments) if signature.generic_type_context is not None else 0, len(expr["typeargs"]))) signature = signature.specialize([ self.resolve_strict(typ, generic_type_context) for typ in expr["typeargs"] ], self.program, expr["typeargs"]) if signature is not None: if (not suppress_coercing_void_warning) and isinstance( signature.returntype, VoidType): expr.warn("Coercing void") return signature.returntype if expr[0].i("."): dot_node = expr[0] lhs_type = self.decide_type(dot_node[0], scope) if not lhs_type.is_clazz(): raise TypingError( dot_node[1], "Attempt to call a method on non-class type '%s'" % lhs_type) signature = lhs_type.method_signature(dot_node[1].data) if signature is None: expr.compile_error("Unknown method name '%s'" % expr[0].data) if (not suppress_coercing_void_warning) and isinstance( signature.returntype, VoidType): expr.warn("Coercing void") return signature.returntype elif expr.i("new"): ret = self.resolve_strict(expr[0], generic_type_context, allow_raw=True) # Why not .is_class()? Because we can't instantiate generic type parameters. if not isinstance(ret, ClazzType): raise TypingError(expr[0], "Type %s is not a class" % ret) type_arguments: List[AbstractType] = [] for argument in expr["typeargs"]: type_arguments.append( self.resolve_strict(argument, generic_type_context)) ret = ret.specialize(type_arguments, expr) return ret elif expr.i("."): # Ternary operator to satisfy typechecker (if-else statement would effectively require phi node which is ugly) lhs_typ: AbstractType = \ (scope.resolve(expr[0].data_strict, expr[0]).type) if expr[0].i("ident") \ else self.decide_type(expr[0], scope, generic_type_context) if not lhs_typ.is_clazz(): expr.compile_error( "Attempt to access an attribute of something that isn't a class" ) assert isinstance(lhs_typ, ClazzType) return lhs_typ.type_of_property(expr[1].data_strict, expr) elif expr.i("string"): string_type = self.get_string_type() if string_type is None: expr.compile_error( "Cannot use string literal without an implementation of stdlib.String" ) return string_type elif expr.i("super"): # TODO: This is horribly ugly typ = scope.resolve("this", expr).type if not isinstance(typ, ClazzType): expr.compile_error("Variable `this` isn't a class type") parent_type = typ.get_supertype() if parent_type is None: expr.compile_error( "Attempt to reference superclass in a class without a superclass" ) return parent_type else: raise ValueError( "Expression not accounted for in typesys. This is a compiler bug." )
pn_concatenation = Node("pn_concatenation" , Seq(pn_ident_or_term_or_pn_groups, NotNeed(","), TRef("pn_rhs", grammar=cur_grammar, flat=True)) , flat_eq_name=True, grammar=cur_grammar) pn_alteration = Node("pn_alteration" , Seq(pn_ident_or_term_or_pn_groups, NotNeed("|"), TRef("pn_rhs", grammar=cur_grammar, flat=True)) , flat_eq_name=True, grammar=cur_grammar) pn_rhs = Node("pn_rhs", Or(pn_concatenation , pn_alteration , pn_groups , pn_ident_or_term) , grammar=cur_grammar) pn_rule = Node("pn_rule", Seq(pn_lhs, NotNeed("="), pn_rhs, NotNeed(";")), grammar=cur_grammar) pn_grammar = Node("ebnf_grammar", ZeroOrMore(pn_rule), grammar=cur_grammar) #token_iterator = TokenIterator(TextReader(open("test1.txt")) # , tt_list, tt_skip_list) #token_reader = TokenReader(token_iterator) #token_reader = TokenReader(TokenIterator(TextReader(open("test1.txt")), tt_list, tt_skip_list)) if __name__ == '__main__': # SetRecursionLimit(5000) # lexing with tokens reduces recursion level rslt = pn_grammar.read_from(token_reader) thing_pprint(rslt.readedlist)
with test('load grammar'): g1 = parser.Grammar(fg1) with test('continuations'): test.eq(sorted(repr(r) for r in g1.continuations('Aux')), [ 'Root -> Aux.$0.$1 NP.$0 VP.$1.-', 'VP.$0.$1 -> Aux.$0.$2 VP.$2.$1', 'VP.$0.- -> Aux.$0.pred AdjP', 'VP.$0.- -> Aux.$0.pred NP.*' ]) with test('g1.lexicon.parts'): test.eq(sorted(str(pos) for pos in g1.lexicon.parts('be')), ['Aux.base.enp', 'Aux.base.ing', 'Aux.base.pred']) with test('Node'): if hasattr(parser, 'Node'): from parser import Node v = Node(C('V.sg.t.*'), 'chases', 2, 3) test.eq(v.cat, ('V', 'sg', 't', '*')) test.eq(v.i, 2) test.eq(v.j, 3) with test('e.__str__'): e = parser.Edge(rule, [v], ('sg', '*')) test.eq(str(e), 'VP.$0 -> [2 V.sg.t.* 3] * NP.* PP.$1 : sg *') with test('e.__repr__'): test.eq(repr(e), '<Edge VP.$0 -> [2 V.sg.t.* 3] * NP.* PP.$1 : sg *>') with test('p.reset'): p = parser.Parser(g0) p.reset('this dog barks'.split()) test.eq(p.chart, {})
def type_of_property(self, name: str, node: parser.Node) -> AbstractType: ret = self.type_of_property_optional(name) if ret is None: node.compile_error("Invalid property name '%s' for type '%s'" % (name, self.name)) return ret