Separated parser class nodes and began writing compile methods
This commit is contained in:
1
app/imports/parser/parseTree/CallNode.js
Normal file
1
app/imports/parser/parseTree/CallNode.js
Normal file
@@ -0,0 +1 @@
|
||||
//TODO
|
||||
21
app/imports/parser/parseTree/ConstantNode.js
Normal file
21
app/imports/parser/parseTree/ConstantNode.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class ConstantNode extends ParseNode {
|
||||
constructor({value, type, errors}){
|
||||
super();
|
||||
// string, number, boolean, numberArray, uncompiledNode
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
if (errors) this.errors = errors;
|
||||
}
|
||||
compile(){
|
||||
return this;
|
||||
}
|
||||
reduce(){
|
||||
if (this.type === 'numberArray'){
|
||||
return this.value.reduce((total, num) => total + num, 0);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
app/imports/parser/parseTree/IfNode.js
Normal file
40
app/imports/parser/parseTree/IfNode.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
|
||||
|
||||
export default class IfNode extends ParseNode {
|
||||
constructor({condition, consequent, alternative}){
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.consequent = consequent;
|
||||
this.alternative = alternative;
|
||||
}
|
||||
compile(){
|
||||
let condition = this.condition.compile();
|
||||
let consequent = this.consequent.compile();
|
||||
let alternative = this.alternative.compile();
|
||||
if (
|
||||
condition.type !== 'string' &&
|
||||
condition.type !== 'number' &&
|
||||
condition.type !== 'boolean'
|
||||
){
|
||||
// Handle unresolved condition
|
||||
return new ConstantNode({
|
||||
value: `if (${condition.value}) ${consequent.value} else ${alternative.value}`,
|
||||
type: 'uncompiledNode',
|
||||
errors: [
|
||||
...condition.errors,
|
||||
...consequent.errors,
|
||||
...alternative.errors,
|
||||
],
|
||||
});
|
||||
} else {
|
||||
// So long as the condition reolves, return the correct alternative,
|
||||
// even if it's unresolved
|
||||
if (condition.value){
|
||||
return consequent;
|
||||
} else {
|
||||
return alternative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
app/imports/parser/parseTree/OperatorNode.js
Normal file
11
app/imports/parser/parseTree/OperatorNode.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
|
||||
export default class OperatorNode extends ParseNode {
|
||||
constructor({left, right, operator, fn}) {
|
||||
super();
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.fn = fn;
|
||||
this.operator = operator;
|
||||
}
|
||||
}
|
||||
14
app/imports/parser/parseTree/ParseNode.js
Normal file
14
app/imports/parser/parseTree/ParseNode.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export default class ParseNode {
|
||||
// Compiling a node must return a ConstantNode
|
||||
compile(){
|
||||
throw new Meteor.Error('Compile not implemented on ' + this);
|
||||
}
|
||||
// Compile, but turn rolls into arrays
|
||||
roll(){
|
||||
return this.compile();
|
||||
}
|
||||
// Compile, turn rolls into arrays, and reduce those arrays into single values
|
||||
reduce(){
|
||||
return this.compileAndRoll()
|
||||
}
|
||||
}
|
||||
0
app/imports/parser/parseTree/RollNode.js
Normal file
0
app/imports/parser/parseTree/RollNode.js
Normal file
24
app/imports/parser/parseTree/SymbolNode.js
Normal file
24
app/imports/parser/parseTree/SymbolNode.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import ParseNode from '/imports/parser/parseTree/ParseNode.js';
|
||||
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
|
||||
|
||||
export default class SymbolNode extends ParseNode {
|
||||
constructor({name}){
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
compile(scope){
|
||||
let value = scope && scope[this.name];
|
||||
let type = typeof value;
|
||||
if (type === 'string' || type === 'number' || type === 'boolean'){
|
||||
return new ConstantNode({value, type});
|
||||
} else if (type === 'undefined'){
|
||||
return new ConstantNode({
|
||||
value: this.name,
|
||||
type: 'uncompiledNode',
|
||||
errors: [`${this.name} could not be resolved`]
|
||||
});
|
||||
} else {
|
||||
throw new Meteor.Error(`Unexpected case: ${this.name} resolved to ${value}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user