Просмотр исходного кода

fixed sorting of functions, and lexing parsing fix for unclosed string params

Torkel Ödegaard 12 лет назад
Родитель
Сommit
2acfa83b76

+ 2 - 2
src/app/controllers/graphiteTarget.js

@@ -27,8 +27,8 @@ function (angular, _, config, graphiteFuncs, Parser) {
       var parser = new Parser($scope.target.target);
       var astNode = parser.getAst();
 
-      if (parser.error) {
-        $scope.parserError = parser.error.text + " at position: " + parser.error.pos;
+      if (astNode.type === 'error') {
+        $scope.parserError = astNode.message + " at position: " + astNode.pos;
         $scope.showTextEditor = true;
         return;
       }

+ 4 - 0
src/app/services/graphite/graphiteFuncs.js

@@ -124,6 +124,10 @@ function (_) {
     defaultParams: ['1d']
   });
 
+  _.each(categories, function(funcList, catName) {
+    categories[catName] = _.sortBy(funcList, 'name');
+  });
+
   function FuncInstance(funcDef) {
     this.def = funcDef;
     this.params = funcDef.defaultParams.slice(0);

+ 9 - 0
src/app/services/graphite/lexer.js

@@ -591,6 +591,15 @@ define([
       this.skip();
 
       while (this.peek() !== quote) {
+        if (this.peek() === "") { // End Of Line
+          return {
+            type: 'string',
+            value: value,
+            isUnclosed: true,
+            quote: quote,
+            pos: this.char
+          };
+        }
 
         var char = this.peek();
         var jump = 1; // A length of a jump, after we're done

+ 18 - 18
src/app/services/graphite/parser.js

@@ -3,25 +3,13 @@ define([
 ], function (Lexer) {
   'use strict';
 
-  var NodeTypes = {
-    MetricExpression: 1,
-    MetricNode: 2,
-    FunctionCall: 4,
-    NumericLiteral: 5,
-    StringLiteral: 6
-  };
-
   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 () {
@@ -29,7 +17,16 @@ define([
     },
 
     start: function () {
-      return this.functionCall() || this.metricExpression();
+      try {
+        return this.functionCall() || this.metricExpression();
+      }
+      catch(e) {
+        return {
+          type: 'error',
+          message: e.message,
+          pos: e.pos
+        };
+      }
     },
 
     metricExpression: function() {
@@ -52,7 +49,6 @@ define([
         var rest = this.metricExpression();
         if (!rest) {
           this.errorMark('Expected metric identifier');
-          return null;
         }
 
         node.segments = node.segments.concat(rest.segments);
@@ -77,7 +73,6 @@ define([
 
       if (!this.match(')')) {
         this.errorMark('Expected closing paranthesis');
-        return null;
       }
 
       this.index++;
@@ -122,19 +117,24 @@ define([
         return null;
       }
 
+      var token = this.tokens[this.index];
+      if (token.isUnclosed) {
+        throw { message: 'Unclosed string parameter', pos: token.pos };
+      }
+
       this.index++;
 
       return {
         type: 'string',
-        value: this.tokens[this.index-1].value
+        value: token.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,
+      throw {
+        message: text + " instead found " + type,
         pos: currentToken ? currentToken.pos : this.lexer.char
       };
     },

+ 13 - 0
src/test/specs/lexer-specs.js

@@ -30,6 +30,19 @@ define([
       expect(tokens[tokens.length - 1].value).to.be(')');
     });
 
+    it('should handle error with unterminated string', function() {
+      var lexer = new Lexer("alias(metric, 'asd)");
+      var tokens = lexer.tokenize();
+      expect(tokens[0].value).to.be('alias');
+      expect(tokens[1].value).to.be('(');
+      expect(tokens[2].value).to.be('metric');
+      expect(tokens[3].value).to.be(',');
+      expect(tokens[4].type).to.be('string');
+      expect(tokens[4].isUnclosed).to.be(true);
+      expect(tokens[4].pos).to.be(20);
+    });
+
+
   });
 
 });

+ 12 - 9
src/test/specs/parser-specs.js

@@ -8,7 +8,6 @@ define([
       var parser = new Parser('metric.test.*.asd.count');
       var rootNode = parser.getAst();
 
-      expect(parser.error).to.be(null);
       expect(rootNode.type).to.be('metric');
       expect(rootNode.segments.length).to.be(5);
       expect(rootNode.segments[0].value).to.be('metric');
@@ -17,7 +16,6 @@ define([
     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('function');
       expect(rootNode.params.length).to.be(1);
     });
@@ -26,7 +24,6 @@ define([
       var parser = new Parser("sum(test, 1, 'test')");
       var rootNode = parser.getAst();
 
-      expect(parser.error).to.be(null);
       expect(rootNode.type).to.be('function');
       expect(rootNode.params.length).to.be(3);
       expect(rootNode.params[0].type).to.be('metric');
@@ -38,7 +35,6 @@ define([
       var parser = new Parser("sum(scaleToSeconds(test, 1))");
       var rootNode = parser.getAst();
 
-      expect(parser.error).to.be(null);
       expect(rootNode.type).to.be('function');
       expect(rootNode.params.length).to.be(1);
       expect(rootNode.params[0].type).to.be('function');
@@ -52,7 +48,6 @@ define([
       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('function');
       expect(rootNode.params.length).to.be(2);
       expect(rootNode.params[0].type).to.be('metric');
@@ -63,16 +58,24 @@ define([
       var parser = new Parser('metric.test.*.asd.');
       var rootNode = parser.getAst();
 
-      expect(parser.error.text).to.be('Expected metric identifier instead found end of string');
-      expect(parser.error.pos).to.be(19);
+      expect(rootNode.message).to.be('Expected metric identifier instead found end of string');
+      expect(rootNode.pos).to.be(19);
     });
 
     it('invalid function expression missing closing paranthesis', function() {
       var parser = new Parser('sum(test');
       var rootNode = parser.getAst();
 
-      expect(parser.error.text).to.be('Expected closing paranthesis instead found end of string');
-      expect(parser.error.pos).to.be(9);
+      expect(rootNode.message).to.be('Expected closing paranthesis instead found end of string');
+      expect(rootNode.pos).to.be(9);
+    });
+
+    it('unclosed string in function', function() {
+      var parser = new Parser("sum('test)");
+      var rootNode = parser.getAst();
+
+      expect(rootNode.message).to.be('Unclosed string parameter');
+      expect(rootNode.pos).to.be(11);
     });
 
   });