reimplement module loading
still missing several important features and its mostly untested but the script test/test-test.js is working and thats enough for now.
This commit is contained in:
Родитель
c2decd720f
Коммит
93f7f0dca0
194
src/main.js
194
src/main.js
|
@ -7,65 +7,157 @@ Array.prototype.encodeUtf8 = function () {
|
|||
}
|
||||
|
||||
node.path = new function () {
|
||||
this.join = function () {
|
||||
var joined = "";
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var part = arguments[i].toString();
|
||||
if (i === 0) {
|
||||
part = part.replace(/\/*$/, "/");
|
||||
} else if (i === arguments.length - 1) {
|
||||
part = part.replace(/^\/*/, "");
|
||||
} else {
|
||||
part = part.replace(/^\/*/, "")
|
||||
.replace(/\/*$/, "/");
|
||||
}
|
||||
joined += part;
|
||||
}
|
||||
return joined;
|
||||
};
|
||||
this.join = function () {
|
||||
var joined = "";
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var part = arguments[i].toString();
|
||||
if (i === 0) {
|
||||
part = part.replace(/\/*$/, "/");
|
||||
} else if (i === arguments.length - 1) {
|
||||
part = part.replace(/^\/*/, "");
|
||||
} else {
|
||||
part = part.replace(/^\/*/, "")
|
||||
.replace(/\/*$/, "/");
|
||||
}
|
||||
joined += part;
|
||||
}
|
||||
return joined;
|
||||
};
|
||||
|
||||
this.dirname = function (path) {
|
||||
var parts = path.split("/");
|
||||
return parts.slice(0, parts.length-1);
|
||||
};
|
||||
this.dirname = function (path) {
|
||||
var parts = path.split("/");
|
||||
return parts.slice(0, parts.length-1);
|
||||
};
|
||||
};
|
||||
|
||||
function __include (module, path) {
|
||||
var export = module.require(path);
|
||||
for (var i in export) {
|
||||
if (export.hasOwnProperty(i))
|
||||
module[i] = export[i];
|
||||
// Namespace for module loading functionality
|
||||
(function () {
|
||||
function findScript(base_directory, name, callback) {
|
||||
// in the future this function will be more complicated
|
||||
if (name.charAt(0) == "/")
|
||||
throw "absolute module paths are not yet supported.";
|
||||
|
||||
var filename = node.path.join(base_directory, name) + ".js";
|
||||
File.exists(filename, function (status) {
|
||||
if (status)
|
||||
callback(filename);
|
||||
else
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
// Constructor for submodule.
|
||||
// "name" is like a path but without .js. e.g. "database/mysql"
|
||||
// "target" is an object into which the submodule will be loaded.
|
||||
function Sub (name, target) {
|
||||
this.name = name;
|
||||
this.target = target;
|
||||
|
||||
//puts("new Sub. name = " + name);
|
||||
|
||||
this.load = function (base_directory, callback) {
|
||||
findScript(base_directory, name, function (filename) {
|
||||
if (filename === null) {
|
||||
stderr.puts("Cannot find a script matching: " + name);
|
||||
process.exit(1);
|
||||
}
|
||||
//puts("load subscript: " + filename);
|
||||
//puts(" target = " + target);
|
||||
loadScript(filename, target, callback);
|
||||
});
|
||||
};
|
||||
|
||||
this.toString = function () {
|
||||
return "[sub name=" + name + " target=" + target.toString() + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __require (path, loading_file) {
|
||||
function Scaffold (source, filename, module) {
|
||||
// wrap the source in a strange function
|
||||
var source = "function (__filename) {\n"
|
||||
+ " var on_load;\n"
|
||||
+ " var exports = this;\n"
|
||||
+ " var require = this.__require;\n"
|
||||
+ " var include = this.__include;\n"
|
||||
+ source + "\n"
|
||||
+ " this.__on_load = on_load;\n"
|
||||
+ "};"
|
||||
;
|
||||
// returns the function
|
||||
var compiled = node.compile(source, filename);
|
||||
|
||||
var filename = path;
|
||||
// relative path
|
||||
// absolute path
|
||||
if (path.slice(0,1) === "/") {
|
||||
} else {
|
||||
//filename = node.path.join(node.path.dirname(loading_file), path);
|
||||
module.__subs = [];
|
||||
module.__require = function (name) {
|
||||
var target = {};
|
||||
module.__subs.push(new Sub(name, target));
|
||||
return target;
|
||||
}
|
||||
//stdout.puts("require: " + filename);
|
||||
|
||||
var source = node.blocking.cat(filename);
|
||||
module.__include = function (name) {
|
||||
module.__subs.push(new Sub(name, module));
|
||||
}
|
||||
// execute the script of interest
|
||||
compiled.apply(module, [filename]);
|
||||
|
||||
// wrap the source in a function
|
||||
source = "function (__file__, __dir__) { "
|
||||
+ " var exports = {};"
|
||||
+ " function require (m) { return __require(m, __file__); }"
|
||||
+ " function include (m) { return __include(this, m); }"
|
||||
+ source
|
||||
+ " return exports;"
|
||||
+ "};"
|
||||
;
|
||||
var create_module = node.blocking.exec(source, filename);
|
||||
// The module still needs to have its submodules loaded.
|
||||
this.module = module;
|
||||
this.subs = module.__subs;
|
||||
this.on_load = module.__on_load;
|
||||
|
||||
// execute the function wrap
|
||||
return create_module(filename, node.path.dirname(filename));
|
||||
}
|
||||
/*
|
||||
puts("new Scaffold.");
|
||||
for(var i = 0; i < this.subs.length; i++) {
|
||||
puts("- subs[" + i.toString() + "] " + this.subs[i].toString());
|
||||
}
|
||||
*/
|
||||
|
||||
// main script execution.
|
||||
__require(ARGV[1], ".");
|
||||
// remove these references so they don't get exported.
|
||||
delete module.__subs;
|
||||
delete module.__on_load;
|
||||
delete module.__require;
|
||||
delete module.__include;
|
||||
}
|
||||
|
||||
function loadScript (filename, target, callback) {
|
||||
File.cat(filename, function (status, content) {
|
||||
if (status != 0) {
|
||||
stderr.puts("Error reading " + filename + ": " + File.strerror(status));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//puts("loadScript: " + filename);
|
||||
|
||||
var scaffold = new Scaffold(content, filename, target);
|
||||
|
||||
function finish() {
|
||||
if (scaffold.on_load instanceof Function)
|
||||
scaffold.on_load();
|
||||
else
|
||||
; //puts("no on_load for " + filename + " .. scaffold.on_load = " + scaffold.on_load);
|
||||
|
||||
if (callback instanceof Function)
|
||||
callback();
|
||||
else
|
||||
; //puts("no loadScript callback for " + filename);
|
||||
}
|
||||
|
||||
// Each time require() or include() was called inside the script
|
||||
// a key/value was added to scaffold.__subs.
|
||||
// Now we loop though each one and recursively load each.
|
||||
if (scaffold.subs.length == 0) {
|
||||
finish();
|
||||
} else {
|
||||
while (scaffold.subs.length > 0) {
|
||||
var sub = scaffold.subs.shift();
|
||||
sub.load(node.path.dirname(filename), function () {
|
||||
//puts("finish sub load: " + sub.name);
|
||||
if(scaffold.subs.length != 0) return;
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadScript(ARGV[1], this);
|
||||
})();
|
||||
|
||||
|
|
60
src/node.cc
60
src/node.cc
|
@ -83,59 +83,7 @@ ExecuteString(v8::Handle<v8::String> source,
|
|||
return scope.Close(result);
|
||||
}
|
||||
|
||||
JS_METHOD(cat)
|
||||
{
|
||||
if (args.Length() < 1) return v8::Undefined();
|
||||
HandleScope scope;
|
||||
|
||||
String::Utf8Value filename(args[0]);
|
||||
|
||||
Local<String> error_msg = String::New("File I/O error");
|
||||
|
||||
FILE* file = fopen(*filename, "rb");
|
||||
if (file == NULL) {
|
||||
// Raise error
|
||||
perror("fopen()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
|
||||
int r = fseek(file, 0, SEEK_END);
|
||||
if (r < 0) {
|
||||
perror("fseek()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
|
||||
int size = ftell(file);
|
||||
if (size < 0) {
|
||||
perror("ftell()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
rewind(file);
|
||||
|
||||
char chars[size+1];
|
||||
chars[size] = '\0';
|
||||
for (int i = 0; i < size;) {
|
||||
int read = fread(&chars[i], 1, size - i, file);
|
||||
if(read <= 0) {
|
||||
perror("read()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
i += read;
|
||||
}
|
||||
|
||||
uint16_t expanded_base[size+1];
|
||||
expanded_base[size] = '\0';
|
||||
for(int i = 0; i < size; i++)
|
||||
expanded_base[i] = chars[i];
|
||||
|
||||
fclose(file);
|
||||
|
||||
Local<String> contents = String::New(expanded_base, size);
|
||||
|
||||
return scope.Close(contents);
|
||||
}
|
||||
|
||||
JS_METHOD(exec)
|
||||
JS_METHOD(compile)
|
||||
{
|
||||
if (args.Length() < 2)
|
||||
return Undefined();
|
||||
|
@ -233,11 +181,7 @@ main (int argc, char *argv[])
|
|||
Local<Object> node = Object::New();
|
||||
g->Set(String::New("node"), node);
|
||||
|
||||
Local<Object> blocking = Object::New();
|
||||
node->Set(String::New("blocking"), blocking);
|
||||
|
||||
JS_SET_METHOD(blocking, "exec", exec);
|
||||
JS_SET_METHOD(blocking, "cat", cat);
|
||||
JS_SET_METHOD(node, "compile", compile);
|
||||
|
||||
Local<Array> arguments = Array::New(argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
|
|
25
test/cat.js
25
test/cat.js
|
@ -1,21 +1,8 @@
|
|||
var filename = ARGV[2];
|
||||
|
||||
function cat (file) {
|
||||
file.read(100, function (status, data) {
|
||||
if (status == 0 && data) {
|
||||
stdout.write(data.encodeUtf8());
|
||||
cat(file);
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var f = new File;
|
||||
f.open(filename, "r", function (status) {
|
||||
puts("open!");
|
||||
if (status == 0)
|
||||
cat(f);
|
||||
File.cat(filename, function (status, content) {
|
||||
if (status == 0)
|
||||
puts(content);
|
||||
else
|
||||
puts("error?");
|
||||
})
|
||||
puts("error");
|
||||
});
|
||||
puts("hello world");
|
||||
|
|
|
@ -8,7 +8,8 @@ File.stat(ARGV[2], function (status, stats) {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
File.exists(ARGV[2], function (r) {
|
||||
puts("file exists: " + r);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
node.blocking.print(__file__);
|
||||
/*
|
||||
if (node.path.dirname(__file__) !== "test-test.js") {
|
||||
throw "wrong __file__ argument";
|
||||
puts(__filename);
|
||||
include("mjsunit");
|
||||
puts(__filename);
|
||||
|
||||
function on_load () {
|
||||
assertFalse(false, "testing the test program.");
|
||||
puts("i think everything is okay.");
|
||||
//mjsunit.assertEquals("test-test.js", __file__);
|
||||
}
|
||||
*/
|
||||
|
||||
var mjsunit = require("./mjsunit.js");
|
||||
node.blocking.print(__file__);
|
||||
|
||||
mjsunit.assertFalse(false, "testing the test program.");
|
||||
//mjsunit.assertEquals("test-test.js", __file__);
|
||||
|
|
Загрузка…
Ссылка в новой задаче