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