aboutsummaryrefslogtreecommitdiff
path: root/driver/conflict_test.go
blob: 750ed4e7f79a6c272346c88bd56a23a6b6ba87bf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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)
		})
	}
}