summaryrefslogtreecommitdiff
path: root/literals.go
diff options
context:
space:
mode:
authorAdam Scarr <adam@vektah.net>2017-08-08 19:56:14 +1000
committerAdam Scarr <adam@vektah.net>2017-08-08 19:56:32 +1000
commit73b55459ac724bc84c43159e820b90909dc63d51 (patch)
tree5d0d00ceb9b60da1ce13be4d0f6164d7df3b208e /literals.go
parent7e6f7ce4cfb577a14999a2434db94c8bb3befa82 (diff)
Move String to its own file
Diffstat (limited to 'literals.go')
-rw-r--r--literals.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/literals.go b/literals.go
new file mode 100644
index 0000000..241dd93
--- /dev/null
+++ b/literals.go
@@ -0,0 +1,107 @@
+package goparsify
+
+import (
+ "bytes"
+ "unicode/utf8"
+)
+
+func StringLit(allowedQuotes string) Parser {
+ return NewParser("string", func(ps *State) Node {
+ ps.AutoWS()
+
+ 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)
+ var buf *bytes.Buffer
+
+ for end < inputLen {
+ switch ps.Input[end] {
+ case '\\':
+ if end+1 >= inputLen {
+ ps.ErrorHere(string(quote))
+ return Node{}
+ }
+
+ if buf == nil {
+ buf = bytes.NewBufferString(ps.Input[ps.Pos+1 : end])
+ }
+
+ 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{}
+ }
+
+ r, ok := unhex(ps.Input[end+2 : end+6])
+ if !ok {
+ ps.Error.Expected = "[a-f0-9]"
+ ps.Error.pos = end + 2
+ return Node{}
+ }
+ buf.WriteRune(r)
+ end += 6
+ } else {
+ buf.WriteByte(c)
+ end += 2
+ }
+ case quote:
+ if buf == nil {
+ result := ps.Input[ps.Pos+1 : end]
+ ps.Pos = end + 1
+ return Node{Token: result}
+ }
+ ps.Pos = end + 1
+ return Node{Token: buf.String()}
+ default:
+ r, w := utf8.DecodeRuneInString(ps.Input[end:])
+ end += w
+ if buf != nil {
+ buf.WriteRune(r)
+ }
+ }
+ }
+
+ 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
+}