mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
basic:fixed multidimensional array access for real
This commit is contained in:
101
assets/basic.js
101
assets/basic.js
@@ -222,7 +222,7 @@ let literalTypes = ["string", "num", "bool", "array", "generator"];
|
||||
*/
|
||||
let resolve = function(variable) {
|
||||
if (variable.troType === "internal_arrindexing_lazy")
|
||||
return variable.troValue.arrValue;
|
||||
return eval("variable.troValue.arrFull"+variable.troValue.arrKey);
|
||||
else if (literalTypes.includes(variable.troType) || variable.troType.startsWith("internal_"))
|
||||
return variable.troValue;
|
||||
else if (variable.troType == "lit") {
|
||||
@@ -237,8 +237,6 @@ let resolve = function(variable) {
|
||||
let argCheckErr = function(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.troValue.arrObj !== undefined && o.troValue.arrIndex >= o.troValue.arrObj.length)
|
||||
throw lang.subscrOutOfRng(line, o.troValue.arrName, o.troValue.arrIndex, o.troValue.arrObj.length);
|
||||
}
|
||||
let oneArg = function(lnum, args, action) {
|
||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||
@@ -392,47 +390,44 @@ bStatus.vars = initBvars(); // contains instances of BasicVars
|
||||
bStatus.consts = {"NIL":1}; Object.freeze(bStatus.consts);
|
||||
bStatus.defuns = {};
|
||||
bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number
|
||||
bStatus.getDimSize = function(array, dim) {
|
||||
var dims = [];
|
||||
while (true) {
|
||||
dims.push(array.length);
|
||||
|
||||
if (Array.isArray(array[0]))
|
||||
array = array[0];
|
||||
else
|
||||
break;
|
||||
}
|
||||
return dims[dim];
|
||||
};
|
||||
bStatus.getArrayIndexFun = function(lnum, arrayName, array) {
|
||||
return function(lnum, args) {
|
||||
// NOTE: BASIC arrays are index in column-major order, which is OPPOSITE of C/JS/etc.
|
||||
return varArgNum(lnum, args, (dims) => {
|
||||
let indexingstr = "";
|
||||
if (TRACEON) serial.println("ar dims: "+dims);
|
||||
|
||||
let dimcnt = 1;
|
||||
let oldIstr = "";
|
||||
let istr = "";
|
||||
// check error beforehand
|
||||
dims.reverse().forEach((d) => {
|
||||
oldIstr = istr;
|
||||
istr += `[${d-INDEX_BASE}]`;
|
||||
// test for index out of bounds
|
||||
if (eval(`array${istr}`) === undefined) {
|
||||
throw lang.subscrOutOfRng(lnum, `${arrayName}${oldIstr} (${lang.ord(dimcnt)} dim)`, d-INDEX_BASE, eval(`array${oldIstr}`).length);
|
||||
}
|
||||
let oldIndexingStr = "";
|
||||
let indexingstr = "";
|
||||
|
||||
dims.forEach(d => {
|
||||
oldIndexingStr = indexingstr;
|
||||
indexingstr += `[${d-INDEX_BASE}]`;
|
||||
|
||||
var testingArr = eval(`array${indexingstr}`);
|
||||
if (testingArr === undefined)
|
||||
throw lang.subscrOutOfRng(lnum, `${arrayName}${oldIndexingStr} (${lang.ord(dimcnt)} dim)`, d-INDEX_BASE, bStatus.getDimSize(array, dimcnt-1));
|
||||
|
||||
dimcnt += 1;
|
||||
})
|
||||
// actually build indexing string (trust me, indexing fails with code above; test with 'amazing.bas')
|
||||
dims.forEach((d) => {
|
||||
indexingstr = `[${d-INDEX_BASE}]${indexingstr}`;
|
||||
})
|
||||
});
|
||||
|
||||
if (TRACEON)
|
||||
serial.println("ar indexedValue = "+`/*ar1*/array${indexingstr}`);
|
||||
|
||||
let indexedValue = eval(`/*ar1*/array${indexingstr}`);
|
||||
let index = dims[0]-INDEX_BASE;
|
||||
|
||||
if (TRACEON)
|
||||
serial.println("ar parentArr = "+`/*ar2*/array${indexingstr.substring(0, indexingstr.length - 2 - (""+index).length)}`);
|
||||
//let parentArr = eval(`/*ar2*/array${oldIndexingStr}`);
|
||||
let parentArr = eval(`/*ar2*/array${indexingstr.substring(0, indexingstr.length - 2 - (""+index).length)}`);
|
||||
|
||||
if (index < 0) throw lang.subscrOutOfRng(lnum, arrayName);
|
||||
|
||||
return {arrValue: indexedValue, arrObj: parentArr, arrIndex: index, arrName: arrayName}
|
||||
return {arrFull: array, arrName: arrayName, arrKey: indexingstr};
|
||||
});
|
||||
|
||||
//return {arrValue: indexedValue, arrObj: array, arrIndex: rsvArg0, arrName: arrayName}; //array[rsvArg0];
|
||||
};
|
||||
};
|
||||
bStatus.builtin = {
|
||||
@@ -444,16 +439,21 @@ if no args were given (e.g. "10 NEXT()"), args[0] will be: {troType: null, troVa
|
||||
if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
*/
|
||||
"=" : function(lnum, args) {
|
||||
// THIS FUNCTION MUST BE COPIED TO 'INPUT'
|
||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||
var troValue = args[0].troValue;
|
||||
|
||||
var rh = resolve(args[1]);
|
||||
if (rh === undefined) throw lang.refError(lnum, "RH:"+args[1].troValue);
|
||||
|
||||
if (troValue.arrObj !== undefined) { // assign to existing array
|
||||
if (!isNaN(rh)) rh = rh*1 // if string we got can be cast to number, do it
|
||||
|
||||
if (troValue.arrFull !== undefined) { // assign to existing array
|
||||
if (isNaN(rh) && !Array.isArray(rh)) throw lang.illegalType(lnum, rh);
|
||||
troValue.arrObj[troValue.arrIndex] = rh|0;
|
||||
return {asgnVarName: troValue.arrName, asgnValue: rh|0};
|
||||
let arr = eval("troValue.arrFull"+troValue.arrKey);
|
||||
if (Array.isArray(arr)) throw lang.subscrOutOfRng(lnum, arr);
|
||||
eval("troValue.arrFull"+troValue.arrKey+"=rh");
|
||||
return {asgnVarName: troValue.arrName, asgnValue: rh};
|
||||
}
|
||||
else {
|
||||
var varname = troValue.toUpperCase();
|
||||
@@ -470,7 +470,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
var rh = resolve(args[1]);
|
||||
if (rh === undefined) throw lang.refError(lnum, "RH:"+args[1].troValue);
|
||||
|
||||
if (troValue.arrObj !== undefined) {
|
||||
if (troValue.arrFull !== undefined) {
|
||||
throw lang.syntaxfehler(lnum);
|
||||
}
|
||||
else {
|
||||
@@ -611,7 +611,8 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
});
|
||||
},
|
||||
"DIM" : function(lnum, args) {
|
||||
return varArgNum(lnum, args, (dims) => {
|
||||
return varArgNum(lnum, args, (revdims) => {
|
||||
let dims = revdims.reverse();
|
||||
let arraydec = "Array(dims[0]).fill(0)";
|
||||
for (let k = 1; k < dims.length; k++) {
|
||||
arraydec = `Array(dims[${k}]).fill().map(_=>${arraydec})`
|
||||
@@ -877,13 +878,14 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
// print out prompt text
|
||||
print("? "); var rh = sys.read().trim();
|
||||
|
||||
if (rh*1 === (rh|0) || !isNaN(rh)) rh = rh*1
|
||||
if (!isNaN(rh)) rh = rh*1 // if string we got can be cast to number, do it
|
||||
|
||||
if (troValue.arrObj !== undefined) {
|
||||
if (troValue.arrFull !== undefined) { // assign to existing array
|
||||
if (isNaN(rh) && !Array.isArray(rh)) throw lang.illegalType(lnum, rh);
|
||||
|
||||
troValue.arrObj[troValue.arrIndex] = rh|0;
|
||||
return {asgnVarName: troValue.arrName, asgnValue: rh|0};
|
||||
let arr = eval("troValue.arrFull"+troValue.arrKey);
|
||||
if (Array.isArray(arr)) throw lang.subscrOutOfRng(lnum, arr);
|
||||
eval("troValue.arrFull"+troValue.arrKey+"=rh");
|
||||
return {asgnVarName: troValue.arrName, asgnValue: rh};
|
||||
}
|
||||
else {
|
||||
var varname = troValue.toUpperCase();
|
||||
@@ -922,6 +924,18 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
INDEX_BASE = lh|0;
|
||||
});
|
||||
},
|
||||
"OPTIONDEBUG" : function(lnum, args) {
|
||||
return oneArgNum(lnum, args, (lh) => {
|
||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||
DBGON = (1 == lh|0);
|
||||
});
|
||||
},
|
||||
"OPTIONTRACE" : function(lnum, args) {
|
||||
return oneArgNum(lnum, args, (lh) => {
|
||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||
TRACEON = (1 == lh|0);
|
||||
});
|
||||
},
|
||||
"RESOLVE" : function(lnum, args) {
|
||||
if (DBGON) {
|
||||
return oneArg(lnum, args, (it) => {
|
||||
@@ -1770,9 +1784,8 @@ let JStoBASICtype = function(object) {
|
||||
else if (typeof object === "string" || object instanceof String) return "string";
|
||||
else if (object === undefined) return "null";
|
||||
else if (object.asgnVarName !== undefined) return "internal_assignment_object";
|
||||
else if (object.arrValue !== undefined) return "internal_arrindexing_lazy";
|
||||
else if (object.arrName !== undefined) return "internal_arrindexing_lazy";
|
||||
// buncha error msgs
|
||||
else if (object.arrIndex >= object.arrObj.length) throw lang.subscrOutOfRng(undefined, `${object.arrName}(${object.arrIndex}, len:${object.arrObj.length})`);
|
||||
else throw "BasicIntpError: un-translatable object with typeof "+(typeof object)+",\ntoString = "+object+",\nentries = "+Object.entries(object);
|
||||
}
|
||||
let SyntaxTreeReturnObj = function(type, value, nextLine) {
|
||||
|
||||
25
assets/multable.bas
Normal file
25
assets/multable.bas
Normal file
@@ -0,0 +1,25 @@
|
||||
1 PRINT SPC(35);"MULT-TABLE"
|
||||
2 PRINT "THIS PROGRAM TESTS THE MULTIDIMENSIONAL ARRAY ALLOCATING AND INDEXING"
|
||||
3 PRINT
|
||||
4 OPTIONBASE 1
|
||||
5 OPTIONDEBUG 1
|
||||
6 OPTIONTRACE 1
|
||||
9 I=DIM(2)
|
||||
10 PRINT "TABLE WIDTH";
|
||||
11 INPUT I(1)
|
||||
20 PRINT "TABLE HEIGHT";
|
||||
21 INPUT I(2)
|
||||
30 T=DIM(I(2),I(1))
|
||||
40 FOR Y=1 TO I(2)
|
||||
50 FOR X=1 TO I(1)
|
||||
60 T(Y,X)=X*Y
|
||||
70 NEXT
|
||||
80 NEXT
|
||||
90 RESOLVE T
|
||||
100 FOR Y=1 TO I(2)
|
||||
110 FOR X=1 TO I(1)
|
||||
120 PRINT T(Y,X);" ";
|
||||
130 NEXT
|
||||
140 PRINT
|
||||
150 NEXT
|
||||
200 PRINT "ENDE"
|
||||
Reference in New Issue
Block a user