| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- //
- // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #pragma once
- #include <Atomic/IO/Log.h>
- #include <Atomic/Core/ProcessUtils.h>
- using namespace Atomic;
- #include "JSBHeader.h"
- #include "JSBModule.h"
- #include "JSBClass.h"
- #include "JSBPackage.h"
- #include "JSBFunction.h"
- #include "JSBNameVisitor.h"
- namespace ToolCore
- {
- class JSBHeader;
- class JSBPrimitiveType;
- class JSBHeaderVisitor : public SymbolVisitor
- {
- JSBHeader* header_;
- JSBModule* module_;
- TranslationUnit* unit_;
- Namespace* globalNamespace_;
- public:
- JSBHeaderVisitor(JSBHeader* header, TranslationUnit *unit, Namespace* globalNamespace) :
- header_(header),
- unit_(unit),
- globalNamespace_(globalNamespace)
- {
- module_ = header_->GetModule();
- accept(globalNamespace_);
- }
- String getNameString(const Name* name)
- {
- JSBNameVisitor nvisitor;
- return nvisitor(name);
- }
- JSBType* processTypeConversion(Type* type, FullySpecifiedType fst)
- {
- JSBType* jtype = NULL;
- if (type->isIntegerType())
- {
- IntegerType* itype = type->asIntegerType();
- jtype = new JSBPrimitiveType(itype->kind());
- }
- else if (type->isFloatType())
- {
- jtype = new JSBPrimitiveType(JSBPrimitiveType::Float);
- }
- else if (type->isNamedType())
- {
- NamedType* ntype = type->asNamedType();
- String classname = getNameString(ntype->name());
- if (classname.StartsWith("Atomic::"))
- classname.Replace("Atomic::", "");
- if (classname == "VariantVector")
- {
- JSBClass* jclass = JSBPackage::GetClassAllPackages("ScriptVariant");
- assert(jclass);
- jtype = new JSBVectorType(new JSBClassType(jclass), false, true);
- }
- else if (classname == "Vector" || classname == "PODVector")
- {
- PODVector<TemplateType> types;
- unwrapTemplateType(fst, types);
- if (types.Size() == 2)
- {
- JSBType* vtype = processTypeConversion((Type*) types[1].type_, types[1].fstype_);
- if (vtype)
- {
- jtype = new JSBVectorType(vtype, classname == "PODVector");
- }
- }
- else if (types.Size() == 3 && ( getNameString(types[1].name_) == "SharedPtr" || getNameString(types[1].name_) == "WeakPtr"))
- {
- JSBType* vtype = processTypeConversion((Type*) types[2].type_, types[2].fstype_);
- if (vtype)
- {
- JSBVectorType* jvtype = new JSBVectorType(vtype, classname == "PODVector");
- if (getNameString(types[1].name_) == "SharedPtr")
- {
- jvtype->vectorTypeIsSharedPtr_ = true;
- }
- else if (getNameString(types[1].name_) == "WeakPtr")
- {
- jvtype->vectorTypeIsWeakPtr_ = true;
- }
- jtype = jvtype;
- }
- }
- }
- else if (classname == "String")
- {
- jtype = new JSBStringType();
- }
- else if (classname == "StringHash")
- {
- jtype = new JSBStringHashType();
- }
- else if (classname == "JS_HEAP_PTR")
- {
- jtype = new JSBHeapPtrType();
- }
- else
- {
- JSBClass* jclass = JSBPackage::GetClassAllPackages(classname, true);
- if (jclass)
- jtype = new JSBClassType(jclass);
- else
- {
- // this might be an enum
- JSBEnum* jenum = JSBPackage::GetEnumAllPackages(classname);
- if (jenum)
- jtype = new JSBEnumType(jenum);
- }
- }
- }
- else if (type->asUndefinedType())
- {
- UndefinedType* utype = type->asUndefinedType();
- //ErrorExit("Undefined type");
- }
- return jtype;
- }
- struct TemplateType
- {
- FullySpecifiedType fstype_;
- bool isPointer_;
- bool isReference_;
- const Name* name_;
- const Type* type_;
- static void Init(TemplateType& ttype)
- {
- ttype.isPointer_ = false;
- ttype.isReference_ = false;
- ttype.name_ = 0;
- ttype.type_ = 0;
- }
- };
- bool unwrapTemplateType(const FullySpecifiedType& fstype, PODVector<TemplateType>& types)
- {
- TemplateType ttype;
- TemplateType::Init(ttype);
- ttype.fstype_ = fstype;
- ttype.type_ = fstype.type();
- if (ttype.type_->isPointerType())
- {
- ttype.isPointer_=true;
- FullySpecifiedType pfst = ttype.type_->asPointerType()->elementType();
- ttype.type_ = pfst.type();
- }
- if (ttype.type_->isReferenceType())
- {
- ttype.isReference_=true;
- FullySpecifiedType pfst = ttype.type_->asReferenceType()->elementType();
- ttype.type_ = pfst.type();
- }
- const NamedType* ntype = ttype.type_->asNamedType();
- if (!ntype)
- return false;
- if (ntype->name()->asTemplateNameId())
- {
- const TemplateNameId* tnid = ntype->name()->asTemplateNameId();
- ttype.name_ = tnid->identifier()->asNameId();
- types.Push(ttype);
- unwrapTemplateType(tnid->templateArgumentAt(0), types);
- return true;
- }
- ttype.name_ = ntype->name();
- types.Push(ttype);
- return false;
- }
- JSBFunctionType* processFunctionType(FullySpecifiedType fst, bool retType = false)
- {
- JSBType* jtype = NULL;
- Type* type = fst.type();
- bool isPointer = false;
- bool isSharedPtr = false;
- bool isReference = false;
- bool isTemplate = false;
- bool isConst = false;
- if (type->isPointerType())
- {
- isPointer=true;
- FullySpecifiedType pfst = type->asPointerType()->elementType();
- type = pfst.type();
- }
- if (type->isReferenceType())
- {
- isReference=true;
- FullySpecifiedType pfst = type->asReferenceType()->elementType();
- type = pfst.type();
- isConst = pfst.isConst();
- }
- if (!isPointer && retType)
- {
- if (type->isNamedType())
- {
- NamedType* ntype = type->asNamedType();
- if (ntype->name()->asTemplateNameId())
- {
- PODVector<TemplateType> types;
- unwrapTemplateType(fst, types);
- String classname = getNameString(types[0].name_);
- // SharedPtr
- if ( classname == "SharedPtr" && types.Size() == 2 )
- {
- type = (Type*) types[1].type_;
- isTemplate = true;
- isSharedPtr = true;
- }
- }
- }
- }
- if (fst.isUnsigned())
- {
- if (type->isUndefinedType())
- {
- // this happens when just using "unsigned" in code
- jtype = new JSBPrimitiveType(JSBPrimitiveType::Int, true);
- }
- }
- if (!jtype)
- {
- jtype = processTypeConversion(type, fst);
- // explicit script string -> StringHash required
- if (jtype && jtype->asStringHashType())
- isReference = false;
- if (fst.isUnsigned() && jtype->asPrimitiveType())
- jtype->asPrimitiveType()->isUnsigned_ = true;
- }
- if (!jtype)
- return NULL;
- bool skip = false;
- // no pointers to prim atm
- if (isPointer || isReference)
- {
- if (jtype->asPrimitiveType())
- skip = true;
- else if (!retType && !isConst && (jtype->asStringType() || jtype->asStringHashType()))
- {
- skip = true;
- }
- if (skip)
- return NULL;
- }
- // We don't support pointers to Vector2/Vector3/etc which are generally out values
- if (isPointer && jtype->asClassType() && jtype->asClassType()->class_->IsNumberArray())
- return NULL;
- JSBFunctionType* ftype = new JSBFunctionType(jtype);
- ftype->isPointer_ = isPointer;
- ftype->isSharedPtr_ = isSharedPtr;
- ftype->isReference_ = isReference;
- ftype->isTemplate_ = isTemplate;
- ftype->isConst_ = isConst;
- return ftype;
- }
- JSBFunctionType* processFunctionArgType(Argument* arg)
- {
- JSBFunctionType* jtype = processFunctionType(arg->type());
- if (!jtype)
- return NULL;
- jtype->name_ = getNameString(arg->name());
- return jtype;
- }
- JSBFunctionType* processFunctionReturnType(Function* function)
- {
- if (!function->hasReturnType())
- {
- return NULL;
- }
- JSBFunctionType* jtype = processFunctionType(function->returnType(), true);
- if (!jtype)
- return NULL;
- return jtype;
- }
- String parseDocString(int commentLine) const
- {
- const char* comment = NULL;
- for (unsigned i = 0; i < unit_->commentCount(); i++)
- {
- const Token &tcomment = unit_->commentAt(i);
- unsigned line;
- unit_->getPosition(tcomment.utf16charsEnd(), &line);
- if (line == commentLine)
- {
- comment = unit_->firstSourceChar() + tcomment.byteOffset;
- break;
- }
- }
- String docString;
- if (comment && strlen(comment) > 3)
- {
- if (comment[0] == '/' && comment[1] == '/' && comment[2] == '/')
- {
- int index = 3;
- while(comment[index] && comment[index] != '\n' && comment[index] != '\r')
- {
- docString += comment[index++];
- }
- }
- if (comment[0] == '/' && comment[1] == '*' && comment[2] == '*')
- {
- int index = 3;
- bool foundStar = false;
- while(comment[index])
- {
- // did we find a star in the last loop?
- if (foundStar)
- {
- // We have a an end of block indicator, let's break
- if (comment[index] == '/' && foundStar)
- break;
- // This is just a star in the comment, not an end of comment indicator. Let's keep it
- docString += '*';
- }
- foundStar = comment[index] == '*';
- if (!foundStar)
- docString += comment[index];
- index++;
- }
- }
- }
- return docString;
- }
- JSBFunction* processFunction(JSBClass* klass, Function* function)
- {
- JSBFunction* jfunction = new JSBFunction(klass);
- // don't ... atm
- if (function->isVariadic())
- return NULL;
- String name = getNameString(function->name());
- jfunction->SetName(name);
- // don't support operators atm
- if (name.StartsWith("operator "))
- return NULL;
- if (name == klass->GetNativeName())
- jfunction->SetConstructor();
- if (name.StartsWith("~"))
- jfunction->SetDestructor();
- if (function->isVirtual())
- jfunction->SetVirtual(true);
- if (function->isStatic())
- jfunction->SetStatic(true);
- // see if we support return type
- if (function->hasReturnType() && !function->returnType().type()->isVoidType())
- {
- JSBFunctionType* returnType = processFunctionReturnType(function);
- if (!returnType)
- return NULL;
- jfunction->SetReturnType(returnType);
- }
- if (function->hasArguments())
- {
- for (unsigned i = 0; i < function->argumentCount(); i++)
- {
- Symbol* symbol = function->argumentAt(i);
- if (symbol->isArgument())
- {
- Argument* arg = symbol->asArgument();
- JSBFunctionType* ftype = processFunctionArgType(arg);
- // TODO: expose interfaces to TS
- if (ftype && ftype->type_->asClassType() && ftype->type_->asClassType()->class_->IsInterface())
- {
- jfunction->SetSkipLanguage(BINDINGLANGUAGE_JAVASCRIPT);
- }
- if (!ftype)
- {
- // if we don't have an initializer, the function cannot be bound
- // as unscriptable type
- if (!arg->hasInitializer())
- return NULL;
- // otherwise, break and the optional args will be ignored
- break;
- }
- if (arg->hasInitializer())
- {
- ftype->initializer_ = arg->initializer()->chars();
- if (arg->initializer()->_quotedString)
- ftype->initializer_ = "\"" + ftype->initializer_ + "\"";
- }
- jfunction->AddParameter(ftype);
- }
- else
- {
- return NULL;
- }
- }
- }
- jfunction->sourceLocation_ = function->sourceLocation();
- jfunction->fileName_ = function->fileName();
- jfunction->sourceLine_ = function->line();
- jfunction->sourceColumn_ = function->column();
- //const Token &token = unit_->tokenAt(function->sourceLocation());
- //const char* source = unit_->firstSourceChar() + token.byteOffset;
- String docString = parseDocString(function->line() - 1);
- if (docString.Length())
- jfunction->SetDocString(docString);
- return jfunction;
- }
- virtual bool visit(Namespace *nspace)
- {
- String name = getNameString(nspace->name());
- // LOGINFOF("Namespace: %s", name.CString());
- return true;
- }
- // reject template types
- virtual bool visit(Template *t)
- {
- return false;
- }
- // enums visited in preprocessor visitor
- virtual bool visit(Enum *penum)
- {
- return false;
- }
- // global var decl or function
- virtual bool visit(Declaration* decl)
- {
- if (decl->isTypedef())
- return true;
- FullySpecifiedType dtype = decl->type();
- Type* type = dtype.type();
- if (type->isNamedType())
- {
- String classname = getNameString(type->asNamedType()->name());
- if ( dtype.isConst() && classname == "String" ) // find a const string
- {
- const StringLiteral* sinit = decl->getInitializer();
- if (sinit)
- {
- if (sinit->chars())
- {
- String svalue = sinit->chars();
- module_->RegisterConstant(getNameString(decl->name()).CString(), svalue, JSBPrimitiveType::Char );
- return true; // tag this constant as a Char type, because there is no String Primitive type
- }
- }
- }
- }
- if (type->isPointerType() || type->isReferenceType())
- return true;
- if (type->asEnumType())
- return true;
- bool _unsigned = false;
- if (dtype.isUnsigned())
- _unsigned = true;
- if (!type->asFloatType() && !type->asIntegerType() && !_unsigned)
- {
- return true;
- }
- String value;
- const StringLiteral* init = decl->getInitializer();
- if (init)
- {
- if (init->chars())
- value = init->chars();
- }
- if (dtype.isConst())
- {
- if (type->isIntegerType() || _unsigned)
- {
- module_->RegisterConstant(getNameString(decl->name()).CString(), value, JSBPrimitiveType::Int, _unsigned);
- }
- else
- {
- module_->RegisterConstant(getNameString(decl->name()).CString(), value, JSBPrimitiveType::Float);
- }
- }
- return true;
- }
- virtual bool visit(Class *klass)
- {
- String name = getNameString(klass->name());
- JSBClass* jclass = module_->GetClass(name, true);
- if (!jclass)
- {
- return false;
- }
- jclass->SetHeader(header_);
- String docString = parseDocString(klass->line() - 1);
- if (docString.Length())
- jclass->SetDocString(docString);
- for (unsigned i = 0; i < klass->baseClassCount(); i++)
- {
- BaseClass* baseclass = klass->baseClassAt(i);
- String baseclassname = getNameString(baseclass->name());
- JSBClass* base = JSBPackage::GetClassAllPackages(baseclassname);
- if (!base)
- {
- JSBClass* interface = JSBPackage::GetClassAllPackages(baseclassname, true);
- if (interface)
- {
- jclass->AddInterface(interface);
- }
- else
- {
- if (!i)
- {
- ATOMIC_LOGINFOF("Warning: %s first baseclass %s not in bindings", name.CString(), baseclassname.CString());
- }
- }
- }
- else
- {
- jclass->SetBaseClass(base);
- }
- }
- for (unsigned i = 0; i < klass->memberCount(); i++)
- {
- Symbol* symbol = klass->memberAt(i);
- Declaration* decl = symbol->asDeclaration();
- // if the function describes the body in the header
- Function* function = symbol->asFunction();
- // otherwise it could be a decl
- if (!function && decl)
- function = decl->type()->asFunctionType();
- if (function)
- {
- if (function->isPureVirtual())
- jclass->SetAbstract();
- // only want public functions
- if (!symbol->isPublic())
- continue;
- JSBFunction* jfunction = processFunction(jclass, function);
- if (jfunction)
- jclass->AddFunction(jfunction);
- }
- }
- // return false so we don't traverse the class members
- return false;
- }
- };
- }
|