aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2022-05-29 15:55:53 +0900
committerRyo Nihei <nihei.dev@gmail.com>2022-05-29 15:55:53 +0900
commit1ebed922b8c642b6ff4cec71820f24ceeb331c18 (patch)
tree08b71e6330b418d3d263264193262f489bba29b5
parentAdd vartan-test command (diff)
downloadcotia-1ebed922b8c642b6ff4cec71820f24ceeb331c18.tar.gz
cotia-1ebed922b8c642b6ff4cec71820f24ceeb331c18.tar.xz
Support testable tree output in vartan-parse command
-rw-r--r--cmd/vartan/parse.go24
-rw-r--r--spec/test/parser.go24
-rw-r--r--spec/test/parser_test.go19
-rw-r--r--tester/tester.go6
4 files changed, 66 insertions, 7 deletions
diff --git a/cmd/vartan/parse.go b/cmd/vartan/parse.go
index 2f06732..d1fc80e 100644
--- a/cmd/vartan/parse.go
+++ b/cmd/vartan/parse.go
@@ -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"
)
@@ -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>",
@@ -32,7 +39,7 @@ 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)
}
@@ -40,6 +47,11 @@ 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 {
@@ -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)
}
}
diff --git a/spec/test/parser.go b/spec/test/parser.go
index 0513ee3..175c89e 100644
--- a/spec/test/parser.go
+++ b/spec/test/parser.go
@@ -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
diff --git a/spec/test/parser_test.go b/spec/test/parser_test.go
index 6e77f6d..41b7189 100644
--- a/spec/test/parser_test.go
+++ b/spec/test/parser_test.go
@@ -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
diff --git a/tester/tester.go b/tester/tester.go
index ef3ca61..70d4800 100644
--- a/tester/tester.go
+++ b/tester/tester.go
@@ -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,
@@ -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...)