Skip to content

Commit

Permalink
Structure files and bootstrapping logic to be much cleaner
Browse files Browse the repository at this point in the history
  • Loading branch information
creationix committed Feb 28, 2012
1 parent f40d3cb commit 40c924a
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 243 deletions.
5 changes: 0 additions & 5 deletions lib/utils.js → lib/luvmonkey/utils.js
@@ -1,5 +1,3 @@
(function () {
var exports = {};

var colors = {
black: "0;30",
Expand Down Expand Up @@ -123,6 +121,3 @@ exports.prettyPrint = prettyPrint;
function prettyPrint() {
print.apply(this, Array.prototype.map.call(arguments, dump));
}

return exports;
}());
37 changes: 35 additions & 2 deletions luvmonkey.gyp
@@ -1,13 +1,45 @@
{
'variables': {
'library_files': [
'src/main.js',
],
},

'targets': [

{
'target_name': 'js2c',
'type': 'none',
'toolsets': ['host'],
'actions': [
{
'action_name': 'js2c',

'inputs': [
'./tools/js2c.py',
'<@(library_files)',
],

'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/js_scripts.h',
],


'action': [
'python',
'tools/js2c.py',
'<@(_outputs)',
'<@(library_files)'
],
},
],
},

{ 'target_name': 'luvmonkey',
'type': 'executable',
'dependencies': [
'deps/uv/uv.gyp:uv',
'js2c#host'
],
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
Expand All @@ -18,7 +50,8 @@
'include_dirs': [
'src',
'deps/uv/src/ares',
'deps/mozilla-central/js/src/dist/include'
'deps/mozilla-central/js/src/dist/include',
'<(SHARED_INTERMEDIATE_DIR)' # for js_scripts.h
],
'libraries': [
"-ldl",
Expand All @@ -33,7 +66,7 @@
'src/luv.c',
'src/main.c',
],
}
},

],
}
42 changes: 26 additions & 16 deletions src/luv.c
Expand Up @@ -29,15 +29,26 @@ static JSBool luv_unref(JSContext *cx, uintN argc, jsval *vp) {
static JSBool luv_exepath(JSContext *cx, uintN argc, jsval *vp) {
size_t size = 2*PATH_MAX;
char exec_path[2*PATH_MAX];
if (uv_exepath(exec_path, &size)) {
uv_err_t err = uv_last_error(uv_default_loop());
JS_ReportError(cx, "uv_exepath: %s", uv_strerror(err));
return JS_FALSE;
}
UV_CALL(uv_exepath, exec_path, &size);

JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyN(cx, exec_path, size)));
return JS_TRUE;
}

static JSBool luv_cwd(JSContext *cx, uintN argc, jsval *vp) {
size_t size = 2*PATH_MAX;
char cwd_path[2*PATH_MAX];

uv_err_t err = uv_cwd(cwd_path, size);
if (err.code != UV_OK) {
JS_ReportError(cx, "uv_cwd: %s", uv_strerror(err)); \
return JS_FALSE; \
}

JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyN(cx, cwd_path, strlen(cwd_path))));
return JS_TRUE;
}

static JSBool luv_get_free_memory(JSContext *cx, uintN argc, jsval *vp) {
uint64_t size = uv_get_free_memory();
JS_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(size));
Expand Down Expand Up @@ -74,31 +85,30 @@ static JSFunctionSpec luv_functions[] = {
JS_FS("ref", luv_ref, 0, JSPROP_ENUMERATE),
JS_FS("unref", luv_unref, 0, JSPROP_ENUMERATE),
JS_FS("exepath", luv_exepath, 0, JSPROP_ENUMERATE),
JS_FS("cwd", luv_cwd, 0, JSPROP_ENUMERATE),
JS_FS("get_free_memory", luv_get_free_memory, 0, JSPROP_ENUMERATE),
JS_FS("get_total_memory", luv_get_total_memory, 0, JSPROP_ENUMERATE),
JS_FS("loadavg", luv_loadavg, 0, JSPROP_ENUMERATE),
JS_FS("uptime", luv_uptime, 0, JSPROP_ENUMERATE),
JS_FS_END
};

