|
|
@ -2,109 +2,198 @@ |
|
|
|
#include <node_script.h> |
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
namespace node { |
|
|
|
|
|
|
|
using v8::Context; |
|
|
|
using v8::Script; |
|
|
|
using v8::Value; |
|
|
|
using v8::Handle; |
|
|
|
using v8::HandleScope; |
|
|
|
using v8::Object; |
|
|
|
using v8::Arguments; |
|
|
|
using v8::ThrowException; |
|
|
|
using v8::TryCatch; |
|
|
|
using v8::String; |
|
|
|
using v8::Exception; |
|
|
|
using v8::Local; |
|
|
|
using v8::Array; |
|
|
|
using v8::Persistent; |
|
|
|
using v8::Integer; |
|
|
|
using v8::FunctionTemplate; |
|
|
|
|
|
|
|
using namespace v8; |
|
|
|
using namespace node; |
|
|
|
|
|
|
|
class WrappedContext : ObjectWrap { |
|
|
|
public: |
|
|
|
static void Initialize(Handle<Object> target); |
|
|
|
static Handle<Value> New(const Arguments& args); |
|
|
|
|
|
|
|
Persistent<FunctionTemplate> node::Context::constructor_template; |
|
|
|
Persistent<Context> GetV8Context(); |
|
|
|
static Local<Object> NewInstance(); |
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
|
|
void node::Context::Initialize (Handle<Object> target) { |
|
|
|
static Persistent<FunctionTemplate> constructor_template; |
|
|
|
|
|
|
|
WrappedContext(); |
|
|
|
~WrappedContext(); |
|
|
|
|
|
|
|
Persistent<Context> context_; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Persistent<FunctionTemplate> WrappedContext::constructor_template; |
|
|
|
|
|
|
|
|
|
|
|
class WrappedScript : ObjectWrap { |
|
|
|
public: |
|
|
|
static void Initialize(Handle<Object> target); |
|
|
|
|
|
|
|
enum EvalInputFlags { compileCode, unwrapExternal }; |
|
|
|
enum EvalContextFlags { thisContext, newContext, userContext }; |
|
|
|
enum EvalOutputFlags { returnResult, wrapExternal }; |
|
|
|
|
|
|
|
template <EvalInputFlags input_flag, |
|
|
|
EvalContextFlags context_flag, |
|
|
|
EvalOutputFlags output_flag> |
|
|
|
static Handle<Value> EvalMachine(const Arguments& args); |
|
|
|
|
|
|
|
protected: |
|
|
|
static Persistent<FunctionTemplate> constructor_template; |
|
|
|
|
|
|
|
WrappedScript() : ObjectWrap() {} |
|
|
|
~WrappedScript(); |
|
|
|
|
|
|
|
static Handle<Value> New(const Arguments& args); |
|
|
|
static Handle<Value> CreateContext(const Arguments& arg); |
|
|
|
static Handle<Value> RunInContext(const Arguments& args); |
|
|
|
static Handle<Value> RunInThisContext(const Arguments& args); |
|
|
|
static Handle<Value> RunInNewContext(const Arguments& args); |
|
|
|
static Handle<Value> CompileRunInContext(const Arguments& args); |
|
|
|
static Handle<Value> CompileRunInThisContext(const Arguments& args); |
|
|
|
static Handle<Value> CompileRunInNewContext(const Arguments& args); |
|
|
|
|
|
|
|
Persistent<Script> script_; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void WrappedContext::Initialize(Handle<Object> target) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(node::Context::New); |
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::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()); |
|
|
|
target->Set(String::NewSymbol("Context"), |
|
|
|
constructor_template->GetFunction()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Context::New (const Arguments& args) { |
|
|
|
Handle<Value> WrappedContext::New(const Arguments& args) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
node::Context *t = new node::Context(); |
|
|
|
WrappedContext *t = new WrappedContext(); |
|
|
|
t->Wrap(args.This()); |
|
|
|
|
|
|
|
return args.This(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
node::Context::Context() : ObjectWrap() { |
|
|
|
context_ = v8::Context::New(); |
|
|
|
WrappedContext::WrappedContext() : ObjectWrap() { |
|
|
|
context_ = Context::New(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
node::Context::~Context() { |
|
|
|
WrappedContext::~WrappedContext() { |
|
|
|
context_.Dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Local<Object> node::Context::NewInstance() { |
|
|
|
Local<Object> WrappedContext::NewInstance() { |
|
|
|
Local<Object> context = constructor_template->GetFunction()->NewInstance(); |
|
|
|
return context; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
v8::Persistent<v8::Context> node::Context::GetV8Context() { |
|
|
|
Persistent<Context> WrappedContext::GetV8Context() { |
|
|
|
return context_; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Persistent<FunctionTemplate> node::Script::constructor_template; |
|
|
|
Persistent<FunctionTemplate> WrappedScript::constructor_template; |
|
|
|
|
|
|
|
|
|
|
|
void node::Script::Initialize (Handle<Object> target) { |
|
|
|
void WrappedScript::Initialize(Handle<Object> target) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(node::Script::New); |
|
|
|
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New); |
|
|
|
constructor_template = Persistent<FunctionTemplate>::New(t); |
|
|
|
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); |
|
|
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, |
|
|
|
"createContext", |
|
|
|
WrappedScript::CreateContext); |
|
|
|
|
|
|
|
target->Set(String::NewSymbol("Script"), constructor_template->GetFunction()); |
|
|
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, |
|
|
|
"runInContext", |
|
|
|
WrappedScript::RunInContext); |
|
|
|
|
|
|
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, |
|
|
|
"runInThisContext", |
|
|
|
WrappedScript::RunInThisContext); |
|
|
|
|
|
|
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, |
|
|
|
"runInNewContext", |
|
|
|
WrappedScript::RunInNewContext); |
|
|
|
|
|
|
|
NODE_SET_METHOD(constructor_template, |
|
|
|
"createContext", |
|
|
|
WrappedScript::CreateContext); |
|
|
|
|
|
|
|
NODE_SET_METHOD(constructor_template, |
|
|
|
"runInContext", |
|
|
|
WrappedScript::CompileRunInContext); |
|
|
|
|
|
|
|
NODE_SET_METHOD(constructor_template, |
|
|
|
"runInThisContext", |
|
|
|
WrappedScript::CompileRunInThisContext); |
|
|
|
|
|
|
|
NODE_SET_METHOD(constructor_template, |
|
|
|
"runInNewContext", |
|
|
|
WrappedScript::CompileRunInNewContext); |
|
|
|
|
|
|
|
target->Set(String::NewSymbol("Script"), |
|
|
|
constructor_template->GetFunction()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::New (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::New(const Arguments& args) { |
|
|
|
if (!args.IsConstructCall()) { |
|
|
|
return FromConstructorTemplate(constructor_template, args); |
|
|
|
} |
|
|
|
|
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
node::Script *t = new node::Script(); |
|
|
|
WrappedScript *t = new WrappedScript(); |
|
|
|
t->Wrap(args.Holder()); |
|
|
|
|
|
|
|
return |
|
|
|
node::Script::EvalMachine<compileCode, thisContext, wrapExternal>(args); |
|
|
|
WrappedScript::EvalMachine<compileCode, thisContext, wrapExternal>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
node::Script::~Script() { |
|
|
|
WrappedScript::~WrappedScript() { |
|
|
|
script_.Dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::CreateContext (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::CreateContext(const Arguments& args) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
Local<v8::Object> context = node::Context::NewInstance(); |
|
|
|
Local<Object> context = WrappedContext::NewInstance(); |
|
|
|
|
|
|
|
if (args.Length() > 0) { |
|
|
|
|
|
|
|
Local<Object> sandbox = args[0]->ToObject(); |
|
|
|
Local<Array> keys = sandbox->GetPropertyNames(); |
|
|
|
|
|
|
@ -120,93 +209,94 @@ Handle<Value> node::Script::CreateContext (const Arguments& args) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::RunInContext (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::RunInContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<unwrapExternal, userContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<unwrapExternal, userContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::RunInThisContext (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::RunInThisContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<unwrapExternal, thisContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<unwrapExternal, thisContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::RunInNewContext(const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::RunInNewContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<unwrapExternal, newContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<unwrapExternal, newContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::CompileRunInContext (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::CompileRunInContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<compileCode, userContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<compileCode, userContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::CompileRunInThisContext (const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::CompileRunInThisContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<compileCode, thisContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<compileCode, thisContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> node::Script::CompileRunInNewContext(const Arguments& args) { |
|
|
|
Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& args) { |
|
|
|
return |
|
|
|
node::Script::EvalMachine<compileCode, newContext, returnResult>(args); |
|
|
|
WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <node::Script::EvalInputFlags iFlag, |
|
|
|
node::Script::EvalContextFlags cFlag, |
|
|
|
node::Script::EvalOutputFlags oFlag> |
|
|
|
Handle<Value> node::Script::EvalMachine(const Arguments& args) { |
|
|
|
|
|
|
|
template <WrappedScript::EvalInputFlags input_flag, |
|
|
|
WrappedScript::EvalContextFlags context_flag, |
|
|
|
WrappedScript::EvalOutputFlags output_flag> |
|
|
|
Handle<Value> WrappedScript::EvalMachine(const Arguments& args) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
if (iFlag == compileCode && args.Length() < 1) { |
|
|
|
if (input_flag == compileCode && args.Length() < 1) { |
|
|
|
return ThrowException(Exception::TypeError( |
|
|
|
String::New("needs at least 'code' argument."))); |
|
|
|
} |
|
|
|
|
|
|
|
const int sbIndex = iFlag == compileCode ? 1 : 0; |
|
|
|
if (cFlag == userContext && args.Length() < (sbIndex + 1)) { |
|
|
|
const int sandbox_index = input_flag == compileCode ? 1 : 0; |
|
|
|
if (context_flag == userContext && args.Length() < (sandbox_index + 1)) { |
|
|
|
return ThrowException(Exception::TypeError( |
|
|
|
String::New("needs a 'context' argument."))); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Local<String> code; |
|
|
|
if (iFlag == compileCode) code = args[0]->ToString(); |
|
|
|
if (input_flag == compileCode) code = args[0]->ToString(); |
|
|
|
|
|
|
|
Local<Object> sandbox; |
|
|
|
if (cFlag == newContext) { |
|
|
|
sandbox = args[sbIndex]->IsObject() ? args[sbIndex]->ToObject() : Object::New(); |
|
|
|
} else if (cFlag == userContext) { |
|
|
|
sandbox = args[sbIndex]->ToObject(); |
|
|
|
if (context_flag == newContext) { |
|
|
|
sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject() |
|
|
|
: Object::New(); |
|
|
|
} else if (context_flag == userContext) { |
|
|
|
sandbox = args[sandbox_index]->ToObject(); |
|
|
|
} |
|
|
|
|
|
|
|
const int fnIndex = sbIndex + (cFlag == newContext ? 1 : 0); |
|
|
|
Local<String> filename = args.Length() > fnIndex |
|
|
|
? args[fnIndex]->ToString() |
|
|
|
const int filename_index = sandbox_index + |
|
|
|
(context_flag == newContext ? 1 : 0); |
|
|
|
Local<String> filename = args.Length() > filename_index |
|
|
|
? args[filename_index]->ToString() |
|
|
|
: String::New("evalmachine.<anonymous>"); |
|
|
|
|
|
|
|
Persistent<v8::Context> context; |
|
|
|
Persistent<Context> context; |
|
|
|
|
|
|
|
Local<Array> keys; |
|
|
|
unsigned int i; |
|
|
|
if (cFlag == newContext) { |
|
|
|
if (context_flag == newContext) { |
|
|
|
// Create the new context
|
|
|
|
context = v8::Context::New(); |
|
|
|
context = Context::New(); |
|
|
|
|
|
|
|
} else if (cFlag == userContext) { |
|
|
|
} else if (context_flag == userContext) { |
|
|
|
// Use the passed in context
|
|
|
|
Local<Object> contextArg = args[sbIndex]->ToObject(); |
|
|
|
node::Context *nContext = ObjectWrap::Unwrap<node::Context>(sandbox); |
|
|
|
Local<Object> contextArg = args[sandbox_index]->ToObject(); |
|
|
|
WrappedContext *nContext = ObjectWrap::Unwrap<WrappedContext>(sandbox); |
|
|
|
context = nContext->GetV8Context(); |
|
|
|
} |
|
|
|
|
|
|
|
// New and user context share code. DRY it up.
|
|
|
|
if (cFlag == userContext || cFlag == newContext) { |
|
|
|
if (context_flag == userContext || context_flag == newContext) { |
|
|
|
// Enter the context
|
|
|
|
context->Enter(); |
|
|
|
|
|
|
@ -226,13 +316,13 @@ template <node::Script::EvalInputFlags iFlag, |
|
|
|
TryCatch try_catch; |
|
|
|
|
|
|
|
Handle<Value> result; |
|
|
|
Handle<v8::Script> script; |
|
|
|
Handle<Script> script; |
|
|
|
|
|
|
|
if (iFlag == compileCode) { |
|
|
|
// well, here node::Script::New would suffice in all cases, but maybe
|
|
|
|
if (input_flag == compileCode) { |
|
|
|
// well, here WrappedScript::New would suffice in all cases, but maybe
|
|
|
|
// Compile has a little better performance where possible
|
|
|
|
script = oFlag == returnResult ? v8::Script::Compile(code, filename) |
|
|
|
: v8::Script::New(code, filename); |
|
|
|
script = output_flag == returnResult ? Script::Compile(code, filename) |
|
|
|
: Script::New(code, filename); |
|
|
|
if (script.IsEmpty()) { |
|
|
|
// FIXME UGLY HACK TO DISPLAY SYNTAX ERRORS.
|
|
|
|
DisplayExceptionLine(try_catch); |
|
|
@ -241,33 +331,34 @@ template <node::Script::EvalInputFlags iFlag, |
|
|
|
return try_catch.ReThrow(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); |
|
|
|
if (!nScript) { |
|
|
|
WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder()); |
|
|
|
if (!n_script) { |
|
|
|
return ThrowException(Exception::Error( |
|
|
|
String::New("Must be called as a method of Script."))); |
|
|
|
} else if (nScript->script_.IsEmpty()) { |
|
|
|
String::New("Must be called as a method of WrappedScript."))); |
|
|
|
} else if (n_script->script_.IsEmpty()) { |
|
|
|
return ThrowException(Exception::Error( |
|
|
|
String::New("'this' must be a result of previous new Script(code) call."))); |
|
|
|
String::New("'this' must be a result of previous " |
|
|
|
"new WrappedScript(code) call."))); |
|
|
|
} |
|
|
|
|
|
|
|
script = nScript->script_; |
|
|
|
script = n_script->script_; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (oFlag == returnResult) { |
|
|
|
if (output_flag == returnResult) { |
|
|
|
result = script->Run(); |
|
|
|
if (result.IsEmpty()) return try_catch.ReThrow(); |
|
|
|
} else { |
|
|
|
node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); |
|
|
|
if (!nScript) { |
|
|
|
WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder()); |
|
|
|
if (!n_script) { |
|
|
|
return ThrowException(Exception::Error( |
|
|
|
String::New("Must be called as a method of Script."))); |
|
|
|
String::New("Must be called as a method of WrappedScript."))); |
|
|
|
} |
|
|
|
nScript->script_ = Persistent<v8::Script>::New(script); |
|
|
|
n_script->script_ = Persistent<Script>::New(script); |
|
|
|
result = args.This(); |
|
|
|
} |
|
|
|
|
|
|
|
if (cFlag == userContext || cFlag == newContext) { |
|
|
|
if (context_flag == userContext || context_flag == newContext) { |
|
|
|
// success! copy changes back onto the sandbox object.
|
|
|
|
keys = context->Global()->GetPropertyNames(); |
|
|
|
for (i = 0; i < keys->Length(); i++) { |
|
|
@ -278,12 +369,12 @@ template <node::Script::EvalInputFlags iFlag, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (cFlag == newContext) { |
|
|
|
if (context_flag == newContext) { |
|
|
|
// Clean up, clean up, everybody everywhere!
|
|
|
|
context->DetachGlobal(); |
|
|
|
context->Exit(); |
|
|
|
context.Dispose(); |
|
|
|
} else if (cFlag == userContext) { |
|
|
|
} else if (context_flag == userContext) { |
|
|
|
// Exit the passed in context.
|
|
|
|
context->Exit(); |
|
|
|
} |
|
|
@ -291,11 +382,17 @@ template <node::Script::EvalInputFlags iFlag, |
|
|
|
return result == args.This() ? result : scope.Close(result); |
|
|
|
} |
|
|
|
|
|
|
|
void node::InitEvals(Handle<Object> target) { |
|
|
|
|
|
|
|
void InitEvals(Handle<Object> target) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
node::Context::Initialize(target); |
|
|
|
node::Script::Initialize(target); |
|
|
|
WrappedContext::Initialize(target); |
|
|
|
WrappedScript::Initialize(target); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} // namespace node
|
|
|
|
|
|
|
|
|
|
|
|
NODE_MODULE(node_evals, node::InitEvals); |
|
|
|
|
|
|
|