Lots of work on the parser including testing interface
This commit is contained in:
@@ -2,11 +2,16 @@
|
||||
// http://github.com/Hardmath123/nearley
|
||||
function id(x) { return x[0]; }
|
||||
|
||||
import ArrayNode from '/imports/parser/parseTree/ArrayNode.js';
|
||||
import CallNode from '/imports/parser/parseTree/CallNode.js';
|
||||
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
|
||||
import IfNode from '/imports/parser/parseTree/IfNode.js';
|
||||
import IfNode from '/imports/parser/parseTree/IfNode.js';
|
||||
import IndexNode from '/imports/parser/parseTree/IndexNode.js';
|
||||
import OperatorNode from '/imports/parser/parseTree/OperatorNode.js';
|
||||
import SymbolNode from '/imports/parser/parseTree/SymbolNode.js';
|
||||
import ParenthesisNode from '/imports/parser/parseTree/ParenthesisNode.js';
|
||||
import RollNode from '/imports/parser/parseTree/RollNode.js';
|
||||
import SymbolNode from '/imports/parser/parseTree/SymbolNode.js';
|
||||
|
||||
import moo from 'moo';
|
||||
|
||||
const lexer = moo.compile({
|
||||
@@ -25,7 +30,8 @@ function id(x) { return x[0]; }
|
||||
match: /\s+/,
|
||||
lineBreaks: true,
|
||||
},
|
||||
separators: [',', '.'],
|
||||
separator: [',', ';'],
|
||||
period: ['.'],
|
||||
multiplicativeOperator: ['*', '/'],
|
||||
exponentOperator: ['^'],
|
||||
additiveOperator: ['+', '-'],
|
||||
@@ -35,7 +41,7 @@ function id(x) { return x[0]; }
|
||||
stringDelimiters: ['\"', '\''],
|
||||
equalityOperator: ['=', '==', '===', '!=', '!=='],
|
||||
relationalOperator: ['>', '<', '>=', '<='],
|
||||
brackets: ['(', ')', '{', '}'],
|
||||
brackets: ['(', ')', '{', '}', '[', ']'],
|
||||
});
|
||||
|
||||
function nuller() { return null; }
|
||||
@@ -49,11 +55,11 @@ function id(x) { return x[0]; }
|
||||
}
|
||||
let Lexer = lexer;
|
||||
let ParserRules = [
|
||||
{"name": "ifStatement", "symbols": [{"literal":"if"}, "_", {"literal":"("}, "_", "expression", "_", {"literal":")"}, "_", "ifStatement", "_", {"literal":"else"}, "_", "ifStatement"], "postprocess":
|
||||
{"name": "expression", "symbols": ["ifStatement"], "postprocess": d => d[0]},
|
||||
{"name": "ifStatement", "symbols": ["_", "expression", "_", {"literal":"?"}, "_", "expression", "_", {"literal":":"}, "_", "expression"], "postprocess":
|
||||
d => new IfNode({condition: d[4], consequent: d[8], alternative: d[12]})
|
||||
},
|
||||
{"name": "ifStatement", "symbols": ["expression"], "postprocess": id},
|
||||
{"name": "expression", "symbols": ["equalityExpression"], "postprocess": d => d[0]},
|
||||
{"name": "ifStatement", "symbols": ["equalityExpression"], "postprocess": id},
|
||||
{"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')},
|
||||
@@ -66,33 +72,47 @@ let ParserRules = [
|
||||
{"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": "rollExpression", "symbols": ["rollExpression", "_", {"literal":"d"}, "_", "exponentExpression"], "postprocess": d => new RollNode({left: d[0], right: d[4]})},
|
||||
{"name": "rollExpression", "symbols": ["singleRollExpression"], "postprocess": id},
|
||||
{"name": "singleRollExpression", "symbols": [{"literal":"d"}, "_", "exponentExpression"], "postprocess": d => new RollNode({left: new ConstantNode({value: 1, type: 'number'}), right: d[2]})},
|
||||
{"name": "singleRollExpression", "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 => new CallNode ({type: "call", fn: d[0], arguments: d[2]})
|
||||
},
|
||||
{"name": "callExpression", "symbols": ["parenthesizedExpression"], "postprocess": id},
|
||||
{"name": "callExpression", "symbols": ["indexExpression"], "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$subexpression$1", "symbols": ["_", (lexer.has("separator") ? {type: "separator"} : separator), "_", "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": "indexExpression", "symbols": ["arrayExpression", {"literal":"["}, "_", "expression", "_", {"literal":"]"}], "postprocess": d => new IndexNode ({array: d[0], index: d[3]})},
|
||||
{"name": "indexExpression", "symbols": ["arrayExpression"], "postprocess": id},
|
||||
{"name": "arrayExpression$ebnf$1$subexpression$1", "symbols": ["expression"], "postprocess": d => d[0]},
|
||||
{"name": "arrayExpression$ebnf$1", "symbols": ["arrayExpression$ebnf$1$subexpression$1"], "postprocess": id},
|
||||
{"name": "arrayExpression$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}},
|
||||
{"name": "arrayExpression$ebnf$2", "symbols": []},
|
||||
{"name": "arrayExpression$ebnf$2$subexpression$1", "symbols": ["_", (lexer.has("separator") ? {type: "separator"} : separator), "_", "expression"], "postprocess": d => d[3]},
|
||||
{"name": "arrayExpression$ebnf$2", "symbols": ["arrayExpression$ebnf$2", "arrayExpression$ebnf$2$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
|
||||
{"name": "arrayExpression", "symbols": [{"literal":"["}, "_", "arrayExpression$ebnf$1", "arrayExpression$ebnf$2", "_", {"literal":"]"}], "postprocess":
|
||||
d => new ArrayNode({values: [d[2], ...d[3]]})
|
||||
},
|
||||
{"name": "parenthesizedExpression", "symbols": [{"literal":"("}, "_", "expression", "_", {"literal":")"}], "postprocess": d => d[2]},
|
||||
{"name": "arrayExpression", "symbols": ["parenthesizedExpression"], "postprocess": id},
|
||||
{"name": "parenthesizedExpression", "symbols": [{"literal":"("}, "_", "expression", "_", {"literal":")"}], "postprocess": d => new ParenthesisNode({content: d[2]})},
|
||||
{"name": "parenthesizedExpression", "symbols": ["valueExpression"], "postprocess": id},
|
||||
{"name": "valueExpression", "symbols": ["name"], "postprocess": id},
|
||||
{"name": "valueExpression", "symbols": ["number"], "postprocess": id},
|
||||
{"name": "valueExpression", "symbols": ["string"], "postprocess": id},
|
||||
{"name": "number", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => new ConstantNode({value: d[0].value, type: 'number'})},
|
||||
{"name": "number", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => new ConstantNode({value: +d[0].value, type: 'number'})},
|
||||
{"name": "name", "symbols": [(lexer.has("name") ? {type: "name"} : name)], "postprocess": d => new SymbolNode({name: d[0].value})},
|
||||
{"name": "string", "symbols": [(lexer.has("string") ? {type: "string"} : string)], "postprocess": d => new ConstantNode({value: d[0].value, type: 'string'})},
|
||||
{"name": "_", "symbols": []},
|
||||
{"name": "_", "symbols": [(lexer.has("space") ? {type: "space"} : space)], "postprocess": nuller}
|
||||
];
|
||||
let ParserStart = "ifStatement";
|
||||
let ParserStart = "expression";
|
||||
export default { Lexer, ParserRules, ParserStart };
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
@preprocessor esmodule
|
||||
@{%
|
||||
import ArrayNode from '/imports/parser/parseTree/ArrayNode.js';
|
||||
import CallNode from '/imports/parser/parseTree/CallNode.js';
|
||||
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
|
||||
import IfNode from '/imports/parser/parseTree/IfNode.js';
|
||||
import IfNode from '/imports/parser/parseTree/IfNode.js';
|
||||
import IndexNode from '/imports/parser/parseTree/IndexNode.js';
|
||||
import OperatorNode from '/imports/parser/parseTree/OperatorNode.js';
|
||||
import SymbolNode from '/imports/parser/parseTree/SymbolNode.js';
|
||||
import ParenthesisNode from '/imports/parser/parseTree/ParenthesisNode.js';
|
||||
import RollNode from '/imports/parser/parseTree/RollNode.js';
|
||||
import SymbolNode from '/imports/parser/parseTree/SymbolNode.js';
|
||||
|
||||
import moo from 'moo';
|
||||
|
||||
const lexer = moo.compile({
|
||||
@@ -23,7 +28,8 @@
|
||||
match: /\s+/,
|
||||
lineBreaks: true,
|
||||
},
|
||||
separators: [',', '.'],
|
||||
separator: [',', ';'],
|
||||
period: ['.'],
|
||||
multiplicativeOperator: ['*', '/'],
|
||||
exponentOperator: ['^'],
|
||||
additiveOperator: ['+', '-'],
|
||||
@@ -33,7 +39,7 @@
|
||||
stringDelimiters: ['\"', '\''],
|
||||
equalityOperator: ['=', '==', '===', '!=', '!=='],
|
||||
relationalOperator: ['>', '<', '>=', '<='],
|
||||
brackets: ['(', ')', '{', '}'],
|
||||
brackets: ['(', ')', '{', '}', '[', ']'],
|
||||
});
|
||||
|
||||
function nuller() { return null; }
|
||||
@@ -50,14 +56,14 @@
|
||||
# Use the Moo lexer
|
||||
@lexer lexer
|
||||
|
||||
expression ->
|
||||
ifStatement {% d => d[0] %}
|
||||
|
||||
ifStatement ->
|
||||
"if" _ "(" _ expression _ ")" _ ifStatement _ "else" _ ifStatement {%
|
||||
_ expression _ "?" _ expression _ ":" _ expression {%
|
||||
d => new IfNode({condition: d[4], consequent: d[8], alternative: d[12]})
|
||||
%}
|
||||
| expression {% id %}
|
||||
|
||||
expression ->
|
||||
equalityExpression {% d => d[0] %}
|
||||
| equalityExpression {% id %}
|
||||
|
||||
equalityExpression ->
|
||||
equalityExpression _ %equalityOperator _ relationalExpression {% d => operator(d, 'equality') %}
|
||||
@@ -84,7 +90,11 @@ multiplicativeExpression ->
|
||||
| rollExpression {% id %}
|
||||
|
||||
rollExpression ->
|
||||
rollExpression _ "d" _ exponentExpression {% d => operator(d, 'roll') %}
|
||||
rollExpression _ "d" _ exponentExpression {% d => new RollNode({left: d[0], right: d[4]}) %}
|
||||
| singleRollExpression {% id %}
|
||||
|
||||
singleRollExpression ->
|
||||
"d" _ exponentExpression {% d => new RollNode({left: new ConstantNode({value: 1, type: 'number'}), right: d[2]}) %}
|
||||
| exponentExpression {% id %}
|
||||
|
||||
exponentExpression ->
|
||||
@@ -95,15 +105,25 @@ callExpression ->
|
||||
name _ arguments {%
|
||||
d => new CallNode ({type: "call", fn: d[0], arguments: d[2]})
|
||||
%}
|
||||
| parenthesizedExpression {% id %}
|
||||
| indexExpression {% id %}
|
||||
|
||||
arguments ->
|
||||
"(" _ (expression {% d => d[0] %}):? ( _ "," _ expression {% d => d[3] %} ):* _ ")" {%
|
||||
d => [d[2], ...d[3]]
|
||||
"(" _ (expression {% d => d[0] %}):? ( _ %separator _ expression {% d => d[3] %} ):* _ ")" {%
|
||||
d => [d[2], ...d[3]]
|
||||
%}
|
||||
|
||||
indexExpression ->
|
||||
arrayExpression "[" _ expression _ "]" {% d => new IndexNode ({array: d[0], index: d[3]}) %}
|
||||
| arrayExpression {% id %}
|
||||
|
||||
arrayExpression ->
|
||||
"[" _ (expression {% d => d[0] %}):? ( _ %separator _ expression {% d => d[3] %} ):* _ "]" {%
|
||||
d => new ArrayNode({values: [d[2], ...d[3]]})
|
||||
%}
|
||||
| parenthesizedExpression {% id %}
|
||||
|
||||
parenthesizedExpression ->
|
||||
"(" _ expression _ ")" {% d => d[2] %}
|
||||
"(" _ expression _ ")" {% d => new ParenthesisNode({content: d[2]}) %}
|
||||
| valueExpression {% id %}
|
||||
|
||||
valueExpression ->
|
||||
@@ -113,7 +133,7 @@ valueExpression ->
|
||||
|
||||
# A number or a function of a number
|
||||
number ->
|
||||
%number {% d => new ConstantNode({value: d[0].value, type: 'number'}) %}
|
||||
%number {% d => new ConstantNode({value: +d[0].value, type: 'number'}) %}
|
||||
|
||||
name ->
|
||||
%name {% d => new SymbolNode({name: d[0].value}) %}
|
||||
|
||||
15
app/imports/parser/parseTree/ArrayNode.js
Normal file
15
app/imports/parser/parseTree/ArrayNode.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class ArrayNode extends ParseNode {
|
||||
constructor({values}) {
|
||||
super();
|
||||
this.values = values;
|
||||
}
|
||||
compile(){
|
||||
let values = this.values.map(node => node.compile());
|
||||
return new ArrayNode({values});
|
||||
}
|
||||
toString(){
|
||||
return `[${this.values.map(node => node.toString()).join(', ')}]`;
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,13 @@ export default class ConstantNode extends ParseNode {
|
||||
compile(){
|
||||
return this;
|
||||
}
|
||||
reduce(){
|
||||
if (this.type === 'numberArray'){
|
||||
return this.value.reduce((total, num) => total + num, 0);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
toString(){
|
||||
return `${this.value}`;
|
||||
}
|
||||
get isNumber(){
|
||||
return this.type === 'number';
|
||||
}
|
||||
get isInteger(){
|
||||
return this.isNumberNode && Number.isInteger(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
15
app/imports/parser/parseTree/ErrorNode.js
Normal file
15
app/imports/parser/parseTree/ErrorNode.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class ErrorNode extends ParseNode {
|
||||
constructor({node, error}) {
|
||||
super();
|
||||
this.node = node;
|
||||
this.error = error;
|
||||
}
|
||||
compile(){
|
||||
return this;
|
||||
}
|
||||
toString(){
|
||||
return '###';
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ export default class IfNode extends ParseNode {
|
||||
this.consequent = consequent;
|
||||
this.alternative = alternative;
|
||||
}
|
||||
toString(){
|
||||
let {condition, consequent, alternative} = this;
|
||||
return `${condition.toString()} ? ${consequent.toString()} : ${alternative.toString()}`
|
||||
}
|
||||
compile(){
|
||||
let condition = this.condition.compile();
|
||||
let consequent = this.consequent.compile();
|
||||
@@ -19,7 +23,7 @@ export default class IfNode extends ParseNode {
|
||||
){
|
||||
// Handle unresolved condition
|
||||
return new ConstantNode({
|
||||
value: `if (${condition.value}) ${consequent.value} else ${alternative.value}`,
|
||||
value: `${condition.value}) ${consequent.value} else ${alternative.value}`,
|
||||
type: 'uncompiledNode',
|
||||
errors: [
|
||||
...condition.errors,
|
||||
|
||||
25
app/imports/parser/parseTree/IndexNode.js
Normal file
25
app/imports/parser/parseTree/IndexNode.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class IndexNode extends ParseNode {
|
||||
constructor({array, index}) {
|
||||
super();
|
||||
this.array = array;
|
||||
this.index = index;
|
||||
}
|
||||
compile(){
|
||||
let index = this.index.compile();
|
||||
if (index.constructor.name === 'ConstantNode' && index.type === 'number'){
|
||||
let selection = this.array.values[index.value];
|
||||
if (selection){
|
||||
return selection.compile();
|
||||
}
|
||||
}
|
||||
return new IndexNode({
|
||||
array: this.array.compile(),
|
||||
index: this.index.compile(),
|
||||
});
|
||||
}
|
||||
toString(){
|
||||
return `${this.array.toString()}[${this.index.toString()}]`;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
|
||||
|
||||
export default class OperatorNode extends ParseNode {
|
||||
constructor({left, right, operator, fn}) {
|
||||
@@ -8,4 +9,45 @@ export default class OperatorNode extends ParseNode {
|
||||
this.fn = fn;
|
||||
this.operator = operator;
|
||||
}
|
||||
compile(){
|
||||
let leftNode = this.left.compile();
|
||||
let rightNode = this.right.compile();
|
||||
let left, right;
|
||||
if (leftNode.type !== 'number' || rightNode.type !== 'number'){
|
||||
return new OperatorNode({
|
||||
left: leftNode,
|
||||
right: rightNode,
|
||||
operator: this.operator,
|
||||
fn: this.fn
|
||||
});
|
||||
} else {
|
||||
left = leftNode.value;
|
||||
right = rightNode.value;
|
||||
}
|
||||
let result;
|
||||
switch(this.operator){
|
||||
case '+': result = left + right; break;
|
||||
case '-': result = left - right; break;
|
||||
case '*': result = left * right; break;
|
||||
case '/': result = left / right; break;
|
||||
case '^': result = Math.pow(left, right); break;
|
||||
case '&':
|
||||
case '&&': result = left && right; break;
|
||||
case '|':
|
||||
case '||': result = left || right; break;
|
||||
case '=':
|
||||
case '==':
|
||||
case '===': result = left == right; break;
|
||||
case '!=':
|
||||
case '>': result = left > right; break;
|
||||
case '<': result = left < right; break;
|
||||
case '>=': result = left >= right; break;
|
||||
case '<=': result = left <= right; break;
|
||||
}
|
||||
return new ConstantNode({value: result, type: typeof result});
|
||||
}
|
||||
toString(){
|
||||
let {left, right, operator} = this;
|
||||
return `${left.toString()} ${operator} ${right.toString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
19
app/imports/parser/parseTree/ParenthesisNode.js
Normal file
19
app/imports/parser/parseTree/ParenthesisNode.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class ParenthesisNode extends ParseNode {
|
||||
constructor({content}) {
|
||||
super();
|
||||
this.content = content;
|
||||
}
|
||||
compile(){
|
||||
let content = this.content.compile();
|
||||
if (content.constructor.name === 'ConstantNode'){
|
||||
return content;
|
||||
} else {
|
||||
return new ParenthesisNode({content});
|
||||
}
|
||||
}
|
||||
toString(){
|
||||
return `(${this.content.toString()})`;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
export default class ParseNode {
|
||||
// Compiling a node must return a ConstantNode
|
||||
compile(){
|
||||
throw new Meteor.Error('Compile not implemented on ' + this);
|
||||
// Returns a ParseNode, a ConstantNode if possible
|
||||
throw new Meteor.Error('Compile not implemented on ' + this.constructor.name);
|
||||
}
|
||||
toString(){
|
||||
throw new Meteor.Error('toString not implemented on ' + this.constructor.name);
|
||||
}
|
||||
// Compile, but turn rolls into arrays
|
||||
roll(){
|
||||
@@ -9,6 +12,6 @@ export default class ParseNode {
|
||||
}
|
||||
// Compile, turn rolls into arrays, and reduce those arrays into single values
|
||||
reduce(){
|
||||
return this.compileAndRoll()
|
||||
return this.roll();
|
||||
}
|
||||
}
|
||||
|
||||
17
app/imports/parser/parseTree/RollArrayNode.js
Normal file
17
app/imports/parser/parseTree/RollArrayNode.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class RollArrayNode extends ParseNode {
|
||||
constructor({values}) {
|
||||
super();
|
||||
this.values = values;
|
||||
}
|
||||
compile(){
|
||||
return this;
|
||||
}
|
||||
toString(){
|
||||
return `[${this.values.join(', ')}]`;
|
||||
}
|
||||
reduce(){
|
||||
//TODO sum and return values
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
import ArrayNode from '/imports/parser/parseTree/ArrayNode.js';
|
||||
import ErrorNode from '/imports/parser/parseTree/ErrorNode.js';
|
||||
|
||||
export default class RollNode extends ParseNode {
|
||||
constructor({left, right}) {
|
||||
super();
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
compile(){
|
||||
let left = this.left.compile();
|
||||
let right = this.right.compile();
|
||||
return new RollNode({left, right});
|
||||
}
|
||||
toString(){
|
||||
if (
|
||||
this.left.isNumberNode && this.left.value === 1
|
||||
){
|
||||
return `d${this.right.toString()}`;
|
||||
} else {
|
||||
return `${this.left.toString()}d${this.right.toString()}`;
|
||||
}
|
||||
}
|
||||
roll(){
|
||||
let left = this.left.reduce();
|
||||
let right = this.right.reduce();
|
||||
if (!left.isInteger){
|
||||
return new ErrorNode({
|
||||
node: this,
|
||||
error: 'Number of dice is not an integer'
|
||||
});
|
||||
}
|
||||
if (!right.isInteger){
|
||||
return new ErrorNode({
|
||||
node: this,
|
||||
error: 'Dice size is not an integer'
|
||||
});
|
||||
}
|
||||
let number = left.value;
|
||||
if (number > 100) return new ErrorNode({
|
||||
node: this,
|
||||
error: 'Can\'t roll more than 100 dice at once'
|
||||
});
|
||||
let diceSize = right.value;
|
||||
let randomSrc = DDP.randomStream('diceRoller');
|
||||
let rolls = [];
|
||||
for (let i = 0; i < number; i++){
|
||||
let roll = ~~(randomSrc.fraction() * diceSize) + 1
|
||||
rolls.push(roll);
|
||||
}
|
||||
return new ArrayNode({values: rolls});
|
||||
}
|
||||
reduce(){
|
||||
this.roll().reduce();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ export default class SymbolNode extends ParseNode {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
toString(){
|
||||
return `${this.name}`
|
||||
}
|
||||
compile(scope){
|
||||
let value = scope && scope[this.name];
|
||||
let type = typeof value;
|
||||
|
||||
51
app/imports/ui/pages/Parser.vue
Normal file
51
app/imports/ui/pages/Parser.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template lang="html">
|
||||
<div class="layout column align-center justify-center pa-4">
|
||||
<v-card style="width: 100%; max-width: 400px;">
|
||||
<v-card-text>
|
||||
<v-text-field v-model="input" />
|
||||
<v-textarea
|
||||
v-model="output"
|
||||
readonly
|
||||
label="output"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="string"
|
||||
readonly
|
||||
label="string"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="compiled"
|
||||
readonly
|
||||
label="compiled"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Parser from '/imports/parser/parser.js';
|
||||
console.log(Parser);
|
||||
export default {
|
||||
data(){return {
|
||||
input: null,
|
||||
output: null,
|
||||
compiled: null,
|
||||
string: null,
|
||||
}},
|
||||
watch: {
|
||||
input(val){
|
||||
this.output = this.compiled = this.string = '';
|
||||
let output = new Parser().feed(val).finish()[0];
|
||||
console.log(output);
|
||||
this.output = JSON.stringify(output, null, 2);
|
||||
if (!output) return;
|
||||
this.string = output;
|
||||
this.compiled = output.compile();
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -23,6 +23,7 @@ import PatreonLevelTooLow from '/imports/ui/pages/PatreonLevelTooLow.vue';
|
||||
import Tabletops from '/imports/ui/pages/Tabletops.vue';
|
||||
import Tabletop from '/imports/ui/pages/Tabletop.vue';
|
||||
import TabletopToolbar from '/imports/ui/tabletop/TabletopToolbar.vue';
|
||||
import Parser from '/imports/ui/pages/Parser.vue';
|
||||
|
||||
let userSubscription = Meteor.subscribe('user');
|
||||
|
||||
@@ -109,6 +110,14 @@ RouterFactory.configure(factory => {
|
||||
title: 'Character List',
|
||||
},
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
path: '/parser',
|
||||
components: {
|
||||
default: Parser,
|
||||
},
|
||||
meta: {
|
||||
title: 'Parser',
|
||||
},
|
||||
},{
|
||||
path: '/library',
|
||||
components: {
|
||||
|
||||
Reference in New Issue
Block a user