Files
DiceCloud/app/imports/parser/grammar.ne
Stefan Zermatten d578a87632 parser fix for chain indexing into nested arrays
`[ [‘a1’, ‘a2’ ], [‘b1’, ‘b2’] ][2][1]` => `'b1'`
2023-08-24 12:29:44 +02:00

174 lines
4.8 KiB
Plaintext

@preprocessor esmodule
@{%
import node from './parseTree/_index.js';
import moo from 'moo';
const lexer = moo.compile({
number: /[0-9]+(?:\.[0-9]+)?/,
string: {
match: /'[^']*'|"[^"]*"/,
value: s => s.slice(1, -1).replace('\\n', '\n'),
},
name: {
match: /[~#]?[a-zA-Z]*[a-ce-zA-Z][a-zA-Z0-9_]*/,
type: moo.keywords({
'keywords': ['true', 'false'],
}),
},
space: {
match: /\s+/,
lineBreaks: true,
},
diceOperator: ['d'],
separator: [',', ';'],
period: ['.'],
ifOperator: ['?'],
elseOperator: [':'],
multiplicativeOperator: ['*', '/'],
exponentOperator: ['^'],
additiveOperator: ['+', '-'],
moduloOperator: ['%'],
andOperator: ['&', '&&'],
orOperator: ['|', '||'],
stringDelimiters: ['\"', '\''],
equalityOperator: ['=', '==', '===', '!=', '!=='],
notOperator: ['!'],
relationalOperator: ['>', '<', '>=', '<='],
brackets: ['(', ')', '{', '}', '[', ']'],
});
function nuller() { return null; }
function operator([left, _1, operator, _2, right], fn){
return node.operator.create({
left,
right,
operator: operator.value,
fn
});
}
%}
# Use the Moo lexer
@lexer lexer
spacedExpression ->
_ expression _ {% d => d[1] %}
expression ->
ifStatement {% id %}
ifStatement ->
orExpression _ %ifOperator _ orExpression _ %elseOperator _ ifStatement {%
d => node.if.create({condition: d[0], consequent: d[4], alternative: d[8]})
%}
| orExpression {% id %}
orExpression ->
orExpression _ %orOperator _ andExpression {% d => operator(d, 'or') %}
| andExpression {% id %}
andExpression ->
andExpression _ %andOperator _ equalityExpression {% d => operator(d, 'and') %}
| equalityExpression {% id %}
equalityExpression ->
equalityExpression _ %equalityOperator _ relationalExpression {% d => operator(d, 'equality') %}
| relationalExpression {% id %}
relationalExpression ->
relationalExpression _ %relationalOperator _ additiveExpression {% d => operator(d, 'relation') %}
| additiveExpression {% id %}
additiveExpression ->
additiveExpression _ %additiveOperator _ remainderExpression {% d => operator(d, 'add') %}
| remainderExpression {% id %}
remainderExpression ->
remainderExpression _ %moduloOperator _ multiplicativeExpression {% d => operator(d, 'remainder') %}
| multiplicativeExpression {% id %}
multiplicativeExpression ->
multiplicativeExpression _ %multiplicativeOperator _ rollExpression {% d => operator(d, 'multiply') %}
| rollExpression {% id %}
rollExpression ->
rollExpression _ %diceOperator _ exponentExpression {% d => node.roll.create({left: d[0], right: d[4]}) %}
| singleRollExpression {% id %}
singleRollExpression ->
"d" _ singleRollExpression {% d => node.roll.create({left: node.constant.create({value: 1}), right: d[2]}) %}
| exponentExpression {% id %}
exponentExpression ->
callExpression _ %exponentOperator _ exponentExpression {% d => operator(d, 'exponent') %}
| unaryExpression {% id %}
unaryExpression ->
%additiveOperator _ unaryExpression {% d => node.unaryOperator.create({operator: d[0].value, right: d[2]})%}
| notExpression {% id %}
notExpression ->
%notOperator _ notExpression {% d => node.not.create({right: d[2]})%}
| callExpression {% id %}
callExpression ->
name _ arguments {%
d => node.call.create({functionName: d[0].name, args: d[2]})
%}
| indexExpression {% id %}
arguments ->
"(" _ (expression {% d => d[0] %}) ( _ %separator _ expression {% d => d[3] %} ):* _ ")" {%
d => [d[2], ...d[3]]
%}
| "(" _ ")" {% d => [] %}
indexExpression ->
indexExpression "[" _ expression _ "]" {% d => node.index.create({array: d[0], index: d[3]}) %}
| arrayExpression {% id %}
arrayExpression ->
"[" _ (expression {% d => d[0] %}) ( _ %separator _ expression {% d => d[3] %} ):* _ "]" {%
d => node.array.create({ values: [d[2], ...d[3]] })
%}
| "[" _ "]" {% d => node.array.create({ values: [] }) %}
| parenthesizedExpression {% id %}
parenthesizedExpression ->
"(" _ expression _ ")" {% d => node.parenthesis.create({content: d[2]}) %}
| accessorExpression {% id %}
accessorExpression ->
(%name {% d => d[0].value %}) ( "." keyExpression {% d => d[1] %} ):+ {%
d=> node.accessor.create({name: d[0], path: d[1]})
%}
| valueExpression {% id %}
keyExpression -> name {% d => d[0].name %}
| number {% d => d[0].value %}
valueExpression ->
name {% id %}
| number {% id %}
| string {% id %}
| boolean {% id %}
# A number or a function of a number
number ->
%number {% d => node.constant.create({value: +d[0].value}) %}
name ->
%name {% d => node.symbol.create({name: d[0].value}) %}
string ->
%string {% d => node.constant.create({value: d[0].value}) %}
boolean ->
"true" {% d => node.constant.create({value: true}) %}
| "false" {% d => node.constant.create({value: false}) %}
_ ->
null
| %space {% nuller %}