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

+
+ + + + + + + + + + + + + + + +"if" + + + + + + + +_ + + + + + + + +"(" + + + + + + + +_ + + + + + + + +callExpression + + + + + + + +_ + + + + + + + +")" + + + + + + + +_ + + + + + + + +ifStatement + + + + + + + +_ + + + + + + + +"else" + + + + + + + +_ + + + + + + + +ifStatement + + + + + + + + + + + + + +callExpression + + + + + + + + + +
+

callExpression

+
+ + + + + + + + + + + + + + + +name + + + + + + + +_ + + + + + + + +arguments + + + + + + + + + + + + + +expression + + + + + + + + + +
+

arguments

+
+ + + + + + + + + + + + + + + +"(" + + + + + + + +_ + + + + + + + + + + + + + + + + + + + + + + + +expression + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +_ + + + + + + + +"," + + + + + + + +_ + + + + + + + +expression + + + + + + + + + + + + + + + + + + + +_ + + + + + + + +")" + + + + + + + + + +
+

expression

+
+ + + + + + + + + + + + + + + +equalityExpression + + + + + + + + + +
+

equalityExpression

+
+ + + + + + + + + + + + + + + +equalityExpression + + + + + + + +_ + + + + + + + +equalityOperator + + + + + + + +_ + + + + + + + +relationalExpression + + + + + + + + + + + + + +relationalExpression + + + + + + + + + +
+

relationalExpression

+
+ + + + + + + + + + + + + + + +relationalExpression + + + + + + + +_ + + + + + + + +relationalOperator + + + + + + + +_ + + + + + + + +orExpression + + + + + + + + + + + + + +orExpression + + + + + + + + + +
+

orExpression

+
+ + + + + + + + + + + + + + + +orExpression + + + + + + + +_ + + + + + + + +orOperator + + + + + + + +_ + + + + + + + +andExpression + + + + + + + + + + + + + +andExpression + + + + + + + + + +
+

andExpression

+
+ + + + + + + + + + + + + + + +andExpression + + + + + + + +_ + + + + + + + +andOperator + + + + + + + +_ + + + + + + + +additiveExpression + + + + + + + + + + + + + +additiveExpression + + + + + + + + + +
+

additiveExpression

+
+ + + + + + + + + + + + + + + +additiveExpression + + + + + + + +_ + + + + + + + +additiveOperator + + + + + + + +_ + + + + + + + +multiplicativeExpression + + + + + + + + + + + + + +multiplicativeExpression + + + + + + + + + +
+

multiplicativeExpression

+
+ + + + + + + + + + + + + + + +multiplicativeExpression + + + + + + + +_ + + + + + + + +multiplicativeOperator + + + + + + + +_ + + + + + + + +rollExpression + + + + + + + + + + + + + +rollExpression + + + + + + + + + +
+

rollExpression

+
+ + + + + + + + + + + + + + + +rollExpression + + + + + + + +_ + + + + + + + +"d" + + + + + + + +_ + + + + + + + +exponentExpression + + + + + + + + + + + + + +exponentExpression + + + + + + + + + +
+

exponentExpression

+
+ + + + + + + + + + + + + + + +parenthesizedExpression + + + + + + + +_ + + + + + + + +exponentOperator + + + + + + + +_ + + + + + + + +exponentExpression + + + + + + + + + + + + + +parenthesizedExpression + + + + + + + + + +
+

parenthesizedExpression

+
+ + + + + + + + + + + + + + + +"(" + + + + + + + +_ + + + + + + + +expression + + + + + + + +_ + + + + + + + +")" + + + + + + + + + + + + + +valueExpression + + + + + + + + + +
+

valueExpression

+
+ + + + + + + + + + + + + + + +name + + + + + + + + + + + + + +number + + + + + + + + + + + + + +string + + + + + + + + + +
+

number

+
+ + + + + + + + + + + + + + + +number + + + + + + + + + +
+

name

+
+ + + + + + + + + + + + + + + +name + + + + + + + + + +
+

string

+
+ + + + + + + + + + + + + + + +string + + + + + + + + + +
+

_

+
+ + + + + + + + + + + + + + + +null + + + + + + + + + + + + + +space + + + + + + + + + +
+ + \ 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": {