int luv_init(JSContext* cx, JSObject *uv) {
JSBool luv_init(JSContext *cx, uintN argc, jsval *vp) {
JSObject* uv = JS_NewObject(cx, NULL, NULL, NULL);
if (!JS_DefineFunctions(cx, uv, luv_functions)) {
fprintf(stderr, "Error in define functions\n");
return 1;
return JS_FALSE;
}
if (luv_handle_init(cx, uv)) {
fprintf(stderr, "Error in handle_init\n");
return 1;
return JS_FALSE;
}
if (luv_stream_init(cx, uv)) {
fprintf(stderr, "Error in stream_init\n");
return 1;
return JS_FALSE;
}
if (luv_tcp_init(cx, uv)) {
fprintf(stderr, "Error in tcp_init\n");
return 1;
return JS_FALSE;
}
return 0;
}

JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(uv));
return JS_TRUE;
}

2 changes: 1 addition & 1 deletion src/luv.h
Expand Up @@ -3,6 +3,6 @@

#include "jsapi.h"

int luv_init(JSContext* cx, JSObject* uv);
JSBool luv_init(JSContext *cx, uintN argc, jsval *vp);

#endif
2 changes: 0 additions & 2 deletions src/luv_tcp.c
Expand Up @@ -12,7 +12,6 @@ static JSClass Tcp_class = {


static JSBool Tcp_constructor(JSContext *cx, uintN argc, jsval *vp) {
printf("Tcp instance getting created\n");
JSObject* obj = JS_NewObject(cx, &Tcp_class, Tcp_prototype, NULL);

uv_tcp_t* handle = malloc(sizeof(uv_tcp_t));
Expand All @@ -25,7 +24,6 @@ static JSBool Tcp_constructor(JSContext *cx, uintN argc, jsval *vp) {

/* Free the uv_tcp_t* when the object gets GCed */
static void Tcp_finalize(JSContext *cx, JSObject *this) {
printf("Tcp instance getting freed\n");
free(JS_GetPrivate(this));
}

Expand Down
76 changes: 42 additions & 34 deletions src/main.c
Expand Up @@ -2,6 +2,7 @@
#include "jsapi.h"
#include "luv.h"
#include "main.h"
#include "js_scripts.h"

/* The class of the global object. */
static JSClass global_class = {
Expand Down Expand Up @@ -59,43 +60,58 @@ PrintErr(JSContext *cx, uintN argc, jsval *vp)
return PrintInternal(cx, argc, vp, stderr);
}

static JSFunctionSpec global_functions[] = {
JS_FS("print", Print, 0, 0),
JS_FS("printErr", PrintErr, 0, 0),
JS_FS_END
};
static JSBool Exit(JSContext *cx, uintN argc, jsval *vp) {
int exitCode;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "i", &exitCode)) {
return JS_FALSE;
}
exit(exitCode);
}

static JSBool executeFile(JSContext *cx, uintN argc, jsval *vp) {

static JSBool compileFile(JSContext *cx, uintN argc, jsval *vp) {
JSString* str;
JSObject* obj;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "So", &str, &obj)) {
return JS_FALSE;
}
char *filename = JS_EncodeString(cx, str);

/* TODO: get filename from arg */
const char* filename = "lib/utils.js";
JSScript* script = JS_CompileUTF8File(cx, JS_THIS_OBJECT(cx, vp), filename);
JS_free(cx, filename);
if (!script) {
return JS_FALSE;
}

jsval result;
if (!JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, &result)) {
if (!JS_ExecuteScript(cx, obj, script, &result)) {
return JS_FALSE;
}

JS_SET_RVAL(cx, vp, result);
return JS_TRUE;
}

static JSFunctionSpec global_functions[] = {
JS_FS("print", Print, 0, 0),
JS_FS("printErr", PrintErr, 0, 0),
JS_FS("executeFile", executeFile, 2, 0),
JS_FS("exit", Exit, 1, 0),
JS_FS_END
};

static JSFunctionSpec binding_functions[] = {
JS_FS("uv", luv_init, 0, 0),
JS_FS_END
};

int main(int argc, const char *argv[])
{

if ( argc < 2 ) {
printf( "usage: %s filename\n", argv[0] );
return 1;
}

/* JS variables. */
JSRuntime *rt;
JSContext *cx;
JSObject *global;
JSRuntime* rt;
JSContext* cx;
JSObject* global;

/* Create a JS runtime. */
rt = JS_NewRuntime(8L * 1024L * 1024L);
Expand All @@ -118,35 +134,27 @@ int main(int argc, const char *argv[])
like Object and Array. */
if (!JS_InitStandardClasses(cx, global)) return 1;

/* Attach the global functions */
if (!JS_DefineFunctions(cx, global, global_functions)) return 1;

/* Make global reference itself at "global" */
jsval global_val = OBJECT_TO_JSVAL(global);
if (!JS_SetProperty(cx, global, "global", &global_val)) return 1;
JSObject* alpha = JS_DefineObject(cx, global, "alpha", NULL, NULL, 0);

/* Create a "uv" namespace for the uv_* functions */
JSObject* uv = JS_DefineObject(cx, global, "uv", NULL, NULL, 0);
if (luv_init(cx, uv)) return 1;
/* Attach the global functions */
if (!JS_DefineFunctions(cx, alpha, global_functions)) return 1;

/* define a compileFile function */
JS_DefineFunction(cx, global, "compileFile", compileFile, 1, 0);
/* expose the binding functions for require to use */
JSObject* bindings = JS_DefineObject(cx, alpha, "bindings", NULL, NULL, 0);
if (!JS_DefineFunctions(cx, bindings, binding_functions)) return 1;

/* Set args as global */
JSObject* args = JS_NewArrayObject(cx, 0, NULL);
jsval args_val = OBJECT_TO_JSVAL(args);
if (!JS_SetProperty(cx, global, "args", &args_val)) return 1;
if (!JS_SetProperty(cx, alpha, "args", &args_val)) return 1;
int index;
for (index = 0; index < argc; index++) {
jsval arg = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, argv[index]));
if (!JS_SetElement(cx, args, index, &arg)) return 1;
}

/* Execute the file given on argv[1] */
const char* filename = argv[1];
JSScript* script = JS_CompileUTF8File(cx, global, filename);
if (!script) return 2;
JS_ExecuteScript(cx, global, script, NULL);
/* Bootstrap using the code in main.js */
JS_EvaluateScript(cx, global, embedded_src_main_js, strlen(embedded_src_main_js), "main.js", 1, NULL);

/* Cleanup. */
JS_DestroyContext(cx);
Expand Down
80 changes: 80 additions & 0 deletions src/main.js
@@ -0,0 +1,80 @@
// Keep locals out of global scope
(function () {

// Copy the interesting bits from alpha to where we want them
var bindings = alpha.bindings;
var executeFile = alpha.executeFile;
(function() {
var global = this;
global.global = global;
global.args = alpha.args;
global.print = alpha.print;
global.exit = alpha.exit;
global.printErr = alpha.printErr;
delete global.alpha;
}());

// This is needed before we can require anything
var moduleCache = {};

var uv = realRequire('uv');

function loadBuiltin(name) {
if (!bindings.hasOwnProperty(name)) return false;
if (moduleCache.hasOwnProperty(name)) {
return moduleCache[name];
}
return moduleCache[name] = bindings[name]();
}
function loadModule(filename) {
var dirname = filename.substr(0, filename.lastIndexOf("/"));
var require = function require(name) {
return realRequire(name, dirname);
}
require.resolve = function resolve(name) {
return realResolve(name, dirname);
}
var exports = moduleCache[filename];
var module = { exports: exports };
var sandbox = Object.create(this, {
exports: { value: exports },
module: { value: module },
__filename: { value: filename },
__dirname: { value: dirname },
require: { value: require }
});
executeFile(filename, sandbox);
return module.exports;
}

function realResolve(name, base) {
// TODO: put prefix here once makefile puts binary in bin folder
// var prefix = uv.exepath().match(/^(.*)\/[^\/]+\/[^\/]+$/)[1] + "/";
return "lib/luvmonkey/" + name + ".js";
}

function realRequire(name, base) {
var module = loadBuiltin(name);
if (module) return module;
var filename = realResolve(name, base);
if (moduleCache.hasOwnProperty(filename)) {
return moduleCache[filename];
}
moduleCache[filename] = {};
return moduleCache[filename] = loadModule(filename);
}

if (args.length < 2) {
print("Usage\n\t" + args[0] + " filename.js\n")
exit(1);
}

// Execute the first arg as a luvmonkey script.
var path = args[1];
if (path[0] !== "/") path = uv.cwd() + "/" + path;
loadModule(path);

// Start the event loop.
uv.run();

}());

0 comments on commit 40c924a

Please sign in to comment.