diff options
Diffstat (limited to 'src/repl.ts')
-rw-r--r-- | src/repl.ts | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/repl.ts b/src/repl.ts new file mode 100644 index 0000000..a42183a --- /dev/null +++ b/src/repl.ts @@ -0,0 +1,80 @@ +import type { TracingLogger } from './utils'; +import * as readline from 'node:readline/promises'; +import { stdin as input, stdout as output } from 'node:process'; +import { peggyParse } from './parser'; +import { evaluate } from './interpreter'; + +// cool asci logo for CPS +const LOGO = ` + _______ ________ ______ _______ __ +/ \\ / | / \\ / \\ / | +$$$$$$$ |$$$$$$$$/ /$$$$$$ |$$$$$$$ |$$ | +$$ |__$$ |$$ |__ $$ | $$/ $$ |__$$ |$$ | +$$ $$< $$ | $$ | $$ $$/ $$ | +$$$$$$$ |$$$$$/ $$ | __ $$$$$$$/ $$ | +$$ | $$ |$$ |_____ $$ \\__/ |$$ | $$ |_____ +$$ | $$ |$$ |$$ $$/ $$ | $$ | +$$/ $$/ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ + +`; + +const HELP = ` + This is the CPS REPL. You can enter CPS programs and see the result of evaluating them. + This REPL supports multi-line input. To end a multi-line input, enter an empty line. + + Commands: + help - Show this message + exit - Exit the REPL + + About: + Read "Compiling With Continuations" by Andrew W. Appel for more information about + this Intermediate Representation. + + Example: + ~> PRIMOP(+, [INT 1, INT 2], [result], [ + | APP(LABEL id, [VAR result]) + | ]) +`; + +export const doRepl = async ( + logger: TracingLogger, + prompt = 0, + rl = readline.createInterface({ input, output }), +): Promise<any> => { + if (prompt === 0) { + logger.info('welcome to recpl (read eval continue print loop) :)' + LOGO); + } + + const promptString = `[ ${prompt} ] ~> `; + const lines: string[] = [await rl.question(promptString)]; + while (lines.at(-1)) { + const line = lines.at(-1)!; + + if (lines.length === 1 && line === 'help') { + logger.info(HELP); + return doRepl(logger, prompt + 1, rl); + } + if (line === 'exit') { + logger.info('Exiting REPL...'); + rl.close(); + return; + } + + lines.push( + await rl.question(`|`.padStart(promptString.length - 1, ' ') + ' '), + ); + } + + const program = lines.slice(0, -1).join('\n'); + try { + const ast = peggyParse(program); + logger.debug('AST: ' + JSON.stringify(ast, null, 2)); + + const result = await evaluate(ast, logger.createChild('evaluate')); + logger.info('Result: ' + JSON.stringify(result, null, 2) + '\n'); + } catch (e) { + logger.error(e!.toString() + '\n'); + } + + return doRepl(logger, prompt + 1, rl); +}; |