diff options
author | Adam Scarr <adam@vektah.net> | 2017-08-08 19:24:49 +1000 |
---|---|---|
committer | Adam Scarr <adam@vektah.net> | 2017-08-08 19:36:32 +1000 |
commit | b835581a732f3311e18aad10286d43f50a6006cf (patch) | |
tree | 3b45edcd651019003c4b4c7efb2b9ba7308d4d27 /parser.go | |
parent | 6e1c004fea8d841f554c2e94ff39e1fcee94b4e3 (diff) |
complete string implementation
Diffstat (limited to 'parser.go')
-rw-r--r-- | parser.go | 93 |
1 files changed, 73 insertions, 20 deletions
@@ -201,39 +201,92 @@ func charsImpl(matcher string, stopOn bool, repetition ...int) Parser { } } -func String(quote rune) Parser { +func String(allowedQuotes string) Parser { return NewParser("string", func(ps *State) Node { ps.AutoWS() - var r rune - var w int - var matched int - r, matched = utf8.DecodeRuneInString(ps.Input[ps.Pos:]) - if r != quote { - ps.ErrorHere("\"") + + for i := 0; i < len(allowedQuotes); i++ { + if ps.Input[ps.Pos] == allowedQuotes[i] { + + } + } + if !stringContainsByte(allowedQuotes, ps.Input[ps.Pos]) { + ps.ErrorHere(allowedQuotes) return Node{} } + quote := ps.Input[ps.Pos] + + var end int = ps.Pos + 1 + inputLen := len(ps.Input) result := &bytes.Buffer{} - for ps.Pos+matched < len(ps.Input) { - r, w = utf8.DecodeRuneInString(ps.Input[ps.Pos+matched:]) - matched += w + for end < inputLen { + switch ps.Input[end] { + case '\\': + if end+1 >= inputLen { + ps.ErrorHere(string(quote)) + return Node{} + } - if r == '\\' { - r, w = utf8.DecodeRuneInString(ps.Input[ps.Pos+matched:]) - result.WriteRune(r) - matched += w - continue - } + c := ps.Input[end+1] + if c == 'u' { + if end+6 >= inputLen { + ps.Error.Expected = "[a-f0-9]{4}" + ps.Error.pos = end + 2 + return Node{} + } - if r == quote { - ps.Advance(matched) + r, ok := unhex(ps.Input[end+2 : end+6]) + if !ok { + ps.Error.Expected = "[a-f0-9]" + ps.Error.pos = end + 2 + return Node{} + } + result.WriteRune(r) + end += 6 + } else { + result.WriteByte(c) + end += 2 + } + case quote: + ps.Pos = end + 1 return Node{Token: result.String()} + default: + r, w := utf8.DecodeRuneInString(ps.Input[end:]) + result.WriteRune(r) + end += w } - result.WriteRune(r) } - ps.ErrorHere("\"") + ps.ErrorHere(string(quote)) return Node{} }) } + +func stringContainsByte(s string, b byte) bool { + for i := 0; i < len(s); i++ { + if b == s[i] { + return true + } + } + return false +} + +func unhex(b string) (v rune, ok bool) { + for _, c := range b { + v <<= 4 + switch { + case '0' <= c && c <= '9': + v |= c - '0' + case 'a' <= c && c <= 'f': + v |= c - 'a' + 10 + case 'A' <= c && c <= 'F': + v |= c - 'A' + 10 + default: + return 0, false + } + } + + return v, true +} |