Commit cef4349b by Torkel Ödegaard

added lexer/parser support for templated metric expressions, karma test runner is working

parent 9480077f
...@@ -82,13 +82,24 @@ function (angular, _, config, graphiteFuncs, Parser) { ...@@ -82,13 +82,24 @@ function (angular, _, config, graphiteFuncs, Parser) {
$scope.segments = _.map(astNode.segments, function(segment) { $scope.segments = _.map(astNode.segments, function(segment) {
return { return {
type: segment.type,
val: segment.value, val: segment.value,
html: segment.value === '*' ? '<i class="icon-asterisk"><i>' : segment.value html: getSegmentHtml(segment)
}; };
}); });
} }
} }
function getSegmentHtml(segment) {
if (segment.value === '*') {
return '<i class="icon-asterisk"><i>';
}
if (segment.type === 'template') {
return "<span style='color: #ECEC09'>[[" + segment.value + "]]</span>";
}
return segment.value;
}
function getSegmentPathUpTo(index) { function getSegmentPathUpTo(index) {
var arr = $scope.segments.slice(0, index); var arr = $scope.segments.slice(0, index);
......
...@@ -182,6 +182,7 @@ define([ ...@@ -182,6 +182,7 @@ define([
match = match =
this.scanIdentifier() || this.scanIdentifier() ||
this.scanTemplateSequence() ||
this.scanPunctuator() || this.scanPunctuator() ||
this.scanNumericLiteral(); this.scanNumericLiteral();
...@@ -194,6 +195,26 @@ define([ ...@@ -194,6 +195,26 @@ define([
return null; return null;
}, },
scanTemplateSequence: function() {
if (this.peek() === '[' && this.peek(1) === '[') {
return {
type: 'templateStart',
value: '[[',
pos: this.char
};
}
if (this.peek() === ']' && this.peek(1) === ']') {
return {
type: 'templateEnd',
value: '[[',
pos: this.char
};
}
return null;
},
/* /*
* Extract a JavaScript identifier out of the next sequence of * Extract a JavaScript identifier out of the next sequence of
* characters or return 'null' if its not possible. In addition, * characters or return 'null' if its not possible. In addition,
......
...@@ -29,29 +29,61 @@ define([ ...@@ -29,29 +29,61 @@ define([
} }
}, },
metricExpression: function() { metricSegment: function() {
if (this.match('identifier')) {
this.index++;
return {
type: 'segment',
value: this.tokens[this.index-1].value
};
}
if (!this.match('templateStart')) {
this.errorMark('Expected metric identifier');
}
this.index++;
if (!this.match('identifier')) { if (!this.match('identifier')) {
return null; this.errorMark('Expected identifier after templateStart');
} }
var node = { var node = {
type: 'metric', type: 'template',
segments: [{
type: 'segment',
value: this.tokens[this.index].value value: this.tokens[this.index].value
}]
}; };
this.index++; this.index++;
if (this.match('.')) { if (!this.match('templateEnd')) {
this.errorMark('Expected templateEnd');
}
this.index++; this.index++;
var rest = this.metricExpression(); return node;
if (!rest) { },
metricExpression: function() {
if (!this.match('templateStart') && !this.match('identifier')) {
return null;
}
var node = {
type: 'metric',
segments: []
};
node.segments.push(this.metricSegment());
while(this.match('.')) {
this.index++;
var segment = this.metricSegment();
if (!segment) {
this.errorMark('Expected metric identifier'); this.errorMark('Expected metric identifier');
} }
node.segments = node.segments.concat(rest.segments); node.segments.push(segment);
} }
return node; return node;
......
module.exports = function(config) {
config.set({
basePath: '../',
frameworks: ['mocha', 'requirejs', 'expect'],
// list of files / patterns to load in the browser
files: [
'test/test-main.js',
{pattern: 'app/**/*.js', included: false},
{pattern: 'test/**/*.js', included: false}
],
// list of files to exclude
exclude: [
],
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
captureTimeout: 60000,
singleRun: false
});
};
...@@ -30,6 +30,15 @@ define([ ...@@ -30,6 +30,15 @@ define([
expect(tokens[tokens.length - 1].value).to.be(')'); expect(tokens[tokens.length - 1].value).to.be(')');
}); });
it('should tokenize metric with template parameter', function() {
var lexer = new Lexer("metric.[[server]].test");
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('templateStart');
expect(tokens[3].type).to.be('identifier');
expect(tokens[3].value).to.be('server');
expect(tokens[4].type).to.be('templateEnd');
});
it('should handle error with unterminated string', function() { it('should handle error with unterminated string', function() {
var lexer = new Lexer("alias(metric, 'asd)"); var lexer = new Lexer("alias(metric, 'asd)");
var tokens = lexer.tokenize(); var tokens = lexer.tokenize();
......
...@@ -54,6 +54,15 @@ define([ ...@@ -54,6 +54,15 @@ define([
expect(rootNode.params[1].type).to.be('metric'); expect(rootNode.params[1].type).to.be('metric');
}); });
it('function with templated series', function() {
var parser = new Parser("sum(test.[[server]].count)");
var rootNode = parser.getAst();
expect(rootNode.message).to.be(undefined)
expect(rootNode.params[0].type).to.be('metric');
expect(rootNode.params[0].segments[1].type).to.be('template');
});
it('invalid metric expression', function() { it('invalid metric expression', function() {
var parser = new Parser('metric.test.*.asd.'); var parser = new Parser('metric.test.*.asd.');
var rootNode = parser.getAst(); var rootNode = parser.getAst();
......
require.config({
baseUrl:'base'
});
require([
'test/specs/lexer-specs',
'test/specs/parser-specs',
], function () {
window.__karma__.start();
});
\ No newline at end of file
module.exports = function(config) {
return {
unit: {
configFile: 'src/test/karma.conf.js',
singleRun: false,
browsers: ['Chrome']
}
};
};
\ No newline at end of file
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