Skip to content

Commit

Permalink
Support repl multiline input
Browse files Browse the repository at this point in the history
  • Loading branch information
hayd committed Nov 6, 2018
1 parent e1d5f82 commit bdd3d5b
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 18 deletions.
79 changes: 61 additions & 18 deletions js/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,39 +51,82 @@ export function replLoop(): void {
window.deno = deno; // FIXME use a new scope (rather than window).

const historyFile = "deno_history.txt";
const prompt = "> ";

const rid = startRepl(historyFile);

let line = "";
let code = "";
while (true) {
try {
line = readline(rid, prompt);
line = line.trim();
code = readLines(rid, "> ", " ");
} catch (err) {
if (err.message === "EOF") {
break;
}
console.error(err);
exit(1);
}
if (!line) {
if (!code) {
continue;
}
if (line === ".exit") {
break;
handleCommand(code);
evaluate(code);
}

close(rid);
}

function handleCommand(code: string): void {
if (code.trim() === ".exit") {
exit(0);
}
}

function evaluate(line: string): void {
try {
const result = eval.call(window, line); // FIXME use a new scope.
console.log(result);
} catch (err) {
if (err instanceof Error) {
console.error(`${err.constructor.name}: ${err.message}`);
} else {
console.error("Thrown:", err);
}
try {
const result = eval.call(window, line); // FIXME use a new scope.
console.log(result);
} catch (err) {
if (err instanceof Error) {
console.error(`${err.constructor.name}: ${err.message}`);
} else {
console.error("Thrown:", err);
}
}

function readLines(
rid: number,
prompt: string,
continuedPrompt: string
): string {
let code = "";
do {
code += readline(rid, prompt);
prompt = continuedPrompt;
} while (parenthesesAreOpen(code));
return code;
}

// modified from
// https://codereview.stackexchange.com/a/46039/148556
function parenthesesAreOpen(code: string): boolean {
const parentheses = "[]{}()";
const stack = [];

for (const ch of code) {
const bracePosition = parentheses.indexOf(ch);

if (bracePosition === -1) {
// not a paren
continue;
}

if (bracePosition % 2 === 0) {
stack.push(bracePosition + 1); // push next expected brace position
} else {
if (stack.length === 0 || stack.pop() !== bracePosition) {
return false;
}
}
}

close(rid);
return stack.length > 0;
}
6 changes: 6 additions & 0 deletions tools/repl_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def test_type_error(self):
assertEqual(err, 'TypeError: console is not a function\n')
assertEqual(code, 0)

def test_type_error(self):
out, err, code = self.input("(\n1 + 2\n)")
assertEqual(out, '3\n')
assertEqual(err, '')
assertEqual(code, 0)

def test_exit_command(self):
out, err, code = self.input(".exit", "'ignored'", exit=False)
assertEqual(out, '')
Expand Down

0 comments on commit bdd3d5b

Please sign in to comment.