120 lines
2.8 KiB
JavaScript
120 lines
2.8 KiB
JavaScript
import Exception from "../exception";
|
|
import AST from "./ast";
|
|
|
|
function Visitor() {
|
|
this.parents = [];
|
|
}
|
|
|
|
Visitor.prototype = {
|
|
constructor: Visitor,
|
|
mutating: false,
|
|
|
|
// Visits a given value. If mutating, will replace the value if necessary.
|
|
acceptKey: function(node, name) {
|
|
var value = this.accept(node[name]);
|
|
if (this.mutating) {
|
|
// Hacky sanity check:
|
|
if (value && (!value.type || !AST[value.type])) {
|
|
throw new Exception('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
|
|
}
|
|
node[name] = value;
|
|
}
|
|
},
|
|
|
|
// Performs an accept operation with added sanity check to ensure
|
|
// required keys are not removed.
|
|
acceptRequired: function(node, name) {
|
|
this.acceptKey(node, name);
|
|
|
|
if (!node[name]) {
|
|
throw new Exception(node.type + ' requires ' + name);
|
|
}
|
|
},
|
|
|
|
// Traverses a given array. If mutating, empty respnses will be removed
|
|
// for child elements.
|
|
acceptArray: function(array) {
|
|
for (var i = 0, l = array.length; i < l; i++) {
|
|
this.acceptKey(array, i);
|
|
|
|
if (!array[i]) {
|
|
array.splice(i, 1);
|
|
i--;
|
|
l--;
|
|
}
|
|
}
|
|
},
|
|
|
|
accept: function(object) {
|
|
if (!object) {
|
|
return;
|
|
}
|
|
|
|
if (this.current) {
|
|
this.parents.unshift(this.current);
|
|
}
|
|
this.current = object;
|
|
|
|
var ret = this[object.type](object);
|
|
|
|
this.current = this.parents.shift();
|
|
|
|
if (!this.mutating || ret) {
|
|
return ret;
|
|
} else if (ret !== false) {
|
|
return object;
|
|
}
|
|
},
|
|
|
|
Program: function(program) {
|
|
this.acceptArray(program.body);
|
|
},
|
|
|
|
MustacheStatement: function(mustache) {
|
|
this.acceptRequired(mustache, 'path');
|
|
this.acceptArray(mustache.params);
|
|
this.acceptKey(mustache, 'hash');
|
|
},
|
|
|
|
BlockStatement: function(block) {
|
|
this.acceptRequired(block, 'path');
|
|
this.acceptArray(block.params);
|
|
this.acceptKey(block, 'hash');
|
|
|
|
this.acceptKey(block, 'program');
|
|
this.acceptKey(block, 'inverse');
|
|
},
|
|
|
|
PartialStatement: function(partial) {
|
|
this.acceptRequired(partial, 'name');
|
|
this.acceptArray(partial.params);
|
|
this.acceptKey(partial, 'hash');
|
|
},
|
|
|
|
ContentStatement: function(/* content */) {},
|
|
CommentStatement: function(/* comment */) {},
|
|
|
|
SubExpression: function(sexpr) {
|
|
this.acceptRequired(sexpr, 'path');
|
|
this.acceptArray(sexpr.params);
|
|
this.acceptKey(sexpr, 'hash');
|
|
},
|
|
|
|
PathExpression: function(/* path */) {},
|
|
|
|
StringLiteral: function(/* string */) {},
|
|
NumberLiteral: function(/* number */) {},
|
|
BooleanLiteral: function(/* bool */) {},
|
|
UndefinedLiteral: function(/* literal */) {},
|
|
NullLiteral: function(/* literal */) {},
|
|
|
|
Hash: function(hash) {
|
|
this.acceptArray(hash.pairs);
|
|
},
|
|
HashPair: function(pair) {
|
|
this.acceptRequired(pair, 'value');
|
|
}
|
|
};
|
|
|
|
export default Visitor;
|