Commit 35ae9e33 by Torkel Ödegaard

parser working horrible code

parent 8f77a821
...@@ -185,10 +185,14 @@ define([ ...@@ -185,10 +185,14 @@ define([
} }
} }
var match = var match = this.scanStringLiteral();
if (match) {
return match;
}
match =
this.scanIdentifier() || this.scanIdentifier() ||
this.scanPunctuator() || this.scanPunctuator() ||
this.scanStringLiteral() ||
this.scanNumericLiteral(); this.scanNumericLiteral();
if (match) { if (match) {
......
...@@ -3,9 +3,11 @@ define([ ...@@ -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([ ...@@ -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) { isUnexpectedToken: function (expected, value) {
if (token === null) { 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 " if (this.token.type === expected) {
+ expected + " instead found + " return false;
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 (nextToken == null) { if (value && this.token.value === value) {
return { return false;
type: NodeTypes.MetricExpression,
nodes: [
{
type: NodeTypes.MetricNode,
value: token.value
}
]
}
} }
if (checkToken(nextToken, Lexer.Token.Punctuator)) { this.error = "Expected token " + expected +
return null; ' instead found token ' + this.token.type +
} ' ("' + this.token.value + '")' +
" at position: " + this.lexer.char;
if (nextToken.value === '.') { return true;
return parseMetricExpression(token);
}
}, },
parseMetricExpression: function(firstToken) { parse: function (state, allowParams) {
var node = { var node = { };
type: NodeTypes.MetricExpression,
nodes: [
{
type: NodeTypes.MetricNode,
value: firstToken.value
}
]
};
var token;
while(true) { while(true) {
token = lexer.nextToken(); this.token = this.lexer.next();
if (checkToken(token, Lexer.Token.Identifier)) {
return null;
}
}
}
/*while(true) {
token = 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) { if (this.token == null || (allowParams && this.token.value === ',')) {
node.type = NodeTypes.MetricExpression; return {
node.children.push([ type: NodeTypes.MetricExpression,
type: NodeTypes.MetricNode, segments: [{
value: prevToken.value; type: NodeTypes.MetricExpression,
]); value: this.prevToken.value
}]
return node; };
} }
if (checkToken(token, Lexer.Token.Punctuator)) { if (this.isUnexpectedToken(Lexer.Token.Punctuator)) {
return; 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 === '(') { if (this.token.value === '(') {
state = 'function'; 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;
......
...@@ -26,6 +26,7 @@ define([ ...@@ -26,6 +26,7 @@ define([
expect(tokens[6].value).to.be('12'); expect(tokens[6].value).to.be('12');
expect(tokens[8].type).to.be(Lexer.Token.StringLiteral); expect(tokens[8].type).to.be(Lexer.Token.StringLiteral);
expect(tokens[8].value).to.be('test'); expect(tokens[8].value).to.be('test');
expect(tokens[tokens.length - 1].value).to.be(')');
}); });
}); });
......
...@@ -4,15 +4,61 @@ define([ ...@@ -4,15 +4,61 @@ define([
describe('when parsing graphite expression', function() { describe('when parsing graphite expression', function() {
it('should return ast', function() { it('simple metric expression', function() {
var parser = new Parser('metric.test.*.asd.count'); var parser = new Parser('metric.test.*.asd.count');
var ast = parser.getAst(); var rootNode = parser.getAst();
expect(ast[0].type).to.be(Parser.Nodes.MetricExpression);
expect(ast[0].nodes.length).to.be(5);
expect(ast[0].nodes[0].value).to.be('metric');
expect(parser.error).to.be(null);
expect(rootNode.type).to.be(Parser.Nodes.MetricExpression);
expect(rootNode.segments.length).to.be(5);
expect(rootNode.segments[0].value).to.be('metric');
});
it('simple function', function() {
var parser = new Parser('sum(test)');
var rootNode = parser.getAst();
expect(parser.error).to.be(null);
expect(rootNode.type).to.be(Parser.Nodes.FunctionCall);
expect(rootNode.params.length).to.be(1);
});
it('function with multiple args', function() {
var parser = new Parser("sum(test, 1, 'test')");
var rootNode = parser.getAst();
expect(parser.error).to.be(null);
expect(rootNode.type).to.be(Parser.Nodes.FunctionCall);
expect(rootNode.params.length).to.be(3);
expect(rootNode.params[0].type).to.be(Parser.Nodes.MetricExpression);
expect(rootNode.params[1].type).to.be(Parser.Nodes.NumericLiteral);
expect(rootNode.params[2].type).to.be(Parser.Nodes.StringLiteral);
}); });
it('function with nested function', function() {
var parser = new Parser("sum(scaleToSeconds(test, 1))");
var rootNode = parser.getAst();
expect(parser.error).to.be(null);
expect(rootNode.type).to.be(Parser.Nodes.FunctionCall);
expect(rootNode.params.length).to.be(1);
expect(rootNode.params[0].type).to.be(Parser.Nodes.FunctionCall);
expect(rootNode.params[0].name).to.be('scaleToSeconds');
expect(rootNode.params[0].params.length).to.be(2);
expect(rootNode.params[0].params[0].type).to.be(Parser.Nodes.MetricExpression);
expect(rootNode.params[0].params[1].type).to.be(Parser.Nodes.NumericLiteral);
});
it('function with multiple series', function() {
var parser = new Parser("sum(test.test.*.count, test.timers.*.count)");
var rootNode = parser.getAst();
expect(parser.error).to.be(null);
expect(rootNode.type).to.be(Parser.Nodes.FunctionCall);
expect(rootNode.params.length).to.be(2);
expect(rootNode.params[0].type).to.be(Parser.Nodes.MetricExpression);
expect(rootNode.params[1].type).to.be(Parser.Nodes.MetricExpression);
});
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment