Lots of fixes for JS bindings

This commit is contained in:
Felipe Magno de Almeida 2014-12-05 17:43:45 -02:00
parent 8b3f57f9ea
commit 3cd6638e0b
13 changed files with 241 additions and 56 deletions

View File

@ -163,6 +163,12 @@ pc/eet-cxx.pc \
pc/eo-cxx.pc
endif
if HAVE_JS
pkgconfig_DATA += \
pc/eolian-js.pc \
pc/eo-js.pc
endif
if BUILD_ENGINE_SOFTWARE_X11
pkgconfig_DATA += pc/evas-software-x11.pc
endif

View File

@ -999,6 +999,11 @@ EFL_EVAL_PKGS([EINA_CXX])
EFL_LIB_END([Eina_Cxx])
#### End of Eina CXX
AC_ARG_ENABLE([js-bindings],
[AS_HELP_STRING([--enable-js-bindings],[enable JavaScript bindings. @<:@default=disabled@:>@])],
[want_js="${enableval}"], [want_js="no"])
AM_CONDITIONAL([HAVE_JS], [test "x${want_js}" = "xyes"])
#### Eina JS
EFL_LIB_START([Eina_Js])
@ -4577,6 +4582,7 @@ pc/eo-cxx.pc
pc/eolian.pc
pc/eolian-cxx.pc
pc/eolian-js.pc
pc/eo-js.pc
pc/efl.pc
pc/efl-cxx.pc
pc/evas-fb.pc

15
pc/eo-js.pc.in Normal file
View File

@ -0,0 +1,15 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
datarootdir=@datarootdir@
datadir=@datadir@
eoincludedir=@datadir@/eolian/include
eolian_flags=-I${eoincludedir}/eo-@VMAJ@
Name: Eo JavaScript
Description: JavaScript C++ helpers for bindings for EFL's generic object system.
Version: @PACKAGE_VERSION@
Requires.private: @requirements_pc_eo@
Libs.private: @requirements_libs_eo@
Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eo-@VMAJ@ -I${includedir}/eo-js-@VMAJ@

View File

@ -5,7 +5,7 @@ includedir=@includedir@
datarootdir=@datarootdir@
datadir=@datadir@
Name: Eolian++
Name: Eolian-JS
Description: EFL's JavaScript bindings generator.
Version: @VERSION@
Require.private: @requirements_pc_eolian@

View File

@ -13,4 +13,4 @@ Requires.private: @requirements_pc_evas@
Version: @VERSION@
Libs: -L${libdir} -levas
Libs.private: @requirements_libs_evas@
Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/evas-@VMAJ@
Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/evas-@VMAJ@ -I${includedir}/evas-@VMAJ@/canvas

View File

@ -14,6 +14,7 @@ bindings/eina_cxx/eina_clone_allocators.hh \
bindings/eina_cxx/eina_error.hh \
bindings/eina_cxx/eina_eo_base_fwd.hh \
bindings/eina_cxx/eina_fold.hh \
bindings/eina_cxx/eina_function.hh \
bindings/eina_cxx/eina_inarray.hh \
bindings/eina_cxx/eina_inlist.hh \
bindings/eina_cxx/eina_integer_sequence.hh \
@ -21,6 +22,7 @@ bindings/eina_cxx/eina_iterator.hh \
bindings/eina_cxx/eina_lists_auxiliary.hh \
bindings/eina_cxx/eina_list.hh \
bindings/eina_cxx/eina_log.hh \
bindings/eina_cxx/eina_logical.hh \
bindings/eina_cxx/eina_optional.hh \
bindings/eina_cxx/eina_ptrarray.hh \
bindings/eina_cxx/eina_ptrlist.hh \
@ -30,6 +32,7 @@ bindings/eina_cxx/eina_stringshare.hh \
bindings/eina_cxx/eina_thread.hh \
bindings/eina_cxx/eina_throw.hh \
bindings/eina_cxx/eina_tuple.hh \
bindings/eina_cxx/eina_tuple_c.hh \
bindings/eina_cxx/eina_tuple_unwrap.hh \
bindings/eina_cxx/eina_type_traits.hh \
bindings/eina_cxx/eina_value.hh

