[input strategy] input queueing

This commit is contained in:
2024-01-02 15:45:31 +05:30
parent 36ed3328d1
commit a15429d964
5 changed files with 955 additions and 694 deletions

View File

@@ -3,114 +3,144 @@ import { LoopStmtContext } from './generated/bfParser';
import { bfVisitor } from './generated/bfVisitor'; import { bfVisitor } from './generated/bfVisitor';
import { DiagnosticSeverity } from 'vscode-languageclient'; import { DiagnosticSeverity } from 'vscode-languageclient';
import { getTree } from './BranFlakesParseRunner'; import { getTree } from './BranFlakesParseRunner';
import { RuleNode } from 'antlr4ts/tree/RuleNode';
import InputStrategy from './input/InputStrategy';
export default class BranFlakesExecutorVisitor export default class BranFlakesExecutorVisitor
extends AbstractParseTreeVisitor<void> extends AbstractParseTreeVisitor<Promise<void>>
implements bfVisitor<void> { implements bfVisitor<Promise<void>>
{
/**
*
* @param input Input string
* @param inputPtr Input pointer to start from
*/
constructor(
protected inputStrategy: InputStrategy,
protected logger: (val: string) => Thenable<string>,
protected inputPtr: number = 0
) {
super();
}
// /**
// * The memory cells (Can work with negative cells this way)
// */
// protected cells: Map<number, number> = new Map();
/** protected byteArraySize: number = 30000;
* protected byteArray: Int8Array = new Int8Array(this.byteArraySize);
* @param input Input string /**
* @param inputPtr Input pointer to start from * Pointer
*/ */
constructor(protected input: string = '', protected inputPtr: number = 0) { protected ptr: number = 0;
super(); /** Output string */
} protected outputStrArray: string[] = [];
/**
* The memory cells (Can work with negative cells this way)
*/
protected cells: Map<number, number> = new Map();
protected byteArray: Int8Array = new Int8Array(30000);
/**
* Pointer
*/
protected ptr: number = 0;
/** Output string */
protected outputStrArray: string[] = [];
/** /**
* Output string (Available only after visiting) * Output string (Available only after visiting)
*/ */
public get outputStr() { public get outputStr() {
return this.outputStrArray.join(''); return this.outputStrArray.join('');
} }
defaultResult() {
return Promise.resolve();
}
/**
* Run a file
* @param text
* @param fn
* @param inputStrategy
* @returns
*/
static async run(
text: string,
fn: string,
inputStrategy: InputStrategy,
logger: (str:string) => Thenable<string>
) {
//get tree and issues
const { tree, issues } = getTree(text, fn);
defaultResult() { } //get only errors
/** const x = issues.filter(e => e.type === DiagnosticSeverity.Error);
* Run a file //if any error, drop
* @param text if (x.length > 0) {
* @param fn throw Error('Errors exist');
* @param input }
* @returns // make visitor
*/ const vis = new BranFlakesExecutorVisitor(inputStrategy, logger);
static run(text:string,fn: string, input:string){ //visit the tree
//get tree and issues await vis.visit(tree);
const { tree, issues } = getTree(text, fn);
//get only errors //get output
const x = issues.filter(e => e.type === DiagnosticSeverity.Error); return vis.outputStr;
//if any error, drop }
if (x.length > 0) {
throw Error('Errors exist');
}
// make visitor
const vis = new BranFlakesExecutorVisitor(input);
//visit the tree
vis.visit(tree);
//get output
return vis.outputStr;
}
visitLoopStmt(ctx: LoopStmtContext) { getCell(pointerIndex: number) {
while ((this.cells.get(this.ptr) ?? 0) !== 0) { return this.byteArray[pointerIndex];
this.visitChildren(ctx); }
} setCell(pointerIndex: number, value: number): void {
} this.byteArray[pointerIndex] = value;
visitPtrLeft() { }
--this.ptr; async visitLoopStmt(ctx: LoopStmtContext) {
} while ((this.getCell(this.ptr) ?? 0) !== 0) {
visitPtrRight() { await this.visitChildren(ctx);
++this.ptr; }
} }
visitPtrIncr() { async visitPtrLeft() {
--this.ptr;
}
async visitPtrRight() {
++this.ptr;
}
async visitPtrIncr() {
const val = this.getCell(this.ptr);
this.setCell(this.ptr, (val + 1) % 256);
}
async visitPtrDecr() {
const val = this.getCell(this.ptr);
this.setCell(this.ptr, (val + 255) % 256);
}
async visitOutputStmt() {
const val = this.getCell(this.ptr) ?? 0;
const str = String.fromCharCode(val);
const val = this.cells.get(this.ptr); this.outputStrArray.push(str);
if (val === undefined) { }
this.cells.set(this.ptr, 1);
} else if (val === 255) {
this.cells.delete(this.ptr);
} else {
this.cells.set(this.ptr, val + 1);
}
}
visitPtrDecr() {
// console.log('down',this.ptr,this.cells);
const val = this.cells.get(this.ptr);
if (val === undefined || val === 0) {
this.cells.set(this.ptr, 255);
} else if (val === 1) {
this.cells.delete(this.ptr);
} else {
this.cells.set(this.ptr, val - 1);
}
}
visitOutputStmt() {
const val = this.cells.get(this.ptr) ?? 0;
const str = String.fromCharCode(val);
// console.log('op',str);
this.outputStrArray.push(str);
}
visitInputStmt() { async visitInputStmt() {
//get char //get char
const char = this.input.charCodeAt(this.inputPtr) ?? 0; const char = await this.inputStrategy.getInput() ?? 0;
//increment the input pointer after this //increment the input pointer after this
this.inputPtr++; this.inputPtr++;
this.cells.set(this.ptr, char); this.setCell(this.ptr, char);
} }
// override for maintaining async
async visitChildren(node: RuleNode): Promise<void> {
// await this.logger("checking "+node.constructor.name)
let result = this.defaultResult();
await result;
let n = node.childCount;
for (let i = 0; i < n; i++) {
if (!this.shouldVisitNextChild(node, result)) {
break;
}
let c = node.getChild(i);
let childResult = c.accept(this);
result = this.aggregateResult(result, childResult);
await result;
}
return Promise.resolve();
}
// override for maintaining async
protected async aggregateResult(
aggregate: Promise<void>,
nextResult: Promise<void>
): Promise<void> {
await aggregate;
return nextResult;
}
} }

View File

@@ -4,7 +4,7 @@
* ------------------------------------------------------------------------------------------ */ * ------------------------------------------------------------------------------------------ */
import * as path from 'path'; import * as path from 'path';
import { workspace, ExtensionContext,commands, window } from 'vscode'; import { ExtensionContext,commands, window } from 'vscode';
import { import {
LanguageClient, LanguageClient,
LanguageClientOptions, LanguageClientOptions,
@@ -12,6 +12,7 @@ import {
TransportKind TransportKind
} from 'vscode-languageclient'; } from 'vscode-languageclient';
import BranFlakesExecutorVisitor from './BranFlakesExecutorVisitor'; import BranFlakesExecutorVisitor from './BranFlakesExecutorVisitor';
import { VSCodePromptInputStrategy } from './input/VSCodePromptInputStrategy';
let client: LanguageClient; let client: LanguageClient;
@@ -46,10 +47,8 @@ export function activate(context: ExtensionContext) {
const commandHandler = async()=>{ const commandHandler = async()=>{
const text= window.activeTextEditor.document.getText(); const text= window.activeTextEditor.document.getText();
const fn = window.activeTextEditor.document.fileName; const fn = window.activeTextEditor.document.fileName;
const input = await window.showInputBox({prompt:'Enter input (If not enough, program will assume 0)'}); const inputStrategy = new VSCodePromptInputStrategy(window.showInputBox);
const output = await BranFlakesExecutorVisitor.run(text,fn,inputStrategy,window.showInformationMessage);
const output = BranFlakesExecutorVisitor.run(text,fn,input);
await window.showInformationMessage(`Output: ${output}`); await window.showInformationMessage(`Output: ${output}`);
}; };

View File

@@ -0,0 +1,4 @@
export default interface InputStrategy {
getInput(): Promise<number>;
}

View File

@@ -0,0 +1,22 @@
import { CancellationToken, InputBoxOptions } from 'vscode';
import InputStrategy from './InputStrategy';
export class VSCodePromptInputStrategy implements InputStrategy {
private inputQueue:string;
constructor(private requestor:(promptOptions?:InputBoxOptions,cancelToken?:CancellationToken)=>Thenable<string>) {}
async getInput(): Promise<number> {
while (this.inputQueue.length == 0) {
await this.requestInputFromPrompt();
}
const character = this.inputQueue.charCodeAt(0);
this.inputQueue = this.inputQueue.substring(1);
//request input
return character;
}
private async requestInputFromPrompt() {
const inputPrompt = await this.requestor({prompt:"More input is required. Please provide input:"});
this.inputQueue += inputPrompt;
}
}

1386
package-lock.json generated

File diff suppressed because it is too large Load Diff