// CodeMirror, copyright © by Marijn Haverbeke and others // Distributed under an MIT license: codemirror.net/LICENSE

(function(mod) {

if (typeof exports == "object" && typeof module == "object") // CommonJS
  mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
  define(["../../lib/codemirror"], mod);
else // Plain browser env
  mod(CodeMirror);

})(function(CodeMirror) { “use strict”;

CodeMirror.defineMode(“gas”, function(_config, parserConfig) {

'use strict';

// If an architecture is specified, its initialization function may
// populate this array with custom parsing functions which will be
// tried in the event that the standard functions do not find a match.
var custom = [];

// The symbol used to start a line comment changes based on the target
// architecture.
// If no architecture is pased in "parserConfig" then only multiline
// comments will have syntax support.
var lineCommentStartSymbol = "";

// These directives are architecture independent.
// Machine specific directives should go in their respective
// architecture initialization function.
// Reference:
// http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops
var directives = {
  ".abort" : "builtin",
  ".align" : "builtin",
  ".altmacro" : "builtin",
  ".ascii" : "builtin",
  ".asciz" : "builtin",
  ".balign" : "builtin",
  ".balignw" : "builtin",
  ".balignl" : "builtin",
  ".bundle_align_mode" : "builtin",
  ".bundle_lock" : "builtin",
  ".bundle_unlock" : "builtin",
  ".byte" : "builtin",
  ".cfi_startproc" : "builtin",
  ".comm" : "builtin",
  ".data" : "builtin",
  ".def" : "builtin",
  ".desc" : "builtin",
  ".dim" : "builtin",
  ".double" : "builtin",
  ".eject" : "builtin",
  ".else" : "builtin",
  ".elseif" : "builtin",
  ".end" : "builtin",
  ".endef" : "builtin",
  ".endfunc" : "builtin",
  ".endif" : "builtin",
  ".equ" : "builtin",
  ".equiv" : "builtin",
  ".eqv" : "builtin",
  ".err" : "builtin",
  ".error" : "builtin",
  ".exitm" : "builtin",
  ".extern" : "builtin",
  ".fail" : "builtin",
  ".file" : "builtin",
  ".fill" : "builtin",
  ".float" : "builtin",
  ".func" : "builtin",
  ".global" : "builtin",
  ".gnu_attribute" : "builtin",
  ".hidden" : "builtin",
  ".hword" : "builtin",
  ".ident" : "builtin",
  ".if" : "builtin",
  ".incbin" : "builtin",
  ".include" : "builtin",
  ".int" : "builtin",
  ".internal" : "builtin",
  ".irp" : "builtin",
  ".irpc" : "builtin",
  ".lcomm" : "builtin",
  ".lflags" : "builtin",
  ".line" : "builtin",
  ".linkonce" : "builtin",
  ".list" : "builtin",
  ".ln" : "builtin",
  ".loc" : "builtin",
  ".loc_mark_labels" : "builtin",
  ".local" : "builtin",
  ".long" : "builtin",
  ".macro" : "builtin",
  ".mri" : "builtin",
  ".noaltmacro" : "builtin",
  ".nolist" : "builtin",
  ".octa" : "builtin",
  ".offset" : "builtin",
  ".org" : "builtin",
  ".p2align" : "builtin",
  ".popsection" : "builtin",
  ".previous" : "builtin",
  ".print" : "builtin",
  ".protected" : "builtin",
  ".psize" : "builtin",
  ".purgem" : "builtin",
  ".pushsection" : "builtin",
  ".quad" : "builtin",
  ".reloc" : "builtin",
  ".rept" : "builtin",
  ".sbttl" : "builtin",
  ".scl" : "builtin",
  ".section" : "builtin",
  ".set" : "builtin",
  ".short" : "builtin",
  ".single" : "builtin",
  ".size" : "builtin",
  ".skip" : "builtin",
  ".sleb128" : "builtin",
  ".space" : "builtin",
  ".stab" : "builtin",
  ".string" : "builtin",
  ".struct" : "builtin",
  ".subsection" : "builtin",
  ".symver" : "builtin",
  ".tag" : "builtin",
  ".text" : "builtin",
  ".title" : "builtin",
  ".type" : "builtin",
  ".uleb128" : "builtin",
  ".val" : "builtin",
  ".version" : "builtin",
  ".vtable_entry" : "builtin",
  ".vtable_inherit" : "builtin",
  ".warning" : "builtin",
  ".weak" : "builtin",
  ".weakref" : "builtin",
  ".word" : "builtin"
};

var registers = {};

function x86(_parserConfig) {
  lineCommentStartSymbol = "#";

  registers.ax  = "variable";
  registers.eax = "variable-2";
  registers.rax = "variable-3";

  registers.bx  = "variable";
  registers.ebx = "variable-2";
  registers.rbx = "variable-3";

  registers.cx  = "variable";
  registers.ecx = "variable-2";
  registers.rcx = "variable-3";

  registers.dx  = "variable";
  registers.edx = "variable-2";
  registers.rdx = "variable-3";

  registers.si  = "variable";
  registers.esi = "variable-2";
  registers.rsi = "variable-3";

  registers.di  = "variable";
  registers.edi = "variable-2";
  registers.rdi = "variable-3";

  registers.sp  = "variable";
  registers.esp = "variable-2";
  registers.rsp = "variable-3";

  registers.bp  = "variable";
  registers.ebp = "variable-2";
  registers.rbp = "variable-3";

  registers.ip  = "variable";
  registers.eip = "variable-2";
  registers.rip = "variable-3";

  registers.cs  = "keyword";
  registers.ds  = "keyword";
  registers.ss  = "keyword";
  registers.es  = "keyword";
  registers.fs  = "keyword";
  registers.gs  = "keyword";
}

function armv6(_parserConfig) {
  // Reference:
  // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf
  // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf
  lineCommentStartSymbol = "@";
  directives.syntax = "builtin";

  registers.r0  = "variable";
  registers.r1  = "variable";
  registers.r2  = "variable";
  registers.r3  = "variable";
  registers.r4  = "variable";
  registers.r5  = "variable";
  registers.r6  = "variable";
  registers.r7  = "variable";
  registers.r8  = "variable";
  registers.r9  = "variable";
  registers.r10 = "variable";
  registers.r11 = "variable";
  registers.r12 = "variable";

  registers.sp  = "variable-2";
  registers.lr  = "variable-2";
  registers.pc  = "variable-2";
  registers.r13 = registers.sp;
  registers.r14 = registers.lr;
  registers.r15 = registers.pc;

  custom.push(function(ch, stream) {
    if (ch === '#') {
      stream.eatWhile(/\w/);
      return "number";
    }
  });
}

var arch = (parserConfig.architecture || "x86").toLowerCase();
if (arch === "x86") {
  x86(parserConfig);
} else if (arch === "arm" || arch === "armv6") {
  armv6(parserConfig);
}

function nextUntilUnescaped(stream, end) {
  var escaped = false, next;
  while ((next = stream.next()) != null) {
    if (next === end && !escaped) {
      return false;
    }
    escaped = !escaped && next === "\\";
  }
  return escaped;
}

function clikeComment(stream, state) {
  var maybeEnd = false, ch;
  while ((ch = stream.next()) != null) {
    if (ch === "/" && maybeEnd) {
      state.tokenize = null;
      break;
    }
    maybeEnd = (ch === "*");
  }
  return "comment";
}

return {
  startState: function() {
    return {
      tokenize: null
    };
  },

  token: function(stream, state) {
    if (state.tokenize) {
      return state.tokenize(stream, state);
    }

    if (stream.eatSpace()) {
      return null;
    }

    var style, cur, ch = stream.next();

    if (ch === "/") {
      if (stream.eat("*")) {
        state.tokenize = clikeComment;
        return clikeComment(stream, state);
      }
    }

    if (ch === lineCommentStartSymbol) {
      stream.skipToEnd();
      return "comment";
    }

    if (ch === '"') {
      nextUntilUnescaped(stream, '"');
      return "string";
    }

    if (ch === '.') {
      stream.eatWhile(/\w/);
      cur = stream.current().toLowerCase();
      style = directives[cur];
      return style || null;
    }

    if (ch === '=') {
      stream.eatWhile(/\w/);
      return "tag";
    }

    if (ch === '{') {
      return "braket";
    }

    if (ch === '}') {
      return "braket";
    }

    if (/\d/.test(ch)) {
      if (ch === "0" && stream.eat("x")) {
        stream.eatWhile(/[0-9a-fA-F]/);
        return "number";
      }
      stream.eatWhile(/\d/);
      return "number";
    }

    if (/\w/.test(ch)) {
      stream.eatWhile(/\w/);
      if (stream.eat(":")) {
        return 'tag';
      }
      cur = stream.current().toLowerCase();
      style = registers[cur];
      return style || null;
    }

    for (var i = 0; i < custom.length; i++) {
      style = custom[i](ch, stream, state);
      if (style) {
        return style;
      }
    }
  },

  lineComment: lineCommentStartSymbol,
  blockCommentStart: "/*",
  blockCommentEnd: "*/"
};

});

});