View File

@ -4,7 +4,12 @@
if HAVE_CXX11
installed_eojsmainheadersdir = $(includedir)/eo-js-@VMAJ@
dist_installed_eojsmainheaders_DATA = \
bindings/eo_js/eo_js_constructor.hh
bindings/eo_js/eo_js_call_function.hh \
bindings/eo_js/eo_js_constructor.hh \
bindings/eo_js/eo_js_direction.hh \
bindings/eo_js/eo_js_get_value_from_c.hh \
bindings/eo_js/eo_js_get_value.hh \
bindings/eo_js/Eo_Js.hh
### Unit tests

View File

@ -26,7 +26,7 @@ lib_eolian_js_libeolian_js_la_SOURCES =\
bindings/eolian_js/main.cc \
$(generated_evas_canvas_js_bindings)
lib_eolian_js_libeolian_js_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
lib_eolian_js_libeolian_js_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_builddir)/src/lib/efl/interfaces \
@EINA_CFLAGS@ @EINA_CXX_CFLAGS@ @EO_JS_CFLAGS@ @EO_CFLAGS@ @EVAS_CFLAGS@ @ECORE_CFLAGS@ @ECORE_EVAS_CFLAGS@ @EINA_CFLAGS@ \
-I$(top_builddir)/src/lib/evas/canvas \
-DPACKAGE_BIN_DIR=\"$(bindir)\" \

View File

