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:
parent
a23ecda69f
commit
84baa7614a
@ -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
37
v8js.cc
@ -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}
|
||||
|
108
v8js_methods.cc
108
v8js_methods.cc
@ -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);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user