| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- define([
- './lexer'
- ], function (Lexer) {
- var NodeTypes = {
- MetricExpression: 1,
- MetricNode: 2,
- FunctionCall: 4,
- NumericLiteral: 5,
- StringLiteral: 6
- };
- function Node(type, value) {
- this.type = type;
- this.value = value;
- }
- function Parser(expression) {
- this.expression = expression;
- this.lexer = new Lexer(expression);
- this.state = "start";
- this.error = null;
- this.tokens = this.lexer.tokenize();
- this.index = 0;
- }
- Parser.Nodes = NodeTypes;
- Parser.prototype = {
- getAst: function () {
- return this.start();
- },
- start: function () {
- return this.functionCall() || this.metricExpression();
- },
- metricExpression: function() {
- if (!this.match('identifier')) {
- return null;
- }
- var node = {
- type: 'metric',
- segments: [{
- type: 'segment',
- value: this.tokens[this.index].value
- }]
- }
- this.index++;
- if (this.match('.')) {
- this.index++;
- var rest = this.metricExpression();
- if (!rest) {
- this.errorMark('Expected metric identifier');
- return null;
- }
- node.segments = node.segments.concat(rest.segments)
- }
- return node;
- },
- functionCall: function() {
- if (!this.match('identifier', '(')) {
- return null;
- }
- var node = {
- type: 'function',
- name: this.tokens[this.index].value,
- };
- this.index += 2;
- node.params = this.functionParameters();
- if (!this.match(')')) {
- this.errorMark('Expected closing paranthesis');
- return null;
- }
- this.index++;
- return node;
- },
- functionParameters: function () {
- if (this.match(')') || this.match('')) {
- return [];
- }
- var param =
- this.functionCall() ||
- this.metricExpression() ||
- this.numericLiteral() ||
- this.stringLiteral();
- if (!this.match(',')) {
- return [param];
- }
- this.index++;
- return [param].concat(this.functionParameters());
- },
- numericLiteral: function () {
- if (!this.match('number')) {
- return null;
- }
- this.index++;
- return {
- type: 'number',
- value: this.tokens[this.index-1].value
- };
- },
- stringLiteral: function () {
- if (!this.match('string')) {
- return null;
- }
- this.index++;
- return {
- type: 'string',
- value: this.tokens[this.index-1].value
- };
- },
- errorMark: function(text) {
- var currentToken = this.tokens[this.index];
- var type = currentToken ? currentToken.type : 'end of string';
- this.error = {
- text: text + " instead found " + type,
- pos: currentToken ? currentToken.pos : this.lexer.char
- };
- },
- matchToken: function(type, index) {
- var token = this.tokens[this.index + index];
- return (token === undefined && type === '') ||
- token && token.type === type;
- },
- match: function(token1, token2) {
- return this.matchToken(token1, 0) &&
- (!token2 || this.matchToken(token2, 1))
- },
- };
- return Parser;
- });
|