featurebase/sql3/parser/token.go
2022-11-07 10:51:55 -06:00

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")
}
}