dockerfile/examples/omnivore/api/liqe/src/grammar.ne

296 lines
9.4 KiB
Plaintext
Raw Normal View History

2024-03-15 14:52:38 +08:00
@preprocessor typescript
main -> _ logical_expression _ {% (data) => data[1] %}
# Whitespace: `_` is optional, `__` is mandatory.
_ -> whitespace_character:* {% (data) => data[0].length %}
__ -> whitespace_character:+ {% (data) => data[0].length %}
whitespace_character -> [ \t\n\v\f] {% id %}
# # Numbers
# decimal -> "-":? [0-9]:+ ("." [0-9]:+):? {%
# (data) => parseFloat(
# (data[0] || "") +
# data[1].join("") +
# (data[2] ? "."+data[2][1].join("") : "")
# )
# %}
# Double-quoted string
dqstring -> "\"" dstrchar:* "\"" {% (data) => data[1].join('') %}
sqstring -> "'" sstrchar:* "'" {% (data) => data[1].join('') %}
dstrchar -> [^\\"\n] {% id %}
| "\\" strescape {%
(data) => JSON.parse("\""+data.join("")+"\"")
%}
sstrchar -> [^\\'\n] {% id %}
| "\\" strescape
{% (data) => JSON.parse("\"" + data.join("") + "\"") %}
| "\\'"
{% () => "'" %}
strescape -> ["\\/bfnrt] {% id %}
| "u" [a-fA-F0-9] [a-fA-F0-9] [a-fA-F0-9] [a-fA-F0-9] {%
(data) => data.join('')
%}
logical_expression -> two_op_logical_expression {% id %}
two_op_logical_expression ->
pre_two_op_logical_expression boolean_operator post_one_op_logical_expression {% (data) => ({
type: 'LogicalExpression',
location: {
start: data[0].location.start,
end: data[2].location.end,
},
operator: data[1],
left: data[0],
right: data[2]
}) %}
| pre_two_op_implicit_logical_expression __ post_one_op_implicit_logical_expression {% (data) => ({
type: 'LogicalExpression',
location: {
start: data[0].location.start,
end: data[2].location.end,
},
operator: {
operator: 'AND',
type: 'ImplicitBooleanOperator'
},
left: data[0],
right: data[2]
}) %}
| one_op_logical_expression {% d => d[0] %}
pre_two_op_implicit_logical_expression ->
two_op_logical_expression {% d => d[0] %}
| parentheses_open _ two_op_logical_expression _ parentheses_close {% d => ({location: {start: d[0].location.start, end: d[4].location.start + 1, }, type: 'ParenthesizedExpression', expression: d[2]}) %}
post_one_op_implicit_logical_expression ->
one_op_logical_expression {% d => d[0] %}
| parentheses_open _ one_op_logical_expression _ parentheses_close {% d => ({location: {start: d[0].location.start, end: d[4].location.start + 1, },type: 'ParenthesizedExpression', expression: d[2]}) %}
pre_two_op_logical_expression ->
two_op_logical_expression __ {% d => d[0] %}
| parentheses_open _ two_op_logical_expression _ parentheses_close {% d => ({location: {start: d[0].location.start, end: d[4].location.start + 1, },type: 'ParenthesizedExpression', expression: d[2]}) %}
one_op_logical_expression ->
parentheses_open _ parentheses_close {% d => ({location: {start: d[0].location.start, end: d[2].location.start + 1, },type: 'ParenthesizedExpression', expression: {
type: 'EmptyExpression',
location: {
start: d[0].location.start + 1,
end: d[0].location.start + 1,
},
}}) %}
| parentheses_open _ two_op_logical_expression _ parentheses_close {% d => ({location: {start: d[0].location.start, end: d[4].location.start + 1, },type: 'ParenthesizedExpression', expression: d[2]}) %}
| "NOT" post_boolean_primary {% (data, start) => {
return {
type: 'UnaryOperator',
operator: 'NOT',
operand: data[1],
location: {
start,
end: data[1].location.end,
}
};
} %}
| "-" boolean_primary {% (data, start) => {
return {
type: 'UnaryOperator',
operator: '-',
operand: data[1],
location: {
start,
end: data[1].location.end,
}
};
} %}
| boolean_primary {% d => d[0] %}
post_one_op_logical_expression ->
__ one_op_logical_expression {% d => d[1] %}
| parentheses_open _ one_op_logical_expression _ parentheses_close {% d => ({location: {start: d[0].location, end: d[4].location + 1, },type: 'ParenthesizedExpression', expression: d[2]}) %}
parentheses_open ->
"(" {% (data, start) => ({location: {start}}) %}
parentheses_close ->
")" {% (data, start) => ({location: {start}}) %}
boolean_operator ->
"OR" {% (data, start) => ({location: {start, end: start + 2}, operator: 'OR', type: 'BooleanOperator'}) %}
| "AND" {% (data, start) => ({location: {start, end: start + 3}, operator: 'AND', type: 'BooleanOperator'}) %}
boolean_primary ->
tag_expression {% id %}
post_boolean_primary ->
__ parentheses_open _ two_op_logical_expression _ parentheses_close {% d => ({location: {start: d[1].location.start, end: d[5].location.start + 1, }, type: 'ParenthesizedExpression', expression: d[3]}) %}
| __ boolean_primary {% d => d[1] %}
tag_expression ->
field comparison_operator expression {% (data, start) => {
const field = {
type: 'Field',
name: data[0].name,
path: data[0].name.split('.').filter(Boolean),
quoted: data[0].quoted,
quotes: data[0].quotes,
location: data[0].location,
};
if (!data[0].quotes) {
delete field.quotes;
}
return {
location: {
start,
end: data[2].expression.location.end,
},
field,
operator: data[1],
...data[2]
}
} %}
| field comparison_operator {% (data, start) => {
const field = {
type: 'Field',
name: data[0].name,
path: data[0].name.split('.').filter(Boolean),
quoted: data[0].quoted,
quotes: data[0].quotes,
location: data[0].location,
};
if (!data[0].quotes) {
delete field.quotes;
}
return {
type: 'Tag',
location: {
start,
end: data[1].location.end,
},
field,
operator: data[1],
expression: {
type: 'EmptyExpression',
location: {
start: data[1].location.end,
end: data[1].location.end,
},
}
}
} %}
| expression {% (data, start) => {
return {location: {start, end: data[0].expression.location.end}, field: {type: 'ImplicitField'}, ...data[0]};
} %}
field ->
[_a-zA-Z$] [a-zA-Z\d_$.]:* {% (data, start) => ({type: 'LiteralExpression', name: data[0] + data[1].join(''), quoted: false, location: {start, end: start + (data[0] + data[1].join('')).length}}) %}
| sqstring {% (data, start) => ({type: 'LiteralExpression', name: data[0], quoted: true, quotes: 'single', location: {start, end: start + data[0].length + 2}}) %}
| dqstring {% (data, start) => ({type: 'LiteralExpression', name: data[0], quoted: true, quotes: 'double', location: {start, end: start + data[0].length + 2}}) %}
expression ->
# decimal {% (data, start) => ({type: 'Tag', expression: {location: {start, end: start + data.join('').length}, type: 'LiteralExpression', quoted: false, value: Number(data.join(''))}}) %}
regex {% (data, start) => ({type: 'Tag', expression: {location: {start, end: start + data.join('').length}, type: 'RegexExpression', value: data.join('')}}) %}
# | range {% (data) => data[0] %}
| unquoted_value {% (data, start, reject) => {
const value = data.join('');
if (data[0] === 'AND' || data[0] === 'OR' || data[0] === 'NOT') {
return reject;
}
let normalizedValue;
if (value === 'true') {
normalizedValue = true;
} else if (value === 'false') {
normalizedValue = false;
} else if (value === 'null') {
normalizedValue = null;
} else {
normalizedValue = value;
}
return {
type: 'Tag',
expression: {
location: {
start,
end: start + value.length,
},
type: 'LiteralExpression',
quoted: false,
value: normalizedValue
},
};
} %}
| sqstring {% (data, start) => ({type: 'Tag', expression: {location: {start, end: start + data.join('').length + 2}, type: 'LiteralExpression', quoted: true, quotes: 'single', value: data.join('')}}) %}
| dqstring {% (data, start) => ({type: 'Tag', expression: {location: {start, end: start + data.join('').length + 2}, type: 'LiteralExpression', quoted: true, quotes: 'double', value: data.join('')}}) %}
# range ->
# range_open decimal " TO " decimal range_close {% (data, start) => {
# return {
# location: {
# start,
# },
# type: 'Tag',
# expression: {
# location: {
# start: data[0].location.start,
# end: data[4].location.start + 1,
# },
# type: 'RangeExpression',
# range: {
# min: data[1],
# minInclusive: data[0].inclusive,
# maxInclusive: data[4].inclusive,
# max: data[3],
# }
# }
# }
# } %}
#
# range_open ->
# "[" {% (data, start) => ({location: {start}, inclusive: true}) %}
# | "{" {% (data, start) => ({location: {start}, inclusive: false}) %}
#
# range_close ->
# "]" {% (data, start) => ({location: {start}, inclusive: true}) %}
# | "}" {% (data, start) => ({location: {start}, inclusive: false}) %}
comparison_operator ->
(
":"
| ":="
| ":>"
| ":<"
| ":>="
| ":<="
) {% (data, start) => ({location: {start, end: start + data[0][0].length}, type: 'ComparisonOperator', operator: data[0][0]}) %}
regex ->
regex_body regex_flags {% d => d.join('') %}
regex_body ->
"/" regex_body_char:* "/" {% (data) => '/' + data[1].join('') + '/' %}
regex_body_char ->
[^\\] {% id %}
| "\\" [^\\] {% d => '\\' + d[1] %}
regex_flags ->
null |
[gmiyusd]:+ {% d => d[0].join('') %}
unquoted_value ->
[a-zA-Z_*?@#$\u0080-\uFFFF0-9] [a-zA-Z\.\-_*?@#$\u0080-\uFFFF0-9]:* {% d => d[0] + d[1].join('') %}