--- /dev/null
+/*?\r
+ // --- Scope -----------------\r
+ // Lang : Language expressions\r
+*/\r
+/**\r
+ * Constructs a new Tokenizer.\r
+ * @exports ProtoBuf.DotProto.Tokenizer\r
+ * @class prototype tokenizer\r
+ * @param {string} proto Proto to tokenize\r
+ * @constructor\r
+ */\r
+var Tokenizer = function(proto) {\r
+\r
+ /**\r
+ * Source to parse.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.source = proto+"";\r
+\r
+ /**\r
+ * Current index.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.index = 0;\r
+\r
+ /**\r
+ * Current line.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.line = 1;\r
+\r
+ /**\r
+ * Token stack.\r
+ * @type {!Array.<string>}\r
+ * @expose\r
+ */\r
+ this.stack = [];\r
+\r
+ /**\r
+ * Opening character of the current string read, if any.\r
+ * @type {?string}\r
+ * @private\r
+ */\r
+ this._stringOpen = null;\r
+};\r
+\r
+/**\r
+ * @alias ProtoBuf.DotProto.Tokenizer.prototype\r
+ * @inner\r
+ */\r
+var TokenizerPrototype = Tokenizer.prototype;\r
+\r
+/**\r
+ * Reads a string beginning at the current index.\r
+ * @return {string}\r
+ * @private\r
+ */\r
+TokenizerPrototype._readString = function() {\r
+ var re = this._stringOpen === '"'\r
+ ? Lang.STRING_DQ\r
+ : Lang.STRING_SQ;\r
+ re.lastIndex = this.index - 1; // Include the open quote\r
+ var match = re.exec(this.source);\r
+ if (!match)\r
+ throw Error("unterminated string");\r
+ this.index = re.lastIndex;\r
+ this.stack.push(this._stringOpen);\r
+ this._stringOpen = null;\r
+ return match[1];\r
+};\r
+\r
+/**\r
+ * Gets the next token and advances by one.\r
+ * @return {?string} Token or `null` on EOF\r
+ * @expose\r
+ */\r
+TokenizerPrototype.next = function() {\r
+ if (this.stack.length > 0)\r
+ return this.stack.shift();\r
+ if (this.index >= this.source.length)\r
+ return null;\r
+ if (this._stringOpen !== null)\r
+ return this._readString();\r
+\r
+ var repeat,\r
+ prev,\r
+ next;\r
+ do {\r
+ repeat = false;\r
+\r
+ // Strip white spaces\r
+ while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) {\r
+ if (next === '\n')\r
+ ++this.line;\r
+ if (++this.index === this.source.length)\r
+ return null;\r
+ }\r
+\r
+ // Strip comments\r
+ if (this.source.charAt(this.index) === '/') {\r
+ ++this.index;\r
+ if (this.source.charAt(this.index) === '/') { // Line\r
+ while (this.source.charAt(++this.index) !== '\n')\r
+ if (this.index == this.source.length)\r
+ return null;\r
+ ++this.index;\r
+ ++this.line;\r
+ repeat = true;\r
+ } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */\r
+ do {\r
+ if (next === '\n')\r
+ ++this.line;\r
+ if (++this.index === this.source.length)\r
+ return null;\r
+ prev = next;\r
+ next = this.source.charAt(this.index);\r
+ } while (prev !== '*' || next !== '/');\r
+ ++this.index;\r
+ repeat = true;\r
+ } else\r
+ return '/';\r
+ }\r
+ } while (repeat);\r
+\r
+ if (this.index === this.source.length)\r
+ return null;\r
+\r
+ // Read the next token\r
+ var end = this.index;\r
+ Lang.DELIM.lastIndex = 0;\r
+ var delim = Lang.DELIM.test(this.source.charAt(end++));\r
+ if (!delim)\r
+ while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end)))\r
+ ++end;\r
+ var token = this.source.substring(this.index, this.index = end);\r
+ if (token === '"' || token === "'")\r
+ this._stringOpen = token;\r
+ return token;\r
+};\r
+\r
+/**\r
+ * Peeks for the next token.\r
+ * @return {?string} Token or `null` on EOF\r
+ * @expose\r
+ */\r
+TokenizerPrototype.peek = function() {\r
+ if (this.stack.length === 0) {\r
+ var token = this.next();\r
+ if (token === null)\r
+ return null;\r
+ this.stack.push(token);\r
+ }\r
+ return this.stack[0];\r
+};\r
+\r
+/**\r
+ * Skips a specific token and throws if it differs.\r
+ * @param {string} expected Expected token\r
+ * @throws {Error} If the actual token differs\r
+ */\r
+TokenizerPrototype.skip = function(expected) {\r
+ var actual = this.next();\r
+ if (actual !== expected)\r
+ throw Error("illegal '"+actual+"', '"+expected+"' expected");\r
+};\r
+\r
+/**\r
+ * Omits an optional token.\r
+ * @param {string} expected Expected optional token\r
+ * @returns {boolean} `true` if the token exists\r
+ */\r
+TokenizerPrototype.omit = function(expected) {\r
+ if (this.peek() === expected) {\r
+ this.next();\r
+ return true;\r
+ }\r
+ return false;\r
+};\r
+\r
+/**\r
+ * Returns a string representation of this object.\r
+ * @return {string} String representation as of "Tokenizer(index/length)"\r
+ * @expose\r
+ */\r
+TokenizerPrototype.toString = function() {\r
+ return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")";\r
+};\r