Class: Mochiscript::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/mochiscript/core.rb

Constant Summary collapse

JAVASCRIPT =
"var $m  = { ROOT: this, ADAPTER: _$m_adapter, PLATFORM: 'ruby' };\nvar JS2 = $m;\n(function () {\n  // CLASS HELPERS\n(function (undefined, $m) {\n\n  var OO = function (klass, par) {\n    this.klass = klass;\n    this.par   = par;\n\n    this.members       = {};\n    this.staticMembers = {};\n    this.children = [];\n    this.included = [];\n\n    if (this.par) this.par.OO.children.push(klass);\n  };\n\n  $m.PUSH_ROOT = function (r) {\n    this.ROOTS = this.ROOTS || [];\n    this.ROOTS.push(r);\n    this.ROOT = r;\n  };\n\n  $m.POP_ROOT = function () {\n    this.ROOTS = this.ROOTS || [];\n    if (this.ROOTS.length) {\n      this.ROOTS.pop();\n      this.ROOT = this.ROOTS[this.ROOTS.length-1];\n    }\n\n  };\n\n  OO.prototype = {\n    forbiddenMembers: {\n      'prototype': undefined,\n      'OO': undefined\n    },\n\n    include: function(module) {\n      this.included.push(module);\n      var members = module.OO.members;\n      for (var name in members) {\n        if (members.hasOwnProperty(name)) {\n          this.addMember(name, members[name]);\n        }\n      }\n\n      var staticMembers = module.OO.staticMembers;\n      for (var name in staticMembers) {\n        if (staticMembers.hasOwnProperty(name)) {\n          this.addStaticMember(name, staticMembers[name]);\n        }\n      }\n\n      if (typeof staticMembers['included'] == 'function') {\n        staticMembers['included'](this.klass);\n      }\n    },\n\n    createNamespace: function(name) {\n      var splitted = name.split('.');\n      var klassName = splitted.pop();\n      var root = $m.ROOT;\n\n      while (splitted.length > 0) {\n        var name = splitted.shift();\n        if (!root[name]) root[name] = $m.Class.extend({});\n        root = root[name];\n      }\n\n      return [ root, klassName ];\n    },\n\n    makeSuper: function(newMethod, oldMethod) {\n      if (!oldMethod) return newMethod;\n\n      return function() {\n        this.$super = oldMethod;\n        return newMethod.apply(this, arguments);\n      };\n    },\n\n    addMember: function(name, member) {\n      if (this.forbiddenMembers.hasOwnProperty(name)) return;\n\n      var proto = this.klass.prototype;\n      if (typeof proto[name] == 'function' && !(proto[name] instanceof RegExp)) {\n        member = this.makeSuper(member, proto[name]);\n      }\n\n      proto[name] = member;\n      this.members[name] = member;\n    },\n\n    addStaticMember: function(name, member) {\n      if (this.forbiddenMembers.hasOwnProperty(name)) return;\n\n      if (typeof this.klass[name] == 'function') {\n        if (!this.klass.hasOwnProperty(name)) {\n          member = this.makeSuper(member, this.klass[name]);\n        }\n      }\n\n      this.klass[name] = member;\n      this.staticMembers[name] = member;\n    }\n  };\n\n  $m.Class = function() { this.initialize.apply(this, arguments); };\n  $m.Class.OO = new OO($m.Class);\n  $m.Class.prototype = {\n    initialize: function () {},\n    oo: $m.Class.OO\n  };\n\n  var namedClasses = {};\n  $m.getClass = function(name) {\n    return namedClasses[name];\n  };\n\n  var noInit = false;\n  $m.Class.extend = function(name, klassDef) {\n    var klass = function() { if (!noInit) this.initialize.apply(this, arguments); };\n    klass.OO  = new OO(klass, this);\n\n    if (typeof name != 'string') {\n      klassDef = name;\n    } else {\n      namedClasses[name] = klass;\n      var namespace = this.OO.createNamespace(name);\n      namespace[0][namespace[1]] = klass;\n    }\n\n    // create instance of this as prototype for new this\n    noInit = true;\n    var proto = new this();\n    noInit = false;\n\n    klass.prototype = proto;\n    var oo   = klass.OO;\n    proto.OO = oo;\n\n    for (var name in this) {\n      oo.addStaticMember(name, this[name]);\n    }\n\n    if (typeof klassDef == 'function') {\n      klassDef(klass, oo);\n    } else {\n      for (var name in klassDef) {\n        oo.addMember(name, klassDef[name]);\n      }\n    }\n\n    return klass;\n  };\n\n  $m.Module = $m.Class;\n\n  var assert = {\n    'eq': function(expected, actual) { if (expected != actual) $m.outs(\"Expected \"+expected+\", but got \"+actual+\".\") },\n    'isFalse': function(val) { if (val) $m.outs(\"Expected false, but got \"+JSON.stringify(val)+\".\") },\n    'isTrue': function(val) { if (!val) $m.outs(\"Expected true, but got \" +val+\".\") }\n  };\n\n  $m.test = function(message, callback) {\n    if (!callback) callback = message;\n    callback(assert);\n  };\n\n  function addListener(type, listener) {\n    var events = this.__$events || (this.__$events = {});\n    this.emit('newListener', type, listener);\n    if (!events[type]) events[type] = [];\n    events[type].push(listener);\n  }\n\n  $m.out = function () {\n    for (var i=0,arg=null,_list_0=arguments,_len_0=_list_0.length;(arg=_list_0[i])||i<_len_0;i++){\n      $m.ADAPTER.out(arg);\n      if (i < arguments.length-1) {\n        $m.ADAPTER.out(',');\n      }\n    }\n  };\n\n  $m.outs = function () {\n    for (var _i_0=0,arg=null,_list_0=arguments,_len_0=_list_0.length;(arg=_list_0[_i_0])||_i_0<_len_0;_i_0++){\n      $m.ADAPTER.outs(arg);\n    }\n  };\n\n  return $m;\n})(undefined, $m);\n\n\n$m.Module.extend(\"EventEmitter\", function(KLASS, OO){\n  \n    var MAX_LISTENERS = 10;\n    var isArray = Array.isArray;\n  \n\n  OO.addMember(\"emit\", function(){\n    var type = arguments[0];\n    // If there is no 'error' event listener then throw.\n    if (type === 'error') {\n      if (!this._events || !this._events.error ||\n          (isArray(this._events.error) && !this._events.error.length))\n      {\n        if (arguments[1] instanceof Error) {\n          throw arguments[1]; // Unhandled 'error' event\n        } else {\n          throw new Error(\"Uncaught, unspecified 'error' event.\");\n        }\n        return false;\n      }\n    }\n\n    if (!this._events) return false;\n    var handler = this._events[type];\n    if (!handler) return false;\n\n    if (typeof handler == 'function') {\n      switch (arguments.length) {\n        // fast cases\n        case 1:\n          handler.call(this);\n          break;\n        case 2:\n          handler.call(this, arguments[1]);\n          break;\n        case 3:\n          handler.call(this, arguments[1], arguments[2]);\n          break;\n        // slower\n        default:\n          var l = arguments.length;\n          var args = new Array(l - 1);\n          for (var i = 1; i < l; i++) args[i - 1] = arguments[i];\n          handler.apply(this, args);\n      }\n      return true;\n\n    } else if (isArray(handler)) {\n      var l = arguments.length;\n      var args = new Array(l - 1);\n      for (var i = 1; i < l; i++) args[i - 1] = arguments[i];\n\n      var listeners = handler.slice();\n      for (var i = 0, l = listeners.length; i < l; i++) {\n        listeners[i].apply(this, args);\n      }\n      return true;\n\n    } else {\n      return false;\n    }\n\n  }); \n\n  OO.addMember(\"addListener\", function(type, listener){\n    if ('function' !== typeof listener) {\n      throw new Error('addListener only takes instances of Function');\n    }\n\n    if (!this._events) this._events = {};\n\n    // To avoid recursion in the case that type == \"newListeners\"! Before\n    // adding it to the listeners, first emit \"newListeners\".\n    this.emit('newListener', type, typeof listener.listener === 'function' ?\n              listener.listener : listener);\n\n    if (!this._events[type]) {\n      // Optimize the case of one listener. Don't need the extra array object.\n      this._events[type] = listener;\n    } else if (isArray(this._events[type])) {\n\n      // If we've already got an array, just append.\n      this._events[type].push(listener);\n\n    } else {\n      // Adding the second element, need to change to array.\n      this._events[type] = [this._events[type], listener];\n\n    }\n\n    // Check for listener leak\n    if (isArray(this._events[type]) && !this._events[type].warned) {\n      var m;\n      if (MAX_LISTENERS !== undefined) {\n        m = MAX_LISTENERS;\n      } else {\n        m = defaultMaxListeners;\n      }\n\n      if (m && m > 0 && this._events[type].length > m) {\n        this._events[type].warned = true;\n        console.error('(node) warning: possible EventEmitter memory ' +\n                      'leak detected. %d listeners added. ' +\n                      'Use emitter.setMaxListeners() to increase limit.',\n                      this._events[type].length);\n        console.trace();\n      }\n    }\n\n    return this;\n  });\n\n  OO.addMember(\"on\", function(type, listener){\n    this.addListener(type, listener);\n  });\n\n  OO.addMember(\"once\", function(type, listener){\n    if ('function' !== typeof listener) {\n      throw new Error('.once only takes instances of Function');\n    }\n\n    function g() {\n      self.removeListener(type, g);\n      listener.apply(this, arguments);\n    };\n\n    g.listener = listener;\n    this.on(type, g);\n\n    return this;\n  });\n\n  OO.addMember(\"removeListener\", function(type, listener){\n    if ('function' !== typeof listener) {\n      throw new Error('removeListener only takes instances of Function');\n    }\n\n    // does not use listeners(), so no side effect of creating _events[type]\n    if (!this._events || !this._events[type]) return this;\n\n    var list = this._events[type];\n\n    if (isArray(list)) {\n      var position = -1;\n      for (var i = 0, length = list.length; i < length; i++) {\n        if (list[i] === listener ||\n            (list[i].listener && list[i].listener === listener))\n        {\n          position = i;\n          break;\n        }\n      }\n\n      if (position < 0) return this;\n      list.splice(position, 1);\n      if (list.length == 0)\n        delete this._events[type];\n    } else if (list === listener ||\n               (list.listener && list.listener === listener))\n    {\n      delete this._events[type];\n    }\n\n    return this;\n  });\n\n  OO.addMember(\"removeAllListeners\", function(type){\n    if (arguments.length === 0) {\n      this._events = {};\n      return this;\n    }\n\n    // does not use listeners(), so no side effect of creating _events[type]\n    if (type && this._events && this._events[type]) this._events[type] = null;\n    return this;\n  });\n\n  OO.addMember(\"listeners\", function(type){\n    if (!this._events) this._events = {};\n    if (!this._events[type]) this._events[type] = [];\n    if (!isArray(this._events[type])) {\n      this._events[type] = [this._events[type]];\n    }\n    return this._events[type];\n  });\n});\n\n$m.EventEmitter = $m.ROOT.EventEmitter;\n\n\n  var IDENT  = \"[\\\\$\\\\w]+\";\nvar TOKENS = [\n  [ \"SPACE\", \"\\\\s+\"  ],\n  [ \"RETURN\", \"=>\", 'ReturnParser' ],\n\n  [ \"STATIC\",   \"static\\\\b\" ],\n  [ \"MODULE\",   \"module\\\\b\", 'ModuleParser' ],\n\n  [ \"EXPORT\",   \"export\\\\s+class\\\\b\", 'ClassParser' ],\n  [ \"PUBLIC\",   \"public\\\\s+class\\\\b\", 'ClassParser' ],\n\n  [ \"CLASS\",    \"class\\\\b\",  'ClassParser' ],\n  [ \"FUNCTION\", \"function\\\\b\" ],\n  [ \"INCLUDE\",  \"include\\\\b\" ],\n  [ \"VAR\",      \"var\\\\b\" ],\n  [ \"PRIVATE\",  \"private\\\\b\" ],\n  [ \"EXTENDS\",  \"extends\\\\b\" ],\n  [ \"FOREACH\",  \"foreach\\\\b\", 'ForeachParser' ],\n\n  [ \"SHORTHAND_MAPPER\",   \"#[\\\\w\\\\$]+\\\\s*(?:{|\\\\()\", 'ShorthandMapperParser' ],\n  [ \"SHORTHAND_FUNCTION\", \"#(?:{|\\\\()\", 'ShorthandFunctionParser' ],\n  [ \"ISTRING_START\", \"%{\", 'IStringParser' ],\n  [ \"HEREDOC\", \"<<[A-Z][0-9A-Z]*\", 'HereDocParser' ],\n\n  [ \"DSTRING\", \"\\\"(?:\\\\\\\\.|[^\\\"])*\\\"\" ],\n  [ \"SSTRING\", \"\\'(?:\\\\\\\\.|[^\\'])*\\'\" ],\n\n  [ \"SEMICOLON\", \";\" ],\n  [ \"OPERATOR\",  \"\\\\+|\\\\-|\\\\++\" ],\n  [ \"EQUALS\",    \"=\" ],\n\n  [ \"COMMENT\", \"\\\\/\\\\/|\\\\/\\\\*\", \"CommentParser\" ],\n  [ \"REGEX\", \"/\", 'RegexParser' ],\n\n  [ \"LBRACE\", \"\\\\(\" ],\n  [ \"RBRACE\", \"\\\\)\" ],\n  [ \"LCURLY\", \"\\\\{\" ],\n  [ \"RCURLY\", \"\\\\}\" ],\n\n  [ \"IDENT\", IDENT ],\n  [ \"WHATEVER\", \".\" ]\n];\n\nvar $c      = $m.ROOT;\nvar TYPES   = {};\nvar REGEXES = [];\nvar MAIN_REGEX = null;\nvar RTYPES  = {};\n\nfor (var i=0,t=null,_list_0=TOKENS,_len_0=_list_0.length;(t=_list_0[i])||i<_len_0;i++){\n  TYPES[t[0]] = i;\n  RTYPES[i]   = t[0];\n  REGEXES.push(\"(\" + t[1] + \")\");\n}\n\nvar EXTRA_REGEX_STRINGS = {\n  ARGS: \"\\\\(\\s*(?:\" + IDENT + \")?(?:\\\\s*,\\\\s*\" + IDENT + \")*\\s*\\\\)\",\n  CLASSNAME: \"[\\\\$\\\\w\\\\.]+\"\n};\n\nvar MAIN_REGEX = new RegExp(\"^\" + REGEXES.join('|'));\n\n$m.Class.extend(\"Tokens\", function(KLASS, OO){\n  OO.addMember(\"initialize\", function(str){\n    this.orig     = str;\n    this.str      = str;\n    this.iterator = 0;\n    this.consumed = 0;\n  });\n\n  OO.addMember(\"peek\", function(){\n    if (this._peek) return this._peek;\n\n    var m = this.str.match(MAIN_REGEX);\n    if (!m) return null;\n\n    for (var i=0,ele=null,_list_0=TOKENS,_len_0=_list_0.length;(ele=_list_0[i])||i<_len_0;i++){\n      if (m[i+1]) return this._peek = [ i, m[i+1], ele[2] ];\n    }\n  });\n\n  OO.addStaticMember(\"regex\", function(str){\n    var regexStr = str.replace(/\\*\\*/g, \"\\\\s*\").replace(/\\s+/g, \"\\\\s+\").replace(/\\>\\</g, \">\\\\s*<\").replace(/\\<(\\w+)\\>/g, function($1,$2,$3){\n      return \"(\" + (EXTRA_REGEX_STRINGS[$2] || TOKENS[TYPES[$2]][1])  + \")\";\n    });\n\n    return new RegExp(\"^\" + regexStr);\n  });\n\n  OO.addMember(\"consume\", function(n){\n    this.str   = this.str.substr(n, this.str.length-n);\n    this._peek = null;\n    this.consumed += n;\n  });\n\n  OO.addMember(\"length\", function(){\n    return this.str.length;\n  });\n\n  OO.addMember(\"lookback\", function(n){\n    var starting = this.consumed - 1;\n\n    //$m.outs(JSON.stringify(this.orig.substr(starting-10, 10)));\n    //$m.outs(JSON.stringify(this.orig.charAt(starting)));\n    while (this.orig.charAt(starting).match(/\\s/)) {\n      //$m.outs(\"back\");\n      starting--;\n    }\n\n    //$m.outs(n + \"= \" + JSON.stringify(this.orig.substr(starting-n, n)));\n    return this.orig.substr(starting-n+1, n);\n  });\n\n  OO.addMember(\"lookahead\", function(n){\n    var starting = this.consumed;\n    while (this.orig.charAt(starting).match(/\\s/)) starting++;\n    return this.orig.substr(starting, n);\n  });\n\n\n  OO.addMember(\"any\", function(){\n    return this.str.length > 0;\n  });\n\n  OO.addMember(\"match\", function(regex){\n    return this.str.match(regex);\n  });\n});\nvar Tokens = $c.Tokens;\n\n\n$m.parse = function (str) {\n  var parser = new $c.RootParser();\n  parser.parse(new $c.Tokens(str));\n  return parser.toString();\n};\n\n$m.toJSON = function (str, options) {\n  var parser = new $c.RootParser();\n  parser.parse(new $c.Tokens(str));\n  return parser.toJSON();\n};\n\n$m.pp = function (str, options) {\n  var parser = new $c.RootParser();\n  parser.parse(new $c.Tokens(str));\n  return parser.pp();\n};\n\nvar OPTIONS = {};\n\n$m.Class.extend(\"RootParser\", function(KLASS, OO){\n  OO.addMember(\"handlers\", {});\n\n  OO.addMember(\"initialize\", function(){\n    this.out = [];\n    this.finished = false;\n  });\n\n  OO.addMember(\"parse\", function(tokens){\n    var len = tokens.length();\n    if (this.startParse(tokens) === false || this.parseTokens(tokens) === false || this.endParse(tokens) === false) return false\n    return len != tokens.length();\n  });\n\n  // TODO: messy clean this process up\n  OO.addMember(\"parseTokens\", function(tokens){\n    var sanity  = 100;\n    var origLen = tokens.length();\n\n    while (tokens.any()) {\n      var token   = tokens.peek();\n      if (!token) break;\n\n      // has a parser class associated with this token\n      var handlerClass = this.getHandler(token) || token[2];\n      if (handlerClass) {\n        var handler = new $c[handlerClass];\n        handler._TYPE = handlerClass;\n        if (handler.parse(tokens) !== false) {\n          this.out.push(handler);\n          tokens.lastHandler = handler;\n        } else {\n          this.handleToken(token, tokens);\n        }\n      }\n\n      // no parser class, use \"this\" to just consume it\n      else {\n        this.handleToken(token, tokens);\n      }\n\n      if (this.finished) break;\n\n      if (origLen == tokens.length() && sanity-- == 0) {\n        throw \"parse error\";\n      } else {\n        sanity = 100;\n      }\n    }\n  });\n\n  OO.addMember(\"startParse\", function(){ });\n  OO.addMember(\"endParse\", function(){ });\n\n  OO.addMember(\"handleToken\", function(token, tokens){\n    this.out.push(token[1]);\n    tokens.consume(token[1].length);\n  });\n\n  OO.addMember(\"toString\", function(){\n    var ret = [];\n    for (var i=0; i<this.out.length; i++) {\n      var ele = this.out[i];\n      ret.push(ele === undefined ? '' : ele.toString());\n    }\n    return ret.join(\"\");\n  });\n\n  OO.addMember(\"toJSON\", function(){\n    return JSON.stringify(this.toStruct());\n  });\n\n  OO.addMember(\"pp\", function(space){\n    space = space == null ? \"  \" : space + \"  \";\n\n    var ret = [ space + (this._TYPE || 'NODE') ];\n    var generic = [];\n    for (var _i_0=0,ele=null,_list_0=this.out,_len_0=_list_0.length;(ele=_list_0[_i_0])||_i_0<_len_0;_i_0++){\n      if (ele === undefined) {\n        ret.push(space + \"  UNDEFINED!\");\n        continue;\n      }\n\n      if (ele.pp) {\n        if (generic.length) {\n          ret.push(space + \"  TOKENS:\" + JSON.stringify(generic.join('')));\n          generic = [];\n        }\n        ret.push(ele.pp(space));\n      }\n\n      else {\n        generic.push(ele);\n      }\n    }\n\n    if (generic.length) {\n      ret.push(space + \"  TOKENS:\" + JSON.stringify(generic.join('')));\n    }\n\n    return ret.join(\"\\n\");\n  });\n\n  OO.addMember(\"toStruct\", function(){\n    var ret = [];\n    for (var _i_0=0,ele=null,_list_0=this.out,_len_0=_list_0.length;(ele=_list_0[_i_0])||_i_0<_len_0;_i_0++){\n      ret.push(ele.toStruct ? ele.toStruct() : ele);\n    }\n    return ret;\n  });\n\n  // intercepts parser class for special cases\n  OO.addMember(\"getHandler\", function(token){\n    return null;\n  });\n\n  OO.addMember(\"chop\", function(){\n    this.out.pop();\n  });\n});\n\nvar RootParser = $c.RootParser;\n\nRootParser.extend(\"ClassParser\", function(KLASS, OO){\n  \n    var REGEX   = Tokens.regex(\"(?:<EXPORT>|<PUBLIC>|<CLASS>) <CLASSNAME><LCURLY>\");\n    var EXTENDS = Tokens.regex(\"(?:<EXPORT>|<PUBLIC>|<CLASS>) <CLASSNAME><EXTENDS><CLASSNAME><LCURLY>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.match(REGEX) || tokens.match(EXTENDS);\n    var name      = m[4];\n    var extending = m[6] || \"$m.Class\";\n\n    tokens.consume(m[0].length-1);\n\n    var content = new $c.ClassContentParser();\n    content.parse(tokens);\n\n    var isPublic  = ($m.PLATFORM == 'node' && m[2] && m[2].indexOf('public') == 0) ? \"exports.\" + name + '=' + name + ';' : '';\n    var isExports = ($m.PLATFORM == 'node' && m[1] && m[1].indexOf('export') == 0) ? \"module.exports=\" + name + ';' : '';\n\n    this.out = [ extending, \".extend(\", JSON.stringify(name), \", function(KLASS, OO)\", content, \");\", isPublic, isExports ];\n  });\n});\n\nRootParser.extend(\"ModuleParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"<MODULE> <CLASSNAME><LCURLY>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.match(REGEX);\n    if (!m) return false;\n    var name = m[2];\n    tokens.consume(m[0].length-1);\n\n    var content = new $c.ClassContentParser();\n    content.parse(tokens);\n\n    this.out = [ \"$m.Module.extend(\", JSON.stringify(name), \", function(KLASS, OO)\", content, \");\" ];\n  });\n});\n\nRootParser.extend(\"CurlyParser\", function(KLASS, OO){\n  OO.addMember(\"_TYPE\", 'CurlyParser');\n\n  OO.addMember(\"initialize\", function(chop){\n    this.chop = chop;\n    this.$super();\n  });\n\n  OO.addMember(\"handleToken\", function(token, tokens){\n    if (this.curly === undefined) this.curly = 0;\n    if (token[0] == TYPES.RCURLY) {\n      this.curly--;\n    } else if (token[0] == TYPES.LCURLY) {\n      this.curly++;\n    }\n\n    this.$super(token, tokens);\n\n    if (this.curly == 0) {\n      this.finished = true;\n    }\n  });\n\n  OO.addMember(\"endParse\", function(tokens){\n    if (this.chop) {\n      this.out.pop();\n      this.out.shift();\n    }\n  });\n});\n\nvar CurlyParser = $c.CurlyParser;\n\nCurlyParser.extend(\"ClassContentParser\", function(KLASS, OO){\n  OO.addMember(\"getHandler\", function(token){\n    switch(token[0]) {\n      case TYPES.STATIC:   return \"StaticParser\";\n      case TYPES.VAR:      return \"MemberParser\";\n      case TYPES.FUNCTION: return \"MethodParser\";\n      case TYPES.PRIVATE:  return \"PrivateParser\";\n      case TYPES.INCLUDE:  return \"IncludeParser\";\n    }\n  });\n});\n\nRootParser.extend(\"LineParser\", function(KLASS, OO){\n  OO.addMember(\"handleToken\", function(token, tokens){\n    this.$super(token, tokens);\n    if (token[0] == TYPES.SEMICOLON) {\n      this.finished = true;\n    }\n  });\n});\n\nCurlyParser.extend(\"PrivateParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"<PRIVATE>\\\\s*\");\n  \n\n  OO.addMember(\"startParse\", function(tokens){\n    var m = tokens.match(REGEX);\n    tokens.consume(m[0].length);\n  });\n\n  OO.addMember(\"endParse\", function(tokens){\n    this.out.pop();\n    this.out.shift();\n  });\n});\n\n\nRootParser.extend(\"IStringParser\", function(KLASS, OO){\n  \n    var BEGIN = Tokens.regex(\"<ISTRING_START>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.match(BEGIN);\n    tokens.consume(m[0].length);\n    this.out.push('\"');\n\n    while (1) {\n      var m = tokens.match(/^((?:\\\\.|.)*?)(#\\{|})/);\n      var str = m[1];\n      var len = m[0].length;\n      str.replace(/\"/, '\\\\\"');\n\n      if (m[2] == '\#{') {\n        this.out.push(str+'\"+(');\n        tokens.consume(len-1);\n        this.parseMiddle(tokens);\n        this.out.push(')+\"');\n      }\n\n      else if (m[2] == '}') {\n        this.out.push(str);\n        this.out.push('\"');\n        tokens.consume(len);\n        return;\n      }\n    }\n  });\n\n  OO.addMember(\"parseMiddle\", function(tokens){\n    var parser = new $c.CurlyParser(true);\n    parser.parse(tokens);\n    this.out.push(parser);\n  });\n});\n\nRootParser.extend(\"StaticParser\", function(KLASS, OO){\n  \n    var VAR_REGEX = Tokens.regex(\"(<STATIC>(\\\\s+))<VAR>\");\n    var FUNCT_REGEX = Tokens.regex(\"(<STATIC>(\\\\s+))<FUNCTION>\");\n  \n\n  OO.addMember(\"parseTokens\", function(tokens){\n    var varMatch = tokens.match(VAR_REGEX);\n    if (varMatch) {\n      tokens.consume(varMatch[1].length);\n      var parser = new $c.MemberParser();\n      parser.isStatic = true;\n      parser.parse(tokens);\n      this.out.push(parser);\n    }\n\n    else {\n      var functMatch = tokens.match(FUNCT_REGEX);\n      tokens.consume(functMatch[1].length);\n\n      var parser = new $c.MethodParser();\n      parser.isStatic = true;\n      parser.parse(tokens);\n      this.out.push(parser);\n    }\n  });\n});\n\nRootParser.extend(\"MemberParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"var <IDENT>\\\\s*=\\\\s*?\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.str.match(REGEX);\n    this.name = m[1];\n    tokens.consume(m[0].length);\n\n    var parser = new $c.LineParser();\n    parser.parse(tokens);\n    parser.chop();\n    var addMethod = this.isStatic ? 'addStaticMember' : 'addMember';\n\n    this.out = [ \"OO.\" + addMethod + \"(\", JSON.stringify(this.name), \",\",  parser, \");\" ];\n  });\n});\n\nvar MemberParser = $m.MemberParser;\n\n\n\nRootParser.extend(\"IncludeParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"<INCLUDE> <CLASSNAME><SEMICOLON>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.match(REGEX);\n    tokens.consume(m[0].length);\n    this.out = [ 'OO.include(',  m[2], ');' ];\n  });\n});\n\nRootParser.extend(\"HereDocParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"<HEREDOC>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var beginning  = tokens.match(/^<<(\\w+)(?::(\\w+))?\\s*([;\\)])*\\n/);\n    var terminator = beginning[1];\n\n    tokens.consume(beginning[0].length);\n\n    var spacing  = tokens.match(/^(\\s*)/);\n    var regexSub = new RegExp(\"^\" + (spacing[0] || ''), \"mg\");\n\n    var strMatch = tokens.match(new RegExp(\"^([\\\\s\\\\S]*?)\\\\n\\\\s*\" + terminator + \"\\\\b\"));\n    var toParse  = strMatch[1] || '';\n\n    toParse = toParse.replace(regexSub, '');\n    toParse = toParse.replace(/\\n/g, \"\\\\n\");\n\n    // TODO handle options for interpolation\n    var string = '\"' + toParse.replace(/\"/g, '\\\\\"') + '\"';\n    tokens.consume(strMatch[0] ? strMatch[0].length : 0);\n\n    // TODO put this in register\n    if (beginning[2]) {\n      this.out = [ '$m.JSML.process(', string, ')',  beginning[3] || ';' ];\n    } else {\n      this.out = [ string, beginning[3] || ';' ];\n    }\n  });\n});\n\nRootParser.extend(\"MethodParser\", function(KLASS, OO){\n  \n    var REGEX = Tokens.regex(\"<FUNCTION> <IDENT><ARGS><SPACE>\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.str.match(REGEX);\n    tokens.consume(m[0].length);\n    var name = m[2];\n    var args = m[3];\n\n    var body = new $c.CurlyParser();\n    body.parse(tokens);\n    body.out[0] = \"{var self=this;\";\n\n    var addMethod = this.isStatic ? 'addStaticMember' : 'addMember';\n\n\n    this.out = [ 'OO.' + addMethod + '(', JSON.stringify(name), ', function', args, body, ');' ];\n  });\n});\n\nRootParser.extend(\"ReturnParser\", function(KLASS, OO){\n  OO.addMember(\"parse\", function(tokens){\n    tokens.consume(2);\n    this.out = [ 'return ' ];\n  });\n});\n\nRootParser.extend(\"ShorthandMapperParser\", function(KLASS, OO){\n  \n    var ARGS_REGEX = Tokens.regex(\"<ARGS>\\\\s*\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    tokens.consume(1);\n    var nameMatch = tokens.match(/^([\\w\\$]+)\\s*/);\n    tokens.consume(nameMatch[0].length);\n\n    var method = nameMatch[1];\n\n    var argsMatch = tokens.match(ARGS_REGEX);\n    var args = null;\n\n    if (argsMatch) {\n      args = argsMatch[0];\n      tokens.consume(argsMatch[0].length);\n    } else {\n      args = \"($1,$2,$3)\";\n    }\n\n    var body = new $c.ReturnableCurlyParser();\n    body.parse(tokens);\n\n    this.out = [ '.', method, '(function', args, body, ')' ];\n  });\n});\n\nRootParser.extend(\"ShorthandFunctionParser\", function(KLASS, OO){\n  \n    var ARGS_REGEX = Tokens.regex(\"<ARGS>\\\\s*\");\n  \n\n  OO.addMember(\"parse\", function(tokens){\n    tokens.consume(1);\n    var argsMatch = tokens.match(ARGS_REGEX);\n    var args = null;\n\n    if (argsMatch) {\n      args = argsMatch[0];\n      tokens.consume(argsMatch[0].length);\n    } else {\n      args = \"($1,$2,$3)\";\n    }\n\n    var body = new $c.CurlyParser();\n    body.parse(tokens);\n    var semi = tokens.match(/^\\s*[,;\\)]/) ? '' : ';';\n\n    this.out = [ 'function', args, body, semi ];\n  });\n});\n\nRootParser.extend(\"CommentParser\", function(KLASS, OO){\n  OO.addMember(\"parse\", function(tokens){\n    var m = tokens.match(/^\\/\\/.*?\\n/);\n    if (m) {\n      tokens.consume(m[0].length);\n      this.out = [ m[0] ];\n      return;\n    }\n\n    var m2 = tokens.match(/^\\/\\*[\\s\\S]*?\\*\\//);\n    if (m2) {\n      tokens.consume(m2[0].length);\n      this.out = [ m2[0] ];\n      return;\n    }\n\n    return false;\n  });\n});\n\nRootParser.extend(\"RegexParser\", function(KLASS, OO){\n  \n    var REGEX  = /^\\/(\\\\.|[^\\/])+\\/[imgy]{0,4}/;\n    var DIVIDE = /(\\}|\\)|\\+\\+|\\-\\-|[\\w\\$])$/;\n  \n\n  OO.addMember(\"parseTokens\", function(tokens){\n    var back = tokens.lookback(2);\n\n    if (back.match(DIVIDE)) {\n      this._TYPE = 'DIVIDE';\n      tokens.consume(1);\n      this.out.push(\"/\");\n    }\n\n    else {\n      var m = tokens.match(REGEX);\n      if (m) {\n        this.out.push(m[0]);\n        tokens.consume(m[0].length);\n      } else {\n        return false;\n      }\n    }\n\n  });\n\n});\n\nCurlyParser.extend(\"ReturnableCurlyParser\", function(KLASS, OO){\n  OO.addMember(\"toString\", function(){\n    var ret = this.$super();\n    return ret.replace(/^{(\\s*)(return)?/, '{$1return ');\n  });\n});\n\n\n\nCurlyParser.extend(\"ForeachParser\", function(KLASS, OO){\n  OO.addMember(\"_TYPE\", 'Foreach');\n\n  \n    var REGEX = Tokens.regex(\"<FOREACH><LBRACE><VAR> <IDENT>(?:**:**<IDENT>)? in (.*?)**<RBRACE>**{\");\n  \n\n  OO.addMember(\"startParse\", function(tokens){\n    var m = tokens.match(REGEX);\n    namespace = tokens.iterator++;\n\n    this.item     = m[4];\n    this.iterator = m[5] || \"_i_\" + namespace;\n    this.list     = m[6];\n\n    // TODO ugly, revisit this later\n    tokens.consume(m[0].length-1);\n    var declare = [ this.iterator + \"=0\", this.item + \"=null\", \"_list_\" + namespace + \"=\" + this.list, \"_len_\" + namespace + \"=_list_\" + namespace + \".length\" ].join(',');\n\n    var bool = \"(\" + this.item + \"=\" + \"_list_\" + namespace + \"[\" + this.iterator + \"])||\" + this.iterator + \"<_len_\" + namespace;\n\n    this.out = [ \"for (var \", declare, \";\", bool, ';', this.iterator + \"++)\" ];\n  });\n\n  OO.addMember(\"endParse\", function(tokens){\n    tokens.iterator--;\n  });\n\n});\n\n\n$m.Class.extend(\"CLI\", function(KLASS, OO){\n  \n    var COMMANDS = {\n      help:    'help',\n      render:  'render',\n      compile: 'compile',\n      watch:   'watch'\n    };\n  \n\n  OO.addMember(\"run\", function(args){\n    var opts = this.parseOpts(args);\n    var options = opts[0];\n    var command = opts[1];\n    var files   = opts[2];\n  });\n\n  OO.addMember(\"parseOpts\", function(args){\n    var files   = [];\n    var options = {};\n    var command = null;\n\n    var endedArgs = false;\n\n    for (var i=0,arg=null,_list_0=args,_len_0=_list_0.length;(arg=_list_0[i])||i<_len_0;i++){\n      if (endedArgs) {\n        files.push(arg);\n      }\n\n      else if (COMMANDS[arg]) {\n        command   = arg;\n        endedArgs = true;\n      }\n\n      else {\n        var setting = arg.match(/^(\\w+)(?:=(.*))?$/);\n        if (setting) options[setting[0]] = setting[1] || 'true';\n      }\n    }\n\n    return [ options, command, files ];\n  });\n});\n\n\n})();\n"