Files
DiceCloud/parser/grammar.ne
2019-03-27 11:25:34 +02:00

141 lines
3.4 KiB
Plaintext

@{%
const moo = require("moo");
const lexer = moo.compile({
number: /[0-9]+(?:\.[0-9]+)?/,
string: {
match: /'.*?'|".*?"/,
value: s => s.slice(1, -1),
},
name: {
match: /[a-zA-Z]+\w*?/,
type: moo.keywords({
'keywords': ['if', 'else', 'd'],
}),
},
space: {
match: /\s+/,
lineBreaks: true,
},
separators: [',', '.'],
multiplicativeOperator: ['*', '/'],
exponentOperator: ['^'],
additiveOperator: ['+', '-'],
unaryOperator: ['-'],
andOperator: ['&', '&&'],
orOperator: ['|', '||'],
stringDelimiters: ['\"', '\''],
equalityOperator: ['=', '==', '===', '!=', '!=='],
relationalOperator: ['>', '<', '>=', '<='],
brackets: ['(', ')', '{', '}'],
});
function nuller() { return null; }
class OperatorNode {
constructor({left, right, operator, fn}) {
this.left = left;
this.right = right;
this.fn = fn;
this.operator = operator;
}
}
function operator([left, _1, operator, _2, right], fn){
return new OperatorNode({
left,
right,
operator: operator.value,
fn
});
}
class SymbolNode {
constructor(name){
this.name = name;
}
}
class ConstantNode {
constructor(value, type){
this.type = type;
this.value = value;
}
}
%}
# Use the Moo lexer
@lexer lexer
ifStatement ->
"if" _ "(" _ expression _ ")" _ ifStatement _ "else" _ ifStatement {% d => ({condition: d[4], true: d[8], false: d[12]}) %}
| expression {% id %}
expression ->
equalityExpression {% d => d[0] %}
equalityExpression ->
equalityExpression _ %equalityOperator _ relationalExpression {% d => operator(d, 'equality') %}
| relationalExpression {% id %}
relationalExpression ->
relationalExpression _ %relationalOperator _ orExpression {% d => operator(d, 'relation') %}
| orExpression {% id %}
orExpression ->
orExpression _ %orOperator _ andExpression {% d => operator(d, 'or') %}
| andExpression {% id %}
andExpression ->
andExpression _ %andOperator _ additiveExpression {% d => operator(d, 'and') %}
| additiveExpression {% id %}
additiveExpression ->
additiveExpression _ %additiveOperator _ multiplicativeExpression {% d => operator(d, 'add') %}
| multiplicativeExpression {% id %}
multiplicativeExpression ->
multiplicativeExpression _ %multiplicativeOperator _ rollExpression {% d => operator(d, 'multiply') %}
| rollExpression {% id %}
rollExpression ->
rollExpression _ "d" _ exponentExpression {% d => operator(d, 'roll') %}
| exponentExpression {% id %}
exponentExpression ->
callExpression _ %exponentOperator _ exponentExpression {% d => operator(d, 'exponent') %}
| callExpression {% id %}
callExpression ->
name _ arguments {%
d => ({type: "call", function: d[0], arguments: d[2]})
%}
| parenthesizedExpression {% id %}
arguments ->
"(" _ (expression {% d => d[0] %}):? ( _ "," _ expression {% d => d[3] %} ):* _ ")" {%
d => [d[2], ...d[3]]
%}
parenthesizedExpression ->
"(" _ expression _ ")" {% d => d[2] %}
| valueExpression {% id %}
valueExpression ->
name {% id %}
| number {% id %}
| string {% id %}
# A number or a function of a number
number ->
%number {% d => new ConstantNode(d[0].value, 'number') %}
name ->
%name {% d => new SymbolNode(d[0].value) %}
string ->
%string {% d => new ConstantNode(d[0].value, 'string') %}
_ ->
null
| %space {% nuller %}