[Pkg-mozext-commits] [greasemonkey] 01/45: Parse metadata lines via a formal grammar.

David Prévot taffit at moszumanska.debian.org
Mon Nov 3 20:59:18 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository greasemonkey.

commit ad82f7c5123ceb64fcfd68fea2b017862f6eb7be
Author: Anthony Lieuallen <arantius at gmail.com>
Date:   Mon Aug 25 15:58:47 2014 -0400

    Parse metadata lines via a formal grammar.
    
    And a parser generator.
    
    Refs #1996
---
 modules/parseScript.js        | 155 +++++-----
 modules/stats.js              |  15 -
 modules/util/parseMetaLine.js | 695 ++++++++++++++++++++++++++++++++++++++++++
 peg.txt                       |  85 ++++++
 4 files changed, 856 insertions(+), 94 deletions(-)

diff --git a/modules/parseScript.js b/modules/parseScript.js
index f2b363d..e6ac7e6 100644
--- a/modules/parseScript.js
+++ b/modules/parseScript.js
@@ -1,5 +1,4 @@
-var EXPORTED_SYMBOLS = [
-    'extractMeta', 'parse', 'gLineSplitRegexp', 'gMetaLineRegexp'];
+var EXPORTED_SYMBOLS = ['extractMeta', 'parse'];
 
 Components.utils.import('resource://greasemonkey/script.js');
 Components.utils.import('resource://greasemonkey/scriptIcon.js');
@@ -10,15 +9,15 @@ Components.utils.import('resource://greasemonkey/util.js');
 
 var gIoService = Components.classes["@mozilla.org/network/io-service;1"]
     .getService(Components.interfaces.nsIIOService);
-var gLineSplitRegexp = /.+/g;
 var gAllMetaRegexp = new RegExp(
-    '^(\u00EF\u00BB\u00BF)?// ==UserScript==([\\s\\S]*?)^// ==/UserScript==', 'm');
-var gMetaLineRegexp = new RegExp('// @([^\\s:]+)(?::([a-zA-Z-]+))?(?:\\s+(.*))?');
+    '^(\u00EF\u00BB\u00BF)?// ==UserScript==([\\s\\S]*?)^// ==/UserScript==',
+    'm');
 var gStringBundle = Components
     .classes["@mozilla.org/intl/stringbundle;1"]
     .getService(Components.interfaces.nsIStringBundleService)
     .createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
 
+
 /** Get just the stuff between ==UserScript== lines. */
 function extractMeta(aSource) {
   var meta = aSource.match(gAllMetaRegexp);
@@ -26,9 +25,10 @@ function extractMeta(aSource) {
   return '';
 }
 
+
 /** Parse the source of a script; produce Script object. */
 function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
-  var meta = extractMeta(aSource).match(gLineSplitRegexp);
+  var meta = extractMeta(aSource).match(/.+/g);
   if (aFailWhenMissing && !meta && !aNoMetaOk) return null;
 
   var script = new Script();
@@ -48,124 +48,120 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
   }
 
   var resourceNames = {};
