Bug 1280471 - Turn on highlight for WebAssembly text format. r?jlongster draft
authorYury Delendik <ydelendik@mozilla.com>
Thu, 16 Jun 2016 16:02:49 +0100
changeset 379656 0aa2db8a404e426d2e3654d35fccf1d1a2ef233e
parent 378181 14c5bf11d37b9e92d27f7089d9392de2ac339bb3
child 523538 9d866ded8e0da322e00575a3b19aae20643d037c
push id21018
push userydelendik@mozilla.com
push dateThu, 16 Jun 2016 15:04:01 +0000
reviewersjlongster
bugs1280471
milestone50.0a1
Bug 1280471 - Turn on highlight for WebAssembly text format. r?jlongster MozReview-Commit-ID: GIeIqr3m8WX
devtools/client/debugger/debugger-view.js
devtools/client/jar.mn
devtools/client/sourceeditor/codemirror/mode/wasm.js
devtools/client/sourceeditor/editor.js
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -448,16 +448,20 @@ var DebuggerView = {
    *        The source text content.
    */
   _setEditorMode: function (aUrl, aContentType = "", aTextContent = "") {
     // Use JS mode for files with .js and .jsm extensions.
     if (SourceUtils.isJavaScript(aUrl, aContentType)) {
       return void this.editor.setMode(Editor.modes.js);
     }
 
+    if (aContentType === "text/wasm") {
+      return void this.editor.setMode(Editor.modes.wasm);
+    }
+
     // Use HTML mode for files in which the first non whitespace character is
     // &lt;, regardless of extension.
     if (aTextContent.match(/^\s*</)) {
       return void this.editor.setMode(Editor.modes.html);
     }
 
     // Unknown language, use text.
     this.editor.setMode(Editor.modes.text);
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -50,16 +50,17 @@ devtools.jar:
     content/sourceeditor/codemirror/addon/tern/tern.js (sourceeditor/codemirror/addon/tern/tern.js)
     content/sourceeditor/codemirror/lib/codemirror.js (sourceeditor/codemirror/lib/codemirror.js)
     content/sourceeditor/codemirror/lib/codemirror.css (sourceeditor/codemirror/lib/codemirror.css)
     content/sourceeditor/codemirror/mode/javascript.js (sourceeditor/codemirror/mode/javascript.js)
     content/sourceeditor/codemirror/mode/xml.js (sourceeditor/codemirror/mode/xml.js)
     content/sourceeditor/codemirror/mode/css.js (sourceeditor/codemirror/mode/css.js)
     content/sourceeditor/codemirror/mode/htmlmixed.js (sourceeditor/codemirror/mode/htmlmixed.js)
     content/sourceeditor/codemirror/mode/clike.js (sourceeditor/codemirror/mode/clike.js)
+    content/sourceeditor/codemirror/mode/wasm.js (sourceeditor/codemirror/mode/wasm.js)
     content/sourceeditor/codemirror/keymap/emacs.js (sourceeditor/codemirror/keymap/emacs.js)
     content/sourceeditor/codemirror/keymap/sublime.js (sourceeditor/codemirror/keymap/sublime.js)
     content/sourceeditor/codemirror/keymap/vim.js (sourceeditor/codemirror/keymap/vim.js)
     content/sourceeditor/codemirror/mozilla.css (sourceeditor/codemirror/mozilla.css)
     content/debugger/debugger.xul (debugger/debugger.xul)
     content/debugger/debugger.css (debugger/debugger.css)
     content/debugger/debugger-controller.js (debugger/debugger-controller.js)
     content/debugger/debugger-view.js (debugger/debugger-view.js)
new file mode 100644
--- /dev/null
+++ b/devtools/client/sourceeditor/codemirror/mode/wasm.js
@@ -0,0 +1,203 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// WebAssembly experimental syntax highlight add-on for CodeMirror.
+
+(function (root, factory) {
+  if (typeof define === 'function' && define.amd) {
+    define(["../../lib/codemirror"], factory);
+  } else if (typeof exports !== 'undefined') {
+    factory(require("../../lib/codemirror"));
+  } else {
+    factory(root.CodeMirror);
+  }
+}(this, function (CodeMirror) {
+"use strict";
+
+var isWordChar = /[\w\$_\.\\\/@]/;
+
+function createLookupTable(list) {
+  var obj = Object.create(null);
+  list.forEach(function (key) {
+    obj[key] = true;
+  });
+  return obj;
+}
+
+CodeMirror.defineMode("wasm", function() {
+  var keywords = createLookupTable([
+    "function", "import", "export", "table", "memory", "segment", "as", "type",
+    "of", "from", "typeof", "br", "br_if", "loop", "br_table", "if", "else",
+    "call", "call_import", "call_indirect", "nop", "unreachable", "var",
+    "align", "select", "return"]);
+  var builtins = createLookupTable([
+    "i32:8", "i32:8u", "i32:8s", "i32:16", "i32:16u", "i32:16s",
+    "i64:8", "i64:8u", "i64:8s", "i64:16", "i64:16u", "i64:16s",
+    "i64:32", "i64:32u", "i64:32s",
+    "i32.add", "i32.sub", "i32.mul", "i32.div_s", "i32.div_u",
+    "i32.rem_s", "i32.rem_u", "i32.and", "i32.or", "i32.xor",
+    "i32.shl", "i32.shr_u", "i32.shr_s", "i32.rotr", "i32.rotl",
+    "i32.eq", "i32.ne", "i32.lt_s", "i32.le_s", "i32.lt_u",
+    "i32.le_u", "i32.gt_s", "i32.ge_s", "i32.gt_u", "i32.ge_u",
+    "i32.clz", "i32.ctz", "i32.popcnt", "i32.eqz", "i64.add",
+    "i64.sub", "i64.mul", "i64.div_s", "i64.div_u", "i64.rem_s",
+    "i64.rem_u", "i64.and", "i64.or", "i64.xor", "i64.shl",
+    "i64.shr_u", "i64.shr_s", "i64.rotr", "i64.rotl", "i64.eq",
+    "i64.ne", "i64.lt_s", "i64.le_s", "i64.lt_u", "i64.le_u",
+    "i64.gt_s", "i64.ge_s", "i64.gt_u", "i64.ge_u", "i64.clz",
+    "i64.ctz", "i64.popcnt", "i64.eqz", "f32.add", "f32.sub",
+    "f32.mul", "f32.div", "f32.min", "f32.max", "f32.abs",
+    "f32.neg", "f32.copysign", "f32.ceil", "f32.floor", "f32.trunc",
+    "f32.nearest", "f32.sqrt", "f32.eq", "f32.ne", "f32.lt",
+    "f32.le", "f32.gt", "f32.ge", "f64.add", "f64.sub", "f64.mul",
+    "f64.div", "f64.min", "f64.max", "f64.abs", "f64.neg",
+    "f64.copysign", "f64.ceil", "f64.floor", "f64.trunc", "f64.nearest",
+    "f64.sqrt", "f64.eq", "f64.ne", "f64.lt", "f64.le", "f64.gt",
+    "f64.ge", "i32.trunc_s/f32", "i32.trunc_s/f64", "i32.trunc_u/f32",
+    "i32.trunc_u/f64", "i32.wrap/i64", "i64.trunc_s/f32",
+    "i64.trunc_s/f64", "i64.trunc_u/f32", "i64.trunc_u/f64",
+    "i64.extend_s/i32", "i64.extend_u/i32", "f32.convert_s/i32",
+    "f32.convert_u/i32", "f32.convert_s/i64", "f32.convert_u/i64",
+    "f32.demote/f64", "f32.reinterpret/i32", "f64.convert_s/i32",
+    "f64.convert_u/i32", "f64.convert_s/i64", "f64.convert_u/i64",
+    "f64.promote/f32", "f64.reinterpret/i64", "i32.reinterpret/f32",
+    "i64.reinterpret/f64"]);
+  var dataTypes = createLookupTable(["i32", "i64", "f32", "f64"]);
+  var isUnaryOperator = /[\-!]/;
+  var operators = createLookupTable([
+    "+", "-", "*", "/", "/s", "/u", "%", "%s", "%u",
+    "<<", ">>u", ">>s", ">=", "<=", "==", "!=",
+    "<s", "<u", "<=s", "<=u", ">=s", ">=u", ">s", ">u",
+    "<", ">", "=", "&", "|", "^", "!"]);
+
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (ch === "$") {
+      stream.eatWhile(isWordChar);
+      return "variable";
+    }
+    if (ch === "@") {
+      stream.eatWhile(isWordChar);
+      return "meta";
+    }
+    if (ch === '"') {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    }
+    if (ch == "/") {
+      if (stream.eat("*")) {
+        state.tokenize = tokenComment;
+        return tokenComment(stream, state);
+      } else if (stream.eat("/")) {
+        stream.skipToEnd();
+        return "comment";
+      }
+    }
+    if (/\d/.test(ch) ||
+        ((ch === "-" || ch === "+") && /\d/.test(stream.peek()))) {
+      stream.eatWhile(/[\w\._\-+]/);
+      return "number";
+    }
+    if (/[\[\]\(\)\{\},:]/.test(ch)) {
+      return null;
+    }
+    if (isUnaryOperator.test(ch)) {
+      return "operator";
+    }
+    stream.eatWhile(isWordChar);
+    var word = stream.current();
+
+    if (word in operators) {
+      return "operator";
+    }
+    if (word in keywords){
+      return "keyword";
+    }
+    if (word in dataTypes) {
+      if (!stream.eat(":")) {
+        return "builtin";
+      }
+      stream.eatWhile(isWordChar);
+      word = stream.current();
+      // fall thru for "builtin" check
+    }
+    if (word in builtins) {
+      return "builtin";
+    }
+
+    if (word === "Temporary") {
+      // Nightly has header with some text graphics -- skipping it.
+      state.tokenize = tokenTemporary;
+      return state.tokenize(stream, state);
+    }
+    return null;
+  }
+
+  function tokenComment(stream, state) {
+    state.commentDepth = 1;
+    var next;
+    while ((next = stream.next()) != null) {
+      if (next === "*" && stream.eat("/")) {
+        if (--state.commentDepth === 0) {
+          state.tokenize = null;
+          return "comment";
+        }
+      }
+      if (next === "/" && stream.eat("*")) {
+        // Nested comment
+        state.commentDepth++;
+      }
+    }
+    return "comment";
+  }
+
+  function tokenTemporary(stream, state) {
+    var next, endState = state.commentState;
+    // Skipping until "text support (Work In Progress):" is found.
+    while ((next = stream.next()) != null) {
+      if (endState === 0 && next === "t") {
+        endState = 1;
+      } else if (endState === 1 && next === ":") {
+        state.tokenize = null;
+        state.commentState = 0;
+        endState = 2;
+        return "comment";
+      }
+    }
+    state.commentState = endState;
+    return "comment";
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, next, end = false;
+      while ((next = stream.next()) != null) {
+        if (next == quote && !escaped) {
+          state.tokenize = null;
+          return "string";
+        }
+        escaped = !escaped && next === "\\";
+      }
+      return "string";
+    };
+  }
+
+  return {
+    startState: function() {
+      return {tokenize: null, commentState: 0, commentDepth: 0};
+    },
+
+    token: function(stream, state) {
+      if (stream.eatSpace()) return null;
+      var style = (state.tokenize || tokenBase)(stream, state);
+      return style;
+    }
+  };
+});
+
+CodeMirror.registerHelper("wordChars", "wasm", isWordChar);
+
+CodeMirror.defineMIME("text/wasm", "wasm");
+
+}));
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -60,16 +60,17 @@ const CM_SCRIPTS = [
   "chrome://devtools/content/sourceeditor/codemirror/addon/edit/matchbrackets.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/edit/closebrackets.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/comment/comment.js",
   "chrome://devtools/content/sourceeditor/codemirror/mode/javascript.js",
   "chrome://devtools/content/sourceeditor/codemirror/mode/xml.js",
   "chrome://devtools/content/sourceeditor/codemirror/mode/css.js",
   "chrome://devtools/content/sourceeditor/codemirror/mode/htmlmixed.js",
   "chrome://devtools/content/sourceeditor/codemirror/mode/clike.js",
+  "chrome://devtools/content/sourceeditor/codemirror/mode/wasm.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/selection/active-line.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/edit/trailingspace.js",
   "chrome://devtools/content/sourceeditor/codemirror/keymap/emacs.js",
   "chrome://devtools/content/sourceeditor/codemirror/keymap/vim.js",
   "chrome://devtools/content/sourceeditor/codemirror/keymap/sublime.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/fold/foldcode.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/fold/brace-fold.js",
   "chrome://devtools/content/sourceeditor/codemirror/addon/fold/comment-fold.js",
@@ -113,16 +114,17 @@ const CM_MAPPING = [
 const { cssProperties, cssValues, cssColors } = getCSSKeywords();
 
 const editors = new WeakMap();
 
 Editor.modes = {
   text: { name: "text" },
   html: { name: "htmlmixed" },
   css: { name: "css" },
+  wasm: { name: "wasm" },
   js: { name: "javascript" },
   vs: { name: "x-shader/x-vertex" },
   fs: { name: "x-shader/x-fragment" }
 };
 
 /**
  * A very thin wrapper around CodeMirror. Provides a number
  * of helper methods to make our use of CodeMirror easier and