Simplify parsing @table:thing definitions
This commit is contained in:
parent
a3da779190
commit
2de5a8fa3f
5 changed files with 70 additions and 119 deletions
|
@ -635,6 +635,8 @@ func NewThing(TB string, ID interface{}) *Thing {
|
||||||
return &Thing{TB: TB, ID: int64(cnv)}
|
return &Thing{TB: TB, ID: int64(cnv)}
|
||||||
}
|
}
|
||||||
return &Thing{TB: TB, ID: cnv}
|
return &Thing{TB: TB, ID: cnv}
|
||||||
|
} else if cnv, err := strconv.ParseBool(str); err == nil {
|
||||||
|
return &Thing{TB: TB, ID: cnv}
|
||||||
} else if cnv, err := time.Parse(RFCDate, str); err == nil {
|
} else if cnv, err := time.Parse(RFCDate, str); err == nil {
|
||||||
return &Thing{TB: TB, ID: cnv.UTC()}
|
return &Thing{TB: TB, ID: cnv.UTC()}
|
||||||
} else if cnv, err := time.Parse(RFCTime, str); err == nil {
|
} else if cnv, err := time.Parse(RFCTime, str); err == nil {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (p *parser) parseWhat() (mul []Expr, err error) {
|
||||||
|
|
||||||
tok, lit, err := p.shouldBe(IDENT, THING, PARAM)
|
tok, lit, err := p.shouldBe(IDENT, THING, PARAM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &ParseError{Found: lit, Expected: []string{"table name or record id"}}
|
return nil, &ParseError{Found: lit, Expected: []string{"table, or thing"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.is(tok, IDENT) {
|
if p.is(tok, IDENT) {
|
||||||
|
|
|
@ -62,7 +62,11 @@ func (p *parser) parseLetStatement() (stmt *LetStatement, err error) {
|
||||||
p.v[stmt.Name.ID] = stmt.What
|
p.v[stmt.Name.ID] = stmt.What
|
||||||
case time.Time, time.Duration:
|
case time.Time, time.Duration:
|
||||||
p.v[stmt.Name.ID] = stmt.What
|
p.v[stmt.Name.ID] = stmt.What
|
||||||
case *Null, *Void, *Empty, *Table, *Thing, *Param:
|
case Array, Object:
|
||||||
|
p.v[stmt.Name.ID] = stmt.What
|
||||||
|
case *Null, *Void, *Empty:
|
||||||
|
p.v[stmt.Name.ID] = stmt.What
|
||||||
|
case *Table, *Thing, *Param, *Ident, *Value:
|
||||||
p.v[stmt.Name.ID] = stmt.What
|
p.v[stmt.Name.ID] = stmt.What
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
178
sql/scanner.go
178
sql/scanner.go
|
@ -17,6 +17,7 @@ package sql
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -425,140 +426,38 @@ func (s *scanner) scanThing(chp ...rune) (tok Token, lit string, val interface{}
|
||||||
|
|
||||||
tok = THING
|
tok = THING
|
||||||
|
|
||||||
// Store whether params
|
|
||||||
var tbp bool
|
|
||||||
var idp bool
|
|
||||||
|
|
||||||
// Store section values
|
|
||||||
var tbv string
|
var tbv string
|
||||||
var idv interface{}
|
var idv interface{}
|
||||||
|
|
||||||
// Create a buffer
|
// Create a buffer
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
var beg bytes.Buffer
|
|
||||||
var mid bytes.Buffer
|
|
||||||
var end bytes.Buffer
|
|
||||||
|
|
||||||
// Read passed in runes
|
// Read passed in runes
|
||||||
for _, ch := range chp {
|
for _, ch := range chp {
|
||||||
buf.WriteRune(ch)
|
buf.WriteRune(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
if tok, tbv, _ = s.part(); tok == ILLEGAL {
|
||||||
if ch := s.next(); ch == eof {
|
buf.WriteString(tbv)
|
||||||
break
|
return ILLEGAL, buf.String(), val
|
||||||
} else if isThingChar(ch) {
|
} else {
|
||||||
tok, lit, _ = s.scanIdent(ch)
|
buf.WriteString(tbv)
|
||||||
beg.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '$' {
|
|
||||||
tbp = true // The TB is a param
|
|
||||||
tok, lit, _ = s.scanParams(ch)
|
|
||||||
beg.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '`' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
beg.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '{' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
beg.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '⟨' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
beg.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
s.undo()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if beg.Len() < 1 || tok == ILLEGAL {
|
if ch := s.next(); ch == ':' {
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
buf.WriteRune(ch)
|
||||||
|
} else {
|
||||||
|
return ILLEGAL, buf.String(), val
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
if tok, lit, idv = s.part(); tok == ILLEGAL {
|
||||||
if ch := s.next(); ch != ':' {
|
buf.WriteString(lit)
|
||||||
s.undo()
|
return ILLEGAL, buf.String(), val
|
||||||
break
|
} else {
|
||||||
} else {
|
buf.WriteString(lit)
|
||||||
mid.WriteRune(ch)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mid.Len() < 1 {
|
return THING, buf.String(), NewThing(tbv, idv)
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if ch := s.next(); ch == eof {
|
|
||||||
break
|
|
||||||
} else if isThingChar(ch) {
|
|
||||||
tok, lit, _ = s.scanIdent(ch)
|
|
||||||
end.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '$' {
|
|
||||||
idp = true // The ID is a param
|
|
||||||
tok, lit, _ = s.scanParams(ch)
|
|
||||||
end.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '`' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
end.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '{' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
end.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else if ch == '⟨' {
|
|
||||||
tok, lit, _ = s.scanQuoted(ch)
|
|
||||||
end.WriteString(lit)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
s.undo()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if end.Len() < 1 || tok == ILLEGAL {
|
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
|
|
||||||
tbv = beg.String()
|
|
||||||
idv = end.String()
|
|
||||||
|
|
||||||
if tbp { // The TB is a param
|
|
||||||
if p, ok := s.p.v[tbv]; ok {
|
|
||||||
switch v := p.(type) {
|
|
||||||
case string:
|
|
||||||
tbv = v
|
|
||||||
default:
|
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if idp { // The ID is a param
|
|
||||||
if p, ok := s.p.v[idv.(string)]; ok {
|
|
||||||
switch v := p.(type) {
|
|
||||||
case bool, int64, float64, string, []interface{}, map[string]interface{}:
|
|
||||||
idv = v
|
|
||||||
default:
|
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val = NewThing(tbv, idv)
|
|
||||||
|
|
||||||
// Otherwise return as a regular thing.
|
|
||||||
return THING, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,6 +694,51 @@ func (s *scanner) scanObject(chp ...rune) (tok Token, lit string, val interface{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *scanner) part() (tok Token, lit string, val interface{}) {
|
||||||
|
|
||||||
|
if ch := s.next(); isLetter(ch) {
|
||||||
|
tok, lit, _ = s.scanIdent(ch)
|
||||||
|
} else if isNumber(ch) {
|
||||||
|
tok, lit, _ = s.scanNumber(ch)
|
||||||
|
} else if ch == '`' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
} else if ch == '{' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
} else if ch == '⟨' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
} else if ch == '$' {
|
||||||
|
tok, lit, _ = s.scanParams(ch)
|
||||||
|
if p, ok := s.p.v[lit]; ok {
|
||||||
|
switch v := p.(type) {
|
||||||
|
case bool, int64, float64, string:
|
||||||
|
val, lit = v, fmt.Sprint(v)
|
||||||
|
case *Ident:
|
||||||
|
lit = v.ID
|
||||||
|
case *Value:
|
||||||
|
lit = v.ID
|
||||||
|
default:
|
||||||
|
tok = ILLEGAL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tok = ILLEGAL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.undo()
|
||||||
|
tok = ILLEGAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if tok != IDENT && tok != PARAM && tok != NUMBER && tok != DOUBLE {
|
||||||
|
tok = ILLEGAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if val == nil {
|
||||||
|
val = lit
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// next reads the next rune from the bufferred reader.
|
// next reads the next rune from the bufferred reader.
|
||||||
// Returns the rune(0) if an error occurs (or io.EOF is returned).
|
// Returns the rune(0) if an error occurs (or io.EOF is returned).
|
||||||
func (s *scanner) next() rune {
|
func (s *scanner) next() rune {
|
||||||
|
|
|
@ -211,6 +211,7 @@ var tokens = [...]string{
|
||||||
DATE: "DATE",
|
DATE: "DATE",
|
||||||
TIME: "TIME",
|
TIME: "TIME",
|
||||||
JSON: "JSON",
|
JSON: "JSON",
|
||||||
|
EXPR: "EXPR",
|
||||||
IDENT: "IDENT",
|
IDENT: "IDENT",
|
||||||
THING: "THING",
|
THING: "THING",
|
||||||
STRING: "STRING",
|
STRING: "STRING",
|
||||||
|
|
Loading…
Reference in a new issue