Add String parser

This commit is contained in:
Adam Scarr 2017-08-06 17:28:34 +10:00
parent a65a9325aa
commit 2c0c5b628f
4 changed files with 63 additions and 3 deletions

View File

@ -21,7 +21,7 @@ var (
element = Any(text, &tag) element = Any(text, &tag)
elements = Kleene(element) elements = Kleene(element)
//attr := And(identifier, equal, String()) //attr := And(identifier, equal, String())
attr = And(identifier, WS, "=", WS, `"test"`) attr = And(WS, identifier, WS, "=", WS, Any(String('"'), String('\'')))
attrs = Map(Kleene(attr, WS), func(node Node) Node { attrs = Map(Kleene(attr, WS), func(node Node) Node {
nodes := node.([]Node) nodes := node.([]Node)
attr := map[string]string{} attr := map[string]string{}

View File

@ -8,10 +8,10 @@ import (
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
result, _, err := Parse("<body>hello <b>world</b></body>") result, _, err := Parse(`<body>hello <p color="blue">world</p></body>`)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, Tag{Name: "body", Attributes: map[string]string{}, Body: []Node{ require.Equal(t, Tag{Name: "body", Attributes: map[string]string{}, Body: []Node{
"hello ", "hello ",
Tag{Name: "b", Attributes: map[string]string{}, Body: []Node{"world"}}, Tag{Name: "p", Attributes: map[string]string{"color": "blue"}, Body: []Node{"world"}},
}}, result) }}, result)
} }

View File

@ -1,6 +1,7 @@
package parsec package parsec
import ( import (
"bytes"
"fmt" "fmt"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@ -185,3 +186,36 @@ func WS(p Pointer) (Node, Pointer) {
_, p2 := CharRun("\t\n\v\f\r \x85\xA0")(p) _, p2 := CharRun("\t\n\v\f\r \x85\xA0")(p)
return nil, p2 return nil, p2
} }
func String(quote rune) Parser {
return func(p Pointer) (Node, Pointer) {
var r rune
var w int
r, w = utf8.DecodeRuneInString(p.input[p.pos:])
if r != quote {
return NewError(p.pos, `Expected "`), p
}
matched := w
result := &bytes.Buffer{}
for p.pos+matched < len(p.input) {
r, w = utf8.DecodeRuneInString(p.input[p.pos+matched:])
matched += w
if r == '\\' {
r, w = utf8.DecodeRuneInString(p.input[p.pos+matched:])
result.WriteRune(r)
matched += w
continue
}
if r == quote {
return result.String(), p.Advance(matched)
}
result.WriteRune(r)
}
return NewError(p.pos, "Unterminated string"), p
}
}

View File

@ -178,3 +178,29 @@ func TestParseString(t *testing.T) {
require.Equal(t, "offset 0: Expected world", err.Error()) require.Equal(t, "offset 0: Expected world", err.Error())
}) })
} }
func TestString(t *testing.T) {
t.Run("test basic match", func(t *testing.T) {
result, p := String('"')(Pointer{`"hello"`, 0})
require.Equal(t, `hello`, result)
require.Equal(t, "", p.Get())
})
t.Run("test non match", func(t *testing.T) {
result, p := String('"')(Pointer{`1`, 0})
require.Equal(t, NewError(0, `Expected "`), result)
require.Equal(t, `1`, p.Get())
})
t.Run("test unterminated string", func(t *testing.T) {
result, p := String('"')(Pointer{`"hello `, 0})
require.Equal(t, NewError(0, `Unterminated string`), result)
require.Equal(t, `"hello `, p.Get())
})
t.Run("test escaping", func(t *testing.T) {
result, p := String('"')(Pointer{`"hello \"world\""`, 0})
require.Equal(t, `hello "world"`, result)
require.Equal(t, ``, p.Get())
})
}