Skip to content

Commit 242161b

Browse files
cha0sry
authored andcommitted
Added new API to Script, and implemented it in the REPL
1 parent 5a25338 commit 242161b

10 files changed

+211
-37
lines changed

lib/repl.js

+21-20
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
// repl.start("node via TCP socket> ", socket);
1111
// }).listen(5001);
1212

13-
// repl.start("node > ").scope.foo = "stdin is fun"; // expose foo to repl scope
13+
// repl.start("node > ").context.foo = "stdin is fun"; // expose foo to repl context
1414

1515
var sys = require('sys');
16-
var evalcx = process.binding('evals').Script.runInNewContext;
16+
var Script = process.binding('evals').Script;
17+
var evalcx = Script.runInContext;
1718
var path = require("path");
1819
var rl = require('readline');
19-
var scope;
20+
var context;
2021

2122
function cwdRequire (id) {
2223
if (id.match(/^\.\.\//) || id.match(/^\.\//)) {
@@ -28,11 +29,11 @@ Object.keys(require).forEach(function (k) {
2829
cwdRequire[k] = require[k];
2930
});
3031

31-
function setScope (self) {
32-
scope = {};
33-
for (var i in global) scope[i] = global[i];
34-
scope.module = module;
35-
scope.require = cwdRequire;
32+
function resetContext() {
33+
context = Script.createContext();
34+
for (var i in global) context[i] = global[i];
35+
context.module = module;
36+
context.require = cwdRequire;
3637
}
3738

3839

@@ -41,8 +42,8 @@ exports.writer = sys.inspect;
4142

4243
function REPLServer(prompt, stream) {
4344
var self = this;
44-
if (!scope) setScope();
45-
self.scope = scope;
45+
if (!context) resetContext();
46+
self.context = context;
4647
self.buffered_cmd = '';
4748

4849
self.stream = stream || process.openStdin();
@@ -70,10 +71,10 @@ function REPLServer(prompt, stream) {
7071
// This try is for determining if the command is complete, or should
7172
// continue onto the next line.
7273
try {
73-
// Use evalcx to supply the global scope
74-
var ret = evalcx(self.buffered_cmd, scope, "repl");
74+
// Use evalcx to supply the global context
75+
var ret = evalcx(self.buffered_cmd, context, "repl");
7576
if (ret !== undefined) {
76-
scope._ = ret;
77+
context._ = ret;
7778
flushed = self.stream.write(exports.writer(ret) + "\n");
7879
}
7980

@@ -150,17 +151,17 @@ REPLServer.prototype.parseREPLKeyword = function (cmd) {
150151
self.displayPrompt();
151152
return true;
152153
case ".clear":
153-
self.stream.write("Clearing Scope...\n");
154+
self.stream.write("Clearing context...\n");
154155
self.buffered_cmd = '';
155-
setScope();
156+
resetContext();
156157
self.displayPrompt();
157158
return true;
158159
case ".exit":
159160
self.stream.destroy();
160161
return true;
161162
case ".help":
162163
self.stream.write(".break\tSometimes you get stuck in a place you can't get out... This will get you out.\n");
163-
self.stream.write(".clear\tBreak, and also clear the local scope.\n");
164+
self.stream.write(".clear\tBreak, and also clear the local context.\n");
164165
self.stream.write(".exit\tExit the prompt\n");
165166
self.stream.write(".help\tShow repl options\n");
166167
self.displayPrompt();
@@ -180,21 +181,21 @@ function trimWhitespace (cmd) {
180181

181182
/**
182183
* Converts commands that use var and function <name>() to use the
183-
* local exports.scope when evaled. This provides a local scope
184+
* local exports.context when evaled. This provides a local context
184185
* on the REPL.
185186
*
186187
* @param {String} cmd The cmd to convert
187188
* @returns {String} The converted command
188189
*/
189-
REPLServer.prototype.convertToScope = function (cmd) {
190+
REPLServer.prototype.convertToContext = function (cmd) {
190191
var self = this, matches,
191192
scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m,
192193
scopeFunc = /^\s*function\s*([_\w\$]+)/;
193194

194-
// Replaces: var foo = "bar"; with: self.scope.foo = bar;
195+
// Replaces: var foo = "bar"; with: self.context.foo = bar;
195196
matches = scopeVar.exec(cmd);
196197
if (matches && matches.length === 3) {
197-
return "self.scope." + matches[1] + matches[2];
198+
return "self.context." + matches[1] + matches[2];
198199
}
199200

200201
// Replaces: function foo() {}; with: foo = function foo() {};

src/node.cc

+4-3
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,7 @@ static Handle<Value> Binding(const Arguments& args) {
16311631
exports = binding_cache->Get(module)->ToObject();
16321632
} else {
16331633
exports = Object::New();
1634+
node::Context::Initialize(exports);
16341635
node::Script::Initialize(exports);
16351636
binding_cache->Set(module, exports);
16361637
}
@@ -1685,7 +1686,7 @@ static void Load(int argc, char *argv[]) {
16851686
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
16861687

16871688
// Add a reference to the global object
1688-
Local<Object> global = Context::GetCurrent()->Global();
1689+
Local<Object> global = v8::Context::GetCurrent()->Global();
16891690
process->Set(String::NewSymbol("global"), global);
16901691

16911692
// process.version
@@ -1987,8 +1988,8 @@ int main(int argc, char *argv[]) {
19871988
}
19881989

19891990
// Create the one and only Context.
1990-
Persistent<Context> context = Context::New();
1991-
Context::Scope context_scope(context);
1991+
Persistent<v8::Context> context = v8::Context::New();
1992+
v8::Context::Scope context_scope(context);
19921993

19931994
atexit(node::AtExit);
19941995

src/node_cares.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ static void ResolveError(Persistent<Function> &cb, int status) {
223223

224224
TryCatch try_catch;
225225

226-
cb->Call(Context::GetCurrent()->Global(), 1, &e);
226+
cb->Call(v8::Context::GetCurrent()->Global(), 1, &e);
227227

228228
if (try_catch.HasCaught()) {
229229
FatalException(try_catch);
@@ -251,7 +251,7 @@ static void HostByNameCb(void *data,
251251

252252
Local<Value> argv[2] = { Local<Value>::New(Null()), addresses};
253253

254-
(*cb)->Call(Context::GetCurrent()->Global(), 2, argv);
254+
(*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
255255

256256
if (try_catch.HasCaught()) {
257257
FatalException(try_catch);
@@ -281,7 +281,7 @@ static void HostByAddrCb(void *data,
281281

282282
Local<Value> argv[2] = { Local<Value>::New(Null()), names };
283283

284-
(*cb)->Call(Context::GetCurrent()->Global(), 2, argv);
284+
(*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
285285

286286
if (try_catch.HasCaught()) {
287287
FatalException(try_catch);
@@ -294,7 +294,7 @@ static void HostByAddrCb(void *data,
294294
static void cb_call(Persistent<Function> &cb, int argc, Local<Value> *argv) {
295295
TryCatch try_catch;
296296

297-
cb->Call(Context::GetCurrent()->Global(), argc, argv);
297+
cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
298298

299299
if (try_catch.HasCaught()) {
300300
FatalException(try_catch);

src/node_child_process.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ Handle<Value> ChildProcess::Kill(const Arguments& args) {
156156
sig = args[0]->Int32Value();
157157
} else if (args[0]->IsString()) {
158158
Local<String> signame = args[0]->ToString();
159-
Local<Object> process = Context::GetCurrent()->Global();
159+
Local<Object> process = v8::Context::GetCurrent()->Global();
160160
Local<Object> node_obj = process->Get(String::NewSymbol("process"))->ToObject();
161161

162162
Local<Value> sig_v = node_obj->Get(signame);

src/node_file.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static int After(eio_req *req) {
145145

146146
TryCatch try_catch;
147147

148-
(*callback)->Call(Context::GetCurrent()->Global(), argc, argv);
148+
(*callback)->Call(v8::Context::GetCurrent()->Global(), argc, argv);
149149

150150
if (try_catch.HasCaught()) {
151151
FatalException(try_catch);

src/node_script.cc

+119-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,52 @@
77
using namespace v8;
88
using namespace node;
99

10+
Persistent<FunctionTemplate> node::Context::constructor_template;
11+
12+
void
13+
node::Context::Initialize (Handle<Object> target)
14+
{
15+
HandleScope scope;
16+
17+
Local<FunctionTemplate> t = FunctionTemplate::New(node::Context::New);
18+
constructor_template = Persistent<FunctionTemplate>::New(t);
19+
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
20+
constructor_template->SetClassName(String::NewSymbol("Context"));
21+
22+
target->Set(String::NewSymbol("Context"), constructor_template->GetFunction());
23+
}
24+
25+
Handle<Value>
26+
node::Context::New (const Arguments& args)
27+
{
28+
HandleScope scope;
29+
30+
node::Context *t = new node::Context();
31+
t->Wrap(args.This());
32+
33+
return args.This();
34+
}
35+
36+
node::Context::~Context() {
37+
_context.Dispose();
38+
}
39+
40+
Local<Object>
41+
node::Context::NewInstance()
42+
{
43+
Local<Object> context = constructor_template->GetFunction()->NewInstance();
44+
node::Context *nContext = ObjectWrap::Unwrap<node::Context>(context);
45+
nContext->_context = v8::Context::New();
46+
return context;
47+
}
48+
49+
v8::Persistent<v8::Context>
50+
node::Context::GetV8Context()
51+
{
52+
return _context;
53+
}
54+
55+
1056
Persistent<FunctionTemplate> node::Script::constructor_template;
1157

1258
void
@@ -19,8 +65,12 @@ node::Script::Initialize (Handle<Object> target)
1965
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
2066
constructor_template->SetClassName(String::NewSymbol("Script"));
2167

68+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "createContext", node::Script::CreateContext);
69+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInContext", node::Script::RunInContext);
2270
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInThisContext", node::Script::RunInThisContext);
2371
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInNewContext", node::Script::RunInNewContext);
72+
NODE_SET_METHOD(constructor_template, "createContext", node::Script::CreateContext);
73+
NODE_SET_METHOD(constructor_template, "runInContext", node::Script::CompileRunInContext);
2474
NODE_SET_METHOD(constructor_template, "runInThisContext", node::Script::CompileRunInThisContext);
2575
NODE_SET_METHOD(constructor_template, "runInNewContext", node::Script::CompileRunInNewContext);
2676

@@ -44,6 +94,37 @@ node::Script::~Script() {
4494
}
4595

4696

97+
Handle<Value>
98+
node::Script::CreateContext (const Arguments& args)
99+
{
100+
HandleScope scope;
101+
102+
Local<v8::Object> context = node::Context::NewInstance();
103+
104+
if (args.Length() > 0) {
105+
106+
Local<Object> sandbox = args[0]->ToObject();
107+
Local<Array> keys = sandbox->GetPropertyNames();
108+
109+
for (int i = 0; i < keys->Length(); i++) {
110+
Handle<String> key = keys->Get(Integer::New(i))->ToString();
111+
Handle<Value> value = sandbox->Get(key);
112+
context->Set(key, value);
113+
}
114+
}
115+
116+
117+
return scope.Close(context);
118+
}
119+
120+
Handle<Value>
121+
node::Script::RunInContext (const Arguments& args)
122+
{
123+
return
124+
node::Script::EvalMachine<unwrapExternal, userContext, returnResult>(args);
125+
}
126+
127+
47128
Handle<Value>
48129
node::Script::RunInThisContext (const Arguments& args)
49130
{
@@ -59,6 +140,14 @@ node::Script::RunInNewContext(const Arguments& args) {
59140
}
60141

61142

143+
Handle<Value>
144+
node::Script::CompileRunInContext (const Arguments& args)
145+
{
146+
return
147+
node::Script::EvalMachine<compileCode, userContext, returnResult>(args);
148+
}
149+
150+
62151
Handle<Value>
63152
node::Script::CompileRunInThisContext (const Arguments& args)
64153
{
@@ -91,29 +180,50 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) {
91180
));
92181
}
93182

183+
const int sbIndex = iFlag == compileCode ? 1 : 0;
184+
if (cFlag == userContext && args.Length() < (sbIndex + 1)) {
185+
return ThrowException(Exception::TypeError(
186+
String::New("needs a 'context' argument.")
187+
));
188+
}
189+
190+
94191
Local<String> code;
95192
if (iFlag == compileCode) { code = args[0]->ToString(); }
96193

97194
Local<Object> sandbox;
98-
const int sbIndex = iFlag == compileCode ? 1 : 0;
99195
if (cFlag == newContext) {
100196
sandbox = args.Length() > sbIndex ? args[sbIndex]->ToObject() : Object::New();
101197
}
198+
else if (cFlag == userContext) {
199+
sandbox = args[sbIndex]->ToObject();
200+
}
102201
const int fnIndex = sbIndex + (cFlag == newContext ? 1 : 0);
103202
Local<String> filename = args.Length() > fnIndex ? args[fnIndex]->ToString()
104203
: String::New("evalmachine.<anonymous>");
105204

106-
Persistent<Context> context;
205+
Persistent<v8::Context> context;
107206
Local<Array> keys;
108207
unsigned int i;
109208
if (cFlag == newContext) {
110209
// Create the new context
111-
context = Context::New();
210+
context = v8::Context::New();
112211

113-
// Enter and compile script
212+
} else if (cFlag == userContext) {
213+
// Use the passed in context
214+
Local<Object> contextArg = args[sbIndex]->ToObject();
215+
node::Context *nContext = ObjectWrap::Unwrap<node::Context>(sandbox);
216+
context = nContext->GetV8Context();
217+
}
218+
219+
// New and user context share code. DRY it up.
220+
if (cFlag == userContext || cFlag == newContext) {
221+
222+
// Enter the context
114223
context->Enter();
115224

116-
// Copy objects from global context, to our brand new context
225+
// Copy everything from the passed in sandbox (either the persistent
226+
// context for runInContext(), or the sandbox arg to runInNewContext()).
117227
keys = sandbox->GetPropertyNames();
118228

119229
for (i = 0; i < keys->Length(); i++) {
@@ -167,7 +277,7 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) {
167277
}
168278
if (result.IsEmpty()) {
169279
return try_catch.ReThrow();
170-
} else if (cFlag == newContext) {
280+
} else if (cFlag == userContext || cFlag == newContext) {
171281
// success! copy changes back onto the sandbox object.
172282
keys = context->Global()->GetPropertyNames();
173283
for (i = 0; i < keys->Length(); i++) {
@@ -183,6 +293,9 @@ Handle<Value> node::Script::EvalMachine(const Arguments& args) {
183293
context->DetachGlobal();
184294
context->Exit();
185295
context.Dispose();
296+
} else if (cFlag == userContext) {
297+
// Exit the passed in context.
298+
context->Exit();
186299
}
187300

188301
return result == args.This() ? result : scope.Close(result);

0 commit comments

Comments
 (0)