Add REPL support.

Reviewed-by: asquare
This commit is contained in:
Kinsley Wong 2013-12-06 11:01:09 -08:00
parent b0f3c1ca3f
commit 7241ec81bf
8 changed files with 169 additions and 28 deletions

View File

@ -274,6 +274,7 @@
<apply-diff src="lib" mod="src/main/js/lib" name="querystring.js"/>
<apply-diff src="lib" mod="src/main/js/lib" name="module.js"/>
<apply-diff src="lib" mod="src/main/js/lib" name="net.js"/>
<apply-diff src="lib" mod="src/main/js/lib" name="repl.js"/>
<apply-diff src="lib" mod="src/main/js/lib" name="string_decoder.js"/>
<apply-diff src="lib" mod="src/main/js/lib" name="tls.js"/>
<!-- tests -->
@ -350,6 +351,7 @@
<apply-patch-file target="src/main/js/lib" dir="lib" name="querystring.js"/>
<apply-patch-file target="src/main/js/lib" dir="lib" name="module.js"/>
<apply-patch-file target="src/main/js/lib" dir="lib" name="net.js"/>
<apply-patch-file target="src/main/js/lib" dir="lib" name="repl.js"/>
<apply-patch-file target="src/main/js/lib" dir="lib" name="string_decoder.js"/>
<apply-patch-file target="src/main/js/lib" dir="lib" name="tls.js"/>
<!-- tests -->

View File

