mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-06 05:28:31 +09:00
wordprocessor wip
This commit is contained in:
58
assets/bios/wp.js
Normal file
58
assets/bios/wp.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const COL_TEXT = 253
|
||||
const COL_BACK = 255
|
||||
const COL_SUPERTEXT = 239
|
||||
const COL_DIMTEXT = 249
|
||||
const COL_LNUMBACK = 18
|
||||
const COL_LNUMFORE = 253
|
||||
const COL_CARET_ROW = 81
|
||||
const PAINT_START_X = 5
|
||||
const PAINT_START_Y = 2
|
||||
const BIG_STRIDE = 999
|
||||
const TAB_SIZE = 4
|
||||
|
||||
const caretLeft = 10
|
||||
const caretRight = 80
|
||||
|
||||
let scroll = 0
|
||||
let scrollHor = 0
|
||||
let textbuffer = [""]
|
||||
let cursorRow = 0
|
||||
let cursorCol = 0
|
||||
let exit = false
|
||||
let scene = -1 // -1: main, 0: filemenu, 1: editmenu , ...
|
||||
let bulletinShown = false
|
||||
let cursoringCol = 0
|
||||
|
||||
let windowWidth = 0
|
||||
let windowHeight = 0
|
||||
let paintWidth = 0
|
||||
let paintHeight = 0
|
||||
let scrollPeek = 0
|
||||
function drawInit() {
|
||||
windowWidth = con.getmaxyx()[1]
|
||||
windowHeight = con.getmaxyx()[0]
|
||||
paintWidth = windowWidth - PAINT_START_X + 1
|
||||
paintHeight = windowHeight - PAINT_START_Y + 1
|
||||
scrollPeek = Math.ceil((paintHeight / 7))
|
||||
}
|
||||
const scrollHorPeek = 1; // to accommodate the scroll indicator
|
||||
|
||||
|
||||
function drawMain() {
|
||||
con.curs_set(0)
|
||||
drawInit()
|
||||
con.clear()
|
||||
con.color_pair(COL_TEXT, COL_BACK)
|
||||
|
||||
// column indicator
|
||||
con.move(2,1)
|
||||
for (let k = 0; k < 9; k++) print(`${k}....:....`)
|
||||
con.color_pair(COL_BACK, COL_TEXT)
|
||||
con.mvaddch(2,1+caretLeft,91)
|
||||
con.mvaddch(2,1+caretRight,93)
|
||||
|
||||
con.color_pair(COL_BACK, COL_TEXT)
|
||||
}
|
||||
|
||||
|
||||
drawMain()
|
||||
@@ -312,6 +312,14 @@ let monadToString = function(monad, depth) {
|
||||
}*/
|
||||
return sb;
|
||||
}
|
||||
let arrayToString = function(a) {
|
||||
let acc = "";
|
||||
for (let k = 0; k < a.length; k++) {
|
||||
if (k > 0) acc += ",";
|
||||
acc += (Array.isArray(a[k])) ? arrayToString(a[k]) : a[k];
|
||||
}
|
||||
return "{"+acc+"}";
|
||||
}
|
||||
let theLambdaBoundVars = function() {
|
||||
let sb = "";
|
||||
lambdaBoundVars.forEach((it,i) => {
|
||||
@@ -325,11 +333,7 @@ let theLambdaBoundVars = function() {
|
||||
})
|
||||
return sb;
|
||||
}
|
||||
let makeBase32Hash = function() {
|
||||
let e = "YBNDRFG8EJKMCPQXOTLVWIS2A345H769";
|
||||
let m = e.length;
|
||||
return e[Math.floor(Math.random()*m)] + e[Math.floor(Math.random()*m)] + e[Math.floor(Math.random()*m)] + e[Math.floor(Math.random()*m)] + e[Math.floor(Math.random()*m)]
|
||||
}
|
||||
let makeBase32Hash = ()=>[1,2,3,4,5].map(i=>"YBNDRFG8EJKMCPQXOTLVWIS2A345H769"[Math.random()*32|0]).join('');
|
||||
let BasicAST = function() {
|
||||
this.astLnum = 0;
|
||||
this.astLeaves = [];
|
||||
@@ -431,8 +435,11 @@ let resolve = function(variable) {
|
||||
else if (literalTypes.includes(variable.troType) || variable.troType.startsWith("internal_"))
|
||||
return variable.troValue;
|
||||
else if (variable.troType == "lit") {
|
||||
if (isNumable(variable.troValue)) { // rarely we get a number as a variable name, notably on (&)
|
||||
return tonum(variable.troValue);
|
||||
}
|
||||
// when program tries to call builtin function (e.g. SIN), return usrdefun-wrapped version
|
||||
if (bS.builtin[variable.troValue] !== undefined) {
|
||||
else if (bS.builtin[variable.troValue] !== undefined) {
|
||||
return bS.wrapBuiltinToUsrdefun(variable.troValue);
|
||||
}
|
||||
// else, it's just a plain-old variable :p
|
||||
@@ -636,17 +643,7 @@ let varArgNum = function(lnum, stmtnum, args, action) {
|
||||
return action(rsvArg);
|
||||
}
|
||||
let makeIdFun = () => {
|
||||
let i = new BasicAST();
|
||||
i.astValue = [0,0];
|
||||
i.astType = "defun_args";
|
||||
i.astLnum = "**";
|
||||
|
||||
let a = new BasicAST();
|
||||
a.astValue = i;
|
||||
a.astType = "usrdefun";
|
||||
a.astLnum = "**";
|
||||
|
||||
return a;
|
||||
return JSON.parse(`{"astLnum":"**","astLeaves":[],"astSeps":[],"astValue":[0,0],"astType":"defun_args","astHash":"IDFUN"}`);
|
||||
}
|
||||
let _basicConsts = {
|
||||
"NIL": new BasicVar([], "array"),
|
||||
@@ -1082,7 +1079,9 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
//serial.println(`${lnum} PRINT ${lang.ord(llll)} arg: ${Object.entries(args[llll])}, resolved: ${rsvArg}`);
|
||||
|
||||
let printstr = "";
|
||||
if (rsvArg === undefined || rsvArg === "")
|
||||
if (Array.isArray(rsvArg))
|
||||
printstr = arrayToString(rsvArg);
|
||||
else if (rsvArg === undefined || rsvArg === "")
|
||||
printstr = "";
|
||||
else if (rsvArg.toString !== undefined)
|
||||
printstr = rsvArg.toString();
|
||||
@@ -1221,7 +1220,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
}},
|
||||
"TEST" : {argc:1, f:function(lnum, stmtnum, args) {
|
||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length+lang.aG);
|
||||
return !!resolve(args[0]);
|
||||
return !!resolve(args[0]); // string 'false' will be interpreted as truthy; this is completely intentional
|
||||
}},
|
||||
"FOREACH" : {f:function(lnum, stmtnum, args) { // list comprehension model
|
||||
var asgnObj = resolve(args[0]);
|
||||
@@ -1626,6 +1625,9 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
return bF._executeSyntaxTree(lnum, stmtnum, newTree, 0);
|
||||
}
|
||||
}},
|
||||
"&" : {argc:2, f:function(lnum, stmtnum, args) {
|
||||
return bS.builtin["$"].f(lnum, stmtnum, [args[1], args[0]].concat(args.slice(2)));
|
||||
}},
|
||||
"REDUCE" : {noprod:1, argc:1, f:function(lnum, stmtnum, args) {
|
||||
return oneArg(lnum, stmtnum, args, bv => {
|
||||
if (isAST(bv)) {
|
||||
@@ -1769,7 +1771,7 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
print(String.fromCharCode(27,91)+"48;5;"+(col|0)+"m");
|
||||
});
|
||||
}},
|
||||
/** type: (list of function) <*> (list of functor)
|
||||
/** type: (list of function) <*> (a functor)
|
||||
* Sequnetial application
|
||||
*
|
||||
* Can be implemented on pure TerranBASIC using:
|
||||
@@ -1783,16 +1785,35 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
if (isGenerator(functor)) functor = genToArray(functor);
|
||||
|
||||
let ret = [];
|
||||
fns.forEach(fn => ret.push(functor.map(it => bS.getDefunThunk(fn)(lnum, stmtnum, [it]))));
|
||||
fns.forEach(fn => ret = ret.concat(functor.map(it => bS.getDefunThunk(fn)(lnum, stmtnum, [it]))));
|
||||
return ret;
|
||||
});
|
||||
}},
|
||||
/** type: (a function) <*> (list of functor)
|
||||
/** type: (a function) <*> (a functor)
|
||||
* Infix MAP
|
||||
*/
|
||||
"<$>" : {argc:2, f:function(lnum, stmtnum, args) {
|
||||
return bS.builtin.MAP.f(lnum, stmtnum, args);
|
||||
}},
|
||||
/** type: (a function/list of functions) <~> (a functor)
|
||||
* SEQUENTIAL CURRY-MAP
|
||||
*
|
||||
* returns a list of functions curried with each element of the functor
|
||||
*/
|
||||
"<~>" : {argc:2, f:function(lnum, stmtnum, args) {
|
||||
return twoArg(lnum, stmtnum, args, (fns, functor) => {
|
||||
if (!isRunnable(fns) && !(Array.isArray(fns) && isRunnable(fns[0]))) throw lang.badFunctionCallFormat(lnum, "first argument is not a function: got "+JStoBASICtype(fns));
|
||||
if (!isGenerator(functor) && !Array.isArray(functor)) throw lang.syntaxfehler(lnum, "not a mappable type: "+functor+((typeof functor == "object") ? Object.entries(functor) : ""));
|
||||
// generator?
|
||||
if (isGenerator(functor)) functor = genToArray(functor);
|
||||
// single function?
|
||||
if (!Array.isArray(fns)) fns = [fns];
|
||||
|
||||
let ret = [];
|
||||
fns.forEach(fn => ret = ret.concat(functor.map(it => bS.builtin["~<"].f(lnum, stmtnum, [fn, it]))));
|
||||
return ret;
|
||||
});
|
||||
}},
|
||||
"OPTIONDEBUG" : {f:function(lnum, stmtnum, args) {
|
||||
oneArgNum(lnum, stmtnum, args, (lh) => {
|
||||
if (lh != 0 && lh != 1) throw lang.syntaxfehler(line);
|
||||
@@ -1842,7 +1863,10 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length
|
||||
}},
|
||||
"UNRESOLVE0" : {debugonly:1, argc:1, f:function(lnum, stmtnum, args) {
|
||||
println(Object.entries(args[0]));
|
||||
}}
|
||||
}},
|
||||
"TOJSON" : {debugonly:1, argc:1, f:function(lnum, stmtnum, args) {
|
||||
println(JSON.stringify(resolve(args[0])));
|
||||
}},
|
||||
};
|
||||
Object.freeze(bS.builtin);
|
||||
let bF = {}; // BASIC functions
|
||||
@@ -1905,22 +1929,24 @@ bF._opPrc = {
|
||||
"BOR":202,
|
||||
"AND":300,
|
||||
"OR":301,
|
||||
"TO":400,
|
||||
"STEP":401,
|
||||
"!":500,"~":501, // array CONS and PUSH
|
||||
"TO":400,"STEP":401,
|
||||
"!":500,
|
||||
"~":501, // array CONS and PUSH
|
||||
"#":502, // array concat
|
||||
".": 600, // compo operator
|
||||
"$": 600, // apply operator
|
||||
"&": 600, // pipe operator
|
||||
"~<": 601, // curry operator
|
||||
"<*>": 602, // sequential application operator
|
||||
"<$>": 602, // infix map operator
|
||||
"<*>": 602, // sequential application operator
|
||||
"<~>": 602, // infix curry-map operator
|
||||
"@":700, // MRET
|
||||
"~>": 1000, // closure operator
|
||||
">>~": 1000, // monad sequnce operator
|
||||
">>=": 1000, // monad bind operator
|
||||
"=":9999,"IN":9999
|
||||
}; // when to ops have same index of prc but different in associativity, right associative op gets higher priority (at least for the current parser implementation)
|
||||
bF._opRh = {"^":1,"=":1,"!":1,"IN":1,"~>":1,"$":1,".":1,">>=":1,">>~":1,">!>":1,"@":1,"`":1,"<*>":1,"<$>":1}; // ~< and ~> cannot have same associativity
|
||||
bF._opRh = {"^":1,"=":1,"!":1,"IN":1,"~>":1,"$":1,".":1,">>=":1,">>~":1,">!>":1,"@":1,"`":1,"<$>":1}; // ~< and ~> cannot have same associativity
|
||||
// these names appear on executeSyntaxTree as "exceptional terms" on parsing (regular function calls are not "exceptional terms")
|
||||
bF._tokenise = function(lnum, cmd) {
|
||||
var _debugprintStateTransition = false;
|
||||
@@ -2402,26 +2428,23 @@ stmt =
|
||||
| expr ; (* if the statement is 'lit' and contains only one word, treat it as function_call
|
||||
e.g. NEXT for FOR loop *)
|
||||
|
||||
array_inner =
|
||||
"{" , expr , "}" , ["," , "{" , expr , "}"] ;
|
||||
|
||||
expr = (* this basically blocks some funny attemps such as using DEFUN as anon function
|
||||
because everything is global in BASIC *)
|
||||
? empty string ?
|
||||
| lit
|
||||
| array_inner
|
||||
| "{" , [expr , {"," , expr}] , "}"
|
||||
| "(" , expr , ")"
|
||||
| ident_tuple
|
||||
| "IF" , expr_sans_asgn , "THEN" , expr , ["ELSE" , expr]
|
||||
| kywd , expr - "(" (* also deals with FOR statement *)
|
||||
(* at this point, if OP is found in paren-level 0, skip function_call *)
|
||||
| function_call
|
||||
| ("FOR"|"FOREACH") , expr
|
||||
| expr , op , expr
|
||||
| op_uni , expr ;
|
||||
| op_uni , expr
|
||||
| kywd , expr - "("
|
||||
| function_call ;
|
||||
|
||||
expr_sans_asgn = ? identical to expr except errors out whenever "=" is found ? ;
|
||||
|
||||
ident_tuple = "[" , ident , ["," , ident] , "]" ;
|
||||
ident_tuple = "[" , ident , {"," , ident} , "]" ;
|
||||
|
||||
function_call =
|
||||
ident , "(" , [expr , {argsep , expr} , [argsep]] , ")"
|
||||
@@ -2433,10 +2456,11 @@ kywd = ? words that exists on the list of predefined function that are not opera
|
||||
argsep = "," | ";" ;
|
||||
ident = alph , [digits] ; (* variable and function names *)
|
||||
lit = alph , [digits] | num | string ; (* ident + numbers and string literals *)
|
||||
op = "^" | "*" | "/" | "MOD" | "+" | "-" | "<<" | ">>" | "<" | ">" | "<="
|
||||
| "=<" | ">=" | "=>" | "==" | "<>" | "><" | "BAND" | "BXOR" | "BOR"
|
||||
| "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" ;
|
||||
op_uni = "-" | "+" ;
|
||||
op = "^" | "*" | "/" | "\" | "MOD" | "+" | "-" | "<<" | ">>" | "<" | ">"
|
||||
| "<=" | "=<" | ">=" | "=>" | "==" | "<>" | "><" | "MIN" | "MAX" | "BAND" | "BXOR" | "BOR"
|
||||
| "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "." | "$" | "&" | "~<" | "<$>" | "<*>"
|
||||
| "<~>" | "~>" | ">>~" | ">>=" | "=" ;
|
||||
op_uni = "-" | "+" | "NOT" | "BNOT" | "`" | "@" ;
|
||||
|
||||
alph = letter | letter , alph ;
|
||||
digits = digit | digit , digits ;
|
||||
@@ -2446,7 +2470,7 @@ num = digits | digits , "." , [digits] | "." , digits
|
||||
| ("0x"|"0X") , hexdigits
|
||||
| ("0b"|"0B") , bindigits ; (* sorry, no e-notation! *)
|
||||
visible = ? ASCII 0x20 to 0x7E ? ;
|
||||
string = '"' , (visible | visible , stringlit) , '"' ;
|
||||
string = '"' , {visible} , '"' ;
|
||||
|
||||
letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N"
|
||||
| "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b"
|
||||
@@ -2493,6 +2517,11 @@ LAMBDA (type: op, value: "~>")
|
||||
[2. arg1]
|
||||
[3. argN...]
|
||||
2. stmt
|
||||
|
||||
ARRAY CONSTRUCTOR (type: function, value: undefined)
|
||||
1. 0th element of the array
|
||||
2. 1st element of the array
|
||||
[3. Nth element of the array...]
|
||||
*/
|
||||
// @returns BasicAST
|
||||
bF._EquationIllegalTokens = ["IF","THEN","ELSE","DEFUN","ON"];
|
||||
@@ -2787,15 +2816,15 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
|
||||
expr = (* this basically blocks some funny attemps such as using DEFUN as anon function because everything is global in BASIC *)
|
||||
? empty string ?
|
||||
| lit
|
||||
| array_inner
|
||||
| "{" , [expr , {"," , expr}] , "}"
|
||||
| "(" , expr , ")"
|
||||
| ident_tuple
|
||||
| "IF" , expr_sans_asgn , "THEN" , expr , ["ELSE" , expr]
|
||||
| kywd , expr - "(" (* also deals with FOR statement *)
|
||||
(* at this point, if OP is found in paren-level 0, skip function_call *)
|
||||
| function_call
|
||||
| ("FOR"|"FOREACH") , expr
|
||||
| expr , op , expr
|
||||
| op_uni , expr ;
|
||||
| op_uni , expr
|
||||
| kywd , expr - "("
|
||||
| function_call ;
|
||||
|
||||
* @return: BasicAST
|
||||
*/
|
||||
@@ -2905,7 +2934,7 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
|
||||
/*************************************************************************/
|
||||
|
||||
// ## case for:
|
||||
// | array_inner
|
||||
// | "{" , [expr , {"," , expr}] , "}"
|
||||
if (curlyStart == 0 && curlyEnd == tokens.length - 1) {
|
||||
bF.parserPrintdbgline('e', "Array", lnum, recDepth);
|
||||
return bF._parseArrayLiteral(lnum, tokens, states, recDepth + 1);
|
||||
@@ -2943,31 +2972,16 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
|
||||
/*************************************************************************/
|
||||
|
||||
// ## case for:
|
||||
// | kywd , expr (* kywd = ? words that exists on the list of predefined function that are not operators ? ; *)
|
||||
if (bS.builtin[headTkn] && headSta == "lit" && !bF._opPrc[headTkn] &&
|
||||
states[1] != "paren" && tokens[1] != "("
|
||||
) {
|
||||
bF.parserPrintdbgline('e', 'Builtin Function Call w/o Paren', lnum, recDepth);
|
||||
|
||||
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// ## case for:
|
||||
// (* at this point, if OP is found in paren-level 0, skip function_call *)
|
||||
// | function_call ;
|
||||
if (topmostOp === undefined) { // don't remove this IF statement!
|
||||
// | ("FOR"|"FOREACH") , expr
|
||||
try {
|
||||
bF.parserPrintdbgline('e', "Trying Function Call...", lnum, recDepth);
|
||||
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1);
|
||||
bF.parserPrintdbgline('e', "Trying FOR Expression...", lnum, recDepth);
|
||||
return bF._parseForLoop(lnum, tokens, states, recDepth + 1);
|
||||
}
|
||||
// if ParserError is raised, continue applying other rules
|
||||
catch (e) {
|
||||
if (!(e instanceof ParserError)) throw e;
|
||||
bF.parserPrintdbgline('e', 'It was NOT!', lnum, recDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
@@ -3020,10 +3034,38 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// ## case for:
|
||||
// | kywd , expr - "("
|
||||
if (bS.builtin[headTkn] && headSta == "lit" && !bF._opPrc[headTkn] &&
|
||||
states[1] != "paren" && tokens[1] != "("
|
||||
) {
|
||||
bF.parserPrintdbgline('e', 'Builtin Function Call w/o Paren', lnum, recDepth);
|
||||
|
||||
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// ## case for:
|
||||
// | function_call ;
|
||||
if (topmostOp === undefined) { // don't remove this IF statement!
|
||||
try {
|
||||
bF.parserPrintdbgline('e', "Trying Function Call...", lnum, recDepth);
|
||||
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1);
|
||||
}
|
||||
// if ParserError is raised, continue applying other rules
|
||||
catch (e) {
|
||||
if (!(e instanceof ParserError)) throw e;
|
||||
bF.parserPrintdbgline('e', 'It was NOT!', lnum, recDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
throw new ParserError(`Expression "${tokens.join(" ")}" cannot be parsed in ${lnum}`);
|
||||
} // END of EXPR
|
||||
/** Parses following EBNF rule:
|
||||
"{" , expr , "}" , ["," , "{" , expr , "}"] ;
|
||||
"{" , [expr , {"," , expr}] , "}"
|
||||
* @return: BasicAST
|
||||
*/
|
||||
bF._parseArrayLiteral = function(lnum, tokens, states, recDepth) {
|
||||
@@ -3191,6 +3233,40 @@ bF._parseIfMode = function(lnum, tokens, states, recDepth, exprMode) {
|
||||
|
||||
throw new ParserError("not an IF "+(exprMode) ? "expression" : "statement");
|
||||
} // END of IF
|
||||
/** Parses following EBNF rule:
|
||||
("FOR"|"FOREACH") , expr
|
||||
* @return: BasicAST
|
||||
*/
|
||||
bF._parseForLoop = function(lnum, tokens, states, recDepth) {
|
||||
bF.parserPrintdbg2('\\', lnum, tokens, states, recDepth);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
let headTkn = tokens[0].toUpperCase();
|
||||
let headSta = states[0];
|
||||
|
||||
let treeHead = new BasicAST();
|
||||
treeHead.astLnum = lnum;
|
||||
|
||||
// ## case for:
|
||||
// ("FOR"|"FOREACH") , expr
|
||||
if (("FOR" == headTkn || "FOREACH" == headTkn) && "lit" == headSta) {
|
||||
|
||||
treeHead.astValue = headTkn;
|
||||
treeHead.astType = "function";
|
||||
|
||||
treeHead.astLeaves[0] = bF._parseExpr(lnum,
|
||||
tokens.slice(1),
|
||||
states.slice(1),
|
||||
recDepth + 1
|
||||
);
|
||||
|
||||
return treeHead;
|
||||
}
|
||||
|
||||
throw new ParserError("not an FOR/FOREACH expression");
|
||||
|
||||
} // END of FOR
|
||||
/** Parses following EBNF rule:
|
||||
ident_tuple = "[" , ident , ["," , ident] , "]" ;
|
||||
* @return: BasicAST
|
||||
@@ -3330,7 +3406,7 @@ bF._parseFunctionCall = function(lnum, tokens, states, recDepth) {
|
||||
|
||||
// recursively parse function arguments
|
||||
treeHead.astLeaves = argPos.map((x,i) => {
|
||||
bF.parserPrintdbgline("F", 'Function Arguments #'+(i+1), lnum, recDepth);
|
||||
bF.parserPrintdbgline("F", `Function Arguments #${i+1} of ${argPos.length}`, lnum, recDepth);
|
||||
|
||||
// check for empty tokens
|
||||
if (x.end - x.start < 0) throw new ParserError("not a function call because it's malformed");
|
||||
|
||||
@@ -23,24 +23,26 @@ public class AppLoader {
|
||||
appConfig.resizable = false;
|
||||
appConfig.title = appTitle;
|
||||
appConfig.forceExit = true;
|
||||
appConfig.width = 560;//720;
|
||||
appConfig.height = 448;//480;
|
||||
appConfig.width = 810;//720;
|
||||
appConfig.height = 300;//480;
|
||||
|
||||
|
||||
// val vm = VM(64.kB(), TheRealWorld(), arrayOf(GenericBios))
|
||||
//VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, BasicRom.INSTANCE});
|
||||
//VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE});
|
||||
//VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE});
|
||||
VM vm = new VM(256 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.INSTANCE});
|
||||
|
||||
// uncomment to target the TerranBASIC runner
|
||||
VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE});
|
||||
//VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE});
|
||||
|
||||
EmulInstance reference = new EmulInstance(appConfig, vm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", "assets/disk0");
|
||||
EmulInstance reference2 = new EmulInstance(appConfig, vm, "net.torvald.tsvm.peripheral.ReferenceLikeLCD", "assets/disk0");
|
||||
EmulInstance term = new EmulInstance(appConfig, vm, "net.torvald.tsvm.peripheral.TexticsAdapter", "assets/disk0");
|
||||
EmulInstance portable = new EmulInstance(appConfig, vm, "net.torvald.tsvm.peripheral.CharacterLCDdisplay", "assets/disk0");
|
||||
|
||||
new LwjglApplication(new VMGUI(reference), appConfig);
|
||||
EmulInstance wp = new EmulInstance(appConfig, vm, "net.torvald.tsvm.peripheral.WpTerm", "assets/wpdisk");
|
||||
|
||||
new LwjglApplication(new VMGUI(wp), appConfig);
|
||||
}
|
||||
|
||||
public static ShaderProgram loadShaderFromFile(String vert, String frag) {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package net.torvald.tsvm.peripheral
|
||||
|
||||
import net.torvald.tsvm.CompressorDelegate
|
||||
import net.torvald.tsvm.CompressorDelegate.GZIP_HEADER
|
||||
import net.torvald.tsvm.VM
|
||||
import net.torvald.tsvm.startsWith
|
||||
import java.io.File
|
||||
|
||||
object OEMBios : VMProgramRom {
|
||||
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/TBMBIOS.js").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import net.torvald.tsvm.VM
|
||||
import net.torvald.tsvm.kB
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class TexticsAdapter(vm: VM) : GraphicsAdapter(vm, AdapterConfig(
|
||||
open class TexticsAdapter(vm: VM, config: AdapterConfig = AdapterConfig(
|
||||
"crt_white",
|
||||
720,
|
||||
480,
|
||||
@@ -21,19 +21,7 @@ class TexticsAdapter(vm: VM) : GraphicsAdapter(vm, AdapterConfig(
|
||||
"./hp2640.png",
|
||||
0.32f,
|
||||
GraphicsAdapter.TEXT_TILING_SHADER_MONOCHROME
|
||||
)) {
|
||||
/*class TexticsAdapter(vm: VM) : GraphicsAdapter(vm, AdapterConfig(
|
||||
"crt_color",
|
||||
560,
|
||||
448,
|
||||
80,
|
||||
32,
|
||||
254,
|
||||
255,
|
||||
256.kB(),
|
||||
"./cp437_fira_code.png",
|
||||
0.64f
|
||||
)) {*/
|
||||
)) : GraphicsAdapter(vm, config) {
|
||||
|
||||
private val crtGradTex = Texture("./assets/crt_grad.png")
|
||||
|
||||
@@ -88,3 +76,17 @@ class TexticsAdapter(vm: VM) : GraphicsAdapter(vm, AdapterConfig(
|
||||
super.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
class WpTerm(vm: VM) : TexticsAdapter(vm = vm, AdapterConfig(
|
||||
"crt_amber",
|
||||
810,
|
||||
300,
|
||||
90,
|
||||
20,
|
||||
254,
|
||||
0,
|
||||
256.kB(),
|
||||
"./hp2640.png",
|
||||
0.32f,
|
||||
GraphicsAdapter.TEXT_TILING_SHADER_MONOCHROME
|
||||
))
|
||||
@@ -6,20 +6,15 @@ import net.torvald.tsvm.VM
|
||||
import net.torvald.tsvm.startsWith
|
||||
import java.io.File
|
||||
|
||||
interface VMProgramRom {
|
||||
fun readAll(): String
|
||||
operator fun get(addr: Int): Byte
|
||||
}
|
||||
|
||||
object GenericBios : VMProgramRom {
|
||||
open class VMProgramRom(path: String) {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/bios1.bin").readBytes()
|
||||
val bytes = File(path).readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
@@ -27,100 +22,14 @@ object GenericBios : VMProgramRom {
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
|
||||
object QuickBios : VMProgramRom {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/quick.js").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
|
||||
object BasicBios : VMProgramRom {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/basicbios.js").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
|
||||
object TandemBios : VMProgramRom {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/tandemport.js").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
|
||||
object BasicRom : VMProgramRom {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/basic.bin").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
|
||||
object TBASRelBios : VMProgramRom {
|
||||
private val contents: ByteArray
|
||||
|
||||
init {
|
||||
val bytes = File("./assets/bios/tbasdist.js").readBytes()
|
||||
contents = bytes.sliceArray(0 until minOf(65536, bytes.size))
|
||||
}
|
||||
|
||||
override fun readAll(): String {
|
||||
// check if bios is compressed in gzip
|
||||
return if (contents.startsWith(GZIP_HEADER))
|
||||
CompressorDelegate.decomp(contents).toString(VM.CHARSET)
|
||||
else
|
||||
contents.toString(VM.CHARSET)
|
||||
}
|
||||
|
||||
override fun get(addr: Int): Byte = contents[addr]
|
||||
}
|
||||
object GenericBios : VMProgramRom("./assets/bios/bios1.bin")
|
||||
object OEMBios : VMProgramRom("./assets/bios/TBMBIOS.js")
|
||||
object QuickBios : VMProgramRom("./assets/bios/quick.js")
|
||||
object BasicBios : VMProgramRom("./assets/bios/basicbios.js")
|
||||
object TandemBios : VMProgramRom("./assets/bios/tandemport.js")
|
||||
object BasicRom : VMProgramRom("./assets/bios/basic.bin")
|
||||
object TBASRelBios : VMProgramRom("./assets/bios/tbasdist.js")
|
||||
object WPBios : VMProgramRom("./assets/bios/wp.js")
|
||||
Reference in New Issue
Block a user