diff --git a/dist/examples/examples.js b/dist/examples/examples.js
index 62c077e..2a251da 100644
--- a/dist/examples/examples.js
+++ b/dist/examples/examples.js
@@ -1519,13 +1519,32 @@ PRINT
'
DEF FNnumStr$(x) = RIGHT$(STR$(x), LEN(STR$(x)) - 1)
'
+PRINT "Properties of "; FNnumStr$(n); "!:"
+GOSUB 400 ' number of digits of n!
GOSUB 500 ' trailing zeroes of n! (for checking the result)
PRINT
+FRAME
GOSUB 1000 ' algorithm1
PRINT
+FRAME
GOSUB 2000 ' algorithm2
END
'
+REM Calculate number of digits
+REM https://www.geeksforgeeks.org/count-digits-in-a-factorial-using-logarithm/
+400 digits = 0
+FOR i = 2 TO n
+ digits = digits + LOG10(i)
+NEXT
+digits = INT(digits) + 1
+'or use Stirling's formula:
+econst = 2.718281828459045
+digits2 = n * LOG10(n / econst) + LOG10(2 * PI * n) / 2.0
+digits2 = INT(digits2+1)
+if digits<>digits2 THEN ?"digits calculation differs:"; digits; digits2
+PRINT "Number of digits:"; digits
+RETURN
+'
REM Calculate number of trailing zeroes (to check the result)
REM https://www.geeksforgeeks.org/count-trailing-zeroes-factorial-number/
500 trailz = 0
@@ -1534,18 +1553,13 @@ WHILE INT(n / i) >= 1
trailz = trailz + INT(n / i)
i = i * 5
WEND
-PRINT "Number of trailing zeroes for "; FNnumStr$(n); "!:"; trailz
+PRINT "Number of trailing zeroes:"; trailz
RETURN
'
REM factorial 1
1000 t = TIME
-REM Calculate number of 5-digit blocks
-l = 1
-FOR i = 2 TO n
- l = l + LOG10(i)
-NEXT
-ri = INT(l / 5 + 1)
-DIM r(ri)
+ri = INT(digits / 5) - (digits mod 5 <> 0): 'number of 5-digit blocks
+DIM r(ri + 1): 'one more to allow carry
r(1) = 1
'
REM Calculate factorial using sum of logarithms
@@ -1592,20 +1606,15 @@ RETURN
REM factorial2
REM based on: https://www.geeksforgeeks.org/factorial-large-number/
2000 t = TIME
-l = 1
-FOR i = 2 TO n
- l = l + LOG10(i)
-NEXT
-ri2 = INT(l) + 1
-DIM res(ri2)
+DIM res(digits)
res(1) = 1
resSize = 1
FOR x = 2 TO n
carry = 0
FOR i = 1 TO resSize
prod = res(i) * x + carry
- res(i) = prod MOD 10
carry = INT(prod / 10)
+ res(i) = prod - carry * 10
NEXT i
WHILE carry > 0
resSize = resSize + 1
@@ -2443,6 +2452,63 @@ END
'
`);
+cpcBasic.addItem("", `
+ REM sierpin - Sierpinski triangle
+ REM see also: https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
+ DEG
+ MODE 2
+ DIM cx(5),cy(5),r(5),lc(5),s$(80,25),smc(25)
+ cx(1)=320*80/640:cy(1)=140*25/400
+ r(1)=75:r(2)=40:r(3)=20:r(4)=12:r(5)=8
+ '
+ sa=120
+ st=1
+ GOSUB 800: 'init
+ GOSUB 1000: 'compute
+ GOSUB 2000: 'output
+ END
+ '
+ ' Initialize output array
+ 800 FOR r1=1 TO 25
+ FOR c1=1 TO 79
+ s$(c1,r1)=" "
+ NEXT
+ NEXT
+ RETURN
+ '
+ ' Compute
+ 1000 cx1=ROUND(cx(st))
+ cy1=ROUND((25-cy(st)))
+ 'lc(st)=0
+ s$(cx1,cy1)=chr$(48+st)
+ IF cx1>smc(cy1) THEN smc(cy1)=cx1 'update max column
+ IF st<5 THEN GOSUB 2000:FRAME: 'intermediate output
+ IF st=5 THEN RETURN
+ lc(st)=0
+ start=1
+ WHILE (lc(st) MOD 360)<>0 OR start=1
+ start=0
+ cx(st+1)=cx(st)+1.7*80/640*r(st)*SIN(sa+lc(st))
+ cy(st+1)=cy(st)+1.7*25/400*r(st)*COS(sa+lc(st))
+ st=st+1
+ GOSUB 1000 'recursive call
+ st=st-1
+ lc(st)=lc(st)+2*sa
+ WEND
+ RETURN
+ '
+ ' Output
+ 2000 CLS
+ FOR r1=1 TO 25
+ FOR c1=1 TO smc(r1)
+ PRINT s$(c1,r1);
+ NEXT
+ PRINT
+ NEXT
+ RETURN
+ '
+`);
+
cpcBasic.addItem("", `
REM sievebe - Sieve Benchmark
MODE 2
@@ -2540,62 +2606,6 @@ DATA -1,-1,-1: '"end"
'
`);
-cpcBasic.addItem("", `
-REM test1 - Test 1
-DEG
-MODE 2
-DIM cx(5),cy(5),r(5),lc(5),s$(80,25),smc(25)
-cx(1)=320*80/640:cy(1)=140*25/400
-r(1)=75:r(2)=40:r(3)=20:r(4)=12:r(5)=8
-'
-sa=120
-st=1
-GOSUB 800: 'init
-GOSUB 1000: 'compute
-GOSUB 2000: 'output
-END
-'
-' Initialize output array
-800 FOR r1=1 TO 25
- FOR c1=1 TO 79
- s$(c1,r1)=" "
- NEXT
-NEXT
-RETURN
-'
-' Compute
-1000 cx1=ROUND(cx(st))
-cy1=ROUND((25-cy(st)))
-'lc(st)=0
-s$(cx1,cy1)=chr$(48+st)
-IF cx1>smc(cy1) THEN smc(cy1)=cx1 'update max column
-IF st<5 THEN GOSUB 2000:FRAME: 'intermediate output
-IF st=5 THEN RETURN
-lc(st)=0
-start=1
-WHILE (lc(st) MOD 360)<>0 OR start=1
- start=0
- cx(st+1)=cx(st)+1.7*80/640*r(st)*SIN(sa+lc(st))
- cy(st+1)=cy(st)+1.7*25/400*r(st)*COS(sa+lc(st))
- st=st+1
- GOSUB 1000 'recursive call
- st=st-1
- lc(st)=lc(st)+2*sa
-WEND
-RETURN
-'
-' Output
-2000 CLS
-FOR r1=1 TO 25
- FOR c1=1 TO smc(r1)
- PRINT s$(c1,r1);
- NEXT
- PRINT
-NEXT
-RETURN
-'
-`);
-
cpcBasic.addItem("", `
10 REM testinpu - Test Input
20 CLS
diff --git a/dist/index.html b/dist/index.html
index 9752967..4662adf 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -4,7 +4,7 @@
-
LocoBasic v0.1.35
+ LocoBasic v0.1.36
diff --git a/package.json b/package.json
index 8225871..87b71c7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "locobasic",
- "version": "0.1.35",
+ "version": "0.1.36",
"description": "# LocoBasic - Loco BASIC",
"type": "commonjs",
"scripts": {
diff --git a/rollup.config.mjs b/rollup.config.mjs
index d72576d..c24f69b 100644
--- a/rollup.config.mjs
+++ b/rollup.config.mjs
@@ -6,7 +6,7 @@ export default [
input: 'src/main.ts', // main entry
output: {
file: 'dist/locobasic.js',
- format: 'umd', // "es" ECMAScript-Module
+ format: 'umd',
sourcemap: true,
name: 'locobasic',
globals: {
@@ -19,11 +19,15 @@ export default [
input: "./src/UI/UI.ts", // main entry
output: {
file: "dist/locobasicUI.js",
- format: "umd", // "es" ECMAScript-Module
+ format: "umd",
sourcemap: true,
name: "locobasicUI"
},
- plugins: [typescript()]
+ plugins: [
+ typescript({
+ tsconfig: "./src/UI/tsconfig.json"
+ })
+ ]
}
];
diff --git a/src/BasicVmBrowser.ts b/src/BasicVmBrowser.ts
index 8f9e842..e4a7bcd 100644
--- a/src/BasicVmBrowser.ts
+++ b/src/BasicVmBrowser.ts
@@ -32,11 +32,11 @@ export class BasicVmBrowser extends BasicVmCore {
/**
* Prompts the user with a message and returns the input.
* @param msg - The message to prompt.
- * @returns The user input.
+ * @returns A promise that resolves to the user input or null if canceled.
*/
- public fnOnPrompt(msg: string): string | null {
+ public async fnOnPrompt(msg: string): Promise {
const input = this.ui.prompt(msg);
- return input;
+ return Promise.resolve(input);
}
/**
diff --git a/src/BasicVmCore.ts b/src/BasicVmCore.ts
index fb0ff3c..9ab67c6 100644
--- a/src/BasicVmCore.ts
+++ b/src/BasicVmCore.ts
@@ -26,7 +26,7 @@ export class BasicVmCore implements IVmAdmin {
// override
}
- protected fnOnPrompt(_msg: string): string | null { // eslint-disable-line @typescript-eslint/no-unused-vars
+ protected async fnOnPrompt(_msg: string): Promise { // eslint-disable-line @typescript-eslint/no-unused-vars
// override
return "";
}
@@ -133,7 +133,7 @@ export class BasicVmCore implements IVmAdmin {
this.output += args.join('');
}
- public prompt(msg: string): string | null {
+ public prompt(msg: string): Promise {
this.flush();
return this.fnOnPrompt(msg);
};
diff --git a/src/BasicVmNode.ts b/src/BasicVmNode.ts
index 6553c3f..fc8f1ed 100644
--- a/src/BasicVmNode.ts
+++ b/src/BasicVmNode.ts
@@ -62,9 +62,9 @@ export class BasicVmNode extends BasicVmCore {
console.log(msg.replace(/\n$/, ""));
}
- public fnOnPrompt(msg: string): string {
+ public async fnOnPrompt(msg: string): Promise {
console.log(msg);
- return "";
+ return Promise.resolve("");
}
public fnGetPenColor(num: number): string {
diff --git a/src/Interfaces.ts b/src/Interfaces.ts
index bc2cc42..0054c9c 100644
--- a/src/Interfaces.ts
+++ b/src/Interfaces.ts
@@ -21,7 +21,7 @@ export interface IVm {
paper(color: number): void;
pen(color: number): void;
print(_msg: string): void;
- prompt(_msg: string): string | null;
+ prompt(_msg: string): Promise;
}
export interface IVmAdmin extends IVm {
diff --git a/src/NodeParts.ts b/src/NodeParts.ts
index 7d8873d..1cafdef 100644
--- a/src/NodeParts.ts
+++ b/src/NodeParts.ts
@@ -29,7 +29,7 @@ const dummyVm: DummyVm = {
paper(num: number) { this.debug("paper:", num); },
pen(num: number) { this.debug("pen:", num); },
print(...args: (string | number)[]) { this._output += args.join(''); },
- prompt(msg: string) { console.log(msg); return ""; }
+ async prompt(msg: string) { console.log(msg); return ""; }
};
export class NodeParts {
diff --git a/src/Semantics.ts b/src/Semantics.ts
index 09e10cf..6cd3aa7 100644
--- a/src/Semantics.ts
+++ b/src/Semantics.ts
@@ -8,6 +8,7 @@ function getCodeSnippets() {
const _data: (string | number)[] = [];
let _dataPtr = 0;
const _restoreMap: Record = {};
+ const frame = async () => {}; // dummy
const codeSnippets = {
bin$: function bin$(num: number, pad: number = 0): string {
@@ -42,7 +43,7 @@ function getCodeSnippets() {
_o.flush();
return "end";
},
- frame: function frame() { // async
+ frame: async function frame() {
_o.flush();
return new Promise(resolve => setTimeout(() => resolve(), Date.now() % 50));
},
@@ -52,13 +53,17 @@ function getCodeSnippets() {
hex$: function hex$(num: number, pad?: number) {
return num.toString(16).toUpperCase().padStart(pad || 0, "0");
},
- input: function input(msg: string, isNum: boolean) { // async
- _o.flush();
- return new Promise(resolve => setTimeout(() => {
- const input = _o.prompt(msg);
- resolve(isNum ? Number(input) : input);
- }, 5));
- },
+ input: async function input(msg: string, isNum: boolean) {
+ await frame();
+ const input = await _o.prompt(msg);
+ if (input === null) {
+ throw new Error("Input canceled");
+ } else if (isNum && isNaN(Number(input))) {
+ throw new Error("Invalid number input");
+ } else {
+ return isNum ? Number(input) : input;
+ }
+ },
mid$Assign: function mid$Assign(s: string, start: number, newString: string, len?: number) {
start -= 1;
len = Math.min(len ?? newString.length, newString.length, s.length - start);
@@ -225,11 +230,9 @@ function getSemantics(semanticsHelper: ISemanticsHelper): ActionDict {
if (instrMap[key]) {
const code = String((codeSnippets[key as keyof typeof codeSnippets]).toString());
const adaptedCode = trimIndent(code);
- if (adaptedCode.includes("Promise") || adaptedCode.includes("await")) {
- lineList.push("async " + adaptedCode);
+ lineList.push(adaptedCode);
+ if (adaptedCode.startsWith("async ")) {
needsAsync = true;
- } else {
- lineList.push(adaptedCode);
}
}
}
@@ -507,6 +510,7 @@ function getSemantics(semanticsHelper: ISemanticsHelper): ActionDict {
Input(_inputLit: Node, message: Node, _semi: Node, e: Node) {
semanticsHelper.addInstr("input");
+ semanticsHelper.addInstr("frame");
const messageString = message.sourceString.replace(/\s*[;,]$/, "");
const identifier = e.eval();
diff --git a/src/UI/tsconfig.json b/src/UI/tsconfig.json
index cfb754b..29f2537 100644
--- a/src/UI/tsconfig.json
+++ b/src/UI/tsconfig.json
@@ -3,11 +3,11 @@
"compilerOptions": {
"outDir": "../../dist/UI",
"declarationDir": "../../dist/UI/types",
- //"sourceRoot":"./src/UI",
"lib": [
"es2020",
"dom"
],
+ "rootDir": "../",
"composite": true,
},
"include": ["./*.ts"],
diff --git a/src/tsconfig-base.json b/src/tsconfig-base.json
index 9547cd3..4ff078d 100644
--- a/src/tsconfig-base.json
+++ b/src/tsconfig-base.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "ESNext",
- "target": "ES6",
+ "target": "ES2017",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
diff --git a/tsconfig.json b/tsconfig.json
index 7646a42..35cf2a3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,15 +1,5 @@
{
- "compilerOptions": {
- "module": "ESNext",
- "target": "ES6",
- "moduleResolution": "node",
- "esModuleInterop": true,
- "strict": true,
- "declaration": true,
- "declarationMap": true,
- "sourceMap": true,
- },
-
+ "extends": "./src/tsconfig-base.json",
"files": [],
"include": [],
"references": [