Skip to content

Commit

Permalink
Support testable tree output in vartan-parse command
Browse files Browse the repository at this point in the history
  • Loading branch information
nihei9 committed May 29, 2022
1 parent ceb6649 commit 1ebed92
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 7 deletions.
24 changes: 20 additions & 4 deletions cmd/vartan/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/nihei9/vartan/driver"
spec "github.com/nihei9/vartan/spec/grammar"
"github.com/nihei9/vartan/tester"
"github.com/spf13/cobra"
)

Expand All @@ -17,9 +18,15 @@ var parseFlags = struct {
onlyParse *bool
cst *bool
disableLAC *bool
json *bool
format *string
}{}

const (
outputFormatText = "text"
outputFormatTree = "tree"
outputFormatJSON = "json"
)

func init() {
cmd := &cobra.Command{
Use: "parse <grammar file path>",
Expand All @@ -32,14 +39,19 @@ func init() {
parseFlags.onlyParse = cmd.Flags().Bool("only-parse", false, "when this option is enabled, the parser performs only parse and doesn't semantic actions")
parseFlags.cst = cmd.Flags().Bool("cst", false, "when this option is enabled, the parser generates a CST")
parseFlags.disableLAC = cmd.Flags().Bool("disable-lac", false, "disable LAC (lookahead correction)")
parseFlags.json = cmd.Flags().Bool("json", false, "enable JSON output")
parseFlags.format = cmd.Flags().StringP("format", "f", "text", "output format: one of text|tree|json")
rootCmd.AddCommand(cmd)
}

func runParse(cmd *cobra.Command, args []string) error {
if *parseFlags.onlyParse && *parseFlags.cst {
return fmt.Errorf("You cannot enable --only-parse and --cst at the same time")
}
if *parseFlags.format != outputFormatText &&
*parseFlags.format != outputFormatTree &&
*parseFlags.format != outputFormatJSON {
return fmt.Errorf("invalid output format: %v", *parseFlags.format)
}

cg, err := readCompiledGrammar(args[0])
if err != nil {
Expand Down Expand Up @@ -108,13 +120,17 @@ func runParse(cmd *cobra.Command, args []string) error {
tree = tb.Tree()
}
if tree != nil {
if *parseFlags.json {
switch *parseFlags.format {
case "tree":
b := tester.ConvertSyntaxTreeToTestableTree(tree).Format()
fmt.Fprintln(os.Stdout, string(b))
case "json":
b, err := json.Marshal(tree)
if err != nil {
return err
}
fmt.Fprintln(os.Stdout, string(b))
} else {
default:
driver.PrintTree(os.Stdout, tree)
}
}
Expand Down
24 changes: 24 additions & 0 deletions spec/test/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,30 @@ func (t *Tree) path() string {
return fmt.Sprintf("%v.[%v]%v", t.Parent.path(), t.Offset, t.Kind)
}

func (t *Tree) Format() []byte {
var b bytes.Buffer
t.format(&b, 0)
return b.Bytes()
}

func (t *Tree) format(buf *bytes.Buffer, depth int) {
for i := 0; i < depth; i++ {
buf.WriteString(" ")
}
buf.WriteString("(")
buf.WriteString(t.Kind)
if len(t.Children) > 0 {
buf.WriteString("\n")
for i, c := range t.Children {
c.format(buf, depth+1)
if i < len(t.Children)-1 {
buf.WriteString("\n")
}
}
}
buf.WriteString(")")
}

func DiffTree(expected, actual *Tree) []*TreeDiff {
if expected == nil && actual == nil {
return nil
Expand Down
19 changes: 19 additions & 0 deletions spec/test/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ import (
"testing"
)

func TestTree_Format(t *testing.T) {
expected := `(a
(b
(c))
(d)
(e))`
tree := NewTree("a",
NewTree("b",
NewTree("c"),
),
NewTree("d"),
NewTree("e"),
)
actual := string(tree.Format())
if actual != expected {
t.Fatalf("unexpected format:\n%v", actual)
}
}

func TestDiffTree(t *testing.T) {
tests := []struct {
t1 *Tree
Expand Down
6 changes: 3 additions & 3 deletions tester/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func runTest(g *gspec.CompiledGrammar, c *TestCaseWithMetadata) *TestResult {
}

// When a parse tree exists, the test continues regardless of whether or not syntax errors occurred.
diffs := tspec.DiffTree(genTree(tb.Tree()).Fill(), c.TestCase.Output)
diffs := tspec.DiffTree(ConvertSyntaxTreeToTestableTree(tb.Tree()).Fill(), c.TestCase.Output)
if len(diffs) > 0 {
return &TestResult{
TestCasePath: c.FilePath,
Expand All @@ -165,12 +165,12 @@ func runTest(g *gspec.CompiledGrammar, c *TestCaseWithMetadata) *TestResult {
}
}

func genTree(dTree *driver.Node) *tspec.Tree {
func ConvertSyntaxTreeToTestableTree(dTree *driver.Node) *tspec.Tree {
var children []*tspec.Tree
if len(dTree.Children) > 0 {
children = make([]*tspec.Tree, len(dTree.Children))
for i, c := range dTree.Children {
children[i] = genTree(c)
children[i] = ConvertSyntaxTreeToTestableTree(c)
}
}
return tspec.NewTree(dTree.KindName, children...)
Expand Down

0 comments on commit 1ebed92

Please sign in to comment.