Merge pull request #24 from m-novikov/math-expressions

Improve mathematical expressions support
pull/315/head
Max Novikov 2022-06-11 11:11:03 +07:00 committed by GitHub
commit dbd2fcfeae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50831 additions and 35018 deletions

@ -1,3 +1,28 @@
const PREC = {
primary: 8,
unary: 7,
exp: 6,
multiplicative: 5,
additive: 4,
comparative: 3,
and: 2,
or: 1,
};
const multiplicative_operators = ["*", "/", "%", "<<", ">>", "&"];
const additive_operators = ["+", "-", "|", "#"];
const comparative_operators = [
"<",
"<=",
"<>",
"=",
">",
">=",
"~",
"!~",
"~*",
"!~*",
];
// Generate case insentitive match for SQL keyword
// In case of multiple word keyword provide a seq matcher
function kw(keyword) {
@ -458,15 +483,6 @@ module.exports = grammar({
optional(field("arguments", commaSep1($._expression))),
")",
),
comparison_operator: $ =>
prec.left(
6,
seq(
$._expression,
field("operator", choice("<", "<=", "<>", "=", ">", ">=")),
$._expression,
),
),
_parenthesized_expression: $ => seq("(", $._expression, ")"),
is_expression: $ =>
prec.left(
@ -481,9 +497,9 @@ module.exports = grammar({
distinct_from: $ => prec.left(seq(kw("DISTINCT FROM"), $._expression)),
boolean_expression: $ =>
choice(
prec.left(5, seq(kw("NOT"), $._expression)),
prec.left(4, seq($._expression, kw("AND"), $._expression)),
prec.left(3, seq($._expression, kw("OR"), $._expression)),
prec.left(PREC.unary, seq(kw("NOT"), $._expression)),
prec.left(PREC.and, seq($._expression, kw("AND"), $._expression)),
prec.left(PREC.or, seq($._expression, kw("OR"), $._expression)),
),
NULL: $ => kw("NULL"),
TRUE: $ => kw("TRUE"),
@ -529,13 +545,49 @@ module.exports = grammar({
),
array_element_access: $ =>
seq(choice($.identifier, $.argument_reference), "[", $._expression, "]"),
binary_expression: $ =>
prec.left(
choice(
seq($._expression, "~", $._expression),
seq($._expression, "+", $._expression),
unary_expression: $ =>
prec(
PREC.unary,
seq(
field(
"operator",
choice(
"+",
"-",
"!!", // Factorial op (Removed in Postgres >= 14)
"~", // Bitwise not
"@", // Absolute value
"|/", // square root
"||/", // cube root
),
),
field("operand", $._expression),
),
),
binary_expression: $ => {
const table = [
[PREC.exp, "^"],
[PREC.multiplicative, choice(...multiplicative_operators)],
[PREC.additive, choice(...additive_operators)],
[PREC.comparative, choice(...comparative_operators)],
];
return choice(
...table.map(([precedence, operator]) =>
prec.left(
precedence,
seq(
field("left", $._expression),
field("operator", operator),
field("right", $._expression),
),
),
),
);
},
binary_operator: $ => choice("=", "&&", "||"),
asterisk_expression: $ => seq(optional(seq($.identifier, ".")), "*"),
interval_expression: $ => seq(token(prec(1, kw("INTERVAL"))), $.string),
@ -552,12 +604,12 @@ module.exports = grammar({
$.asterisk_expression,
$._identifier,
$.number,
$.comparison_operator,
$.in_expression,
$.is_expression,
$.boolean_expression,
$._parenthesized_expression,
$.type_cast,
$.unary_expression,
$.binary_expression,
$.array_element_access,
$.argument_reference,

335
src/grammar.json vendored

@ -4042,56 +4042,6 @@
}
]
},
"comparison_operator": {
"type": "PREC_LEFT",
"value": 6,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_expression"
},
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "<"
},
{
"type": "STRING",
"value": "<="
},
{
"type": "STRING",
"value": "<>"
},
{
"type": "STRING",
"value": "="
},
{
"type": "STRING",
"value": ">"
},
{
"type": "STRING",
"value": ">="
}
]
}
},
{
"type": "SYMBOL",
"name": "_expression"
}
]
}
},
"_parenthesized_expression": {
"type": "SEQ",
"members": [
@ -4205,7 +4155,7 @@
"members": [
{
"type": "PREC_LEFT",
"value": 5,
"value": 7,
"content": {
"type": "SEQ",
"members": [
@ -4227,7 +4177,7 @@
},
{
"type": "PREC_LEFT",
"value": 4,
"value": 2,
"content": {
"type": "SEQ",
"members": [
@ -4253,7 +4203,7 @@
},
{
"type": "PREC_LEFT",
"value": 3,
"value": 1,
"content": {
"type": "SEQ",
"members": [
@ -4682,48 +4632,279 @@
}
]
},
"binary_expression": {
"type": "PREC_LEFT",
"value": 0,
"unary_expression": {
"type": "PREC",
"value": 7,
"content": {
"type": "CHOICE",
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "+"
},
{
"type": "STRING",
"value": "-"
},
{
"type": "STRING",
"value": "!!"
},
{
"type": "STRING",
"value": "~"
},
{
"type": "STRING",
"value": "@"
},
{
"type": "STRING",
"value": "|/"
},
{
"type": "STRING",
"value": "||/"
}
]
}
},
{
"type": "FIELD",
"name": "operand",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
}
},
"binary_expression": {
"type": "CHOICE",
"members": [
{
"type": "PREC_LEFT",
"value": 6,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
},
{
"type": "STRING",
"value": "~"
"type": "FIELD",
"name": "operator",
"content": {
"type": "STRING",
"value": "^"
}
},
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
},
{
}
},
{
"type": "PREC_LEFT",
"value": 5,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
},
{
"type": "STRING",
"value": "+"
"type": "FIELD",
"name": "operator",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "*"
},
{
"type": "STRING",
"value": "/"
},
{
"type": "STRING",
"value": "%"
},
{
"type": "STRING",
"value": "<<"
},
{
"type": "STRING",
"value": ">>"
},
{
"type": "STRING",
"value": "&"
}
]
}
},
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
}
]
}
},
{
"type": "PREC_LEFT",
"value": 4,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
},
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "+"
},
{
"type": "STRING",
"value": "-"
},
{
"type": "STRING",
"value": "|"
},
{
"type": "STRING",
"value": "#"
}
]
}
},
{
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
}
},
{
"type": "PREC_LEFT",
"value": 3,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
},
{
"type": "FIELD",
"name": "operator",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "<"
},
{
"type": "STRING",
"value": "<="
},
{
"type": "STRING",
"value": "<>"
},
{
"type": "STRING",
"value": "="
},
{
"type": "STRING",
"value": ">"
},
{
"type": "STRING",
"value": ">="
},
{
"type": "STRING",
"value": "~"
},
{
"type": "STRING",
"value": "!~"
},
{
"type": "STRING",
"value": "~*"
},
{
"type": "STRING",
"value": "!~*"
}
]
}
},
{
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
}
}
]
},
"binary_operator": {
"type": "CHOICE",
@ -4853,10 +5034,6 @@
"type": "SYMBOL",
"name": "number"
},
{
"type": "SYMBOL",
"name": "comparison_operator"
},
{
"type": "SYMBOL",
"name": "in_expression"
@ -4877,6 +5054,10 @@
"type": "SYMBOL",
"name": "type_cast"
},
{
"type": "SYMBOL",
"name": "unary_expression"
},
{
"type": "SYMBOL",
"name": "binary_expression"

905
src/node-types.json vendored

File diff suppressed because it is too large Load Diff

84392
src/parser.c vendored

File diff suppressed because it is too large Load Diff

@ -36,7 +36,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(identifier)))
(join_clause
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -46,7 +46,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -56,7 +56,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -66,7 +66,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -76,7 +76,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -86,7 +86,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -96,7 +96,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))
@ -106,7 +106,7 @@ LEFT OUTER JOIN t7 ON t.a = t7.a;
(join_clause
(join_type)
(identifier)
(comparison_operator
(binary_expression
(dotted_name
(identifier)
(identifier))

@ -276,7 +276,7 @@ SELECT 1 < 2;
(select_statement
(select_clause
(select_clause_body
(comparison_operator
(binary_expression
(number)
(number))))))
@ -320,6 +320,89 @@ SELECT foo.bar FROM a;
(from_clause
(identifier))))
================================================================================
Operator precedence
================================================================================
SELECT 1 + -1, 1 <= 1;
SELECT 1 * 2 + 3, 3 + 1 * 2, (3 + 1) * 2;
SELECT 1 / 2 + 3, 3 + 1 / 2, (3 + 1) / 2;
SELECT @1, !!2, |/3, ||/4, ~5, -6, +7;
SELECT @ - 2;
--------------------------------------------------------------------------------
(source_file
(select_statement
(select_clause
(select_clause_body
(binary_expression
(number)
(unary_expression
(number)))
(binary_expression
(number)
(number)))))
(select_statement
(select_clause
(select_clause_body
(binary_expression
(binary_expression
(number)
(number))
(number))
(binary_expression
(number)
(binary_expression
(number)
(number)))
(binary_expression
(binary_expression
(number)
(number))
(number)))))
(select_statement
(select_clause
(select_clause_body
(binary_expression
(binary_expression
(number)
(number))
(number))
(binary_expression
(number)
(binary_expression
(number)
(number)))
(binary_expression
(binary_expression
(number)
(number))
(number)))))
(select_statement
(select_clause
(select_clause_body
(unary_expression
(number))
(unary_expression
(number))
(unary_expression
(number))
(unary_expression
(number))
(unary_expression
(number))
(unary_expression
(number))
(unary_expression
(number)))))
(select_statement
(select_clause
(select_clause_body
(unary_expression
(unary_expression
(number)))))))
================================================================================
SELECT statement with comparison expression and is expression
================================================================================
@ -333,7 +416,7 @@ SELECT 1 < 2 IS TRUE;
(select_clause
(select_clause_body
(is_expression
(comparison_operator
(binary_expression
(number)
(number))
(TRUE))))))
@ -350,7 +433,7 @@ SELECT foo(bar, baz) < 10;
(select_statement
(select_clause
(select_clause_body
(comparison_operator
(binary_expression
(function_call
(identifier)
(identifier)
@ -392,12 +475,12 @@ SELECT TRUE AND foo(1) OR FALSE AND NOT a = b.c;
(number)))
(boolean_expression
(FALSE)
(boolean_expression
(comparison_operator
(binary_expression
(boolean_expression
(identifier))
(dotted_name
(identifier)
(dotted_name
(identifier)
(identifier))))))))))
(identifier)))))))))
================================================================================
SELECT parenthesized expression
@ -686,7 +769,7 @@ CREATE INDEX test_idx ON table(col1) WHERE col1 <> 1
(index_table_parameters
(identifier))
(where_clause
(comparison_operator
(binary_expression
(identifier)
(number)))))
@ -1301,12 +1384,12 @@ CREATE TABLE foo(
(type
(identifier)))
(check
(comparison_operator
(binary_expression
(identifier)
(identifier)))
(identifier)
(check
(comparison_operator
(binary_expression
(function_call
(identifier)
(identifier))
@ -1473,7 +1556,7 @@ CREATE FUNCTION add(IN int, OUT int, INOUT int, VARIADIC int) RETURNS int
(from_clause
(identifier))
(where_clause
(comparison_operator
(binary_expression
(identifier)
(argument_reference)))))
(language)))
@ -1506,7 +1589,7 @@ CREATE FUNCTION add(text) RETURNS SETOF int
(from_clause
(identifier))
(where_clause
(comparison_operator
(binary_expression
(identifier)
(argument_reference)))))
(language)))
@ -1542,7 +1625,7 @@ CREATE FUNCTION add(text) RETURNS SETOF int NOT NULL
(from_clause
(identifier))
(where_clause
(comparison_operator
(binary_expression
(identifier)
(argument_reference)))))
(language)))

@ -38,6 +38,6 @@ UPDATE table1 SET col1 = 3, col2 = 4 WHERE col1 > col2
(identifier)
(number))))
(where_clause
(comparison_operator
(binary_expression
(identifier)
(identifier)))))