@ -1,6 +1,10 @@
#ifndef EOLIAN_KLASS_HH
#define EOLIAN_KLASS_HH
#include <Eina.hh>
#include <eolian/js/domain.hh>
#include <ostream>
inline std::string name(Eolian_Class const* klass)
@ -35,37 +39,54 @@ inline void print_lower_case_namespace(Eolian_Class const* klass, std::ostream&
inline void print_eo_class(Eolian_Class const* klass, std::ostream& os)
{
auto toupper = [] (unsigned char c) { return std::toupper(c); };
assert(klass != 0);
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "print_eo_class";
auto toupper = [] (unsigned char c) { return std::toupper(c); };
std::vector<std::string> namespace_;
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "print_eo_class";
std::vector<std::string> namespace_;
for(efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass))
, last; first != last; ++first)
namespace_.push_back(&*first);
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "namespace";
namespace_.push_back(name(klass));
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "class";
switch(eolian_class_type_get(klass))
{
case EOLIAN_CLASS_REGULAR:
case EOLIAN_CLASS_ABSTRACT:
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
namespace_.push_back("CLASS");
break;
case EOLIAN_CLASS_INTERFACE:
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
namespace_.push_back("INTERFACE");
break;
case EOLIAN_CLASS_MIXIN:
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
namespace_.push_back("MIXIN");
break;
default:
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "default ?";
std::abort();
}
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
for(auto first = namespace_.begin(), last = namespace_.end()
; first != last; ++first)
{
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
std::string upper(*first);
std::transform(upper.begin(), upper.end(), upper.begin(), toupper);
os << upper;
if(std::next(first) != last) os << "_";
}
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "";
}
inline bool is_evas(Eolian_Class const* klass)
{
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "is_evas";
efl::eina::iterator<const char> first (::eolian_class_namespaces_get(klass));
return first != efl::eina::iterator<const char>()
&& std::strcmp(&*first, "Evas") == 0;

View File

@ -3,6 +3,6 @@
namespace eolian { namespace js {
efl::eina::log_domain domain("eolian_cxx");
extern efl::eina::log_domain domain;
} }

View File

@ -17,6 +17,11 @@
#include <cstdlib>
#include <vector>
namespace eolian { namespace js {
efl::eina::log_domain domain("eina_cxx");
} }
int main(int argc, char** argv)
{
@ -116,31 +121,43 @@ int main(int argc, char** argv)
for(; first != last; ++first)
{
Eolian_Function const* function = &*first;
std::cout << "function " << ::eolian_function_full_c_name_get(function) << std::endl;
if( ::eolian_function_is_constructor(function, klass))
// constructor_functions.push_back(function);
;
else
normal_functions.push_back(function);
if(eolian_function_scope_get(function) == EOLIAN_SCOPE_PUBLIC)
{
std::cout << "function " << ::eolian_function_full_c_name_get(function) << std::endl;
if( ::eolian_function_is_constructor(function, klass))
{
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "is a constructor";
constructor_functions.push_back(function);
}
else
{
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "is a NOT constructor";
normal_functions.push_back(function);
}
}
}
};
separate_functions(klass, EOLIAN_METHOD);
separate_functions(klass, EOLIAN_PROPERTY);
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "functions were separated";
std::function<void(Eolian_Class const*)> recurse_inherits
= [&] (Eolian_Class const* klass)
{
for(efl::eina::iterator<const char> first ( ::eolian_class_inherits_get(klass))
, last; first != last; ++first)
{
std::cout << "base " << &*first << std::endl;
Eolian_Class const* base = ::eolian_class_get_by_name(&*first);
separate_functions(base, EOLIAN_METHOD);
separate_functions(base, EOLIAN_PROPERTY);
recurse_inherits(base);
}
for(efl::eina::iterator<const char> first ( ::eolian_class_inherits_get(klass))
, last; first != last; ++first)
{
std::cout << "base " << &*first << std::endl;
Eolian_Class const* base = ::eolian_class_get_by_name(&*first);
separate_functions(base, EOLIAN_METHOD);
separate_functions(base, EOLIAN_PROPERTY);
recurse_inherits(base);
}
};
recurse_inherits(klass);
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "inherits were recursed";
std::ofstream os (out_file.c_str());
if(!os.is_open())
@ -149,40 +166,83 @@ int main(int argc, char** argv)
return -1;
}
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "output was opened";
std::string class_name (name(klass)), upper_case_class_name(class_name)
, lower_case_class_name(class_name);
std::transform(upper_case_class_name.begin(), upper_case_class_name.end(), upper_case_class_name.begin()
, [] (unsigned char c) { return std::toupper(c); });
std::transform(lower_case_class_name.begin(), lower_case_class_name.end(), lower_case_class_name.begin()
, [] (unsigned char c) { return std::tolower(c); });
os << "#ifndef EFL_GENERATED_EOLIAN_CLASS_GUARD_" << upper_case_class_name << "_H\n";
os << "#define EFL_GENERATED_EOLIAN_CLASS_GUARD_" << upper_case_class_name << "_H\n\n";
if (getenv("EFL_RUN_IN_TREE"))
{
os << "#ifdef HAVE_CONFIG_H\n";
os << "#include \"config.h\"\n";
os << "#endif\n";
os << "extern \"C\"\n";
os << "{\n";
os << "#include <Efl.h>\n";
os << "}\n";
os << "#include <Eo.h>\n\n";
}
else
{
os << "#ifdef HAVE_CONFIG_H\n";
os << "#include \"elementary_config.h\"\n";
os << "#endif\n";
os << "extern \"C\"\n";
os << "{\n";
os << "#include <Efl.h>\n";
os << "}\n";
os << "#include <Eo.h>\n\n";
os << "#include <Evas.h>\n\n";
os << "#include <Edje.h>\n\n";
os << "#ifdef HAVE_CONFIG_H\n";
os << "#include \"config.h\"\n";
os << "#endif\n";
os << "extern \"C\"\n";
os << "{\n";
os << "#include <Efl.h>\n";
os << "}\n";
os << "#include <Elementary.h>\n\n";
os << "extern \"C\" {\n";
os << "#include <elm_widget.h>\n";
os << "}\n\n";
}
os << "#include <Eo_Js.hh>\n\n";
os << "#include <Eo.h>\n\n";
os << "#include <node/v8.h>\n\n";
os << "extern \"C\" {\n";
if(is_evas(klass))
os << "#include <Evas.h>\n";
std::function<void(Eolian_Class const*)> recurse_inherits_includes
= [&] (Eolian_Class const* klass)
{
for(efl::eina::iterator<const char> first ( ::eolian_class_inherits_get(klass))
, last; first != last; ++first)
{
std::cout << "base " << &*first << std::endl;
Eolian_Class const* base = ::eolian_class_get_by_name(&*first);
os << "#include <" << eolian_class_file_get(base) << ".h>\n\n";
recurse_inherits_includes(base);
}
};
recurse_inherits_includes(klass);
os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n";
os << "}\n";
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "includes added";
if(namespace_size(klass))
{
os << "namespace ";
print_lower_case_namespace(klass, os);
os << " {\n";
}
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "namespace";
os << "EAPI void register_" << lower_case_class_name
<< "(v8::Handle<v8::Object> global, v8::Isolate* isolate)\n";
@ -191,8 +251,13 @@ int main(int argc, char** argv)
os << " (/*isolate,*/ efl::eo::js::constructor\n"
<< " , efl::eo::js::constructor_data(isolate\n"
" , ";
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "before print eo_class";
print_eo_class(klass, os);
EINA_CXX_DOM_LOG_ERR(eolian::js::domain) << "print eo_class";
for(auto function : constructor_functions)
{
os << "\n , & ::"
@ -315,5 +380,4 @@ int main(int argc, char** argv)
for(std::size_t i = 0, j = namespace_size(klass); i != j; ++i)
os << "}";
os << "\n";
os << "\n#endif\n\n";
}

