*Node -> Node

This commit is contained in:
Adam Scarr 2017-08-07 21:45:12 +10:00
parent 132876fce4
commit 88aaf567a5
7 changed files with 75 additions and 77 deletions

View File

@ -4,8 +4,8 @@ import (
"bytes" "bytes"
) )
var Nil = NewParser("Nil", func(ps *State) *Node { var Nil = NewParser("Nil", func(ps *State) Node {
return nil return Node{}
}) })
func And(parsers ...Parserish) Parser { func And(parsers ...Parserish) Parser {
@ -15,26 +15,24 @@ func And(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return NewParser("And()", func(ps *State) *Node { return NewParser("And()", func(ps *State) Node {
var nodes = make([]*Node, 0, len(parserfied)) var nodes = make([]Node, 0, len(parserfied))
startpos := ps.Pos startpos := ps.Pos
for _, parser := range parserfied { for _, parser := range parserfied {
node := parser(ps) node := parser(ps)
if ps.Errored() { if ps.Errored() {
ps.Pos = startpos ps.Pos = startpos
return nil return Node{}
} }
if node != nil {
nodes = append(nodes, node) nodes = append(nodes, node)
} }
} return Node{Children: nodes}
return &Node{Children: nodes}
}) })
} }
func NoAutoWS(parser Parserish) Parser { func NoAutoWS(parser Parserish) Parser {
parserfied := Parsify(parser) parserfied := Parsify(parser)
return func(ps *State) *Node { return func(ps *State) Node {
ps.NoAutoWS = true ps.NoAutoWS = true
ret := parserfied(ps) ret := parserfied(ps)
@ -51,7 +49,7 @@ func Any(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return NewParser("Any()", func(ps *State) *Node { return NewParser("Any()", func(ps *State) Node {
longestError := Error{} longestError := Error{}
startpos := ps.Pos startpos := ps.Pos
for _, parser := range parserfied { for _, parser := range parserfied {
@ -68,7 +66,7 @@ func Any(parsers ...Parserish) Parser {
ps.Error = longestError ps.Error = longestError
ps.Pos = startpos 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]) sepParser = Parsify(sep[0])
} }
return func(ps *State) *Node { return func(ps *State) Node {
var node *Node var node Node
nodes := make([]*Node, 0, 20) nodes := make([]Node, 0, 20)
startpos := ps.Pos startpos := ps.Pos
for { for {
tempPos := ps.Pos tempPos := ps.Pos
@ -109,7 +107,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
if len(nodes) < min { if len(nodes) < min {
ps.Pos = startpos ps.Pos = startpos
ps.ErrorHere("something else") ps.ErrorHere("something else")
return nil return Node{}
} }
break break
} }
@ -120,7 +118,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
if ps.Errored() { if ps.Errored() {
if len(nodes) < min { if len(nodes) < min {
ps.Pos = startpos ps.Pos = startpos
return nil return Node{}
} }
ps.ClearError() ps.ClearError()
break break
@ -134,37 +132,37 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
break break
} }
} }
return &Node{Children: nodes} return Node{Children: nodes}
} }
} }
func Maybe(parser Parserish) Parser { func Maybe(parser Parserish) Parser {
parserfied := Parsify(parser) parserfied := Parsify(parser)
return NewParser("Maybe()", func(ps *State) *Node { return NewParser("Maybe()", func(ps *State) Node {
node := parserfied(ps) node := parserfied(ps)
if ps.Errored() { if ps.Errored() {
ps.ClearError() ps.ClearError()
return nil return Node{}
} }
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) p := Parsify(parser)
return NewParser("Map()", func(ps *State) *Node { return NewParser("Map()", func(ps *State) Node {
node := p(ps) node := p(ps)
if ps.Errored() { if ps.Errored() {
return nil return Node{}
} }
return f(node) return f(node)
}) })
} }
func flatten(n *Node) string { func flatten(n Node) string {
if n.Token != "" { if n.Token != "" {
return n.Token return n.Token
} }
@ -181,7 +179,7 @@ func flatten(n *Node) string {
} }
func Merge(parser Parserish) Parser { func Merge(parser Parserish) Parser {
return NewParser("Merge()", Map(parser, func(n *Node) *Node { return NewParser("Merge()", Map(parser, func(n Node) Node {
return &Node{Token: flatten(n)} return Node{Token: flatten(n)}
})) }))
} }

View File

@ -9,7 +9,7 @@ import (
func TestNil(t *testing.T) { func TestNil(t *testing.T) {
node, p2 := runParser("hello world", Nil) node, p2 := runParser("hello world", Nil)
require.Nil(t, node) require.Equal(t, Node{}, node)
require.Equal(t, 0, p2.Pos) require.Equal(t, 0, p2.Pos)
require.False(t, p2.Errored()) require.False(t, p2.Errored())
} }
@ -44,7 +44,7 @@ func TestMaybe(t *testing.T) {
t.Run("returns no errors", func(t *testing.T) { t.Run("returns no errors", func(t *testing.T) {
node, p3 := runParser("hello world", Maybe("world")) node, p3 := runParser("hello world", Maybe("world"))
require.Nil(t, node) require.Equal(t, Node{}, node)
require.False(t, p3.Errored()) require.False(t, p3.Errored())
require.Equal(t, 0, p3.Pos) require.Equal(t, 0, p3.Pos)
}) })
@ -70,7 +70,7 @@ func TestAny(t *testing.T) {
t.Run("Accepts nil matches", func(t *testing.T) { t.Run("Accepts nil matches", func(t *testing.T) {
node, p2 := runParser("hello world!", Any(Exact("ffffff"))) node, p2 := runParser("hello world!", Any(Exact("ffffff")))
require.Nil(t, node) require.Equal(t, Node{}, node)
require.Equal(t, 0, p2.Pos) require.Equal(t, 0, p2.Pos)
}) })
@ -168,8 +168,8 @@ type htmlTag struct {
} }
func TestMap(t *testing.T) { func TestMap(t *testing.T) {
parser := Map(And("<", Chars("a-zA-Z0-9"), ">"), func(n *Node) *Node { parser := Map(And("<", Chars("a-zA-Z0-9"), ">"), func(n Node) Node {
return &Node{Result: htmlTag{n.Children[1].Token}} return Node{Result: htmlTag{n.Children[1].Token}}
}) })
t.Run("sucess", func(t *testing.T) { t.Run("sucess", func(t *testing.T) {
@ -203,11 +203,11 @@ func TestMerge(t *testing.T) {
func assertNilParser(t *testing.T, parser Parser) { func assertNilParser(t *testing.T, parser Parser) {
node, p2 := runParser("fff", parser) node, p2 := runParser("fff", parser)
require.Nil(t, node) require.Equal(t, Node{}, node)
require.Equal(t, 0, p2.Pos) 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) require.NotNil(t, node)
actual := []string{} actual := []string{}

View File

@ -20,7 +20,7 @@ type DebugParser struct {
Calls int Calls int
} }
func (dp *DebugParser) Parse(ps *State) *Node { func (dp *DebugParser) Parse(ps *State) Node {
start := time.Now() start := time.Now()
ret := dp.Next(ps) ret := dp.Next(ps)

View File

@ -18,28 +18,28 @@ var (
tag Parser tag Parser
identifier = NoAutoWS(Merge(And(WS(), Chars("a-zA-Z", 1), Chars("a-zA-Z0-9", 0)))) identifier = NoAutoWS(Merge(And(WS(), Chars("a-zA-Z", 1), Chars("a-zA-Z0-9", 0))))
text = Map(NotChars("<>"), func(n *Node) *Node { text = Map(NotChars("<>"), func(n Node) Node {
return &Node{Result: n.Token} return Node{Result: n.Token}
}) })
element = Any(text, &tag) element = Any(text, &tag)
elements = Map(Kleene(element), func(n *Node) *Node { elements = Map(Kleene(element), func(n Node) Node {
ret := []interface{}{} ret := []interface{}{}
for _, child := range n.Children { for _, child := range n.Children {
ret = append(ret, child.Result) ret = append(ret, child.Result)
} }
return &Node{Result: ret} return Node{Result: ret}
}) })
attr = And(identifier, "=", Any(String('"'), String('\''))) 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{} attr := map[string]string{}
for _, attrNode := range node.Children { for _, attrNode := range node.Children {
attr[attrNode.Children[0].Token] = attrNode.Children[2].Token attr[attrNode.Children[0].Token] = attrNode.Children[2].Token
} }
return &Node{Result: attr} return Node{Result: attr}
}) })
tstart = And("<", identifier, attrs, ">") tstart = And("<", identifier, attrs, ">")
@ -47,9 +47,9 @@ var (
) )
func init() { 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] openTag := node.Children[0]
return &Node{Result: Tag{ return Node{Result: Tag{
Name: openTag.Children[1].Token, Name: openTag.Children[1].Token,
Attributes: openTag.Children[2].Result.(map[string]string), Attributes: openTag.Children[2].Result.(map[string]string),
Body: node.Children[1].Result.([]interface{}), Body: node.Children[1].Result.([]interface{}),

View File

@ -9,42 +9,42 @@ import (
var ( var (
value Parser value Parser
_array = Map(And("[", Kleene(&value, ","), "]"), func(n *Node) *Node { _array = Map(And("[", Kleene(&value, ","), "]"), func(n Node) Node {
ret := []interface{}{} ret := []interface{}{}
for _, child := range n.Children[1].Children { for _, child := range n.Children[1].Children {
ret = append(ret, child.Result) ret = append(ret, child.Result)
} }
return &Node{Result: ret} return Node{Result: ret}
}) })
properties = Kleene(And(String('"'), ":", &value), ",") 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{}{} ret := map[string]interface{}{}
for _, prop := range n.Children[1].Children { for _, prop := range n.Children[1].Children {
ret[prop.Children[0].Token] = prop.Children[2].Result ret[prop.Children[0].Token] = prop.Children[2].Result
} }
return &Node{Result: ret} return Node{Result: ret}
}) })
_null = Map("null", func(n *Node) *Node { _null = Map("null", func(n Node) Node {
return &Node{Result: nil} return Node{Result: nil}
}) })
_true = Map("true", func(n *Node) *Node { _true = Map("true", func(n Node) Node {
return &Node{Result: true} return Node{Result: true}
}) })
_false = Map("false", func(n *Node) *Node { _false = Map("false", func(n Node) Node {
return &Node{Result: false} return Node{Result: false}
}) })
_string = Map(String('"'), func(n *Node) *Node { _string = Map(String('"'), func(n Node) Node {
return &Node{Result: n.Token} return Node{Result: n.Token}
}) })
Y = Map(&value, func(n *Node) *Node { Y = Map(&value, func(n Node) Node {
return &Node{Result: n.Result} return Node{Result: n.Result}
}) })
) )

View File

@ -9,11 +9,11 @@ import (
type Node struct { type Node struct {
Token string Token string
Children []*Node Children []Node
Result interface{} 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 // Parserish types are any type that can be turned into a Parser by Parsify
// These currently include *Parser and string literals. // These currently include *Parser and string literals.
@ -35,13 +35,13 @@ func Parsify(p Parserish) Parser {
switch p := p.(type) { switch p := p.(type) {
case nil: case nil:
return nil return nil
case func(*State) *Node: case func(*State) Node:
return NewParser("anonymous func", p) return NewParser("anonymous func", p)
case Parser: case Parser:
return p return p
case *Parser: case *Parser:
// Todo: Maybe capture this stack and on nil show it? Is there a good error library to do this? // 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) return (*p)(ptr)
} }
case string: case string:
@ -60,9 +60,9 @@ func ParsifyAll(parsers ...Parserish) []Parser {
} }
func WS() Parser { func WS() Parser {
return NewParser("AutoWS", func(ps *State) *Node { return NewParser("AutoWS", func(ps *State) Node {
ps.WS() ps.WS()
return nil return Node{}
}) })
} }
@ -81,16 +81,16 @@ func ParseString(parser Parserish, input string) (result interface{}, remaining
} }
func Exact(match string) Parser { func Exact(match string) Parser {
return NewParser(match, func(ps *State) *Node { return NewParser(match, func(ps *State) Node {
ps.AutoWS() ps.AutoWS()
if !strings.HasPrefix(ps.Get(), match) { if !strings.HasPrefix(ps.Get(), match) {
ps.ErrorHere(match) ps.ErrorHere(match)
return nil return Node{}
} }
ps.Advance(len(match)) 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...) min, max := parseRepetition(1, -1, repetition...)
matches, ranges := parseMatcher(matcher) matches, ranges := parseMatcher(matcher)
return func(ps *State) *Node { return func(ps *State) Node {
ps.AutoWS() ps.AutoWS()
matched := 0 matched := 0
for ps.Pos+matched < len(ps.Input) { for ps.Pos+matched < len(ps.Input) {
@ -177,17 +177,17 @@ func charsImpl(matcher string, stopOn bool, repetition ...int) Parser {
if matched < min { if matched < min {
ps.ErrorHere(matcher) ps.ErrorHere(matcher)
return nil return Node{}
} }
result := ps.Input[ps.Pos : ps.Pos+matched] result := ps.Input[ps.Pos : ps.Pos+matched]
ps.Advance(matched) ps.Advance(matched)
return &Node{Token: result} return Node{Token: result}
} }
} }
func String(quote rune) Parser { func String(quote rune) Parser {
return NewParser("string", func(ps *State) *Node { return NewParser("string", func(ps *State) Node {
ps.AutoWS() ps.AutoWS()
var r rune var r rune
var w int var w int
@ -195,7 +195,7 @@ func String(quote rune) Parser {
r, matched = utf8.DecodeRuneInString(ps.Input[ps.Pos:]) r, matched = utf8.DecodeRuneInString(ps.Input[ps.Pos:])
if r != quote { if r != quote {
ps.ErrorHere("\"") ps.ErrorHere("\"")
return nil return Node{}
} }
result := &bytes.Buffer{} result := &bytes.Buffer{}
@ -213,12 +213,12 @@ func String(quote rune) Parser {
if r == quote { if r == quote {
ps.Advance(matched) ps.Advance(matched)
return &Node{Token: result.String()} return Node{Token: result.String()}
} }
result.WriteRune(r) result.WriteRune(r)
} }
ps.ErrorHere("\"") ps.ErrorHere("\"")
return nil return Node{}
}) })
} }

View File

@ -17,8 +17,8 @@ func TestParsify(t *testing.T) {
}) })
t.Run("parser funcs", func(t *testing.T) { t.Run("parser funcs", func(t *testing.T) {
node := Parsify(func(p *State) *Node { node := Parsify(func(p *State) Node {
return &Node{Token: "hello"} return Node{Token: "hello"}
})(InputString("ffooo")) })(InputString("ffooo"))
require.Equal(t, "hello", node.Token) require.Equal(t, "hello", node.Token)
@ -45,7 +45,7 @@ func TestParsifyAll(t *testing.T) {
require.Equal(t, "ff", result.Token) require.Equal(t, "ff", result.Token)
result = parsers[1](InputString("ffooo")) result = parsers[1](InputString("ffooo"))
require.Nil(t, result) require.Equal(t, "", result.Token)
} }
func TestExact(t *testing.T) { func TestExact(t *testing.T) {
@ -116,7 +116,7 @@ func TestChars(t *testing.T) {
} }
func TestParseString(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) { t.Run("partial match", func(t *testing.T) {
result, remaining, err := ParseString(Y, "hello world") result, remaining, err := ParseString(Y, "hello world")
require.Equal(t, "hello", result) 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) ps := InputString(input)
result := parser(ps) result := parser(ps)
return result, ps return result, ps