package db0303 import ( "errors" "strconv" "strings" ) type Parser struct { buf string pos int } func NewParser(s string) Parser { return Parser{buf: s, pos: 0} } type StmtSelect struct { table string cols []string keys []NamedCell } type NamedCell struct { column string value Cell } func isSpace(ch byte) bool { switch ch { case '\t', '\n', '\v', '\f', '\r', ' ': return true } return false } func isAlpha(ch byte) bool { return 'a' <= (ch|32) && (ch|32) <= 'z' } func isDigit(ch byte) bool { return '0' <= ch && ch <= '9' } func isNameStart(ch byte) bool { return isAlpha(ch) || ch == '_' } func isNameContinue(ch byte) bool { return isAlpha(ch) || isDigit(ch) || ch == '_' } func isSeparator(ch byte) bool { return ch < 128 && !isNameContinue(ch) } func (p *Parser) skipSpaces() { for p.pos < len(p.buf) && isSpace(p.buf[p.pos]) { p.pos += 1 } } func (p *Parser) tryKeyword(kw string) bool { p.skipSpaces() if !(p.pos+len(kw) <= len(p.buf) && strings.EqualFold(p.buf[p.pos:p.pos+len(kw)], kw)) { return false } if p.pos+len(kw) < len(p.buf) && !isSeparator(p.buf[p.pos+len(kw)]) { return false } p.pos += len(kw) return true } func (p *Parser) tryPunctuation(tok string) bool { p.skipSpaces() if !(p.pos+len(tok) <= len(p.buf) && p.buf[p.pos:p.pos+len(tok)] == tok) { return false } p.pos += len(tok) return true } func (p *Parser) tryName() (string, bool) { p.skipSpaces() start, cur := p.pos, p.pos if !(cur < len(p.buf) && isNameStart(p.buf[cur])) { return "", false } cur++ for cur < len(p.buf) && isNameContinue(p.buf[cur]) { cur++ } p.pos = cur return p.buf[start:cur], true } func (p *Parser) parseValue(out *Cell) error { p.skipSpaces() if p.pos >= len(p.buf) { return errors.New("expect value") } ch := p.buf[p.pos] if ch == '"' || ch == '\'' { return p.parseString(out) } else if isDigit(ch) || ch == '-' || ch == '+' { return p.parseInt(out) } else { return errors.New("expect value") } } func (p *Parser) parseString(out *Cell) error { quote := p.buf[p.pos] cur := p.pos + 1 for cur < len(p.buf) { ch := p.buf[cur] if ch == '\\' { cur++ if cur < len(p.buf) && (p.buf[cur] == '"' || p.buf[cur] == '\'') { out.Str = append(out.Str, p.buf[cur]) cur++ } else { return errors.New("bad escape") } } else if ch == quote { out.Type = TypeStr p.pos = cur + 1 return nil } else { out.Str = append(out.Str, p.buf[cur]) cur++ } } return errors.New("string is not terminated") } func (p *Parser) parseInt(out *Cell) (err error) { start, cur := p.pos, p.pos if p.buf[cur] == '-' || p.buf[cur] == '+' { cur++ } for cur < len(p.buf) && isDigit(p.buf[cur]) { cur++ } if out.I64, err = strconv.ParseInt(p.buf[start:cur], 10, 64); err != nil { return err } out.Type = TypeI64 p.pos = cur return nil } func (p *Parser) parseEqual(out *NamedCell) error func (p *Parser) parseSelect(out *StmtSelect) error func (p *Parser) parseWhere(out *[]NamedCell) error func (p *Parser) isEnd() bool { p.skipSpaces() return p.pos >= len(p.buf) } // QzBQWVJJOUhU https://trialofcode.org/