diff --git a/combinator.go b/combinator.go index 15e6cea..48aef09 100644 --- a/combinator.go +++ b/combinator.go @@ -4,8 +4,8 @@ import ( "bytes" ) -var Nil = NewParser("Nil", func(ps *State) *Node { - return nil +var Nil = NewParser("Nil", func(ps *State) Node { + return Node{} }) func And(parsers ...Parserish) Parser { @@ -15,26 +15,24 @@ func And(parsers ...Parserish) Parser { parserfied := ParsifyAll(parsers...) - return NewParser("And()", func(ps *State) *Node { - var nodes = make([]*Node, 0, len(parserfied)) + return NewParser("And()", func(ps *State) Node { + var nodes = make([]Node, 0, len(parserfied)) startpos := ps.Pos for _, parser := range parserfied { node := parser(ps) if ps.Errored() { ps.Pos = startpos - return nil - } - if node != nil { - nodes = append(nodes, node) + return Node{} } + nodes = append(nodes, node) } - return &Node{Children: nodes} + return Node{Children: nodes} }) } func NoAutoWS(parser Parserish) Parser { parserfied := Parsify(parser) - return func(ps *State) *Node { + return func(ps *State) Node { ps.NoAutoWS = true ret := parserfied(ps) @@ -51,7 +49,7 @@ func Any(parsers ...Parserish) Parser { parserfied := ParsifyAll(parsers...) - return NewParser("Any()", func(ps *State) *Node { + return NewParser("Any()", func(ps *State) Node { longestError := Error{} startpos := ps.Pos for _, parser := range parserfied { @@ -68,7 +66,7 @@ func Any(parsers ...Parserish) Parser { ps.Error = longestError ps.Pos = startpos - return nil + return Node{} }) } @@ -96,9 +94,9 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { sepParser = Parsify(sep[0]) } - return func(ps *State) *Node { - var node *Node - nodes := make([]*Node, 0, 20) + return func(ps *State) Node { + var node Node + nodes := make([]Node, 0, 20) startpos := ps.Pos for { tempPos := ps.Pos @@ -109,7 +107,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { if len(nodes) < min { ps.Pos = startpos ps.ErrorHere("something else") - return nil + return Node{} } break } @@ -120,7 +118,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { if ps.Errored() { if len(nodes) < min { ps.Pos = startpos - return nil + return Node{} } ps.ClearError() break @@ -134,37 +132,37 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { break } } - return &Node{Children: nodes} + return Node{Children: nodes} } } func Maybe(parser Parserish) Parser { parserfied := Parsify(parser) - return NewParser("Maybe()", func(ps *State) *Node { + return NewParser("Maybe()", func(ps *State) Node { node := parserfied(ps) if ps.Errored() { ps.ClearError() - return nil + return Node{} } return node }) } -func Map(parser Parserish, f func(n *Node) *Node) Parser { +func Map(parser Parserish, f func(n Node) Node) Parser { p := Parsify(parser) - return NewParser("Map()", func(ps *State) *Node { + return NewParser("Map()", func(ps *State) Node { node := p(ps) if ps.Errored() { - return nil + return Node{} } return f(node) }) } -func flatten(n *Node) string { +func flatten(n Node) string { if n.Token != "" { return n.Token } @@ -181,7 +179,7 @@ func flatten(n *Node) string { } func Merge(parser Parserish) Parser { - return NewParser("Merge()", Map(parser, func(n *Node) *Node { - return &Node{Token: flatten(n)} + return NewParser("Merge()", Map(parser, func(n Node) Node { + return Node{Token: flatten(n)} })) } diff --git a/combinator_test.go b/combinator_test.go index 5fd23eb..10ff788 100644 --- a/combinator_test.go +++ b/combinator_test.go @@ -9,7 +9,7 @@ import ( func TestNil(t *testing.T) { node, p2 := runParser("hello world", Nil) - require.Nil(t, node) + require.Equal(t, Node{}, node) require.Equal(t, 0, p2.Pos) require.False(t, p2.Errored()) } @@ -44,7 +44,7 @@ func TestMaybe(t *testing.T) { t.Run("returns no errors", func(t *testing.T) { node, p3 := runParser("hello world", Maybe("world")) - require.Nil(t, node) + require.Equal(t, Node{}, node) require.False(t, p3.Errored()) require.Equal(t, 0, p3.Pos) }) @@ -70,7 +70,7 @@ func TestAny(t *testing.T) { t.Run("Accepts nil matches", func(t *testing.T) { node, p2 := runParser("hello world!", Any(Exact("ffffff"))) - require.Nil(t, node) + require.Equal(t, Node{}, node) require.Equal(t, 0, p2.Pos) }) @@ -168,8 +168,8 @@ type htmlTag struct { } func TestMap(t *testing.T) { - parser := Map(And("<", Chars("a-zA-Z0-9"), ">"), func(n *Node) *Node { - return &Node{Result: htmlTag{n.Children[1].Token}} + parser := Map(And("<", Chars("a-zA-Z0-9"), ">"), func(n Node) Node { + return Node{Result: htmlTag{n.Children[1].Token}} }) t.Run("sucess", func(t *testing.T) { @@ -203,11 +203,11 @@ func TestMerge(t *testing.T) { func assertNilParser(t *testing.T, parser Parser) { node, p2 := runParser("fff", parser) - require.Nil(t, node) + require.Equal(t, Node{}, node) require.Equal(t, 0, p2.Pos) } -func assertSequence(t *testing.T, node *Node, expected ...string) { +func assertSequence(t *testing.T, node Node, expected ...string) { require.NotNil(t, node) actual := []string{} diff --git a/debugon.go b/debugon.go index 79acf0f..f80b6ea 100644 --- a/debugon.go +++ b/debugon.go @@ -20,7 +20,7 @@ type DebugParser struct { Calls int } -func (dp *DebugParser) Parse(ps *State) *Node { +func (dp *DebugParser) Parse(ps *State) Node { start := time.Now() ret := dp.Next(ps) diff --git a/html/html.go b/html/html.go index 4d02cb0..dab239e 100644 --- a/html/html.go +++ b/html/html.go @@ -18,28 +18,28 @@ var ( tag Parser identifier = NoAutoWS(Merge(And(WS(), Chars("a-zA-Z", 1), Chars("a-zA-Z0-9", 0)))) - text = Map(NotChars("<>"), func(n *Node) *Node { - return &Node{Result: n.Token} + text = Map(NotChars("<>"), func(n Node) Node { + return Node{Result: n.Token} }) element = Any(text, &tag) - elements = Map(Kleene(element), func(n *Node) *Node { + elements = Map(Kleene(element), func(n Node) Node { ret := []interface{}{} for _, child := range n.Children { ret = append(ret, child.Result) } - return &Node{Result: ret} + return Node{Result: ret} }) attr = And(identifier, "=", Any(String('"'), String('\''))) - attrs = Map(Kleene(attr), func(node *Node) *Node { + attrs = Map(Kleene(attr), func(node Node) Node { attr := map[string]string{} for _, attrNode := range node.Children { attr[attrNode.Children[0].Token] = attrNode.Children[2].Token } - return &Node{Result: attr} + return Node{Result: attr} }) tstart = And("<", identifier, attrs, ">") @@ -47,9 +47,9 @@ var ( ) func init() { - tag = Map(And(tstart, elements, tend), func(node *Node) *Node { + tag = Map(And(tstart, elements, tend), func(node Node) Node { openTag := node.Children[0] - return &Node{Result: Tag{ + return Node{Result: Tag{ Name: openTag.Children[1].Token, Attributes: openTag.Children[2].Result.(map[string]string), Body: node.Children[1].Result.([]interface{}), diff --git a/json/json.go b/json/json.go index 01d209f..28889bd 100644 --- a/json/json.go +++ b/json/json.go @@ -9,42 +9,42 @@ import ( var ( value Parser - _array = Map(And("[", Kleene(&value, ","), "]"), func(n *Node) *Node { + _array = Map(And("[", Kleene(&value, ","), "]"), func(n Node) Node { ret := []interface{}{} for _, child := range n.Children[1].Children { ret = append(ret, child.Result) } - return &Node{Result: ret} + return Node{Result: ret} }) properties = Kleene(And(String('"'), ":", &value), ",") - _object = Map(And("{", properties, "}"), func(n *Node) *Node { + _object = Map(And("{", properties, "}"), func(n Node) Node { ret := map[string]interface{}{} for _, prop := range n.Children[1].Children { ret[prop.Children[0].Token] = prop.Children[2].Result } - return &Node{Result: ret} + return Node{Result: ret} }) - _null = Map("null", func(n *Node) *Node { - return &Node{Result: nil} + _null = Map("null", func(n Node) Node { + return Node{Result: nil} }) - _true = Map("true", func(n *Node) *Node { - return &Node{Result: true} + _true = Map("true", func(n Node) Node { + return Node{Result: true} }) - _false = Map("false", func(n *Node) *Node { - return &Node{Result: false} + _false = Map("false", func(n Node) Node { + return Node{Result: false} }) - _string = Map(String('"'), func(n *Node) *Node { - return &Node{Result: n.Token} + _string = Map(String('"'), func(n Node) Node { + return Node{Result: n.Token} }) - Y = Map(&value, func(n *Node) *Node { - return &Node{Result: n.Result} + Y = Map(&value, func(n Node) Node { + return Node{Result: n.Result} }) ) diff --git a/parser.go b/parser.go index 2da450f..c6d7f9b 100644 --- a/parser.go +++ b/parser.go @@ -9,11 +9,11 @@ import ( type Node struct { Token string - Children []*Node + Children []Node Result interface{} } -type Parser func(*State) *Node +type Parser func(*State) Node // Parserish types are any type that can be turned into a Parser by Parsify // These currently include *Parser and string literals. @@ -35,13 +35,13 @@ func Parsify(p Parserish) Parser { switch p := p.(type) { case nil: return nil - case func(*State) *Node: + case func(*State) Node: return NewParser("anonymous func", p) case Parser: return p case *Parser: // Todo: Maybe capture this stack and on nil show it? Is there a good error library to do this? - return func(ptr *State) *Node { + return func(ptr *State) Node { return (*p)(ptr) } case string: @@ -60,9 +60,9 @@ func ParsifyAll(parsers ...Parserish) []Parser { } func WS() Parser { - return NewParser("AutoWS", func(ps *State) *Node { + return NewParser("AutoWS", func(ps *State) Node { ps.WS() - return nil + return Node{} }) } @@ -81,16 +81,16 @@ func ParseString(parser Parserish, input string) (result interface{}, remaining } func Exact(match string) Parser { - return NewParser(match, func(ps *State) *Node { + return NewParser(match, func(ps *State) Node { ps.AutoWS() if !strings.HasPrefix(ps.Get(), match) { ps.ErrorHere(match) - return nil + return Node{} } ps.Advance(len(match)) - return &Node{Token: match} + return Node{Token: match} }) } @@ -149,7 +149,7 @@ func charsImpl(matcher string, stopOn bool, repetition ...int) Parser { min, max := parseRepetition(1, -1, repetition...) matches, ranges := parseMatcher(matcher) - return func(ps *State) *Node { + return func(ps *State) Node { ps.AutoWS() matched := 0 for ps.Pos+matched < len(ps.Input) { @@ -177,17 +177,17 @@ func charsImpl(matcher string, stopOn bool, repetition ...int) Parser { if matched < min { ps.ErrorHere(matcher) - return nil + return Node{} } result := ps.Input[ps.Pos : ps.Pos+matched] ps.Advance(matched) - return &Node{Token: result} + return Node{Token: result} } } func String(quote rune) Parser { - return NewParser("string", func(ps *State) *Node { + return NewParser("string", func(ps *State) Node { ps.AutoWS() var r rune var w int @@ -195,7 +195,7 @@ func String(quote rune) Parser { r, matched = utf8.DecodeRuneInString(ps.Input[ps.Pos:]) if r != quote { ps.ErrorHere("\"") - return nil + return Node{} } result := &bytes.Buffer{} @@ -213,12 +213,12 @@ func String(quote rune) Parser { if r == quote { ps.Advance(matched) - return &Node{Token: result.String()} + return Node{Token: result.String()} } result.WriteRune(r) } ps.ErrorHere("\"") - return nil + return Node{} }) } diff --git a/parser_test.go b/parser_test.go index cd2d24a..c61dcda 100644 --- a/parser_test.go +++ b/parser_test.go @@ -17,8 +17,8 @@ func TestParsify(t *testing.T) { }) t.Run("parser funcs", func(t *testing.T) { - node := Parsify(func(p *State) *Node { - return &Node{Token: "hello"} + node := Parsify(func(p *State) Node { + return Node{Token: "hello"} })(InputString("ffooo")) require.Equal(t, "hello", node.Token) @@ -45,7 +45,7 @@ func TestParsifyAll(t *testing.T) { require.Equal(t, "ff", result.Token) result = parsers[1](InputString("ffooo")) - require.Nil(t, result) + require.Equal(t, "", result.Token) } func TestExact(t *testing.T) { @@ -116,7 +116,7 @@ func TestChars(t *testing.T) { } func TestParseString(t *testing.T) { - Y := Map("hello", func(n *Node) *Node { return &Node{Result: n.Token} }) + Y := Map("hello", func(n Node) Node { return Node{Result: n.Token} }) t.Run("partial match", func(t *testing.T) { result, remaining, err := ParseString(Y, "hello world") require.Equal(t, "hello", result) @@ -159,7 +159,7 @@ func TestString(t *testing.T) { }) } -func runParser(input string, parser Parser) (*Node, *State) { +func runParser(input string, parser Parser) (Node, *State) { ps := InputString(input) result := parser(ps) return result, ps