/* * @project: TERA * @version: Development (beta) * @license: MIT (not for evil) * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] * Web: https://terafoundation.org * Twitter: https://twitter.com/terafoundation * Telegram: https://t.me/terafoundation */ const LOC_ADD_NAME = "$"; module.exports = function() { 'use strict'; this.ErrorIgnore = false; this.ErrorOne = true; this.CommentIgnore = true; this.PrintMargin = 120; this.FileNumber = 0; this.InjectCheck = true; this.SideMode = "client"; this.Clear = function() { this.ExternMap = {}; this.FunctionMap = {}; this.WasPlus = 0; this.buf = ""; this.stream = ""; this.bWasBackSlash = false; this.pos = 0; this.start = 0; this.beforeRegExp = 0; this.value = ""; this.type = ""; this.BlockLevel = 0; this.LastStreamValue = ""; this.CountCol = 0; this.ErrCount = 0; this.WasEnter = false; this.lastComment = 0; this.lastAddCode = - 1; this.LineNumber = 0; this.posLineNumber = 0; this.IgnoreCodeLevel = false; this.AddToStream = this.AddToStreamAddTab; }; this.AllowedWords = { true: 1, false: 1, undefined: 1, Infinity: 1, NaN: 1, null: 1, context: 5, this: 5, arguments: 5, }; this.KeyWords = { break: 1, return: 1, case: 1, do: 1, if: 1, switch: 1, var: 1, throw: 1, while: 1, default: 1, for: 1, try: 1, continue: 1, with: 1, function: 3, void: 3, new: 3, delete: 3, typeof: 3, finally: 5, catch: 5, else: 5, instanceof: 4, in: 4, }; this.ProcessWords = { break: "break", return: "return", case: "case", do: "do", if: "if", switch: "switch", var: "var", throw: "throw", with: "with", while: "while", default: "default", for: "for", try: "try", continue: "continue", function: "function", void: "void", new: "new", delete: "delete", typeof: "typeof", finally: "finally", catch: "catch", else: "else", }; this.enIndenifier = "1"; this.enString = "2"; this.enNumber = "3"; this.enSpaces = "4"; this.enNewLine = "5"; this.enComments = "6"; this.enRegular = "7"; this.enOperator = "O"; this.enEndFile = "EoF"; this.lexTypeAll = new Array(0x10000); this.lexTypeIdentifier = new Array(0x10000); this.lexTypeNumbers = new Array(0x10000); this.lexTypeNumbers16 = new Array(0x10000); this.lexTypeSpaces = new Array(0x10000); this.lexTypeNewLines = new Array(0x10000); this.lexTypeRegStart = new Array(0x10000); this.SpacesArray = new Array(100); this.Init = function() { var BufNumbers = "0123456789"; var BufNumbers16 = "0123456789ABCDEFabcdef"; var BufChars = "~!%^&*-+/<>`@#()=\\|{}[];':\"?,."; var BufSpaces = " \t\b\f\v\u00A0\u2028\u2029\u000C"; var BufNewLine = "\n\r"; var BufRegStart = "`~!#%^&*(+|-=\\[{};:,?<>"; SetType("N", BufNumbers, this.lexTypeAll); SetType("C", BufChars, this.lexTypeAll); SetType("S", BufSpaces, this.lexTypeAll); SetType("M", BufNewLine, this.lexTypeAll); SetLetterType("L", this.lexTypeAll, this.lexTypeAll); SetType("N", BufNumbers, this.lexTypeNumbers); SetType("N", BufNumbers16, this.lexTypeNumbers16); SetType("S", BufSpaces, this.lexTypeSpaces); SetType("M", BufNewLine, this.lexTypeNewLines); SetType("R", BufRegStart, this.lexTypeRegStart); SetLetterType("L", this.lexTypeAll, this.lexTypeIdentifier); SetType("N", BufNumbers, this.lexTypeIdentifier); Normalize(this.lexTypeAll); Normalize(this.lexTypeNumbers); Normalize(this.lexTypeNumbers16); Normalize(this.lexTypeSpaces); Normalize(this.lexTypeNewLines); Normalize(this.lexTypeRegStart); Normalize(this.lexTypeIdentifier); this.SpacesArray[0] = ""; this.SpacesArray[1] = ""; for (var i = 2; i < 100; i++) this.SpacesArray[i] = this.SpacesArray[i - 1] + " "; function SetType(type, buf, TypeArray) { for (var pos = 0; pos < buf.length; pos++) { var c = buf.charCodeAt(pos); TypeArray[c] = type; } }; function SetLetterType(type, lexTypeAll, TypeArray) { for (var i = 32; i < 0x10000; i++) { if (!lexTypeAll[i] || lexTypeAll[i] == "L") TypeArray[i] = "L"; } TypeArray[92] = "L"; }; function Normalize(TypeArray) { for (var i = 0; i < 0x10000; i++) { TypeArray[i] = TypeArray[i] || false; } }; function SetVeryQuickly(TypeArray) { var Ret = 0; for (var i = 0; i < 0x10000; i++) { if (TypeArray[i]) Ret = 1; else Ret = 0; } return Ret; }; }; this.Init(); function LANG(Str) { for (var i = 1; i < arguments.length; i++) Str = Str.replace("%" + i, arguments[i]); return Str; }; this.Error = function() { var Str1 = LANG.apply(this, arguments); var begin = 0; for (var i = this.start; i >= 0; i--) if (this.buf[i] == "\n" || this.buf[i] == "\r") { begin = i + 1; break; } var end = this.buf.length - 1; for (var i = this.pos; i < this.buf.length; i++) if (this.buf[i] == "\n" || this.buf[i] == "\r") { end = i; break; } var line = 1; for (var i = 0; i < this.start; i++) if (this.buf[i] == "\n") { line++; } var col = this.start + 1 - begin; var Dots1 = ""; var Dots2 = ""; if (this.start - begin > 100) { begin = this.start - 100; Dots1 = "..."; } if (end - this.start > 100) { end = this.start + 100; Dots2 = "..."; } this.ErrCount++; var ErrLabel; if (!this.ErrorOne && this.ErrorIgnore) ErrLabel = " <> "; else ErrLabel = " <> "; var StrLine = this.buf.substring(begin, this.start) + ErrLabel + this.buf.substring(this.start, end); var Str2 = LANG("At line: %1 col: %2", line - 1, col - 1); var Str = "SyntaxError: " + Str1 + ". " + Str2 + "\n" + Dots1 + StrLine + Dots2; if (this.ErrorIgnore) { console.log(Str); this.stream += ErrLabel; this.stream += this.value + " "; if (this.ErrorOne) { this.stream += "\n\n" + Str; } else { this.NotBackPos(); return; } } throw Str; }; this.code_base = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f'; this.FromBackSlashString = function(str) { var Ret = ""; for (var i = 0; i < str.length; i++) { var s = str[i]; if (s == "\\") { var s2 = str[i + 1]; switch (s2) { case "r": i = i + 1; Ret = Ret + "\r"; break; case "n": i = i + 1; Ret = Ret + "\n"; break; case "t": i = i + 1; Ret = Ret + "\t"; break; case "b": i = i + 1; Ret = Ret + "\b"; break; case "f": i = i + 1; Ret = Ret + "\f"; break; case "u": var s = str.substring(i + 2, i + 6); var code = parseInt(s); if (isNaN(code)) this.Error("Unrecognize unicode symbol: '%1'", "\\u" + s); else Ret = Ret + String.fromCharCode(code); i = i + 5; break; case "x": var s = str.substring(i + 2, i + 4); var code = parseInt(s, 16); if (isNaN(code)) this.Error("Unrecognize Latin symbol: '%1'", "\\x" + s); else Ret = Ret + this.code_base.charAt(code); i = i + 3; break; default: var c = str.charCodeAt(i + 1); if (this.lexTypeNumbers[c] == "N") { var s = str.substring(i + 1, i + 4); var code = parseInt(s, 8); if (isNaN(code)) this.Error("Unrecognize Latin symbol: '%1'", "\\" + s); else Ret = Ret + this.code_base.charAt(code); i = i + 3; } break; } } else { Ret = Ret + s; } } return Ret; }; this.PosString = function() { var separator = this.buf[this.pos]; this.pos++; while (this.pos < this.buf.length) { var s = this.buf[this.pos]; if (s == separator) { this.pos++; return; } else if (s == "\\") { this.pos++; this.bWasBackSlash = true; } else if (s == "\n") { this.Error("Found end of line during calculate string"); return; } this.pos++; } this.Error("Found end of file during calculate string"); }; this.PosRegExp = function() { this.Error("RegExp not support"); return; var separator = "/"; this.pos++; while (this.pos < this.buf.length) { var s = this.buf[this.pos]; if (s == separator) { this.pos++; return; } else if (s == "[") { separator = ""; } else if (s == "]" && separator == "") { separator = "/"; } else if (s == "\\") { this.pos++; this.bWasBackSlash = true; } else if (s == "\n") { this.Error("Found end of line during calculate regexp"); return; } this.pos++; } this.Error("Found end of file during calculate regexp"); }; this.PosCurrentType = function(TypeArray) { while (this.pos < this.buf.length) { var c = this.buf.charCodeAt(this.pos); if (!TypeArray[c]) break; if (c == 92) this.bWasBackSlash = true; this.pos++; } }; this.PosIdentifier = function() { this.PosCurrentType(this.lexTypeIdentifier); }; this.PosSpaces = function() { this.PosCurrentType(this.lexTypeSpaces); }; this.PosNewLines = function() { this.PosCurrentType(this.lexTypeNewLines); }; this.PosNumber = function() { if (this.buf[this.pos] == "0") { this.pos++; var s = this.buf[this.pos]; if (s == "x" || s == "X") { this.pos++; this.PosCurrentType(this.lexTypeNumbers16); } else if (s == ".") { this.pos++; this.PosCurrentType(this.lexTypeNumbers); } else { this.PosCurrentType(this.lexTypeNumbers); } return; } this.PosCurrentType(this.lexTypeNumbers); if (this.buf[this.pos] == ".") { this.pos++; this.PosCurrentType(this.lexTypeNumbers); } if (this.buf[this.pos] == "e" || this.buf[this.pos] == "E") { this.pos++; var s2 = this.buf[this.pos]; if (s2 == "+" || s2 == "-") this.pos++; var posstart = this.pos; this.PosCurrentType(this.lexTypeNumbers); if (posstart == this.pos) this.Error("Unrecognize exponent number"); } var c = this.buf.charCodeAt(this.pos); var type = this.lexTypeAll[c]; if (type == "L") this.Error("Unrecognize number"); }; this.PosCommentsOneLine = function() { while (this.pos < this.buf.length) { var s = this.buf[this.pos]; if (s == '\n') break; else if (s == '\r') break; this.pos++; } }; this.PosCommentsMultiLine = function() { while (this.pos < this.buf.length) { var s = this.buf[this.pos] + this.buf[this.pos + 1]; if (s == '*/') { this.pos += 2; break; } this.pos++; } }; this.BackPos = function() { if (this.type != this.enEndFile) this.pos = this.start; }; this.NotBackPos = function() { if (this.pos == this.start) this.PosNextItem(); }; this.PosNextToken = function() { this.WasEnter = false; while (true) { this.PosNextItem(); switch (this.type) { case this.enNewLine: this.WasEnter = true; break; case this.enSpaces: case this.enComments: break; default: return this.type; } } }; this.PosNextItem = function() { this.start = this.pos; if (this.pos >= this.buf.length) { this.type = this.enEndFile; return this.enEndFile; } var c = this.buf.charCodeAt(this.pos); var lex = this.lexTypeAll[c]; switch (lex) { case "L": this.bWasBackSlash = false; this.PosIdentifier(); this.value = this.buf.substring(this.start, this.pos); if (this.bWasBackSlash) this.value = this.FromBackSlashString(this.value); this.beforeRegExp = 65; this.type = this.enIndenifier; if (this.value == "in" || this.value == "of" || this.value == "instanceof") { return this.value; } return this.enIndenifier; case "N": this.PosNumber(); this.value = this.buf.substring(this.start, this.pos); this.beforeRegExp = 48; this.type = this.enNumber; return this.enNumber; case "S": this.PosSpaces(); this.type = this.enSpaces; return this.enSpaces; case "M": this.PosNewLines(); this.type = this.enNewLine; return this.enNewLine; case "C": var s = this.buf[this.pos]; switch (s) { case '"': case "'": this.bWasBackSlash = false; this.PosString(); this.value = this.buf.substring(this.start, this.pos); this.beforeRegExp = 65; this.type = this.enString; return this.enString; case "/": var s2 = this.buf[this.pos + 1]; if (s2 == '/') { this.PosCommentsOneLine(); if (!this.CommentIgnore && this.lastComment <= this.start) { this.lastComment = this.start + 1; this.value = this.buf.substring(this.start, this.pos); this.AddToStream(this.value); this.AddToStream("\n"); } this.type = this.enComments; return this.enComments; } else if (s2 == '*') { this.PosCommentsMultiLine(); if (!this.CommentIgnore && this.lastComment <= this.start) { this.lastComment = this.start + 1; this.value = this.buf.substring(this.start, this.pos); this.AddToStream(this.value); if (this.buf[this.pos] == "\n") { this.AddToStream("\n"); this.pos++; } } this.type = this.enComments; return this.enComments; } else if (this.lexTypeRegStart[this.beforeRegExp] == "R") { this.PosRegExp(); this.beforeRegExp = 65; while ("gmi".indexOf(this.buf[this.pos]) >= 0) { this.pos++; } this.value = this.buf.substring(this.start, this.pos); this.type = this.enRegular; return this.enRegular; } s += this.AddNextOperator("="); break; case "/": this.beforeRegExp = 0; s += this.AddNextOperator("="); break; case "=": s += this.AddNextOperator("="); s += this.AddNextOperator("="); break; case ">": s += this.AddNextOperator(">"); s += this.AddNextOperator("="); if (s == ">>=") break; s += this.AddNextOperator(">"); s += this.AddNextOperator("="); break; case "<": s += this.AddNextOperator("<"); s += this.AddNextOperator("="); break; case "!": s += this.AddNextOperator("="); s += this.AddNextOperator("="); break; case "~": break; case "+": s += this.AddNextOperator("+"); if (s == "++") break; s += this.AddNextOperator("="); break; case "-": s += this.AddNextOperator("-"); if (s == "--") break; s += this.AddNextOperator("="); break; case "*": s += this.AddNextOperator("="); break; case "&": s += this.AddNextOperator("&"); if (s == "&&") break; s += this.AddNextOperator("="); break; case "|": s += this.AddNextOperator("|"); if (s == "||") break; s += this.AddNextOperator("="); break; case "^": s += this.AddNextOperator("="); break; case "%": s += this.AddNextOperator("="); break; case ".": var c2 = this.buf.charCodeAt(this.pos + 1); if (this.lexTypeNumbers[c2]) { this.pos++; this.PosNumber(); this.value = this.buf.substring(this.start, this.pos); this.beforeRegExp = 48; this.type = this.enNumber; return this.enNumber; } break; } this.beforeRegExp = c; this.value = s; this.pos++; this.type = s; return s; default: this.Error("Unrecognize symbol: '%1'", c); } this.type = this.enNewLine; return this.enNewLine; }; this.AddNextOperator = function(find) { var s2 = this.buf[this.pos + 1]; if (s2 == find) { this.pos++; return s2; } else { return ""; } }; this.ParseLexem = function(Code, bWrite) { this.Clear(); this.buf = Code; this.beforeRegExp = 61; var AllStr = ""; while (true) { var type = this.PosNextItem(); if (type == this.enEndFile) break; if (bWrite) { AllStr = AllStr + this.value + "\n"; } } if (AllStr) { console.log(AllStr); } return AllStr; }; this.ParseLexem2 = function(Code) { this.Clear(); this.buf = Code; this.beforeRegExp = 61; var n = 0; var Value1 = new Uint32Array(Code.length); var Value2 = new Uint32Array(Code.length); while (true) { var type = this.PosNextItem(); if (type == this.enEndFile) break; Value1[n] = this.start; Value2[n] = this.pos; n++; } return { Value1: Value1, Value2: Value2 }; }; this.ParseCode = function(Code) { this.Clear(); this.buf = Code; this.ParseSmart(); }; this.ParseSmart = function() { var bPublic = 0; while (true) { var type = this.PosNextToken(); if (type === this.enEndFile) break; if (type === this.enString && this.value === '"public"') { bPublic = 1; continue; } if (this.value === "function") { var FuncName = this.Parse_function(0, 1); if (bPublic) this.ExternMap[FuncName] = bPublic; bPublic = 0; this.AddNewLineToStream(";\n"); } else { this.Error("Require 'function' indenifier"); } } }; this.ParseBlock = function(sConditions, bOneIteration, bSimpleMode, bNotCheck) { if (!bOneIteration) this.BlockLevel++; var WasIgnoreCodeLevel = this.IgnoreCodeLevel; var bWasLabel = false; this.beforeRegExp = 61; Main: while (true) { var posSave = this.pos; var type = this.PosNextToken(); if (!bNotCheck && !bSimpleMode && !bWasLabel) { switch (type) { case ";": case ":": case "{": case "}": case this.enEndFile: break; case this.enIndenifier: default: this.AddCheckLineToStream(); } } switch (type) { case ";": bWasLabel = false; break; case ":": this.Error("Unexpected token: '%1'", this.GetTokenName(type)); bWasLabel = false; break; case "{": this.AddNewLineToStream("{\n", true); this.ParseBlock("}"); this.AddNewLineToStream("}\n", true); bWasLabel = false; break; case "}": break Main; case this.enEndFile: break Main; case this.enIndenifier: bNotCheck = false; var Name = this.value; var key = this.KeyWords[Name]; if (key == 1 || Name == "function") { this["Parse_" + this.ProcessWords[Name]](); if (!bSimpleMode) { this.AddNewLineToStream(";\n"); } type = this.type; break; } default: this.pos = posSave; type = this.ParseExpressionWithComma(false, false, true); if (type === ":") { bWasLabel = true; } else { bWasLabel = false; if (!bSimpleMode) { this.AddNewLineToStream(";\n"); } } } if (bOneIteration && type != ":") break; } if (sConditions) { if (sConditions.indexOf(type) == - 1) { this.Error("Error block closing. Unexpected token: '%1'", this.GetTokenName(type)); } } this.IgnoreCodeLevel = WasIgnoreCodeLevel; if (!bOneIteration) this.BlockLevel--; return type; }; this.ParseOneBlock = function() { var type = this.PosNextToken(); if (type == "{") { this.AddNewLineToStream("\n"); this.AddNewLineToStream("{\n", true); var type = this.ParseBlock("}"); this.AddNewLineToStream("}\n", true); } else if (type == ";") { if (this.InjectCheck) { this.AddCheckLineToStream(); this.AddNewLineToStream("\n"); } else this.AddNewLineToStream(";\n"); } else { if (this.InjectCheck) { this.AddNewLineToStream("\n"); this.AddNewLineToStream("{\n", true); this.BackPos(); var type = this.ParseBlock(false, true); this.AddNewLineToStream("}\n", true); } else { this.AddNewLineToStream("\n"); this.BackPos(); this.BlockLevel++; type = this.ParseBlock(false, true); this.BlockLevel--; } } if (type == ";") { this.NotBackPos(); } return type; }; this.ParseExpressionWithComma = function(sConditions, bCanEmpty, bCanLabel) { var sConditions2; if (sConditions) sConditions2 = "," + sConditions; while (true) { var prev = this.pos; var type = this.ParseExpression(sConditions2, bCanEmpty, bCanLabel); if (type != ",") break; if (prev == this.pos || !sConditions2) this.PosNextItem(); bCanLabel = false; if (this.CountCol <= this.PrintMargin) this.AddToStream(", "); else this.AddNewLineToStream(",\n", true); } return type; }; this.ParseExpression = function(sConditions, bCanEmpty, bCanLabel) { var WasPlus2 = this.WasPlus; var stream2 = this.stream; this.WasPlus = 0; this.stream = ""; var type = this.ParseExpression0(sConditions, bCanEmpty, bCanLabel); if (this.WasPlus) this.stream = stream2 + "CHKL(" + this.stream + ")"; else this.stream = stream2 + this.stream; this.WasPlus = WasPlus2; return type; }; this.ParseExpression0 = function(sConditions, bCanEmpty, bCanLabel) { var bWasExpr = false; var bCanDot = false; var bCanLeftSide = false; this.beforeRegExp = 61; Main: while (true) { var type = this.PosNextItem(); switch (type) { case this.enSpaces: case this.enComments: continue; case this.enNewLine: bCanLeftSide = false; this.WasEnter = true; continue; case this.enNumber: case this.enIndenifier: case this.enString: case this.enRegular: case "{": if (bWasExpr) break Main; } switch (type) { case this.enIndenifier: var Name = this.value; var key = this.KeyWords[Name]; if (key == 3) { this["Parse_" + this.ProcessWords[Name]](); } else if (key == 1 || key == 5) { type = this.enOperator; this.BackPos(); break Main; } else { if (!this.AllowedWords[Name]) Name = LOC_ADD_NAME + Name; this.AddToStream(Name); if (bCanLabel) { var posSave2 = this.pos; var type2 = this.PosNextToken(); if (type2 == ":") { type = type2; bWasExpr = true; this.AddNewLineToStream(":\n", true); return ":"; } else { this.pos = posSave2; } } } bCanLeftSide = true; bCanDot = true; bWasExpr = true; break; case this.enNumber: this.AddToStream(this.value); bCanLeftSide = false; bCanDot = true; bWasExpr = true; break; case this.enString: this.AddToStream(this.value); bCanLeftSide = false; bCanDot = true; bWasExpr = true; break; case this.enRegular: this.AddToStream(this.value); bCanLeftSide = false; bCanDot = true; bWasExpr = true; break; case "{": this.ParseDefObject(); bCanLeftSide = false; bCanDot = true; bWasExpr = true; break; case "[": this.ParseDefArray(); bCanLeftSide = true; bCanDot = true; bWasExpr = true; break; case "(": this.ParseFunctionCall(bCanDot); bCanLeftSide = true; bCanDot = true; bWasExpr = true; break; case ".": if (!bCanDot) this.Error("Unexpected token: '%1'", type); this.AddToStream("."); this.RequireIndenifier(); bCanLeftSide = true; bCanDot = true; bWasExpr = true; break; case "?": if (!bWasExpr) this.Error("Require expression before token: '%1'", type); this.ParseIfCondition(); bCanLeftSide = false; bCanDot = false; bWasExpr = true; break; case "=": case "+=": if (type === "+=") this.WasPlus = 1; if (!bCanLeftSide) this.Error("Unexpected token: '%1'", type); this.AddToStream(" " + type + " "); var type2 = this.ParseExpression(undefined, false, false); bCanLeftSide = false; bCanDot = false; bWasExpr = true; break; case "-=": case "*=": case "/=": case ">>=": case "<<=": case ">>>=": case "&=": case "|=": case "^=": case "%=": if (!bCanLeftSide) this.Error("Unexpected token: '%1'", type); this.AddToStream(" " + type + " "); bCanLeftSide = false; bCanDot = false; bWasExpr = false; break; case "!": this.AddToStream(type); bCanLeftSide = false; bCanDot = false; break; case "~": this.AddToStream(type); bCanLeftSide = false; bCanDot = false; break; case "==": case "===": case "!=": case "!==": case ">=": case "<=": case ">": case "<": case "~": case "^": case "&": case "|": case "<<": case ">>": case ">>>": case "%": case "*": case "/": case "&&": case "||": if (!bWasExpr) this.Error("Require expression before token: '%1'", type); bWasExpr = false; this.AddToStream(" " + type + " "); bCanLeftSide = false; bCanDot = false; break; case "-": case "+": if (type === "+") this.WasPlus = 1; bWasExpr = false; this.AddToStream(" " + type + " "); bCanLeftSide = false; bCanDot = false; break; case "++": case "--": if (this.WasEnter) if (bWasExpr) { type = ";"; break Main; } if (bWasExpr) if (!bCanDot) this.Error("Invalid left-side argument before token: '%1'", type); this.AddToStream(type); bCanLeftSide = false; bCanDot = false; break; case "in": case "of": case "instanceof": if (!bWasExpr) this.Error("Invalid argument before: '%1'", type); this.AddToStream(" " + type + " "); this.ParseExpressionWithComma(false, false); bWasExpr = true; bCanLeftSide = false; bCanDot = false; break; case ",": case ";": case ")": case "]": case "}": case ":": case this.enEndFile: break Main; default: this.Error("Unexpected token: '%1'", type); } this.WasEnter = false; } if (sConditions) { if (sConditions.indexOf(type) == - 1) { if (type == this.enOperator) this.Error("Unexpected keywords: '%1'", Name); else { var str = this.GetTokenName(type); if (str == type) this.Error("Error expression closing. Unexpected token: '%1'", str); else this.Error("Error expression closing. Unexpected %1", str); } } } else { this.BackPos(); } if (!bCanEmpty && !bWasExpr) { var str; if (type == this.enOperator) str = Name; else { str = this.GetTokenName(type); } if (str == type) this.Error("Require expression before token: '%1'", str); else this.Error("Require expression before: %1", str); } return type; }; this.GetTokenName = function(type) { switch (type) { case this.enNumber: return "number"; case this.enIndenifier: return "indenifier"; case this.enString: return "string"; case this.enRegular: return "regular"; case this.enEndFile: return "End of file"; default: return type; } }; this.RequireChar = function(sFind) { var type = this.PosNextToken(); if (type != sFind) this.Error("Require token: '%1'", sFind); }; this.RequireIndenifier = function(Name, DopStr) { var type = this.PosNextToken(); if (type != this.enIndenifier || (Name && this.value != Name)) { if (Name) this.Error("Require indenifier: '%1'", Name); else this.Error("Require indenifier"); } if (DopStr) this.AddToStream(DopStr + this.value); else this.AddToStream(this.value); return this.value; }; this.RequireIndenifierOptional = function() { var type = this.PosNextToken(); if (type != this.enIndenifier) { this.BackPos(); } else { this.AddToStream(" " + this.value); } }; this.HasEnter = function() { this.PosNextToken(); this.BackPos(); return this.WasEnter; }; this.Parse_var = function() { this.AddToStream("var "); while (true) { this.RequireIndenifier(undefined, LOC_ADD_NAME); var type = this.PosNextToken(); this.AddToStream(type); if (type === "=") this.ParseExpressionWithComma(false, false); if (type !== ",") { break; } } }; this.Parse_function = function(bGetSet, bFindExternal) { if (!bGetSet) { this.AddToStream("function "); } var FuncName; var type = this.PosNextToken(); if (type == this.enIndenifier) { FuncName = this.value; if (bGetSet) this.AddToStream(FuncName); else this.AddToStream(LOC_ADD_NAME + FuncName); type = this.PosNextToken(); } else if (bGetSet) { this.Error("Require name before: '%1'", type); } if (type != "(") this.Error("Require token: '%1'", "("); this.AddToStream("("); var bMustIdentifier = false; while (true) { type = this.PosNextToken(); if (type == this.enIndenifier) { var Name = this.value; this.AddToStream(LOC_ADD_NAME + Name); type = this.PosNextToken(); if (type == ",") { this.AddToStream(","); bMustIdentifier = true; continue; } bMustIdentifier = false; } else if (bMustIdentifier) { this.Error("Require indenifier"); break; } if (type == ")") break; this.Error("Require indenifier"); } if (FuncName && bFindExternal) { this.FunctionMap[FuncName] = 1; type = this.PosNextToken(); if (this.value === 'public') { this.ExternMap[FuncName] = 1; } else { this.BackPos(); } } this.RequireChar("{"); this.AddNewLineToStream(")\n", true); this.AddNewLineToStream("{\n", true); if (this.InjectCheck) { this.AddCheckLineToStream(30); } this.ParseBlock("}", false, false, false); this.AddNewLineToStream("\n"); this.AddToStream("}", "} "); return FuncName; }; this.ParseFunctionCall = function(bCanEmpty) { this.AddToStream("("); this.ParseExpressionWithComma(")", true); this.AddToStream(")"); }; this.Parse_void = function() { this.AddToStream("void "); var type = this.ParseExpression(); }; this.Parse_new = function() { this.AddToStream("new "); var type = this.ParseExpression(); }; this.Parse_delete = function() { this.AddToStream("delete "); this.ParseExpression(); }; this.ParseIfCondition = function() { this.AddToStream(" ? "); this.ParseExpression(":"); this.AddToStream(" : "); this.ParseExpression(); }; this.ParseDefArray = function() { this.AddToStream("["); this.ParseExpressionWithComma("]", true); this.AddToStream("]"); }; this.ParseDefObject = function() { this.BlockLevel++; this.AddToStream("{"); while (true) { var type = this.PosNextToken(); if (type == this.enIndenifier || type == this.enString || type == this.enNumber) { var Name = this.value; if (Name === "get" || Name === "set") { type = this.PosNextToken(); if (type == ":") { this.AddToStream(Name + ":"); type = this.ParseExpression(",}"); } else { this.AddToStream(Name + " "); this.BackPos(); this.Parse_function(true); type = this.PosNextToken(); } } else { this.RequireChar(":"); this.AddToStream(Name + ":"); type = this.ParseExpression(",}"); } } if (type == "}") break; else if (type == ",") { if (this.CountCol <= this.PrintMargin) this.AddToStream(", "); else this.AddNewLineToStream(",\n", true); continue; } else { this.Error("Unexpected token: '%1'", this.GetTokenName(type)); break; } } this.BlockLevel--; this.AddToStream("}", "} "); }; this.Parse_break = function() { this.AddToStream("break"); if (this.HasEnter()) return; this.RequireIndenifierOptional(); }; this.Parse_continue = function() { this.AddToStream("continue"); if (this.HasEnter()) return; this.RequireIndenifierOptional(); }; this.Parse_return = function() { this.AddToStream("return "); if (this.HasEnter()) return; this.ParseExpressionWithComma(false, true); }; this.Parse_typeof = function() { this.AddToStream("typeof "); this.ParseExpression(); }; this.Parse_for = function() { this.AddToStream("for("); this.RequireChar("("); var bForInMode = false; var bWasVar = false; var bWasName; var posSave = this.pos; var type = this.PosNextToken(); if (type == this.enIndenifier) { if (this.value == "var") { type = this.PosNextToken(); bWasVar = true; } if (type == this.enIndenifier) { bWasName = this.value; type = this.PosNextToken(); if (type == this.enIndenifier && (this.value == "in" || this.value == "of")) bForInMode = true; } } if (bForInMode) { if (bWasVar) this.AddToStream("var "); this.AddToStream(LOC_ADD_NAME + bWasName + " " + this.value + " "); } else { this.pos = posSave; var type = this.ParseBlock(";", true, true); if (type == ";") this.NotBackPos(); this.AddToStream("; "); this.ParseExpressionWithComma(";", true); this.AddToStream("; "); } this.ParseExpressionWithComma(")", true); this.AddToStream(")"); this.ParseOneBlock(); }; this.Parse_while = function() { this.RequireChar("("); this.AddToStream("while("); this.ParseExpressionWithComma(")"); this.AddToStream(")"); this.ParseOneBlock(); }; this.Parse_do = function() { this.AddToStream("do"); this.ParseOneBlock(); this.RequireIndenifier("while"); this.RequireChar("("); this.AddToStream("("); this.ParseExpressionWithComma(")"); this.AddToStream(")"); }; this.Parse_if = function() { this.AddToStream("if("); this.RequireChar("("); this.ParseExpressionWithComma(")"); this.AddToStream(")"); this.ParseOneBlock(); var type = this.PosNextToken(); if (type == this.enIndenifier && this.ProcessWords[this.value] == "else") { this.AddToStream("else"); this.ParseOneBlock(); } else { this.BackPos(); } }; this.Parse_switch = function() { this.RequireChar("("); this.AddToStream("switch("); this.ParseExpressionWithComma(")"); this.RequireChar("{"); this.AddNewLineToStream(")\n", true); this.AddNewLineToStream("{\n", true); this.BlockLevel++; this.ParseBlock("}", false, false, true); this.BlockLevel--; this.AddNewLineToStream("}\n", true); }; this.Parse_case = function() { this.BlockLevel--; this.AddToStream("case "); this.ParseExpressionWithComma(":"); this.AddNewLineToStream(":\n", true); this.BlockLevel++; }; this.Parse_default = function() { this.RequireChar(":"); this.BlockLevel--; this.AddNewLineToStream("default:\n", true); this.BlockLevel++; }; this.Parse_with = function() { this.RequireChar("("); this.AddToStream("with("); this.ParseExpressionWithComma(")"); this.AddToStream(")"); this.ParseOneBlock(); }; this.Parse_try = function() { this.Error("try-catch not support"); return; this.RequireChar("{"); this.AddToStream("try\n"); this.AddNewLineToStream("{\n", true); this.ParseBlock("}"); this.AddNewLineToStream("}\n", true); var type = this.PosNextToken(); if (type == this.enIndenifier && this.ProcessWords[this.value] == "catch") { this.AddToStream("catch("); this.RequireChar("("); this.RequireIndenifier(); this.RequireChar(")"); this.AddNewLineToStream(")\n", true); this.AddNewLineToStream("{\n", true); this.RequireChar("{"); this.ParseBlock("}"); this.AddToStream("}"); type = this.PosNextToken(); } if (type == this.enIndenifier && this.ProcessWords[this.value] == "finally") { this.RequireChar("{"); this.AddNewLineToStream("\n"); this.AddNewLineToStream("finally\n", true); this.AddNewLineToStream("{\n", true); this.ParseBlock("}"); this.AddToStream("}"); } else { this.BackPos(); } }; this.Parse_throw = function() { this.AddToStream("throw "); if (this.HasEnter()) return; var type = this.ParseExpressionWithComma(); }; this.AddCheckLineToStream = function(Count) { if (this.InjectCheck) { if (!Count) Count = 1; this.CalculateLineNumber(); this.AddToStream("DO(" + Count + ");"); } }; this.CalculateLineNumber = function() { for (var i = this.posLineNumber; i < this.pos; i++) if (this.buf[i] == "\n") this.LineNumber++; this.posLineNumber = this.pos; }; this.CalculateLineNumber0 = function(str) { for (var i = 0; i < str.length; i++) if (str[i] == "\n") this.LineNumber++; }; this.AddCheckToStream = function(str) { if (this.InjectCheck) { this.AddToStream(str); } }; this.AddToStreamSimple = function(str, strMustLast) { if (strMustLast) this.LastStreamValue = strMustLast; else this.LastStreamValue = str; if (!this.IgnoreCodeLevel) this.stream += str; }; this.AddToStreamAddTab = function(str, strMustLast) { if (this.LastStreamValue[this.LastStreamValue.length - 1] == "\n") { this.CountCol = 0; if (!this.IgnoreCodeLevel) this.stream += this.SpacesArray[this.BlockLevel >= 100 ? 99 : this.BlockLevel]; } if (str[str.length - 1] == "\n") { this.CountCol = 0; } else { this.CountCol += str.length; } this.AddToStreamSimple(str, strMustLast); }; this.AddNewLineToStream = function(str, bAlways) { var sLast = this.LastStreamValue[this.LastStreamValue.length - 1]; if (bAlways || sLast != "\n") { if (str == ";\n" && (sLast == "}" || sLast == ";")) { this.AddToStream("\n"); } else { this.AddToStream(str); } } }; }; global.LexerJS = new module.exports();