// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved // Please see LICENSE.md in repository root for license information // https://github.com/AtomicGameEngine/AtomicGameEngine #include #include #include #include #include #include "JSBind.h" #include "JSBModule.h" #include "JSBindings.h" #include "JSBClass.h" #include "JSBTypeScript.h" #include "JSBDoc.h" JSBindings* JSBindings::instance_ = NULL; void JSBindings::ParseHeaders() { for (unsigned i = 0; i < modules_.Size(); i++) { modules_[i]->ParseHeaders(); } for (unsigned i = 0; i < modules_.Size(); i++) { modules_[i]->PreprocessHeaders(); } for (unsigned i = 0; i < modules_.Size(); i++) { modules_[i]->VisitHeaders(); } JSBClass::Preprocess(); JSBClass::Process(); String modulesFolder = "Build/Source/Generated/" + JSBind::PLATFORM + "/Javascript/Modules"; String outputFolder = JSBind::ROOT_FOLDER + "/" + modulesFolder; if (!JSBind::fileSystem_->CreateDirs(JSBind::ROOT_FOLDER, modulesFolder) || !JSBind::fileSystem_->DirExists(outputFolder)) { String error = "Unable to create bindings output folder: " + outputFolder; ErrorExit(error.CString()); } EmitJSModules(outputFolder); if (JSBind::PLATFORM == "MACOSX") { JSBTypeScript* ts = new JSBTypeScript(); ts->Emit(JSBind::ROOT_FOLDER + "/Bin/Atomic.d.ts"); JSBDoc* jsdoc = new JSBDoc(); jsdoc->Emit(JSBind::ROOT_FOLDER + "/Bin/Atomic.js"); } } void JSBindings::EmitJSModules(const String& rootpath) { File file(JSBind::context_); file.Open(rootpath + "/JSModules.cpp", FILE_WRITE); String source = "// This file was autogenerated by JSBind, changes will be lost\n\n"; source += "#include \n"; source += "#include \n"; source += "#include \n"; source += "\n\nnamespace Atomic\n{\n"; for (unsigned i = 0; i < modules_.Size(); i++) { JSBModule* module = modules_.At(i); source.AppendWithFormat("\nextern void jsb_preinit_%s (JSVM* vm);", module->name_.ToLower().CString()); source.AppendWithFormat("\nextern void jsb_init_%s (JSVM* vm);", module->name_.ToLower().CString()); } source += "\n\nstatic void jsb_modules_setup_prototypes(JSVM* vm)\n{\n"; source += " // It is important that these are in order so the prototypes are created properly\n"; source += " // This isn't trivial as modules can have dependencies, so do it here\n\n"; JSBClass::WriteProtoTypeSetup(source); source += "\n}\n"; source += "\n\nvoid jsb_modules_preinit(JSVM* vm)\n{"; for (unsigned i = 0; i < modules_.Size(); i++) { JSBModule* module = modules_.At(i); if (module->Requires("3D")) source += "\n#ifdef ATOMIC_3D"; source.AppendWithFormat("\n jsb_preinit_%s(vm);", module->name_.ToLower().CString()); if (module->Requires("3D")) source += "\n#endif //ATOMIC_3D\n"; } source += "\n}\n\n"; source += "\n\nvoid jsb_modules_init(JSVM* vm)\n{"; source += "\n\n jsb_modules_preinit(vm);\n"; source += "\n\n jsb_modules_setup_prototypes(vm);\n"; for (unsigned i = 0; i < modules_.Size(); i++) { JSBModule* module = modules_.At(i); if (module->Requires("3D")) source += "\n#ifdef ATOMIC_3D"; source.AppendWithFormat("\n jsb_init_%s(vm);", module->name_.ToLower().CString()); if (module->Requires("3D")) source += "\n#endif //ATOMIC_3D\n"; } source += "\n}\n\n"; // end Atomic namespace source += "\n}\n"; file.Write(source.CString(), source.Length()); file.Close(); for (unsigned i = 0; i < modules_.Size(); i++) { String filepath = rootpath + "/JSModule" + modules_.At(i)->name_ + ".cpp"; modules_.At(i)->EmitSource(filepath); } } void JSBindings::RegisterEnum(JSBEnum* jenum) { if (enums_.Contains(jenum->name_)) { LOGERRORF("Enum name collision: %s", jenum->name_.CString()); ErrorExit(); } for (unsigned i = 0; i < jenum->values_.Size(); i++) { if (enumNames_.Contains(jenum->values_[i])) { LOGERRORF("Enum value collision: %s", jenum->values_[i].CString()); ErrorExit(); } else enumNames_[jenum->values_[i]] = jenum->values_[i]; } enums_[jenum->name_] = jenum; } void JSBindings::RegisterClass(const String &classname, const String &_rename) { String rename = _rename; if (!rename.Length()) rename = classname; if (classes_.Contains(rename)) { LOGERRORF("Class name collision: %s", classname.CString()); ErrorExit(); } classes_[classname] = new JSBClass(rename, classname); } void JSBindings::Initialize() { ResourceCache* cache = JSBind::context_->GetSubsystem(); JSONFile* jsonFile = cache->GetResource("modules/Modules.json"); JSONValue json = jsonFile->GetRoot(); JSONValue modules = json.GetChild("modules"); List moduleExclusions; if (JSBind::PLATFORM == "WEB") { JSONValue jmodulesExclude = json.GetChild("moduleExclude"); JSONValue jexcludes = jmodulesExclude.GetChild("WEB"); for (unsigned i = 0; i < jexcludes.GetSize(); i++) { moduleExclusions.Push(jexcludes.GetString(i)); } } for (unsigned i = 0; i < modules.GetSize(); i++) { if (moduleExclusions.Contains(modules.GetString(i))) continue; String moduleName = "modules/" + modules.GetString(i) + ".json"; JSBModule* jsbModule = new JSBModule(this); jsbModule->Load(moduleName); modules_.Push(jsbModule); } } JSBModule* JSBindings::GetModuleByName(const String& name) { for (unsigned i = 0; i < modules_.Size(); i++) if (modules_[i]->name_ == name) return modules_[i]; return NULL; }