mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-25 18:33:11 +00:00
basic: added ENTER elapsed time
This commit is contained in:
parent
7d806850ee
commit
eeae662e6b
@ -10,7 +10,7 @@ export interface BASICOptions {
|
||||
optionalLabels : boolean; // can omit line numbers and use labels?
|
||||
optionalWhitespace : boolean; // can "crunch" keywords? also, eat extra ":" delims
|
||||
multipleStmtsPerLine : boolean; // multiple statements separated by ":"
|
||||
varNaming : 'A'|'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings
|
||||
varNaming : 'A'|'A1'|'A1$'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings
|
||||
squareBrackets : boolean; // "[" and "]" interchangable with "(" and ")"?
|
||||
tickComments : boolean; // support 'comments?
|
||||
hexOctalConsts : boolean; // support &H and &O integer constants?
|
||||
@ -198,6 +198,13 @@ export interface INPUT_Statement extends Statement {
|
||||
command: "INPUT";
|
||||
prompt: Expr;
|
||||
args: IndOp[];
|
||||
timeout?: Expr;
|
||||
elapsed?: IndOp;
|
||||
}
|
||||
|
||||
export interface ENTER_Statement extends INPUT_Statement {
|
||||
timeout: Expr;
|
||||
elapsed: IndOp;
|
||||
}
|
||||
|
||||
export interface DATA_Statement extends Statement {
|
||||
@ -852,6 +859,10 @@ export class BASICParser {
|
||||
if (lexpr.args != null && !/^[A-Z]?[$]?$/i.test(lexpr.name))
|
||||
this.dialectErrorNoSupport(`array names other than a single letter`);
|
||||
break;
|
||||
case 'A1$':
|
||||
if (!/^[A-Z][0-9]?[$]?$/i.test(lexpr.name))
|
||||
this.dialectErrorNoSupport(`variable names other than a letter followed by an optional digit`);
|
||||
break;
|
||||
case 'AA':
|
||||
if (lexpr.args == null && !/^[A-Z][A-Z0-9]?[$]?$/i.test(lexpr.name))
|
||||
this.dialectErrorNoSupport(`variable names other than a letter followed by an optional letter or digit`);
|
||||
@ -1057,11 +1068,11 @@ export class BASICParser {
|
||||
}
|
||||
/* for HP BASIC only */
|
||||
stmt__ENTER() : INPUT_Statement {
|
||||
var secs = this.parseExpr();
|
||||
var timeout = this.parseExpr();
|
||||
this.expectToken(',');
|
||||
var result = this.parseLexpr(); // TODO: this has to go somewheres
|
||||
var elapsed = this.parseLexpr(); // TODO: this has to go somewheres
|
||||
this.expectToken(',');
|
||||
return this.stmt__INPUT();
|
||||
return { command:'INPUT', prompt:null, args:this.parseLexprList(), timeout:timeout, elapsed:elapsed };
|
||||
}
|
||||
// TODO: DATA statement doesn't read unquoted strings
|
||||
stmt__DATA() : DATA_Statement {
|
||||
@ -1406,7 +1417,7 @@ export const HP_TIMESHARED_BASIC : BASICOptions = {
|
||||
optionalLabels : false,
|
||||
optionalWhitespace : false,
|
||||
multipleStmtsPerLine : true,
|
||||
varNaming : "A1",
|
||||
varNaming : "A1$",
|
||||
staticArrays : true,
|
||||
sharedArrayNamespace : false,
|
||||
defaultArrayBase : 1,
|
||||
@ -1874,6 +1885,7 @@ const BUILTIN_DEFS : BuiltinFunctionDef[] = [
|
||||
['OCT$', ['number'], 'string' ],
|
||||
['PI', [], 'number'],
|
||||
['POS', ['number'], 'number' ], // arg ignored
|
||||
['POS', ['string','string'], 'number' ], // HP POS
|
||||
['LEFT$', ['string', 'number'], 'string' ],
|
||||
['RND', [], 'number' ],
|
||||
['RND', ['number'], 'number' ],
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
import { BASICParser, DIALECTS, BASICOptions, CompileError } from "./compiler";
|
||||
import { BASICRuntime } from "./runtime";
|
||||
import { BASICRuntime, InputResponse } from "./runtime";
|
||||
import { EmuHalt } from "../emu";
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
@ -20,12 +20,12 @@ export function fuzz(buf) {
|
||||
runtime.print = (s) => {
|
||||
if (s == null) throw new Error("PRINT null string");
|
||||
}
|
||||
runtime.input = function(prompt: string, nargs: number) : Promise<string[]> {
|
||||
var p = new Promise<string[]>( (resolve, reject) => {
|
||||
runtime.input = function(prompt: string, nargs: number) : Promise<InputResponse> {
|
||||
var p = new Promise<InputResponse>( (resolve, reject) => {
|
||||
var arr = [];
|
||||
for (var i=0; i<Math.random()*10; i++)
|
||||
arr.push(i+"");
|
||||
resolve(arr);
|
||||
resolve({vals:arr, line:arr.join(' ')});
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
@ -69,9 +69,10 @@ runtime.print = (s:string) => {
|
||||
runtime.input = async (prompt:string) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
function answered(answer) {
|
||||
var vals = answer.toUpperCase().split(',');
|
||||
var line = answer.toUpperCase();
|
||||
var vals = line.split(',');
|
||||
//console.log(">>>",vals);
|
||||
resolve(vals);
|
||||
resolve({line:line, vals:vals});
|
||||
}
|
||||
prompt += ' ?';
|
||||
if (inputlines.length) {
|
||||
|
@ -16,6 +16,12 @@ function isUnOp(arg: basic.Expr): arg is basic.UnOp {
|
||||
return (arg as any).op != null && (arg as any).expr != null;
|
||||
}
|
||||
|
||||
export interface InputResponse {
|
||||
line: string;
|
||||
vals: string[];
|
||||
elapsed?: number;
|
||||
}
|
||||
|
||||
// expr2js() options
|
||||
class ExprOptions {
|
||||
isconst?: boolean; // only allow constant operations
|
||||
@ -408,8 +414,8 @@ export class BASICRuntime {
|
||||
}
|
||||
|
||||
// override this
|
||||
async input(prompt: string, nargs: number) : Promise<string[]> {
|
||||
return [];
|
||||
async input(prompt: string, nargs: number) : Promise<InputResponse> {
|
||||
return {line:"", vals:[]};
|
||||
}
|
||||
|
||||
// override this
|
||||
@ -730,22 +736,24 @@ export class BASICRuntime {
|
||||
}
|
||||
|
||||
do__INPUT(stmt : basic.INPUT_Statement) {
|
||||
var prompt = this.expr2js(stmt.prompt);
|
||||
var prompt = stmt.prompt != null ? this.expr2js(stmt.prompt) : '""';
|
||||
var elapsed = stmt.elapsed != null ? this.assign2js(stmt.elapsed) : "let ___";
|
||||
var setvals = '';
|
||||
stmt.args.forEach((arg, index) => {
|
||||
var lexpr = this.assign2js(arg);
|
||||
setvals += `
|
||||
var value = this.convert(${JSON.stringify(arg.name)}, vals[${index}]);
|
||||
var value = this.convert(${JSON.stringify(arg.name)}, response.vals[${index}]);
|
||||
valid &= this.isValid(value);
|
||||
${lexpr} = value;
|
||||
`
|
||||
});
|
||||
return `this.preInput();
|
||||
this.input(${prompt}, ${stmt.args.length}).then((vals) => {
|
||||
this.input(${prompt}, ${stmt.args.length}).then((response) => {
|
||||
let valid = 1;
|
||||
${setvals}
|
||||
this.postInput(valid);
|
||||
this.column = 0; // assume linefeed
|
||||
${elapsed} = response.elapsed;
|
||||
})`;
|
||||
}
|
||||
|
||||
@ -1165,7 +1173,10 @@ export class BASICRuntime {
|
||||
return Math.PI;
|
||||
}
|
||||
// TODO: POS(haystack, needle, start)
|
||||
POS(arg : number) : number { // arg ignored
|
||||
POS(arg1, arg2) { // arg ignored
|
||||
if (typeof arg1 == 'string' && typeof arg2 == 'string')
|
||||
return arg1.indexOf(arg2) >= 0 + 1;
|
||||
else
|
||||
return this.column + 1;
|
||||
}
|
||||
RIGHT$(arg : string, count : number) : string {
|
||||
|
@ -1,4 +1,6 @@
|
||||
|
||||
import { InputResponse } from "./basic/runtime";
|
||||
|
||||
export class TeleType {
|
||||
page: HTMLElement;
|
||||
fixed: boolean;
|
||||
@ -166,11 +168,12 @@ export class TeleTypeWithKeyboard extends TeleType {
|
||||
keephandler : boolean = true;
|
||||
uppercaseOnly : boolean = false;
|
||||
splitInput : boolean = false;
|
||||
resolveInput : (inp) => void;
|
||||
resolveInput : (InputResponse) => void;
|
||||
|
||||
focused : boolean = true;
|
||||
scrolling : number = 0;
|
||||
waitingfor : string;
|
||||
lastInputRequestTime : number;
|
||||
|
||||
constructor(page: HTMLElement, fixed: boolean, input: HTMLInputElement) {
|
||||
super(page, fixed);
|
||||
@ -214,6 +217,7 @@ export class TeleTypeWithKeyboard extends TeleType {
|
||||
$(this.input).addClass('transcript-input-char')
|
||||
else
|
||||
$(this.input).removeClass('transcript-input-char')
|
||||
this.lastInputRequestTime = Date.now();
|
||||
}
|
||||
hideinput() {
|
||||
this.showPrintHead(true);
|
||||
@ -238,12 +242,14 @@ export class TeleTypeWithKeyboard extends TeleType {
|
||||
}
|
||||
sendinput(s: string) {
|
||||
if (this.resolveInput) {
|
||||
var elapsed = Date.now() - this.lastInputRequestTime;
|
||||
if (this.uppercaseOnly) s = s.toUpperCase(); // TODO: always uppercase?
|
||||
this.addtext(s, 4);
|
||||
this.flushline();
|
||||
this.clearinput();
|
||||
this.hideinput(); // keep from losing input handlers
|
||||
this.resolveInput(this.splitInput ? s.split(',') : s);
|
||||
var vals = this.splitInput ? s.split(',') : null;
|
||||
this.resolveInput({line:s, vals:vals, elapsed:elapsed/1000});
|
||||
if (!this.keephandler) this.resolveInput = null;
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +262,6 @@ export class SourceEditor implements ProjectView {
|
||||
}
|
||||
|
||||
clearErrors() {
|
||||
this.refreshDebugState(false); // TODO: why?
|
||||
this.dirtylisting = true;
|
||||
// clear line widgets
|
||||
this.editor.clearGutter("gutter-info");
|
||||
|
@ -3,6 +3,7 @@ import { Platform, BasePlatform, BaseDebugPlatform, Preset, EmuState, inspectSym
|
||||
import { PLATFORMS, EmuHalt } from "../common/emu";
|
||||
import { loadScript } from "../ide/ui";
|
||||
import { TeleType, TeleTypeWithKeyboard } from "../common/teletype";
|
||||
import { InputResponse } from "../common/basic/runtime";
|
||||
|
||||
const ZMACHINE_PRESETS = [
|
||||
{ id: 'hello.inf', name: 'Hello World' },
|
||||
@ -71,7 +72,8 @@ class GlkImpl {
|
||||
3: new TeleType(null, true), // fake window for resizing
|
||||
};
|
||||
this.input = input;
|
||||
this.mainwnd.resolveInput = (s:string) => {
|
||||
this.mainwnd.resolveInput = (resp:InputResponse) => {
|
||||
var s = resp.line;
|
||||
if (this.vm.read_data.buffer) {
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
this.vm.read_data.buffer[i] = s.charCodeAt(i) & 0xff;
|
||||
|
Loading…
Reference in New Issue
Block a user