From a18ae9e85347d6d4f7fbb695dfdb0b662b9d7082 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 9 Jan 2016 12:50:40 +0100 Subject: [PATCH] Implement JS-side wrapper around PHP Generator objects --- config.m4 | 8 ++++ config.w32 | 3 +- tests/generators_to_v8_basic.phpt | 41 +++++++++++++++++ v8js_generator_export.cc | 73 +++++++++++++++++++++++++++++++ v8js_generator_export.h | 28 ++++++++++++ v8js_object_export.cc | 13 +++++- 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 tests/generators_to_v8_basic.phpt create mode 100644 v8js_generator_export.cc create mode 100644 v8js_generator_export.h diff --git a/config.m4 b/config.m4 index 1e3c488..5d9e4eb 100644 --- a/config.m4 +++ b/config.m4 @@ -180,6 +180,7 @@ int main () v8js_commonjs.cc \ v8js_convert.cc \ v8js_exceptions.cc \ + v8js_generator_export.cc \ v8js_methods.cc \ v8js_object_export.cc \ v8js_timer.cc \ @@ -190,3 +191,10 @@ int main () PHP_ADD_MAKEFILE_FRAGMENT fi + +dnl Local variables: +dnl tab-width: 4 +dnl c-basic-offset: 4 +dnl End: +dnl vim600: noet sw=4 ts=4 fdm=marker +dnl vim<600: noet sw=4 ts=4 diff --git a/config.w32 b/config.w32 index 92b90ee..8ac5694 100644 --- a/config.w32 +++ b/config.w32 @@ -17,11 +17,10 @@ if (PHP_V8JS != "no") { AC_DEFINE("PHP_V8_API_VERSION", "4007075", "", false); AC_DEFINE("PHP_V8_VERSION", "4.7.75", "", true); - EXTENSION("v8js", "v8js_array_access.cc v8js.cc v8js_class.cc v8js_commonjs.cc v8js_convert.cc v8js_exceptions.cc v8js_methods.cc v8js_object_export.cc v8js_timer.cc v8js_v8.cc v8js_v8object_class.cc v8js_variables.cc", "yes"); + EXTENSION("v8js", "v8js_array_access.cc v8js.cc v8js_class.cc v8js_commonjs.cc v8js_convert.cc v8js_exceptions.cc v8js_generator_export.cc v8js_methods.cc v8js_object_export.cc v8js_timer.cc v8js_v8.cc v8js_v8object_class.cc v8js_variables.cc", "yes"); } else { WARNING("v8js not enabled, headers or libs not found"); } } - diff --git a/tests/generators_to_v8_basic.phpt b/tests/generators_to_v8_basic.phpt new file mode 100644 index 0000000..d14a35d --- /dev/null +++ b/tests/generators_to_v8_basic.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test V8::executeString() : Generators PHP -> V8 +--SKIPIF-- + +--FILE-- +gen = TheGenerator(); +$gen = $v8->executeString($js); + +?> +===EOF=== +--EXPECTF-- +int(0) +int(1) +int(2) +int(3) +int(0) +int(1) +int(2) +int(3) +===EOF=== diff --git a/v8js_generator_export.cc b/v8js_generator_export.cc new file mode 100644 index 0000000..19bc1cb --- /dev/null +++ b/v8js_generator_export.cc @@ -0,0 +1,73 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 2016 The PHP Group | + +----------------------------------------------------------------------+ + | http://www.opensource.org/licenses/mit-license.php MIT License | + +----------------------------------------------------------------------+ + | Author: Stefan Siegl | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "php_v8js_macros.h" + +v8::Local v8js_wrap_generator(v8js_ctx *ctx, v8::Local wrapped_object) /* {{{ */ +{ + v8::Local result; + V8JS_CTX_PROLOGUE_EX(ctx, result); + + assert(!wrapped_object.IsEmpty()); + assert(wrapped_object->IsObject()); + + v8::TryCatch try_catch; + v8::Local source = v8::String::NewFromUtf8(ctx->isolate, "(\ +function(wrapped_object) { \ + return (function*() { \ + for(;;) { \ + if(!wrapped_object.valid()) { \ + return; \ + } \ + yield wrapped_object.current(); \ + wrapped_object.next(); \ + } \ + })(); \ +})"); + v8::Local script = v8::Script::Compile(source); + + if(script.IsEmpty()) { + zend_error(E_ERROR, "Failed to compile Generator object wrapper"); + return result; + } + + v8::Local wrapper_fn_val = script->Run(); + + if(wrapper_fn_val.IsEmpty() || !wrapper_fn_val->IsFunction()) { + zend_error(E_ERROR, "Failed to create Generator object wrapper function"); + return result; + } + + v8::Local wrapper_fn = v8::Local::Cast(wrapper_fn_val); + v8::Local *jsArgv = static_cast *>(alloca(sizeof(v8::Local))); + + new(&jsArgv[0]) v8::Local; + jsArgv[0] = v8::Local::New(isolate, wrapped_object); + + result = wrapper_fn->Call(V8JS_GLOBAL(isolate), 1, jsArgv); + return result; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/v8js_generator_export.h b/v8js_generator_export.h new file mode 100644 index 0000000..13e6d09 --- /dev/null +++ b/v8js_generator_export.h @@ -0,0 +1,28 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 2016 The PHP Group | + +----------------------------------------------------------------------+ + | http://www.opensource.org/licenses/mit-license.php MIT License | + +----------------------------------------------------------------------+ + | Author: Stefan Siegl | + +----------------------------------------------------------------------+ +*/ + +#ifndef V8JS_GENERATOR_EXPORT_H +#define V8JS_GENERATOR_EXPORT_H + +v8::Local v8js_wrap_generator(v8js_ctx *ctx, v8::Local wrapped_object); + +#endif /* V8JS_GENERATOR_EXPORT_H */ + +/* + * Local variables: + * mode: c++ + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/v8js_object_export.cc b/v8js_object_export.cc index c34e82b..b21dc91 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -17,6 +17,7 @@ #include "php_v8js_macros.h" #include "v8js_array_access.h" +#include "v8js_generator_export.h" #include "v8js_object_export.h" #include "v8js_v8object_class.h" @@ -26,6 +27,7 @@ extern "C" { #include "zend_interfaces.h" #include "zend_closures.h" #include "zend_exceptions.h" +#include "zend_generators.h" } static void v8js_weak_object_callback(const v8::WeakCallbackData &data); @@ -955,7 +957,16 @@ v8::Handle v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRML /* If it's a PHP object, wrap it */ if (ce) { - return v8js_wrap_object(isolate, ce, value TSRMLS_CC); + v8::Local wrapped_object = v8js_wrap_object(isolate, ce, value TSRMLS_CC); + + if (ce == zend_ce_generator) { + /* Wrap PHP Generator object in a wrapper function that provides + * ES6 style behaviour. */ + v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0); + wrapped_object = v8js_wrap_generator(ctx, wrapped_object); + } + + return wrapped_object; } /* Associative PHP arrays cannot be wrapped to JS arrays, convert them to