Parse record ids whole instead of seperately

This commit is contained in:
Tobie Morgan Hitchcock 2016-09-07 16:58:05 +01:00
parent 1219b3825f
commit f8562f1ccb
3 changed files with 131 additions and 123 deletions

View file

@ -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)

View file

@ -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

View file

@ -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
}