// repl.start("node via TCP socket> ", socket);
// }).listen(5001);
-// repl.start("node > ").scope.foo = "stdin is fun"; // expose foo to repl scope
+// repl.start("node > ").context.foo = "stdin is fun"; // expose foo to repl context
var sys = require('sys');
-var evalcx = process.binding('evals').Script.runInNewContext;
+var Script = process.binding('evals').Script;
+var evalcx = Script.runInContext;
var path = require("path");
var rl = require('readline');
-var scope;
+var context;
function cwdRequire (id) {
if (id.match(/^\.\.\//) || id.match(/^\.\//)) {
cwdRequire[k] = require[k];
});
-function setScope (self) {
- scope = {};
- for (var i in global) scope[i] = global[i];
- scope.module = module;
- scope.require = cwdRequire;
+function resetContext() {
+ context = Script.createContext();
+ for (var i in global) context[i] = global[i];
+ context.module = module;
+ context.require = cwdRequire;
}
function REPLServer(prompt, stream) {
var self = this;
- if (!scope) setScope();
- self.scope = scope;
+ if (!context) resetContext();
+ self.context = context;
self.buffered_cmd = '';
self.stream = stream || process.openStdin();
// This try is for determining if the command is complete, or should
// continue onto the next line.
try {
- // Use evalcx to supply the global scope
- var ret = evalcx(self.buffered_cmd, scope, "repl");
+ // Use evalcx to supply the global context
+ var ret = evalcx(self.buffered_cmd, context, "repl");
if (ret !== undefined) {
- scope._ = ret;
+ context._ = ret;
flushed = self.stream.write(exports.writer(ret) + "\n");
}
self.displayPrompt();
return true;
case ".clear":
- self.stream.write("Clearing Scope...\n");
+ self.stream.write("Clearing context...\n");
self.buffered_cmd = '';
- setScope();
+ resetContext();
self.displayPrompt();
return true;
case ".exit":
return true;
case ".help":
self.stream.write(".break\tSometimes you get stuck in a place you can't get out... This will get you out.\n");
- self.stream.write(".clear\tBreak, and also clear the local scope.\n");
+ self.stream.write(".clear\tBreak, and also clear the local context.\n");
self.stream.write(".exit\tExit the prompt\n");
self.stream.write(".help\tShow repl options\n");
self.displayPrompt();
/**
* Converts commands that use var and function <name>() to use the
- * local exports.scope when evaled. This provides a local scope
+ * local exports.context when evaled. This provides a local context
* on the REPL.
*
* @param {String} cmd The cmd to convert
* @returns {String} The converted command
*/
-REPLServer.prototype.convertToScope = function (cmd) {
+REPLServer.prototype.convertToContext = function (cmd) {
var self = this, matches,
scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m,
scopeFunc = /^\s*function\s*([_\w\$]+)/;
- // Replaces: var foo = "bar"; with: self.scope.foo = bar;
+ // Replaces: var foo = "bar"; with: self.context.foo = bar;
matches = scopeVar.exec(cmd);
if (matches && matches.length === 3) {
- return "self.scope." + matches[1] + matches[2];
+ return "self.context." + matches[1] + matches[2];
}
// Replaces: function foo() {}; with: foo = function foo() {};
exports = binding_cache->Get(module)->ToObject();
} else {
exports = Object::New();
+ node::Context::Initialize(exports);
node::Script::Initialize(exports);
binding_cache->Set(module, exports);
}
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
// Add a reference to the global object
- Local<Object> global = Context::GetCurrent()->Global();
+ Local<Object> global = v8::Context::GetCurrent()->Global();
process->Set(String::NewSymbol("global"), global);
// process.version
}
// Create the one and only Context.
- Persistent<Context> context = Context::New();
- Context::Scope context_scope(context);
+ Persistent<v8::Context> context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
atexit(node::AtExit);
TryCatch try_catch;
- cb->Call(Context::GetCurrent()->Global(), 1, &e);
+ cb->Call(v8::Context::GetCurrent()->Global(), 1, &e);
if (try_catch.HasCaught()) {
FatalException(try_catch);
Local<Value> argv[2] = { Local<Value>::New(Null()), addresses};
- (*cb)->Call(Context::GetCurrent()->Global(), 2, argv);
+ (*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
Local<Value> argv[2] = { Local<Value>::New(Null()), names };
- (*cb)->Call(Context::GetCurrent()->Global(), 2, argv);
+ (*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
static void cb_call(Persistent<Function> &cb, int argc, Local<Value> *argv) {
TryCatch try_catch;
- cb->Call(Context::GetCurrent()->Global(), argc, argv);
+ cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
sig = args[0]->Int32Value();
} else if (args[0]->IsString()) {
Local<String> signame = args[0]->ToString();
- Local<Object> process = Context::GetCurrent()->Global();
+ Local<Object> process = v8::Context::GetCurrent()->Global();
Local<Object> node_obj = process->Get(String::NewSymbol("process"))->ToObject();
Local<Value> sig_v = node_obj->Get(signame);
TryCatch try_catch;
- (*callback)->Call(Context::GetCurrent()->Global(), argc, argv);
+ (*callback)->Call(v8::Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
using namespace v8;
using namespace node;
+Persistent<FunctionTemplate> node::Context::constructor_template;
+
+void
+node::Context::Initialize (Handle<Object> target)
+{
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(node::Context::New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("Context"));
+
+ target->Set(String::NewSymbol("Context"), constructor_template->GetFunction());
+}
+
+Handle<Value>
+node::Context::New (const Arguments& args)
+{
+ HandleScope scope;
+
+ node::Context *t = new node::Context();
+ t->Wrap(args.This());
+
+ return args.This();
+}
+
+node::Context::~Context() {
+ _context.Dispose();
+}
+
+Local<Object>
+node::Context::NewInstance()
+{
+ Local<Object> context = constructor_template->GetFunction()->NewInstance();
+ node::Context *nContext = ObjectWrap::Unwrap<node::Context>(context);
+ nContext->_context = v8::Context::New();
+ return context;
+}
+
+v8::Persistent<v8::Context>
+node::Context::GetV8Context()
+{
+ return _context;
+}
+
+
Persistent<FunctionTemplate> node::Script::constructor_template;
void
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Script"));
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "createContext", node::Script::CreateContext);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInContext", node::Script::RunInContext);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInThisContext", node::Script::RunInThisContext);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInNewContext", node::Script::RunInNewContext);
+ NODE_SET_METHOD(constructor_template, "createContext", node::Script::CreateContext);
+ NODE_SET_METHOD(constructor_template, "runInContext", node::Script::CompileRunInContext);
NODE_SET_METHOD(constructor_template, "runInThisContext", node::Script::CompileRunInThisContext);
NODE_SET_METHOD(constructor_template, "runInNewContext", node::Script::CompileRunInNewContext);
Handle<Value>
+node::Script::CreateContext (const Arguments& args)
+{
+ HandleScope scope;
+
+ Local<v8::Object> context = node::Context::NewInstance();
+
+ if (args.Length() > 0) {
+
+ Local<Object> sandbox = args[0]->ToObject();
+ Local<Array> keys = sandbox->GetPropertyNames();
+
+ for (int i = 0; i < keys->Length(); i++) {
+ Handle<String> key = keys->Get(Integer::New(i))->ToString();
+ Handle<Value> value = sandbox->Get(key);
+ context->Set(key, value);
+ }
+ }
+
+
+ return scope.Close(context);
+}
+
+Handle<Value>
+node::Script::RunInContext (const Arguments& args)
+{
+ return
+ node::Script::EvalMachine<unwrapExternal, userContext, returnResult>(args);
+}
+
+
+Handle<Value>
node::Script::RunInThisContext (const Arguments& args)
{
return
Handle<Value>
+node::Script::CompileRunInContext (const Arguments& args)
+{
+ return
+ node::Script::EvalMachine<compileCode, userContext, returnResult>(args);
+}
+
+
+Handle<Value>
node::Script::CompileRunInThisContext (const Arguments& args)
{
return
));
}
+ const int sbIndex = iFlag == compileCode ? 1 : 0;
+ if (cFlag == userContext && args.Length() < (sbIndex + 1)) {
+ return ThrowException(Exception::TypeError(
+ String::New("needs a 'context' argument.")
+ ));
+ }
+
+
Local<String> code;
if (iFlag == compileCode) { code = args[0]->ToString(); }
Local<Object> sandbox;
- const int sbIndex = iFlag == compileCode ? 1 : 0;
if (cFlag == newContext) {
sandbox = args.Length() > sbIndex ? args[sbIndex]->ToObject() : Object::New();
}
+ else if (cFlag == userContext) {
+ sandbox = args[sbIndex]->ToObject();
+ }
const int fnIndex = sbIndex + (cFlag == newContext ? 1 : 0);
Local<String> filename = args.Length() > fnIndex ? args[fnIndex]->ToString()
: String::New("evalmachine.<anonymous>");
- Persistent<Context> context;
+ Persistent<v8::Context> context;
Local<Array> keys;
unsigned int i;
if (cFlag == newContext) {
// Create the new context
- context = Context::New();
+ context = v8::Context::New();
- // Enter and compile script
+ } else if (cFlag == userContext) {
+ // Use the passed in context
+ Local<Object> contextArg = args[sbIndex]->ToObject();
+ node::Context *nContext = ObjectWrap::Unwrap<node::Context>(sandbox);
+ context = nContext->GetV8Context();
+ }
+
+ // New and user context share code. DRY it up.
+ if (cFlag == userContext || cFlag == newContext) {
+
+ // Enter the context
context->Enter();
- // Copy objects from global context, to our brand new context
+ // Copy everything from the passed in sandbox (either the persistent
+ // context for runInContext(), or the sandbox arg to runInNewContext()).
keys = sandbox->GetPropertyNames();
for (i = 0; i < keys->Length(); i++) {
}
if (result.IsEmpty()) {
return try_catch.ReThrow();
- } else if (cFlag == newContext) {
+ } else if (cFlag == userContext || cFlag == newContext) {
// success! copy changes back onto the sandbox object.
keys = context->Global()->GetPropertyNames();
for (i = 0; i < keys->Length(); i++) {
context->DetachGlobal();
context->Exit();
context.Dispose();
+ } else if (cFlag == userContext) {
+ // Exit the passed in context.
+ context->Exit();
}
return result == args.This() ? result : scope.Close(result);
namespace node {
+class Context : ObjectWrap {
+ public:
+ static void Initialize (v8::Handle<v8::Object> target);
+ static v8::Handle<v8::Value> New (const v8::Arguments& args);
+
+ v8::Persistent<v8::Context> GetV8Context();
+ static v8::Local<v8::Object> NewInstance();
+
+ protected:
+
+ static v8::Persistent<v8::FunctionTemplate> constructor_template;
+
+ Context () : ObjectWrap () {}
+ ~Context();
+
+ v8::Persistent<v8::Context> _context;
+};
+
class Script : ObjectWrap {
public:
static void Initialize (v8::Handle<v8::Object> target);
enum EvalInputFlags { compileCode, unwrapExternal };
- enum EvalContextFlags { thisContext, newContext };
+ enum EvalContextFlags { thisContext, newContext, userContext };
enum EvalOutputFlags { returnResult, wrapExternal };
template <EvalInputFlags iFlag, EvalContextFlags cFlag, EvalOutputFlags oFlag>
~Script();
static v8::Handle<v8::Value> New (const v8::Arguments& args);
+ static v8::Handle<v8::Value> CreateContext (const v8::Arguments& arg);
+ static v8::Handle<v8::Value> RunInContext (const v8::Arguments& args);
static v8::Handle<v8::Value> RunInThisContext (const v8::Arguments& args);
static v8::Handle<v8::Value> RunInNewContext (const v8::Arguments& args);
+ static v8::Handle<v8::Value> CompileRunInContext (const v8::Arguments& args);
static v8::Handle<v8::Value> CompileRunInThisContext (const v8::Arguments& args);
static v8::Handle<v8::Value> CompileRunInNewContext (const v8::Arguments& args);
socket.end();
});
- repl.start(prompt_unix, socket).scope.message = message;
+ repl.start(prompt_unix, socket).context.message = message;
});
server_unix.addListener('listening', function () {
--- /dev/null
+require("../common");
+
+var Script = process.binding('evals').Script;
+var script = new Script('"passed";');
+
+debug('run in a new empty context');
+var context = script.createContext();
+var result = script.runInContext(context);
+assert.equal('passed', result);
+
+debug('create a new pre-populated context');
+context = script.createContext({'foo': 'bar', 'thing': 'lala'});
+assert.equal('bar', context.foo);
+assert.equal('lala', context.thing);
+
+debug('test updating context');
+script = new Script('foo = 3;');
+result = script.runInContext(context);
+assert.equal(3, context.foo);
+assert.equal('lala', context.thing);
--- /dev/null
+require("../common");
+
+var Script = process.binding('evals').Script;
+
+debug('run in a new empty context');
+var context = Script.createContext();
+var result = Script.runInContext('"passed";', context);
+assert.equal('passed', result);
+
+debug('create a new pre-populated context');
+context = Script.createContext({'foo': 'bar', 'thing': 'lala'});
+assert.equal('bar', context.foo);
+assert.equal('lala', context.thing);
+
+debug('test updating context');
+result = Script.runInContext('var foo = 3;', context);
+assert.equal(3, context.foo);
+assert.equal('lala', context.thing);