diff options
author | Ryo Nihei <nihei.dev@gmail.com> | 2022-05-03 21:40:43 +0900 |
---|---|---|
committer | Ryo Nihei <nihei.dev@gmail.com> | 2022-05-10 23:14:34 +0900 |
commit | f7484ef11af39585989dbbcad701551c561fa67c (patch) | |
tree | 828b4225802ed442e92017a81d01b5442d2b4fb6 /driver | |
parent | Update CHANGELOG (diff) | |
download | cotia-f7484ef11af39585989dbbcad701551c561fa67c.tar.gz cotia-f7484ef11af39585989dbbcad701551c561fa67c.tar.xz |
Add --json option to vartan-parse command
Diffstat (limited to 'driver')
-rw-r--r-- | driver/parser_test.go | 12 | ||||
-rw-r--r-- | driver/semantic_action.go | 94 |
2 files changed, 79 insertions, 27 deletions
diff --git a/driver/parser_test.go b/driver/parser_test.go index fa8307e..4795e29 100644 --- a/driver/parser_test.go +++ b/driver/parser_test.go @@ -11,6 +11,7 @@ import ( func termNode(kind string, text string, children ...*Node) *Node { return &Node{ + Type: NodeTypeTerminal, KindName: kind, Text: text, Children: children, @@ -19,13 +20,14 @@ func termNode(kind string, text string, children ...*Node) *Node { func errorNode() *Node { return &Node{ + Type: NodeTypeError, KindName: "error", - Error: true, } } func nonTermNode(kind string, children ...*Node) *Node { return &Node{ + Type: NodeTypeNonTerminal, KindName: kind, Children: children, } @@ -131,8 +133,8 @@ bar_text: "bar"; `, src: ``, cst: nonTermNode("s", - termNode("foo", ""), - termNode("bar", ""), + nonTermNode("foo"), + nonTermNode("bar"), ), }, // The driver can reduce productions that have the empty alternative and can generate a CST (and AST) node. @@ -154,7 +156,7 @@ bar_text: "bar"; `, src: `bar`, cst: nonTermNode("s", - termNode("foo", ""), + nonTermNode("foo"), nonTermNode("bar", termNode("bar_text", "bar"), ), @@ -716,7 +718,7 @@ bar: 'bar'; func testTree(t *testing.T, node, expected *Node) { t.Helper() - if node.KindName != expected.KindName || node.Text != expected.Text || node.Error != expected.Error { + if node.Type != expected.Type || node.KindName != expected.KindName || node.Text != expected.Text { t.Fatalf("unexpected node; want: %+v, got: %+v", expected, node) } if len(node.Children) != len(expected.Children) { diff --git a/driver/semantic_action.go b/driver/semantic_action.go index 7c52e24..73f3bb0 100644 --- a/driver/semantic_action.go +++ b/driver/semantic_action.go @@ -1,6 +1,7 @@ package driver import ( + "encoding/json" "fmt" "io" ) @@ -68,6 +69,7 @@ func NewDefaultSyntaxTreeBuilder() *DefaulSyntaxTreeBuilder { // Shift is a implementation of SyntaxTreeBuilder.Shift. func (b *DefaulSyntaxTreeBuilder) Shift(kindName string, text string, row, col int) SyntaxTreeNode { return &Node{ + Type: NodeTypeTerminal, KindName: kindName, Text: text, Row: row, @@ -78,8 +80,8 @@ func (b *DefaulSyntaxTreeBuilder) Shift(kindName string, text string, row, col i // ShiftError is a implementation of SyntaxTreeBuilder.ShiftError. func (b *DefaulSyntaxTreeBuilder) ShiftError(kindName string) SyntaxTreeNode { return &Node{ + Type: NodeTypeError, KindName: kindName, - Error: true, } } @@ -90,6 +92,7 @@ func (b *DefaulSyntaxTreeBuilder) Reduce(kindName string, children []SyntaxTreeN cNodes[i] = c.(*Node) } return &Node{ + Type: NodeTypeNonTerminal, KindName: kindName, Children: cNodes, } @@ -238,14 +241,61 @@ func (s *semanticStack) pop(n int) []SyntaxTreeNode { return fs } +type NodeType int + +const ( + NodeTypeError = 0 + NodeTypeTerminal = 1 + NodeTypeNonTerminal = 2 +) + // Node is a implementation of SyntaxTreeNode interface. type Node struct { + Type NodeType KindName string Text string Row int Col int Children []*Node - Error bool +} + +func (n *Node) MarshalJSON() ([]byte, error) { + switch n.Type { + case NodeTypeError: + return json.Marshal(struct { + Type NodeType `json:"type"` + KindName string `json:"kind_name"` + }{ + Type: n.Type, + KindName: n.KindName, + }) + case NodeTypeTerminal: + return json.Marshal(struct { + Type NodeType `json:"type"` + KindName string `json:"kind_name"` + Text string `json:"text"` + Row int `json:"row"` + Col int `json:"col"` + }{ + Type: n.Type, + KindName: n.KindName, + Text: n.Text, + Row: n.Row, + Col: n.Col, + }) + case NodeTypeNonTerminal: + return json.Marshal(struct { + Type NodeType `json:"type"` + KindName string `json:"kind_name"` + Children []*Node `json:"children"` + }{ + Type: n.Type, + KindName: n.KindName, + Children: n.Children, + }) + default: + return nil, fmt.Errorf("invalid node type: %v", n.Type) + } } // ChildCount is a implementation of SyntaxTreeNode.ChildCount. @@ -272,31 +322,31 @@ func printTree(w io.Writer, node *Node, ruledLine string, childRuledLinePrefix s return } - switch { - case node.Error: + switch node.Type { + case NodeTypeError: fmt.Fprintf(w, "%v!%v\n", ruledLine, node.KindName) - case node.Text != "": + case NodeTypeTerminal: fmt.Fprintf(w, "%v%v %#v\n", ruledLine, node.KindName, node.Text) - default: + case NodeTypeNonTerminal: fmt.Fprintf(w, "%v%v\n", ruledLine, node.KindName) - } - num := len(node.Children) - for i, child := range node.Children { - var line string - if num > 1 && i < num-1 { - line = "├─ " - } else { - line = "└─ " - } + num := len(node.Children) + for i, child := range node.Children { + var line string + if num > 1 && i < num-1 { + line = "├─ " + } else { + line = "└─ " + } - var prefix string - if i >= num-1 { - prefix = " " - } else { - prefix = "│ " - } + var prefix string + if i >= num-1 { + prefix = " " + } else { + prefix = "│ " + } - printTree(w, child, childRuledLinePrefix+line, childRuledLinePrefix+prefix) + printTree(w, child, childRuledLinePrefix+line, childRuledLinePrefix+prefix) + } } } |