Created
June 23, 2010 12:04
-
-
Save cha0s/449842 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 7e9c16806638ca413025defc91185c8f2ea471a6 Mon Sep 17 00:00:00 2001 | |
From: Ruben Rodriguez <cha0s@therealcha0s.net> | |
Date: Wed, 23 Jun 2010 07:00:06 -0500 | |
Subject: [PATCH] Added Script.createContext() and Script.runInContext() and implemented it in the REPL. | |
--- | |
lib/repl.js | 40 ++++++++-------- | |
src/node.cc | 7 ++- | |
src/node_cares.cc | 8 ++-- | |
src/node_child_process.cc | 2 +- | |
src/node_file.cc | 2 +- | |
src/node_script.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++- | |
src/node_script.h | 23 +++++++++- | |
7 files changed, 159 insertions(+), 32 deletions(-) | |
diff --git a/lib/repl.js b/lib/repl.js | |
index d0fefde..dec6684 100644 | |
--- a/lib/repl.js | |
+++ b/lib/repl.js | |
@@ -10,13 +10,14 @@ | |
// 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(/^\.\//)) { | |
@@ -28,11 +29,11 @@ Object.keys(require).forEach(function (k) { | |
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; | |
} | |
@@ -41,8 +42,7 @@ exports.writer = sys.inspect; | |
function REPLServer(prompt, stream) { | |
var self = this; | |
- if (!scope) setScope(); | |
- self.scope = scope; | |
+ if (!context) resetContext(); | |
self.buffered_cmd = ''; | |
self.stream = stream || process.openStdin(); | |
@@ -70,10 +70,10 @@ function REPLServer(prompt, stream) { | |
// 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"); | |
} | |
@@ -150,9 +150,9 @@ REPLServer.prototype.parseREPLKeyword = function (cmd) { | |
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": | |
@@ -160,7 +160,7 @@ REPLServer.prototype.parseREPLKeyword = function (cmd) { | |
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(); | |
@@ -180,21 +180,21 @@ function trimWhitespace (cmd) { | |
/** | |
* 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() {}; | |
diff --git a/src/node.cc b/src/node.cc | |
index 3fc90cf..ea7de5f 100644 | |
--- a/src/node.cc | |
+++ b/src/node.cc | |
@@ -1631,6 +1631,7 @@ static Handle<Value> Binding(const Arguments& args) { | |
exports = binding_cache->Get(module)->ToObject(); | |
} else { | |
exports = Object::New(); | |
+ node::Context::Initialize(exports); | |
node::Script::Initialize(exports); | |
binding_cache->Set(module, exports); | |
} | |
@@ -1685,7 +1686,7 @@ static void Load(int argc, char *argv[]) { | |
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 | |
@@ -1987,8 +1988,8 @@ int main(int argc, char *argv[]) { | |
} | |
// 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); | |
diff --git a/src/node_cares.cc b/src/node_cares.cc | |
index 892f648..4b50776 100644 | |
--- a/src/node_cares.cc | |
+++ b/src/node_cares.cc | |
@@ -223,7 +223,7 @@ static void ResolveError(Persistent<Function> &cb, int status) { | |
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); | |
@@ -251,7 +251,7 @@ static void HostByNameCb(void *data, | |
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); | |
@@ -281,7 +281,7 @@ static void HostByAddrCb(void *data, | |
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); | |
@@ -294,7 +294,7 @@ static void HostByAddrCb(void *data, | |
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); | |
diff --git a/src/node_child_process.cc b/src/node_child_process.cc | |
index 72787f0..8a0c32c 100644 | |
--- a/src/node_child_process.cc | |
+++ b/src/node_child_process.cc | |
@@ -156,7 +156,7 @@ Handle<Value> ChildProcess::Kill(const Arguments& args) { | |
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); | |
diff --git a/src/node_file.cc b/src/node_file.cc | |
index dde2740..a2ec398 100644 | |
--- a/src/node_file.cc | |
+++ b/src/node_file.cc | |
@@ -145,7 +145,7 @@ static int After(eio_req *req) { | |
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); | |
diff --git a/src/node_script.cc b/src/node_script.cc | |
index 78136dd..bf42502 100644 | |
--- a/src/node_script.cc | |
+++ b/src/node_script.cc | |
@@ -7,6 +7,52 @@ | |
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 | |
@@ -19,8 +65,12 @@ node::Script::Initialize (Handle<Object> target) | |
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); | |
@@ -45,6 +95,37 @@ node::Script::~Script() { | |
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 | |
@@ -60,6 +141,14 @@ node::Script::RunInNewContext(const Arguments& args) { | |
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 | |
@@ -90,6 +179,12 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) { | |
String::New("needs at least 'code' argument.") | |
)); | |
} | |
+ if (cFlag == userContext && args.Length() < 2) { | |
+ return ThrowException(Exception::TypeError( | |
+ String::New("needs a 'context' argument.") | |
+ )); | |
+ } | |
+ | |
Local<String> code; | |
if (iFlag == compileCode) { code = args[0]->ToString(); } | |
@@ -103,12 +198,12 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) { | |
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 | |
context->Enter(); | |
@@ -121,6 +216,13 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) { | |
Handle<Value> value = sandbox->Get(key); | |
context->Global()->Set(key, value); | |
} | |
+ } else if (cFlag == userContext) { | |
+ // Use the passed in context | |
+ node::Context *nContext = ObjectWrap::Unwrap<node::Context>(args[1]->ToObject()); | |
+ context = nContext->GetV8Context(); | |
+ | |
+ // Enter the context | |
+ context->Enter(); | |
} | |
// Catch errors | |
@@ -183,6 +285,9 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) { | |
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); | |
diff --git a/src/node_script.h b/src/node_script.h | |
index edf51c3..8cac141 100644 | |
--- a/src/node_script.h | |
+++ b/src/node_script.h | |
@@ -8,12 +8,30 @@ | |
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> | |
@@ -26,8 +44,11 @@ class Script : ObjectWrap { | |
~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); | |
-- | |
1.7.0.4 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment