Skip to content

Commit e48c037

Browse files
authored
Merge pull request #45 from mindsdb/add-operators
Add operators `<<`, `>>`, `:=`, `&`, `|`, `^`
2 parents 8115913 + e482155 commit e48c037

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

mindsdb_sql_parser/__init__.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ def __init__(self, lexer, parser):
1313
self.parser = parser
1414
self.lexer = lexer
1515

16-
def process(self, error_info):
16+
def process(self) -> str:
17+
error_info = self.parser.error_info
1718
self.tokens = [t for t in error_info['tokens'] if t is not None]
1819
self.bad_token = error_info['bad_token']
1920
self.expected_tokens = error_info['expected_tokens']
@@ -48,7 +49,11 @@ def error_location(self):
4849
else:
4950
line = line.ljust(token.index)
5051

51-
line += token.value
52+
if token.type == 'VARIABLE':
53+
line += f'@{token.value}'
54+
else:
55+
line += token.value
56+
5257
lines_idx[token.lineno] = line
5358

5459
msgs = []
@@ -175,7 +180,7 @@ def parse_sql(sql, dialect=None):
175180
if ast is None:
176181

177182
eh = ErrorHandling(lexer, parser)
178-
message = eh.process(parser.error_info)
183+
message = eh.process()
179184

180185
raise ParsingException(message)
181186

mindsdb_sql_parser/lexer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ class MindsDBLexer(Lexer):
7171
LBRACE, RBRACE, LBRACKET, RBRACKET, COLON, SEMICOLON,
7272

7373
# Operators
74-
PLUS, MINUS, MATCH, NOT_MATCH, DIVIDE, MODULO,
75-
EQUALS, NEQUALS, GREATER, GEQ, LESS, LEQ,
74+
PLUS, MINUS, MATCH, NOT_MATCH, DIVIDE, MODULO, BIT_AND, BIT_OR, BIT_XOR,
75+
ASSIGN_COLON, RIGHT_SHIFT, LEFT_SHIFT, EQUALS, NEQUALS, GREATER, GEQ, LESS, LEQ,
7676
AND, OR, NOT, IS, IS_NOT, TYPECAST,
7777
IN, NOT_IN, LIKE, NOT_LIKE, CONCAT, BETWEEN, WINDOW, OVER, PARTITION_BY,
7878
VECT_L2, VECT_L1, VECT_INNER, VECT_COS, VECT_HAMM, VECT_JACC,
@@ -272,6 +272,9 @@ class MindsDBLexer(Lexer):
272272
LPAREN = r'\('
273273
RPAREN = r'\)'
274274
PARAMETER = r'\?'
275+
276+
ASSIGN_COLON = r':='
277+
275278
# json
276279
LBRACE = r'\{'
277280
RBRACE = r'\}'
@@ -296,6 +299,10 @@ class MindsDBLexer(Lexer):
296299
NOT_MATCH = r'!~'
297300
DIVIDE = r'/'
298301
MODULO = r'%'
302+
BIT_AND = r'&'
303+
BIT_XOR = r'\^'
304+
RIGHT_SHIFT = r'>>'
305+
LEFT_SHIFT = r'<<'
299306
EQUALS = r'='
300307
NEQUALS = r'(!=|<>)'
301308
GEQ = r'>='
@@ -313,6 +320,7 @@ class MindsDBLexer(Lexer):
313320
IN = r'\bIN\b'
314321
CAST = r'\bCAST\b'
315322
CONCAT = r'\|\|'
323+
BIT_OR = r'\|'
316324
BETWEEN = r'\bBETWEEN\b'
317325
INTERVAL = r'\bINTERVAL\b'
318326
WINDOW = r'\bWINDOW\b'

mindsdb_sql_parser/parser.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ class MindsDBParser(Parser):
4646
('left', OR),
4747
('left', AND),
4848
('right', UNOT),
49-
('left', EQUALS, NEQUALS),
50-
('nonassoc', LESS, LEQ, GREATER, GEQ, IN, NOT_IN, BETWEEN, IS, IS_NOT, NOT_LIKE, LIKE),
49+
('left', EQUALS, NEQUALS, ASSIGN_COLON),
50+
('nonassoc', LESS, LEQ, GREATER, GEQ, IN, NOT_IN, BETWEEN, IS, IS_NOT, NOT_LIKE, LIKE, RIGHT_SHIFT, LEFT_SHIFT),
5151
('left', JSON_GET),
5252
('left', PLUS, MINUS),
53+
('left', BIT_AND, BIT_XOR, BIT_OR),
5354
('left', STAR, DIVIDE, TYPECAST, MODULO),
5455
('right', UMINUS), # Unary minus operator, unary not
5556

@@ -1631,8 +1632,14 @@ def star(self, p):
16311632
'expr STAR expr',
16321633
'expr DIVIDE expr',
16331634
'expr MODULO expr',
1635+
'expr BIT_AND expr',
1636+
'expr BIT_XOR expr',
1637+
'expr BIT_OR expr',
1638+
'expr ASSIGN_COLON expr',
16341639
'expr EQUALS expr',
16351640
'expr NEQUALS expr',
1641+
'expr RIGHT_SHIFT expr',
1642+
'expr LEFT_SHIFT expr',
16361643
'expr GEQ expr',
16371644
'expr GREATER expr',
16381645
'expr GEQ LAST',
@@ -1657,6 +1664,10 @@ def star(self, p):
16571664
'expr NOT_IN expr',
16581665
'expr IN expr',)
16591666
def expr(self, p):
1667+
if p[1] == ':=':
1668+
# allow 'assign' only for variables
1669+
if not isinstance(p[0], Variable):
1670+
raise ParsingException("Assignment `:=` allowed only to variables (@var := ...)")
16601671
if hasattr(p, 'LAST'):
16611672
arg1 = Last()
16621673
else:

tests/test_base_sql/test_base_lexer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ def test_binary_ops(self):
120120
('>=', 'GEQ'),
121121
('<', 'LESS'),
122122
('<=', 'LEQ'),
123+
('>>', 'RIGHT_SHIFT'),
124+
('<<', 'LEFT_SHIFT'),
125+
(':=', 'ASSIGN_COLON'),
126+
('&', 'BIT_AND'),
127+
('|', 'BIT_OR'),
128+
('^', 'BIT_XOR'),
123129
('AND', 'AND'),
124130
('OR', 'OR'),
125131
('IS', 'IS'),

tests/test_base_sql/test_select_operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
class TestOperations:
88
def test_select_binary_operations(self):
9-
for op in ['+', '-', '/', '*', '%', '=', '!=', '>', '<', '>=', '<=',
10-
'is', 'IS NOT', 'like', 'in', 'and', 'or', '||']:
9+
for op in ['+', '-', '/', '*', '%', '=', '!=', '>', '<', '>=', '<=', '>>', '<<',
10+
'is', 'IS NOT', 'like', 'in', 'and', 'or', '||', '&', '|', '^']:
1111
sql = f'SELECT column1 {op.upper()} column2 FROM tab'
1212
ast = parse_sql(sql)
1313

0 commit comments

Comments
 (0)