mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-10 15:04:03 +09:00
basic: stmt-level indexing successfully wip
This commit is contained in:
491
assets/basic.js
491
assets/basic.js
@@ -76,7 +76,7 @@ lang.illegalType = function(line, obj) {
|
|||||||
lang.refError = function(line, obj) {
|
lang.refError = function(line, obj) {
|
||||||
serial.printerr(`${line} Unresolved reference:`);
|
serial.printerr(`${line} Unresolved reference:`);
|
||||||
serial.printerr(` object: ${obj}, typeof: ${typeof obj}`);
|
serial.printerr(` object: ${obj}, typeof: ${typeof obj}`);
|
||||||
serial.printerr(` entries: ${Object.entries(obj)}`);
|
if (obj !== null && obj !== undefined) serial.printerr(` entries: ${Object.entries(obj)}`);
|
||||||
return Error("Unresolved reference" + ((obj !== undefined) ? ` "${obj}"` : "") + ((line !== undefined) ? (" in "+line) : ""));
|
return Error("Unresolved reference" + ((obj !== undefined) ? ` "${obj}"` : "") + ((line !== undefined) ? (" in "+line) : ""));
|
||||||
};
|
};
|
||||||
lang.nowhereToReturn = function(line) { return "RETURN without GOSUB in " + line; };
|
lang.nowhereToReturn = function(line) { return "RETURN without GOSUB in " + line; };
|
||||||
@@ -273,20 +273,20 @@ let argCheckErr = function(lnum, o) {
|
|||||||
if (o === undefined || o.troType == "null") throw lang.refError(lnum, o);
|
if (o === undefined || o.troType == "null") throw lang.refError(lnum, o);
|
||||||
if (o.troType == "lit" && bStatus.vars[o.troValue] === undefined) throw lang.refError(lnum, o);
|
if (o.troType == "lit" && bStatus.vars[o.troValue] === undefined) throw lang.refError(lnum, o);
|
||||||
}
|
}
|
||||||
let oneArg = function(lnum, args, action) {
|
let oneArg = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
var rsvArg0 = resolve(args[0]);
|
var rsvArg0 = resolve(args[0]);
|
||||||
return action(rsvArg0);
|
return action(rsvArg0);
|
||||||
}
|
}
|
||||||
let oneArgNum = function(lnum, args, action) {
|
let oneArgNum = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
var rsvArg0 = resolve(args[0]);
|
var rsvArg0 = resolve(args[0]);
|
||||||
if (isNaN(rsvArg0)) throw lang.illegalType(lnum, args[0]);
|
if (isNaN(rsvArg0)) throw lang.illegalType(lnum, args[0]);
|
||||||
return action(rsvArg0);
|
return action(rsvArg0);
|
||||||
}
|
}
|
||||||
let twoArg = function(lnum, args, action) {
|
let twoArg = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
var rsvArg0 = resolve(args[0]);
|
var rsvArg0 = resolve(args[0]);
|
||||||
@@ -294,7 +294,7 @@ let twoArg = function(lnum, args, action) {
|
|||||||
var rsvArg1 = resolve(args[1]);
|
var rsvArg1 = resolve(args[1]);
|
||||||
return action(rsvArg0, rsvArg1);
|
return action(rsvArg0, rsvArg1);
|
||||||
}
|
}
|
||||||
let twoArgNum = function(lnum, args, action) {
|
let twoArgNum = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
var rsvArg0 = resolve(args[0]);
|
var rsvArg0 = resolve(args[0]);
|
||||||
@@ -304,7 +304,7 @@ let twoArgNum = function(lnum, args, action) {
|
|||||||
if (isNaN(rsvArg1)) throw lang.illegalType(lnum, "RH:"+Object.entries(args[1]));
|
if (isNaN(rsvArg1)) throw lang.illegalType(lnum, "RH:"+Object.entries(args[1]));
|
||||||
return action(rsvArg0, rsvArg1);
|
return action(rsvArg0, rsvArg1);
|
||||||
}
|
}
|
||||||
let threeArg = function(lnum, args, action) {
|
let threeArg = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 3) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 3) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
var rsvArg0 = resolve(args[0]);
|
var rsvArg0 = resolve(args[0]);
|
||||||
@@ -314,7 +314,7 @@ let threeArg = function(lnum, args, action) {
|
|||||||
var rsvArg2 = resolve(args[2]);
|
var rsvArg2 = resolve(args[2]);
|
||||||
return action(rsvArg0, rsvArg1, rsvArg2);
|
return action(rsvArg0, rsvArg1, rsvArg2);
|
||||||
}
|
}
|
||||||
let threeArgNum = function(lnum, args, action) {
|
let threeArgNum = function(lnum, stmtnum, args, action) {
|
||||||
if (args.length != 3) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 3) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
if (rsvArg0 === undefined) throw lang.refError(lnum, args[0]);
|
if (rsvArg0 === undefined) throw lang.refError(lnum, args[0]);
|
||||||
argCheckErr(lnum, args[0]);
|
argCheckErr(lnum, args[0]);
|
||||||
@@ -327,7 +327,7 @@ let threeArgNum = function(lnum, args, action) {
|
|||||||
if (isNaN(rsvArg2)) throw lang.illegalType(lnum, args[2]);
|
if (isNaN(rsvArg2)) throw lang.illegalType(lnum, args[2]);
|
||||||
return action(rsvArg0, rsvArg1, rsvArg2);
|
return action(rsvArg0, rsvArg1, rsvArg2);
|
||||||
}
|
}
|
||||||
let varArg = function(lnum, args, action) {
|
let varArg = function(lnum, stmtnum, args, action) {
|
||||||
var rsvArg = args.map((it) => {
|
var rsvArg = args.map((it) => {
|
||||||
argCheckErr(lnum, it);
|
argCheckErr(lnum, it);
|
||||||
var r = resolve(it);
|
var r = resolve(it);
|
||||||
@@ -335,7 +335,7 @@ let varArg = function(lnum, args, action) {
|
|||||||
});
|
});
|
||||||
return action(rsvArg);
|
return action(rsvArg);
|
||||||
}
|
}
|
||||||
let varArgNum = function(lnum, args, action) {
|
let varArgNum = function(lnum, stmtnum, args, action) {
|
||||||
var rsvArg = args.map((it) => {
|
var rsvArg = args.map((it) => {
|
||||||
argCheckErr(lnum, it);
|
argCheckErr(lnum, it);
|
||||||
var r = resolve(it);
|
var r = resolve(it);
|
||||||
@@ -424,7 +424,7 @@ let ForGen = function(s,e,t) {
|
|||||||
}
|
}
|
||||||
let bStatus = {};
|
let bStatus = {};
|
||||||
bStatus.gosubStack = [];
|
bStatus.gosubStack = [];
|
||||||
bStatus.forLnums = {}; // key: forVar, value: linenum
|
bStatus.forLnums = {}; // key: forVar, value: [lnum, stmtnum]
|
||||||
bStatus.forStack = []; // forVars only
|
bStatus.forStack = []; // forVars only
|
||||||
bStatus.vars = initBvars(); // contains instances of BasicVars
|
bStatus.vars = initBvars(); // contains instances of BasicVars
|
||||||
bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number
|
bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number
|
||||||
@@ -440,10 +440,14 @@ bStatus.getDimSize = function(array, dim) {
|
|||||||
}
|
}
|
||||||
return dims[dim];
|
return dims[dim];
|
||||||
};
|
};
|
||||||
bStatus.getArrayIndexFun = function(lnum, arrayName, array) {
|
bStatus.getArrayIndexFun = function(lnum, stmtnum, arrayName, array) {
|
||||||
return function(lnum, args, seps) {
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
|
return function(lnum, stmtnum, args, seps) {
|
||||||
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
// NOTE: BASIC arrays are index in column-major order, which is OPPOSITE of C/JS/etc.
|
// NOTE: BASIC arrays are index in column-major order, which is OPPOSITE of C/JS/etc.
|
||||||
return varArgNum(lnum, args, (dims) => {
|
return varArgNum(lnum, stmtnum, args, (dims) => {
|
||||||
if (TRACEON) serial.println("ar dims: "+dims);
|
if (TRACEON) serial.println("ar dims: "+dims);
|
||||||
|
|
||||||
let dimcnt = 1;
|
let dimcnt = 1;
|
||||||
@@ -468,9 +472,13 @@ bStatus.getArrayIndexFun = function(lnum, arrayName, array) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
bStatus.getDefunThunk = function(lnum, exprTree) {
|
bStatus.getDefunThunk = function(lnum, stmtnum, exprTree) {
|
||||||
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
let tree = JSON.parse(JSON.stringify(exprTree)); // ALWAYS create new tree instance!
|
let tree = JSON.parse(JSON.stringify(exprTree)); // ALWAYS create new tree instance!
|
||||||
return function(lnum, args, seps) {
|
return function(lnum, stmtnum, args, seps) {
|
||||||
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
let argsMap = [];
|
let argsMap = [];
|
||||||
args.map(it => {
|
args.map(it => {
|
||||||
argCheckErr(lnum, it);
|
argCheckErr(lnum, it);
|
||||||
@@ -507,7 +515,7 @@ bStatus.getDefunThunk = function(lnum, exprTree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// evaluate new tree
|
// evaluate new tree
|
||||||
return resolve(bF._executeSyntaxTree(lnum, tree, 0));
|
return resolve(bF._executeSyntaxTree(lnum, stmtnum, tree, 0));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bStatus.builtin = {
|
bStatus.builtin = {
|
||||||
@@ -518,7 +526,7 @@ bStatus.builtin = {
|
|||||||
if no args were given (e.g. "10 NEXT()"), args[0] will be: {troType: null, troValue: , troNextLine: 11}
|
if no args were given (e.g. "10 NEXT()"), args[0] will be: {troType: null, troValue: , troNextLine: 11}
|
||||||
if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||||
*/
|
*/
|
||||||
"=" : function(lnum, args) {
|
"=" : function(lnum, stmtnum, args) {
|
||||||
// THIS FUNCTION MUST BE COPIED TO 'INPUT'
|
// THIS FUNCTION MUST BE COPIED TO 'INPUT'
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
var troValue = args[0].troValue;
|
var troValue = args[0].troValue;
|
||||||
@@ -558,7 +566,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IN" : function(lnum, args) { // almost same as =, but don't actually make new variable. Used by FOR statement
|
"IN" : function(lnum, stmtnum, args) { // almost same as =, but don't actually make new variable. Used by FOR statement
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
var troValue = args[0].troValue;
|
var troValue = args[0].troValue;
|
||||||
|
|
||||||
@@ -575,56 +583,56 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return {asgnVarName: varname, asgnValue: rh};
|
return {asgnVarName: varname, asgnValue: rh};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"==" : function(lnum, args) {
|
"==" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (lh,rh) => lh == rh);
|
return twoArg(lnum, stmtnum, args, (lh,rh) => lh == rh);
|
||||||
},
|
},
|
||||||
"<>" : function(lnum, args) {
|
"<>" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (lh,rh) => lh != rh);
|
return twoArg(lnum, stmtnum, args, (lh,rh) => lh != rh);
|
||||||
},
|
},
|
||||||
"><" : function(lnum, args) {
|
"><" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (lh,rh) => lh != rh);
|
return twoArg(lnum, stmtnum, args, (lh,rh) => lh != rh);
|
||||||
},
|
},
|
||||||
"<=" : function(lnum, args) {
|
"<=" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh <= rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh <= rh);
|
||||||
},
|
},
|
||||||
"=<" : function(lnum, args) {
|
"=<" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh <= rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh <= rh);
|
||||||
},
|
},
|
||||||
">=" : function(lnum, args) {
|
">=" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh >= rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh >= rh);
|
||||||
},
|
},
|
||||||
"=>" : function(lnum, args) {
|
"=>" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh >= rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh >= rh);
|
||||||
},
|
},
|
||||||
"<" : function(lnum, args) {
|
"<" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh < rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh < rh);
|
||||||
},
|
},
|
||||||
">" : function(lnum, args) {
|
">" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh > rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh > rh);
|
||||||
},
|
},
|
||||||
"<<" : function(lnum, args) {
|
"<<" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh << rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh << rh);
|
||||||
},
|
},
|
||||||
">>" : function(lnum, args) {
|
">>" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh >> rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh >> rh);
|
||||||
},
|
},
|
||||||
"UNARYMINUS" : function(lnum, args) {
|
"UNARYMINUS" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => -lh);
|
return oneArgNum(lnum, stmtnum, args, (lh) => -lh);
|
||||||
},
|
},
|
||||||
"UNARYPLUS" : function(lnum, args) {
|
"UNARYPLUS" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => +lh);
|
return oneArgNum(lnum, stmtnum, args, (lh) => +lh);
|
||||||
},
|
},
|
||||||
"BAND" : function(lnum, args) {
|
"BAND" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh & rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh & rh);
|
||||||
},
|
},
|
||||||
"BOR" : function(lnum, args) {
|
"BOR" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh | rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh | rh);
|
||||||
},
|
},
|
||||||
"BXOR" : function(lnum, args) {
|
"BXOR" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh ^ rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh ^ rh);
|
||||||
},
|
},
|
||||||
"!" : function(lnum, args) { // Haskell-style CONS
|
"!" : function(lnum, stmtnum, args) { // Haskell-style CONS
|
||||||
return twoArg(lnum, args, (lh,rh) => {
|
return twoArg(lnum, stmtnum, args, (lh,rh) => {
|
||||||
if (isNaN(lh))
|
if (isNaN(lh))
|
||||||
throw lang.illegalType(lnum, lh); // BASIC array is numbers only
|
throw lang.illegalType(lnum, lh); // BASIC array is numbers only
|
||||||
if (!Array.isArray(rh))
|
if (!Array.isArray(rh))
|
||||||
@@ -632,8 +640,8 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return [lh].concat(rh);
|
return [lh].concat(rh);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"~" : function(lnum, args) { // array PUSH
|
"~" : function(lnum, stmtnum, args) { // array PUSH
|
||||||
return twoArg(lnum, args, (lh,rh) => {
|
return twoArg(lnum, stmtnum, args, (lh,rh) => {
|
||||||
if (isNaN(rh))
|
if (isNaN(rh))
|
||||||
throw lang.illegalType(lnum, rh); // BASIC array is numbers only
|
throw lang.illegalType(lnum, rh); // BASIC array is numbers only
|
||||||
if (!Array.isArray(lh))
|
if (!Array.isArray(lh))
|
||||||
@@ -641,8 +649,8 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return lh.concat([rh]);
|
return lh.concat([rh]);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"#" : function(lnum, args) { // array CONCAT
|
"#" : function(lnum, stmtnum, args) { // array CONCAT
|
||||||
return twoArg(lnum, args, (lh,rh) => {
|
return twoArg(lnum, stmtnum, args, (lh,rh) => {
|
||||||
if (!Array.isArray(rh))
|
if (!Array.isArray(rh))
|
||||||
throw lang.illegalType(lnum, rh);
|
throw lang.illegalType(lnum, rh);
|
||||||
if (!Array.isArray(lh))
|
if (!Array.isArray(lh))
|
||||||
@@ -650,37 +658,37 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return lh.concat(rh);
|
return lh.concat(rh);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"+" : function(lnum, args) { // addition, string concat
|
"+" : function(lnum, stmtnum, args) { // addition, string concat
|
||||||
return twoArg(lnum, args, (lh,rh) => (!isNaN(lh) && !isNaN(rh)) ? (lh*1 + rh*1) : (lh + rh));
|
return twoArg(lnum, stmtnum, args, (lh,rh) => (!isNaN(lh) && !isNaN(rh)) ? (lh*1 + rh*1) : (lh + rh));
|
||||||
},
|
},
|
||||||
"-" : function(lnum, args) {
|
"-" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh - rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh - rh);
|
||||||
},
|
},
|
||||||
"*" : function(lnum, args) {
|
"*" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh * rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh * rh);
|
||||||
},
|
},
|
||||||
"/" : function(lnum, args) {
|
"/" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => {
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => {
|
||||||
if (rh == 0) throw lang.divByZero;
|
if (rh == 0) throw lang.divByZero;
|
||||||
return lh / rh
|
return lh / rh
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"MOD" : function(lnum, args) {
|
"MOD" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => lh % rh);
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => lh % rh);
|
||||||
},
|
},
|
||||||
"^" : function(lnum, args) {
|
"^" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (lh,rh) => Math.pow(lh, rh));
|
return twoArgNum(lnum, stmtnum, args, (lh,rh) => Math.pow(lh, rh));
|
||||||
},
|
},
|
||||||
"TO" : function(lnum, args) {
|
"TO" : function(lnum, stmtnum, args) {
|
||||||
return twoArgNum(lnum, args, (from, to) => new ForGen(from, to, 1));
|
return twoArgNum(lnum, stmtnum, args, (from, to) => new ForGen(from, to, 1));
|
||||||
},
|
},
|
||||||
"STEP" : function(lnum, args) {
|
"STEP" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (gen, step) => {
|
return twoArg(lnum, stmtnum, args, (gen, step) => {
|
||||||
if (!(gen instanceof ForGen)) throw lang.illegalType(lnum, gen);
|
if (!(gen instanceof ForGen)) throw lang.illegalType(lnum, gen);
|
||||||
return new ForGen(gen.start, gen.end, step);
|
return new ForGen(gen.start, gen.end, step);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"DIM" : function(lnum, args) {
|
"DIM" : function(lnum, stmtnum, args) {
|
||||||
return varArgNum(lnum, args, (revdims) => {
|
return varArgNum(lnum, args, (revdims) => {
|
||||||
let dims = revdims.reverse();
|
let dims = revdims.reverse();
|
||||||
let arraydec = "Array(dims[0]).fill(0)";
|
let arraydec = "Array(dims[0]).fill(0)";
|
||||||
@@ -690,7 +698,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return eval(arraydec);
|
return eval(arraydec);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"PRINT" : function(lnum, args, seps) {
|
"PRINT" : function(lnum, stmtnum, args, seps) {
|
||||||
if (args.length == 0)
|
if (args.length == 0)
|
||||||
println();
|
println();
|
||||||
else {
|
else {
|
||||||
@@ -722,7 +730,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
|
|
||||||
if (args[args.length - 1] !== undefined && args[args.length - 1].troType != "null") println();
|
if (args[args.length - 1] !== undefined && args[args.length - 1].troType != "null") println();
|
||||||
},
|
},
|
||||||
"EMIT" : function(lnum, args, seps) {
|
"EMIT" : function(lnum, stmtnum, args, seps) {
|
||||||
if (args.length == 0)
|
if (args.length == 0)
|
||||||
println();
|
println();
|
||||||
else {
|
else {
|
||||||
@@ -755,39 +763,39 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
|
|
||||||
if (args[args.length - 1] !== undefined && args[args.length - 1].troType != "null") println();
|
if (args[args.length - 1] !== undefined && args[args.length - 1].troType != "null") println();
|
||||||
},
|
},
|
||||||
"POKE" : function(lnum, args) {
|
"POKE" : function(lnum, stmtnum, args) {
|
||||||
twoArgNum(lnum, args, (lh,rh) => sys.poke(lh, rh));
|
twoArgNum(lnum, args, (lh,rh) => sys.poke(lh, rh));
|
||||||
},
|
},
|
||||||
"PEEK" : function(lnum, args) {
|
"PEEK" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => sys.peek(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => sys.peek(lh));
|
||||||
},
|
},
|
||||||
"GOTO" : function(lnum, args) {
|
"GOTO" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
||||||
return lh;
|
return new JumpObj(lh, 0, lnum, lh);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"GOSUB" : function(lnum, args) {
|
"GOSUB" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
||||||
bStatus.gosubStack.push(lnum + 1);
|
bStatus.gosubStack.push([lnum, stmtnum + 1]);
|
||||||
//println(lnum+" GOSUB into "+lh);
|
//println(lnum+" GOSUB into "+lh);
|
||||||
return lh;
|
return new JumpObj(lh, 0, lnum, lh);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"RETURN" : function(lnum, args) {
|
"RETURN" : function(lnum, stmtnum, args) {
|
||||||
var r = bStatus.gosubStack.pop();
|
var r = bStatus.gosubStack.pop();
|
||||||
if (r === undefined) throw lang.nowhereToReturn(lnum);
|
if (r === undefined) throw lang.nowhereToReturn(lnum);
|
||||||
//println(lnum+" RETURN to "+r);
|
//println(lnum+" RETURN to "+r);
|
||||||
return r;
|
return new JumpObj(r[0], r[1], lnum, r);
|
||||||
},
|
},
|
||||||
"CLEAR" : function(lnum, args) {
|
"CLEAR" : function(lnum, stmtnum, args) {
|
||||||
bStatus.vars = initBvars();
|
bStatus.vars = initBvars();
|
||||||
},
|
},
|
||||||
"PLOT" : function(lnum, args) {
|
"PLOT" : function(lnum, stmtnum, args) {
|
||||||
threeArgNum(lnum, args, (xpos, ypos, color) => graphics.plotPixel(xpos, ypos, color));
|
threeArgNum(lnum, args, (xpos, ypos, color) => graphics.plotPixel(xpos, ypos, color));
|
||||||
},
|
},
|
||||||
"AND" : function(lnum, args) {
|
"AND" : function(lnum, stmtnum, args) {
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
var rsvArg = args.map((it) => resolve(it));
|
var rsvArg = args.map((it) => resolve(it));
|
||||||
rsvArg.forEach((v) => {
|
rsvArg.forEach((v) => {
|
||||||
@@ -800,7 +808,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
});
|
});
|
||||||
return argum[0] && argum[1];
|
return argum[0] && argum[1];
|
||||||
},
|
},
|
||||||
"OR" : function(lnum, args) {
|
"OR" : function(lnum, stmtnum, args) {
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
var rsvArg = args.map((it) => resolve(it));
|
var rsvArg = args.map((it) => resolve(it));
|
||||||
rsvArg.forEach((v) => {
|
rsvArg.forEach((v) => {
|
||||||
@@ -813,36 +821,36 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
});
|
});
|
||||||
return argum[0] || argum[1];
|
return argum[0] || argum[1];
|
||||||
},
|
},
|
||||||
"RND" : function(lnum, args) {
|
"RND" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (!(args.length > 0 && args[0].troValue === 0))
|
if (!(args.length > 0 && args[0].troValue === 0))
|
||||||
bStatus.rnd = Math.random();//(bStatus.rnd * 214013 + 2531011) % 16777216; // GW-BASIC does this
|
bStatus.rnd = Math.random();//(bStatus.rnd * 214013 + 2531011) % 16777216; // GW-BASIC does this
|
||||||
return bStatus.rnd;
|
return bStatus.rnd;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"ROUND" : function(lnum, args) {
|
"ROUND" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => Math.round(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => Math.round(lh));
|
||||||
},
|
},
|
||||||
"FLOOR" : function(lnum, args) {
|
"FLOOR" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => Math.floor(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => Math.floor(lh));
|
||||||
},
|
},
|
||||||
"INT" : function(lnum, args) { // synonymous to FLOOR
|
"INT" : function(lnum, stmtnum, args) { // synonymous to FLOOR
|
||||||
return oneArgNum(lnum, args, (lh) => Math.floor(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => Math.floor(lh));
|
||||||
},
|
},
|
||||||
"CEIL" : function(lnum, args) {
|
"CEIL" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => Math.ceil(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => Math.ceil(lh));
|
||||||
},
|
},
|
||||||
"FIX" : function(lnum, args) {
|
"FIX" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => (lh|0));
|
return oneArgNum(lnum, stmtnum, args, (lh) => (lh|0));
|
||||||
},
|
},
|
||||||
"CHR" : function(lnum, args) {
|
"CHR" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => String.fromCharCode(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => String.fromCharCode(lh));
|
||||||
},
|
},
|
||||||
"TEST" : function(lnum, args) {
|
"TEST" : function(lnum, stmtnum, args) {
|
||||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
return resolve(args[0]);
|
return resolve(args[0]);
|
||||||
},
|
},
|
||||||
"FOREACH" : function(lnum, args) { // list comprehension model
|
"FOREACH" : function(lnum, stmtnum, args) { // list comprehension model
|
||||||
var asgnObj = resolve(args[0]);
|
var asgnObj = resolve(args[0]);
|
||||||
// type check
|
// type check
|
||||||
if (asgnObj === undefined) throw lang.syntaxfehler(lnum);
|
if (asgnObj === undefined) throw lang.syntaxfehler(lnum);
|
||||||
@@ -856,10 +864,10 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
// stores entire array (sans head) into temporary storage
|
// stores entire array (sans head) into temporary storage
|
||||||
bStatus.vars["for var "+varname] = new BasicVar(asgnObj.asgnValue, "array");
|
bStatus.vars["for var "+varname] = new BasicVar(asgnObj.asgnValue, "array");
|
||||||
// put the varname to forstack
|
// put the varname to forstack
|
||||||
bStatus.forLnums[varname] = lnum;
|
bStatus.forLnums[varname] = [lnum, stmtnum];
|
||||||
bStatus.forStack.push(varname);
|
bStatus.forStack.push(varname);
|
||||||
},
|
},
|
||||||
"FOR" : function(lnum, args) { // generator model
|
"FOR" : function(lnum, stmtnum, args) { // generator model
|
||||||
var asgnObj = resolve(args[0]);
|
var asgnObj = resolve(args[0]);
|
||||||
// type check
|
// type check
|
||||||
if (asgnObj === undefined) throw lang.syntaxfehler(lnum);
|
if (asgnObj === undefined) throw lang.syntaxfehler(lnum);
|
||||||
@@ -874,10 +882,10 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
// stores entire array (sans head) into temporary storage
|
// stores entire array (sans head) into temporary storage
|
||||||
bStatus.vars["for var "+varname] = new BasicVar(generator, "generator");
|
bStatus.vars["for var "+varname] = new BasicVar(generator, "generator");
|
||||||
// put the varname to forstack
|
// put the varname to forstack
|
||||||
bStatus.forLnums[varname] = lnum;
|
bStatus.forLnums[varname] = [lnum, stmtnum];
|
||||||
bStatus.forStack.push(varname);
|
bStatus.forStack.push(varname);
|
||||||
},
|
},
|
||||||
"NEXT" : function(lnum, args) {
|
"NEXT" : function(lnum, stmtnum, args) {
|
||||||
// if no args were given
|
// if no args were given
|
||||||
if (args.length == 0 || (args.length == 1 && args.troType == "null")) {
|
if (args.length == 0 || (args.length == 1 && args.troType == "null")) {
|
||||||
// go to most recent FOR
|
// go to most recent FOR
|
||||||
@@ -899,7 +907,8 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
if ((bStatus.vars[forVarname].bvLiteral !== undefined)) {
|
if ((bStatus.vars[forVarname].bvLiteral !== undefined)) {
|
||||||
// feed popped value back, we're not done yet
|
// feed popped value back, we're not done yet
|
||||||
bStatus.forStack.push(forVarname);
|
bStatus.forStack.push(forVarname);
|
||||||
return bStatus.forLnums[forVarname] + 1;
|
let forLnum = bStatus.forLnums[forVarname]
|
||||||
|
return new JumpObj(forLnum[0], forLnum[1]+1, lnum, [forLnum[0], forLnum[1]+1]); // goto the statement RIGHT AFTER the FOR-declaration
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (forVar instanceof ForGen)
|
if (forVar instanceof ForGen)
|
||||||
@@ -907,14 +916,14 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
else
|
else
|
||||||
bStatus.vars[forVarname] === undefined; // unregister the variable
|
bStatus.vars[forVarname] === undefined; // unregister the variable
|
||||||
|
|
||||||
return lnum + 1;
|
return new JumpObj(lnum, stmtnum + 1, lnum, [lnum, stmtnum + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw lang.syntaxfehler(lnum, "extra arguments for NEXT");
|
throw lang.syntaxfehler(lnum, "extra arguments for NEXT");
|
||||||
},
|
},
|
||||||
"BREAKTO" : function(lnum, args) {
|
/*"BREAKTO" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
var forVarname = bStatus.forStack.pop();
|
var forVarname = bStatus.forStack.pop();
|
||||||
if (forVarname === undefined) {
|
if (forVarname === undefined) {
|
||||||
throw lang.nextWithoutFor(lnum);
|
throw lang.nextWithoutFor(lnum);
|
||||||
@@ -922,9 +931,9 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
if (TRACEON) serial.println(`[BASIC.FOR] breaking from ${forVarname}, jump to ${lh}`);
|
if (TRACEON) serial.println(`[BASIC.FOR] breaking from ${forVarname}, jump to ${lh}`);
|
||||||
|
|
||||||
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
if (lh < 0) throw lang.syntaxfehler(lnum, lh);
|
||||||
return lh;
|
return new JumpObj(lh, 0, lnum, lh);
|
||||||
});
|
});
|
||||||
},
|
},*/
|
||||||
/*
|
/*
|
||||||
10 input;"what is your name";a$
|
10 input;"what is your name";a$
|
||||||
|
|
||||||
@@ -962,7 +971,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
| `-----------------
|
| `-----------------
|
||||||
`-----------------
|
`-----------------
|
||||||
*/
|
*/
|
||||||
"INPUT" : function(lnum, args) {
|
"INPUT" : function(lnum, stmtnum, args) {
|
||||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||||
var troValue = args[0].troValue;
|
var troValue = args[0].troValue;
|
||||||
|
|
||||||
@@ -989,76 +998,76 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
return {asgnVarName: varname, asgnValue: rh};
|
return {asgnVarName: varname, asgnValue: rh};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"END" : function(lnum, args) {
|
"END" : function(lnum, stmtnum, args) {
|
||||||
serial.println("Program terminated in "+lnum);
|
serial.println("Program terminated in "+lnum);
|
||||||
return Number.MAX_SAFE_INTEGER; // GOTO far-far-away
|
return new JumpObj(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER - 1, lnum, undefined); // GOTO far-far-away
|
||||||
},
|
},
|
||||||
"SPC" : function(lnum, args) {
|
"SPC" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => " ".repeat(lh));
|
return oneArgNum(lnum, stmtnum, args, (lh) => " ".repeat(lh));
|
||||||
},
|
},
|
||||||
"LEFT" : function(lnum, args) {
|
"LEFT" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (str, len) => str.substring(0, len));
|
return twoArg(lnum, stmtnum, args, (str, len) => str.substring(0, len));
|
||||||
},
|
},
|
||||||
"MID" : function(lnum, args) {
|
"MID" : function(lnum, stmtnum, args) {
|
||||||
return threeArg(lnum, args, (str, start, len) => str.substring(start-INDEX_BASE, start-INDEX_BASE+len));
|
return threeArg(lnum, stmtnum, args, (str, start, len) => str.substring(start-INDEX_BASE, start-INDEX_BASE+len));
|
||||||
},
|
},
|
||||||
"RIGHT" : function(lnum, args) {
|
"RIGHT" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (str, len) => str.substring(str.length - len, str.length));
|
return twoArg(lnum, stmtnum, args, (str, len) => str.substring(str.length - len, str.length));
|
||||||
},
|
},
|
||||||
"SGN" : function(lnum, args) {
|
"SGN" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => (it > 0) ? 1 : (it < 0) ? -1 : 0);
|
return oneArgNum(lnum, stmtnum, args, (it) => (it > 0) ? 1 : (it < 0) ? -1 : 0);
|
||||||
},
|
},
|
||||||
"ABS" : function(lnum, args) {
|
"ABS" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.abs(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.abs(it));
|
||||||
},
|
},
|
||||||
"SIN" : function(lnum, args) {
|
"SIN" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.sin(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.sin(it));
|
||||||
},
|
},
|
||||||
"COS" : function(lnum, args) {
|
"COS" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.cos(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.cos(it));
|
||||||
},
|
},
|
||||||
"TAN" : function(lnum, args) {
|
"TAN" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.tan(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.tan(it));
|
||||||
},
|
},
|
||||||
"EXP" : function(lnum, args) {
|
"EXP" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.exp(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.exp(it));
|
||||||
},
|
},
|
||||||
"ASN" : function(lnum, args) {
|
"ASN" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.asin(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.asin(it));
|
||||||
},
|
},
|
||||||
"ACO" : function(lnum, args) {
|
"ACO" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.acos(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.acos(it));
|
||||||
},
|
},
|
||||||
"ATN" : function(lnum, args) {
|
"ATN" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.atan(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.atan(it));
|
||||||
},
|
},
|
||||||
"SQR" : function(lnum, args) {
|
"SQR" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.sqrt(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.sqrt(it));
|
||||||
},
|
},
|
||||||
"CBR" : function(lnum, args) {
|
"CBR" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.cbrt(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.cbrt(it));
|
||||||
},
|
},
|
||||||
"SINH" : function(lnum, args) {
|
"SINH" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.sinh(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.sinh(it));
|
||||||
},
|
},
|
||||||
"COSH" : function(lnum, args) {
|
"COSH" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.cosh(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.cosh(it));
|
||||||
},
|
},
|
||||||
"TANH" : function(lnum, args) {
|
"TANH" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.tanh(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.tanh(it));
|
||||||
},
|
},
|
||||||
"LOG" : function(lnum, args) {
|
"LOG" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (it) => Math.log(it));
|
return oneArgNum(lnum, stmtnum, args, (it) => Math.log(it));
|
||||||
},
|
},
|
||||||
"RESTORE" : function(lnum, args) {
|
"RESTORE" : function(lnum, stmtnum, args) {
|
||||||
DATA_CURSOR = 0;
|
DATA_CURSOR = 0;
|
||||||
},
|
},
|
||||||
"READ" : function(lnum, args) {
|
"READ" : function(lnum, stmtnum, args) {
|
||||||
let r = DATA_CONSTS.shift();
|
let r = DATA_CONSTS.shift();
|
||||||
if (r === undefined) throw lang.outOfData(lnum);
|
if (r === undefined) throw lang.outOfData(lnum);
|
||||||
},
|
},
|
||||||
"OPTIONBASE" : function(lnum, args) {
|
"OPTIONBASE" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||||
INDEX_BASE = lh|0;
|
INDEX_BASE = lh|0;
|
||||||
});
|
});
|
||||||
@@ -1066,22 +1075,22 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
"DATA" : function() { /*DATA must do nothing when encountered; they must be pre-processed*/ },
|
"DATA" : function() { /*DATA must do nothing when encountered; they must be pre-processed*/ },
|
||||||
/* Syopsis: MAP function, functor
|
/* Syopsis: MAP function, functor
|
||||||
*/
|
*/
|
||||||
"MAP" : function(lnum, args) {
|
"MAP" : function(lnum, stmtnum, args) {
|
||||||
return twoArg(lnum, args, (fn, functor) => {
|
return twoArg(lnum, stmtnum, args, (fn, functor) => {
|
||||||
// TODO test only works with DEFUN'd functions
|
// TODO test only works with DEFUN'd functions
|
||||||
if (fn.astLeaves === undefined) throw lang.badFunctionCallFormat("Only works with DEFUN'd functions yet");
|
if (fn.astLeaves === undefined) throw lang.badFunctionCallFormat("Only works with DEFUN'd functions yet");
|
||||||
if (functor.toArray === undefined && !Array.isArray(functor)) throw lang.syntaxfehler(lnum, functor);
|
if (functor.toArray === undefined && !Array.isArray(functor)) throw lang.syntaxfehler(lnum, functor);
|
||||||
// generator?
|
// generator?
|
||||||
if (functor.toArray) functor = functor.toArray();
|
if (functor.toArray) functor = functor.toArray();
|
||||||
|
|
||||||
return functor.map(it => bStatus.getDefunThunk(lnum, fn)(lnum, [it]));
|
return functor.map(it => bStatus.getDefunThunk(lnum, stmtnum, fn)(lnum, stmtnum, [it]));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Synopsis: FOLD function, init_value, functor
|
/* Synopsis: FOLD function, init_value, functor
|
||||||
* a function must accept two arguments, of which first argument will be an accumulator
|
* a function must accept two arguments, of which first argument will be an accumulator
|
||||||
*/
|
*/
|
||||||
"FOLD" : function(lnum, args) {
|
"FOLD" : function(lnum, stmtnum, args) {
|
||||||
return threeArg(lnum, args, (fn, init, functor) => {
|
return threeArg(lnum, stmtnum, args, (fn, init, functor) => {
|
||||||
// TODO test only works with DEFUN'd functions
|
// TODO test only works with DEFUN'd functions
|
||||||
if (fn.astLeaves === undefined) throw lang.badFunctionCallFormat("Only works with DEFUN'd functions yet");
|
if (fn.astLeaves === undefined) throw lang.badFunctionCallFormat("Only works with DEFUN'd functions yet");
|
||||||
if (functor.toArray === undefined && !Array.isArray(functor)) throw lang.syntaxfehler(lnum, functor);
|
if (functor.toArray === undefined && !Array.isArray(functor)) throw lang.syntaxfehler(lnum, functor);
|
||||||
@@ -1090,32 +1099,32 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
|
|
||||||
let akku = init;
|
let akku = init;
|
||||||
functor.forEach(it => {
|
functor.forEach(it => {
|
||||||
akku = bStatus.getDefunThunk(lnum, fn)(lnum, [akku, it]);
|
akku = bStatus.getDefunThunk(lnum, stmtnum, fn)(lnum, stmtnum, [akku, it]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return akku;
|
return akku;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* GOTO and GOSUB won't work but that's probably the best...? */
|
/* GOTO and GOSUB won't work but that's probably the best...? */
|
||||||
"DO" : function(lnum, args) {
|
"DO" : function(lnum, stmtnum, args) {
|
||||||
//return resolve(args[args.length - 1]);
|
//return resolve(args[args.length - 1]);
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
"OPTIONDEBUG" : function(lnum, args) {
|
"OPTIONDEBUG" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||||
DBGON = (1 == lh|0);
|
DBGON = (1 == lh|0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"OPTIONTRACE" : function(lnum, args) {
|
"OPTIONTRACE" : function(lnum, stmtnum, args) {
|
||||||
return oneArgNum(lnum, args, (lh) => {
|
return oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||||
TRACEON = (1 == lh|0);
|
TRACEON = (1 == lh|0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"RESOLVE" : function(lnum, args) {
|
"RESOLVE" : function(lnum, stmtnum, args) {
|
||||||
if (DBGON) {
|
if (DBGON) {
|
||||||
return oneArg(lnum, args, (it) => {
|
return oneArg(lnum, stmtnum, args, (it) => {
|
||||||
println(it);
|
println(it);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1123,9 +1132,9 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
throw lang.syntaxfehler(lnum);
|
throw lang.syntaxfehler(lnum);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"RESOLVE0" : function(lnum, args) {
|
"RESOLVE0" : function(lnum, stmtnum, args) {
|
||||||
if (DBGON) {
|
if (DBGON) {
|
||||||
return oneArg(lnum, args, (it) => {
|
return oneArg(lnum, stmtnum, args, (it) => {
|
||||||
println(Object.entries(it));
|
println(Object.entries(it));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1133,7 +1142,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
throw lang.syntaxfehler(lnum);
|
throw lang.syntaxfehler(lnum);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"UNRESOLVE" : function(lnum, args) {
|
"UNRESOLVE" : function(lnum, stmtnum, args) {
|
||||||
if (DBGON) {
|
if (DBGON) {
|
||||||
println(args[0]);
|
println(args[0]);
|
||||||
}
|
}
|
||||||
@@ -1141,7 +1150,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
|||||||
throw lang.syntaxfehler(lnum);
|
throw lang.syntaxfehler(lnum);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"UNRESOLVE0" : function(lnum, args) {
|
"UNRESOLVE0" : function(lnum, stmtnum, args) {
|
||||||
if (DBGON) {
|
if (DBGON) {
|
||||||
println(Object.entries(args[0]));
|
println(Object.entries(args[0]));
|
||||||
}
|
}
|
||||||
@@ -2404,11 +2413,18 @@ let JStoBASICtype = function(object) {
|
|||||||
else throw Error("BasicIntpError: un-translatable object with typeof "+(typeof object)+",\ntoString = "+object+",\nentries = "+Object.entries(object));
|
else throw Error("BasicIntpError: un-translatable object with typeof "+(typeof object)+",\ntoString = "+object+",\nentries = "+Object.entries(object));
|
||||||
}
|
}
|
||||||
let SyntaxTreeReturnObj = function(type, value, nextLine) {
|
let SyntaxTreeReturnObj = function(type, value, nextLine) {
|
||||||
|
if (nextLine === undefined || !Array.isArray(nextLine))
|
||||||
|
throw Error("TODO change format of troNextLine to [linenumber, stmtnumber]")
|
||||||
|
|
||||||
this.troType = type;
|
this.troType = type;
|
||||||
this.troValue = value;
|
this.troValue = value;
|
||||||
this.troNextLine = nextLine;
|
this.troNextLine = nextLine; // TODO change format of troNextLine to [linenumber, stmtnumber]
|
||||||
|
}
|
||||||
|
let JumpObj = function(targetLnum, targetStmtNum, fromLnum, rawValue) {
|
||||||
|
this.jmpNext = [targetLnum, targetStmtNum];
|
||||||
|
this.jmpFrom = fromLnum;
|
||||||
|
this.jmpReturningValue = rawValue;
|
||||||
}
|
}
|
||||||
bF._gotoCmds = {GOTO:1,GOSUB:1,RETURN:1,NEXT:1,END:1,BREAKTO:1}; // put nonzero (truthy) value here
|
|
||||||
/**
|
/**
|
||||||
* @param lnum line number of BASIC
|
* @param lnum line number of BASIC
|
||||||
* @param syntaxTree BasicAST
|
* @param syntaxTree BasicAST
|
||||||
@@ -2416,8 +2432,10 @@ bF._gotoCmds = {GOTO:1,GOSUB:1,RETURN:1,NEXT:1,END:1,BREAKTO:1}; // put nonzero
|
|||||||
*
|
*
|
||||||
* @return syntaxTreeReturnObject if recursion is escaped
|
* @return syntaxTreeReturnObject if recursion is escaped
|
||||||
*/
|
*/
|
||||||
bF._troNOP = function(lnum) { return new SyntaxTreeReturnObj("null", undefined, lnum + 1); }
|
bF._troNOP = function(lnum, stmtnum) { return new SyntaxTreeReturnObj("null", undefined, [lnum, stmtnum+1]); }
|
||||||
bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
bF._executeSyntaxTree = function(lnum, stmtnum, syntaxTree, recDepth) {
|
||||||
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
let _debugExec = false;
|
let _debugExec = false;
|
||||||
let _debugPrintCurrentLine = false;
|
let _debugPrintCurrentLine = false;
|
||||||
let recWedge = "> ".repeat(recDepth);
|
let recWedge = "> ".repeat(recDepth);
|
||||||
@@ -2429,10 +2447,10 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (syntaxTree == undefined) return bF._troNOP(lnum);
|
if (syntaxTree == undefined) return bF._troNOP(lnum, stmtnum);
|
||||||
else if (syntaxTree.astValue == undefined) { // empty meaningless parens
|
else if (syntaxTree.astValue == undefined) { // empty meaningless parens
|
||||||
if (syntaxTree.astLeaves.length > 1) throw Error("WTF");
|
if (syntaxTree.astLeaves.length > 1) throw Error("WTF");
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[0], recDepth);
|
return bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[0], recDepth);
|
||||||
}
|
}
|
||||||
else if (syntaxTree.astType == "function" || syntaxTree.astType == "op") {
|
else if (syntaxTree.astType == "function" || syntaxTree.astType == "op") {
|
||||||
if (_debugExec) serial.println(recWedge+"function|operator");
|
if (_debugExec) serial.println(recWedge+"function|operator");
|
||||||
@@ -2443,7 +2461,7 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
|
|
||||||
if ("IF" == funcName) {
|
if ("IF" == funcName) {
|
||||||
if (syntaxTree.astLeaves.length != 2 && syntaxTree.astLeaves.length != 3) throw lang.syntaxfehler(lnum);
|
if (syntaxTree.astLeaves.length != 2 && syntaxTree.astLeaves.length != 3) throw lang.syntaxfehler(lnum);
|
||||||
var testedval = bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[0], recDepth + 1);
|
var testedval = bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[0], recDepth + 1);
|
||||||
|
|
||||||
if (_debugExec) {
|
if (_debugExec) {
|
||||||
serial.println(recWedge+"testedval:");
|
serial.println(recWedge+"testedval:");
|
||||||
@@ -2453,21 +2471,21 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var iftest = bStatus.builtin["TEST"](lnum, [testedval]);
|
var iftest = bStatus.builtin["TEST"](lnum, stmtnum, [testedval]);
|
||||||
|
|
||||||
if (!iftest && syntaxTree.astLeaves[2] !== undefined)
|
if (!iftest && syntaxTree.astLeaves[2] !== undefined)
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[2], recDepth + 1);
|
return bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[2], recDepth + 1);
|
||||||
else if (iftest)
|
else if (iftest)
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[1], recDepth + 1);
|
return bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[1], recDepth + 1);
|
||||||
else
|
else
|
||||||
return new SyntaxTreeReturnObj("null", undefined, lnum + 1);
|
return bF._troNOP(lnum, stmtnum);
|
||||||
}
|
}
|
||||||
catch (eeeee) {
|
catch (eeeee) {
|
||||||
|
serial.printerr(`${e}\n${e.stack || "Stack trace undefined"}`);
|
||||||
throw lang.errorinline(lnum, "TEST", eeeee);
|
throw lang.errorinline(lnum, "TEST", eeeee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("DEFUN" == funcName) {
|
else if ("DEFUN" == funcName) {
|
||||||
//if (recDepth > 0) throw lang.badFunctionCallFormat(); // nested DEFUN is TODO and it involves currying and de bruijn indexing
|
|
||||||
if (syntaxTree.astLeaves.length !== 2) throw lang.syntaxfehler(lnum, "DEFUN 1");
|
if (syntaxTree.astLeaves.length !== 2) throw lang.syntaxfehler(lnum, "DEFUN 1");
|
||||||
let nameTree = syntaxTree.astLeaves[0];
|
let nameTree = syntaxTree.astLeaves[0];
|
||||||
let exprTree = syntaxTree.astLeaves[1];
|
let exprTree = syntaxTree.astLeaves[1];
|
||||||
@@ -2506,15 +2524,33 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
if (_basicConsts[defunName]) throw lang.asgnOnConst(lnum, defunName);
|
if (_basicConsts[defunName]) throw lang.asgnOnConst(lnum, defunName);
|
||||||
// search from builtin functions
|
// search from builtin functions
|
||||||
if (bStatus.builtin[defunName] !== undefined || bF[defunName.toLowerCase()] !== undefined)
|
if (bStatus.builtin[defunName] !== undefined || bF[defunName.toLowerCase()] !== undefined)
|
||||||
throw lang.dupDef(lnum, defunName);
|
throw lang.dupDef(lnum, stmtnum, defunName);
|
||||||
|
|
||||||
// finally assign the function to the variable table
|
// finally assign the function to the variable table
|
||||||
bStatus.vars[defunName] = new BasicVar(exprTree, "usrdefun");
|
bStatus.vars[defunName] = new BasicVar(exprTree, "usrdefun");
|
||||||
|
|
||||||
return new SyntaxTreeReturnObj("function", exprTree, lnum + 1);
|
return new SyntaxTreeReturnObj("function", exprTree, [lnum, stmtnum + 1]);
|
||||||
|
}
|
||||||
|
else if ("ON" == funcName) {
|
||||||
|
if (syntaxTree.astLeaves.length < 3) throw lang.badFunctionCallFormat();
|
||||||
|
|
||||||
|
let testValue = bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[0], recDepth + 1);
|
||||||
|
let functionName = syntaxTree.astLeaves[1].astValue;
|
||||||
|
let arrays = [];
|
||||||
|
for (let k = 2; k < astLeaves.length; k++)
|
||||||
|
arrays.push(bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[k], recDepth + 1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
let r = bStatus.builtin["ON"](lnum, stmtnum, [testValue].concat(arrays))
|
||||||
|
return new SyntaxTreeReturnObj(JStoBASICtype(r.jmpReturningValue), r.jmpReturningValue, r.jmpNext);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
serial.printerr(`${e}\n${e.stack || "Stack trace undefined"}`);
|
||||||
|
throw lang.errorinline(lnum, "ON error", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var args = syntaxTree.astLeaves.map(it => bF._executeSyntaxTree(lnum, it, recDepth + 1));
|
var args = syntaxTree.astLeaves.map(it => bF._executeSyntaxTree(lnum, stmtnum, it, recDepth + 1));
|
||||||
|
|
||||||
if (_debugExec) {
|
if (_debugExec) {
|
||||||
serial.println(recWedge+"fn call name: "+funcName);
|
serial.println(recWedge+"fn call name: "+funcName);
|
||||||
@@ -2531,10 +2567,10 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
throw lang.syntaxfehler(lnum, funcName + " is undefined");
|
throw lang.syntaxfehler(lnum, funcName + " is undefined");
|
||||||
}
|
}
|
||||||
else if ("array" == someVar.bvType) {
|
else if ("array" == someVar.bvType) {
|
||||||
func = bStatus.getArrayIndexFun(lnum, funcName, someVar.bvLiteral);
|
func = bStatus.getArrayIndexFun(lnum, stmtnum, funcName, someVar.bvLiteral);
|
||||||
}
|
}
|
||||||
else if ("usrdefun" == someVar.bvType) {
|
else if ("usrdefun" == someVar.bvType) {
|
||||||
func = bStatus.getDefunThunk(lnum, someVar.bvLiteral);
|
func = bStatus.getDefunThunk(lnum, stmtnum, someVar.bvLiteral);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw lang.syntaxfehler(lnum, funcName + " is not a function or an array");
|
throw lang.syntaxfehler(lnum, funcName + " is not a function or an array");
|
||||||
@@ -2542,30 +2578,31 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
}
|
}
|
||||||
// call whatever the 'func' has whether it's builtin or we just made shit up right above
|
// call whatever the 'func' has whether it's builtin or we just made shit up right above
|
||||||
try {
|
try {
|
||||||
var funcCallResult = func(lnum, args, syntaxTree.astSeps);
|
let funcCallResult = func(lnum, stmtnum, args, syntaxTree.astSeps);
|
||||||
|
let retVal = (funcCallResult instanceof JumpObj) ? funcCallResult.jmpReturningValue : funcCallResult;
|
||||||
|
|
||||||
return new SyntaxTreeReturnObj(
|
return new SyntaxTreeReturnObj(
|
||||||
JStoBASICtype(funcCallResult),
|
JStoBASICtype(retVal),
|
||||||
funcCallResult,
|
retVal,
|
||||||
(bF._gotoCmds[funcName] !== undefined) ? funcCallResult : lnum + 1,
|
(funcCallResult instanceof JumpObj) ? funcCallResult.jmpNext : [lnum, stmtnum + 1]
|
||||||
syntaxTree.astSeps
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (eeeee) {
|
catch (e) {
|
||||||
throw lang.errorinline(lnum, (funcName === undefined) ? "undefined" : funcName, (eeeee === undefined) ? "undefined" : eeeee);
|
serial.printerr(`${e}\n${e.stack || "Stack trace undefined"}`);
|
||||||
|
throw lang.errorinline(lnum, (funcName === undefined) ? "undefined" : funcName, (e === undefined) ? "undefined" : e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (syntaxTree.astType == "num") {
|
else if (syntaxTree.astType == "num") {
|
||||||
if (_debugExec) serial.println(recWedge+"num");
|
if (_debugExec) serial.println(recWedge+"num");
|
||||||
return new SyntaxTreeReturnObj(syntaxTree.astType, (syntaxTree.astValue)*1, lnum + 1);
|
return new SyntaxTreeReturnObj(syntaxTree.astType, (syntaxTree.astValue)*1, [lnum, stmtnum + 1]);
|
||||||
}
|
}
|
||||||
else if (syntaxTree.astType == "string" || syntaxTree.astType == "lit" || syntaxTree.astType == "bool") {
|
else if (syntaxTree.astType == "string" || syntaxTree.astType == "lit" || syntaxTree.astType == "bool") {
|
||||||
if (_debugExec) serial.println(recWedge+"string|literal|bool");
|
if (_debugExec) serial.println(recWedge+"string|literal|bool");
|
||||||
return new SyntaxTreeReturnObj(syntaxTree.astType, syntaxTree.astValue, lnum + 1);
|
return new SyntaxTreeReturnObj(syntaxTree.astType, syntaxTree.astValue, [lnum, stmtnum + 1]);
|
||||||
}
|
}
|
||||||
else if (syntaxTree.astType == "null") {
|
else if (syntaxTree.astType == "null") {
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[0], recDepth + 1);
|
return bF._executeSyntaxTree(lnum, stmtnum, syntaxTree.astLeaves[0], recDepth + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
serial.println(recWedge+"Parse error in "+lnum);
|
serial.println(recWedge+"Parse error in "+lnum);
|
||||||
@@ -2602,18 +2639,20 @@ bF._interpretLine = function(lnum, cmd) {
|
|||||||
|
|
||||||
return syntaxTrees;
|
return syntaxTrees;
|
||||||
}; // end INTERPRETLINE
|
}; // end INTERPRETLINE
|
||||||
// @return next line number
|
// @return [next line number, next statement number]
|
||||||
bF._executeAndGet = function(lnum, syntaxTree) {
|
bF._executeAndGet = function(lnum, stmtnum, syntaxTree) {
|
||||||
|
if (lnum === undefined || stmtnum === undefined) throw Error(`Line or statement number is undefined: (${lnum},${stmtnum})`);
|
||||||
|
|
||||||
// EXECUTE
|
// EXECUTE
|
||||||
try {
|
try {
|
||||||
var execResult = bF._executeSyntaxTree(lnum, syntaxTree, 0);
|
var execResult = bF._executeSyntaxTree(lnum, stmtnum, syntaxTree, 0);
|
||||||
|
|
||||||
if (bF.parserDoDebugPrint) serial.println(`Line ${lnum} TRO: ${Object.entries(execResult)}`);
|
if (bF.parserDoDebugPrint) serial.println(`Line ${lnum} TRO: ${Object.entries(execResult)}`);
|
||||||
|
|
||||||
return execResult.troNextLine;
|
return execResult.troNextLine;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
serial.printerr(`ERROR on ${lnum} -- PARSE TREE:\n${astToString(syntaxTree)}\nERROR CONTENTS:\n${e}\n${e.stack || "Stack trace undefined"}`);
|
serial.printerr(`ERROR on ${lnum}:${stmtnum} -- PARSE TREE:\n${astToString(syntaxTree)}\nERROR CONTENTS:\n${e}\n${e.stack || "Stack trace undefined"}`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2698,37 +2737,39 @@ bF.run = function(args) { // RUN function
|
|||||||
});
|
});
|
||||||
|
|
||||||
// actually execute the program
|
// actually execute the program
|
||||||
var linenumber = 1;
|
let lnum = 1;
|
||||||
var oldnum = 1;
|
let stmtnum = 0;
|
||||||
|
let oldnum = 1;
|
||||||
|
let tree = undefined;
|
||||||
do {
|
do {
|
||||||
if (cmdbuf[linenumber] !== undefined) {
|
if (programTrees[lnum] !== undefined) {
|
||||||
if (TRACEON) {
|
if (TRACEON) {
|
||||||
//print(`[${lnum}]`);
|
//print(`[${lnum}]`);
|
||||||
serial.println("[BASIC] Line "+linenumber);
|
serial.println("[BASIC] Line "+lnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
oldnum = linenumber;
|
oldnum = lnum;
|
||||||
|
tree = (programTrees[lnum] !== undefined) ? programTrees[lnum][stmtnum] : undefined;
|
||||||
|
|
||||||
let trees = programTrees[linenumber];
|
if (tree !== undefined) {
|
||||||
|
let nextObj = bF._executeAndGet(lnum, stmtnum, tree);
|
||||||
if (trees !== undefined) {
|
lnum = nextObj[0];
|
||||||
trees.forEach((t,i) => {
|
stmtnum = nextObj[1];
|
||||||
linenumber = bF._executeAndGet(linenumber, t);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
linenumber += 1;
|
lnum += 1;
|
||||||
|
stmtnum = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
linenumber += 1;
|
lnum += 1;
|
||||||
}
|
}
|
||||||
if (linenumber < 0) throw lang.badNumberFormat;
|
if (lnum < 0) throw lang.badNumberFormat;
|
||||||
if (con.hitterminate()) {
|
if (con.hitterminate()) {
|
||||||
println("Break in "+oldnum);
|
println("Break in "+oldnum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (linenumber < cmdbuf.length)
|
} while (lnum < cmdbuf.length)
|
||||||
con.resetkeybuf();
|
con.resetkeybuf();
|
||||||
};
|
};
|
||||||
bF.save = function(args) { // SAVE function
|
bF.save = function(args) { // SAVE function
|
||||||
|
|||||||
3
assets/facmap
Normal file
3
assets/facmap
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
10 DEFUN FAC(N)=IF N==0 THEN 1 ELSE N*FAC(N-1)
|
||||||
|
20 K=MAP(FAC, 1 TO 10)
|
||||||
|
30 PRINT K
|
||||||
Reference in New Issue
Block a user