View File

@ -63,7 +63,7 @@ inline v8::Handle<v8::Value> constructor(v8::Arguments const& args)
}
#endif
//template <typename...F>
template <typename...F>
struct constructor_caller
{
struct call
@ -71,11 +71,13 @@ struct constructor_caller
template <typename T>
void operator()(T function) const
{
std::cout << "function called " << __func__ << std::endl;
std::cout << "function called call " << __func__ << std::endl;
int const parameters
= std::tuple_size<typename eina::_mpl::function_params<T>::type>::value;
if(*current + parameters <= args->Length())
{
std::cout << "calling " << typeid(function).name() << " with " << parameters
<< " parameters" << std::endl;
aux(function, eina::make_index_sequence<parameters>());
*current += parameters;
}
@ -147,7 +149,7 @@ struct constructor_caller
Eo* eo = eo_add
(klass
, NULL
// , eina::_mpl::for_each(constructors, call{&current_index, &args})
, eina::_mpl::for_each(constructors, call{&current_index, &args})
);
assert(eo != 0);
v8::Local<v8::Object> self = args.This();
@ -159,7 +161,7 @@ struct constructor_caller
#endif
Eo_Class const* klass;
//std::tuple<F...> constructors;
std::tuple<F...> constructors;
};
#if 0
@ -173,28 +175,26 @@ v8::Handle<v8::Value> constructor_data(v8::Isolate* isolate, Eo_Class const* kla
);
}
#else
template <typename T> void foo(T const&);
//template <typename... F>
inline
v8::Handle<v8::Value> constructor_data(v8::Isolate* isolate, Eo_Class const* klass/*, F... f*/)
template <typename... F>
v8::Handle<v8::Value> constructor_data(v8::Isolate* isolate, Eo_Class const* klass, F... f)
{
fprintf(stderr, "function called %s\n", __func__); fflush(stderr);
std::cerr << "function called " << __func__ << std::endl;
return v8::External::New
(new std::function<v8::Handle<v8::Value>(v8::Arguments const&)>
(constructor_caller/*<F...>*/{klass/*, std::tuple<F...>{f...}*/}));
}
inline
/*v8::Handle<v8::Value>*/void constructor_data1(v8::Isolate* isolate, Eo_Class const* klass/*, F... f*/)
{
fprintf(stderr, "function called %s\n", __func__); fflush(stderr);
std::cerr << "function called " << __func__ << std::endl;
// return v8::External::New
// new std::function<v8::Handle<v8::Value>(v8::Arguments const&)>(
std::function<v8::Handle<v8::Value>(v8::Arguments const&)>
((constructor_caller/*<F...>*/{nullptr/*klass/*, std::tuple<F...>{f...}*/}));
// return v8::Handle<v8::Value>();
(constructor_caller<F...>{klass, std::tuple<F...>{f...}}));
}
// inline
// /*v8::Handle<v8::Value>*/void constructor_data1(v8::Isolate* isolate, Eo_Class const* klass/*, F... f*/)
// {
// fprintf(stderr, "function called %s\n", __func__); fflush(stderr);
// std::cerr << "function called " << __func__ << std::endl;
// return v8::External::New
// new std::function<v8::Handle<v8::Value>(v8::Arguments const&)>(
// std::function<v8::Handle<v8::Value>(v8::Arguments const&)>
// ((constructor_caller/*<F...>*/{klass, std::tuple<F...>{f...}}));
// return v8::Handle<v8::Value>();
// }
#endif
} } }