-  if (meta) for (var i = 0, metaLine = ''; metaLine = meta[i]; i++) {
-    metaLine = metaLine.replace(/\s+$/, '');
-
-    var match = metaLine.match(gMetaLineRegexp);
-    if (!match) continue;
-
-    var header = match[1];
-    var locale = match[2];
-    var value = match[3] || null;
+  for (var i = 0, metaLine = ''; metaLine = meta[i]; i++) {
+    try {
+      var data = GM_util.parseMetaLine(metaLine.replace(/\s+$/, ''));
+    } catch (e) {
+      // Ignore invalid/unsupported meta lines.
+      continue;
+    }
 
-    switch (header) {
+    switch (data.keyword) {
     case 'description':
     case 'name':
+      var locale = data.locale.replace(/^:/, '');
+
       if (locale) {
-        if (!script._locales[locale])
+        if (!script._locales[locale]) {
           script._locales[locale] = {};
+        }
+        script._locales[locale][keyword] = data.value;
+      }
+
+      script['_' + data.keyword] = data.value;
 
-        script._locales[locale][header] = value;
-        break;
+      break;
+
+    case 'resource':
+      var name = data.value1;
+      var url = data.value2;
+
+      resourceNames[name] = true;
+
+      try {
+        var resUri = GM_util.uriFromUrl(url, aUri);
+        var scriptResource = new ScriptResource(script);
+        scriptResource._name = name;
+        scriptResource._downloadURL = resUri.spec;
+        script._resources.push(scriptResource);
+        script._rawMeta += data.keyword + '\0'
+            + name + '\0'
+            + resUri.spec + '\0';
+      } catch (e) {
+        script.parseErrors.push(
+            gStringBundle.GetStringFromName('parse.resource-failed')
+                .replace('%1', name).replace('%2', url)
+            );
       }
-      // fall-through if no locale given
+
+      break;
+
     case 'namespace':
     case 'version':
-    case 'updateMetaStatus':
-      script['_' + header] = value;
+      script['_' + data.keyword] = data.value;
+      break;
+    case 'exclude':
+      script._excludes.push(data.value);
+      break;
+    case 'grant':
+      script._grants.push(data.value);
+      break;
+    case 'include':
+      script._includes.push(data.value);
+      break;
+    case 'run-at':
+      script._runAt = data.value;
       break;
 
     case 'installURL':
-      header = 'downloadURL';
+      data.keyword = 'downloadURL';
     case 'downloadURL':
     case 'updateURL':
       try {
-        var uri = GM_util.uriFromUrl(value, aUri);
-        script[header] = uri.spec;
+        var uri = GM_util.uriFromUrl(data.value, aUri);
+        script[data.keyword] = uri.spec;
       } catch (e) {
-        dump('Failed to parse ' + header + ' "' + value + '":\n' + e + '\n');
+        dump('Failed to parse ' + data.keyword
+            + ' "' + data.value + '":\n' + e + '\n');
       }
       break;
 
-    case 'exclude':
-      script._excludes.push(value);
-      break;
-    case 'grant':
-      script._grants.push(value);
-      break;
     case 'icon':
       try {
-        script.icon.setMetaVal(value);
-        script._rawMeta += header + '\0' + value + '\0';
+        script.icon.setMetaVal(data.value);
+        script._rawMeta += data.keyword + '\0' + data.value + '\0';
       } catch (e) {
         script.parseErrors.push(e.message);
       }
       break;
-    case 'include':
-      script._includes.push(value);
-      break;
+
     case 'match':
       try {
-        var match = new MatchPattern(value);
+        var match = new MatchPattern(data.value);
         script._matches.push(match);
       } catch (e) {
         script.parseErrors.push(
             gStringBundle.GetStringFromName('parse.ignoring-match')
-                .replace('%1', value).replace('%2', e)
+                .replace('%1', data.value).replace('%2', e)
             );
       }
       break;
+
     case 'require':
       try {
-        var reqUri = GM_util.uriFromUrl(value, aUri);
+        var reqUri = GM_util.uriFromUrl(data.value, aUri);
         var scriptRequire = new ScriptRequire(script);
         scriptRequire._downloadURL = reqUri.spec;
         script._requires.push(scriptRequire);
-        script._rawMeta += header + '\0' + value + '\0';
+        script._rawMeta += data.keyword + '\0' + data.value + '\0';
       } catch (e) {
+        dump('require err:'+e+'\n');
         script.parseErrors.push(
             gStringBundle.GetStringFromName('parse.require-failed')
-                .replace('%1', value)
+                .replace('%1', data.value)
             );
       }
       break;
-    case 'resource':
-      var res = value.match(/(\S+)\s+(.*)/);
-      if (res === null) {
-        script.parseErrors.push(
-            gStringBundle.GetStringFromName('parse.resource-syntax')
-                .replace('%1', value)
-            );
-        break;
-      }
-
-      var resName = res[1];
-      if (resourceNames[resName]) {
-        script.parseErrors.push(
-            gStringBundle.GetStringFromName('parse.resource-duplicate')
-                .replace('%1', resName)
-            );
-        break;
-      }
-      resourceNames[resName] = true;
-
-      try {
-        var resUri = GM_util.uriFromUrl(res[2], aUri);
-        var scriptResource = new ScriptResource(script);
-        scriptResource._name = resName;
-        scriptResource._downloadURL = resUri.spec;
-        script._resources.push(scriptResource);
-        script._rawMeta += header + '\0' + resName + '\0' + resUri.spec + '\0';
-      } catch (e) {
-        script.parseErrors.push(
-            gStringBundle.GetStringFromName('parse.resource-failed')
-                .replace('%1', resName).replace('%2', res[2])
-            );
-      }
-      break;
-    case 'run-at':
-      script._runAt = value;
-      break;
     }
   }
 
@@ -173,6 +169,7 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
   return script;
 }
 
+
 function setDefaults(script) {
   if (!script.updateURL && script.downloadURL) {
     script.updateURL = script.downloadURL;
diff --git a/modules/stats.js b/modules/stats.js
index e3dd84e..997d0f6 100644
--- a/modules/stats.js
+++ b/modules/stats.js
@@ -109,18 +109,6 @@ function getStatsObj() {
   for (var i = 0, script = null; script = scripts[i]; i++) {
     var valueStats = GM_ScriptStorage(script).getStats();
 
-    var explicitGrants = [];
-    var imperatives = [];
-    var metaLines = extractMeta(script.textContent).match(gLineSplitRegexp);
-    for (var j = 0, metaLine = null; metaLine = metaLines[j]; j++) {
-      var m = gMetaLineRegexp.exec(metaLine);
-      if (!m) continue;
-      imperatives[imperatives.length] = m[1];
-      if ('grant' == m[1]) {
-        explicitGrants[explicitGrants.length] = m[2];
-      }
-    }
-
     var downloadUri = GM_util.uriFromUrl(script.downloadURL);
     var domain = null;
     try {
@@ -135,10 +123,7 @@ function getStatsObj() {
 
     var scriptStat = {
         'enabled': script.enabled,
-        'explicitGrants': explicitGrants,
         'id': script.id,
-        'imperatives': imperatives,
-        'implicitGrants': script.grants,
         'installScheme': downloadUri.scheme,
         'installDomain': domain,
         'installTime': script.installDate.toISOString(),
diff --git a/modules/util/parseMetaLine.js b/modules/util/parseMetaLine.js
new file mode 100644
index 0000000..121ab32
--- /dev/null
+++ b/modules/util/parseMetaLine.js
@@ -0,0 +1,695 @@
+const EXPORTED_SYMBOLS = ['SyntaxError', 'parseMetaLine'];
+
+/*
+ * Generated by PEG.js 0.8.0.
+ *
+ * http://pegjs.majda.cz/
+ */
+
+function peg$subclass(child, parent) {
+  function ctor() { this.constructor = child; }
+  ctor.prototype = parent.prototype;
+  child.prototype = new ctor();
+}
+
+function SyntaxError(message, expected, found, offset, line, column) {
+  this.message  = message;
+  this.expected = expected;
+  this.found    = found;
+  this.offset   = offset;
+  this.line     = line;
+  this.column   = column;
+
+  this.name     = "SyntaxError";
+}
+
+peg$subclass(SyntaxError, Error);
+
+function parseMetaLine(input) {
+  var options = arguments.length > 1 ? arguments[1] : {},
+
+      peg$FAILED = {},
+
+      peg$startRuleFunctions = { line: peg$parseline },
+      peg$startRuleFunction  = peg$parseline,
+
+      peg$c0 = peg$FAILED,
+      peg$c1 = "// @",
+      peg$c2 = { type: "literal", value: "// @", description: "\"// @\"" },
+      peg$c3 = null,
+      peg$c4 = "\n",
+      peg$c5 = { type: "literal", value: "\n", description: "\"\\n\"" },
+      peg$c6 = function(meta) { return meta; },
+      peg$c7 = [],
+      peg$c8 = /^[ \t\n]/,
+      peg$c9 = { type: "class", value: "[ \\t\\n]", description: "[ \\t\\n]" },
+      peg$c10 = /^[^ \t\n]/,
+      peg$c11 = { type: "class", value: "[^ \\t\\n]", description: "[^ \\t\\n]" },
+      peg$c12 = function(val) { return val.join('');},
+      peg$c13 = /^[^\n]/,
+      peg$c14 = { type: "class", value: "[^\\n]", description: "[^\\n]" },
+      peg$c15 = "downloadURL",
+      peg$c16 = { type: "literal", value: "downloadURL", description: "\"downloadURL\"" },
+      peg$c17 = "exclude",
+      peg$c18 = { type: "literal", value: "exclude", description: "\"exclude\"" },
+      peg$c19 = "grant",
+      peg$c20 = { type: "literal", value: "grant", description: "\"grant\"" },
+      peg$c21 = "icon",
+      peg$c22 = { type: "literal", value: "icon", description: "\"icon\"" },
+      peg$c23 = "include",
+      peg$c24 = { type: "literal", value: "include", description: "\"include\"" },
+      peg$c25 = "installURL",
+      peg$c26 = { type: "literal", value: "installURL", description: "\"installURL\"" },
+      peg$c27 = "match",
+      peg$c28 = { type: "literal", value: "match", description: "\"match\"" },
+      peg$c29 = "namespace",
+      peg$c30 = { type: "literal", value: "namespace", description: "\"namespace\"" },
+      peg$c31 = "require",
+      peg$c32 = { type: "literal", value: "require", description: "\"require\"" },
+      peg$c33 = "run-at",
+      peg$c34 = { type: "literal", value: "run-at", description: "\"run-at\"" },
+      peg$c35 = "updateURL",
+      peg$c36 = { type: "literal", value: "updateURL", description: "\"updateURL\"" },
+      peg$c37 = "version",
+      peg$c38 = { type: "literal", value: "version", description: "\"version\"" },
+      peg$c39 = function(keyword, value) { return {keyword:keyword, value:value}; },
+      peg$c40 = "resource",
+      peg$c41 = { type: "literal", value: "resource", description: "\"resource\"" },
+      peg$c42 = function(keyword, value1, value2) { return {keyword:keyword, value1:value1, value2:value2}; },
+      peg$c43 = "description",
+      peg$c44 = { type: "literal", value: "description", description: "\"description\"" },
+      peg$c45 = "name",
+      peg$c46 = { type: "literal", value: "name", description: "\"name\"" },
+      peg$c47 = ":",
+      peg$c48 = { type: "literal", value: ":", description: "\":\"" },
+      peg$c49 = /^[a-zA-Z\-]/,
+      peg$c50 = { type: "class", value: "[a-zA-Z\\-]", description: "[a-zA-Z\\-]" },
+      peg$c51 = function(keyword, locale, value) { return {keyword:keyword, locale:locale, value:value}; },
+
+      peg$currPos          = 0,
+      peg$reportedPos      = 0,
+      peg$cachedPos        = 0,
+      peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
+      peg$maxFailPos       = 0,
+      peg$maxFailExpected  = [],
+      peg$silentFails      = 0,
+
+      peg$result;
+
+  if ("startRule" in options) {
+    if (!(options.startRule in peg$startRuleFunctions)) {
+      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
+    }
+
+    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+  }
+
+  function text() {
+    return input.substring(peg$reportedPos, peg$currPos);
+  }
+
+  function offset() {
+    return peg$reportedPos;
+  }
+
+  function line() {
+    return peg$computePosDetails(peg$reportedPos).line;
+  }
+
+  function column() {
+    return peg$computePosDetails(peg$reportedPos).column;
+  }
+
+  function expected(description) {
+    throw peg$buildException(
+      null,
+      [{ type: "other", description: description }],
+      peg$reportedPos
+    );
+  }
+
+  function error(message) {
+    throw peg$buildException(message, null, peg$reportedPos);
+  }
+
+  function peg$computePosDetails(pos) {
+    function advance(details, startPos, endPos) {
+      var p, ch;
+
+      for (p = startPos; p < endPos; p++) {
+        ch = input.charAt(p);
+        if (ch === "\n") {
+          if (!details.seenCR) { details.line++; }
+          details.column = 1;
+          details.seenCR = false;
+        } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+          details.line++;
+          details.column = 1;
+          details.seenCR = true;
+        } else {
+          details.column++;
+          details.seenCR = false;
+        }
+      }
+    }
+
+    if (peg$cachedPos !== pos) {
+      if (peg$cachedPos > pos) {
+        peg$cachedPos = 0;
+        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
+      }
+      advance(peg$cachedPosDetails, peg$cachedPos, pos);
+      peg$cachedPos = pos;
+    }
+
+    return peg$cachedPosDetails;
+  }
+
+  function peg$fail(expected) {
+    if (peg$currPos < peg$maxFailPos) { return; }
+
+    if (peg$currPos > peg$maxFailPos) {
+      peg$maxFailPos = peg$currPos;
+      peg$maxFailExpected = [];
+    }
+
+    peg$maxFailExpected.push(expected);
+  }
+
+  function peg$buildException(message, expected, pos) {
+    function cleanupExpected(expected) {
+      var i = 1;
+
+      expected.sort(function(a, b) {
+        if (a.description < b.description) {
+          return -1;
+        } else if (a.description > b.description) {
+          return 1;
+        } else {
+          return 0;
+        }
+      });
+
+      while (i < expected.length) {
+        if (expected[i - 1] === expected[i]) {
+          expected.splice(i, 1);
+        } else {
+          i++;
+        }
+      }
+    }
+
+    function buildMessage(expected, found) {
+      function stringEscape(s) {
+        function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
+
+        return s
+          .replace(/\\/g,   '\\\\')
+          .replace(/"/g,    '\\"')
+          .replace(/\x08/g, '\\b')
+          .replace(/\t/g,   '\\t')
+          .replace(/\n/g,   '\\n')
+          .replace(/\f/g,   '\\f')
+          .replace(/\r/g,   '\\r')
+          .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
+          .replace(/[\x10-\x1F\x80-\xFF]/g,    function(ch) { return '\\x'  + hex(ch); })
+          .replace(/[\u0180-\u0FFF]/g,         function(ch) { return '\\u0' + hex(ch); })
+          .replace(/[\u1080-\uFFFF]/g,         function(ch) { return '\\u'  + hex(ch); });
+      }
+
+      var expectedDescs = new Array(expected.length),
+          expectedDesc, foundDesc, i;
+
+      for (i = 0; i < expected.length; i++) {
+        expectedDescs[i] = expected[i].description;
+      }
+
+      expectedDesc = expected.length > 1
+        ? expectedDescs.slice(0, -1).join(", ")
+            + " or "
+            + expectedDescs[expected.length - 1]
+        : expectedDescs[0];
+
+      foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
+
+      return "Expected " + expectedDesc + " but " + foundDesc + " found.";
+    }
+
+    var posDetails = peg$computePosDetails(pos),
+        found      = pos < input.length ? input.charAt(pos) : null;
+
+    if (expected !== null) {
+      cleanupExpected(expected);
+    }
+
+    return new SyntaxError(
+      message !== null ? message : buildMessage(expected, found),
+      expected,
+      found,
+      pos,
+      posDetails.line,
+      posDetails.column
+    );
+  }
+
+  function peg$parseline() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4) === peg$c1) {
+      s1 = peg$c1;
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c2); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsekeyword1();
+      if (s2 === peg$FAILED) {
+        s2 = peg$parsekeyword2();
+        if (s2 === peg$FAILED) {
+          s2 = peg$parsekeywordLocale();
+        }
+      }
+      if (s2 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 10) {
+          s3 = peg$c4;
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c5); }
+        }
+        if (s3 === peg$FAILED) {
+          s3 = peg$c3;
+        }
+        if (s3 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c6(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$c0;
+    }
+
+    return s0;
+  }
+
+  function peg$parsewhitespace() {
+    var s0, s1;
+
+    s0 = [];
+    if (peg$c8.test(input.charAt(peg$currPos))) {
+      s1 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c9); }
+    }
+    if (s1 !== peg$FAILED) {
+      while (s1 !== peg$FAILED) {
+        s0.push(s1);
+        if (peg$c8.test(input.charAt(peg$currPos))) {
+          s1 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s1 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c9); }
+        }
+      }
+    } else {
+      s0 = peg$c0;
+    }
+
+    return s0;
+  }
+
+  function peg$parsenon_whitespace() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = [];
+    if (peg$c10.test(input.charAt(peg$currPos))) {
+      s2 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s2 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c11); }
+    }
+    if (s2 !== peg$FAILED) {
+      while (s2 !== peg$FAILED) {
+        s1.push(s2);
+        if (peg$c10.test(input.charAt(peg$currPos))) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c11); }
+        }
+      }
+    } else {
+      s1 = peg$c0;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$reportedPos = s0;
+      s1 = peg$c12(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsenon_newline() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = [];
+    if (peg$c13.test(input.charAt(peg$currPos))) {
+      s2 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s2 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c14); }
+    }
+    if (s2 !== peg$FAILED) {
+      while (s2 !== peg$FAILED) {
+        s1.push(s2);
+        if (peg$c13.test(input.charAt(peg$currPos))) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c14); }
+        }
+      }
+    } else {
+      s1 = peg$c0;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$reportedPos = s0;
+      s1 = peg$c12(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsekeyword1() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 11) === peg$c15) {
+      s1 = peg$c15;
+      peg$currPos += 11;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c16); }
+    }
+    if (s1 === peg$FAILED) {
+      if (input.substr(peg$currPos, 7) === peg$c17) {
+        s1 = peg$c17;
+        peg$currPos += 7;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c18); }
+      }
+      if (s1 === peg$FAILED) {
+        if (input.substr(peg$currPos, 5) === peg$c19) {
+          s1 = peg$c19;
+          peg$currPos += 5;
+        } else {
+          s1 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c20); }
+        }
+        if (s1 === peg$FAILED) {
+          if (input.substr(peg$currPos, 4) === peg$c21) {
+            s1 = peg$c21;
+            peg$currPos += 4;
+          } else {
+            s1 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c22); }
+          }
+          if (s1 === peg$FAILED) {
+            if (input.substr(peg$currPos, 7) === peg$c23) {
+              s1 = peg$c23;
+              peg$currPos += 7;
+            } else {
+              s1 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c24); }
+            }
+            if (s1 === peg$FAILED) {
+              if (input.substr(peg$currPos, 10) === peg$c25) {
+                s1 = peg$c25;
+                peg$currPos += 10;
+              } else {
+                s1 = peg$FAILED;
+                if (peg$silentFails === 0) { peg$fail(peg$c26); }
+              }
+              if (s1 === peg$FAILED) {
+                if (input.substr(peg$currPos, 5) === peg$c27) {
+                  s1 = peg$c27;
+                  peg$currPos += 5;
+                } else {
+                  s1 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$c28); }
+                }
+                if (s1 === peg$FAILED) {
+                  if (input.substr(peg$currPos, 9) === peg$c29) {
+                    s1 = peg$c29;
+                    peg$currPos += 9;
+                  } else {
+                    s1 = peg$FAILED;
+                    if (peg$silentFails === 0) { peg$fail(peg$c30); }
+                  }
+                  if (s1 === peg$FAILED) {
+                    if (input.substr(peg$currPos, 7) === peg$c31) {
+                      s1 = peg$c31;
+                      peg$currPos += 7;
+                    } else {
+                      s1 = peg$FAILED;
+                      if (peg$silentFails === 0) { peg$fail(peg$c32); }
+                    }
+                    if (s1 === peg$FAILED) {
+                      if (input.substr(peg$currPos, 6) === peg$c33) {
+                        s1 = peg$c33;
+                        peg$currPos += 6;
+                      } else {
+                        s1 = peg$FAILED;
+                        if (peg$silentFails === 0) { peg$fail(peg$c34); }
+                      }
+                      if (s1 === peg$FAILED) {
+                        if (input.substr(peg$currPos, 9) === peg$c35) {
+                          s1 = peg$c35;
+                          peg$currPos += 9;
+                        } else {
+                          s1 = peg$FAILED;
+                          if (peg$silentFails === 0) { peg$fail(peg$c36); }
+                        }
+                        if (s1 === peg$FAILED) {
+                          if (input.substr(peg$currPos, 7) === peg$c37) {
+                            s1 = peg$c37;
+                            peg$currPos += 7;
+                          } else {
+                            s1 = peg$FAILED;
+                            if (peg$silentFails === 0) { peg$fail(peg$c38); }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsewhitespace();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parsenon_newline();
+        if (s3 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c39(s1, s3);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$c0;
+    }
+
+    return s0;
+  }
+
+  function peg$parsekeyword2() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 8) === peg$c40) {
+      s1 = peg$c40;
+      peg$currPos += 8;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c41); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsewhitespace();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parsenon_whitespace();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parsewhitespace();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parsenon_newline();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c42(s1, s3, s5);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$c0;
+    }
+
+    return s0;
+  }
+
+  function peg$parsekeywordLocale() {
+    var s0, s1, s2, s3, s4, s5, s6;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 11) === peg$c43) {
+      s1 = peg$c43;
+      peg$currPos += 11;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$c44); }
+    }
+    if (s1 === peg$FAILED) {
+      if (input.substr(peg$currPos, 4) === peg$c45) {
+        s1 = peg$c45;
+        peg$currPos += 4;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c46); }
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      s3 = peg$currPos;
+      if (input.charCodeAt(peg$currPos) === 58) {
+        s4 = peg$c47;
+        peg$currPos++;
+      } else {
+        s4 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c48); }
+      }
+      if (s4 !== peg$FAILED) {
+        s5 = [];
+        if (peg$c49.test(input.charAt(peg$currPos))) {
+          s6 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s6 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c50); }
+        }
+        if (s6 !== peg$FAILED) {
+          while (s6 !== peg$FAILED) {
+            s5.push(s6);
+            if (peg$c49.test(input.charAt(peg$currPos))) {
+              s6 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s6 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c50); }
+            }
+          }
+        } else {
+          s5 = peg$c0;
+        }
+        if (s5 !== peg$FAILED) {
+          s4 = [s4, s5];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$c0;
+      }
+      if (s3 === peg$FAILED) {
+        s3 = peg$c3;
+      }
+      if (s3 !== peg$FAILED) {
+        s3 = input.substring(s2, peg$currPos);
+      }
+      s2 = s3;
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parsewhitespace();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parsenon_newline();
+          if (s4 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c51(s1, s2, s4);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$c0;
+    }
+
+    return s0;
+  }
+
+  peg$result = peg$startRuleFunction();
+
+  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+    return peg$result;
+  } else {
+    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
+      peg$fail({ type: "end", description: "end of input" });
+    }
+
+    throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
+  }
+}
diff --git a/peg.txt b/peg.txt
new file mode 100644
index 0000000..7dc4fa5
--- /dev/null
+++ b/peg.txt
@@ -0,0 +1,85 @@
+// PEG grammar for parsing user script metadata
+// http://pegjs.majda.cz/online
+
+/*
+Test value:
+
+// ==UserScript==
+// @name      Metadata Test
+// @name:de   Auf deutsch bitte!
+// @namespace test
+// @description Test value including all metas.
+// @version   1.2.3
+// @icon      http://example.com/favicon.ico
+// @include   http://example.com/*
+// @match     http://example.net/*
+// @exclude   http://example.com/foo
+// @run-at    document-start
+// @grant     none
+// @downloadURL http://example.org/foo.user.js
+// @updateURL http://example.org/foo.meta.js
+// @require   http://example.net/library.js
+// @resource  css http://example.net/library.css
+// ==/UserScript==
+
+*/
+
+/*
+// Uncomment to parse an entire metadata block.
+// I.E for testing/development.
+meta =
+  "// ==UserScript==\n"
+  lines:line*
+  "// ==/UserScript==" ("\n"?)
+  { return lines; }
+*/
+
+line =
+    "// @"
+    meta:(keyword1 / keyword2 / keywordLocale)
+    "\n"?
+    { return meta; }
+
+whitespace = [ \t\n]+
+non_whitespace =
+    val:[^ \t\n]+ { return val.join('');}
+non_newline =
+    val:[^\n]+ { return val.join('');}
+
+keyword1 =
+    keyword:(
+        "downloadURL" /
+        "exclude" /
+        "grant" /
+        "icon" /
+        "include" /
+        "installURL" /
+        "match" /
+        "namespace" /
+        "require" /
+        "run-at" /
+        "updateURL" /
+        "version"
+        )
+    whitespace
+    value:non_newline
+    { return {keyword:keyword, value:value}; }
+
+keyword2 =
+    keyword:("resource")
+    whitespace
+    value1:non_whitespace
+    whitespace
+    value2:non_newline
+    { return {keyword:keyword, value1:value1, value2:value2}; }
+
+keywordLocale
+  = keyword:(
+        "description" /
+        "name"
+        )
+    locale:$(":" [a-zA-Z-]+)?
+    whitespace
+    value:non_newline
+    { return {keyword:keyword, locale:locale, value:value}; }
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/greasemonkey.git



More information about the Pkg-mozext-commits mailing list