mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
parser working horrible code
This commit is contained in:
@@ -185,10 +185,14 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
var match =
|
||||
var match = this.scanStringLiteral();
|
||||
if (match) {
|
||||
return match;
|
||||
}
|
||||
|
||||
match =
|
||||
this.scanIdentifier() ||
|
||||
this.scanPunctuator() ||
|
||||
this.scanStringLiteral() ||
|
||||
this.scanNumericLiteral();
|
||||
|
||||
if (match) {
|
||||
|
||||
@@ -3,9 +3,11 @@ define([
|
||||
], function (Lexer) {
|
||||
|
||||
var NodeTypes = {
|
||||
MetricExpression = 1,
|
||||
MetricExpression: 1,
|
||||
MetricNode: 2,
|
||||
FunctionCall: 4
|
||||
FunctionCall: 4,
|
||||
NumericLiteral: 5,
|
||||
StringLiteral: 6
|
||||
};
|
||||
|
||||
function Node(type, value) {
|
||||
@@ -20,147 +22,184 @@ define([
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
Parser.Nodes = NodeTypes;
|
||||
|
||||
Parser.prototype = {
|
||||
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";
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.type === expected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.error = "Expected token "
|
||||
+ expected + " instead found + "
|
||||
found + " at position: " + lexer.char;
|
||||
if (this.token.type === expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (value && this.token.value === value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.error = "Expected token " + expected +
|
||||
' instead found token ' + this.token.type +
|
||||
' ("' + this.token.value + '")' +
|
||||
" at position: " + this.lexer.char;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
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) {
|
||||
return {
|
||||
type: NodeTypes.MetricExpression,
|
||||
nodes: [
|
||||
{
|
||||
type: NodeTypes.MetricNode,
|
||||
value: token.value
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (checkToken(nextToken, Lexer.Token.Punctuator)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (nextToken.value === '.') {
|
||||
return parseMetricExpression(token);
|
||||
}
|
||||
},
|
||||
|
||||
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) {
|
||||
token = lexer.nextToken();
|
||||
if (checkToken(token, Lexer.Token.Identifier)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*while(true) {
|
||||
token = lexer.next();
|
||||
this.token = this.lexer.next();
|
||||
|
||||
switch(state) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
state = "identifier";
|
||||
prevToken = token;
|
||||
this.prevToken = this.token;
|
||||
break;
|
||||
|
||||
case "identifier":
|
||||
if (token == null) {
|
||||
node.type = NodeTypes.MetricExpression;
|
||||
node.children.push([
|
||||
type: NodeTypes.MetricNode,
|
||||
value: prevToken.value;
|
||||
]);
|
||||
if (this.token == null || (allowParams && this.token.value === ',')) {
|
||||
return {
|
||||
type: NodeTypes.MetricExpression,
|
||||
segments: [{
|
||||
type: NodeTypes.MetricExpression,
|
||||
value: this.prevToken.value
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isUnexpectedToken(Lexer.Token.Punctuator)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.token.value === '.') {
|
||||
state = "metricNode";
|
||||
node.type = NodeTypes.MetricExpression;
|
||||
node.segments = [{
|
||||
type: NodeTypes.MetricNode,
|
||||
value: this.prevToken.value
|
||||
}];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.token.value === '(') {
|
||||
node.type = NodeTypes.FunctionCall;
|
||||
node.name = this.prevToken.value;
|
||||
node.params = this.parseFunc();
|
||||
return node;
|
||||
}
|
||||
|
||||
if (checkToken(token, Lexer.Token.Punctuator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.value === '.') {
|
||||
state = "metricNode";
|
||||
node.type = NodeTypes.MetricExpression;
|
||||
node.children.push({
|
||||
type: NodeTypes.MetricNode,
|
||||
value: prevToken.value
|
||||
});
|
||||
}
|
||||
|
||||
if (token.value === '(') {
|
||||
state = 'function';
|
||||
if (this.token.value === ')') {
|
||||
return node;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'metricEnd':
|
||||
if (token === null) {
|
||||
if (this.token === null) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (checkToken(token, Lexer.Token.Punctuator)) {
|
||||
if (this.isUnexpectedToken(Lexer.Token.Punctuator)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.token.value === '.') {
|
||||
state = 'metricNode';
|
||||
}
|
||||
|
||||
if (allowParams && (this.token.value === ',' || this.token.value === ')')) {
|
||||
return node;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'metricNode':
|
||||
if (checkToken(token, Lexer.Token.Identifier)) {
|
||||
if (this.isUnexpectedToken(Lexer.Token.Identifier)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
node.children.push([
|
||||
node.segments.push({
|
||||
type: NodeTypes.MetricNode,
|
||||
value: token.value
|
||||
]);
|
||||
value: this.token.value
|
||||
});
|
||||
|
||||
state = 'metricEnd';
|
||||
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;
|
||||
|
||||
@@ -26,6 +26,7 @@ define([
|
||||
expect(tokens[6].value).to.be('12');
|
||||
expect(tokens[8].type).to.be(Lexer.Token.StringLiteral);
|
||||
expect(tokens[8].value).to.be('test');
|
||||
expect(tokens[tokens.length - 1].value).to.be(')');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -4,15 +4,61 @@ define([
|
||||
|
||||
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 ast = 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');
|
||||
var rootNode = parser.getAst();
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user