@ -1,5 +1,5 @@
--- ../node/lib/module.js 2013-08-22 13:55:28.000000000 +0200
+++ src/main/js/lib/module.js 2013-10-07 14:01:12.000000000 +0200
--- ../nodejs/lib/module.js 2013-12-02 16:45:51.723090200 -0800
+++ src/main/js/lib/module.js 2013-12-05 16:49:59.264917800 -0800
@@ -271,13 +271,19 @@
return [id, [path.dirname(parent.filename)]];
};
@ -21,6 +21,15 @@
var cachedModule = Module._cache[filename];
if (cachedModule) {
@@ -288,7 +294,7 @@
// REPL is a special case, because it needs the real require.
if (filename == 'repl') {
var replModule = new Module('repl');
- replModule._compile(NativeModule.getSource('repl'), 'repl.js');
+ replModule._compile(NativeModule.getSource('/lib/repl.js'), 'repl.js');
NativeModule._cache.repl = replModule;
return replModule.exports;
}
@@ -309,7 +315,11 @@
var hadException = true;
@ -49,7 +58,7 @@
// Returns exception if any
Module.prototype._compile = function(content, filename) {
var self = this;
+
+
// remove shebang
+ if(content != null) {
content = content.replace(/^\#\!.*/, '');

24
patches/lib/repl.js.patch Normal file
View File

@ -0,0 +1,24 @@
--- ../nodejs/lib/repl.js 2013-12-05 16:43:37.738090700 -0800
+++ src/main/js/lib/repl.js 2013-12-05 16:44:53.691533100 -0800
@@ -535,7 +535,7 @@
// Get global vars synchronously
if (this.useGlobal ||
this.context.constructor &&
- this.context.constructor.name === 'Context') {
+ this.context.constructor.name === 'Object') {
var contextProto = this.context;
while (contextProto = Object.getPrototypeOf(contextProto)) {
completionGroups.push(Object.getOwnPropertyNames(contextProto));
@@ -918,10 +918,10 @@
e = e && (e.stack || e.toString());
return e && e.match(/^SyntaxError/) &&
// RegExp syntax error
- !e.match(/^SyntaxError: Invalid regular expression/) &&
+ !e.match(/^SyntaxError: repl/) &&
!e.match(/^SyntaxError: Invalid flags supplied to RegExp constructor/) &&
// "strict mode" syntax errors
!e.match(/^SyntaxError: .*strict mode.*/i) &&
// JSON.parse() error
- !e.match(/\n {4}at Object.parse \(native\)\n/);
+ !e.match(/^SyntaxError: Invalid /);
}

View File

@ -28,6 +28,7 @@ source.lib.modules = \
path.js \
querystring.js \
readline.js \
repl.js \
stream.js \
string_decoder.js \
timers.js \
@ -436,6 +437,12 @@ source.test.simple.list = \
test-regress-GH-877.js \
test-regress-GH-897.js \
test-regression-object-prototype.js \
test-repl-autolibs.js \
test-repl-console.js \
test-repl-end-emits-exit.js \
test-repl-options.js \
test-repl-require-cache.js \
test-repl-tab-complete.js \
test-require-cache.js \
test-require-cache-without-stat.js \
test-require-exceptions.js \

View File

@ -25,6 +25,7 @@
package net.java.avatar.js;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -125,6 +126,8 @@ public abstract class Loader {
*/
public abstract boolean exists(final String id);
public abstract String load(final String id);
/**
* Returns the value of a compiled-in property.
* @param key the key whose value is desired
@ -192,6 +195,27 @@ public abstract class Loader {
return BUILD_PROPERTIES.getProperty(key);
}
@Override
public String load(final String id) {
final int BUFFERSIZE = 64 * 1024;
final byte[] data = new byte[BUFFERSIZE];
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(BUFFERSIZE);
final InputStream is = this.getClass().getResourceAsStream(id);
assert is != null;
try {
int bytesRead = is.read(data, 0, data.length);
while (bytesRead != -1) {
buffer.write(data, 0, bytesRead);
bytesRead = is.read(data, 0, data.length);
}
buffer.flush();
} catch (final IOException ex) {
ex.printStackTrace();
}
return new String(buffer.toByteArray());
}
protected String pathFor(final String id) {
return MODULES_DIR + id + SCRIPT_EXTENSION;
}

View File

@ -100,9 +100,7 @@ public final class Server {
}
public static void main(final String... args) throws Exception {
if (args != null && args.length > 0) {
new Server().run(args);
}
new Server().run(args);
}
public Server() throws Exception {
@ -147,7 +145,11 @@ public final class Server {
checkPermission();
bindings.put(SECURE_HOLDER, holder);
try {
runUserScripts(args);
if (args.length == 0) {
runREPL();
} else {
runUserScripts(args);
}
} catch (final ScriptException ex) {
if (!eventLoop.handleCallbackException(ex)) {
throw ex;
@ -206,11 +208,21 @@ public final class Server {
}
final String[] userFiles = {userFile};
holder.setArgs(avatarArgs.toArray(new String[avatarArgs.size()]),
userArgs.toArray(new String[userArgs.size()]),
userFiles);
runEventLoop(avatarArgs.toArray(new String[avatarArgs.size()]),
userArgs.toArray(new String[userArgs.size()]),
userFiles);
}
private void runREPL() throws Exception {
holder.setForceRepl(true);
runEventLoop(null, null, null);
}
private void runEventLoop(final String[] avatarArgs, final String[] userArgs, final String[] userFiles) throws Exception {
Exception rootCause = null;
// First run the main script...
holder.setArgs(avatarArgs, userArgs, userFiles);
try {
runSystemScript(SYSTEM_INIT_SCRIPTS);
} catch(Exception ex) {
@ -234,17 +246,15 @@ public final class Server {
throw ex;
}
} finally {
if (args != null && args.length > 0) {
try {
// emit the process.exit event
runSystemScript(SYSTEM_FINALIZATION_SCRIPTS);
} catch (Exception ex) {
if (rootCause != null) {
rootCause.addSuppressed(ex);
throw rootCause;
}
throw ex;
try {
// emit the process.exit event
runSystemScript(SYSTEM_FINALIZATION_SCRIPTS);
} catch (Exception ex) {
if (rootCause != null) {
rootCause.addSuppressed(ex);
throw rootCause;
}
throw ex;
}
}
}
@ -266,6 +276,8 @@ public final class Server {
} else if ("--trace-deprecation".equals(arg)) {
holder.setTraceDeprecation(true);
holder.setThrowDeprecation(false);
} else if ("-i".equals(arg) || "--interactive".equals(arg)) {
holder.setForceRepl(true);
} else {
System.out.println(HELP);
throw new IllegalArgumentException(arg);
@ -339,6 +351,7 @@ public final class Server {
private String[] userFiles;
private boolean throwDeprecation = true;
private boolean traceDeprecation;
private boolean forceRepl = false;
private int exitCode = 0;
private final Invocable invocable;
private Object nativeModule;
@ -368,9 +381,9 @@ public final class Server {
}
private void setArgs(final String[] avatarArgs, final String[] userArgs, final String[] userFiles) {
this.avatarArgs = avatarArgs.clone();
this.userArgs = userArgs.clone();
this.userFiles = userFiles.clone();
this.avatarArgs = avatarArgs != null ? avatarArgs.clone() : null;
this.userArgs = userArgs != null ? userArgs.clone() : null;
this.userFiles = userFiles != null ? userFiles.clone() : null;
}
public String[] getAvatarArgs() {
@ -393,6 +406,10 @@ public final class Server {
this.traceDeprecation = traceDeprecation;
}
private void setForceRepl(boolean forceRepl) {
this.forceRepl = forceRepl;
}
public boolean getThrowDeprecation() {
return throwDeprecation;
}
@ -401,6 +418,10 @@ public final class Server {
return traceDeprecation;
}
public boolean getForceRepl() {
return forceRepl;
}
private void setExitCode(int exitCode) {
this.exitCode = exitCode;
}

View File

@ -77,6 +77,11 @@ Object.defineProperty(exports, 'traceDeprecation', {
value: __avatar.traceDeprecation
});
Object.defineProperty(exports, '_forceRepl', {
enumerable: true,
value: __avatar.forceRepl
});
var stdin;
Object.defineProperty(exports, 'stdin', {
enumerable: true,
@ -278,12 +283,12 @@ Object.defineProperty(exports, 'argv', {
_argv = [];
_argv.push(exports.execPath);
var uf = __avatar.userFiles;
var flen = uf.length;
var flen = uf ? uf.length : 0;
for (var i=0; i < flen; i++) {
_argv.push(uf[i]);
}
var ua = __avatar.userArgs;
var alen = ua.length;
var alen = ua ? ua.length : 0;
for (var j=0; j < alen; j++) {
_argv.push(ua[j]);
}
@ -302,7 +307,7 @@ Object.defineProperty(exports, 'execArgv', {
if (!_execArgv) {
_execArgv = [];
var aa = __avatar.avatarArgs;
var alen = aa.length;
var alen = aa ? aa.length : 0;
for (var j=0; j < alen; j++) {
_execArgv.push(aa[j]);
}

View File

@ -300,6 +300,55 @@ var gc = global.gc;
return current.apply(this, args);
}
NativeModule.require('module').runMain();
if (process.argv[1]) {
// make process.argv[1] into a full path
var path = NativeModule.require('path');
process.argv[1] = path.resolve(process.argv[1]);
// If this is a worker in cluster mode, start up the communiction
// channel.
if (process.env.NODE_UNIQUE_ID) {
var cluster = NativeModule.require('cluster');
cluster._setupWorker();
// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_UNIQUE_ID;
}
NativeModule.require('module').runMain();
} else {
var Module = NativeModule.require('module');
// If -i or --interactive were passed, or stdin is a TTY.
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
// REPL
var opts = {
useGlobal: true,
ignoreUndefined: false
};
if (parseInt(process.env['NODE_NO_READLINE'], 10)) {
opts.terminal = false;
}
if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) {
opts.useColors = false;
}
var repl = Module.requireRepl().start(opts);
repl.on('exit', function() {
process.exit();
});
} else {
// Read all of stdin - execute it.
process.stdin.setEncoding('utf8');
var code = '';
process.stdin.on('data', function(d) {
code += d;
});
process.stdin.on('end', function() {
process._eval = code;
evalScript('[stdin]');
});
}
}
} )();