def splitword(self, n, word): offset = n.pos[0] parts = [] children = [] prev = None if hasattr(n, "parts"): parts = n.parts for part in parts: begin = part.pos[0] end = part.pos[1] if offset != begin: text = word[offset - n.pos[0]:begin - n.pos[0]] if prev == "CommandSubstitution" and text.startswith(")"): # Workaround for bashlex bug text = text[1:] if len(text) != 0: children.append(Node( "Literal", [Field( "value", "str", self.to_leaf_value("str", text))])) children.append(bashlex_ast_to_ast(script, part, split_value)) prev = children[-1].type_name offset = end if offset != n.pos[1]: text = word[offset - n.pos[0]:] if prev == "CommandSubstitution" and text.startswith(")"): # Workaround for bashlex bug text = text[1:] if len(text) != 0: children.append(Node( "Literal", [Field("value", "str", self.to_leaf_value("str", text))])) return children
def generate(head: int, node_type: Optional[NodeType] = None) -> AST: action = self._action_sequence[head] if isinstance(action, GenerateToken): if action.kind is None: assert node_type is not None assert node_type.type_name is not None return Leaf(node_type.type_name, action.value) else: return Leaf(action.kind, action.value) elif isinstance(action, ApplyRule): # The head action should apply ExpandTreeRule rule = cast(ExpandTreeRule, action.rule) ast = Node(rule.parent.type_name, []) for (name, node_type), actions in zip(rule.children, self._tree.children[head]): assert node_type.type_name is not None if node_type.is_variadic: # Variadic field ast.fields.append(Field(name, node_type.type_name, [])) for act in actions: if isinstance(self._action_sequence[act], ApplyRule): a = cast(ApplyRule, self._action_sequence[act]) if isinstance(a.rule, CloseVariadicFieldRule): break assert isinstance(ast.fields[-1].value, list) ast.fields[-1].value.append( generate(act, node_type)) else: ast.fields.append( Field(name, node_type.type_name, generate(actions[0], node_type))) return ast
def visitfunction(self, n, name, body, parts): # Node(type_name="Funtion", fields={"name":Leaf(name), # "body":[...]} body = [bashlex_ast_to_ast(script, x, split_value) for x in body] self.value = Node("Function", [ Field("name", "str", self.to_leaf_value("str", name)), Field("body", "Node", body)]) return False
def visitcompound(self, n, list, redirects): # Node(type_name="Compound", fileds={"list":[**list], # "redirects":[**redicects]}) list = [bashlex_ast_to_ast(script, x, split_value) for x in list] redirects = [bashlex_ast_to_ast( script, x, split_value) for x in redirects] self.value = Node("Compound", [ Field("list", "Node", list), Field("redirects", "Node", redirects)]) return False
def visitprocesssubstitution(self, n, command): # Node(type_name="ProcessSubstitution", # fileds={"command": command, "type": Leaf(type)}) t = script[n.pos[0]] self.value = Node("ProcessSubstitution", [Field( "command", "Node", bashlex_ast_to_ast(script, command, split_value)), Field("type", "str", self.to_leaf_value("str", t))]) return False
def visittilde(self, n, value): # Node(type_name="Tilde", fileds={"value": Leaf(value)}) self.value = \ Node( "Tilde", [Field("value", "str", self.to_leaf_value("str", value))]) return False
def visitreservedword(self, n, word): # Node(type_name="ReservedWord", fileds={"word": Leaf(word)}) self.value = \ Node("ReservedWord", [Field("word", "str", self.to_leaf_value("str", word))]) return False
def test_clone(self): a = Node("list", [ Field("name", "literal", Leaf("str", "name")), Field("elems", "literal", [Leaf("str", "foo"), Leaf("str", "bar")]) ]) a1 = a.clone() a.name = "" a.type_name = "" a.fields[0].name = "" a.fields[1].value[0].type_name = "" assert Node("list", [ Field("name", "literal", Leaf("str", "name")), Field("elems", "literal", [Leaf("str", "foo"), Leaf("str", "bar")]) ]) == a1
def test_create_leaf(self): seq = ActionSequence.create(Leaf("str", "t0 t1")) assert [ ApplyRule( ExpandTreeRule(NodeType(None, NodeConstraint.Node, False), [ ("root", NodeType(Root(), NodeConstraint.Token, False)) ])), GenerateToken("str", "t0 t1") ] == seq.action_sequence seq = ActionSequence.create( Node( "value", [Field("name", "str", [Leaf("str", "t0"), Leaf("str", "t1")])])) assert [ ApplyRule( ExpandTreeRule( NodeType(None, NodeConstraint.Node, False), [("root", NodeType(Root(), NodeConstraint.Node, False))])), ApplyRule( ExpandTreeRule( NodeType("value", NodeConstraint.Node, False), [("name", NodeType("str", NodeConstraint.Token, True))])), GenerateToken("str", "t0"), GenerateToken("str", "t1"), ApplyRule(CloseVariadicFieldRule()) ] == seq.action_sequence
def visitcommandsubstitution(self, n, command): # Node(type_name="CommandSubstitution", # fileds={"command": command}) self.value = Node("CommandSubstitution", [Field( "command", "Node", bashlex_ast_to_ast(script, command, split_value))]) return False
def visitredirect(self, n, input, type, output, heredoc): # Node(type_name="Redirect", fields={"type":Leaf(type), # "heredoc": heredoc or NoneNode # "input": input or NoneNode # "output": output or NoneNode heredoc = bashlex_ast_to_ast(script, heredoc, split_value) \ if heredoc is not None \ else Node("None", []) input = bashlex_ast_to_ast(script, input, split_value) \ if input is not None \ else Node("None", []) output = bashlex_ast_to_ast(script, output, split_value) \ if output is not None \ else Node("None", []) self.value = Node("Redirect", [ Field("type", "str", self.to_leaf_value("str", type)), Field("heredoc", "Node", heredoc), Field("input", "Node", input), Field("output", "Node", output) ]) return False
def test_create_node(self): a = Node("def", [Field("name", "literal", Leaf("str", "foo"))]) seq = ActionSequence.create(a) assert [ ApplyRule( ExpandTreeRule( NodeType(None, NodeConstraint.Node, False), [("root", NodeType(Root(), NodeConstraint.Node, False))])), ApplyRule( ExpandTreeRule(NodeType("def", NodeConstraint.Node, False), [ ("name", NodeType("literal", NodeConstraint.Token, False)) ])), GenerateToken("str", "foo") ] == seq.action_sequence
def parse(self, code): ast = Node("Assign", [Field("name", "Name", Node("Name", [Field("id", "str", Leaf("str", "x"))])), Field("value", "expr", Node("Op", [ Field("op", "str", Leaf("str", "+")), Field("arg0", "expr", Node("Name", [Field("id", "str", Leaf("str", "y"))])), Field("arg1", "expr", Node("Number", [ Field("value", "number", Leaf("number", "1"))]))] ))]) return ast
def test_generate(self): funcdef = ExpandTreeRule( NodeType("def", NodeConstraint.Node, False), [("name", NodeType("value", NodeConstraint.Token, True)), ("body", NodeType("expr", NodeConstraint.Node, True))]) expr = ExpandTreeRule( NodeType("expr", NodeConstraint.Node, False), [("op", NodeType("value", NodeConstraint.Token, False)), ("arg0", NodeType("value", NodeConstraint.Token, False)), ("arg1", NodeType("value", NodeConstraint.Token, False))]) action_sequence = ActionSequence() action_sequence.eval(ApplyRule(funcdef)) action_sequence.eval(GenerateToken("name", "f")) action_sequence.eval(GenerateToken("name", "_")) action_sequence.eval(GenerateToken("name", "0")) action_sequence.eval(ApplyRule(CloseVariadicFieldRule())) action_sequence.eval(ApplyRule(expr)) action_sequence.eval(GenerateToken("value", "+")) action_sequence.eval(GenerateToken("value", "1")) action_sequence.eval(GenerateToken("value", "2")) action_sequence.eval(ApplyRule(CloseVariadicFieldRule())) assert action_sequence.head is None assert Node("def", [ Field("name", "value", [Leaf("name", "f"), Leaf("name", "_"), Leaf("name", "0")]), Field("body", "expr", [ Node("expr", [ Field("op", "value", Leaf("value", "+")), Field("arg0", "value", Leaf("value", "1")), Field("arg1", "value", Leaf("value", "2")) ]) ]) ]) == action_sequence.generate()
def test_create_node_with_variadic_fields(self): a = Node( "list", [Field("elems", "literal", [Node("str", []), Node("str", [])])]) seq = ActionSequence.create(a) assert [ ApplyRule( ExpandTreeRule( NodeType(None, NodeConstraint.Node, False), [("root", NodeType(Root(), NodeConstraint.Node, False))])), ApplyRule( ExpandTreeRule(NodeType("list", NodeConstraint.Node, False), [ ("elems", NodeType("literal", NodeConstraint.Node, True)) ])), ApplyRule( ExpandTreeRule(NodeType("str", NodeConstraint.Node, False), [])), ApplyRule( ExpandTreeRule(NodeType("str", NodeConstraint.Node, False), [])), ApplyRule(CloseVariadicFieldRule()) ] == seq.action_sequence
def test_node(self): assert Sugar.node("list", name=("literal", Leaf("str", "name"))) == \ Node("list", [Field("name", "literal", Leaf("str", "name"))])
def test_parse_circle(self, parser): assert Node("Circle", [Field("r", "size", Leaf("size", 1))]) == parser.parse( Circle(1))
def test_parse_rectangle(self, parser): assert Node("Rectangle", [ Field("w", "size", Leaf("size", 1)), Field("h", "size", Leaf("size", 2)) ]) == parser.parse(Rectangle(1, 2))
def test_parse_translation(self, parser): assert Node("Translation", [ Field("x", "length", Leaf("length", 1)), Field("y", "length", Leaf("length", 2)), Field("child", "CSG", Leaf("CSG", Reference(0))) ]) == parser.parse(Translation(1, 2, Reference(0)))
def visitcommand(self, n, parts): # Node(type_name="Command", fields={"parts":[...]}) parts = [bashlex_ast_to_ast(script, x, split_value) for x in parts] self.value = Node("Command", [Field("parts", "Node", parts)]) return False
def visitassignment(self, n, word): word = script[n.pos[0]:n.pos[1]] children = self.splitword(n, word) self.value = Node("Assign", [Field("value", "Node", children)]) return False
def visitpipeline(self, n, parts): # Node(type_name="Pipeline", fields={"parts": [...]}) parts = [bashlex_ast_to_ast(script, p, split_value) for p in parts] self.value = Node("Pipeline", [Field("parts", "Node", parts)]) return False
def test_parse_union(self, parser): assert Node("Union", [ Field("a", "CSG", Leaf("CSG", Reference(0))), Field("b", "CSG", Leaf("CSG", Reference(1))) ]) == parser.parse(Union(Reference(0), Reference(1)))
def visitpipe(self, n, pipe): # Node(type_name="Pipe", fileds={"pipe": Leaf(pipe)}) self.value = \ Node("Pipe", [Field("pipe", "str", self.to_leaf_value("str", pipe))]) return False
def visitoperator(self, n, op): # Node(type_name="Operator", fileds={"op": Leaf(op)}) self.value = \ Node("Operator", [Field("op", "str", self.to_leaf_value("str", op))]) return False
def test_parse_difference(self, parser): assert Node("Difference", [ Field("a", "CSG", Leaf("CSG", Reference(0))), Field("b", "CSG", Leaf("CSG", Reference(1))) ]) == parser.parse(Difference(Reference(0), Reference(1)))
def create(node: AST): """ Return the action sequence corresponding to this AST Parameters ---------- node: AST Returns ------- actionSequence The corresponding action sequence """ def to_sequence(node: AST) -> List[Action]: if isinstance(node, Node): def to_node_type(field: Field) -> NodeType: if isinstance(field.value, list): if len(field.value) > 0 and \ isinstance(field.value[0], Leaf): return NodeType(field.type_name, NodeConstraint.Token, True) else: return NodeType(field.type_name, NodeConstraint.Node, True) else: if isinstance(field.value, Leaf): return NodeType(field.type_name, NodeConstraint.Token, False) else: return NodeType(field.type_name, NodeConstraint.Node, False) children = list( map(lambda f: (f.name, to_node_type(f)), node.fields)) seq: List[Action] = [ ApplyRule( ExpandTreeRule( NodeType(node.type_name, NodeConstraint.Node, False), children)) ] for field in node.fields: if isinstance(field.value, list): for v in field.value: seq.extend(to_sequence(v)) seq.append(ApplyRule(CloseVariadicFieldRule())) else: seq.extend(to_sequence(field.value)) return seq elif isinstance(node, Leaf): node_type = node.get_type_name() assert not isinstance(node_type, Root) assert node_type is not None return [GenerateToken(node_type, node.value)] else: logger.critical(f"Invalid type of node: {type(node)}") raise RuntimeError(f"Invalid type of node: {type(node)}") action_sequence = ActionSequence() node = Node(None, [Field("root", Root(), node)]) for action in to_sequence(node): action_sequence.eval(action) return action_sequence
def test_parse_rotation(self, parser): assert Node("Rotation", [ Field("theta", "degree", Leaf("degree", 45)), Field("child", "CSG", Leaf("CSG", Reference(0))) ]) == parser.parse(Rotation(45, Reference(0)))
def parse(self, code: csgAST) -> Optional[AST]: if isinstance(code, Circle): return Node("Circle", [Field("r", "size", Leaf("size", code.r))]) elif isinstance(code, Rectangle): return Node("Rectangle", [ Field("w", "size", Leaf("size", code.w)), Field("h", "size", Leaf("size", code.h)) ]) elif isinstance(code, Translation): child = self.parse(code.child) if child is None: return None else: return Node("Translation", [ Field("x", "length", Leaf("length", code.x)), Field("y", "length", Leaf("length", code.y)), Field("child", "CSG", child) ]) elif isinstance(code, Rotation): child = self.parse(code.child) if child is None: return None else: return Node("Rotation", [ Field("theta", "degree", Leaf("degree", code.theta_degree)), Field("child", "CSG", child) ]) elif isinstance(code, Union): a, b = self.parse(code.a), self.parse(code.b) if a is None or b is None: return None else: return Node("Union", [Field("a", "CSG", a), Field("b", "CSG", b)]) elif isinstance(code, Difference): a, b = self.parse(code.a), self.parse(code.b) if a is None or b is None: return None else: return Node("Difference", [Field("a", "CSG", a), Field("b", "CSG", b)]) elif isinstance(code, Reference): return Leaf("CSG", code) logger.warning(f"Invalid node type {code.type_name()}") # TODO throw exception return None
def visitheredoc(self, n, value): # Node(type_name="Heredoc", fileds={"value": Leaf(value)}) self.value = Node( "Heredoc", [Field("value", "str", self.to_leaf_value("str", value))]) return False