|
@@ -3,9 +3,11 @@ define([
|
|
|
], function (Lexer) {
|
|
], function (Lexer) {
|
|
|
|
|
|
|
|
var NodeTypes = {
|
|
var NodeTypes = {
|
|
|
- MetricExpression = 1,
|
|
|
|
|
|
|
+ MetricExpression: 1,
|
|
|
MetricNode: 2,
|
|
MetricNode: 2,
|
|
|
- FunctionCall: 4
|
|
|
|
|
|
|
+ FunctionCall: 4,
|
|
|
|
|
+ NumericLiteral: 5,
|
|
|
|
|
+ StringLiteral: 6
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
function Node(type, value) {
|
|
function Node(type, value) {
|
|
@@ -20,147 +22,184 @@ define([
|
|
|
this.error = null;
|
|
this.error = null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ Parser.Nodes = NodeTypes;
|
|
|
|
|
+
|
|
|
Parser.prototype = {
|
|
Parser.prototype = {
|
|
|
getAst: function () {
|
|
getAst: function () {
|
|
|
- return parse('start');
|
|
|
|
|
|
|
+ return this.parse('start');
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- checkToken: function (token, expected) {
|
|
|
|
|
- if (token === null) {
|
|
|
|
|
|
|
+ isUnexpectedToken: function (expected, value) {
|
|
|
|
|
+ if (this.token === null) {
|
|
|
this.error = "Expected token: " + expected + " instead found end of string";
|
|
this.error = "Expected token: " + expected + " instead found end of string";
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (token.type === expected) {
|
|
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- this.error = "Expected token "
|
|
|
|
|
- + expected + " instead found + "
|
|
|
|
|
- found + " at position: " + lexer.char;
|
|
|
|
|
-
|
|
|
|
|
- return false;
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- parse: function (state) {
|
|
|
|
|
- var node = { children: [] };
|
|
|
|
|
-
|
|
|
|
|
- var token = lexer.next();
|
|
|
|
|
- var nextToken = lexer.next();
|
|
|
|
|
-
|
|
|
|
|
- if (checkToken(token, Lexer.Token.Identifier) {
|
|
|
|
|
- return null;
|
|
|
|
|
|
|
+ if (this.token.type === expected) {
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (nextToken == null) {
|
|
|
|
|
- return {
|
|
|
|
|
- type: NodeTypes.MetricExpression,
|
|
|
|
|
- nodes: [
|
|
|
|
|
- {
|
|
|
|
|
- type: NodeTypes.MetricNode,
|
|
|
|
|
- value: token.value
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (value && this.token.value === value) {
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (checkToken(nextToken, Lexer.Token.Punctuator)) {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ this.error = "Expected token " + expected +
|
|
|
|
|
+ ' instead found token ' + this.token.type +
|
|
|
|
|
+ ' ("' + this.token.value + '")' +
|
|
|
|
|
+ " at position: " + this.lexer.char;
|
|
|
|
|
|
|
|
- if (nextToken.value === '.') {
|
|
|
|
|
- return parseMetricExpression(token);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return true;
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- parseMetricExpression: function(firstToken) {
|
|
|
|
|
- var node = {
|
|
|
|
|
- type: NodeTypes.MetricExpression,
|
|
|
|
|
- nodes: [
|
|
|
|
|
- {
|
|
|
|
|
- type: NodeTypes.MetricNode,
|
|
|
|
|
- value: firstToken.value
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- var token;
|
|
|
|
|
|
|
+ parse: function (state, allowParams) {
|
|
|
|
|
+ var node = { };
|
|
|
|
|
|
|
|
while(true) {
|
|
while(true) {
|
|
|
- token = lexer.nextToken();
|
|
|
|
|
- if (checkToken(token, Lexer.Token.Identifier)) {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- /*while(true) {
|
|
|
|
|
- token = lexer.next();
|
|
|
|
|
|
|
+ this.token = this.lexer.next();
|
|
|
|
|
|
|
|
switch(state) {
|
|
switch(state) {
|
|
|
-
|
|
|
|
|
case "start":
|
|
case "start":
|
|
|
- if (checkToken(token, Lexer.Token.Identifier) {
|
|
|
|
|
|
|
+ if (allowParams) {
|
|
|
|
|
+ if (this.token === null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.type === Lexer.Token.NumericLiteral) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ type: NodeTypes.NumericLiteral,
|
|
|
|
|
+ value: parseInt(this.token.value)
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.type === Lexer.Token.StringLiteral) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ type: NodeTypes.StringLiteral,
|
|
|
|
|
+ value: this.token.value
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.isUnexpectedToken(Lexer.Token.Identifier)) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
state = "identifier";
|
|
state = "identifier";
|
|
|
- prevToken = token;
|
|
|
|
|
|
|
+ this.prevToken = this.token;
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case "identifier":
|
|
case "identifier":
|
|
|
- if (token == null) {
|
|
|
|
|
- node.type = NodeTypes.MetricExpression;
|
|
|
|
|
- node.children.push([
|
|
|
|
|
- type: NodeTypes.MetricNode,
|
|
|
|
|
- value: prevToken.value;
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- return node;
|
|
|
|
|
|
|
+ if (this.token == null || (allowParams && this.token.value === ',')) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ type: NodeTypes.MetricExpression,
|
|
|
|
|
+ segments: [{
|
|
|
|
|
+ type: NodeTypes.MetricExpression,
|
|
|
|
|
+ value: this.prevToken.value
|
|
|
|
|
+ }]
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (checkToken(token, Lexer.Token.Punctuator)) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ if (this.isUnexpectedToken(Lexer.Token.Punctuator)) {
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (token.value === '.') {
|
|
|
|
|
|
|
+ if (this.token.value === '.') {
|
|
|
state = "metricNode";
|
|
state = "metricNode";
|
|
|
node.type = NodeTypes.MetricExpression;
|
|
node.type = NodeTypes.MetricExpression;
|
|
|
- node.children.push({
|
|
|
|
|
|
|
+ node.segments = [{
|
|
|
type: NodeTypes.MetricNode,
|
|
type: NodeTypes.MetricNode,
|
|
|
- value: prevToken.value
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ value: this.prevToken.value
|
|
|
|
|
+ }];
|
|
|
|
|
+
|
|
|
|
|
+ continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (token.value === '(') {
|
|
|
|
|
- state = 'function';
|
|
|
|
|
|
|
+ if (this.token.value === '(') {
|
|
|
|
|
+ node.type = NodeTypes.FunctionCall;
|
|
|
|
|
+ node.name = this.prevToken.value;
|
|
|
|
|
+ node.params = this.parseFunc();
|
|
|
|
|
+ return node;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.value === ')') {
|
|
|
|
|
+ return node;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
break;
|
|
|
|
|
+
|
|
|
case 'metricEnd':
|
|
case 'metricEnd':
|
|
|
- if (token === null) {
|
|
|
|
|
|
|
+ if (this.token === null) {
|
|
|
return node;
|
|
return node;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (checkToken(token, Lexer.Token.Punctuator)) {
|
|
|
|
|
|
|
+ if (this.isUnexpectedToken(Lexer.Token.Punctuator)) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (this.token.value === '.') {
|
|
|
|
|
+ state = 'metricNode';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (allowParams && (this.token.value === ',' || this.token.value === ')')) {
|
|
|
|
|
+ return node;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
case 'metricNode':
|
|
case 'metricNode':
|
|
|
- if (checkToken(token, Lexer.Token.Identifier)) {
|
|
|
|
|
|
|
+ if (this.isUnexpectedToken(Lexer.Token.Identifier)) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- node.children.push([
|
|
|
|
|
|
|
+ node.segments.push({
|
|
|
type: NodeTypes.MetricNode,
|
|
type: NodeTypes.MetricNode,
|
|
|
- value: token.value
|
|
|
|
|
- ]);
|
|
|
|
|
|
|
+ value: this.token.value
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
state = 'metricEnd';
|
|
state = 'metricEnd';
|
|
|
break;
|
|
break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ this.error = 'unknown token: ' + this.token.type;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }*/
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ parseFunc: function() {
|
|
|
|
|
+ var arguments = [];
|
|
|
|
|
+ var arg;
|
|
|
|
|
+
|
|
|
|
|
+ while(true) {
|
|
|
|
|
+
|
|
|
|
|
+ arg = this.parse('start', true);
|
|
|
|
|
+ if (arg === null) {
|
|
|
|
|
+ this.error = "expected function arguments";
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ arguments.push(arg);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token === null) {
|
|
|
|
|
+ this.error = "expected closing function at position: " + this.lexer.char;
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.value === ')') {
|
|
|
|
|
+ return arguments;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.type === Lexer.Token.NumericLiteral ||
|
|
|
|
|
+ this.token.type === Lexer.Token.StringLiteral) {
|
|
|
|
|
+ this.token = this.lexer.next();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.isUnexpectedToken(Lexer.Token.Punctuator, ',')) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.token.value === ')') {
|
|
|
|
|
+ return arguments;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
return Parser;
|
|
return Parser;
|