mirror of https://github.com/lukechilds/node.git
Browse Source
Now supports: - command options: .help, .break, .clear, .exit - local vars and global functions - ability to print 0, false and "" - when value is a function, prints [Function] - when object is circular, prints [Circular Object] instead of throwing an errorv0.7.4-release
RayMorgan
15 years ago
1 changed files with 156 additions and 18 deletions
@ -1,37 +1,175 @@ |
|||
// A repl library that you can include in your own code to get a runtime
|
|||
// interface to your program. Just require("/repl.js").
|
|||
|
|||
puts("Type '.help' for options."); |
|||
|
|||
node.stdio.open(); |
|||
node.stdio.addListener("data", readline); |
|||
|
|||
var buffered_cmd = ''; |
|||
var trimmer = /^\s*(.+)\s*$/m; |
|||
var scopedVar = /^\s*var\s*([_\w\$]+)(.*)$/m; |
|||
var scopeFunc = /^\s*function\s*([_\w\$]+)/; |
|||
|
|||
exports.prompt = "node> "; |
|||
|
|||
function displayPrompt () { |
|||
print(buffered_cmd.length ? '... ' : exports.prompt); |
|||
} |
|||
exports.scope = {}; |
|||
|
|||
displayPrompt(); |
|||
|
|||
node.stdio.addListener("data", function (cmd) { |
|||
var matches = trimmer.exec(cmd); |
|||
|
|||
if (matches && matches.length == 2) { |
|||
cmd = matches[1]; |
|||
/** |
|||
* The main REPL function. This is called everytime the user enters |
|||
* data on the command line. |
|||
*/ |
|||
function readline (cmd) { |
|||
cmd = trimWhitespace(cmd); |
|||
|
|||
// Check to see if a REPL keyword was used. If it returns true,
|
|||
// display next prompt and return.
|
|||
if (parseREPLKeyword(cmd) === true) { |
|||
return; |
|||
} |
|||
|
|||
// The catchall for errors
|
|||
try { |
|||
buffered_cmd += cmd; |
|||
// This try is for determining if the command is complete, or should
|
|||
// continue onto the next line.
|
|||
try { |
|||
buffered_cmd += cmd; |
|||
try { |
|||
puts(JSON.stringify(eval(buffered_cmd))); |
|||
buffered_cmd = ''; |
|||
} catch (e) { |
|||
if (!(e instanceof SyntaxError)) |
|||
throw e; |
|||
buffered_cmd = convertToScope(buffered_cmd); |
|||
|
|||
// Scope the readline with exports.scope to provide "local" vars
|
|||
with (exports.scope) { |
|||
var ret = eval(buffered_cmd); |
|||
printValue(ret); |
|||
} |
|||
} catch (e) { |
|||
puts('caught an exception: ' + e); |
|||
|
|||
buffered_cmd = ''; |
|||
} catch (e) { |
|||
if (!(e instanceof SyntaxError)) |
|||
throw e; |
|||
} |
|||
} catch (e) { |
|||
// On error: Print the error and clear the buffer
|
|||
puts('caught an exception: ' + e); |
|||
buffered_cmd = ''; |
|||
} |
|||
|
|||
displayPrompt(); |
|||
}); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Used to display the prompt. |
|||
*/ |
|||
function displayPrompt () { |
|||
print(buffered_cmd.length ? '... ' : exports.prompt); |
|||
} |
|||
|
|||
/** |
|||
* Used to parse and execute the Node REPL commands. |
|||
* |
|||
* @param {cmd} cmd The command entered to check |
|||
* @returns {Boolean} If true it means don't continue parsing the command |
|||
*/ |
|||
function parseREPLKeyword (cmd) { |
|||
switch (cmd) { |
|||
case ".break": |
|||
buffered_cmd = ''; |
|||
displayPrompt(); |
|||
return true; |
|||
case ".clear": |
|||
puts("Clearing Scope..."); |
|||
buffered_cmd = ''; |
|||
exports.scope = {}; |
|||
displayPrompt(); |
|||
return true; |
|||
case ".exit": |
|||
node.stdio.close(); |
|||
return true; |
|||
case ".help": |
|||
puts(".break\tSometimes you get stuck in a place you can't get out... This will get you out."); |
|||
puts(".clear\tBreak, and also clear the local scope."); |
|||
puts(".exit\tExit the prompt"); |
|||
puts(".help\tShow repl options"); |
|||
displayPrompt(); |
|||
return true; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/** |
|||
* Trims Whitespace from a line. |
|||
* |
|||
* @param {String} cmd The string to trim the whitespace from |
|||
* @returns {String} The trimmed string |
|||
*/ |
|||
function trimWhitespace (cmd) { |
|||
var matches = trimmer.exec(cmd); |
|||
if (matches && matches.length == 2) { |
|||
return matches[1]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Converts commands that use var and function <name>() to use the |
|||
* local exports.scope when evaled. This provides a local scope |
|||
* on the REPL. |
|||
* |
|||
* @param {String} cmd The cmd to convert |
|||
* @returns {String} The converted command |
|||
*/ |
|||
function convertToScope (cmd) { |
|||
var matches; |
|||
|
|||
// Replaces: var foo = "bar"; with: exports.scope.foo = bar;
|
|||
matches = scopedVar.exec(cmd); |
|||
if (matches && matches.length == 3) { |
|||
return "exports.scope." + matches[1] + matches[2]; |
|||
} |
|||
|
|||
// Replaces: function foo() {}; with: foo = function foo() {};
|
|||
matches = scopeFunc.exec(buffered_cmd); |
|||
if (matches && matches.length == 2) { |
|||
return matches[1] + " = " + buffered_cmd; |
|||
} |
|||
|
|||
return cmd; |
|||
} |
|||
|
|||
/** |
|||
* Echos the value of a value. Trys to print the value out |
|||
* in the best way possible given the different types. |
|||
* |
|||
* @param {Object} value The object to print out |
|||
*/ |
|||
function printValue (value) { |
|||
if (value === 0) { |
|||
puts("0"); |
|||
return; |
|||
} |
|||
|
|||
if (value === false) { |
|||
puts("false"); |
|||
return; |
|||
} |
|||
|
|||
if (value === "") { |
|||
puts('""'); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(value) == "function") { |
|||
puts("[Function]"); |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
puts(JSON.stringify(value)); |
|||
} catch (e) { |
|||
if (e.message.search("circular")) |
|||
puts("[Circular Object]"); |
|||
else |
|||
throw e; |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue