/* * @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();