var Console = require('console').Console;
var EventEmitter = require('events').EventEmitter;
var domain = require('domain');
+var debug = util.debuglog('repl');
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
});
} catch (e) {
err = e;
- err._isSyntaxError = isSyntaxError(err);
+ debug('parse error %j', code, e);
}
+
if (!err) {
try {
if (self.useGlobal) {
}
} catch (e) {
err = e;
- err._isSyntaxError = false;
+ if (err && process.domain) {
+ debug('not recoverable, send to domain');
+ process.domain.emit('error', err);
+ process.domain.exit();
+ return;
+ }
}
}
- if (err && process.domain && !err._isSyntaxError) {
- process.domain.emit('error', err);
- process.domain.exit();
- }
- else {
- cb(err, result);
- }
+
+ cb(err, result);
}
self.eval = self._domain.bind(eval_);
self._domain.on('error', function(e) {
+ debug('domain error');
self.outputStream.write((e.stack || e) + '\n');
self.bufferedCommand = '';
self.lines.level = [];
});
rli.on('line', function(cmd) {
+ debug('line %j', cmd);
sawSIGINT = false;
var skipCatchall = false;
cmd = trimWhitespace(cmd);
}
if (!skipCatchall) {
- var evalCmd = self.bufferedCommand + cmd + '\n';
-
- // This try is for determining if the command is complete, or should
- // continue onto the next line.
- // We try to evaluate both expressions e.g.
- // '{ a : 1 }'
- // and statements e.g.
- // 'for (var i = 0; i < 10; i++) console.log(i);'
-
- // First we attempt to eval as expression with parens.
- // This catches '{a : 1}' properly.
- self.eval('(' + evalCmd + ')',
- self.context,
- 'repl',
- function(e, ret) {
- if (e && !e._isSyntaxError) return finish(e);
-
- if (util.isFunction(ret) &&
- /^[\r\n\s]*function/.test(evalCmd) || e) {
- // Now as statement without parens.
- self.eval(evalCmd, self.context, 'repl', finish);
- } else {
- finish(null, ret);
- }
- });
+ var evalCmd = self.bufferedCommand + cmd;
+ if (/^\s*\{/.test(evalCmd) && /\}\s*$/.test(evalCmd)) {
+ // It's confusing for `{ a : 1 }` to be interpreted as a block
+ // statement rather than an object literal. So, we first try
+ // to wrap it in parentheses, so that it will be interpreted as
+ // an expression.
+ evalCmd = '(' + evalCmd + ')\n';
+ } else {
+ // otherwise we just append a \n so that it will be either
+ // terminated, or continued onto the next expression if it's an
+ // unexpected end of input.
+ evalCmd = evalCmd + '\n';
+ }
+ debug('eval %j', evalCmd);
+ self.eval(evalCmd, self.context, 'repl', finish);
} else {
finish(null);
}
function finish(e, ret) {
-
+ debug('finish', e, ret);
self.memory(cmd);
+ if (e && !self.bufferedCommand && cmd.trim().match(/^npm /)) {
+ self.outputStream.write('npm should be run outside of the ' +
+ 'node repl, in your normal shell.\n' +
+ '(Press Control-D to exit.)\n');
+ self.bufferedCommand = '';
+ self.displayPrompt();
+ return;
+ }
+
// If error was SyntaxError and not JSON.parse error
- if (e && e._isSyntaxError) {
- if (!self.bufferedCommand && cmd.trim().match(/^npm /)) {
- self.outputStream.write('npm should be run outside of the ' +
- 'node repl, in your normal shell.\n' +
- '(Press Control-D to exit.)\n');
- self.bufferedCommand = '';
+ if (e) {
+ if (isRecoverableError(e)) {
+ // Start buffering data like that:
+ // {
+ // ... x: 1
+ // ... }
+ self.bufferedCommand += cmd + '\n';
self.displayPrompt();
return;
+ } else {
+ self._domain.emit('error', e);
}
-
- // Start buffering data like that:
- // {
- // ... x: 1
- // ... }
- self.bufferedCommand += cmd + '\n';
- self.displayPrompt();
- return;
- } else if (e) {
- self._domain.emit('error', e);
}
// Clear buffer if no SyntaxErrors
};
-/**
- * Returns `true` if "e" is a SyntaxError, `false` otherwise.
- * filters out strict-mode errors, which are not recoverable
- */
-function isSyntaxError(e) {
- // Convert error to string
- e = e && (e.stack || e.toString());
- return e && e.match(/^SyntaxError/) &&
- // "strict mode" syntax errors
- !e.match(/^SyntaxError: .*strict mode.*/i) &&
- !e.match(/^SyntaxError: Assignment to constant variable/i);
+// If the error is that we've unexpectedly ended the input,
+// then let the user try to recover by adding more input.
+function isRecoverableError(e) {
+ return e &&
+ e.name === 'SyntaxError' &&
+ /^Unexpected end of input/.test(e.message);
}