func TestWalk(t *testing.T) { g := ast.Grammar([]*ast.Production{ { Name: &ast.Name{Name: "E"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "T"}, &ast.Terminal{Terminal: "+"}, &ast.Name{Name: "T"}, }), &ast.Name{Name: "T"}, &ast.Epsilon{Epsilon: "e"}, }), }, { Name: &ast.Name{Name: "T"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Terminal{Terminal: "("}, &ast.Name{Name: "T"}, &ast.Terminal{Terminal: ")"}, }), &ast.Name{Name: "T"}, }), }, }) order := []string{ "ast.Grammar", "*ast.Production", "*ast.Name", "ast.Alternative", "ast.Sequence", "*ast.Name", "*ast.Terminal", "*ast.Name", "*ast.Name", "*ast.Epsilon", "*ast.Production", "*ast.Name", "ast.Alternative", "ast.Sequence", "*ast.Terminal", "*ast.Name", "*ast.Terminal", "*ast.Name", } i := 0 ast.Walk(func(n ast.Node) bool { if n == nil { return false } if typ := reflect.TypeOf(n).String(); order[i] != typ { t.Errorf("got %q want %q", typ, order[i]) } i++ return true }, g) }
func TestFprint(t *testing.T) { const expected = `Expr → Term "+" Expr | Term "-" Expr | Term | ε . Term → Factor "*" Term | Factor "/" Term | Factor . Factor → "(" Expr ")" | Number . Number → Digit | Digit Number . Digit → "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .` g := ast.Grammar([]*ast.Production{ { Name: &ast.Name{Name: "Expr"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "+"}, &ast.Name{Name: "Expr"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "-"}, &ast.Name{Name: "Expr"}, }), &ast.Name{Name: "Term"}, &ast.Epsilon{Epsilon: "e"}, }), }, { Name: &ast.Name{Name: "Term"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "*"}, &ast.Name{Name: "Term"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "/"}, &ast.Name{Name: "Term"}, }), &ast.Name{Name: "Factor"}, }), }, { Name: &ast.Name{Name: "Factor"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Terminal{Terminal: "("}, &ast.Name{Name: "Expr"}, &ast.Terminal{Terminal: ")"}, }), &ast.Name{Name: "Number"}, }), }, { Name: &ast.Name{Name: "Number"}, Expr: ast.Alternative([]ast.Expression{ &ast.Name{Name: "Digit"}, ast.Sequence([]ast.Expression{ &ast.Name{Name: "Digit"}, &ast.Name{Name: "Number"}, }), }), }, { Name: &ast.Name{Name: "Digit"}, Expr: ast.Alternative([]ast.Expression{ &ast.Terminal{Terminal: "0"}, &ast.Terminal{Terminal: "1"}, &ast.Terminal{Terminal: "2"}, &ast.Terminal{Terminal: "3"}, &ast.Terminal{Terminal: "4"}, &ast.Terminal{Terminal: "5"}, &ast.Terminal{Terminal: "6"}, &ast.Terminal{Terminal: "7"}, &ast.Terminal{Terminal: "8"}, &ast.Terminal{Terminal: "9"}, }), }, }) var buf bytes.Buffer if err := printer.Fprint(&buf, g); err != nil { t.Errorf("error: %v", err) } if actual := buf.String(); actual != expected { t.Errorf("got\n'%s'\nwant\n'%s'", actual, expected) } }
func TestParse(t *testing.T) { const src = `Start -> Expr. Expr → Term "+" Expr | Term "-" Expr | Term | ε. Term → Factor "*" Term | Factor "/" Term | Factor . Factor → "(" Expr ")" | Number . Number → Digit | Digit Number . Digit → "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .` expected := ast.Grammar([]*ast.Production{ { Name: &ast.Name{Name: "Start"}, Expr: &ast.Name{Name: "Expr"}, }, { Name: &ast.Name{Name: "Expr"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "+"}, &ast.Name{Name: "Expr"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "-"}, &ast.Name{Name: "Expr"}, }), &ast.Name{Name: "Term"}, &ast.Epsilon{Epsilon: "ε"}, }), }, { Name: &ast.Name{Name: "Term"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "*"}, &ast.Name{Name: "Term"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "/"}, &ast.Name{Name: "Term"}, }), &ast.Name{Name: "Factor"}, }), }, { Name: &ast.Name{Name: "Factor"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Terminal{Terminal: "("}, &ast.Name{Name: "Expr"}, &ast.Terminal{Terminal: ")"}, }), &ast.Name{Name: "Number"}, }), }, { Name: &ast.Name{Name: "Number"}, Expr: ast.Alternative([]ast.Expression{ &ast.Name{Name: "Digit"}, ast.Sequence([]ast.Expression{ &ast.Name{Name: "Digit"}, &ast.Name{Name: "Number"}, }), }), }, { Name: &ast.Name{Name: "Digit"}, Expr: ast.Alternative([]ast.Expression{ &ast.Terminal{Terminal: "0"}, &ast.Terminal{Terminal: "1"}, &ast.Terminal{Terminal: "2"}, &ast.Terminal{Terminal: "3"}, &ast.Terminal{Terminal: "4"}, &ast.Terminal{Terminal: "5"}, &ast.Terminal{Terminal: "6"}, &ast.Terminal{Terminal: "7"}, &ast.Terminal{Terminal: "8"}, &ast.Terminal{Terminal: "9"}, }), }, }) g, err := parser.Parse([]byte(src), "test") if err != nil { t.Errorf("error: %v", err) } check(t, g, expected) }
var testGrammar = ast.Grammar([]*ast.Production{ { Name: &ast.Name{Name: "E"}, Expr: ast.Alternative([]ast.Expression{ &ast.Name{Name: "T"}, ast.Sequence([]ast.Expression{ &ast.Name{Name: "E"}, &ast.Terminal{Terminal: "+"}, &ast.Name{Name: "T"}, }), }), }, { Name: &ast.Name{Name: "T"}, Expr: ast.Alternative([]ast.Expression{ &ast.Name{Name: "F"}, ast.Sequence([]ast.Expression{ &ast.Name{Name: "T"}, &ast.Terminal{Terminal: "*"}, &ast.Name{Name: "F"}, }), }), }, { Name: &ast.Name{Name: "F"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Terminal{Terminal: "("}, &ast.Name{Name: "E"}, &ast.Terminal{Terminal: ")"}, }), &ast.Terminal{Terminal: "id"}, }), }, })