From 88ad5495536b40d2216a479d3093af93a418a08a Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 15 Nov 2020 22:52:29 +0900 Subject: [PATCH] basic: for loop init --- assets/tbas/basic.js | 86 +++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/assets/tbas/basic.js b/assets/tbas/basic.js index 877960b..05e8d94 100644 --- a/assets/tbas/basic.js +++ b/assets/tbas/basic.js @@ -52,6 +52,9 @@ lang.parserError = function(line, errorobj) { lang.outOfMem = function(line) { return "Out of memory in " + line; }; +lang.dupDef = function(line, varname) { + return "Duplicate definition"+((varname !== undefined) ? (" on "+varname) : "")+" in "+line; +}; Object.freeze(lang); let fs = {}; @@ -223,7 +226,7 @@ let literalTypes = ["string", "number", "bool", "array"]; BASIC variable table and return the literal value of the BasicVar; undefined will be returned if no such var exists. */ let resolve = function(variable) { - if (literalTypes.includes(variable.troType)) + if (literalTypes.includes(variable.troType) || variable.troType.startsWith("internal_")) return variable.troValue; else if (variable.troType == "literal") { var basicVar = bStatus.vars[parseSigil(variable.troValue).sgName]; @@ -237,60 +240,60 @@ let resolve = function(variable) { let oneArg = function(lnum, args, action) { if (args.length != 1) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); return action(rsvArg0); } let oneArgNum = function(lnum, args, action) { if (args.length != 1) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); - if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); + if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0); return action(rsvArg0); } let twoArg = function(lnum, args, action) { if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); var rsvArg1 = resolve(args[1]); - if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1.value); + if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1); return action(rsvArg0, rsvArg1); } let twoArgNum = function(lnum, args, action) { if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); - if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); + if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0); var rsvArg1 = resolve(args[1]); - if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1.value); - if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1.value); + if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1); + if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1); return action(rsvArg0, rsvArg1); } let threeArg = function(lnum, args, action) { if (args.length != 3) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); var rsvArg1 = resolve(args[1]); - if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1.value); + if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1); var rsvArg2 = resolve(args[2]); - if (rsvArg2 === undefined) throw lang.refError(lnum, rsvArg2.value); + if (rsvArg2 === undefined) throw lang.refError(lnum, rsvArg2); return action(rsvArg0, rsvArg1, rsvArg2); } let threeArgNum = function(lnum, args, action) { if (args.length != 3) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); - if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); + if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0); var rsvArg1 = resolve(args[1]); - if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1.value); - if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1.value); + if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1); + if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1); var rsvArg2 = resolve(args[2]); - if (rsvArg2 === undefined) throw lang.refError(lnum, rsvArg2.value); - if (isNaN(rsvArg2)) throw lang.illegalType(lnum, rsvArg2.value); + if (rsvArg2 === undefined) throw lang.refError(lnum, rsvArg2); + if (isNaN(rsvArg2)) throw lang.illegalType(lnum, rsvArg2); return action(rsvArg0, rsvArg1, rsvArg2); } let bStatus = {}; bStatus.gosubStack = []; -bStatus.forStack = {}; +bStatus.forStack = {}; // key: forVar, value: linenum bStatus.vars = {}; // contains instances of BasicVars bStatus.defuns = {}; bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number @@ -299,8 +302,8 @@ bStatus.getArrayIndexFun = function(lnum, array) { // TODO test 1-d array // NOTE: BASIC arrays are index in column-major order, which is OPPOSITE of C/JS/etc. var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); - if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); + if (isNaN(rsvArg0)) throw lang.illegalType(lnum, rsvArg0); return array[rsvArg0]; }; @@ -318,7 +321,7 @@ bStatus.builtin = { if (rh === undefined) throw lang.refError(lnum, args[1].troValue); var type = sigil.sgType || JStoBASICtype(rh); bStatus.vars[sigil.sgName] = new BasicVar(rh, type); - return rh; + return {asgnVarName: sigil.sgName, asgnValue: rh}; }, "==" : function(lnum, args) { return twoArg(lnum, args, function(lh, rh) { return lh == rh; }); @@ -406,11 +409,11 @@ bStatus.builtin = { "STEP" : function(lnum, args) { if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg0 = resolve(args[0]); - if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0.value); - if (!Array.isArray(rsvArg0)) throw lang.illegalType(lnum, rsvArg0.value); + if (rsvArg0 === undefined) throw lang.refError(lnum, rsvArg0); + if (!Array.isArray(rsvArg0)) throw lang.illegalType(lnum, rsvArg0); var rsvArg1 = resolve(args[1]); - if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1.value); - if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1.value); + if (rsvArg1 === undefined) throw lang.refError(lnum, rsvArg1); + if (isNaN(rsvArg1)) throw lang.illegalType(lnum, rsvArg1); let a = []; let stepcnt = 0; rsvArg0.forEach(function(v,i) { if (stepcnt == 0) a.push(v); @@ -487,11 +490,11 @@ bStatus.builtin = { if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given"); var rsvArg = args.map(function(it) { return resolve(it); }); rsvArg.forEach(function(v) { - if (v === undefined) throw lang.refError(lnum, v.value); - if (typeof v !== "boolean") throw lang.illegalType(lnum, v.value); + if (v === undefined) throw lang.refError(lnum, v); + if (typeof v !== "boolean") throw lang.illegalType(lnum, v); }); var argum = rsvArg.map(function(it) { - if (it === undefined) throw lang.refError(lnum, it.value); + if (it === undefined) throw lang.refError(lnum, it); return it; }); return argum[0] && argum[1]; @@ -501,10 +504,10 @@ bStatus.builtin = { var rsvArg = args.map(function(it) { return resolve(it); }); rsvArg.forEach(function(v) { if (v === undefined) throw lang.refError(lnum, v.value); - if (typeof v !== "boolean") throw lang.illegalType(lnum, v.value); + if (typeof v !== "boolean") throw lang.illegalType(lnum, v); }); var argum = rsvArg.map(function(it) { - if (it === undefined) throw lang.refError(lnum, it.value); + if (it === undefined) throw lang.refError(lnum, it); return it; }); return argum[0] || argum[1]; @@ -539,9 +542,19 @@ bStatus.builtin = { return resolve(args[0]); }, "FOR" : function(lnum, args) { - throw TODO(); - // use bStatus.forStack - bStatus.forStack.push(lnum); + let asgnObj = resolve(args[0]); + // type check + if (asgnObj === undefined) throw lang.syntaxfehler(lnum); + if (!Array.isArray(asgnObj.asgnValue)) throw lang.illegalType(lnum, asgnObj); + + let varname = asgnObj.asgnVarName + // check for variable name collision (e.g. 10 K=1TO10 \n 20 FOR I=K should work but 20 FOR K=K must not) + if (bStatus.vars[varname] !== undefined)) throw lang.dupDef(lnum, varname); + + // assign new variable + bStatus.vars[varname] = asgnObj.asgnValue + // put the varname to forstack + bStatus.forStack[asgnObj.asgnVarName] = lnum; }, "NEXT" : function(lnum, args) { throw TODO(); @@ -1323,7 +1336,8 @@ let JStoBASICtype = function(object) { else if (!isNaN(object)) return "number"; else if (typeof object === "string" || object instanceof String) return "string"; else if (object === undefined) return "null"; - else throw "BasicIntpError: un-translatable object with typeof "+(typeof object)+"\n"+object+"\n"+Object.entries(object); + else if (object.asgnVarName !== undefined) return "internal_assignment_object"; + else throw "BasicIntpError: un-translatable object with typeof "+(typeof object)+",\ntoString = "+object+",\nentries = "+Object.entries(object); } let SyntaxTreeReturnObj = function(type, value, nextLine) { this.troType = type;