فهرست منبع

fix(graphite): fixed minor graphite lexer issue when nodes begin with octal syntax and end with dash identifier, fixes #6049#

Torkel Ödegaard 9 سال پیش
والد
کامیت
d65fbcbb42

+ 1 - 1
public/app/features/dashboard/submenu/submenu.html

@@ -2,7 +2,7 @@
   <div ng-repeat="variable in ctrl.variables" ng-hide="variable.hide === 2" class="submenu-item gf-form-inline">
     <div class="gf-form">
       <label class="gf-form-label template-variable" ng-hide="variable.hide === 1">
-        {{variable.label || variable.name}}:
+        {{variable.label || variable.name}}
       </label>
       <value-select-dropdown ng-if="variable.type !== 'adhoc'" variable="variable" on-updated="ctrl.variableUpdated(variable)" get-values-for-tag="ctrl.getValuesForTag(variable, tagKey)"></value-select-dropdown>
     </div>

+ 196 - 198
public/app/plugins/datasource/graphite/lexer.ts

@@ -134,13 +134,7 @@ for (var i = 0; i < 128; i++) {
     i >= 97 && i <= 122;  // a-z
 }
 
-var identifierPartTable = [];
-
-for (var i2 = 0; i2 < 128; i2++) {
-  identifierPartTable[i2] =
-    identifierStartTable[i2] || // $, _, A-Z, a-z
-    i2 >= 48 && i2 <= 57;        // 0-9
-}
+var identifierPartTable = identifierStartTable;
 
 export function Lexer(expression) {
   this.input = expression;
@@ -423,117 +417,148 @@ Lexer.prototype = {
     if (char === '-') {
       value += char;
       index += 1;
-    char = this.peek(index);
-      }
-
-      // Numbers must start either with a decimal digit or a point.
-      if (char !== "." && !isDecimalDigit(char)) {
-        return null;
-      }
-
-      if (char !== ".") {
-        value += this.peek(index);
-        index += 1;
-        char = this.peek(index);
+      char = this.peek(index);
+    }
 
-        if (value === "0") {
-          // Base-16 numbers.
-          if (char === "x" || char === "X") {
-            index += 1;
-            value += char;
+    // Numbers must start either with a decimal digit or a point.
+    if (char !== "." && !isDecimalDigit(char)) {
+      return null;
+    }
 
-            while (index < length) {
-              char = this.peek(index);
-              if (!isHexDigit(char)) {
-                break;
-              }
-              value += char;
-              index += 1;
-            }
+    if (char !== ".") {
+      value += this.peek(index);
+      index += 1;
+      char = this.peek(index);
 
-            if (value.length <= 2) { // 0x
-              return {
-                type: 'number',
-                value: value,
-                isMalformed: true,
-                pos: this.char
-              };
-            }
+      if (value === "0") {
+        // Base-16 numbers.
+        if (char === "x" || char === "X") {
+          index += 1;
+          value += char;
 
-            if (index < length) {
-              char = this.peek(index);
-              if (isIdentifierStart(char)) {
-                return null;
-              }
+          while (index < length) {
+            char = this.peek(index);
+            if (!isHexDigit(char)) {
+              break;
             }
+            value += char;
+            index += 1;
+          }
 
+          if (value.length <= 2) { // 0x
             return {
               type: 'number',
               value: value,
-              base: 16,
-              isMalformed: false,
+              isMalformed: true,
               pos: this.char
             };
           }
 
-          // Base-8 numbers.
-          if (isOctalDigit(char)) {
-            index += 1;
-            value += char;
-            bad = false;
+          if (index < length) {
+            char = this.peek(index);
+            if (isIdentifierStart(char)) {
+              return null;
+            }
+          }
 
-            while (index < length) {
-              char = this.peek(index);
+          return {
+            type: 'number',
+            value: value,
+            base: 16,
+            isMalformed: false,
+            pos: this.char
+          };
+        }
 
-              // Numbers like '019' (note the 9) are not valid octals
-              // but we still parse them and mark as malformed.
+        // Base-8 numbers.
+        if (isOctalDigit(char)) {
+          index += 1;
+          value += char;
+          bad = false;
 
-              if (isDecimalDigit(char)) {
-                bad = true;
-              } else if (!isOctalDigit(char)) {
-                break;
-              }
-              value += char;
-              index += 1;
-            }
+          while (index < length) {
+            char = this.peek(index);
+
+            // Numbers like '019' (note the 9) are not valid octals
+            // but we still parse them and mark as malformed.
 
-            if (index < length) {
-              char = this.peek(index);
-              if (isIdentifierStart(char)) {
+            if (isDecimalDigit(char)) {
+              bad = true;
+            } if (!isOctalDigit(char)) {
+              // if the char is a non punctuator then its not a valid number
+              if (!this.isPunctuator(char)) {
                 return null;
               }
+              break;
             }
-
-            return {
-              type: 'number',
-              value: value,
-              base: 8,
-              isMalformed: false
-            };
+            value += char;
+            index += 1;
           }
 
-          // Decimal numbers that start with '0' such as '09' are illegal
-          // but we still parse them and return as malformed.
-
-          if (isDecimalDigit(char)) {
-            index += 1;
-            value += char;
+          if (index < length) {
+            char = this.peek(index);
+            if (isIdentifierStart(char)) {
+              return null;
+            }
           }
+
+          return {
+            type: 'number',
+            value: value,
+            base: 8,
+            isMalformed: bad
+          };
         }
 
-        while (index < length) {
-          char = this.peek(index);
-          if (!isDecimalDigit(char)) {
-            break;
-          }
-          value += char;
+        // Decimal numbers that start with '0' such as '09' are illegal
+        // but we still parse them and return as malformed.
+
+        if (isDecimalDigit(char)) {
           index += 1;
+          value += char;
         }
       }
 
-      // Decimal digits.
+      while (index < length) {
+        char = this.peek(index);
+        if (!isDecimalDigit(char)) {
+          break;
+        }
+        value += char;
+        index += 1;
+      }
+    }
+
+    // Decimal digits.
+
+    if (char === ".") {
+      value += char;
+      index += 1;
 
-      if (char === ".") {
+      while (index < length) {
+        char = this.peek(index);
+        if (!isDecimalDigit(char)) {
+          break;
+        }
+        value += char;
+        index += 1;
+      }
+    }
+
+    // Exponent part.
+
+    if (char === "e" || char === "E") {
+      value += char;
+      index += 1;
+      char = this.peek(index);
+
+      if (char === "+" || char === "-") {
+        value += this.peek(index);
+        index += 1;
+      }
+
+      char = this.peek(index);
+      if (isDecimalDigit(char)) {
         value += char;
         index += 1;
 
@@ -545,134 +570,107 @@ Lexer.prototype = {
           value += char;
           index += 1;
         }
+      } else {
+        return null;
       }
+    }
 
-      // Exponent part.
-
-      if (char === "e" || char === "E") {
-        value += char;
-        index += 1;
-        char = this.peek(index);
+    if (index < length) {
+      char = this.peek(index);
+      if (!this.isPunctuator(char)) {
+        return null;
+      }
+    }
 
-        if (char === "+" || char === "-") {
-          value += this.peek(index);
-          index += 1;
-        }
+    return {
+      type: 'number',
+      value: value,
+      base: 10,
+      pos: this.char,
+      isMalformed: !isFinite(+value)
+    };
+  },
 
-        char = this.peek(index);
-        if (isDecimalDigit(char)) {
-          value += char;
-          index += 1;
+  isPunctuator: function (ch1) {
+    switch (ch1) {
+      case ".":
+        case "(":
+        case ")":
+        case ",":
+        case "{":
+        case "}":
+        return true;
+    }
 
-          while (index < length) {
-            char = this.peek(index);
-            if (!isDecimalDigit(char)) {
-              break;
-            }
-            value += char;
-            index += 1;
-          }
-        } else {
-          return null;
-        }
-      }
+    return false;
+  },
 
-      if (index < length) {
-        char = this.peek(index);
-        if (!this.isPunctuator(char)) {
-          return null;
-        }
-      }
+  scanPunctuator: function () {
+    var ch1 = this.peek();
 
+    if (this.isPunctuator(ch1)) {
       return {
-        type: 'number',
-        value: value,
-        base: 10,
-        pos: this.char,
-        isMalformed: !isFinite(+value)
+        type: ch1,
+        value: ch1,
+        pos: this.char
       };
-    },
-
-    isPunctuator: function (ch1) {
-      switch (ch1) {
-        case ".":
-          case "(":
-          case ")":
-          case ",":
-          case "{":
-          case "}":
-          return true;
-      }
-
-      return false;
-    },
+    }
 
-    scanPunctuator: function () {
-      var ch1 = this.peek();
+    return null;
+  },
 
-      if (this.isPunctuator(ch1)) {
-        return {
-          type: ch1,
-          value: ch1,
-          pos: this.char
-        };
-      }
+  /*
+   * Extract a string out of the next sequence of characters and/or
+   * lines or return 'null' if its not possible. Since strings can
+   * span across multiple lines this method has to move the char
+   * pointer.
+   *
+   * This method recognizes pseudo-multiline JavaScript strings:
+   *
+   *   var str = "hello\
+   *   world";
+   */
+  scanStringLiteral: function () {
+    /*jshint loopfunc:true */
+    var quote = this.peek();
 
+    // String must start with a quote.
+    if (quote !== "\"" && quote !== "'") {
       return null;
-    },
-
-    /*
-     * Extract a string out of the next sequence of characters and/or
-     * lines or return 'null' if its not possible. Since strings can
-     * span across multiple lines this method has to move the char
-     * pointer.
-     *
-     * This method recognizes pseudo-multiline JavaScript strings:
-     *
-     *   var str = "hello\
-     *   world";
-     */
-    scanStringLiteral: function () {
-      /*jshint loopfunc:true */
-      var quote = this.peek();
-
-      // String must start with a quote.
-      if (quote !== "\"" && quote !== "'") {
-        return null;
-      }
+    }
 
-      var value = "";
+    var value = "";
 
-      this.skip();
+    this.skip();
 
-      while (this.peek() !== quote) {
-        if (this.peek() === "") { // End Of Line
-          return {
-            type: 'string',
-            value: value,
-            isUnclosed: true,
-            quote: quote,
-            pos: this.char
-          };
-        }
+    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
-        // parsing this character.
+      var char = this.peek();
+      var jump = 1; // A length of a jump, after we're done
+      // parsing this character.
 
-        value += char;
-        this.skip(jump);
-      }
+      value += char;
+      this.skip(jump);
+    }
 
-      this.skip();
-      return {
-        type: 'string',
-        value: value,
-        isUnclosed: false,
-        quote: quote,
-        pos: this.char
-      };
-    },
+    this.skip();
+    return {
+      type: 'string',
+      value: value,
+      isUnclosed: false,
+      quote: quote,
+      pos: this.char
+    };
+  },
 
-  };
+};
 

+ 1 - 4
public/app/plugins/datasource/graphite/parser.ts

@@ -100,10 +100,7 @@ Parser.prototype = {
   },
 
   metricExpression: function() {
-    if (!this.match('templateStart') &&
-        !this.match('identifier') &&
-          !this.match('number') &&
-            !this.match('{')) {
+    if (!this.match('templateStart') && !this.match('identifier') && !this.match('number') && !this.match('{')) {
       return null;
     }
 

+ 8 - 0
public/app/plugins/datasource/graphite/specs/lexer_specs.ts

@@ -62,6 +62,14 @@ describe('when lexing graphite expression', function() {
     expect(tokens[4].type).to.be('identifier');
   });
 
+  it('should tokenize metric expression with segment that start with number', function() {
+    var lexer = new Lexer("metric.001-server");
+    var tokens = lexer.tokenize();
+    expect(tokens[0].type).to.be('identifier');
+    expect(tokens[2].type).to.be('identifier');
+    expect(tokens.length).to.be(3);
+  });
+
   it('should tokenize func call with numbered metric and number arg', function() {
     var lexer = new Lexer("scale(metric.10, 15)");
     var tokens = lexer.tokenize();