diff --git a/parser/grammar.html b/parser/grammar.html
index e69de29b..3b0a39e8 100644
--- a/parser/grammar.html
+++ b/parser/grammar.html
@@ -0,0 +1,1251 @@
+
+
+
+
+
+
+
+ifStatement
+
+
+
+
+callExpression
+
+
+
+
+arguments
+
+
+
+
+expression
+
+
+
+
+equalityExpression
+
+
+
+
+relationalExpression
+
+
+
+
+orExpression
+
+
+
+
+andExpression
+
+
+
+
+additiveExpression
+
+
+
+
+multiplicativeExpression
+
+
+
+
+rollExpression
+
+
+
+
+exponentExpression
+
+
+
+
+parenthesizedExpression
+
+
+
+
+valueExpression
+
+
+
+
+number
+
+
+
+
+name
+
+
+
+
+string
+
+
+
+
+_
+
+
+
+
+
+
\ No newline at end of file
diff --git a/parser/grammar.js b/parser/grammar.js
index 9b4fbca7..4b1e8dd9 100644
--- a/parser/grammar.js
+++ b/parser/grammar.js
@@ -7,6 +7,7 @@ function id(x) { return x[0]; }
const lexer = moo.compile({
number: /[0-9]+(?:\.[0-9]+)?/,
+ string: /'.*?'|".*?"/,
name: {match: /[a-zA-Z]+\w*?/, type: moo.keywords({
'keywords': ['if', 'else', 'd'],
})},
@@ -20,23 +21,66 @@ function id(x) { return x[0]; }
orOperator: ['|', '||'],
equalityOperator: ['=', '==', '===', '!=', '!=='],
relationalOperator: ['>', '<', '>=', '<='],
- brackets: {match: ['(', ')', '{', '}'], value: () => null},
+ brackets: ['(', ')', '{', '}'],
});
function nuller() { return null; }
- function operator([left, _1, op, _2, right]){
- return {type: 'operation', operator: op.value, left, right};
+ 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.value = value;
+ this.type = type;
+ }
}
var grammar = {
Lexer: lexer,
ParserRules: [
- {"name": "ifStatement", "symbols": [{"literal":"if"}, "_", {"literal":"("}, "_", "callExpression", "_", {"literal":")"}, "_", "ifStatement", "_", {"literal":"else"}, "_", "ifStatement"], "postprocess": d => ({condition: d[4], true: d[8], false: d[12]})},
- {"name": "ifStatement", "symbols": ["callExpression"], "postprocess": id},
+ {"name": "ifStatement", "symbols": [{"literal":"if"}, "_", {"literal":"("}, "_", "expression", "_", {"literal":")"}, "_", "ifStatement", "_", {"literal":"else"}, "_", "ifStatement"], "postprocess": d => ({condition: d[4], true: d[8], false: d[12]})},
+ {"name": "ifStatement", "symbols": ["expression"], "postprocess": id},
+ {"name": "expression", "symbols": ["equalityExpression"], "postprocess": d => d[0]},
+ {"name": "equalityExpression", "symbols": ["equalityExpression", "_", (lexer.has("equalityOperator") ? {type: "equalityOperator"} : equalityOperator), "_", "relationalExpression"], "postprocess": d => operator(d, 'equality')},
+ {"name": "equalityExpression", "symbols": ["relationalExpression"], "postprocess": id},
+ {"name": "relationalExpression", "symbols": ["relationalExpression", "_", (lexer.has("relationalOperator") ? {type: "relationalOperator"} : relationalOperator), "_", "orExpression"], "postprocess": d => operator(d, 'relation')},
+ {"name": "relationalExpression", "symbols": ["orExpression"], "postprocess": id},
+ {"name": "orExpression", "symbols": ["orExpression", "_", (lexer.has("orOperator") ? {type: "orOperator"} : orOperator), "_", "andExpression"], "postprocess": d => operator(d, 'or')},
+ {"name": "orExpression", "symbols": ["andExpression"], "postprocess": id},
+ {"name": "andExpression", "symbols": ["andExpression", "_", (lexer.has("andOperator") ? {type: "andOperator"} : andOperator), "_", "additiveExpression"], "postprocess": d => operator(d, 'and')},
+ {"name": "andExpression", "symbols": ["additiveExpression"], "postprocess": id},
+ {"name": "additiveExpression", "symbols": ["additiveExpression", "_", (lexer.has("additiveOperator") ? {type: "additiveOperator"} : additiveOperator), "_", "multiplicativeExpression"], "postprocess": d => operator(d, 'add')},
+ {"name": "additiveExpression", "symbols": ["multiplicativeExpression"], "postprocess": id},
+ {"name": "multiplicativeExpression", "symbols": ["multiplicativeExpression", "_", (lexer.has("multiplicativeOperator") ? {type: "multiplicativeOperator"} : multiplicativeOperator), "_", "rollExpression"], "postprocess": d => operator(d, 'multiply')},
+ {"name": "multiplicativeExpression", "symbols": ["rollExpression"], "postprocess": id},
+ {"name": "rollExpression", "symbols": ["rollExpression", "_", {"literal":"d"}, "_", "exponentExpression"], "postprocess": d => operator(d, 'roll')},
+ {"name": "rollExpression", "symbols": ["exponentExpression"], "postprocess": id},
+ {"name": "exponentExpression", "symbols": ["callExpression", "_", (lexer.has("exponentOperator") ? {type: "exponentOperator"} : exponentOperator), "_", "exponentExpression"], "postprocess": d => operator(d, 'exponent')},
+ {"name": "exponentExpression", "symbols": ["callExpression"], "postprocess": id},
{"name": "callExpression", "symbols": ["name", "_", "arguments"], "postprocess":
d => ({type: "call", function: d[0], arguments: d[2]})
},
- {"name": "callExpression", "symbols": ["expression"], "postprocess": id},
+ {"name": "callExpression", "symbols": ["parenthesizedExpression"], "postprocess": id},
{"name": "arguments$ebnf$1$subexpression$1", "symbols": ["expression"], "postprocess": d => d[0]},
{"name": "arguments$ebnf$1", "symbols": ["arguments$ebnf$1$subexpression$1"], "postprocess": id},
{"name": "arguments$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}},
@@ -46,27 +90,14 @@ var grammar = {
{"name": "arguments", "symbols": [{"literal":"("}, "_", "arguments$ebnf$1", "arguments$ebnf$2", "_", {"literal":")"}], "postprocess":
d => [d[2], ...d[3]]
},
- {"name": "expression", "symbols": ["equalityExpression"], "postprocess": id},
- {"name": "equalityExpression", "symbols": ["equalityExpression", "_", (lexer.has("equalityOperator") ? {type: "equalityOperator"} : equalityOperator), "_", "relationalExpression"], "postprocess": operator},
- {"name": "equalityExpression", "symbols": ["relationalExpression"], "postprocess": id},
- {"name": "relationalExpression", "symbols": ["relationalExpression", "_", (lexer.has("relationalOperator") ? {type: "relationalOperator"} : relationalOperator), "_", "additiveExpression"], "postprocess": operator},
- {"name": "relationalExpression", "symbols": ["additiveExpression"], "postprocess": id},
- {"name": "orExpression", "symbols": ["orExpression", "_", (lexer.has("orOperator") ? {type: "orOperator"} : orOperator), "_", "andExpression"], "postprocess": operator},
- {"name": "orExpression", "symbols": ["andExpression"], "postprocess": id},
- {"name": "andExpression", "symbols": ["andExpression", "_", (lexer.has("andOperator") ? {type: "andOperator"} : andOperator), "_", "equalityExpression"], "postprocess": operator},
- {"name": "andExpression", "symbols": ["equalityExpression"], "postprocess": id},
- {"name": "additiveExpression", "symbols": ["additiveExpression", "_", (lexer.has("additiveOperator") ? {type: "additiveOperator"} : additiveOperator), "_", "rollExpression"], "postprocess": operator},
- {"name": "additiveExpression", "symbols": ["rollExpression"], "postprocess": id},
- {"name": "rollExpression", "symbols": ["rollExpression", "_", {"literal":"d"}, "_", "multiplicativeExpression"], "postprocess": operator},
- {"name": "rollExpression", "symbols": ["multiplicativeExpression"], "postprocess": id},
- {"name": "multiplicativeExpression", "symbols": ["multiplicativeExpression", "_", (lexer.has("multiplicativeOperator") ? {type: "multiplicativeOperator"} : multiplicativeOperator), "_", "exponentExpression"], "postprocess": operator},
- {"name": "multiplicativeExpression", "symbols": ["exponentExpression"], "postprocess": id},
- {"name": "exponentExpression", "symbols": ["exponentExpression", "_", (lexer.has("exponentOperator") ? {type: "exponentOperator"} : exponentOperator), "_", "valueExpression"], "postprocess": operator},
- {"name": "exponentExpression", "symbols": ["valueExpression"], "postprocess": id},
+ {"name": "parenthesizedExpression", "symbols": [{"literal":"("}, "_", "expression", "_", {"literal":")"}], "postprocess": d => d[2]},
+ {"name": "parenthesizedExpression", "symbols": ["valueExpression"], "postprocess": id},
{"name": "valueExpression", "symbols": ["name"], "postprocess": id},
{"name": "valueExpression", "symbols": ["number"], "postprocess": id},
- {"name": "number", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => d[0].value},
- {"name": "name", "symbols": [(lexer.has("name") ? {type: "name"} : name)], "postprocess": d => d[0].value},
+ {"name": "valueExpression", "symbols": ["string"], "postprocess": id},
+ {"name": "number", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => new ConstantNode(d[0].value, 'number')},
+ {"name": "name", "symbols": [(lexer.has("name") ? {type: "name"} : name)], "postprocess": d => new SymbolNode(d[0].value)},
+ {"name": "string", "symbols": [(lexer.has("string") ? {type: "string"} : string)], "postprocess": d => new ConstantNode(d[0].value, 'string')},
{"name": "_", "symbols": []},
{"name": "_", "symbols": [(lexer.has("space") ? {type: "space"} : space)], "postprocess": nuller}
]
diff --git a/parser/grammar.ne b/parser/grammar.ne
index ae77435f..5b8e9459 100644
--- a/parser/grammar.ne
+++ b/parser/grammar.ne
@@ -3,6 +3,7 @@
const lexer = moo.compile({
number: /[0-9]+(?:\.[0-9]+)?/,
+ string: /'.*?'|".*?"/,
name: {match: /[a-zA-Z]+\w*?/, type: moo.keywords({
'keywords': ['if', 'else', 'd'],
})},
@@ -16,15 +17,41 @@
orOperator: ['|', '||'],
equalityOperator: ['=', '==', '===', '!=', '!=='],
relationalOperator: ['>', '<', '>=', '<='],
- brackets: {match: ['(', ')', '{', '}'], value: () => null},
+ brackets: ['(', ')', '{', '}'],
});
%}
@{% function nuller() { return null; } %}
@{%
- function operator([left, _1, op, _2, right]){
- return {type: 'operation', operator: op.value, left, right};
+ 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.value = value;
+ this.type = type;
+ }
}
%}
@@ -32,66 +59,73 @@
@lexer lexer
ifStatement ->
- "if" _ "(" _ callExpression _ ")" _ ifStatement _ "else" _ ifStatement {% d => ({condition: d[4], true: d[8], false: d[12]}) %}
-| callExpression {% id %}
-
-callExpression ->
- name _ arguments
- {%
- d => ({type: "call", function: d[0], arguments: d[2]})
- %}
+ "if" _ "(" _ expression _ ")" _ ifStatement _ "else" _ ifStatement {% d => ({condition: d[4], true: d[8], false: d[12]}) %}
| expression {% id %}
-arguments ->
- "(" _ (expression {% d => d[0] %}):? ( _ "," _ expression {% d => d[3] %} ):* _ ")"
- {%
- d => [d[2], ...d[3]]
- %}
-
-expression -> equalityExpression {% id %}
+expression ->
+ equalityExpression {% d => d[0] %}
equalityExpression ->
- equalityExpression _ %equalityOperator _ relationalExpression {%operator%}
+ equalityExpression _ %equalityOperator _ relationalExpression {% d => operator(d, 'equality') %}
| relationalExpression {% id %}
relationalExpression ->
- relationalExpression _ %relationalOperator _ additiveExpression {%operator%}
-| additiveExpression {% id %}
+ relationalExpression _ %relationalOperator _ orExpression {% d => operator(d, 'relation') %}
+| orExpression {% id %}
orExpression ->
- orExpression _ %orOperator _ andExpression {%operator%}
+ orExpression _ %orOperator _ andExpression {% d => operator(d, 'or') %}
| andExpression {% id %}
andExpression ->
- andExpression _ %andOperator _ equalityExpression {%operator%}
-| equalityExpression {% id %}
+ andExpression _ %andOperator _ additiveExpression {% d => operator(d, 'and') %}
+| additiveExpression {% id %}
additiveExpression ->
- additiveExpression _ %additiveOperator _ rollExpression {%operator%}
-| rollExpression {% id %}
-
-rollExpression ->
- rollExpression _ "d" _ multiplicativeExpression {% operator %}
+ additiveExpression _ %additiveOperator _ multiplicativeExpression {% d => operator(d, 'add') %}
| multiplicativeExpression {% id %}
multiplicativeExpression ->
- multiplicativeExpression _ %multiplicativeOperator _ exponentExpression {%operator%}
+ multiplicativeExpression _ %multiplicativeOperator _ rollExpression {% d => operator(d, 'multiply') %}
+| rollExpression {% id %}
+
+rollExpression ->
+ rollExpression _ "d" _ exponentExpression {% d => operator(d, 'roll') %}
| exponentExpression {% id %}
exponentExpression ->
- exponentExpression _ %exponentOperator _ valueExpression {%operator%}
+ 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 => d[0].value %}
+ %number {% d => new ConstantNode(d[0].value, 'number') %}
name ->
- %name {% d => d[0].value %}
+ %name {% d => new SymbolNode(d[0].value) %}
+
+string ->
+ %string {% d => new ConstantNode(d[0].value, 'string') %}
_ ->
null
diff --git a/parser/package.json b/parser/package.json
index 2dd74cc5..fc9d5f52 100644
--- a/parser/package.json
+++ b/parser/package.json
@@ -4,7 +4,8 @@
"scripts": {
"build": "nearleyc grammar.ne -o grammar.js",
"test": "nearley-test grammar.js",
- "unparse": "nearley-unparse grammar.js"
+ "unparse": "nearley-unparse grammar.js",
+ "railroad": "nearley-railroad grammar.ne -o grammar.html"
},
"author": "Stefan Zermatten",
"devDependencies": {