From ffa98d76fc1d9299db00516fe3a5b071184d171c Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 26 Mar 2019 16:32:24 +0200 Subject: [PATCH] Began writing a custom parser for calculations --- parser/.gitignore | 1 + parser/grammar.html | 0 parser/grammar.js | 80 ++++++++++++++++++++++++++++++++ parser/grammar.ne | 98 ++++++++++++++++++++++++++++++++++++++++ parser/package-lock.json | 75 ++++++++++++++++++++++++++++++ parser/package.json | 14 ++++++ 6 files changed, 268 insertions(+) create mode 100644 parser/.gitignore create mode 100644 parser/grammar.html create mode 100644 parser/grammar.js create mode 100644 parser/grammar.ne create mode 100644 parser/package-lock.json create mode 100644 parser/package.json diff --git a/parser/.gitignore b/parser/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/parser/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/parser/grammar.html b/parser/grammar.html new file mode 100644 index 00000000..e69de29b diff --git a/parser/grammar.js b/parser/grammar.js new file mode 100644 index 00000000..9b4fbca7 --- /dev/null +++ b/parser/grammar.js @@ -0,0 +1,80 @@ +// Generated automatically by nearley, version 2.16.0 +// http://github.com/Hardmath123/nearley +(function () { +function id(x) { return x[0]; } + + const moo = require("moo"); + + const lexer = moo.compile({ + number: /[0-9]+(?:\.[0-9]+)?/, + 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: ['|', '||'], + equalityOperator: ['=', '==', '===', '!=', '!=='], + relationalOperator: ['>', '<', '>=', '<='], + brackets: {match: ['(', ')', '{', '}'], value: () => null}, + }); + + function nuller() { return null; } + + function operator([left, _1, op, _2, right]){ + return {type: 'operation', operator: op.value, left, right}; + } +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": "callExpression", "symbols": ["name", "_", "arguments"], "postprocess": + d => ({type: "call", function: d[0], arguments: d[2]}) + }, + {"name": "callExpression", "symbols": ["expression"], "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;}}, + {"name": "arguments$ebnf$2", "symbols": []}, + {"name": "arguments$ebnf$2$subexpression$1", "symbols": ["_", {"literal":","}, "_", "expression"], "postprocess": d => d[3]}, + {"name": "arguments$ebnf$2", "symbols": ["arguments$ebnf$2", "arguments$ebnf$2$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"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": "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": "_", "symbols": []}, + {"name": "_", "symbols": [(lexer.has("space") ? {type: "space"} : space)], "postprocess": nuller} +] + , ParserStart: "ifStatement" +} +if (typeof module !== 'undefined'&& typeof module.exports !== 'undefined') { + module.exports = grammar; +} else { + window.grammar = grammar; +} +})(); diff --git a/parser/grammar.ne b/parser/grammar.ne new file mode 100644 index 00000000..ae77435f --- /dev/null +++ b/parser/grammar.ne @@ -0,0 +1,98 @@ +@{% + const moo = require("moo"); + + const lexer = moo.compile({ + number: /[0-9]+(?:\.[0-9]+)?/, + 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: ['|', '||'], + equalityOperator: ['=', '==', '===', '!=', '!=='], + relationalOperator: ['>', '<', '>=', '<='], + brackets: {match: ['(', ')', '{', '}'], value: () => null}, + }); +%} + +@{% function nuller() { return null; } %} + +@{% + function operator([left, _1, op, _2, right]){ + return {type: 'operation', operator: op.value, left, right}; + } +%} + +# Use the Moo lexer +@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]}) + %} +| expression {% id %} + +arguments -> + "(" _ (expression {% d => d[0] %}):? ( _ "," _ expression {% d => d[3] %} ):* _ ")" + {% + d => [d[2], ...d[3]] + %} + +expression -> equalityExpression {% id %} + +equalityExpression -> + equalityExpression _ %equalityOperator _ relationalExpression {%operator%} +| relationalExpression {% id %} + +relationalExpression -> + relationalExpression _ %relationalOperator _ additiveExpression {%operator%} +| additiveExpression {% id %} + +orExpression -> + orExpression _ %orOperator _ andExpression {%operator%} +| andExpression {% id %} + +andExpression -> + andExpression _ %andOperator _ equalityExpression {%operator%} +| equalityExpression {% id %} + +additiveExpression -> + additiveExpression _ %additiveOperator _ rollExpression {%operator%} +| rollExpression {% id %} + +rollExpression -> + rollExpression _ "d" _ multiplicativeExpression {% operator %} +| multiplicativeExpression {% id %} + +multiplicativeExpression -> + multiplicativeExpression _ %multiplicativeOperator _ exponentExpression {%operator%} +| exponentExpression {% id %} + +exponentExpression -> + exponentExpression _ %exponentOperator _ valueExpression {%operator%} +| valueExpression {% id %} + +valueExpression -> + name {% id %} +| number {% id %} + +# A number or a function of a number +number -> + %number {% d => d[0].value %} + +name -> + %name {% d => d[0].value %} + +_ -> + null +| %space {% nuller %} diff --git a/parser/package-lock.json b/parser/package-lock.json new file mode 100644 index 00000000..b48618db --- /dev/null +++ b/parser/package-lock.json @@ -0,0 +1,75 @@ +{ + "name": "dicecloud-parser", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", + "dev": true + }, + "moo": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.0.tgz", + "integrity": "sha512-AMv6iqhTEd5vT/cQlH6cammKS5ekyHhyqTRKi5zKMWl1RTyFnQ3ohPSBNSm8ySe2wlxSKwDonr9D5ZT44mdO3g==", + "dev": true + }, + "nearley": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", + "dev": true, + "requires": { + "commander": "2.19.0", + "moo": "0.4.3", + "railroad-diagrams": "1.0.0", + "randexp": "0.4.6", + "semver": "5.6.0" + }, + "dependencies": { + "moo": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", + "dev": true + } + } + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", + "dev": true + }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "requires": { + "discontinuous-range": "1.0.0", + "ret": "0.1.15" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + } + } +} diff --git a/parser/package.json b/parser/package.json new file mode 100644 index 00000000..2dd74cc5 --- /dev/null +++ b/parser/package.json @@ -0,0 +1,14 @@ +{ + "name": "dicecloud-parser", + "version": "0.1.0", + "scripts": { + "build": "nearleyc grammar.ne -o grammar.js", + "test": "nearley-test grammar.js", + "unparse": "nearley-unparse grammar.js" + }, + "author": "Stefan Zermatten", + "devDependencies": { + "moo": "^0.5.0", + "nearley": "^2.16.0" + } +}