00001
00002
00003
00004
00005
00006
00007
00008 #include "v8_generator.h"
00009 #include "be_extern.h"
00010
00011 #include "utl_identifier.h"
00012
00013 using namespace AstTypeClassification;
00014
00015 void v8_generator::gen_includes()
00016 {
00017 be_global->add_include("<v8.h>", BE_GlobalData::STREAM_H);
00018 be_global->add_include("<nan.h>", BE_GlobalData::STREAM_CPP);
00019 }
00020
00021 bool v8_generator::gen_enum(AST_Enum*, UTL_ScopedName*,
00022 const std::vector<AST_EnumVal*>&, const char*)
00023 {
00024 return true;
00025 }
00026
00027 namespace {
00028
00029 std::string getV8Type(AST_Type* type,
00030 AST_PredefinedType::PredefinedType* pt = 0)
00031 {
00032 const Classification cls = classify(type);
00033 if (cls & (CL_ENUM | CL_STRING)) return "String";
00034 if (cls & (CL_STRUCTURE | CL_UNION)) return "Object";
00035 if (cls & (CL_ARRAY | CL_SEQUENCE)) return "Array";
00036 if (cls & CL_PRIMITIVE) {
00037 AST_Type* actual = resolveActualType(type);
00038 AST_PredefinedType* p = AST_PredefinedType::narrow_from_decl(actual);
00039 if (pt) *pt = p->pt();
00040 switch (p->pt()) {
00041 case AST_PredefinedType::PT_char:
00042 case AST_PredefinedType::PT_wchar:
00043 return "String";
00044 case AST_PredefinedType::PT_boolean:
00045 return "Boolean";
00046 case AST_PredefinedType::PT_octet:
00047 case AST_PredefinedType::PT_ushort:
00048 case AST_PredefinedType::PT_short:
00049 case AST_PredefinedType::PT_ulong:
00050 case AST_PredefinedType::PT_long:
00051 return "Integer";
00052 default:
00053 return "Number";
00054 }
00055 }
00056 return "";
00057 }
00058
00059 bool builtInSeq(AST_Type* type)
00060 {
00061 const std::string name = scoped(type->name());
00062 static const char PRE[] = "CORBA::";
00063 if (std::strncmp(name.c_str(), PRE, sizeof(PRE) - 1)) return false;
00064 return name.rfind("Seq") == name.size() - 3;
00065 }
00066
00067 void gen_copyto(const char* tgt, const char* src, AST_Type* type,
00068 const char* prop, std::ostream& strm = be_global->impl_)
00069 {
00070 const Classification cls = classify(type);
00071 AST_PredefinedType::PredefinedType pt = AST_PredefinedType::PT_void;
00072 const std::string v8Type = getV8Type(type, &pt),
00073 propName = std::string(tgt) + "->Set(" + prop + ", ";
00074
00075 if (cls & CL_SCALAR) {
00076 std::string prefix, suffix, postNew;
00077
00078 if (cls & CL_ENUM) {
00079 const std::string underscores =
00080 dds_generator::scoped_helper(type->name(), "_"),
00081 array = "gen_" + underscores + "_names";
00082 prefix = '(' + std::string(src) + " >= sizeof(" + array + ")/sizeof(" +
00083 array + "[0])) ? \"<<invalid>>\" : " + array + "[static_cast<int>(";
00084 suffix = ")]";
00085 postNew = ".ToLocalChecked()";
00086
00087 } else if (cls & CL_STRING) {
00088 if (!std::strstr(src, "()")) {
00089 suffix = ".in()";
00090 }
00091 if (cls & CL_WIDE) {
00092 strm <<
00093 " {\n"
00094 " const size_t len = ACE_OS::strlen(" << src << suffix << ");\n"
00095 " uint16_t* const str = new uint16_t[len + 1];\n"
00096 " for (size_t i = 0; i <= len; ++i) {\n"
00097 " str[i] = " << src << "[i];\n"
00098 " }\n"
00099 " " << propName << "Nan::New(str).ToLocalChecked());\n"
00100 " delete[] str;\n"
00101 " }\n";
00102 return;
00103 }
00104 postNew = ".ToLocalChecked()";
00105
00106 } else if (pt == AST_PredefinedType::PT_char) {
00107 strm <<
00108 " {\n"
00109 " const char str[] = {" << src << ", 0};\n"
00110 " " << propName << "Nan::New(str).ToLocalChecked());\n"
00111 " }\n";
00112 return;
00113
00114 } else if (pt == AST_PredefinedType::PT_wchar) {
00115 strm <<
00116 " {\n"
00117 " const uint16_t str[] = {" << src << ", 0};\n"
00118 " " << propName << "Nan::New(str).ToLocalChecked());\n"
00119 " }\n";
00120 return;
00121
00122 } else if (v8Type == "Number") {
00123 prefix = "static_cast<double>(";
00124 suffix = ")";
00125 }
00126
00127 strm <<
00128 " " << propName << "Nan::New(" << prefix << src << suffix << ")"
00129 << postNew << ");\n";
00130
00131 } else if ((cls & CL_SEQUENCE) && builtInSeq(type)) {
00132 AST_Type* real_type = resolveActualType(type);
00133 AST_Sequence* seq = AST_Sequence::narrow_from_decl(real_type);
00134 AST_Type* elem = seq->base_type();
00135 strm <<
00136 " {\n"
00137 " const v8::Local<v8::Array> seq = Nan::New<v8::Array>(" << src
00138 << ".length());\n"
00139 " for (CORBA::ULong j = 0; j < " << src << ".length(); ++j) {\n";
00140 gen_copyto("seq", (std::string(src) + "[j]").c_str(), elem, "j");
00141 strm <<
00142 " }\n"
00143 " " << propName << "seq" << ");\n"
00144 " }\n";
00145
00146 } else {
00147 strm <<
00148 " " << propName << "copyToV8(" << src << "));\n";
00149 }
00150 }
00151
00152 struct gen_field_copyto {
00153 gen_field_copyto(const char* tgt, const char* src) : tgt_(tgt), src_(src) {}
00154 const std::string tgt_, src_;
00155 void operator()(AST_Field* field) const
00156 {
00157 const std::string fieldName = field->local_name()->get_string(),
00158 source = src_ + '.' + fieldName,
00159 prop = "Nan::New<v8::String>(\"" + fieldName + "\").ToLocalChecked()";
00160 gen_copyto(tgt_.c_str(), source.c_str(),
00161 field->field_type(), prop.c_str());
00162 }
00163 };
00164 }
00165
00166 bool v8_generator::gen_struct(AST_Structure*, UTL_ScopedName* name,
00167 const std::vector<AST_Field*>& fields,
00168 AST_Type::SIZE_TYPE, const char*)
00169 {
00170 gen_includes();
00171 {
00172 NamespaceGuard ng;
00173 const std::string clazz = scoped(name);
00174 {
00175 Function ctv("copyToV8", "v8::Local<v8::Object>");
00176 ctv.addArg("src", "const " + clazz + '&');
00177 ctv.endArgs();
00178 be_global->impl_ <<
00179 " const v8::Local<v8::Object> stru = Nan::New<v8::Object>();\n";
00180 std::for_each(fields.begin(), fields.end(),
00181 gen_field_copyto("stru", "src"));
00182 be_global->impl_ <<
00183 " return stru;\n";
00184 }
00185 }
00186
00187 if (idl_global->is_dcps_type(name)) {
00188 be_global->add_include("dds/DCPS/V8TypeConverter.h",
00189 BE_GlobalData::STREAM_CPP);
00190 ScopedNamespaceGuard cppGuard(name, be_global->impl_);
00191 const std::string lname = name->last_component()->get_string(),
00192 tsv8 = lname + "TypeSupportV8Impl";
00193 be_global->impl_ <<
00194 "class " << tsv8 << "\n"
00195 " : public virtual " << lname << "TypeSupportImpl\n"
00196 " , public virtual OpenDDS::DCPS::V8TypeConverter {\n\n"
00197 " v8::Local<v8::Object> toV8(const void* source) const\n"
00198 " {\n"
00199 " return OpenDDS::DCPS::copyToV8(*static_cast<const " << lname
00200 << "*>(source));\n"
00201 " }\n\n"
00202 "public:\n"
00203 " struct Initializer {\n"
00204 " Initializer()\n"
00205 " {\n"
00206 " " << lname << "TypeSupport_var ts = new " << tsv8 << ";\n"
00207 " ts->register_type(0, \"\");\n"
00208 " }\n"
00209 " };\n"
00210 "};\n\n" <<
00211 tsv8 << "::Initializer init_tsv8_" << lname << ";\n";
00212 }
00213 return true;
00214 }
00215
00216 bool v8_generator::gen_typedef(AST_Typedef*, UTL_ScopedName* name,
00217 AST_Type* type, const char* )
00218 {
00219 gen_includes();
00220 switch (type->node_type()) {
00221 case AST_Decl::NT_sequence: {
00222 NamespaceGuard ng;
00223 AST_Sequence* seq = AST_Sequence::narrow_from_decl(type);
00224 const std::string cxx = scoped(name);
00225 AST_Type* elem = seq->base_type();
00226 {
00227 Function ctv("copyToV8", "v8::Local<v8::Object>");
00228 ctv.addArg("src", "const " + cxx + '&');
00229 ctv.endArgs();
00230 be_global->impl_ <<
00231 " const v8::Local<v8::Array> tgt(Nan::New<v8::Array>(src.length()));\n"
00232 " for (CORBA::ULong i = 0; i < src.length(); ++i) {\n"
00233 " ";
00234 gen_copyto("tgt", "src[i]", elem, "i");
00235 be_global->impl_ <<
00236 " }\n"
00237 " return tgt;\n";
00238 }
00239 break;
00240 }
00241 case AST_Decl::NT_array: {
00242
00243 break;
00244 }
00245 default:
00246 return true;
00247 }
00248 return true;
00249 }
00250
00251 namespace {
00252 std::string branchGen(const std::string& name, AST_Type* type,
00253 const std::string&, std::string&,
00254 const std::string&)
00255 {
00256 const std::string source = "src." + name + "()",
00257 prop = "Nan::New<v8::String>(\"" + name + "\").ToLocalChecked()";
00258 std::ostringstream strm;
00259 strm << " ";
00260 gen_copyto("uni", source.c_str(), type, prop.c_str(), strm);
00261 return strm.str();
00262 }
00263 }
00264
00265 bool v8_generator::gen_union(AST_Union*, UTL_ScopedName* name,
00266 const std::vector<AST_UnionBranch*>& branches,
00267 AST_Type* discriminator, const char* )
00268 {
00269 gen_includes();
00270 NamespaceGuard ng;
00271 const std::string clazz = scoped(name);
00272 {
00273 Function ctv("copyToV8", "v8::Local<v8::Object>");
00274 ctv.addArg("src", "const " + clazz + '&');
00275 ctv.endArgs();
00276 be_global->impl_ <<
00277 " const v8::Local<v8::Object> uni = Nan::New<v8::Object>();\n";
00278 gen_copyto("uni", "src._d()", discriminator, "Nan::New<v8::String>(\"_d\").ToLocalChecked()");
00279 generateSwitchForUnion("src._d()", branchGen, branches, discriminator,
00280 "", "", clazz.c_str(), false, false);
00281 be_global->impl_ <<
00282 " return uni;\n";
00283 }
00284 return true;
00285 }