mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
573 lines
10 KiB
Go
573 lines
10 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var keywords map[string]Token
|
|
|
|
func init() {
|
|
keywords = make(map[string]Token)
|
|
for i := keyword_beg + 1; i < keyword_end; i++ {
|
|
keywords[tokens[i]] = i
|
|
}
|
|
keywords[tokens[NULL]] = NULL
|
|
keywords[tokens[TRUE]] = TRUE
|
|
keywords[tokens[FALSE]] = FALSE
|
|
}
|
|
|
|
// Token is the set of lexical tokens of the Go programming language.
|
|
type Token int
|
|
|
|
// TODO (pok) remove unnecessary tokens
|
|
// The list of tokens.
|
|
const (
|
|
// Special tokens
|
|
ILLEGAL Token = iota
|
|
EOF
|
|
COMMENT
|
|
SPACE
|
|
|
|
literal_beg
|
|
IDENT // IDENT
|
|
QIDENT // "IDENT"
|
|
STRING // 'string'
|
|
BLOB // ???
|
|
FLOAT // 123.45
|
|
INTEGER // 123
|
|
NULL // NULL
|
|
TRUE // true
|
|
FALSE // false
|
|
literal_end
|
|
|
|
operator_beg
|
|
SEMI // ;
|
|
LP // (
|
|
RP // )
|
|
LB // [
|
|
RB // ]
|
|
LBR // {
|
|
RBR // }
|
|
COMMA // ,
|
|
NE // !=
|
|
EQ // =
|
|
LE // <=
|
|
LT // <
|
|
GT // >
|
|
GE // >=
|
|
BITAND // &
|
|
BITOR // |
|
|
BITNOT // !
|
|
LSHIFT // <<
|
|
RSHIFT // >>
|
|
PLUS // +
|
|
MINUS // -
|
|
STAR // *
|
|
SLASH // /
|
|
REM // %
|
|
CONCAT // ||
|
|
DOT // .
|
|
operator_end
|
|
|
|
keyword_beg
|
|
ABORT
|
|
ACTION
|
|
ADD
|
|
AFTER
|
|
AGG_COLUMN
|
|
AGG_FUNCTION
|
|
ALL
|
|
ALTER
|
|
ANALYZE
|
|
AND
|
|
AS
|
|
ASC
|
|
ASTERISK
|
|
ATTACH
|
|
AUTOINCREMENT
|
|
BEFORE
|
|
BEGIN
|
|
BETWEEN
|
|
BY
|
|
BULK
|
|
CACHETYPE
|
|
CASCADE
|
|
CASE
|
|
CAST
|
|
CHECK
|
|
COLUMN
|
|
COLUMNS
|
|
COLUMNKW
|
|
COMMIT
|
|
CONFLICT
|
|
CONSTRAINT
|
|
CREATE
|
|
CROSS
|
|
CTIME_KW
|
|
CURRENT
|
|
CURRENT_DATE
|
|
CURRENT_TIMESTAMP
|
|
DATABASE
|
|
DEFAULT
|
|
DEFERRABLE
|
|
DEFERRED
|
|
DELETE
|
|
DESC
|
|
DETACH
|
|
DISTINCT
|
|
DO
|
|
DROP
|
|
EACH
|
|
ELSE
|
|
END
|
|
EPOCH
|
|
ESCAPE
|
|
EXCEPT
|
|
EXCLUDE
|
|
EXCLUSIVE
|
|
EXISTS
|
|
EXPLAIN
|
|
FAIL
|
|
FILTER
|
|
FIRST
|
|
FOLLOWING
|
|
FOR
|
|
FOREIGN
|
|
FROM
|
|
FUNCTION
|
|
GLOB
|
|
GROUP
|
|
GROUPS
|
|
HAVING
|
|
IF
|
|
IF_NULL_ROW
|
|
IGNORE
|
|
IMMEDIATE
|
|
IN
|
|
INDEX
|
|
INDEXED
|
|
INITIALLY
|
|
INNER
|
|
INSERT
|
|
INSTEAD
|
|
INTERSECT
|
|
INTO
|
|
IS
|
|
ISNOT
|
|
JOIN
|
|
KEY
|
|
KEYPARTITIONS
|
|
LAST
|
|
LEFT
|
|
LIKE
|
|
LRU
|
|
MATCH
|
|
MAX
|
|
MIN
|
|
NATURAL
|
|
NO
|
|
NOT
|
|
NOTBETWEEN
|
|
NOTEXISTS
|
|
NOTGLOB
|
|
NOTHING
|
|
NOTIN
|
|
NOTLIKE
|
|
NOTMATCH
|
|
NOTREGEXP
|
|
NULLS
|
|
OF
|
|
ON
|
|
OR
|
|
ORDER
|
|
OTHERS
|
|
OUTER
|
|
OVER
|
|
PARTITION
|
|
PLAN
|
|
PRAGMA
|
|
PRECEDING
|
|
PRIMARY
|
|
QUERY
|
|
RANGE
|
|
RANKED
|
|
RECURSIVE
|
|
REFERENCES
|
|
REGEXP
|
|
REGISTER
|
|
REINDEX
|
|
RELEASE
|
|
RENAME
|
|
REPLACE
|
|
RESTRICT
|
|
ROLLBACK
|
|
ROW
|
|
ROWS
|
|
SAVEPOINT
|
|
SELECT
|
|
SELECT_COLUMN
|
|
SET
|
|
SHARDWIDTH
|
|
SIZE
|
|
SHOW
|
|
SPAN
|
|
TABLE
|
|
TABLES
|
|
TEMP
|
|
THEN
|
|
TIES
|
|
TIMEUNIT
|
|
TIMEQUANTUM
|
|
TO
|
|
TOP
|
|
TOPN
|
|
TRANSACTION
|
|
TRIGGER
|
|
TRUTH
|
|
TTL
|
|
UNBOUNDED
|
|
UNION
|
|
UNIQUE
|
|
UPDATE
|
|
USING
|
|
VACUUM
|
|
VALUES
|
|
VARIABLE
|
|
VECTOR
|
|
VIEW
|
|
VIRTUAL
|
|
WHEN
|
|
WHERE
|
|
WINDOW
|
|
WITH
|
|
WITHOUT
|
|
keyword_end
|
|
|
|
ANY // ???
|
|
)
|
|
|
|
var tokens = [...]string{
|
|
ILLEGAL: "ILLEGAL",
|
|
EOF: "EOF",
|
|
COMMENT: "COMMENT",
|
|
SPACE: "SPACE",
|
|
|
|
IDENT: "IDENT",
|
|
QIDENT: "QIDENT",
|
|
STRING: "STRING",
|
|
FLOAT: "FLOAT",
|
|
INTEGER: "INTEGER",
|
|
NULL: "NULL",
|
|
TRUE: "TRUE",
|
|
FALSE: "FALSE",
|
|
|
|
SEMI: ";",
|
|
LP: "(",
|
|
RP: ")",
|
|
LB: "[",
|
|
RB: "]",
|
|
LBR: "{",
|
|
RBR: "}",
|
|
COMMA: ",",
|
|
NE: "!=",
|
|
EQ: "=",
|
|
LE: "<=",
|
|
LT: "<",
|
|
GT: ">",
|
|
GE: ">=",
|
|
BITAND: "&",
|
|
BITOR: "|",
|
|
BITNOT: "!",
|
|
LSHIFT: "<<",
|
|
RSHIFT: ">>",
|
|
PLUS: "+",
|
|
MINUS: "-",
|
|
STAR: "*",
|
|
SLASH: "/",
|
|
REM: "%",
|
|
CONCAT: "||",
|
|
DOT: ".",
|
|
|
|
ABORT: "ABORT",
|
|
ACTION: "ACTION",
|
|
ADD: "ADD",
|
|
AFTER: "AFTER",
|
|
AGG_COLUMN: "AGG_COLUMN",
|
|
AGG_FUNCTION: "AGG_FUNCTION",
|
|
ALL: "ALL",
|
|
ALTER: "ALTER",
|
|
ANALYZE: "ANALYZE",
|
|
AND: "AND",
|
|
AS: "AS",
|
|
ASC: "ASC",
|
|
ASTERISK: "ASTERISK",
|
|
ATTACH: "ATTACH",
|
|
AUTOINCREMENT: "AUTOINCREMENT",
|
|
BEFORE: "BEFORE",
|
|
BEGIN: "BEGIN",
|
|
BETWEEN: "BETWEEN",
|
|
BY: "BY",
|
|
BULK: "BULK",
|
|
CACHETYPE: "CACHETYPE",
|
|
CASCADE: "CASCADE",
|
|
CASE: "CASE",
|
|
CAST: "CAST",
|
|
CHECK: "CHECK",
|
|
COLUMN: "COLUMN",
|
|
COLUMNS: "COLUMNS",
|
|
COLUMNKW: "COLUMNKW",
|
|
COMMIT: "COMMIT",
|
|
CONFLICT: "CONFLICT",
|
|
CONSTRAINT: "CONSTRAINT",
|
|
CREATE: "CREATE",
|
|
CROSS: "CROSS",
|
|
CTIME_KW: "CTIME_KW",
|
|
CURRENT: "CURRENT",
|
|
CURRENT_DATE: "CURRENT_DATE",
|
|
CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP",
|
|
DATABASE: "DATABASE",
|
|
DEFAULT: "DEFAULT",
|
|
DEFERRABLE: "DEFERRABLE",
|
|
DEFERRED: "DEFERRED",
|
|
DELETE: "DELETE",
|
|
DESC: "DESC",
|
|
DETACH: "DETACH",
|
|
DISTINCT: "DISTINCT",
|
|
DO: "DO",
|
|
DROP: "DROP",
|
|
EACH: "EACH",
|
|
ELSE: "ELSE",
|
|
END: "END",
|
|
EPOCH: "EPOCH",
|
|
ESCAPE: "ESCAPE",
|
|
EXCEPT: "EXCEPT",
|
|
EXCLUDE: "EXCLUDE",
|
|
EXCLUSIVE: "EXCLUSIVE",
|
|
EXISTS: "EXISTS",
|
|
EXPLAIN: "EXPLAIN",
|
|
FAIL: "FAIL",
|
|
FILTER: "FILTER",
|
|
FIRST: "FIRST",
|
|
FOLLOWING: "FOLLOWING",
|
|
FOR: "FOR",
|
|
FOREIGN: "FOREIGN",
|
|
FROM: "FROM",
|
|
FUNCTION: "FUNCTION",
|
|
GLOB: "GLOB",
|
|
GROUP: "GROUP",
|
|
GROUPS: "GROUPS",
|
|
HAVING: "HAVING",
|
|
IF: "IF",
|
|
IF_NULL_ROW: "IF_NULL_ROW",
|
|
IGNORE: "IGNORE",
|
|
IMMEDIATE: "IMMEDIATE",
|
|
IN: "IN",
|
|
INDEX: "INDEX",
|
|
INDEXED: "INDEXED",
|
|
INITIALLY: "INITIALLY",
|
|
INNER: "INNER",
|
|
INSERT: "INSERT",
|
|
INSTEAD: "INSTEAD",
|
|
INTERSECT: "INTERSECT",
|
|
INTO: "INTO",
|
|
IS: "IS",
|
|
ISNOT: "ISNOT",
|
|
JOIN: "JOIN",
|
|
KEY: "KEY",
|
|
KEYPARTITIONS: "KEYPARTITIONS",
|
|
LAST: "LAST",
|
|
LEFT: "LEFT",
|
|
LIKE: "LIKE",
|
|
LRU: "LRU",
|
|
MATCH: "MATCH",
|
|
MAX: "MAX",
|
|
MIN: "MIN",
|
|
NO: "NO",
|
|
NATURAL: "NATURAL",
|
|
NOT: "NOT",
|
|
NOTBETWEEN: "NOTBETWEEN",
|
|
NOTEXISTS: "NOTEXISTS",
|
|
NOTGLOB: "NOTGLOB",
|
|
NOTHING: "NOTHING",
|
|
NOTIN: "NOTIN",
|
|
NOTLIKE: "NOTLIKE",
|
|
NOTMATCH: "NOTMATCH",
|
|
NOTREGEXP: "NOTREGEXP",
|
|
NULLS: "NULLS",
|
|
OF: "OF",
|
|
ON: "ON",
|
|
OR: "OR",
|
|
ORDER: "ORDER",
|
|
OTHERS: "OTHERS",
|
|
OUTER: "OUTER",
|
|
OVER: "OVER",
|
|
PARTITION: "PARTITION",
|
|
PLAN: "PLAN",
|
|
PRAGMA: "PRAGMA",
|
|
PRECEDING: "PRECEDING",
|
|
PRIMARY: "PRIMARY",
|
|
QUERY: "QUERY",
|
|
RANGE: "RANGE",
|
|
RANKED: "RANKED",
|
|
RECURSIVE: "RECURSIVE",
|
|
REFERENCES: "REFERENCES",
|
|
REGEXP: "REGEXP",
|
|
REGISTER: "REGISTER",
|
|
REINDEX: "REINDEX",
|
|
RELEASE: "RELEASE",
|
|
RENAME: "RENAME",
|
|
REPLACE: "REPLACE",
|
|
RESTRICT: "RESTRICT",
|
|
ROLLBACK: "ROLLBACK",
|
|
ROW: "ROW",
|
|
ROWS: "ROWS",
|
|
SAVEPOINT: "SAVEPOINT",
|
|
SELECT: "SELECT",
|
|
SELECT_COLUMN: "SELECT_COLUMN",
|
|
SET: "SET",
|
|
SIZE: "SIZE",
|
|
SHARDWIDTH: "SHARDWIDTH",
|
|
SHOW: "SHOW",
|
|
SPAN: "SPAN",
|
|
TABLE: "TABLE",
|
|
TABLES: "TABLES",
|
|
TEMP: "TEMP",
|
|
THEN: "THEN",
|
|
TIES: "TIES",
|
|
TIMEUNIT: "TIMEUNIT",
|
|
TIMEQUANTUM: "TIMEQUANTUM",
|
|
TO: "TO",
|
|
TOP: "TOP",
|
|
TOPN: "TOPN",
|
|
TRANSACTION: "TRANSACTION",
|
|
TRIGGER: "TRIGGER",
|
|
TRUTH: "TRUTH",
|
|
TTL: "TTL",
|
|
UNBOUNDED: "UNBOUNDED",
|
|
UNION: "UNION",
|
|
UNIQUE: "UNIQUE",
|
|
UPDATE: "UPDATE",
|
|
USING: "USING",
|
|
VACUUM: "VACUUM",
|
|
VALUES: "VALUES",
|
|
VARIABLE: "VARIABLE",
|
|
VECTOR: "VECTOR",
|
|
VIEW: "VIEW",
|
|
VIRTUAL: "VIRTUAL",
|
|
WHEN: "WHEN",
|
|
WHERE: "WHERE",
|
|
WINDOW: "WINDOW",
|
|
WITH: "WITH",
|
|
WITHOUT: "WITHOUT",
|
|
}
|
|
|
|
func (tok Token) String() string {
|
|
s := ""
|
|
if 0 <= tok && tok < Token(len(tokens)) {
|
|
s = tokens[tok]
|
|
}
|
|
if s == "" {
|
|
s = "token(" + strconv.Itoa(int(tok)) + ")"
|
|
}
|
|
return s
|
|
}
|
|
|
|
func Lookup(ident string) Token {
|
|
if tok, ok := keywords[strings.ToUpper(ident)]; ok {
|
|
return tok
|
|
}
|
|
return IDENT
|
|
}
|
|
|
|
func (tok Token) IsLiteral() bool {
|
|
return tok > literal_beg && tok < literal_end
|
|
}
|
|
|
|
func (tok Token) IsOperator() bool {
|
|
return tok > operator_beg && tok < operator_end
|
|
}
|
|
|
|
func (tok Token) IsKeyword() bool {
|
|
return tok > keyword_beg && tok < keyword_end
|
|
}
|
|
|
|
func (tok Token) IsBinaryOp() bool {
|
|
switch tok {
|
|
case PLUS, MINUS, STAR, SLASH, REM, CONCAT, NOT, BETWEEN,
|
|
LSHIFT, RSHIFT, BITAND, BITOR, LT, LE, GT, GE, EQ, NE,
|
|
IS, IN, LIKE, GLOB, MATCH, REGEXP, AND, OR:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func isIdentToken(tok Token) bool {
|
|
return tok == IDENT || tok == QIDENT
|
|
}
|
|
|
|
const (
|
|
LowestPrec = 0 // non-operators
|
|
UnaryPrec = 13
|
|
HighestPrec = 14
|
|
)
|
|
|
|
func (op Token) Precedence() int {
|
|
switch op {
|
|
case OR:
|
|
return 1
|
|
case AND:
|
|
return 2
|
|
case NOT:
|
|
return 3
|
|
case IS, MATCH, LIKE, GLOB, REGEXP, BETWEEN, IN, ISNOT, NE, EQ:
|
|
return 4
|
|
case GT, LE, LT, GE:
|
|
return 5
|
|
case ESCAPE:
|
|
return 6
|
|
case BITAND, BITOR, LSHIFT, RSHIFT:
|
|
return 7
|
|
case PLUS, MINUS:
|
|
return 8
|
|
case STAR, SLASH, REM:
|
|
return 9
|
|
case CONCAT:
|
|
return 10
|
|
case BITNOT:
|
|
return 11
|
|
}
|
|
return LowestPrec
|
|
}
|
|
|
|
type Pos struct {
|
|
Offset int // offset, starting at 0
|
|
Line int // line number, starting at 1
|
|
Column int // column number, starting at 1 (byte count)
|
|
}
|
|
|
|
// String returns a string representation of the position.
|
|
func (p Pos) String() string {
|
|
if !p.IsValid() {
|
|
return "-"
|
|
}
|
|
s := fmt.Sprintf("%d", p.Line)
|
|
if p.Column != 0 {
|
|
s += fmt.Sprintf(":%d", p.Column)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// IsValid returns true if p is non-zero.
|
|
func (p Pos) IsValid() bool {
|
|
return p != Pos{}
|
|
}
|
|
|
|
func assert(condition bool) {
|
|
if !condition {
|
|
panic("assert failed")
|
|
}
|
|
}
|