|
@ -159,79 +159,52 @@ function REPLServer(prompt, stream, eval) { |
|
|
|
|
|
|
|
|
// First we attempt to eval as expression with parens.
|
|
|
// First we attempt to eval as expression with parens.
|
|
|
// This catches '{a : 1}' properly.
|
|
|
// This catches '{a : 1}' properly.
|
|
|
function tryParens() { |
|
|
|
|
|
var success = false; |
|
|
|
|
|
|
|
|
|
|
|
self.eval('(' + self.bufferedCommand + ')', |
|
|
self.eval('(' + self.bufferedCommand + ')', |
|
|
self.context, |
|
|
self.context, |
|
|
'repl', |
|
|
'repl', |
|
|
function(e, ret) { |
|
|
function(e, ret) { |
|
|
if (e) { |
|
|
if (e) return finish(e); |
|
|
if (!(e && e.constructor && |
|
|
|
|
|
e.constructor.name === 'SyntaxError')) { |
|
|
|
|
|
finish(e); |
|
|
|
|
|
} else { |
|
|
|
|
|
tryExpr(e); |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tryExpr(typeof ret === 'function', ret); |
|
|
|
|
|
}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ret === 'function' || e) { |
|
|
// Now as statement without parens.
|
|
|
// Now as statement without parens.
|
|
|
function tryExpr(e, ret) { |
|
|
self.eval(self.bufferedCommand, self.context, 'repl', finish); |
|
|
if (!e) return finish(null, ret); |
|
|
|
|
|
|
|
|
|
|
|
self.eval(self.bufferedCommand, self.context, |
|
|
|
|
|
'repl', function(e, ret) { |
|
|
|
|
|
|
|
|
|
|
|
if (e) { |
|
|
|
|
|
// instanceof doesn't work across context switches.
|
|
|
|
|
|
if (!(e && e.constructor && |
|
|
|
|
|
e.constructor.name === 'SyntaxError')) { |
|
|
|
|
|
return finish(e); |
|
|
|
|
|
// It could also be an error from JSON.parse
|
|
|
|
|
|
} else if (e && |
|
|
|
|
|
e.stack && |
|
|
|
|
|
e.stack.match(/^SyntaxError: Unexpected token .*\n/) && |
|
|
|
|
|
e.stack.match(/\n at Object.parse \(native\)\n/)) { |
|
|
|
|
|
return finish(e); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
finish(true); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
finish(null, ret); |
|
|
finish(null, ret); |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return tryParens(); |
|
|
} else { |
|
|
|
|
|
finish(null); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
finish(null); |
|
|
|
|
|
function finish(e, ret) { |
|
|
function finish(e, ret) { |
|
|
if (e) { |
|
|
// Convert error to string
|
|
|
if (e.stack) { |
|
|
e = e && (e.stack || e.toString()); |
|
|
self.outputStream.write(e.stack + '\n'); |
|
|
|
|
|
} else if (e === true) { |
|
|
// If error was SyntaxError and not JSON.parse error
|
|
|
|
|
|
if (e && e.match(/^SyntaxError/) && |
|
|
|
|
|
!(e.match(/^SyntaxError: Unexpected token .*\n/) && |
|
|
|
|
|
e.match(/\n at Object.parse \(native\)\n/))) { |
|
|
|
|
|
// Start buffering data like that:
|
|
|
|
|
|
// {
|
|
|
|
|
|
// ... x: 1
|
|
|
|
|
|
// ... }
|
|
|
self.displayPrompt(); |
|
|
self.displayPrompt(); |
|
|
return; |
|
|
return; |
|
|
} else { |
|
|
} else if (e) { |
|
|
self.outputStream.write(e.toString() + '\n'); |
|
|
self.outputStream.write(e + '\n'); |
|
|
} |
|
|
} |
|
|
// On error: Print the error and clear the buffer
|
|
|
|
|
|
self.bufferedCommand = ''; |
|
|
// Clear buffer if no SyntaxErrors
|
|
|
} else { |
|
|
|
|
|
self.bufferedCommand = ''; |
|
|
self.bufferedCommand = ''; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ret !== undefined) { |
|
|
// If we got any output - print it (if no error)
|
|
|
|
|
|
if (!e && ret !== undefined) { |
|
|
self.context._ = ret; |
|
|
self.context._ = ret; |
|
|
self.outputStream.write(exports.writer(ret) + '\n'); |
|
|
self.outputStream.write(exports.writer(ret) + '\n'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Display prompt again
|
|
|
self.displayPrompt(); |
|
|
self.displayPrompt(); |
|
|
}; |
|
|
}; |
|
|
}); |
|
|
}); |
|
@ -319,6 +292,7 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
filter = match[1]; |
|
|
filter = match[1]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
completionGroupsLoaded(); |
|
|
} else if (match = line.match(requireRE)) { |
|
|
} else if (match = line.match(requireRE)) { |
|
|
// require('...<Tab>')
|
|
|
// require('...<Tab>')
|
|
|
//TODO: suggest require.exts be exposed to be introspec registered
|
|
|
//TODO: suggest require.exts be exposed to be introspec registered
|
|
@ -384,6 +358,8 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
completionGroups.push(builtinLibs); |
|
|
completionGroups.push(builtinLibs); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
completionGroupsLoaded(); |
|
|
|
|
|
|
|
|
// Handle variable member lookup.
|
|
|
// Handle variable member lookup.
|
|
|
// We support simple chained expressions like the following (no function
|
|
|
// We support simple chained expressions like the following (no function
|
|
|
// calls, etc.). That is for simplicity and also because we *eval* that
|
|
|
// calls, etc.). That is for simplicity and also because we *eval* that
|
|
@ -417,9 +393,12 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
// Resolve expr and get its completions.
|
|
|
// Resolve expr and get its completions.
|
|
|
var obj, memberGroups = []; |
|
|
var obj, memberGroups = []; |
|
|
if (!expr) { |
|
|
if (!expr) { |
|
|
|
|
|
// If context is instance of vm.ScriptContext
|
|
|
|
|
|
// Get global vars synchronously
|
|
|
if (this.context.constructor.name === 'Context') { |
|
|
if (this.context.constructor.name === 'Context') { |
|
|
completionGroups.push(Object.getOwnPropertyNames(this.context)); |
|
|
completionGroups.push(Object.getOwnPropertyNames(this.context)); |
|
|
next(); |
|
|
addStandardGlobals(); |
|
|
|
|
|
completionGroupsLoaded(); |
|
|
} else { |
|
|
} else { |
|
|
this.eval('.scope', this.context, 'repl', function(err, globals) { |
|
|
this.eval('.scope', this.context, 'repl', function(err, globals) { |
|
|
if (Array.isArray(globals[0])) { |
|
|
if (Array.isArray(globals[0])) { |
|
@ -427,17 +406,15 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
globals.forEach(function(group) { |
|
|
globals.forEach(function(group) { |
|
|
completionGroups.push(group); |
|
|
completionGroups.push(group); |
|
|
}); |
|
|
}); |
|
|
finish(); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
completionGroups.push(globals); |
|
|
completionGroups.push(globals); |
|
|
next(); |
|
|
addStandardGlobals(); |
|
|
} |
|
|
} |
|
|
|
|
|
completionGroupsLoaded(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return; |
|
|
function addStandardGlobals() { |
|
|
|
|
|
|
|
|
function next() { |
|
|
|
|
|
// Global object properties
|
|
|
// Global object properties
|
|
|
// (http://www.ecma-international.org/publications/standards/Ecma-262.htm)
|
|
|
// (http://www.ecma-international.org/publications/standards/Ecma-262.htm)
|
|
|
completionGroups.push(['NaN', 'Infinity', 'undefined', |
|
|
completionGroups.push(['NaN', 'Infinity', 'undefined', |
|
@ -457,9 +434,8 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', |
|
|
'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', |
|
|
'while', 'with', 'yield']); |
|
|
'while', 'with', 'yield']); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
finish(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
this.eval(expr, this.context, 'repl', function(e, obj) { |
|
|
this.eval(expr, this.context, 'repl', function(e, obj) { |
|
|
// if (e) console.log(e);
|
|
|
// if (e) console.log(e);
|
|
@ -497,16 +473,17 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
finish(); |
|
|
completionGroupsLoaded(); |
|
|
}); |
|
|
}); |
|
|
return; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
completionGroupsLoaded(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If reach this point - work like sync
|
|
|
// Will be called when all completionGroups are in place
|
|
|
finish(null); |
|
|
// Useful for async autocompletion
|
|
|
function finish(err, ret) { |
|
|
function completionGroupsLoaded(err) { |
|
|
if (err) throw err; |
|
|
if (err) throw err; |
|
|
|
|
|
|
|
|
// Filter, sort (within each group), uniq and merge the completion groups.
|
|
|
// Filter, sort (within each group), uniq and merge the completion groups.
|
|
|