1
0

replace Node pointers with values

This commit is contained in:
Arpad Ryszka 2026-06-01 22:26:27 +02:00
parent f61ea7dac7
commit 76ebeb0948
27 changed files with 1070 additions and 1077 deletions

View File

@ -6,15 +6,15 @@ import (
"testing" "testing"
) )
func parseWithSyntax(s *Syntax, f io.ReadSeeker) (*Node, error) { func parseWithSyntax(s *Syntax, f io.ReadSeeker) (Node, error) {
if _, err := f.Seek(0, 0); err != nil { if _, err := f.Seek(0, 0); err != nil {
return nil, err return Node{}, err
} }
return s.Parse(f) return s.Parse(f)
} }
func syntaxFromTree(n *Node) (*Syntax, error) { func syntaxFromTree(n Node) (*Syntax, error) {
s := &Syntax{} s := &Syntax{}
if err := define(s, n); err != nil { if err := define(s, n); err != nil {
return nil, err return nil, err
@ -27,17 +27,17 @@ func syntaxFromTree(n *Node) (*Syntax, error) {
return s, nil return s, nil
} }
func testParseFromTree(t *testing.T, n *Node, f io.ReadSeeker) *Node { func testParseFromTree(t *testing.T, n Node, f io.ReadSeeker) Node {
s, err := syntaxFromTree(n) s, err := syntaxFromTree(n)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return nil return Node{}
} }
nn, err := parseWithSyntax(s, f) nn, err := parseWithSyntax(s, f)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return nil return Node{}
} }
checkNode(t, false, nn, n) checkNode(t, false, nn, n)

View File

@ -54,6 +54,6 @@ func (p *charParser) parse(c *context) {
func (b *charBuilder) nodeName() string { return b.name } func (b *charBuilder) nodeName() string { return b.name }
func (b *charBuilder) nodeID() int { return b.id } func (b *charBuilder) nodeID() int { return b.id }
func (b *charBuilder) build(c *context) ([]*Node, bool) { func (b *charBuilder) build(c *context) ([]Node, bool) {
return nil, false return nil, false
} }

View File

@ -2,7 +2,7 @@ package treerack
import "testing" import "testing"
func checkNodes(t *testing.T, ignorePosition bool, left, right []*Node) { func checkNodes(t *testing.T, ignorePosition bool, left, right []Node) {
if len(left) != len(right) { if len(left) != len(right) {
t.Error("length doesn't match", len(left), len(right)) t.Error("length doesn't match", len(left), len(right))
t.Log(left) t.Log(left)
@ -20,16 +20,7 @@ func checkNodes(t *testing.T, ignorePosition bool, left, right []*Node) {
} }
} }
func checkNode(t *testing.T, ignorePosition bool, left, right *Node) { func checkNode(t *testing.T, ignorePosition bool, left, right Node) {
if (left == nil) != (right == nil) {
t.Error("nil reference doesn't match", left == nil, right == nil)
return
}
if left == nil {
return
}
if left.Name != right.Name { if left.Name != right.Name {
t.Error("name doesn't match", left.Name, right.Name) t.Error("name doesn't match", left.Name, right.Name)
return return

View File

@ -126,7 +126,7 @@ func (p *choiceParser) parse(c *context) {
func (b *choiceBuilder) nodeName() string { return b.name } func (b *choiceBuilder) nodeName() string { return b.name }
func (b *choiceBuilder) nodeID() int { return b.id } func (b *choiceBuilder) nodeID() int { return b.id }
func (b *choiceBuilder) build(c *context) ([]*Node, bool) { func (b *choiceBuilder) build(c *context) ([]Node, bool) {
to, ok := c.results.longestMatch(c.offset, b.id) to, ok := c.results.longestMatch(c.offset, b.id)
if !ok { if !ok {
return nil, false return nil, false
@ -171,7 +171,7 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
return n, true return n, true
} }
return []*Node{{ return []Node{{
Name: b.name, Name: b.name,
From: from, From: from,
To: to, To: to,

View File

@ -35,7 +35,7 @@ type node struct {
Nodes []node `json:"nodes,omitempty"` Nodes []node `json:"nodes,omitempty"`
} }
func mapNode(n *treerack.Node) node { func mapNode(n treerack.Node) node {
var nn node var nn node
nn.Name = n.Name nn.Name = n.Name
nn.From = n.From nn.From = n.From

View File

@ -2,15 +2,13 @@ package treerack
import "strconv" import "strconv"
func dropComments(n *Node) *Node { func dropComments(n Node) Node {
ncc := *n n.Nodes = filterNodes(func(n Node) bool { return n.Name != "comment" }, n.Nodes)
nc := &ncc n.Nodes = mapNodes(dropComments, n.Nodes)
nc.Nodes = filterNodes(func(n *Node) bool { return n.Name != "comment" }, n.Nodes) return n
nc.Nodes = mapNodes(dropComments, nc.Nodes)
return nc
} }
func flagsToCommitType(n []*Node) CommitType { func flagsToCommitType(n []Node) CommitType {
var ct CommitType var ct CommitType
for _, ni := range n { for _, ni := range n {
switch ni.Name { switch ni.Name {
@ -38,7 +36,7 @@ func toRune(c string) rune {
return []rune(c)[0] return []rune(c)[0]
} }
func nodeChar(n *Node) rune { func nodeChar(n Node) rune {
s := n.Text() s := n.Text()
if s[0] == '\\' { if s[0] == '\\' {
return unescapeChar(toRune(s[1:])) return unescapeChar(toRune(s[1:]))
@ -47,7 +45,7 @@ func nodeChar(n *Node) rune {
return toRune(s) return toRune(s)
} }
func defineMember(s *Syntax, defaultName string, ct CommitType, n *Node) (string, error) { func defineMember(s *Syntax, defaultName string, ct CommitType, n Node) (string, error) {
switch n.Name { switch n.Name {
case "symbol": case "symbol":
return n.Text(), nil return n.Text(), nil
@ -56,7 +54,7 @@ func defineMember(s *Syntax, defaultName string, ct CommitType, n *Node) (string
} }
} }
func defineClass(s *Syntax, name string, ct CommitType, n []*Node) error { func defineClass(s *Syntax, name string, ct CommitType, n []Node) error {
var ( var (
not bool not bool
chars []rune chars []rune
@ -79,7 +77,7 @@ func defineClass(s *Syntax, name string, ct CommitType, n []*Node) error {
return s.class(name, ct, not, chars, ranges) return s.class(name, ct, not, chars, ranges)
} }
func defineCharSequence(s *Syntax, name string, ct CommitType, charNodes []*Node) error { func defineCharSequence(s *Syntax, name string, ct CommitType, charNodes []Node) error {
var chars []rune var chars []rune
for _, ci := range charNodes { for _, ci := range charNodes {
chars = append(chars, nodeChar(ci)) chars = append(chars, nodeChar(ci))
@ -88,7 +86,7 @@ func defineCharSequence(s *Syntax, name string, ct CommitType, charNodes []*Node
return s.charSequence(name, ct, chars) return s.charSequence(name, ct, chars)
} }
func getQuantity(n *Node) (min int, max int, err error) { func getQuantity(n Node) (min int, max int, err error) {
switch n.Name { switch n.Name {
case "count-quantifier": case "count-quantifier":
min, err = strconv.Atoi(n.Nodes[0].Text()) min, err = strconv.Atoi(n.Nodes[0].Text())
@ -125,11 +123,11 @@ func getQuantity(n *Node) (min int, max int, err error) {
return return
} }
func defineSymbol(s *Syntax, name string, ct CommitType, n *Node) error { func defineSymbol(s *Syntax, name string, ct CommitType, n Node) error {
return s.sequence(name, ct, SequenceItem{Name: n.Text()}) return s.sequence(name, ct, SequenceItem{Name: n.Text()})
} }
func defineSequence(s *Syntax, name string, ct CommitType, n ...*Node) error { func defineSequence(s *Syntax, name string, ct CommitType, n ...Node) error {
nows := ct & NoWhitespace nows := ct & NoWhitespace
var items []SequenceItem var items []SequenceItem
for i, ni := range n { for i, ni := range n {
@ -157,7 +155,7 @@ func defineSequence(s *Syntax, name string, ct CommitType, n ...*Node) error {
return s.sequence(name, ct, items...) return s.sequence(name, ct, items...)
} }
func defineChoice(s *Syntax, name string, ct CommitType, n ...*Node) error { func defineChoice(s *Syntax, name string, ct CommitType, n ...Node) error {
var refs []string var refs []string
memberCT := ct&NoWhitespace | Alias memberCT := ct&NoWhitespace | Alias
for i, ni := range n { for i, ni := range n {
@ -173,7 +171,7 @@ func defineChoice(s *Syntax, name string, ct CommitType, n ...*Node) error {
return s.choice(name, ct, refs...) return s.choice(name, ct, refs...)
} }
func defineExpression(s *Syntax, name string, ct CommitType, expression *Node) error { func defineExpression(s *Syntax, name string, ct CommitType, expression Node) error {
var err error var err error
switch expression.Name { switch expression.Name {
case "any-char": case "any-char":
@ -193,7 +191,7 @@ func defineExpression(s *Syntax, name string, ct CommitType, expression *Node) e
return err return err
} }
func addDefinition(s *Syntax, n *Node) error { func addDefinition(s *Syntax, n Node) error {
return defineExpression( return defineExpression(
s, s,
n.Nodes[0].Text(), n.Nodes[0].Text(),
@ -202,7 +200,7 @@ func addDefinition(s *Syntax, n *Node) error {
) )
} }
func define(s *Syntax, syntaxTree *Node) error { func define(s *Syntax, syntaxTree Node) error {
syntaxTree = dropComments(syntaxTree) syntaxTree = dropComments(syntaxTree)
for _, n := range syntaxTree.Nodes { for _, n := range syntaxTree.Nodes {
if err := addDefinition(s, n); err != nil { if err := addDefinition(s, n); err != nil {

View File

@ -22,14 +22,14 @@ const (
type formatItem struct { type formatItem struct {
commentFormat commentFormat commentFormat commentFormat
node *Node node Node
} }
type formatGroup struct { type formatGroup struct {
items []formatItem items []formatItem
} }
func topLevelCommentFormat(ast *Node, i int, n *Node) commentFormat { func topLevelCommentFormat(ast Node, i int, n Node) commentFormat {
if n.Name != "comment" { if n.Name != "comment" {
return commentFormatNone return commentFormatNone
} }
@ -64,7 +64,7 @@ func topLevelCommentFormat(ast *Node, i int, n *Node) commentFormat {
return headerComment return headerComment
} }
func groupASTByComments(ast *Node) []formatGroup { func groupASTByComments(ast Node) []formatGroup {
var ( var (
groups []formatGroup groups []formatGroup
currentGroup formatGroup currentGroup formatGroup
@ -174,7 +174,7 @@ func trimComment(text string, withBlockBody bool) string {
return strings.Join(lines, "\n") return strings.Join(lines, "\n")
} }
func formatComment(out io.Writer, n *Node, withBlockBody bool) error { func formatComment(out io.Writer, n Node, withBlockBody bool) error {
text := n.Text() text := n.Text()
text = trimComment(text, withBlockBody) text = trimComment(text, withBlockBody)
_, err := fmt.Fprint(out, text) _, err := fmt.Fprint(out, text)
@ -221,17 +221,17 @@ func formatAnyChar(out io.Writer) error {
return err return err
} }
func formatCharClass(out io.Writer, n *Node) error { func formatCharClass(out io.Writer, n Node) error {
_, err := fmt.Fprint(out, n.Text()) _, err := fmt.Fprint(out, n.Text())
return err return err
} }
func formatCharSequence(out io.Writer, n *Node) error { func formatCharSequence(out io.Writer, n Node) error {
_, err := fmt.Fprint(out, n.Text()) _, err := fmt.Fprint(out, n.Text())
return err return err
} }
func formatSymbol(out io.Writer, n *Node) error { func formatSymbol(out io.Writer, n Node) error {
_, err := fmt.Fprint(out, n.Text()) _, err := fmt.Fprint(out, n.Text())
return err return err
} }
@ -249,7 +249,7 @@ func decTargetWidth(w, by int) int {
return w return w
} }
func formatSequenceItemNode(out io.Writer, targetWidth int, n *Node) error { func formatSequenceItemNode(out io.Writer, targetWidth int, n Node) error {
var ( var (
min, max int min, max int
err error err error
@ -345,7 +345,7 @@ func formatSequenceItemNode(out io.Writer, targetWidth int, n *Node) error {
return err return err
} }
func formatSequenceItemNodes(out io.Writer, targetWidth int, n []*Node) error { func formatSequenceItemNodes(out io.Writer, targetWidth int, n []Node) error {
sep := " " sep := " "
if targetWidth >= 0 { if targetWidth >= 0 {
sep = "\n " sep = "\n "
@ -374,7 +374,7 @@ func formatSequenceItemNodes(out io.Writer, targetWidth int, n []*Node) error {
return nil return nil
} }
func formatSequence(out io.Writer, targetWidth int, n []*Node) error { func formatSequence(out io.Writer, targetWidth int, n []Node) error {
var hasComments bool var hasComments bool
for _, ni := range n { for _, ni := range n {
if ni.Name == "comment" { if ni.Name == "comment" {
@ -403,7 +403,7 @@ func formatSequence(out io.Writer, targetWidth int, n []*Node) error {
return err return err
} }
func formatChoiceOptionNodes(out io.Writer, targetWidth int, n []*Node) error { func formatChoiceOptionNodes(out io.Writer, targetWidth int, n []Node) error {
sep, commentSep := " | ", " " sep, commentSep := " | ", " "
if targetWidth >= 0 { if targetWidth >= 0 {
sep, commentSep = "\n| ", "\n" sep, commentSep = "\n| ", "\n"
@ -438,7 +438,7 @@ func formatChoiceOptionNodes(out io.Writer, targetWidth int, n []*Node) error {
return nil return nil
} }
func formatChoice(out io.Writer, targetWidth int, n []*Node) error { func formatChoice(out io.Writer, targetWidth int, n []Node) error {
var hasComments bool var hasComments bool
for _, ni := range n { for _, ni := range n {
if ni.Name == "comment" { if ni.Name == "comment" {
@ -467,7 +467,7 @@ func formatChoice(out io.Writer, targetWidth int, n []*Node) error {
return err return err
} }
func formatExpression(out io.Writer, targetWidth int, n *Node) error { func formatExpression(out io.Writer, targetWidth int, n Node) error {
var err error var err error
switch n.Name { switch n.Name {
case "comment": case "comment":
@ -489,7 +489,7 @@ func formatExpression(out io.Writer, targetWidth int, n *Node) error {
return err return err
} }
func formatDefinition(out io.Writer, targetWidth, namesWidth int, pad, name string, n *Node) error { func formatDefinition(out io.Writer, targetWidth, namesWidth int, pad, name string, n Node) error {
var ( var (
buf bytes.Buffer buf bytes.Buffer
foundComment bool foundComment bool
@ -616,7 +616,7 @@ func formatASTGroup(out io.Writer, g formatGroup) error {
return nil return nil
} }
func formatAST(out io.Writer, ast *Node) error { func formatAST(out io.Writer, ast Node) error {
// drop whitespace comments // drop whitespace comments
// use line comments by default // use line comments by default
// comment types: // comment types:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -83,7 +83,7 @@ func (b *charBuilder) nodeName() string {
func (b *charBuilder) nodeID() int { func (b *charBuilder) nodeID() int {
return b.id return b.id
} }
func (b *charBuilder) build(c *context) ([]*Node, bool) { func (b *charBuilder) build(c *context) ([]Node, bool) {
return nil, false return nil, false
} }
@ -199,7 +199,7 @@ func (b *sequenceBuilder) nodeName() string {
func (b *sequenceBuilder) nodeID() int { func (b *sequenceBuilder) nodeID() int {
return b.id return b.id
} }
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { func (b *sequenceBuilder) build(c *context) ([]Node, bool) {
to, ok := c.results.longestMatch(c.offset, b.id) to, ok := c.results.longestMatch(c.offset, b.id)
if !ok { if !ok {
return nil, false return nil, false
@ -211,7 +211,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
if b.commit&Alias != 0 { if b.commit&Alias != 0 {
return nil, true return nil, true
} }
return []*Node{{Name: b.name, From: from, To: to, tokens: c.tokens}}, true return []Node{{Name: b.name, From: from, To: to, tokens: c.tokens}}, true
} else if parsed { } else if parsed {
c.results.dropMatchTo(c.offset, b.id, to) c.results.dropMatchTo(c.offset, b.id, to)
for _, g := range b.generalizations { for _, g := range b.generalizations {
@ -229,7 +229,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
var ( var (
itemIndex int itemIndex int
currentCount int currentCount int
nodes []*Node nodes []Node
) )
for itemIndex < len(b.items) { for itemIndex < len(b.items) {
itemFrom := c.offset itemFrom := c.offset
@ -265,7 +265,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
if b.commit&Alias != 0 { if b.commit&Alias != 0 {
return nodes, true return nodes, true
} }
return []*Node{{Name: b.name, From: from, To: to, Nodes: nodes, tokens: c.tokens}}, true return []Node{{Name: b.name, From: from, To: to, Nodes: nodes, tokens: c.tokens}}, true
} }
type choiceParser struct { type choiceParser struct {
@ -378,7 +378,7 @@ func (b *choiceBuilder) nodeName() string {
func (b *choiceBuilder) nodeID() int { func (b *choiceBuilder) nodeID() int {
return b.id return b.id
} }
func (b *choiceBuilder) build(c *context) ([]*Node, bool) { func (b *choiceBuilder) build(c *context) ([]Node, bool) {
to, ok := c.results.longestMatch(c.offset, b.id) to, ok := c.results.longestMatch(c.offset, b.id)
if !ok { if !ok {
return nil, false return nil, false
@ -416,7 +416,7 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
if b.commit&Alias != 0 { if b.commit&Alias != 0 {
return n, true return n, true
} }
return []*Node{{Name: b.name, From: from, To: to, Nodes: n, tokens: c.tokens}}, true return []Node{{Name: b.name, From: from, To: to, Nodes: n, tokens: c.tokens}}, true
} }
type idSet struct{ ids []uint } type idSet struct{ ids []uint }
@ -733,19 +733,19 @@ func (c *context) finalizeParse(root parser) error {
type Node struct { type Node struct {
Name string Name string
Nodes []*Node Nodes []Node
From int From int
To int To int
tokens []rune tokens []rune
} }
func (n *Node) Tokens() []rune { func (n Node) Tokens() []rune {
return n.tokens return n.tokens
} }
func (n *Node) String() string { func (n Node) String() string {
return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text()) return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text())
} }
func (n *Node) Text() string { func (n Node) Text() string {
return string(n.Tokens()[n.From:n.To]) return string(n.Tokens()[n.From:n.To])
} }
@ -791,7 +791,7 @@ type parser interface {
type builder interface { type builder interface {
nodeName() string nodeName() string
nodeID() int nodeID() int
build(*context) ([]*Node, bool) build(*context) ([]Node, bool)
} }
var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character") var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character")
@ -799,17 +799,17 @@ var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character")
func (pe *ParseError) Error() string { func (pe *ParseError) Error() string {
return fmt.Sprintf("%s:%d:%d:parse failed, parsing: %s", pe.Input, pe.Line+1, pe.Column+1, pe.Definition) return fmt.Sprintf("%s:%d:%d:parse failed, parsing: %s", pe.Input, pe.Line+1, pe.Column+1, pe.Definition)
} }
func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) { func parseInput(r io.Reader, p parser, b builder, kw []parser) (Node, error) {
c := newContext(bufio.NewReader(r), kw) c := newContext(bufio.NewReader(r), kw)
p.parse(c) p.parse(c)
if c.readErr != nil { if c.readErr != nil {
return nil, c.readErr return Node{}, c.readErr
} }
if err := c.finalizeParse(p); err != nil { if err := c.finalizeParse(p); err != nil {
if perr, ok := err.(*ParseError); ok { if perr, ok := err.(*ParseError); ok {
perr.Input = "<input>" perr.Input = "<input>"
} }
return nil, err return Node{}, err
} }
c.offset = 0 c.offset = 0
c.results.resetPending() c.results.resetPending()
@ -819,7 +819,7 @@ func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) {
// eo head // eo head
func Parse(r io.Reader) (*Node, error) { func Parse(r io.Reader) (Node, error) {
var p172 = sequenceParser{id: 172, commit: 128, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var p172 = sequenceParser{id: 172, commit: 128, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}}
var p170 = choiceParser{id: 170, commit: 2} var p170 = choiceParser{id: 170, commit: 2}

View File

@ -142,7 +142,7 @@ func parseJSONNumber(t string) (interface{}, error) {
return n.Float64() return n.Float64()
} }
func nodeToJSONObject(n *Node) (map[string]interface{}, error) { func nodeToJSONObject(n Node) (map[string]interface{}, error) {
o := make(map[string]interface{}) o := make(map[string]interface{})
for _, ni := range n.Nodes { for _, ni := range n.Nodes {
if len(ni.Nodes) != 2 { if len(ni.Nodes) != 2 {
@ -165,7 +165,7 @@ func nodeToJSONObject(n *Node) (map[string]interface{}, error) {
return o, nil return o, nil
} }
func nodeToJSONArray(n *Node) ([]interface{}, error) { func nodeToJSONArray(n Node) ([]interface{}, error) {
a := make([]interface{}, 0, len(n.Nodes)) a := make([]interface{}, 0, len(n.Nodes))
for _, ni := range n.Nodes { for _, ni := range n.Nodes {
item, err := treeToJSON(ni) item, err := treeToJSON(ni)
@ -179,7 +179,7 @@ func nodeToJSONArray(n *Node) ([]interface{}, error) {
return a, nil return a, nil
} }
func treeToJSON(n *Node) (interface{}, error) { func treeToJSON(n Node) (interface{}, error) {
switch n.Name { switch n.Name {
case "true": case "true":
return true, nil return true, nil
@ -272,7 +272,7 @@ func checkJSON(t *testing.T, got, expected interface{}) {
} }
} }
func jsonTreeToJSON(n *Node) (interface{}, error) { func jsonTreeToJSON(n Node) (interface{}, error) {
if n.Name != "json" { if n.Name != "json" {
return nil, fmt.Errorf("invalid root node name: %s", n.Name) return nil, fmt.Errorf("invalid root node name: %s", n.Name)
} }
@ -288,9 +288,9 @@ func TestJSON(t *testing.T) {
runTestsFile(t, "doc/example/json.treerack", []testItem{{ runTestsFile(t, "doc/example/json.treerack", []testItem{{
title: "true", title: "true",
text: "true", text: "true",
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "true", Name: "true",
}}, }},
}, },
@ -298,9 +298,9 @@ func TestJSON(t *testing.T) {
}, { }, {
title: "false", title: "false",
text: "false", text: "false",
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "false", Name: "false",
}}, }},
}, },
@ -308,9 +308,9 @@ func TestJSON(t *testing.T) {
}, { }, {
title: "null", title: "null",
text: "null", text: "null",
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "null", Name: "null",
}}, }},
}, },
@ -318,9 +318,9 @@ func TestJSON(t *testing.T) {
}, { }, {
title: "string", title: "string",
text: `"\"\\n\b\t\uabcd"`, text: `"\"\\n\b\t\uabcd"`,
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}}, }},
}, },
@ -328,9 +328,9 @@ func TestJSON(t *testing.T) {
}, { }, {
title: "number", title: "number",
text: "6.62e-34", text: "6.62e-34",
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "number", Name: "number",
}}, }},
}, },
@ -346,55 +346,55 @@ func TestJSON(t *testing.T) {
"object": {}, "object": {},
"array": [] "array": []
}`, }`,
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "object", Name: "object",
Nodes: []*Node{{ Nodes: []Node{{
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "true", Name: "true",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "false", Name: "false",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "null", Name: "null",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "string", Name: "string",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "number", Name: "number",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "object", Name: "object",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "array", Name: "array",
@ -414,11 +414,11 @@ func TestJSON(t *testing.T) {
"object": {}, "object": {},
"array": [] "array": []
}, []]`, }, []]`,
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "array", Name: "array",
Nodes: []*Node{{ Nodes: []Node{{
Name: "true", Name: "true",
}, { }, {
Name: "false", Name: "false",
@ -430,51 +430,51 @@ func TestJSON(t *testing.T) {
Name: "number", Name: "number",
}, { }, {
Name: "object", Name: "object",
Nodes: []*Node{{ Nodes: []Node{{
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "true", Name: "true",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "false", Name: "false",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "null", Name: "null",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "string", Name: "string",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "number", Name: "number",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "object", Name: "object",
}}, }},
}, { }, {
Name: "entry", Name: "entry",
Nodes: []*Node{{ Nodes: []Node{{
Name: "string", Name: "string",
}, { }, {
Name: "array", Name: "array",
@ -489,9 +489,9 @@ func TestJSON(t *testing.T) {
}, { }, {
title: "bugfix, 100", title: "bugfix, 100",
text: "100", text: "100",
node: &Node{ node: Node{
Name: "json", Name: "json",
Nodes: []*Node{{ Nodes: []Node{{
Name: "number", Name: "number",
}}, }},
}, },

View File

@ -5,19 +5,21 @@ import "testing"
func TestKeyVal(t *testing.T) { func TestKeyVal(t *testing.T) {
runTestsFile(t, "doc/example/keyval.treerack", []testItem{{ runTestsFile(t, "doc/example/keyval.treerack", []testItem{{
title: "empty", title: "empty",
node: Node{Name: "doc"},
}, { }, {
title: "a comment", title: "a comment",
text: "# a comment", text: "# a comment",
node: Node{Name: "doc", To: 11},
}, { }, {
title: "a key", title: "a key",
text: "a key", text: "a key",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
To: 5, To: 5,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
To: 5, To: 5,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
To: 5, To: 5,
}}, }},
@ -26,15 +28,15 @@ func TestKeyVal(t *testing.T) {
}, { }, {
title: "a key with a preceeding whitespace", title: "a key with a preceeding whitespace",
text: " a key", text: " a key",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
From: 1, From: 1,
To: 6, To: 6,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
From: 1, From: 1,
To: 6, To: 6,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 1, From: 1,
To: 6, To: 6,
@ -48,15 +50,15 @@ func TestKeyVal(t *testing.T) {
a key a key
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
From: 20, From: 20,
To: 25, To: 25,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
From: 20, From: 20,
To: 25, To: 25,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 20, From: 20,
To: 25, To: 25,
@ -66,13 +68,13 @@ func TestKeyVal(t *testing.T) {
}, { }, {
title: "a key value pair", title: "a key value pair",
text: "a key = a value", text: "a key = a value",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
To: 15, To: 15,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
To: 5, To: 5,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
To: 5, To: 5,
}}, }},
@ -86,15 +88,15 @@ func TestKeyVal(t *testing.T) {
title: "key value pairs with a comment at the end of line", title: "key value pairs with a comment at the end of line",
text: "a key = a value # a comment\n" + text: "a key = a value # a comment\n" +
"another key = another value # another comment", "another key = another value # another comment",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
From: 0, From: 0,
To: 39, To: 39,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
From: 0, From: 0,
To: 5, To: 5,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 0, From: 0,
To: 5, To: 5,
@ -108,11 +110,11 @@ func TestKeyVal(t *testing.T) {
Name: "key-val", Name: "key-val",
From: 40, From: 40,
To: 85, To: 85,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
From: 40, From: 40,
To: 51, To: 51,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 40, From: 40,
To: 51, To: 51,
@ -126,10 +128,10 @@ func TestKeyVal(t *testing.T) {
}, { }, {
title: "value without a key", title: "value without a key",
text: "= a value", text: "= a value",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
To: 9, To: 9,
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
From: 2, From: 2,
To: 9, To: 9,
@ -141,11 +143,11 @@ func TestKeyVal(t *testing.T) {
# a comment # a comment
a key = a value a key = a value
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
From: 4, From: 4,
To: 34, To: 34,
Nodes: []*Node{{ Nodes: []Node{{
Name: "comment", Name: "comment",
From: 4, From: 4,
To: 15, To: 15,
@ -153,7 +155,7 @@ func TestKeyVal(t *testing.T) {
Name: "key", Name: "key",
From: 19, From: 19,
To: 24, To: 24,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 19, From: 19,
To: 24, To: 24,
@ -167,14 +169,14 @@ func TestKeyVal(t *testing.T) {
}, { }, {
title: "a key with multiple symbols", title: "a key with multiple symbols",
text: "a key . with.multiple.symbols=a value", text: "a key . with.multiple.symbols=a value",
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
To: 37, To: 37,
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
From: 0, From: 0,
To: 29, To: 29,
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
From: 0, From: 0,
To: 5, To: 5,
@ -203,11 +205,11 @@ func TestKeyVal(t *testing.T) {
# a comment # a comment
[a group key.empty] [a group key.empty]
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "group-key", Name: "group-key",
From: 4, From: 4,
To: 38, To: 38,
Nodes: []*Node{{ Nodes: []Node{{
Name: "comment", Name: "comment",
From: 4, From: 4,
To: 15, To: 15,
@ -229,9 +231,9 @@ func TestKeyVal(t *testing.T) {
= two = two
= three = three
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "group-key", Name: "group-key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -240,17 +242,17 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}}, }},
@ -258,9 +260,9 @@ func TestKeyVal(t *testing.T) {
}, { }, {
title: "a group key with multiple values, in a single line", title: "a group key with multiple values, in a single line",
text: "[foo.bar.baz] = one = two = three", text: "[foo.bar.baz] = one = two = three",
nodes: []*Node{{ nodes: []Node{{
Name: "group-key", Name: "group-key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -269,17 +271,17 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "value", Name: "value",
}}, }},
}}, }},
@ -301,11 +303,11 @@ func TestKeyVal(t *testing.T) {
b = 2 # even b = 2 # even
c = 3 c = 3
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
@ -313,9 +315,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -325,9 +327,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -337,9 +339,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
@ -347,7 +349,7 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "group-key", Name: "group-key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "comment", Name: "comment",
}, { }, {
Name: "symbol", Name: "symbol",
@ -358,9 +360,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
@ -368,9 +370,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
@ -378,9 +380,9 @@ func TestKeyVal(t *testing.T) {
}}, }},
}, { }, {
Name: "key-val", Name: "key-val",
Nodes: []*Node{{ Nodes: []Node{{
Name: "key", Name: "key",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {

View File

@ -14,9 +14,9 @@ func TestKeyword(t *testing.T) {
title: "not keyword", title: "not keyword",
text: "baz", text: "baz",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "doc", Name: "doc",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, },
@ -24,9 +24,9 @@ func TestKeyword(t *testing.T) {
title: "keyword", title: "keyword",
text: "foo", text: "foo",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "doc", Name: "doc",
Nodes: []*Node{{ Nodes: []Node{{
Name: "keyword", Name: "keyword",
}}, }},
}, },
@ -34,9 +34,9 @@ func TestKeyword(t *testing.T) {
title: "mixed", title: "mixed",
text: "foo bar baz bar foo baz bar", text: "foo bar baz bar foo baz bar",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "doc", Name: "doc",
Nodes: []*Node{{ Nodes: []Node{{
Name: "keyword", Name: "keyword",
}, { }, {
Name: "keyword", Name: "keyword",

File diff suppressed because it is too large Load Diff

View File

@ -16,18 +16,18 @@ func TestMMLExp2(t *testing.T) {
title: "mixed indexer", title: "mixed indexer",
text: "a.b[c]", text: "a.b[c]",
ignorePosition: true, ignorePosition: true,
nodes: []*Node{{ nodes: []Node{{
Name: "indexer", Name: "indexer",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol-index", Name: "symbol-index",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
Name: "expression-index", Name: "expression-index",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}}, }},
@ -38,18 +38,18 @@ func TestMMLExp2(t *testing.T) {
title: "mixed indexer inverted", title: "mixed indexer inverted",
text: "a[b].c", text: "a[b].c",
ignorePosition: true, ignorePosition: true,
nodes: []*Node{{ nodes: []Node{{
Name: "indexer", Name: "indexer",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "expression-index", Name: "expression-index",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}, { }, {
Name: "symbol-index", Name: "symbol-index",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}}, }},

View File

@ -16,21 +16,21 @@ func TestMMLExp3(t *testing.T) {
title: "assignment", title: "assignment",
text: "fn f() a.b = c", text: "fn f() a.b = c",
ignorePosition: true, ignorePosition: true,
nodes: []*Node{{ nodes: []Node{{
Name: "function-definition", Name: "function-definition",
Nodes: []*Node{{ Nodes: []Node{{
Name: "function-capture", Name: "function-capture",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "assignment", Name: "assignment",
Nodes: []*Node{{ Nodes: []Node{{
Name: "indexer", Name: "indexer",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol-index", Name: "symbol-index",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}}, }},

File diff suppressed because it is too large Load Diff

12
node.go
View File

@ -2,8 +2,8 @@ package treerack
import "code.squareroundforest.org/arpio/treerack/internal/self" import "code.squareroundforest.org/arpio/treerack/internal/self"
func mapNodes(m func(n *Node) *Node, n []*Node) []*Node { func mapNodes(m func(n Node) Node, n []Node) []Node {
var nn []*Node var nn []Node
for i := range n { for i := range n {
nn = append(nn, m(n[i])) nn = append(nn, m(n[i]))
} }
@ -11,8 +11,8 @@ func mapNodes(m func(n *Node) *Node, n []*Node) []*Node {
return nn return nn
} }
func filterNodes(f func(n *Node) bool, n []*Node) []*Node { func filterNodes(f func(n Node) bool, n []Node) []Node {
var nn []*Node var nn []Node
for i := range n { for i := range n {
if f(n[i]) { if f(n[i]) {
nn = append(nn, n[i]) nn = append(nn, n[i])
@ -22,7 +22,7 @@ func filterNodes(f func(n *Node) bool, n []*Node) []*Node {
return nn return nn
} }
func mapSelfNode(n *self.Node) *Node { func mapSelfNode(n self.Node) Node {
nn := Node{ nn := Node{
Name: n.Name, Name: n.Name,
From: n.From, From: n.From,
@ -34,5 +34,5 @@ func mapSelfNode(n *self.Node) *Node {
nn.Nodes = append(nn.Nodes, mapSelfNode(n.Nodes[i])) nn.Nodes = append(nn.Nodes, mapSelfNode(n.Nodes[i]))
} }
return &nn return nn
} }

View File

@ -10,7 +10,7 @@ type Node struct {
Name string Name string
// Nodes contains the child nodes representing the substructures of this node. // Nodes contains the child nodes representing the substructures of this node.
Nodes []*Node Nodes []Node
// From is the inclusive character offset of the starting position in the input stream. // From is the inclusive character offset of the starting position in the input stream.
From int From int
@ -24,17 +24,17 @@ type Node struct {
// Tokens returns the raw slice of runes from the input stream represented by this node. // Tokens returns the raw slice of runes from the input stream represented by this node.
// //
// Note: This returns a reference to the underlying buffer, not a copy. It should not be modified. // Note: This returns a reference to the underlying buffer, not a copy. It should not be modified.
func (n *Node) Tokens() []rune { func (n Node) Tokens() []rune {
return n.tokens return n.tokens
} }
// String returns the string representation of the node, including its name, position range (From/To), and the // String returns the string representation of the node, including its name, position range (From/To), and the
// captured text content. // captured text content.
func (n *Node) String() string { func (n Node) String() string {
return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text()) return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text())
} }
// Text returns the actual string segment from the input stream represented by this node. // Text returns the actual string segment from the input stream represented by this node.
func (n *Node) Text() string { func (n Node) Text() string {
return string(n.Tokens()[n.From:n.To]) return string(n.Tokens()[n.From:n.To])
} }

View File

@ -13,11 +13,11 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, right, left, commit", title: "recursion in choice, right, left, commit",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}}, }},
}}, }},
@ -32,11 +32,11 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, right, right, commit", title: "recursion in choice, right, right, commit",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}}, }},
}}, }},
@ -51,11 +51,11 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, left, right, commit", title: "recursion in choice, left, right, commit",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}}, }},
}}, }},
@ -70,11 +70,11 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, left, left, commit", title: "recursion in choice, left, left, commit",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}}, }},
}}, }},
@ -89,7 +89,7 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, right, left, alias", title: "recursion in choice, right, left, alias",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -102,7 +102,7 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, right, right, alias", title: "recursion in choice, right, right, alias",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -115,7 +115,7 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, left, right, alias", title: "recursion in choice, left, right, alias",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -128,7 +128,7 @@ func TestRecursion(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursion in choice, left, left, alias", title: "recursion in choice, left, left, alias",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -142,17 +142,17 @@ func TestRecursion(t *testing.T) {
title: "recursive sequence in choice", title: "recursive sequence in choice",
text: "aaaa", text: "aaaa",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}, { }, {
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}, { }, {
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}, { }, {
Name: "A", Name: "A",
@ -204,14 +204,14 @@ func TestSequence(t *testing.T) {
[]testItem{{ []testItem{{
title: "sequence with optional items", title: "sequence with optional items",
text: "abb", text: "abb",
node: &Node{ node: Node{
Name: "AB", Name: "AB",
To: 3, To: 3,
}, },
}, { }, {
title: "sequence with optional items, none", title: "sequence with optional items, none",
text: "bb", text: "bb",
node: &Node{ node: Node{
Name: "AB", Name: "AB",
To: 2, To: 2,
}, },
@ -224,9 +224,9 @@ func TestSequence(t *testing.T) {
[]testItem{{ []testItem{{
title: "recursive sequence in choice with redundant quantifier", title: "recursive sequence in choice with redundant quantifier",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "A", Name: "A",
}, { }, {
Name: "A", Name: "A",
@ -244,7 +244,7 @@ func TestSequence(t *testing.T) {
[]testItem{{ []testItem{{
title: "sequence with redundant quantifier", title: "sequence with redundant quantifier",
text: "aaa", text: "aaa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -258,9 +258,9 @@ func TestSequence(t *testing.T) {
title: "single or zero-or-more optional in choice", title: "single or zero-or-more optional in choice",
text: "aaa", text: "aaa",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "a", Name: "a",
}, { }, {
Name: "a", Name: "a",
@ -282,21 +282,21 @@ func TestSequence(t *testing.T) {
title: "just min", title: "just min",
text: "aaa", text: "aaa",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {
title: "less than max", title: "less than max",
text: "aaaa", text: "aaaa",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {
title: "just max", title: "just max",
text: "aaaaa", text: "aaaaa",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {
@ -314,7 +314,7 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero, considered as one", title: "zero, considered as one",
text: "aba", text: "aba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -335,7 +335,7 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "one", title: "one",
text: "aba", text: "aba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -356,7 +356,7 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "three", title: "three",
text: "abbba", text: "abbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 5, To: 5,
}, },
@ -373,14 +373,14 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or one explicit, missing", title: "zero or one explicit, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or one explicit", title: "zero or one explicit",
text: "aba", text: "aba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -397,14 +397,14 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or one explicit, omit zero, missing", title: "zero or one explicit, omit zero, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or one explicit, omit zero", title: "zero or one explicit, omit zero",
text: "aba", text: "aba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -421,14 +421,14 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or one explicit, shortcut, missing", title: "zero or one explicit, shortcut, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or one explicit, shortcut", title: "zero or one explicit, shortcut",
text: "aba", text: "aba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 3, To: 3,
}, },
@ -445,21 +445,21 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or three, missing", title: "zero or three, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or three", title: "zero or three",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
}, { }, {
title: "zero or three", title: "zero or three",
text: "abbba", text: "abbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 5, To: 5,
}, },
@ -476,21 +476,21 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or three, omit zero, missing", title: "zero or three, omit zero, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or three, omit zero", title: "zero or three, omit zero",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
}, { }, {
title: "zero or three, omit zero", title: "zero or three, omit zero",
text: "abbba", text: "abbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 5, To: 5,
}, },
@ -511,14 +511,14 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "one or three", title: "one or three",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
}, { }, {
title: "one or three", title: "one or three",
text: "abbba", text: "abbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 5, To: 5,
}, },
@ -539,14 +539,14 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "three or five", title: "three or five",
text: "abbbba", text: "abbbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 6, To: 6,
}, },
}, { }, {
title: "three or five", title: "three or five",
text: "abbbbba", text: "abbbbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 7, To: 7,
}, },
@ -563,14 +563,14 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or more, explicit, missing", title: "zero or more, explicit, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or more, explicit", title: "zero or more, explicit",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
@ -583,14 +583,14 @@ func TestQuantifiers(t *testing.T) {
[]testItem{{ []testItem{{
title: "zero or more, shortcut, missing", title: "zero or more, shortcut, missing",
text: "aa", text: "aa",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 2, To: 2,
}, },
}, { }, {
title: "zero or more, shortcut", title: "zero or more, shortcut",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
@ -607,7 +607,7 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "one or more, explicit", title: "one or more, explicit",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
@ -624,7 +624,7 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "one or more, shortcut", title: "one or more, shortcut",
text: "abba", text: "abba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 4, To: 4,
}, },
@ -641,7 +641,7 @@ func TestQuantifiers(t *testing.T) {
}, { }, {
title: "three or more, explicit", title: "three or more, explicit",
text: "abbbba", text: "abbbba",
node: &Node{ node: Node{
Name: "A", Name: "A",
To: 6, To: 6,
}, },
@ -664,6 +664,7 @@ func TestEmpty(t *testing.T) {
`A = "1"?`, `A = "1"?`,
[]testItem{{ []testItem{{
title: "empty primitive, succeed", title: "empty primitive, succeed",
node: Node{Name: "A"},
}}, }},
) )
@ -672,9 +673,9 @@ func TestEmpty(t *testing.T) {
`a = "1"?; A = a a`, `a = "1"?; A = a a`,
[]testItem{{ []testItem{{
title: "empty document with quantifiers in the item", title: "empty document with quantifiers in the item",
node: &Node{ node: Node{
Name: "A", Name: "A",
Nodes: []*Node{{ Nodes: []Node{{
Name: "a", Name: "a",
}, { }, {
Name: "a", Name: "a",
@ -688,7 +689,7 @@ func TestEmpty(t *testing.T) {
`a = "1"; A = a? a?`, `a = "1"; A = a? a?`,
[]testItem{{ []testItem{{
title: "empty document with quantifiers in the reference", title: "empty document with quantifiers in the reference",
node: &Node{ node: Node{
Name: "A", Name: "A",
}, },
}}, }},
@ -701,9 +702,9 @@ func TestEmpty(t *testing.T) {
title: "no a", title: "no a",
text: "b", text: "b",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a''", Name: "a''",
Nodes: []*Node{{ Nodes: []Node{{
Name: "a", Name: "a",
}}, }},
}, },
@ -719,7 +720,7 @@ func TestCharAsRoot(t *testing.T) {
title: "char as root", title: "char as root",
text: "a", text: "a",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "A", Name: "A",
}, },
}}, }},
@ -766,7 +767,7 @@ func TestChoiceSequencePriority(t *testing.T) {
title: "bc", title: "bc",
text: "bc", text: "bc",
ignorePosition: true, ignorePosition: true,
node: &Node{Name: "A"}, node: Node{Name: "A"},
}}, }},
) )
} }

View File

@ -10,8 +10,8 @@ type testItem struct {
title string title string
text string text string
fail bool fail bool
node *Node node Node
nodes []*Node nodes []Node
ignorePosition bool ignorePosition bool
} }
@ -43,10 +43,10 @@ func runTestsGetSyntax(t *testing.T, getSyntax func(t *testing.T) *Syntax, tests
return return
} }
if test.node != nil { if len(test.nodes) > 0 {
checkNode(t, test.ignorePosition, n, test.node)
} else {
checkNodes(t, test.ignorePosition, n.Nodes, test.nodes) checkNodes(t, test.ignorePosition, n.Nodes, test.nodes)
} else {
checkNode(t, test.ignorePosition, n, test.node)
} }
}) })
} }

View File

@ -5,6 +5,7 @@ import "testing"
func TestScheme(t *testing.T) { func TestScheme(t *testing.T) {
runTestsFile(t, "doc/example/scheme.treerack", []testItem{{ runTestsFile(t, "doc/example/scheme.treerack", []testItem{{
title: "empty", title: "empty",
node: Node{Name: "scheme"},
}, { }, {
title: "a function", title: "a function",
text: ` text: `
@ -13,13 +14,13 @@ func TestScheme(t *testing.T) {
[baz (- a b c)]) [baz (- a b c)])
(* bar baz))) (* bar baz)))
`, `,
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -30,17 +31,17 @@ func TestScheme(t *testing.T) {
}}, }},
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -52,11 +53,11 @@ func TestScheme(t *testing.T) {
}}, }},
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -69,7 +70,7 @@ func TestScheme(t *testing.T) {
}}, }},
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",

View File

@ -131,7 +131,7 @@ func (p *sequenceParser) parse(c *context) {
func (b *sequenceBuilder) nodeName() string { return b.name } func (b *sequenceBuilder) nodeName() string { return b.name }
func (b *sequenceBuilder) nodeID() int { return b.id } func (b *sequenceBuilder) nodeID() int { return b.id }
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { func (b *sequenceBuilder) build(c *context) ([]Node, bool) {
to, ok := c.results.longestMatch(c.offset, b.id) to, ok := c.results.longestMatch(c.offset, b.id)
if !ok { if !ok {
return nil, false return nil, false
@ -146,7 +146,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
return nil, true return nil, true
} }
return []*Node{{ return []Node{{
Name: b.name, Name: b.name,
From: from, From: from,
To: to, To: to,
@ -172,7 +172,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
var ( var (
itemIndex int itemIndex int
currentCount int currentCount int
nodes []*Node nodes []Node
) )
for itemIndex < len(b.items) { for itemIndex < len(b.items) {
@ -217,7 +217,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
return nodes, true return nodes, true
} }
return []*Node{{ return []Node{{
Name: b.name, Name: b.name,
From: from, From: from,
To: to, To: to,

View File

@ -6,37 +6,37 @@ func TestSExpr(t *testing.T) {
runTestsFile(t, "doc/example/sexpr.treerack", []testItem{{ runTestsFile(t, "doc/example/sexpr.treerack", []testItem{{
title: "number", title: "number",
text: "42", text: "42",
nodes: []*Node{{ nodes: []Node{{
Name: "number", Name: "number",
}}, }},
ignorePosition: true, ignorePosition: true,
}, { }, {
title: "string", title: "string",
text: "\"foo\"", text: "\"foo\"",
nodes: []*Node{{ nodes: []Node{{
Name: "string", Name: "string",
}}, }},
ignorePosition: true, ignorePosition: true,
}, { }, {
title: "symbol", title: "symbol",
text: "foo", text: "foo",
nodes: []*Node{{ nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
ignorePosition: true, ignorePosition: true,
}, { }, {
title: "nil", title: "nil",
text: "()", text: "()",
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
}}, }},
ignorePosition: true, ignorePosition: true,
}, { }, {
title: "list", title: "list",
text: "(foo bar baz)", text: "(foo bar baz)",
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -48,17 +48,17 @@ func TestSExpr(t *testing.T) {
}, { }, {
title: "embedded list", title: "embedded list",
text: "(foo (bar (baz)) qux)", text: "(foo (bar (baz)) qux)",
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}}, }},
}}, }},
@ -72,9 +72,9 @@ func TestSExpr(t *testing.T) {
text: `; some comment text: `; some comment
(some expression)`, (some expression)`,
ignorePosition: true, ignorePosition: true,
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -85,9 +85,9 @@ func TestSExpr(t *testing.T) {
text: `; text: `;
(some expression)`, (some expression)`,
ignorePosition: true, ignorePosition: true,
nodes: []*Node{{ nodes: []Node{{
Name: "list", Name: "list",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",

View File

@ -381,7 +381,7 @@ func (s *Syntax) ReadSyntax(r io.Reader) error {
} }
n := mapSelfNode(sn) n := mapSelfNode(sn)
s.ast = n s.ast = &n
return define(s, n) return define(s, n)
} }
@ -498,9 +498,9 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
fprintln() fprintln()
if o.Export { if o.Export {
fprint(`func Parse(r io.Reader) (*Node, error) {`) fprint(`func Parse(r io.Reader) (Node, error) {`)
} else { } else {
fprint(`func parse(r io.Reader) (*node, error) {`) fprint(`func parse(r io.Reader) (node, error) {`)
} }
fprintln() fprintln()
@ -541,9 +541,9 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
} }
// Parse reads from the input stream and constructs an AST based on the defined syntax. // Parse reads from the input stream and constructs an AST based on the defined syntax.
func (s *Syntax) Parse(r io.Reader) (*Node, error) { func (s *Syntax) Parse(r io.Reader) (Node, error) {
if err := s.Init(); err != nil { if err := s.Init(); err != nil {
return nil, err return Node{}, err
} }
return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers()) return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers())
@ -555,5 +555,5 @@ func (s *Syntax) Format(out io.Writer) error {
return formatDefinitions(out, s) return formatDefinitions(out, s)
} }
return formatAST(out, s.ast) return formatAST(out, *s.ast)
} }

View File

@ -89,7 +89,7 @@ type parser interface {
type builder interface { type builder interface {
nodeName() string nodeName() string
nodeID() int nodeID() int
build(*context) ([]*Node, bool) build(*context) ([]Node, bool)
} }
// ErrInvalidUnicodeCharacter indicates that the input content contains invalid UTF-8 sequences. // ErrInvalidUnicodeCharacter indicates that the input content contains invalid UTF-8 sequences.
@ -106,11 +106,11 @@ func (pe *ParseError) Error() string {
) )
} }
func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) { func parseInput(r io.Reader, p parser, b builder, kw []parser) (Node, error) {
c := newContext(bufio.NewReader(r), kw) c := newContext(bufio.NewReader(r), kw)
p.parse(c) p.parse(c)
if c.readErr != nil { if c.readErr != nil {
return nil, c.readErr return Node{}, c.readErr
} }
if err := c.finalizeParse(p); err != nil { if err := c.finalizeParse(p); err != nil {
@ -118,7 +118,7 @@ func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) {
perr.Input = "<input>" perr.Input = "<input>"
} }
return nil, err return Node{}, err
} }
c.offset = 0 c.offset = 0

View File

@ -25,18 +25,18 @@ func TestCSVWhitespace(t *testing.T) {
tests := []testItem{{ tests := []testItem{{
title: "empty", title: "empty",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
}, },
}, { }, {
title: "only a cell", title: "only a cell",
text: "abc", text: "abc",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}}, }},
}}, }},
@ -45,11 +45,11 @@ func TestCSVWhitespace(t *testing.T) {
title: "single line", title: "single line",
text: `a, b, c`, text: `a, b, c`,
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -63,11 +63,11 @@ func TestCSVWhitespace(t *testing.T) {
text: `a, b, c text: `a, b, c
d, e, f`, d, e, f`,
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -76,7 +76,7 @@ func TestCSVWhitespace(t *testing.T) {
}}, }},
}, { }, {
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -90,11 +90,11 @@ func TestCSVWhitespace(t *testing.T) {
text: `a,, b, c, text: `a,, b, c,
d, ,,,,`, d, ,,,,`,
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -107,7 +107,7 @@ func TestCSVWhitespace(t *testing.T) {
}}, }},
}, { }, {
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -126,11 +126,11 @@ func TestCSVWhitespace(t *testing.T) {
title: "too many commas", title: "too many commas",
text: `a,,`, text: `a,,`,
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -143,11 +143,11 @@ func TestCSVWhitespace(t *testing.T) {
title: "csv with tabs", title: "csv with tabs",
text: "a,\tb, c", text: "a,\tb, c",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}, { }, {
Name: "cell", Name: "cell",
@ -159,14 +159,14 @@ func TestCSVWhitespace(t *testing.T) {
}, { }, {
title: "whitespace between lines", title: "whitespace between lines",
text: " a, b, c \n d, e, f ", text: " a, b, c \n d, e, f ",
node: &Node{ node: Node{
Name: "document", Name: "document",
To: 19, To: 19,
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
From: 1, From: 1,
To: 8, To: 8,
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
From: 1, From: 1,
To: 2, To: 2,
@ -183,7 +183,7 @@ func TestCSVWhitespace(t *testing.T) {
Name: "line", Name: "line",
From: 11, From: 11,
To: 18, To: 18,
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
From: 11, From: 11,
To: 12, To: 12,
@ -202,19 +202,19 @@ func TestCSVWhitespace(t *testing.T) {
title: "just a space", title: "just a space",
text: " ", text: " ",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
}, },
}, { }, {
title: "cell with spaces in it", title: "cell with spaces in it",
text: "cell content 1/1, cell content 1/2\ncell content 2/1, cell content 2/2", text: "cell content 1/1, cell content 1/2\ncell content 2/1, cell content 2/2",
node: &Node{ node: Node{
Name: "document", Name: "document",
To: 69, To: 69,
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
To: 34, To: 34,
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
To: 16, To: 16,
}, { }, {
@ -226,7 +226,7 @@ func TestCSVWhitespace(t *testing.T) {
Name: "line", Name: "line",
From: 35, From: 35,
To: 69, To: 69,
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
From: 35, From: 35,
To: 51, To: 51,
@ -241,21 +241,21 @@ func TestCSVWhitespace(t *testing.T) {
title: "multiple empty lines", title: "multiple empty lines",
text: "\n\n", text: "\n\n",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "document", Name: "document",
Nodes: []*Node{{ Nodes: []Node{{
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}}, }},
}, { }, {
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}}, }},
}, { }, {
Name: "line", Name: "line",
Nodes: []*Node{{ Nodes: []Node{{
Name: "cell", Name: "cell",
}}, }},
}}, }},
@ -296,9 +296,9 @@ func TestWhitespace(t *testing.T) {
title: "multiple symbols", title: "multiple symbols",
text: "a b c", text: "a b c",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "symbols", Name: "symbols",
Nodes: []*Node{{ Nodes: []Node{{
Name: "symbol", Name: "symbol",
}, { }, {
Name: "symbol", Name: "symbol",
@ -322,21 +322,21 @@ func TestWhitespace(t *testing.T) {
title: "just min", title: "just min",
text: "a a a", text: "a a a",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {
title: "less than max", title: "less than max",
text: "a a a a", text: "a a a a",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {
title: "just max", title: "just max",
text: "a a a a a", text: "a a a a a",
ignorePosition: true, ignorePosition: true,
node: &Node{ node: Node{
Name: "a", Name: "a",
}, },
}, { }, {