View File

@ -9,6 +9,8 @@
#include <type_traits>
#include <cstdlib>
#include <iostream>
#include <typeinfo>
namespace efl { namespace eo { namespace js {
@ -23,7 +25,7 @@ inline int get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* isolate
, value_tag<T>
, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, Eina_Bool>::value>::type* = 0)
, typename std::enable_if<(std::is_integral<T>::value && !std::is_same<T, Eina_Bool>::value)>::type* = 0)
{
if(v->IsInt32())
return v->Int32Value();
@ -44,9 +46,69 @@ inline int get_value_from_javascript
return 0;
}
inline int get_value_from_javascript
inline char* get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* /*isolate*/
, value_tag<char*>)
{
if(v->IsString())
{
v8::String::Utf8Value str(v->ToString());
std::cerr << "String " << *str << std::endl;
return const_cast<char*>(*str);
}
else
{
#if 0
isolate->
#else
v8::
#endif
ThrowException
(v8::Exception::TypeError(v8::String::New/*FromUtf8*/(/*isolate,*/ "Type expected is different. Expected Integral type")));
throw std::logic_error("");
}
return 0;
}
inline const char* get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* isolate
, value_tag<const char*>)
{
return get_value_from_javascript(v, isolate, value_tag<char*>());
}
template <typename T>
inline T get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* /*isolate*/
, value_tag<T>
, typename std::enable_if<std::is_enum<T>::value>::type* = 0)
{
if(v->IsInt32())
return static_cast<T>(v->Int32Value());
else if(v->IsUint32())
return static_cast<T>(v->Uint32Value());
else
{
#if 0
isolate->
#else
v8::
#endif
ThrowException
(v8::Exception::TypeError(v8::String::New/*FromUtf8*/(/*isolate,*/ "Type expected is different. Expected Integral type")));
throw std::logic_error("");
}
return T();
}
inline int get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* /*isolate*/
, value_tag<Eina_Bool>)
{
if(v->IsBoolean() || v->IsBooleanObject())
@ -87,11 +149,14 @@ inline double get_value_from_javascript
throw std::logic_error("");
}
}
template <typename T>
inline T get_value_from_javascript
(v8::Local<v8::Value>, v8::Isolate*, value_tag<T>
, typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value>::type* = 0)
, typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value
&& !std::is_enum<T>::value>::type* = 0)
{
std::cerr << "Trying to convert to " << typeid(T).name() << " to call a C function" << std::endl;
std::abort();
}