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) {
|
||||
|
||||
_, 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) {
|
||||
|
||||
_, 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
|
||||
case '÷':
|
||||
return DIV, string(ch), val
|
||||
case '@':
|
||||
return EAT, string(ch), val
|
||||
case ',':
|
||||
return COMMA, string(ch), val
|
||||
case '.':
|
||||
return DOT, string(ch), val
|
||||
case '@':
|
||||
return s.scanThing(ch)
|
||||
case '"':
|
||||
return s.scanString(ch)
|
||||
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{}) {
|
||||
|
||||
tok = NUMBER
|
||||
|
@ -442,6 +545,10 @@ func (s *Scanner) scanString(chp ...rune) (tok Token, lit string, val interface{
|
|||
end = '⟩'
|
||||
}
|
||||
|
||||
if beg == '{' {
|
||||
end = '}'
|
||||
}
|
||||
|
||||
tok = STRING
|
||||
|
||||
// Create a buffer
|
||||
|
|
22
sql/what.go
22
sql/what.go
|
@ -18,27 +18,23 @@ func (p *Parser) parseWhat() (mul []Expr, err error) {
|
|||
|
||||
for {
|
||||
|
||||
_, _, exi := p.mightBe(EAT)
|
||||
tok, lit, err := p.shouldBe(IDENT, THING)
|
||||
if err != nil {
|
||||
return nil, &ParseError{Found: lit, Expected: []string{"table name or record id"}}
|
||||
}
|
||||
|
||||
if exi == false {
|
||||
one, err := p.parseTable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.is(tok, IDENT) {
|
||||
one, _ := p.declare(TABLE, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
|
||||
if exi == true {
|
||||
p.unscan()
|
||||
one, err := p.parseThing()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.is(tok, THING) {
|
||||
one, _ := p.declare(THING, lit)
|
||||
mul = append(mul, one)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue