0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-11-08 14:48:40 +00:00

First working version of CommonJS modules.

This commit is contained in:
Simon Best 2013-03-24 16:27:13 +00:00
parent a23ecda69f
commit 84baa7614a
3 changed files with 147 additions and 16 deletions

View File

@ -91,12 +91,24 @@ v8::Handle<v8::Value> zval_to_v8js(zval * TSRMLS_DC);
/* Convert V8 value into zval */
int v8js_to_zval(v8::Handle<v8::Value>, zval *, int TSRMLS_DC);
/* Register builtin methods into passed object */
void php_v8js_register_methods(v8::Handle<v8::ObjectTemplate>);
/* Register accessors into passed object */
void php_v8js_register_accessors(v8::Local<v8::ObjectTemplate>, zval * TSRMLS_DC);
/* {{{ Context container */
struct php_v8js_ctx {
zend_object std;
v8::Persistent<v8::String> object_name;
v8::Persistent<v8::Context> context;
zend_bool report_uncaught;
zval *pending_exception;
int in_execution;
zval *module_loader;
};
/* }}} */
/* Register builtin methods into passed object */
void php_v8js_register_methods(v8::Handle<v8::ObjectTemplate>, php_v8js_ctx *c);
#endif /* PHP_V8JS_MACROS_H */
/*

37
v8js.cc
View File

@ -126,17 +126,6 @@ struct php_v8js_jsext {
};
/* }}} */
/* {{{ Context container */
struct php_v8js_ctx {
zend_object std;
v8::Persistent<v8::String> object_name;
v8::Persistent<v8::Context> context;
zend_bool report_uncaught;
zval *pending_exception;
int in_execution;
};
/* }}} */
/* {{{ Object container */
struct php_v8js_object {
zend_object std;
@ -579,6 +568,7 @@ static PHP_METHOD(V8Js, __construct)
c->report_uncaught = report_uncaught;
c->pending_exception = NULL;
c->in_execution = 0;
c->module_loader = NULL;
/* Initialize V8 */
php_v8js_init(TSRMLS_C);
@ -606,7 +596,7 @@ static PHP_METHOD(V8Js, __construct)
V8JSG(global_template)->SetClassName(V8JS_SYM("V8Js"));
/* Register builtin methods */
php_v8js_register_methods(V8JSG(global_template)->InstanceTemplate());
php_v8js_register_methods(V8JSG(global_template)->InstanceTemplate(), c);
}
/* Create context */
@ -766,6 +756,24 @@ static PHP_METHOD(V8Js, getPendingException)
}
/* }}} */
/* {{{ proto void V8Js::setModuleLoader(string module)
*/
static PHP_METHOD(V8Js, setModuleLoader)
{
php_v8js_ctx *c;
zval *callable;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callable) == FAILURE) {
return;
}
c = (php_v8js_ctx *) zend_object_store_get_object(getThis() TSRMLS_CC);
c->module_loader = callable;
Z_ADDREF_P(c->module_loader);
}
/* }}} */
static void php_v8js_persistent_zval_ctor(zval **p) /* {{{ */
{
zval *orig_ptr = *p;
@ -925,6 +933,10 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_v8js_getpendingexception, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setmoduleloader, 0, 0, 1)
ZEND_ARG_INFO(0, callable)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_registerextension, 0, 0, 2)
ZEND_ARG_INFO(0, extension_name)
ZEND_ARG_INFO(0, script)
@ -943,6 +955,7 @@ static const zend_function_entry v8js_methods[] = { /* {{{ */
PHP_ME(V8Js, __construct, arginfo_v8js_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(V8Js, executeString, arginfo_v8js_executestring, ZEND_ACC_PUBLIC)
PHP_ME(V8Js, getPendingException, arginfo_v8js_getpendingexception, ZEND_ACC_PUBLIC)
PHP_ME(V8Js, setModuleLoader, arginfo_v8js_setmoduleloader, ZEND_ACC_PUBLIC)
PHP_ME(V8Js, registerExtension, arginfo_v8js_registerextension, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(V8Js, getExtensions, arginfo_v8js_getextensions, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}

View File

@ -29,6 +29,7 @@ extern "C" {
#include "php_v8js_macros.h"
#include <v8.h>
#include <map>
/* global.exit - terminate execution */
V8JS_METHOD(exit) /* {{{ */
@ -167,12 +168,117 @@ V8JS_METHOD(var_dump) /* {{{ */
}
/* }}} */
void php_v8js_register_methods(v8::Handle<v8::ObjectTemplate> global) /* {{{ */
// TODO: Put this in php_v8js_context
std::map<char *, v8::Handle<v8::Object> > modules_loaded;
V8JS_METHOD(require)
{
//v8::Persistent<v8::Value> module_name_value_v8 = v8::Persistent<v8::Value>::New(args[0]->ToObject());
v8::String::Utf8Value module_name_v8(args[0]);
// Make sure to duplicate the string to ensure it is not freed by V8's garbage collector
char *module_name = strdup(ToCString(module_name_v8));
if (modules_loaded.count(module_name) > 0) {
printf("Using cached module\n");
return modules_loaded[module_name];
}
zval module_code;
zval *module_name_zend;
MAKE_STD_ZVAL(module_name_zend);
ZVAL_STRING(module_name_zend, module_name, 1);
zval* params[] = { module_name_zend };
// Get the module loader from extension context
v8::Handle<v8::External> data = v8::Handle<v8::External>::Cast(args.Data());
php_v8js_ctx *c = static_cast<php_v8js_ctx*>(data->Value());
if (c->module_loader == NULL) {
printf("Module loader not defined!\n");
exit(-1);
}
if (SUCCESS == call_user_function(EG(function_table), NULL, c->module_loader, &module_code, 1, params TSRMLS_CC)) {
printf("CODE = %s\n", Z_STRVAL(module_code));
} else {
printf("Module loader callback failed\n");
exit(-1);
}
// Create a template for the global object and set the built-in global functions
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
global->Set(v8::String::New("print"), v8::FunctionTemplate::New(V8JS_MN(print)), v8::ReadOnly);
global->Set(v8::String::New("require"), v8::FunctionTemplate::New(V8JS_MN(require), v8::External::New(c)), v8::ReadOnly);
// Add the exports object
v8::Handle<v8::ObjectTemplate> exports_template = v8::ObjectTemplate::New();
v8::Handle<v8::Object> exports = exports_template->NewInstance();
global->Set(v8::String::New("exports"), exports);
// Each module gets its own context so different modules do not affect each other
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
// Catch JS exceptions
v8::TryCatch try_catch;
// Enter the module context
v8::Context::Scope scope(context);
v8::HandleScope handle_scope;
// Set script identifier
v8::Local<v8::String> sname = V8JS_SYM("require");
// TODO: Load module code here
v8::Local<v8::String> source = v8::String::New(Z_STRVAL(module_code));
// Create and compile script
v8::Local<v8::Script> script = v8::Script::New(source, sname);
// The script will be empty if there are compile errors
if (script.IsEmpty()) {
//php_v8js_throw_exception(&try_catch TSRMLS_CC);
printf("Compile error\n");
exit(-1);
return V8JS_NULL;
}
// Run script
//c->in_execution++;
v8::Local<v8::Value> result = script->Run();
//c->in_execution--;
// Script possibly terminated, return immediately
if (!try_catch.CanContinue()) {
// TODO: Throw PHP exception here?
return V8JS_NULL;
}
// Handle runtime JS exceptions
if (try_catch.HasCaught()) {
// Rethrow the exception back to JS
try_catch.ReThrow();
return V8JS_NULL;
}
// Cache the module
modules_loaded[module_name] = handle_scope.Close(exports);
return modules_loaded[module_name];
}
void php_v8js_register_methods(v8::Handle<v8::ObjectTemplate> global, php_v8js_ctx *c) /* {{{ */
{
global->Set(V8JS_SYM("exit"), v8::FunctionTemplate::New(V8JS_MN(exit)), v8::ReadOnly);
global->Set(V8JS_SYM("sleep"), v8::FunctionTemplate::New(V8JS_MN(sleep)), v8::ReadOnly);
global->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(V8JS_MN(print)), v8::ReadOnly);
global->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(V8JS_MN(var_dump)), v8::ReadOnly);
global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(V8JS_MN(require), v8::External::New(c)), v8::ReadOnly);
}
/* }}} */