text: /* ***** BEGIN LICENSE BLOCK *****
   * Distributed under the BSD license:
   *
   * Copyright (c) 2010, Ajax.org B.V.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *     * Redistributions of source code must retain the above copyright
   *       notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above copyright
   *       notice, this list of conditions and the following disclaimer in the
   *       documentation and/or other materials provided with the distribution.
   *     * Neither the name of Ajax.org B.V. nor the
   *       names of its contributors may be used to endorse or promote products
   *       derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * ***** END LICENSE BLOCK ***** */
  
  define(function (require, exports, module) {
      "use strict";
  
      var oop = require("../lib/oop");
      var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules;
      var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
  
      var SJSHighlightRules = function () {
          var parent = new JavaScriptHighlightRules({noES6: true});
          var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex
              "u[0-9a-fA-F]{4}|" + // unicode
              "[0-2][0-7]{0,2}|" + // oct
              "3[0-6][0-7]?|" + // oct
              "37[0-7]?|" + // oct
              "[4-7][0-7]?|" + //oct
              ".)";
  
          var contextAware = function (f) {
              f.isContextAware = true;
              return f;
          };
  
          var ctxBegin = function (opts) {
              return {
                  token: opts.token,
                  regex: opts.regex,
                  next: contextAware(function (currentState, stack) {
                      if (stack.length === 0)
                          stack.unshift(currentState);
                      stack.unshift(opts.next);
                      return opts.next;
                  })
              };
          };
  
          var ctxEnd = function (opts) {
              return {
                  token: opts.token,
                  regex: opts.regex,
                  next: contextAware(function (currentState, stack) {
                      stack.shift();
                      return stack[0] || "start";
                  })
              };
          };
  
          this.$rules = parent.$rules;
          this.$rules.no_regex = [
              {
                  token: "keyword",
                  regex: "(waitfor|or|and|collapse|spawn|retract)\\b"
              },
              {
                  token: "keyword.operator",
                  regex: "(->|=>|\\.\\.)"
              },
              {
                  token: "variable.language",
                  regex: "(hold|default)\\b"
              },
              ctxBegin({
                  token: "string",
                  regex: "`",
                  next: "bstring"
              }),
              ctxBegin({
                  token: "string",
                  regex: '"',
                  next: "qqstring"
              }),
              ctxBegin({
                  token: "string",
                  regex: '"',
                  next: "qqstring"
              }),
              {
                  token: ["paren.lparen", "text", "paren.rparen"],
                  regex: "(\\{)(\\s*)(\\|)",
                  next: "block_arguments"
              }
  
          ].concat(this.$rules.no_regex);
  
          this.$rules.block_arguments = [
              {
                  token: "paren.rparen",
                  regex: "\\|",
                  next: "no_regex"
              }
          ].concat(this.$rules.function_arguments);
  
          this.$rules.bstring = [
              {
                  token: "constant.language.escape",
                  regex: escapedRe
              },
              {
                  token: "string",
                  regex: "\\\\$",
                  next: "bstring"
              },
              ctxBegin({
                  token: "paren.lparen",
                  regex: "\\$\\{",
                  next: "string_interp"
              }),
              ctxBegin({
                  token: "paren.lparen",
                  regex: "\\$",
                  next: "bstring_interp_single"
              }),
              ctxEnd({
                  token: "string",
                  regex: "`"
              }),
              {
                  defaultToken: "string"
              }
          ];
  
          this.$rules.qqstring = [
              {
                  token: "constant.language.escape",
                  regex: escapedRe
              },
              {
                  token: "string",
                  regex: "\\\\$",
                  next: "qqstring"
              },
              ctxBegin({
                  token: "paren.lparen",
                  regex: "#\\{",
                  next: "string_interp"
              }),
              ctxEnd({
                  token: "string",
                  regex: '"'
              }),
              {
                  defaultToken: "string"
              }
          ];
  
          // collect all context-aware (or stateless), brace-less
          // states. This gives us most normal highlighting
          // for use within interpreted contexts
          // without interfering with context nesting
          var embeddableRules = [];
          for (var i = 0; i < this.$rules.no_regex.length; i++) {
              var rule = this.$rules.no_regex[i];
              var token = String(rule.token);
              if (token.indexOf('paren') == -1 && (!rule.next || rule.next.isContextAware)) {
                  embeddableRules.push(rule);
              }
          }
  
          this.$rules.string_interp = [
              ctxEnd({
                  token: "paren.rparen",
                  regex: "\\}"
              }),
              ctxBegin({
                  token: "paren.lparen",
                  regex: '{',
                  next: "string_interp"
              })
          ].concat(embeddableRules);
  
          // backtick strings can have single interpolation, which accept
          // \w+ followed by an optional set of function call parens
          this.$rules.bstring_interp_single = [
              {
                  token: ["identifier", "paren.lparen"],
                  regex: '(\\w+)(\\()',
                  next: 'bstring_interp_single_call'
              },
              // identifier-only match ends this interp
              ctxEnd({
                  token: "identifier",
                  regex: "\\w*"
              })
          ];
  
          // the call part of a bstring_interp_single
          // is terminated by a close paren `)`, but
          // can have nested parens.
          this.$rules.bstring_interp_single_call = [
              ctxBegin({
                  token: "paren.lparen",
                  regex: "\\(",
                  next: "bstring_interp_single_call"
              }),
              ctxEnd({
                  token: "paren.rparen",
                  regex: "\\)"
              })
          ].concat(embeddableRules);
      }
      oop.inherits(SJSHighlightRules, TextHighlightRules);
  
      exports.SJSHighlightRules = SJSHighlightRules;
  });
  