Merge branch 'master' into errors
This commit is contained in:
commit
5d242cff86
212
format_test.go
212
format_test.go
@ -1,18 +1,62 @@
|
|||||||
package treerack
|
package treerack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCharFormat(t *testing.T) {
|
type formatDefinitionTestItem struct {
|
||||||
type testItem struct {
|
|
||||||
title string
|
title string
|
||||||
definition string
|
definition string
|
||||||
|
syntax string
|
||||||
output string
|
output string
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDefinitionFormatItem(t *testing.T, treerack *Syntax, f formatFlags, test formatDefinitionTestItem) func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
syntax := test.syntax
|
||||||
|
if test.definition != "" {
|
||||||
|
syntax = fmt.Sprintf("def = %s", test.definition)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range []testItem{{
|
nodes, err := treerack.Parse(bytes.NewBufferString(syntax))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &Syntax{}
|
||||||
|
if err := define(s, nodes); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
def, ok := s.registry.definition("def")
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("failed to register definition")
|
||||||
|
}
|
||||||
|
|
||||||
|
output := def.format(s.registry, f)
|
||||||
|
if output != test.output {
|
||||||
|
t.Error("invalid definition format")
|
||||||
|
t.Log("got: ", output)
|
||||||
|
t.Log("expected:", test.output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDefinitionFormat(t *testing.T, f formatFlags, tests []formatDefinitionTestItem) {
|
||||||
|
treerack, err := bootSyntax()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.title, testDefinitionFormatItem(t, treerack, f, test))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCharFormat(t *testing.T) {
|
||||||
|
testDefinitionFormat(t, formatNone, []formatDefinitionTestItem{{
|
||||||
title: "empty",
|
title: "empty",
|
||||||
definition: "[]",
|
definition: "[]",
|
||||||
output: "[]",
|
output: "[]",
|
||||||
@ -56,37 +100,11 @@ func TestCharFormat(t *testing.T) {
|
|||||||
title: "range and char mixed",
|
title: "range and char mixed",
|
||||||
definition: "[a-z_\\-A-Z]",
|
definition: "[a-z_\\-A-Z]",
|
||||||
output: "[_\\-a-zA-Z]",
|
output: "[_\\-a-zA-Z]",
|
||||||
}} {
|
}})
|
||||||
t.Run(test.title, func(t *testing.T) {
|
|
||||||
defString := fmt.Sprintf("def = %s", test.definition)
|
|
||||||
s, err := openSyntaxString(defString)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
def, ok := s.registry.definition(childName("def", 0))
|
|
||||||
if !ok {
|
|
||||||
t.Error("invalid syntax")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
output := def.format(s.registry, formatNone)
|
|
||||||
if output != test.output {
|
|
||||||
t.Error("invalid output", output, test.output)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSequenceFormat(t *testing.T) {
|
func TestSequenceFormat(t *testing.T) {
|
||||||
type testItem struct {
|
testDefinitionFormat(t, formatNone, []formatDefinitionTestItem{{
|
||||||
title string
|
|
||||||
syntax string
|
|
||||||
output string
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range []testItem{{
|
|
||||||
title: "empty char sequence",
|
title: "empty char sequence",
|
||||||
syntax: `def = ""`,
|
syntax: `def = ""`,
|
||||||
output: `""`,
|
output: `""`,
|
||||||
@ -103,92 +121,110 @@ func TestSequenceFormat(t *testing.T) {
|
|||||||
syntax: `def = "abc" [a-z]`,
|
syntax: `def = "abc" [a-z]`,
|
||||||
output: `"abc" [a-z]`,
|
output: `"abc" [a-z]`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, 0-or-more",
|
title: "quantifiers, 0-or-more, single char",
|
||||||
syntax: `def = "a"*`,
|
syntax: `def = "a"*`,
|
||||||
output: `"a"*`,
|
output: `[a]*`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, 0-or-more",
|
||||||
|
syntax: `def = "abc"*`,
|
||||||
|
output: `"abc"*`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, 1-or-more, single char",
|
||||||
|
syntax: `def = "a"+`,
|
||||||
|
output: `[a]+`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, 1-or-more",
|
title: "quantifiers, 1-or-more",
|
||||||
syntax: `def = "a"+`,
|
syntax: `def = "abc"+`,
|
||||||
output: `"a"+`,
|
output: `"abc"+`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, 0-or-one, single char",
|
||||||
|
syntax: `def = "a"?`,
|
||||||
|
output: `[a]?`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, 0-or-one",
|
title: "quantifiers, 0-or-one",
|
||||||
syntax: `def = "a"?`,
|
syntax: `def = "abc"?`,
|
||||||
output: `"a"?`,
|
output: `"abc"?`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, exact number, single char",
|
||||||
|
syntax: `def = "a"{3}`,
|
||||||
|
output: `[a]{3}`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, exact number",
|
title: "quantifiers, exact number",
|
||||||
syntax: `def = "a"{3}`,
|
syntax: `def = "abc"{3}`,
|
||||||
output: `"a"{3}`,
|
output: `"abc"{3}`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, max, single char",
|
||||||
|
syntax: `def = "a"{0, 3}`,
|
||||||
|
output: `[a]{,3}`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, max",
|
title: "quantifiers, max",
|
||||||
syntax: `def = "a"{0, 3}`,
|
syntax: `def = "abc"{0, 3}`,
|
||||||
output: `"a"{,3}`,
|
output: `"abc"{,3}`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, min, single char",
|
||||||
|
syntax: `def = "a"{3,}`,
|
||||||
|
output: `[a]{3,}`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, min",
|
title: "quantifiers, min",
|
||||||
syntax: `def = "a"{3,}`,
|
syntax: `def = "abc"{3,}`,
|
||||||
output: `"a"{3,}`,
|
output: `"abc"{3,}`,
|
||||||
|
}, {
|
||||||
|
title: "quantifiers, range, single char",
|
||||||
|
syntax: `def = "a"{3, 9}`,
|
||||||
|
output: `[a]{3,9}`,
|
||||||
}, {
|
}, {
|
||||||
title: "quantifiers, range",
|
title: "quantifiers, range",
|
||||||
syntax: `def = "a"{3, 9}`,
|
syntax: `def = "abc"{3, 9}`,
|
||||||
output: `"a"{3,9}`,
|
output: `"abc"{3,9}`,
|
||||||
}, {
|
}, {
|
||||||
title: "symbols",
|
title: "symbols",
|
||||||
syntax: `a = "a"; b = "b"; c = "c"; def = a b c`,
|
syntax: `a = "a"; b = "b"; c = "c"; def = a b c`,
|
||||||
output: "a b c",
|
output: "a b c",
|
||||||
}, {
|
}, {
|
||||||
title: "choice in sequence",
|
title: "choice in sequence, single char",
|
||||||
syntax: `def = "a" ("b" | "c")`,
|
syntax: `def = "a" ("b" | "c")`,
|
||||||
output: `"a" ("b" | "c")`,
|
output: `[a] ([b] | [c])`,
|
||||||
|
}, {
|
||||||
|
title: "choice in sequence",
|
||||||
|
syntax: `def = "abc" ("def" | "ghi")`,
|
||||||
|
output: `"abc" ("def" | "ghi")`,
|
||||||
|
}, {
|
||||||
|
title: "grouped quantifier, single char",
|
||||||
|
syntax: `def = ("a" "b"){3}`,
|
||||||
|
output: `([a] [b]){3}`,
|
||||||
}, {
|
}, {
|
||||||
title: "grouped quantifier",
|
title: "grouped quantifier",
|
||||||
syntax: `def = ("a" "b"){3}`,
|
syntax: `def = ("abc" "def"){3}`,
|
||||||
output: `("a" "b"){3}`,
|
output: `("abc" "def"){3}`,
|
||||||
}} {
|
}})
|
||||||
t.Run(test.title, func(t *testing.T) {
|
|
||||||
s, err := openSyntaxString(test.syntax)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
output := s.root.format(s.registry, formatNone)
|
|
||||||
if output != test.output {
|
|
||||||
t.Error("invalid output", output, test.output)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChoiceFormat(t *testing.T) {
|
func TestChoiceFormat(t *testing.T) {
|
||||||
type testItem struct {
|
testDefinitionFormat(t, formatNone, []formatDefinitionTestItem{{
|
||||||
title string
|
title: "choice of char sequences, single char",
|
||||||
syntax string
|
|
||||||
output string
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range []testItem{{
|
|
||||||
title: "choice of char sequences",
|
|
||||||
syntax: `def = "a" | "b" | "c"`,
|
syntax: `def = "a" | "b" | "c"`,
|
||||||
output: `"a" | "b" | "c"`,
|
output: `[a] | [b] | [c]`,
|
||||||
|
}, {
|
||||||
|
title: "choice of char sequences",
|
||||||
|
syntax: `def = "abc" | "def" | "ghi"`,
|
||||||
|
output: `"abc" | "def" | "ghi"`,
|
||||||
|
}, {
|
||||||
|
title: "choice of inline sequences, single char",
|
||||||
|
syntax: `def = "a" "b" | "c" "d" | "e" "f"`,
|
||||||
|
output: `[a] [b] | [c] [d] | [e] [f]`,
|
||||||
}, {
|
}, {
|
||||||
title: "choice of inline sequences",
|
title: "choice of inline sequences",
|
||||||
syntax: `def = "a" "b" | "c" "d" | "e" "f"`,
|
syntax: `def = "abc" "def" | "ghi" "jkl" | "mno" "pqr"`,
|
||||||
output: `"a" "b" | "c" "d" | "e" "f"`,
|
output: `"abc" "def" | "ghi" "jkl" | "mno" "pqr"`,
|
||||||
}, {
|
}, {
|
||||||
title: "choice of symbol",
|
title: "choice of symbol",
|
||||||
syntax: `a = "a"; b = "b"; c = "c"; def = a | b | c`,
|
syntax: `a = "a"; b = "b"; c = "c"; def = a | b | c`,
|
||||||
output: "a | b | c",
|
output: "a | b | c",
|
||||||
}} {
|
}})
|
||||||
t.Run(test.title, func(t *testing.T) {
|
}
|
||||||
s, err := openSyntaxString(test.syntax)
|
|
||||||
if err != nil {
|
func TestMultiLine(t *testing.T) {
|
||||||
t.Error(err)
|
}
|
||||||
return
|
|
||||||
}
|
func TestLineSplit(t *testing.T) {
|
||||||
|
|
||||||
output := s.root.format(s.registry, formatNone)
|
|
||||||
if output != test.output {
|
|
||||||
t.Error("invalid output", output, test.output)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,9 @@ test error report on invalid flag
|
|||||||
|
|
||||||
[optimization]
|
[optimization]
|
||||||
try preallocate larger store chunks
|
try preallocate larger store chunks
|
||||||
|
notes in formatting
|
||||||
|
format: test back and forth equivalence of char classes
|
||||||
|
format: test comments, first apply comments in the syntax
|
||||||
|
|
||||||
[problems]
|
[problems]
|
||||||
can the root be an alias? check the commit mechanism
|
can the root be an alias? check the commit mechanism
|
||||||
|
@ -202,6 +202,12 @@ func (d *sequenceDefinition) isCharSequence(r *registry) bool {
|
|||||||
|
|
||||||
func (d *sequenceDefinition) format(r *registry, f formatFlags) string {
|
func (d *sequenceDefinition) format(r *registry, f formatFlags) string {
|
||||||
if d.isCharSequence(r) {
|
if d.isCharSequence(r) {
|
||||||
|
if len(d.originalItems) == 1 {
|
||||||
|
itemDef, _ := r.definition(d.originalItems[0].Name)
|
||||||
|
c, _ := itemDef.(*charParser)
|
||||||
|
return c.format(r, f)
|
||||||
|
}
|
||||||
|
|
||||||
var chars []rune
|
var chars []rune
|
||||||
for i := range d.originalItems {
|
for i := range d.originalItems {
|
||||||
itemDef, _ := r.definition(d.originalItems[i].Name)
|
itemDef, _ := r.definition(d.originalItems[i].Name)
|
||||||
|
@ -25,6 +25,7 @@ type formatFlags int
|
|||||||
const (
|
const (
|
||||||
formatNone formatFlags = 0
|
formatNone formatFlags = 0
|
||||||
formatPretty formatFlags = 1 << iota
|
formatPretty formatFlags = 1 << iota
|
||||||
|
formatIncludeComments
|
||||||
)
|
)
|
||||||
|
|
||||||
// if min=0&&max=0, it means min=1,max=1
|
// if min=0&&max=0, it means min=1,max=1
|
||||||
|
Loading…
Reference in New Issue
Block a user