aboutsummaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2021-08-21 16:18:56 +0900
committerRyo Nihei <nihei.dev@gmail.com>2021-08-21 16:19:49 +0900
commit94e2400aa8e6017165ab22ba5f2f70a6d0682f63 (patch)
tree83949f605bd729c83f8295db47aa065ad96e65bf /driver
parentFix indents of a tree (diff)
downloadcotia-94e2400aa8e6017165ab22ba5f2f70a6d0682f63.tar.gz
cotia-94e2400aa8e6017165ab22ba5f2f70a6d0682f63.tar.xz
Resolve conflicts by default rules
When a shift/reduce conflict occurred, we prioritize the shift action, and when a reduce/reduce conflict occurred, we prioritize the production defined earlier in the grammar file.
Diffstat (limited to 'driver')
-rw-r--r--driver/conflict_test.go109
-rw-r--r--driver/parser_test.go24
2 files changed, 121 insertions, 12 deletions
diff --git a/driver/conflict_test.go b/driver/conflict_test.go
new file mode 100644
index 0000000..750ed4e
--- /dev/null
+++ b/driver/conflict_test.go
@@ -0,0 +1,109 @@
+package driver
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/nihei9/vartan/grammar"
+ "github.com/nihei9/vartan/spec"
+)
+
+func TestParserWithConflicts(t *testing.T) {
+ tests := []struct {
+ caption string
+ specSrc string
+ src string
+ cst *Node
+ }{
+ {
+ caption: "when a shift/reduce conflict occurred, we prioritize the shift action",
+ specSrc: `
+expr
+ : expr assign expr
+ | id
+ ;
+
+id: "[A-Za-z0-9_]+";
+assign: '=';
+`,
+ src: `foo=bar=baz`,
+ cst: nonTermNode("expr",
+ nonTermNode("expr",
+ termNode("id", "foo"),
+ ),
+ termNode("assign", "="),
+ nonTermNode("expr",
+ nonTermNode("expr",
+ termNode("id", "bar"),
+ ),
+ termNode("assign", "="),
+ nonTermNode("expr",
+ termNode("id", "baz"),
+ ),
+ ),
+ ),
+ },
+ {
+ caption: "when a reduce/reduce conflict occurred, we prioritize the production defined earlier in the grammar",
+ specSrc: `
+s
+ : a
+ | b
+ ;
+a
+ : id
+ ;
+b
+ : id
+ ;
+
+id: "[A-Za-z0-9_]+";
+`,
+ src: `foo`,
+ cst: nonTermNode("s",
+ nonTermNode("a",
+ termNode("id", "foo"),
+ ),
+ ),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.caption, func(t *testing.T) {
+ ast, err := spec.Parse(strings.NewReader(tt.specSrc))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ b := grammar.GrammarBuilder{
+ AST: ast,
+ }
+ g, err := b.Build()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ gram, err := grammar.Compile(g, grammar.SpecifyClass(grammar.ClassSLR))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ p, err := NewParser(gram, strings.NewReader(tt.src), MakeCST())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = p.Parse()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fmt.Printf("CST:\n")
+ PrintTree(os.Stdout, p.CST())
+
+ testTree(t, p.CST(), tt.cst)
+ })
+ }
+}
diff --git a/driver/parser_test.go b/driver/parser_test.go
index 0776232..d50ee85 100644
--- a/driver/parser_test.go
+++ b/driver/parser_test.go
@@ -10,22 +10,22 @@ import (
"github.com/nihei9/vartan/spec"
)
-func TestParser_Parse(t *testing.T) {
- termNode := func(kind string, text string, children ...*Node) *Node {
- return &Node{
- KindName: kind,
- Text: text,
- Children: children,
- }
+func termNode(kind string, text string, children ...*Node) *Node {
+ return &Node{
+ KindName: kind,
+ Text: text,
+ Children: children,
}
+}
- nonTermNode := func(kind string, children ...*Node) *Node {
- return &Node{
- KindName: kind,
- Children: children,
- }
+func nonTermNode(kind string, children ...*Node) *Node {
+ return &Node{
+ KindName: kind,
+ Children: children,
}
+}
+func TestParser_Parse(t *testing.T) {
tests := []struct {
specSrc string
src string