fcf-framework-core
Version:
Basic functions of the fcf framework 2.0
1,225 lines (1,206 loc) • 46.4 kB
JavaScript
(function() {
let STATE_END = 0;
const S_WAIT = STATE_END++;
const S_BACK = STATE_END++;
const S_NUMBER_START = STATE_END++;
const S_NUMBER_READ = STATE_END++;
const S_STRING = STATE_END++;
const S_ESTRING = STATE_END++;
const S_KEY_START = STATE_END++;
const S_KEY_READ = STATE_END++;
const S_OBJECT_START = STATE_END++;
const S_OBJECT_SIMPLE_READ = STATE_END++;
const S_OBJECT_RCLOSE = STATE_END++;
const S_OBJECT_CCLOSE = STATE_END++;
const S_OBJECT_NEXT = STATE_END++;
const S_ARRAY_START = STATE_END++;
const S_ARRAY_NEXT = STATE_END++;
const S_DOBJECT_START = STATE_END++;
const S_DOBJECT_NEXT = STATE_END++;
const S_DOBJECT_KEY = STATE_END++;
const S_COMMAND_READ = STATE_END++;
const S_UCOMMAND_READ = STATE_END++;
const S_BLOCK_OPEN = STATE_END++;
const S_BLOCK_CLOSE = STATE_END++;
const S_BLOCK_SELECT = STATE_END++;
const S_BLOCK_SELECTA = STATE_END++;
const KEYWORDS = {
"new": 1,
"typeof": 1,
"NaN": 1,
"Infinity": 1,
"undefined": 1,
"false": 1,
"true": 1,
"null": 1,
};
const UCOMMANDS = {
"-": "!-",
"!": "!",
"~": "~",
};
const COMMANDS = {
"*": { "": "*", "*": {"": "**"} },
"/": { "": "/" },
"%": { "": "%" },
"+": { "": "+" },
"-": { "": "-" },
"^": { "": "^" },
"|": { "": "|", "|": {"": "||"} },
"&": { "": "&", "&": {"": "&&"} },
"<": { "": "<", "=": {"": "<="}, "<": {"": "<<"} },
">": { "": ">", "=": {"": ">="}, ">": {"": ">>", ">": {"": ">>>"}} },
"!": { "=": {"": "!=", "=": {"": "!=="}} },
"=": { "=": {"": "==", "=": {"": "==="}} },
"i": { "n": {"": "in", "s": {"t": {"a": {"n": {"c": {"e": {"o": {"f": {"": "instanceof"}}}}}}}}} },
};
const WEIGHTS = {
"**": 14,
"*": 13,
"/": 13,
"%": 13,
"+": 12,
"-": 12,
"<<": 11,
">>": 11,
">>>": 11,
"<": 10,
"<=": 10,
">": 10,
">=": 10,
"instanceof": 9,
"in": 9,
"==": 9,
"!=": 9,
"===": 9,
"!==": 9,
"&": 8,
"^": 7,
"|": 6,
"&&": 5,
"||": 4,
};
const ARGS = {
"?": [3, 3],
"!-": [1, 1],
"!": [1, 1],
"~": [1, 1],
"b": [0, 1],
"bi": [1, 1],
"v": [1, 1],
"i": [1, 1],
"n": [1, 1],
"t": [1, 1],
"cmd": [1, 1],
"c": [0, Infinity],
"o": [1, Infinity],
"d": [0, Infinity],
"instanceof": [2, 2],
"in": [2, 2],
"di": [2, 2],
"a": [0, Infinity],
"k": [1, 1],
"**": [2, 2],
"*": [2, 2],
"/": [2, 2],
"%": [2, 2],
"+": [2, 2],
"-": [2, 2],
"<<": [2, 2],
">>": [2, 2],
">>>": [2, 2],
"<": [2, 2],
"<=": [2, 2],
">": [2, 2],
">=": [2, 2],
"==": [2, 2],
"!=": [2, 2],
"===": [2, 2],
"!==": [2, 2],
"&": [2, 2],
"^": [2, 2],
"|": [2, 2],
"&&": [2, 2],
"||": [2, 2],
};
const CHAR0 = '0'.charCodeAt(0);
const CHAR9 = '9'.charCodeAt(0);
const CHARa = 'a'.charCodeAt(0);
const CHARz = 'z'.charCodeAt(0);
const CHARA = 'A'.charCodeAt(0);
const CHARZ = 'Z'.charCodeAt(0);
const CHAR$ = '$'.charCodeAt(0);
const CHAR_ = '_'.charCodeAt(0);
const PROHIBITED_METHODS = {"__defineGetter__": 1, "__defineSetter__": 1, "__lookupGetter__": 1, "__lookupSetter__": 1};
module.exports = fcf.NDetails.inlineExecution = new (class {
execute(a_command, a_args) {
let instructions = typeof a_command == "object" ? a_command : this.parse(a_command);
let info = {
env: fcf.getConfiguration()._tokenizeEnvironment,
args: a_args,
command: a_command
};
return this._execute(info, instructions);
}
_resolve(a_path, a_env) {
for (let p of a_path) {
if (a_env === null && typeof a_env !== "object") {
return {c: false};
}
a_env = a_env[p];
}
return {r: a_env, c: true };
}
_execute(a_info, a_op) {
switch (a_op.t) {
case "b":
return this._execute(a_info, a_op.a[0]);
case "bi":
return this._execute(a_info, a_op.a[0]);
case "v":
return a_op.a[0];
case "cmd":
return this.execute(a_op.a[0], a_info.args);
case "n":
case "o":
{
let newComplete = false;
let isNew = a_op.t == "n";
let items = a_op.t == "n" ? a_op.a[0].a : a_op.a;
let sources = [a_info.args, a_info.env];
let lstObject;
let object;
let found;
let call = items.find((a_item)=>{ return a_item.t == "c" });
if (!call && isNew){
items = fcf.clone(items);
items.push({t:"c", a:[]});
call = true;
}
let calls;
let callsAll;
let directCall;
let lstKey;
let envInfo;
found = items[0].t != "i" ? 0 : -1;
if (call) {
calls = fcf.getConfiguration()._tokenizeFunctions;
callsAll = [];
}
if (found == -1) {
if (call) {
for(let i = 0; i < items.length; ++i) {
lstKey = this._execute(a_info, items[i]);
if (items[i+1].t == "i"){
if (calls.items["*"])
callsAll.push(calls.items["*"].functions)
calls = typeof calls.items[lstKey] == "object" ? calls.items[lstKey] : undefined;
} else {
if (calls.functions[lstKey] || calls.functions["*"]){
found = i;
}
break;
}
if (!calls)
break;
}
}
if (found == -1){
let fullFound = -1;
let shortFound = -1;
lstObject = undefined;
let isEnv = false;
for(let source of sources) {
envInfo = !call && isEnv ? fcf.getConfiguration()._tokenizeEnvironmentInfo : undefined;
isEnv = true;
object = source;
for (let i = 0; i < items.length && items[i].t == "i"; ++i) {
if ((typeof object !== "object" && typeof object !== "string") || object === null) {
shortFound = -1;
fullFound = -1;
envInfo = undefined;
break;
}
lstKey = this._execute(a_info, items[i]);
lstObject = object;
let exists = typeof object == "object" && lstKey in object ? true :
typeof object == "string" && (lstKey == "length" || !isNaN(lstKey)) ? true :
false;
if (envInfo) {
if (i == 0) {
envInfo = envInfo.parts[lstKey];
} else if (envInfo.parts[lstKey]){
envInfo = envInfo.parts[lstKey];
}
}
if (exists) {
fullFound = i;
} else {
fullFound = -1;
}
object = object[lstKey];
shortFound = i;
}
if (shortFound != -1 && found == -1) {
found = shortFound;
}
if (fullFound != -1){
found = fullFound;
break;
}
}
}
} else {
object = this._execute(a_info, items[0]);
}
if (found == -1) {
throw new fcf.Exception("ACCESS_FAILED_FIELD_TOKENIZE", {command: a_info.command});
}
if (!call && envInfo && envInfo.access === false) {
throw new fcf.Exception("ACCESS_FAILED_FIELD_TOKENIZE", {command: a_info.command});
}
++found;
for (let i = found; i < items.length; ++i) {
if (items[i].t == "c") {
let args = [];
for(let arg of items[i].a) {
args.push(this._execute(a_info, arg));
}
let callInfo;
let callInfoAll;
let globalObject = typeof global === "object" ? global : window;
let directCall = false;
if (calls) {
if (calls.functions[lstKey]){
callInfo = calls.functions[lstKey][calls.functions[lstKey].length-1];
directCall = true;
} else if (calls.functions["*"]){
callInfo = calls.functions["*"][calls.functions["*"].length-1];
directCall = true;
}
}
if (!callInfo) {
for(let c of callsAll) {
if (typeof c[lstKey] == "object") {
for(let ci of c[lstKey]) {
if (ci.class){
if (ci.class == "String") {
if (typeof lstObject == "string") {
callInfo = ci;
}
} else {
if (typeof ci.class == "string") {
let classItem = fcf.resolve(globalObject, ci.class);
try {
if (lstObject instanceof classItem){
callInfo = ci;
}
} catch(e){
}
} else if (typeof ci.class == "function") {
callInfo = ci;
}
}
} else {
callInfo = ci;
}
}
}
if (c["*"]) {
for(let ci of c["*"]) {
if (ci.class){
if (ci.class == "String") {
if (typeof lstObject == "string" && !PROHIBITED_METHODS[lstKey]) {
callInfoAll = ci;
}
} else {
if (typeof ci.class == "string" && !PROHIBITED_METHODS[lstKey]) {
let classItem = fcf.resolve(globalObject, ci.class);
try {
if (lstObject instanceof classItem){
callInfoAll = ci;
}
} catch(e){}
} else if (typeof ci.class == "function" && !PROHIBITED_METHODS[lstKey]){
callInfoAll = ci;
}
}
} else {
if (!PROHIBITED_METHODS[lstKey]) {
callInfoAll = ci;
}
}
}
}
}
}
if (!callInfo && callInfoAll){
callInfo = callInfoAll;
}
if (!callInfo){
throw new fcf.Exception("ACCESS_FAILED_FIELD_TOKENIZE", {command: a_info.command});
}
if (isNew && !newComplete){
lstObject = object;
if (directCall && callInfo.object) {
object = (callInfo.object[1] == "" ? globalObject : fcf.resolve(globalObject, callInfo.object[1]))[lstKey];
}
object = new object(...args);
newComplete = true;
} else {
let lst = object;
if (directCall && callInfo.object) {
lstObject = callInfo.object[1] == "" ? globalObject : fcf.resolve(globalObject, callInfo.object[1]);
object = lstObject[lstKey];
}
if (object === undefined || object === null){
throw new fcf.Exception("ACCESS_FAILED_FIELD_TOKENIZE", {command: a_info.command});
}
object = object.apply(lstObject, args);
lstObject = lst;
}
} else if (items[i].t == "i") {
if (!call) {
if ((typeof object != "object" && typeof object != "string") || object === null) {
throw new fcf.Exception("ACCESS_FAILED_FIELD_TOKENIZE", {command: a_info.command});
}
}
lstKey = this._execute(a_info, items[i]);
if (calls) {
if (calls.items["*"]){
callsAll.push(calls.items["*"].functions)
}
calls = typeof calls.items[lstKey] == "object" ? calls.items[lstKey] : undefined;
}
lstObject = object;
if (object !== null) {
object = object[lstKey];
}
} else {
lstObject = object;
object = this._execute(a_info, items[i]);
}
}
if (isNew && !newComplete){
object = new object();
}
return object;
}
case "d":
{
let object = {};
for(let di of a_op.a) {
object[this._execute(a_info, di.a[0])] = this._execute(a_info, di.a[1]);
}
return object;
}
break;
case "a":
{
let arr = [];
for(let itm of a_op.a) {
arr.push(this._execute(a_info, itm));
}
return arr;
}
break;
case "i":
return typeof a_op.a[0] != "object" ? a_op.a[0] : this._execute(a_info, a_op.a[0]);
case "instanceof":
return this._execute(a_info, a_op.a[0]) instanceof this._execute(a_info, a_op.a[1]);
case "in":
return this._execute(a_info, a_op.a[0]) in this._execute(a_info, a_op.a[1]);
case "t":
return typeof this._execute(a_info, a_op.a[0]);
case "?":
return this._execute(a_info, a_op.a[0]) ? this._execute(a_info, a_op.a[1]) : this._execute(a_info, a_op.a[2]);
case "!-":
return -this._execute(a_info, a_op.a[0]);
case "!":
return !this._execute(a_info, a_op.a[0]);
case "~":
return ~this._execute(a_info, a_op.a[0]);
case "**":
return this._execute(a_info, a_op.a[0]) ** this._execute(a_info, a_op.a[1]);
case "*":
return this._execute(a_info, a_op.a[0]) * this._execute(a_info, a_op.a[1]);
case "/":
return this._execute(a_info, a_op.a[0]) / this._execute(a_info, a_op.a[1]);
case "%":
return this._execute(a_info, a_op.a[0]) % this._execute(a_info, a_op.a[1]);
case "+":
return this._execute(a_info, a_op.a[0]) + this._execute(a_info, a_op.a[1]);
case "-":
return this._execute(a_info, a_op.a[0]) - this._execute(a_info, a_op.a[1]);
case "<<":
return this._execute(a_info, a_op.a[0]) << this._execute(a_info, a_op.a[1]);
case ">>":
return this._execute(a_info, a_op.a[0]) >> this._execute(a_info, a_op.a[1]);
case ">>>":
return this._execute(a_info, a_op.a[0]) >>> this._execute(a_info, a_op.a[1]);
case "<":
return this._execute(a_info, a_op.a[0]) < this._execute(a_info, a_op.a[1]);
case "<=":
return this._execute(a_info, a_op.a[0]) <= this._execute(a_info, a_op.a[1]);
case ">":
return this._execute(a_info, a_op.a[0]) > this._execute(a_info, a_op.a[1]);
case ">=":
return this._execute(a_info, a_op.a[0]) >= this._execute(a_info, a_op.a[1]);
case "==":
return this._execute(a_info, a_op.a[0]) == this._execute(a_info, a_op.a[1]);
case "!=":
return this._execute(a_info, a_op.a[0]) != this._execute(a_info, a_op.a[1]);
case "===":
return this._execute(a_info, a_op.a[0]) === this._execute(a_info, a_op.a[1]);
case "!==":
return this._execute(a_info, a_op.a[0]) !== this._execute(a_info, a_op.a[1]);
case "&":
return this._execute(a_info, a_op.a[0]) & this._execute(a_info, a_op.a[1]);
case "^":
return this._execute(a_info, a_op.a[0]) ^ this._execute(a_info, a_op.a[1]);
case "|":
return this._execute(a_info, a_op.a[0]) | this._execute(a_info, a_op.a[1]);
case "&&":
return this._execute(a_info, a_op.a[0]) && this._execute(a_info, a_op.a[1]);
case "||":
return this._execute(a_info, a_op.a[0]) || this._execute(a_info, a_op.a[1]);
default:
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_info.command});
break;
}
}
_popStack(a_command, a_stack) {
if (a_stack.length == 1 ||
!ARGS[a_stack[a_stack.length-1].t] ||
a_stack[a_stack.length-1].a.length < ARGS[a_stack[a_stack.length-1].t][0]) {
if (!a_stack[a_stack.length-1].r) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
}
a_stack.pop();
if (a_stack[a_stack.length-1].u) {
this._popStack(a_command, a_stack);
}
}
_pushArg(a_command, a_item, a_arg) {
let mc = ARGS[a_item.t][1];
if (a_item.a.length >= mc){
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
a_item.a.push(a_arg);
}
_isVarChar(a_char, a_isFirst) {
const cn = a_char !== undefined ? a_char.charCodeAt(0) : undefined;
return cn > 181 ||
(!a_isFirst && cn >= CHAR0 && cn <= CHAR9) ||
(cn >= CHARa && cn <= CHARz) ||
(cn >= CHARA && cn <= CHARZ) ||
cn === CHAR$ || cn === CHAR_;
}
parse(a_command){
a_command = fcf.str(a_command);
let state = S_WAIT;
let stack = [{t: "b", b: true, a: []}];
const cn0 = "0".charCodeAt(0);
const cn9 = "9".charCodeAt(0);
const cnd = ".".charCodeAt(0);
const cnq = "'".charCodeAt(0);
const cndq = "\"".charCodeAt(0);
const lengthWithZero = a_command.length+1;
let isBreak;
let lstState = -1;
let switches = [];
let nswitches = [];
for(let i = 0; i < lengthWithZero; ++i) {
do {
let c = a_command[i];
let cn = a_command.charCodeAt(i);
isBreak = true;
if (state != S_WAIT && lstState == S_WAIT) {
if (switches.length){
if (!switches[switches.length-1][state]){
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
} else {
--switches[switches.length-1][state];
}
}
if (nswitches.length){
for(let j = 0; j < nswitches.length; ++j) {
if (nswitches[j][state] && stack[stack.length-1].t == nswitches[j][state]){
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
}
nswitches = [];
}
}
lstState = state;
switch (state) {
case S_WAIT:
if (cn >= 0 && cn <= 32) {
continue;
} else if (c == "(") {
state = S_BLOCK_OPEN;
isBreak = false;
continue;
} else if (c == ")") {
for(let i = stack.length - 1; i >= 0; --i) {
if (stack[i].t == "c") {
state = S_OBJECT_CCLOSE;
break;
} else if (stack[i].t == "b") {
state = S_BLOCK_CLOSE;
break;
}
}
isBreak = false;
continue;
} else if (c == ",") {
let found;
for(let i = stack.length - 1; i >= 0; --i) {
if (stack[i].t == "a") {
while(stack[stack.length - 1].t != "a") {
this._popStack(a_command, stack);
}
found = true;
state = S_ARRAY_NEXT;
isBreak = false;
break;
} else if (stack[i].t == "d") {
while(stack[stack.length - 1].t != "d") {
this._popStack(a_command, stack);
}
found = true;
state = S_DOBJECT_NEXT;
isBreak = false;
break;
} else if (stack[i].t == "c") {
while(stack[stack.length - 1].t != "c") {
this._popStack(a_command, stack);
}
let ns = {};
ns[S_COMMAND_READ] = "c";
nswitches.push(ns);
found = true;
break;
}
}
if (!found) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
continue;
} else if (c == "?") {
state = S_BLOCK_SELECT;
isBreak = false;
continue;
} else if (c == "{") {
state = S_DOBJECT_START;
continue;
} else if (c == "}") {
state = S_DOBJECT_NEXT;
isBreak = false;
continue;
} else if (c == "[") {
state = S_ARRAY_START;
isBreak = false;
continue;
} else if (c == "]") {
let found = false;
for(let i = stack.length - 1; i >= 1; --i) {
if (stack[i].t == "i" || stack[i].t == "a"){
found = stack[i].t;
break;
}
}
if (found == "i") {
state = S_OBJECT_RCLOSE;
isBreak = false;
} else if (found == "a") {
state = S_ARRAY_NEXT;
isBreak = false;
} else {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
continue;
} else if (c == ":") {
for(let i = stack.length - 1; i >= 0; --i) {
if (i == 0) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
if (stack[i].t == "?") {
state = S_BLOCK_SELECTA;
isBreak = false;
break;
} else if (stack[i].t == "d"){
state = S_DOBJECT_NEXT;
isBreak = false;
break;
}
}
continue;
} else if (cn == cnq || cn == cndq) {
state = S_STRING;
isBreak = false;
continue;
} else if (c == "`") {
state = S_ESTRING;
isBreak = false;
continue;
} else if (cn >= cn0 && cn <= cn9) {
if (stack[stack.length - 1].a.length + 1 > ARGS[stack[stack.length - 1].t][1]) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
state = S_NUMBER_START;
isBreak = false;
continue;
} else if (a_command[i] == "i" && a_command[i+1] == "n" && (!this._isVarChar(a_command[i+2]) || (a_command[i+2] == "s" && a_command[i+3] == "t" && a_command[i+4] == "a" && a_command[i+5] == "n" && a_command[i+6] == "c" && a_command[i+7] == "e" && a_command[i+8] == "o" && a_command[i+9] == "f" && !this._isVarChar(a_command[i+10])))) {
state = S_COMMAND_READ;
isBreak = false;
} else if (this._isVarChar(c, true)) {
if (stack[stack.length - 1].t == "di" && !stack[stack.length - 1].a.length) {
state = S_KEY_START;
isBreak = false;
} else {
state = S_OBJECT_START;
isBreak = false;
}
} else if (isNaN(cn)) {
break;
} else if (stack[stack.length - 1].a.length != 0) {
if (stack[stack.length - 1].c && stack[stack.length - 1].a.length != 2 && UCOMMANDS[c]) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
} else if (stack[stack.length - 1].t == "di" && stack[stack.length - 1].a.length == 1 && UCOMMANDS[c]) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
} else if (stack[stack.length - 1].t == "?" && UCOMMANDS[c]) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
}
if (stack[stack.length - 1].t == "c" && UCOMMANDS[c]) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
}
if (stack[stack.length - 1].t == "a" && UCOMMANDS[c]) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
}
state = S_COMMAND_READ;
isBreak = false;
continue;
} else if (c in UCOMMANDS) {
state = S_UCOMMAND_READ;
isBreak = false;
continue;
} else {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
break;
case S_BLOCK_SELECT:
{
let fill = false;
let item = stack[stack.length - 1];
while(!item.b) {
this._popStack(a_command, stack);
item = stack[stack.length - 1];
}
let v = {t: "?", b: true, a: []};
this._pushArg(a_command, v, item.a[item.a.length-1]);
item.a[item.a.length-1] = v;
stack.push(v);
state = S_WAIT;
}
break;
case S_BLOCK_SELECTA:
{
let fill = false;
let item = stack[stack.length - 1];
while(item.t != "?" || (item.t == "?" && item.a.length == 3)) {
fill = true;
this._popStack(a_command, stack);
item = stack[stack.length - 1];
}
state = S_WAIT;
}
break;
case S_BLOCK_OPEN:
{
let v = {t: "b", b: true, a: []};
let o = {t: "o", a: [v]};
this._pushArg(a_command, stack[stack.length - 1], o);
stack.push(o);
stack.push(v);
state = S_WAIT;
}
break;
case S_BLOCK_CLOSE:
if (!stack[stack.length-1].a.length) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
while(stack[stack.length-1].t != "b") {
this._popStack(a_command, stack);
}
this._popStack(a_command, stack);
state = S_OBJECT_NEXT;
break;
case S_BACK:
state = S_WAIT;
isBreak = false;
continue;
break;
case S_UCOMMAND_READ:
{
let v = {t: UCOMMANDS[c], u: true, a: []};
this._pushArg(a_command, stack[stack.length - 1], v);
if (c == "-" && a_command[i - 1] == "-") {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
stack.push(v);
state = S_WAIT;
}
break;
case S_COMMAND_READ:
let lastCommand;
let lastIndex = i;
let commands = COMMANDS;
let j = i;
while(commands) {
if (!commands[a_command[j]]) {
break;
}
if (commands[a_command[j]][""]){
lastCommand = commands[a_command[j]][""];
lastIndex = j;
}
commands = commands[a_command[j]];
++j;
}
i = lastIndex;
if (!lastCommand) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
let newItm = {t: lastCommand, c: true, a: []};
let weight = WEIGHTS[lastCommand];
let stackItem = stack[stack.length - 1];
while(true) {
if (stack[stack.length-1].c && weight <= WEIGHTS[stack[stack.length-1].t]){
this._popStack(a_command, stack);
stackItem = stack[stack.length-1];
} else {
break;
}
}
let curItm = stackItem.a[stackItem.a.length-1];
this._pushArg(a_command, newItm, curItm);
stackItem.a[stackItem.a.length-1] = newItm;
stack.push(newItm);
state = S_WAIT;
break;
case S_NUMBER_START:
{
let v = {t: "v", a: [""]};
this._pushArg(a_command, stack[stack.length - 1], v);
stack.push(v);
state = S_NUMBER_READ;
isBreak = false;
break;
}
case S_NUMBER_READ:
if ((cn >= cn0 && cn <= cn9) || (stack[stack.length - 1].a[0].length && cn == cnd && !stack[stack.length - 1].dot)) {
if (cn == cnd) {
stack[stack.length - 1].dot = true;
}
stack[stack.length - 1].a[0] += c;
} else {
delete stack[stack.length - 1].dot;
stack[stack.length - 1].a[0] = parseFloat(stack[stack.length - 1].a[0]);
this._popStack(a_command, stack);
state = S_BACK;
isBreak = false;
}
break;
case S_KEY_START:
{
let v = {t: "v", a: [""]};
v.a[0] += c;
stack[stack.length - 1].a.push(v);
stack.push(v);
state = S_KEY_READ;
}
break;
case S_KEY_READ:
if (this._isVarChar(c)){
stack[stack.length - 1].a[0] += c;
} else {
this._popStack(a_command, stack);
state = S_WAIT;
isBreak = false;
}
break;
case S_ARRAY_START:
{
let v = {t: "a", e: false, a: []};
let o = {t: "o", a: [v]};
this._pushArg(a_command, stack[stack.length - 1], o);
stack.push(o);
stack.push(v);
state = S_WAIT;
}
break;
case S_ARRAY_NEXT:
{
if (c == "]") {
for(let i = stack.length-1; i >= 0; --i ) {
if (stack[i]) {
if (stack[i].t == "a") {
stack[i].e = true;
break;
}
this._popStack(a_command, stack);
}
}
this._popStack(a_command, stack);
state = S_OBJECT_NEXT;
} else if (c == ",") {
let ns = {};
ns[S_COMMAND_READ] = "a";
nswitches.push(ns);
for(let i = stack.length-1; i >= 0; --i ) {
if (stack[i]) {
if (stack[i].t == "a") {
break;
}
this._popStack(a_command, stack);
}
}
state = S_WAIT;
}
}
break;
case S_DOBJECT_START:
{
let v = {t: "d", e: false, a: [{t:"di", a:[]}]};
this._pushArg(a_command, stack[stack.length - 1], v);
stack.push(v);
stack.push(v.a[0]);
let s = {};
s[S_NUMBER_START] = 1;
s[S_STRING] = 1;
s[S_KEY_START] = 1;
s[S_DOBJECT_NEXT] = Infinity;
switches.push(s);
state = S_WAIT;
isBreak = false;
}
break;
case S_DOBJECT_NEXT:
{
let item;
for(let i = stack.length-1; i >= 0; --i ) {
if (stack[i].t == "d") {
item = stack[i];
break;
}
}
if (c == "}") {
if (item.a[item.a.length - 1].a.length == 0){
item.a[item.a.length - 1].r = true;
item.a.pop();
}
for(let i = stack.length-1; i >= 0; --i ) {
if (stack[i]) {
if (stack[i].t == "d") {
break;
}
this._popStack(a_command, stack);
}
}
this._popStack(a_command, stack);
if (!item){
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
item.e = true;
state = S_WAIT;
switches.pop();
} else if (c == ",") {
let v = {t:"di", a:[]};
for(let i = stack.length-1; i >= 0; --i ) {
if (stack[i]) {
if (stack[i].t == "d") {
break;
}
this._popStack(a_command, stack);
}
}
stack.push(v);
this._pushArg(a_command, item, v);
let s = {};
s[S_NUMBER_START] = 1;
s[S_STRING] = 1;
s[S_KEY_START] = 1;
s[S_DOBJECT_NEXT] = Infinity;
switches.push(s);
state = S_WAIT;
isBreak = true;
} else if (c == ":") {
if (item.a[item.a.length - 1].a.length != 1){
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
state = S_WAIT;
switches.pop();
}
}
break;
case S_OBJECT_START:
{
let v = {t: "o", a: []};
this._pushArg(a_command, stack[stack.length - 1], v);
stack.push(v);
state = S_OBJECT_SIMPLE_READ;
isBreak = false;
break;
}
break;
case S_OBJECT_SIMPLE_READ:
{
let item = stack[stack.length - 1];
let name = "";
for(; i < a_command.length && this._isVarChar(a_command[i]); ++i) {
name += a_command[i];
}
this._pushArg(a_command, item, { t: "i", a: [name] });
state = S_OBJECT_NEXT;
isBreak = false;
break;
}
break;
case S_OBJECT_NEXT:
{
let item = stack[stack.length - 1];
for(; i < a_command.length && a_command.charCodeAt(i) <= 32 ; ++i);
if (item.a.length == 1 && item.a[0].t == "i" && item.a[0].a[0] in KEYWORDS) {
let keyword = item.a[0].a[0];
if (keyword == "typeof"){
item.t = "t";
item.u = true;
item.a = [];
} else if (keyword == "new") {
item.t = "n";
item.u = true;
item.a = [];
} else {
item.t = "v";
item.a= [(
keyword === "NaN" ? NaN :
keyword === "Infinity" ? Infinity :
keyword === "undefined" ? undefined :
keyword === "null" ? null :
keyword === "false" ? false :
true
)];
this._popStack(a_command, stack);
}
state = S_WAIT;
isBreak = false;
} else if (a_command[i] == ".") {
++i;
for(; i < a_command.length && a_command.charCodeAt(i) <= 32 ; ++i);
if (!this._isVarChar(a_command[i])) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
state = S_OBJECT_SIMPLE_READ;
isBreak = false;
} else if (a_command[i] == "[") {
let arg = {t: "i", b: true, e: false, a: []};
this._pushArg(a_command, item, arg);
stack.push(arg);
state = S_WAIT;
} else if (a_command[i] == "(") {
let arg = {t: "c", b: true, e: false, a: []};
this._pushArg(a_command, item, arg);
stack.push(arg);
state = S_WAIT;
} else {
this._popStack(a_command, stack);
state = S_WAIT;
isBreak = false;
}
}
break;
case S_OBJECT_RCLOSE:
{
while (stack[stack.length - 1].t != "i") {
this._popStack(a_command, stack);
}
this._popStack(a_command, stack);
state = S_OBJECT_NEXT;
}
break;
case S_OBJECT_CCLOSE:
{
let item = stack[stack.length - 1];
item.e = true;
while (item.t != "c") {
this._popStack(a_command, stack);
item = stack[stack.length - 1];
}
this._popStack(a_command, stack);
state = S_OBJECT_NEXT;
}
break;
case S_ESTRING:
case S_STRING:
{
let v = {t: "v", a: [""]};
let rootv = v;
let c = a_command[i];
let eq = c;
let sc = 0;
++i;
c = a_command[i];
const SPEC_CHARS = {
"n": "\n",
"b": "\b",
"r": "\r",
"n": "\n",
"\"": "\"",
"'": "'",
"f": "\f",
"t": "\t",
};
function specChar(i) {
let c = a_command[i];
if (c in SPEC_CHARS) {
v.a[0] += SPEC_CHARS[c];
} else if (c.charCodeAt(0) >= CHAR0 && c.charCodeAt(0) <= "7".charCodeAt(0)) {
let ss = "";
let sn = -1;
for(let j = 0; j < 4 && (i+j) < a_command.length; ++j) {
let sss = ss;
let c = a_command[i+j];
let cn = c.charCodeAt(0);
if (cn < CHAR0 || cn > "7".charCodeAt(0)) {
break;
}
sss += c;
let ssn = parseInt(sss, 8);
if (ssn < 0 || ssn > 255) {
break;
}
ss = sss;
sn = ssn;
}
if (sn != -1){
v.a[0] += String.fromCharCode(sn)
}
if (ss.length) {
i += ss.length - 1;
}
} else if (c == "u" || c == "x") {
let l = 0;
let maxLen = c == "x" ? 2 : 4;
for(let c = a_command.charCodeAt((i+1) + l);
l <= maxLen &&
((i+1) + l) < a_command.length &&
(
(c >= CHAR0 && c <= CHAR9) ||
(c >= CHARa && c <= 'f'.charCodeAt(0)) ||
(c >= CHARA && c <= 'F'.charCodeAt(0))
)
;
++l);
if (l) { --l };
let n = parseInt(a_command.substr(i+1, l), 16);
if (!isNaN(n)) {
v.a[0] += String.fromCharCode(n)
}
i += l;
} else {
v.a[0] += c;
}
return i;
}
while (i < a_command.length && !(c == eq && sc % 2 == 0)) {
if (c == "\\") {
if (sc % 2 == 1) {
v.a[0] += c;
}
++sc;
} else if (sc % 2 == 1) {
i = specChar(i);
sc = 0;
} else if (c == "$" && a_command[i+1] == "{" && (sc % 2 == 0) && state == S_ESTRING) {
let isc = 0;
v.t = "+";
let container = {
t: "+",
a: [
{
t: "cmd",
a: [""],
},
{
t: "v",
a: [""],
},
],
};
v.a[0] = {
t: "v",
a: [ v.a[0] ]
};
v.a[1] = container;
v = container.a[0];
for(i += 2; i < a_command.length; ++i) {
c = a_command[i];
if (c == "\\") {
if (isc % 2 == 1) {
v.a[0] += c;
}
++isc;
} else if (c == "}" && (isc % 2) == 0) {
break;
} else if ((isc % 2) == 1) {
i = specChar(i);
isc = 0;
} else {
v.a[0] += c;
}
}
v = container.a[1];
sc = 0;
} else {
sc = 0;
v.a[0] += c;
}
++i;
c = a_command[i];
}
if (i == a_command.length) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
let o = {t: "o", a: [rootv]};
this._pushArg(a_command, stack[stack.length - 1], o);
stack.push(o);
state = S_OBJECT_NEXT;
}
break;
}
} while(!isBreak);
}
if (!stack.length) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
for(let i = 1; i < stack.length; ++i) {
if (stack[i].a.length < ARGS[stack[i].t][0] || stack[i].e === false) {
throw new fcf.Exception("INVALID_COMMAND_TOKENIZE_INTERPETER", {command: a_command});
}
}
return stack[0];
}
})();
})();