Parse record ids whole instead of seperately
This commit is contained in:
parent
1219b3825f
commit
f8562f1ccb
3 changed files with 131 additions and 123 deletions
121
sql/exprs.go
121
sql/exprs.go
|
@ -57,114 +57,6 @@ func (p *Parser) parseNames() (mul []string, err error) {
|
||||||
//
|
//
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
func (p *Parser) parseTable() (*Table, error) {
|
|
||||||
|
|
||||||
_, lit, err := p.shouldBe(IDENT, NUMBER, DATE)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &ParseError{Found: lit, Expected: []string{"table name"}}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Table{lit}, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Parser) parseTables() (mul []*Table, err error) {
|
|
||||||
|
|
||||||
for {
|
|
||||||
|
|
||||||
one, err := p.parseTable()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mul = append(mul, one)
|
|
||||||
|
|
||||||
// If the next token is not a comma then break the loop.
|
|
||||||
if _, _, exi := p.mightBe(COMMA); !exi {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
//
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
func (p *Parser) parseThing() (one *Thing, err error) {
|
|
||||||
|
|
||||||
var tok Token
|
|
||||||
var lit string
|
|
||||||
var val interface{}
|
|
||||||
|
|
||||||
one = &Thing{}
|
|
||||||
|
|
||||||
_, _, err = p.shouldBe(EAT)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, one.TB, err = p.shouldBe(IDENT, NUMBER, DATE)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &ParseError{Found: one.TB, Expected: []string{"table name"}}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err = p.shouldBe(COLON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tok, lit, err = p.shouldBe(IDENT, NUMBER, DOUBLE, DATE, TIME)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &ParseError{Found: lit, Expected: []string{"table id"}}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tok {
|
|
||||||
case IDENT:
|
|
||||||
val = lit
|
|
||||||
default:
|
|
||||||
val, err = declare(tok, lit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
one.ID = val
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Parser) parseThings() (mul []Expr, err error) {
|
|
||||||
|
|
||||||
for {
|
|
||||||
|
|
||||||
one, err := p.parseThing()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mul = append(mul, one)
|
|
||||||
|
|
||||||
// If the next token is not a comma then break the loop.
|
|
||||||
if _, _, exi := p.mightBe(COMMA); !exi {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
//
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
func (p *Parser) parseIdent() (*Ident, error) {
|
func (p *Parser) parseIdent() (*Ident, error) {
|
||||||
|
|
||||||
_, lit, err := p.shouldBe(IDENT)
|
_, lit, err := p.shouldBe(IDENT)
|
||||||
|
@ -178,6 +70,19 @@ func (p *Parser) parseIdent() (*Ident, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseThing() (*Thing, error) {
|
||||||
|
|
||||||
|
_, lit, err := p.shouldBe(THING)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &ParseError{Found: lit, Expected: []string{"record id"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := p.declare(THING, lit)
|
||||||
|
|
||||||
|
return val.(*Thing), err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Parser) parseArray() ([]interface{}, error) {
|
func (p *Parser) parseArray() ([]interface{}, error) {
|
||||||
|
|
||||||
_, lit, err := p.shouldBe(ARRAY)
|
_, lit, err := p.shouldBe(ARRAY)
|
||||||
|
|
111
sql/scanner.go
111
sql/scanner.go
|
@ -70,12 +70,12 @@ func (s *Scanner) Scan() (tok Token, lit string, val interface{}) {
|
||||||
return MUL, string(ch), val
|
return MUL, string(ch), val
|
||||||
case '÷':
|
case '÷':
|
||||||
return DIV, string(ch), val
|
return DIV, string(ch), val
|
||||||
case '@':
|
|
||||||
return EAT, string(ch), val
|
|
||||||
case ',':
|
case ',':
|
||||||
return COMMA, string(ch), val
|
return COMMA, string(ch), val
|
||||||
case '.':
|
case '.':
|
||||||
return DOT, string(ch), val
|
return DOT, string(ch), val
|
||||||
|
case '@':
|
||||||
|
return s.scanThing(ch)
|
||||||
case '"':
|
case '"':
|
||||||
return s.scanString(ch)
|
return s.scanString(ch)
|
||||||
case '\'':
|
case '\'':
|
||||||
|
@ -374,6 +374,109 @@ func (s *Scanner) scanIdent(chp ...rune) (tok Token, lit string, val interface{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scanThing consumes the current rune and all contiguous ident runes.
|
||||||
|
func (s *Scanner) scanThing(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||||
|
|
||||||
|
tok = THING
|
||||||
|
|
||||||
|
// Create a buffer
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var beg bytes.Buffer
|
||||||
|
var mid bytes.Buffer
|
||||||
|
var end bytes.Buffer
|
||||||
|
|
||||||
|
// Read passed in runes
|
||||||
|
for _, ch := range chp {
|
||||||
|
buf.WriteRune(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ch := s.next(); ch == eof {
|
||||||
|
break
|
||||||
|
} else if isLetter(ch) {
|
||||||
|
tok, lit, _ = s.scanIdent(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else if isNumber(ch) {
|
||||||
|
tok, lit, _ = s.scanNumber(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else if ch == '`' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else if ch == '{' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else if ch == '⟨' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else {
|
||||||
|
s.undo()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if beg.Len() < 1 {
|
||||||
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ch := s.next(); ch != ':' {
|
||||||
|
s.undo()
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
mid.WriteRune(ch)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mid.Len() < 1 {
|
||||||
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ch := s.next(); ch == eof {
|
||||||
|
break
|
||||||
|
} else if isLetter(ch) {
|
||||||
|
tok, lit, _ = s.scanIdent(ch)
|
||||||
|
end.WriteString(lit)
|
||||||
|
} else if isNumber(ch) {
|
||||||
|
tok, lit, _ = s.scanNumber(ch)
|
||||||
|
end.WriteString(lit)
|
||||||
|
} else if ch == '`' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
beg.WriteString(lit)
|
||||||
|
} else if ch == '{' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
end.WriteString(lit)
|
||||||
|
} else if ch == '⟨' {
|
||||||
|
tok, lit, _ = s.scanQuoted(ch)
|
||||||
|
end.WriteString(lit)
|
||||||
|
} else {
|
||||||
|
s.undo()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if end.Len() < 1 {
|
||||||
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
||||||
|
}
|
||||||
|
|
||||||
|
val = &Thing{
|
||||||
|
TB: beg.String(),
|
||||||
|
ID: end.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tok {
|
||||||
|
case DATE, TIME, NUMBER, DOUBLE:
|
||||||
|
val.(*Thing).ID, _ = s.p.declare(tok, end.String())
|
||||||
|
case REGION:
|
||||||
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise return as a regular thing.
|
||||||
|
return THING, buf.String() + beg.String() + mid.String() + end.String(), val
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Scanner) scanNumber(chp ...rune) (tok Token, lit string, val interface{}) {
|
func (s *Scanner) scanNumber(chp ...rune) (tok Token, lit string, val interface{}) {
|
||||||
|
|
||||||
tok = NUMBER
|
tok = NUMBER
|
||||||
|
@ -442,6 +545,10 @@ func (s *Scanner) scanString(chp ...rune) (tok Token, lit string, val interface{
|
||||||
end = '⟩'
|
end = '⟩'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if beg == '{' {
|
||||||
|
end = '}'
|
||||||
|
}
|
||||||
|
|
||||||
tok = STRING
|
tok = STRING
|
||||||
|
|
||||||
// Create a buffer
|
// Create a buffer
|
||||||
|
|
20
sql/what.go
20
sql/what.go
|
@ -18,27 +18,23 @@ func (p *Parser) parseWhat() (mul []Expr, err error) {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
_, _, exi := p.mightBe(EAT)
|
tok, lit, err := p.shouldBe(IDENT, THING)
|
||||||
|
|
||||||
if exi == false {
|
|
||||||
one, err := p.parseTable()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, &ParseError{Found: lit, Expected: []string{"table name or record id"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.is(tok, IDENT) {
|
||||||
|
one, _ := p.declare(TABLE, lit)
|
||||||
mul = append(mul, one)
|
mul = append(mul, one)
|
||||||
}
|
}
|
||||||
|
|
||||||
if exi == true {
|
if p.is(tok, THING) {
|
||||||
p.unscan()
|
one, _ := p.declare(THING, lit)
|
||||||
one, err := p.parseThing()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mul = append(mul, one)
|
mul = append(mul, one)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the next token is not a comma then break the loop.
|
// If the next token is not a comma then break the loop.
|
||||||
if _, _, exi = p.mightBe(COMMA); !exi {
|
if _, _, exi := p.mightBe(COMMA); !exi {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue