├── Example ├── Objects.cpp ├── Main.cpp └── Objects.h ├── Src ├── ReflectorData.cpp ├── Parser.h ├── libccrc │ ├── Reflected.cpp │ └── include │ │ └── Reflected.h ├── Generator.h ├── Reflector.h ├── ParserData.h ├── ReflectorData.h ├── Main.cpp ├── ParserData.cpp ├── Generator.cpp ├── Reflector.cpp └── Parser.cpp ├── .gitignore ├── Test ├── Test.cpp └── Test.h ├── .gitmodules ├── generate.bat └── Marefile /Example/Objects.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Objects.h" 3 | 4 | -------------------------------------------------------------------------------- /Src/ReflectorData.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ReflectorData.h" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Build/ 2 | *.sdf 3 | *.sln 4 | *.vcxproj* 5 | *.txt 6 | *.opensdf 7 | *.suo 8 | Ext/libclang -------------------------------------------------------------------------------- /Test/Test.cpp: -------------------------------------------------------------------------------- 1 | 2 | /** some comment for Class0 */ 3 | class Class0 4 | { 5 | /** 6 | some in class comment 7 | */ 8 | }; 9 | 10 | #include "Test.h" 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Ext/mare"] 2 | path = Ext/mare 3 | url = https://github.com/craflin/mare.git 4 | [submodule "Ext/libnstd"] 5 | path = Ext/libnstd 6 | url = https://github.com/craflin/libnstd.git 7 | -------------------------------------------------------------------------------- /generate.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if not exist Build\Debug\mare\mare.exe call Ext\mare\compile.bat --buildDir=Build/Debug/mare --outputDir=Build/Debug/mare --sourceDir=Ext/mare/src 4 | if not "%1"=="" (Build\Debug\mare\mare.exe %*) else Build\Debug\mare\mare.exe --vcxproj=2013 5 | 6 | -------------------------------------------------------------------------------- /Src/Parser.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "ParserData.h" 5 | 6 | class Parser 7 | { 8 | public: 9 | ParserData data; 10 | 11 | public: 12 | Parser(); 13 | ~Parser(); 14 | 15 | bool_t parse(const String& sourceFile, const String& headerFile, const List& additionalArgs); 16 | 17 | private: 18 | class Private; 19 | Private* p; 20 | }; 21 | -------------------------------------------------------------------------------- /Src/libccrc/Reflected.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Reflected.h" 3 | 4 | namespace Reflection 5 | { 6 | extern const Reflected::Type Reflected = {"Reflected"}; 7 | extern const Reflected::Type _intType = {"int"}; 8 | } 9 | /* 10 | bool_t Reflected::invokeMethod(const String& name, Variant& result, ...) 11 | { 12 | const Type& type = getReflectedType(); 13 | //type. 14 | return false; 15 | } 16 | 17 | bool_t Reflected::getPropery(const String& name, Variant& value) 18 | { 19 | return false; 20 | } 21 | 22 | bool_t Reflected::setPropery(const String& name, const Variant& value) 23 | { 24 | return false; 25 | } 26 | */ -------------------------------------------------------------------------------- /Src/Generator.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | struct ReflectorData; 7 | 8 | class Generator 9 | { 10 | public: 11 | bool_t generate(const String& outputFile, const String& headerFile, const ReflectorData& data); 12 | 13 | private: 14 | File file; 15 | 16 | private: 17 | void_t write(const String& str) {file.write(str); } 18 | void_t write() {file.write("\n"); } 19 | 20 | static String getNamespacePrefix(const String& type); 21 | static String getNamespaceSuffix(const String& type); 22 | static String getVarName(const String& type); 23 | static String getFullVarName(const String& type); 24 | static String formatString(const String& str); 25 | static String formatVariant(const Variant& var); 26 | }; 27 | -------------------------------------------------------------------------------- /Src/Reflector.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "ReflectorData.h" 7 | #include "ParserData.h" 8 | 9 | class Reflector 10 | { 11 | public: 12 | ReflectorData data; 13 | 14 | public: 15 | bool_t reflect(const String& headerFile, const ParserData& parserData); 16 | 17 | private: 18 | const ParserData* parserData; 19 | HashMap referencedTypes; 20 | Pool additionalTypes; 21 | 22 | private: 23 | void_t addReferencedType(const String& name); 24 | ReflectorData::Type::ReflectionType getReflectionType(const ParserData::TypeDecl& type); 25 | 26 | static String getTemplateName(const String& type); 27 | static String extractClassDescriptions(const String& comment); 28 | static void_t extractMethodDescriptions(const String& comment, ReflectorData::Type::Method& method); 29 | 30 | static String buildinTypes[]; 31 | }; 32 | -------------------------------------------------------------------------------- /Src/ParserData.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class ParserData 10 | { 11 | public: 12 | struct TypeDecl 13 | { 14 | enum Type 15 | { 16 | enumType, 17 | classType, 18 | structType, 19 | }; 20 | 21 | struct MethodDecl 22 | { 23 | struct Parameter 24 | { 25 | String name; 26 | String type; 27 | Variant value; 28 | }; 29 | 30 | String name; 31 | String type; 32 | String comment; 33 | List parameters; 34 | 35 | public: 36 | void_t print(); 37 | String getReturnType() const; 38 | }; 39 | 40 | String name; 41 | Type type; 42 | String comment; 43 | String file; 44 | HashMap templateParams; 45 | List baseTypes; 46 | List methods; 47 | List innerComments; 48 | 49 | public: 50 | void_t print(); 51 | }; 52 | 53 | public: 54 | void_t print(); 55 | 56 | public: 57 | HashMap declarations; 58 | HashMap templates; 59 | String headerFile; 60 | }; 61 | -------------------------------------------------------------------------------- /Src/ReflectorData.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct ReflectorData 10 | { 11 | public: 12 | struct Type 13 | { 14 | enum ReflectionType 15 | { 16 | interfaceType, 17 | objectType, 18 | referencedType, 19 | buildinType, 20 | }; 21 | 22 | struct Field 23 | { 24 | String name; 25 | int64_t value; 26 | }; 27 | 28 | struct Method 29 | { 30 | struct Parameter 31 | { 32 | Type* type; 33 | String name; 34 | String description; 35 | Variant value; 36 | }; 37 | 38 | String name; 39 | String description; 40 | Type* type; // return type 41 | List parameters; 42 | }; 43 | 44 | struct Property 45 | { 46 | String name; 47 | String description; 48 | Type* type; 49 | String getter; 50 | String setter; 51 | String variable; 52 | }; 53 | 54 | String name; 55 | String description; 56 | List baseTypes; 57 | List methods; 58 | List properties; 59 | bool_t external; 60 | ReflectionType reflectionType; 61 | }; 62 | 63 | HashMap types; 64 | }; 65 | -------------------------------------------------------------------------------- /Test/Test.h: -------------------------------------------------------------------------------- 1 | 2 | /** some comment for Class1 */ 3 | class Class1 4 | { 5 | }; 6 | 7 | 8 | void _invalid_parameter_noinfoxx_test(int a); 9 | 10 | void __cdecl _invalid_parameter_noinfoxx(int a); 11 | 12 | /* 13 | namespace Test 14 | { 15 | 16 | class Reflected 17 | { 18 | }; 19 | 20 | class MetaInfo; 21 | 22 | class MyObject : public Reflected 23 | { 24 | class SubClass 25 | { 26 | }; 27 | 28 | public: // implements Reflected 29 | virtual const MetaInfo& getMetaInfo(); 30 | }; 31 | 32 | }; 33 | 34 | struct A 35 | { 36 | int a; 37 | } a; 38 | */ 39 | 40 | 41 | 42 | namespace X 43 | { 44 | namespace Test 45 | { 46 | class Class2 : public Reflected 47 | { 48 | }; 49 | 50 | /** some comment for Class3 */ 51 | class Class3 : public Class2 52 | { 53 | /** some in class comment */ 54 | 55 | /** some comment for func1 */ 56 | void func1(int); 57 | }; 58 | 59 | struct Struct1 60 | { 61 | }; 62 | 63 | template class TemplateClass1 64 | { 65 | template class SubTemplateClass1 66 | { 67 | }; 68 | }; 69 | 70 | class Class4 71 | { 72 | TemplateClass1 func2(int a); 73 | }; 74 | 75 | enum Enum1 76 | { 77 | XX_a, 78 | XX_b, 79 | }; 80 | }; 81 | }; 82 | 83 | /* 84 | 85 | #include 86 | 87 | class B 88 | { 89 | int a; 90 | }; 91 | 92 | class C : public MyTemplateObject, public B 93 | { 94 | }; 95 | 96 | template class D : public MyTemplateObject 97 | { 98 | }; 99 | */ -------------------------------------------------------------------------------- /Src/libccrc/include/Reflected.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Reflected 7 | { 8 | public: 9 | struct Type 10 | { 11 | struct Method 12 | { 13 | struct Parameter 14 | { 15 | String name; 16 | String description; 17 | const Type* type; 18 | Variant defaultValue; 19 | }; 20 | 21 | String name; 22 | String description; 23 | const Type* type; // return type 24 | const Parameter* parameters; 25 | size_t parametersNum; 26 | 27 | //virtual bool_t invoke(Reflected& reflected, Variant& result, ...) const = 0; 28 | }; 29 | 30 | struct Property 31 | { 32 | String name; 33 | String description; 34 | bool readOnly; 35 | //virtual bool_t set(Reflected& reflected, const Variant& value) const = 0; 36 | //virtual bool_t get(const Reflected& reflected, Variant& value) const = 0; 37 | }; 38 | 39 | String name; 40 | String description; 41 | const Method* methods; 42 | size_t methodsNum; 43 | const Property* properties; 44 | size_t propertiesNum; 45 | const Type* const * baseTypes; 46 | size_t baseTypesNum; 47 | }; 48 | 49 | public: 50 | virtual const Reflected::Type& getReflectedType() const = 0; 51 | 52 | public: 53 | //bool_t invokeMethod(const String& name, Variant& result, ...); 54 | //bool_t getPropery(const String& name, Variant& value); 55 | //bool_t setPropery(const String& name, const Variant& value); 56 | }; 57 | 58 | -------------------------------------------------------------------------------- /Example/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "Objects.h" 5 | 6 | void_t printObjectMethods(const Reflected::Type& type) 7 | { 8 | for(size_t i = 0; i < type.baseTypesNum; ++i) 9 | printObjectMethods(*type.baseTypes[i]); 10 | for(size_t i = 0; i < type.methodsNum; ++i) 11 | { 12 | const Reflected::Type::Method& method = type.methods[i]; 13 | Console::printf("%s %s(", (const tchar_t*)method.type->name, (const tchar_t*)method.name); 14 | for(size_t i = 0; i < method.parametersNum; ++i) 15 | { 16 | if(i != 0) 17 | Console::printf(", "); 18 | const Reflected::Type::Method::Parameter& parameter = method.parameters[i]; 19 | Console::printf("%s %s", (const tchar_t*)parameter.type->name, (const tchar_t*)parameter.name); 20 | if(!parameter.defaultValue.isNull()) 21 | Console::printf(" = %s", (const tchar_t*)parameter.defaultValue.toString()); 22 | } 23 | Console::printf(")\n"); 24 | } 25 | } 26 | 27 | void_t printObject(const Reflected& obj) 28 | { 29 | const Reflected::Type& type = obj.getReflectedType(); 30 | Console::printf("Name: %s\n", (const tchar_t*)type.name); 31 | Console::printf("Description: %s\n", (const tchar_t*)type.description); 32 | Console::printf("BaseTypes: "); 33 | for(size_t i = 0; i < type.baseTypesNum; ++i) 34 | Console::printf("%s, ", (const tchar_t*)type.baseTypes[i]->name); 35 | Console::printf("\n"); 36 | printObjectMethods(type); 37 | 38 | Console::printf("\n"); 39 | } 40 | 41 | int_t main(int_t argc, char_t* argv[]) 42 | { 43 | MyObject1 o1; 44 | SomeSpace1::MyObject2 o2; 45 | SomeSpace2::MyObject3 o3; 46 | SomeSpace2::MyObject4 o4; 47 | 48 | printObject(o1); 49 | printObject(o2); 50 | printObject(o3); 51 | printObject(o4); 52 | 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Example/Objects.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | class MyInterface1 7 | { 8 | public: 9 | enum Enum1 10 | { 11 | field1, 12 | field2 13 | }; 14 | 15 | public: 16 | /** 17 | * @invokable 18 | * Example "function"\ 19 | * @param p0 Some description 20 | */ 21 | virtual int func1(int p0 = 3) = 0; 22 | 23 | /** 24 | * @invokable 25 | * Example function 26 | * @param p0 Some description 27 | */ 28 | virtual Enum1 func2(int p0) = 0; 29 | }; 30 | 31 | /** some comment for MyObject1 */ 32 | class MyObject1 : public Reflected 33 | { 34 | public: 35 | virtual const Reflected::Type& getReflectedType() const; 36 | 37 | public: 38 | /** 39 | * @invokable 40 | * Example function 41 | * @param p0 Some description 42 | */ 43 | int func3(int p0); 44 | }; 45 | 46 | namespace SomeSpace1 47 | { 48 | 49 | class MyObject2 : public MyInterface1, public Reflected 50 | { 51 | public: 52 | virtual const Reflected::Type& getReflectedType() const; 53 | 54 | public: 55 | virtual int func1(int p0) {return 0;} 56 | virtual Enum1 func2(int p0) {return field1;} 57 | 58 | public: 59 | /** 60 | * @invokable 61 | * Example function 62 | * @param p0 Some description 63 | */ 64 | int func4(int p0); 65 | }; 66 | 67 | } 68 | 69 | namespace SomeSpace2 70 | { 71 | using namespace SomeSpace1; 72 | 73 | class MyObject3 : public MyObject1 74 | { 75 | public: 76 | virtual const Reflected::Type& getReflectedType() const; 77 | 78 | public: 79 | /** 80 | * @invokable 81 | * Example function 82 | * @param p0 Some description 83 | */ 84 | int func5(int p0); 85 | }; 86 | 87 | class MyObject4 : public MyObject2 88 | { 89 | public: 90 | virtual const Reflected::Type& getReflectedType() const; 91 | 92 | public: 93 | /** 94 | * @invokable 95 | * Example function 96 | * @param p0 Some description 97 | */ 98 | int func6(int p0); 99 | 100 | int func7(); 101 | 102 | /** 103 | * @invokable 104 | * Example template function 105 | */ 106 | List func8(); 107 | }; 108 | 109 | class MyObject5 : public Reflected 110 | { 111 | public: 112 | virtual const Reflected::Type& getReflectedType() const; 113 | }; 114 | }; 115 | -------------------------------------------------------------------------------- /Marefile: -------------------------------------------------------------------------------- 1 | 2 | buildDir = "Build/$(configuration)/$(target)" 3 | name = "ccrc" 4 | 5 | targets = { 6 | 7 | Example = cppApplication + { 8 | dependencies = { "libnstd", "ccrc", "libccrc" } 9 | includePaths = { 10 | "Ext/libnstd/include" 11 | "Src/libccrc/include" 12 | } 13 | libPaths = { 14 | "$(dir $(buildDir))/libnstd" 15 | "$(dir $(buildDir))/libccrc" 16 | } 17 | libs = { "nstd", "ccrc" } 18 | root = "Example" 19 | objectFiles = "Example/Objects.h" 20 | files = { 21 | "Example/*.cpp" = cppSource 22 | "Example/*.h" 23 | "$(addprefix $(buildDir)/ccrc_,$(addsuffix .cpp,$(basename $(notdir $(objectFiles)))))" = cppSource + { 24 | folder = ".ccrc" 25 | } 26 | "$(objectFiles)" = { 27 | output = "$(buildDir)/ccrc_$(basename $(notdir $(file))).cpp" 28 | command = "$(dir $(outputDir))/ccrc/ccrc $(file) $(basename $(file)).cpp -o $(output) $(addprefix -I,$(includePaths))" 29 | dependencies = "ccrc" 30 | } 31 | } 32 | if tool == "vcxproj" { 33 | linkFlags += { "/SUBSYSTEM:CONSOLE" } 34 | } 35 | if platform == "Linux" { 36 | libs += { "pthread", "rt" } 37 | } 38 | } 39 | 40 | ccrc = cppApplication + { 41 | dependencies = { "libnstd" } 42 | includePaths = { 43 | "Ext/libnstd/include" 44 | "Ext/libclang/include" 45 | } 46 | libPaths = { 47 | "$(dir $(buildDir))/libnstd" 48 | "Ext/libclang/lib" 49 | } 50 | libs = { "nstd", "libclang" } 51 | root = "Src" 52 | files = { 53 | "Src/*.cpp" = cppSource 54 | "Src/*.h" 55 | "Ext/libclang/bin/libclang.dll" = { 56 | output = "$(outputDir)/$(notdir $(file))" 57 | command = "copy $(subst /,\\,$(file)) $(subst /,\\,$(output))" 58 | } 59 | } 60 | if tool == "vcxproj" { 61 | linkFlags += { "/SUBSYSTEM:CONSOLE" } 62 | } 63 | if platform == "Linux" { 64 | libs += { "pthread", "rt" } 65 | } 66 | } 67 | 68 | libccrc = cppStaticLibrary + { 69 | dependencies = { "libnstd" } 70 | includePaths = { 71 | "Ext/libnstd/include" 72 | "Src/libccrc/include" 73 | } 74 | root = { "Src/libccrc", "Src/libccrc/include" } 75 | files = { 76 | "Src/libccrc/*.cpp" = cppSource 77 | "Src/libccrc/include/*.h" 78 | } 79 | } 80 | 81 | include "Ext/libnstd/libnstd.mare" 82 | libnstd += { 83 | folder = "Ext" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Src/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Parser.h" 7 | #include "Reflector.h" 8 | #include "Generator.h" 9 | 10 | void_t usage(char_t* argv[]) 11 | { 12 | Console::errorf("Usage: %s
-o \n", argv[0]); 13 | } 14 | 15 | int_t main(int_t argc, char_t* argv[]) 16 | { 17 | String headerFile; 18 | String sourceFile; 19 | String outputFile; 20 | List additionalArgs; 21 | { 22 | Process::Option options[] = { 23 | {'o', "output", Process::argumentFlag}, 24 | {'h', "help", Process::optionFlag}, 25 | {'I', 0, Process::argumentFlag}, 26 | }; 27 | Process::Arguments arguments(argc, argv, options); 28 | int_t character; 29 | String argument; 30 | while(arguments.read(character, argument)) 31 | switch(character) 32 | { 33 | case 'o': 34 | outputFile = argument; 35 | break; 36 | case 0: 37 | if(headerFile.isEmpty()) 38 | headerFile = argument; 39 | else if(sourceFile.isEmpty()) 40 | sourceFile = argument; 41 | else 42 | return usage(argv), 1; 43 | break; 44 | case 'I': 45 | additionalArgs.append(String("-I") + argument); 46 | break; 47 | case '?': 48 | Console::errorf("Unknown option: %s.\n", (const char_t*)argument); 49 | return 1; 50 | case ':': 51 | Console::errorf("Option %s required an argument.\n", (const char_t*)argument); 52 | return 1; 53 | default: 54 | return usage(argv), 1; 55 | } 56 | } 57 | 58 | if(headerFile.isEmpty() || outputFile.isEmpty()) 59 | return usage(argv), 1; 60 | 61 | // parse input file 62 | Parser parser; 63 | if(!parser.parse(sourceFile, headerFile, additionalArgs)) 64 | return 1; 65 | //parser.data.print(); 66 | 67 | // create type reflection structure 68 | Reflector reflector; 69 | if(!reflector.reflect(headerFile, parser.data)) 70 | return 1; 71 | 72 | // generate output file 73 | Generator generator; 74 | if(!generator.generate(outputFile, headerFile, reflector.data)) 75 | return 1; 76 | 77 | /* 78 | 79 | // find a compiler 80 | String path = Process::getEnvironmentVariable("PATH"); 81 | //List paths; 82 | //path.split(';', paths); 83 | // todo 84 | String compiler = "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\cl.exe"; 85 | Process::setEnvironmentVariable("INCLUDE", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\INCLUDE;C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\shared;C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\um;C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\winrt;"); 86 | 87 | */ 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /Src/ParserData.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "ParserData.h" 5 | 6 | void_t ParserData::print() 7 | { 8 | for(HashMap::Iterator i = declarations.begin(), end = declarations.end(); i != end; ++i) 9 | i->print(); 10 | } 11 | 12 | void_t ParserData::TypeDecl::print() 13 | { 14 | if(!comment.isEmpty()) 15 | Console::printf("%s\n", (const tchar_t*)comment); 16 | String printName; 17 | switch(type) 18 | { 19 | case enumType: 20 | printName.append("enum"); 21 | break; 22 | case classType: 23 | printName.append("class"); 24 | break; 25 | case structType: 26 | printName.append("struct"); 27 | break; 28 | } 29 | printName.append(" - "); 30 | printName.append(name); 31 | if(!templateParams.isEmpty()) 32 | { 33 | printName.append('<'); 34 | for(HashMap::Iterator i = templateParams.begin(), end = templateParams.end();;) 35 | { 36 | printName.append(i.key()); 37 | if(++i == end) 38 | break; 39 | printName.append(", "); 40 | } 41 | printName.append('>'); 42 | } 43 | if(!baseTypes.isEmpty()) 44 | { 45 | printName.append(" : "); 46 | for(List::Iterator i = baseTypes.begin(), end = baseTypes.end();;) 47 | { 48 | printName.append(*i); 49 | if(++i == end) 50 | break; 51 | printName.append(", "); 52 | } 53 | } 54 | Console::printf("%s\n", (const tchar_t*)printName); 55 | for(List::Iterator i = methods.begin(), end = methods.end(); i != end; ++i) 56 | i->print(); 57 | for(List::Iterator i = innerComments.begin(), end = innerComments.end(); i != end; ++i) 58 | Console::printf(" %s\n", (const tchar_t*)*i); 59 | } 60 | 61 | void_t ParserData::TypeDecl::MethodDecl::print() 62 | { 63 | if(!comment.isEmpty()) 64 | Console::printf(" %s\n", (const tchar_t*)comment); 65 | String printName; 66 | printName.append(getReturnType()); 67 | printName.append(' '); 68 | printName.append(name); 69 | printName.append('('); 70 | if(!parameters.isEmpty()) 71 | for(List::Iterator i = parameters.begin(), end = parameters.end();;) 72 | { 73 | printName.append(i->type); 74 | if(!i->name.isEmpty()) 75 | { 76 | printName.append(' '); 77 | printName.append(i->name); 78 | } 79 | if(++i == end) 80 | break; 81 | printName.append(", "); 82 | } 83 | printName.append(')'); 84 | Console::printf(" %s\n", (const tchar_t*)printName); 85 | } 86 | 87 | String ParserData::TypeDecl::MethodDecl::getReturnType() const 88 | { 89 | const char* functionType = type; 90 | const char* p = String::findOneOf(functionType, " <"); 91 | if(!p) 92 | return String(); 93 | if(*p == ' ') 94 | { 95 | String result =String::fromCString(functionType, p - functionType); 96 | if(result == "const") 97 | { 98 | int k = 42; 99 | } 100 | return result; 101 | } 102 | for(size_t depth = 1;;) 103 | { 104 | p = String::findOneOf(p + 1, "<>"); 105 | if(*p == '<') 106 | ++depth; 107 | else if(depth == 1) 108 | return String::fromCString(functionType, p + 1 - functionType); 109 | else 110 | --depth; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Src/Generator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ReflectorData.h" 7 | #include "Generator.h" 8 | 9 | bool_t Generator::generate(const String& outputFile, const String& headerFile, const ReflectorData& data) 10 | { 11 | if(!file.open(outputFile, File::writeFlag)) 12 | return false; 13 | 14 | String outputFileAbs = File::isAbsolutePath(outputFile) ? outputFile : String("/") + outputFile; 15 | String headerFileAbs = File::isAbsolutePath(headerFile) ? headerFile : String("/") + headerFile; 16 | 17 | write(); 18 | write(String("#include \n")); 19 | write(); 20 | write(String("#include \"") + File::getRelativePath(File::dirname(outputFileAbs), headerFileAbs) + "\"\n"); 21 | write(); 22 | write(String("namespace Reflection\n")); 23 | write(String("{\n")); 24 | 25 | for(HashMap::Iterator i = data.types.begin(), end = data.types.end(); i != end; ++i) 26 | { 27 | const ReflectorData::Type& type = *i; 28 | write(String(" ") + getNamespacePrefix(type.name) + "extern const Reflected::Type " + getVarName(type.name) + ";" + getNamespaceSuffix(type.name) + "\n"); 29 | } 30 | write(); 31 | 32 | for(HashMap::Iterator i = data.types.begin(), end = data.types.end(); i != end; ++i) 33 | { 34 | const ReflectorData::Type& type = *i; 35 | if(type.external && type.reflectionType != ReflectorData::Type::referencedType) 36 | continue; 37 | 38 | write(String(" ") + getNamespacePrefix(type.name) + "\n"); 39 | if(!type.baseTypes.isEmpty()) 40 | { 41 | write(String(" const Reflected::Type* _") + getVarName(type.name) + "_BaseTypes[] = {"); 42 | for(List::Iterator i = type.baseTypes.begin(), end = type.baseTypes.end(); i != end; ++i) 43 | write(String("&") + getFullVarName((*i)->name) + ", "); 44 | write(String("};\n")); 45 | } 46 | 47 | for(List::Iterator i = type.methods.begin(), end = type.methods.end(); i != end; ++i) 48 | { 49 | const ReflectorData::Type::Method& method = *i; 50 | if(!method.parameters.isEmpty()) 51 | { 52 | write(String(" const Reflected::Type::Method::Parameter _Method_") + getVarName(type.name) + "_" + method.name + "_Parameters[] = {\n"); 53 | for(List::Iterator i = method.parameters.begin(), end = method.parameters.end(); i != end; ++i) 54 | { 55 | const ReflectorData::Type::Method::Parameter& parameter = *i; 56 | write(String(" {") + formatString(parameter.name) + ", "); 57 | write(formatString(parameter.description) + ", "); 58 | write(String("&") + getFullVarName(parameter.type->name) + ", "); 59 | write(formatVariant(parameter.value) + "},\n"); 60 | } 61 | write(String(" };\n")); 62 | } 63 | } 64 | if(!type.methods.isEmpty()) 65 | { 66 | write(String(" const Reflected::Type::Method _") + getVarName(type.name) + "_Methods[] = {\n"); 67 | for(List::Iterator i = type.methods.begin(), end = type.methods.end(); i != end; ++i) 68 | { 69 | ReflectorData::Type::Method& method = *i; 70 | write(String(" {") + formatString(method.name) + ", "); 71 | write(formatString(method.description) + ", "); 72 | write(String("&") + getFullVarName(method.type->name) + ", "); 73 | if(method.parameters.isEmpty()) 74 | write(String("0, ")); 75 | else 76 | write(String("_Method_") + getVarName(type.name) + "_" + method.name + "_Parameters, "); 77 | write(String::fromUInt64(method.parameters.size()) + "},\n"); 78 | } 79 | write(String(" };\n")); 80 | } 81 | write(String(" extern const Reflected::Type ") + getVarName(type.name) + " = {"); 82 | write(formatString(type.name) + ", "); 83 | write(formatString(type.description) + ", "); 84 | if(type.methods.isEmpty()) 85 | write(String("0, ")); 86 | else 87 | write(String("_") + getVarName(type.name) + "_Methods, "); 88 | write(String::fromUInt64(type.methods.size()) + ", "); 89 | write(String("0, ")); 90 | write(String("0, ")); 91 | if(type.baseTypes.isEmpty()) 92 | write(String("0, ")); 93 | else 94 | write(String("_") + getVarName(type.name) + "_BaseTypes, "); 95 | write(String::fromUInt64(type.baseTypes.size()) + ","); 96 | write(String("};\n")); 97 | write(String(" ") + getNamespaceSuffix(type.name) + "\n"); 98 | } 99 | 100 | write(String("};\n")); 101 | write(); 102 | 103 | for(HashMap::Iterator i = data.types.begin(), end = data.types.end(); i != end; ++i) 104 | { 105 | const ReflectorData::Type& type = *i; 106 | if(type.external || type.reflectionType != type.objectType) 107 | continue; 108 | write(String("const Reflected::Type& ") + type.name + "::getReflectedType() const {return Reflection::" + getFullVarName(type.name) + ";}\n"); 109 | } 110 | return true; 111 | } 112 | 113 | String Generator::getNamespacePrefix(const String& type) 114 | { 115 | String prefix; 116 | const tchar_t* start = type; 117 | const tchar_t* namespaceStart = start; 118 | for(;;) 119 | { 120 | const tchar_t* namespaceEnd = String::find(namespaceStart, "::"); 121 | if(!namespaceEnd) 122 | return prefix; 123 | prefix.append(String("namespace _") + type.substr(namespaceStart - start, namespaceEnd - namespaceStart) + " {"); 124 | namespaceStart = namespaceEnd + 2; 125 | } 126 | } 127 | 128 | String Generator::getNamespaceSuffix(const String& type) 129 | { 130 | String suffix; 131 | const tchar_t* start = type; 132 | const tchar_t* namespaceStart = start; 133 | for(;;) 134 | { 135 | const tchar_t* namespaceEnd = String::find(namespaceStart, "::"); 136 | if(!namespaceEnd) 137 | return suffix; 138 | suffix.append('}'); 139 | namespaceStart = namespaceEnd + 2; 140 | } 141 | } 142 | 143 | String Generator::getVarName(const String& type) 144 | { 145 | const tchar_t* start = type; 146 | const tchar_t* var = String::findLast(start, "::"); 147 | String result = type; 148 | if(var) 149 | result = type.substr(var + 2 - start); 150 | else 151 | { 152 | if(type == "int") 153 | return String("_") + type + "Type"; 154 | } 155 | result.replace("<", "__"); 156 | result.replace(">", "__"); 157 | return result; 158 | } 159 | 160 | String Generator::getFullVarName(const String& type) 161 | { 162 | String prefix; 163 | const tchar_t* start = type; 164 | const tchar_t* namespaceStart = start; 165 | for(;;) 166 | { 167 | const tchar_t* namespaceEnd = String::find(namespaceStart, "::"); 168 | if(!namespaceEnd) 169 | return prefix + getVarName(type); 170 | prefix.append(String("_") + type.substr(namespaceStart - start, namespaceEnd - namespaceStart) + "::"); 171 | namespaceStart = namespaceEnd + 2; 172 | } 173 | } 174 | 175 | String Generator::formatString(const String& str) 176 | { 177 | if(str.isEmpty()) 178 | return "String()"; 179 | String result(str.length() * 2); 180 | result.append('"'); 181 | for(const tchar_t* p = str;;) 182 | { 183 | const tchar_t* end = String::findOneOf(p, "\"\\\r\n"); 184 | if(!end) 185 | { 186 | result.append(String(p, String::length(p))); 187 | break; 188 | } 189 | result.append(String(p, end - p)); 190 | if(*end == '\r' ||*end == '\n') 191 | { 192 | //result.append("\\n\"\n\""); 193 | result.append("\\n"); 194 | if(*end == '\r' && end[1] == '\n') 195 | ++end; 196 | } 197 | else 198 | { 199 | result.append("\\"); 200 | result.append(*end); 201 | } 202 | p = end + 1; 203 | } 204 | result.append('"'); 205 | return result; 206 | } 207 | 208 | String Generator::formatVariant(const Variant& var) 209 | { 210 | switch(var.getType()) 211 | { 212 | case Variant::boolType: 213 | return String("Variant(") + (var.toBool() ? String("true") : String("false")) + ")"; 214 | case Variant::doubleType: 215 | return String("Variant(") + String::fromDouble(var.toDouble()) + ")"; 216 | case Variant::intType: 217 | return String("Variant(") + String::fromInt64(var.toUInt()) + ")"; 218 | case Variant::uintType: 219 | return String("Variant(") + String::fromInt64(var.toUInt()) + "UL)"; 220 | case Variant::int64Type: 221 | return String("Variant(") + String::fromInt64(var.toUInt64()) + "LL)"; 222 | case Variant::uint64Type: 223 | return String("Variant(") + String::fromUInt64(var.toUInt64()) + "ULL)"; 224 | case Variant::stringType: 225 | return String("Variant(") + formatString(var.toString()) + ")"; 226 | default: 227 | return "Variant()"; 228 | } 229 | } -------------------------------------------------------------------------------- /Src/Reflector.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "Reflector.h" 5 | 6 | String Reflector::buildinTypes[] = { 7 | "int", 8 | "bool", 9 | }; 10 | 11 | void_t Reflector::addReferencedType(const String& name) 12 | { 13 | if(referencedTypes.find(name) != referencedTypes.end()) 14 | return; 15 | HashMap::Iterator it = parserData->declarations.find(name); 16 | if(it != parserData->declarations.end()) 17 | return (void_t)referencedTypes.append(name, &*it); 18 | 19 | for(size_t i = 0; i < sizeof(buildinTypes)/sizeof(*buildinTypes); ++i) 20 | if(name == buildinTypes[i]) 21 | { 22 | ParserData::TypeDecl& type = additionalTypes.append(); 23 | type.name = name; 24 | referencedTypes.append(name, &type); 25 | return; 26 | } 27 | 28 | String templateName = getTemplateName(name); 29 | if(!templateName.isEmpty()) 30 | { 31 | HashMap::Iterator it = parserData->templates.find(templateName); 32 | if(it != parserData->templates.end()) 33 | { 34 | ParserData::TypeDecl& type = additionalTypes.append(); 35 | type = *it; 36 | type.name = name; 37 | referencedTypes.append(name, &type); 38 | return; 39 | } 40 | } 41 | } 42 | 43 | bool_t Reflector::reflect(const String& headerFile, const ParserData& parserData) 44 | { 45 | this->parserData = &parserData; 46 | 47 | // find all referenced types in header file 48 | for(HashMap::Iterator i = parserData.declarations.begin(), end = parserData.declarations.end(); i != end; ++i) 49 | { 50 | const ParserData::TypeDecl& type = *i; 51 | if(type.file != headerFile) 52 | continue; 53 | ReflectorData::Type::ReflectionType reflectionType = getReflectionType(type); 54 | if(reflectionType != ReflectorData::Type::interfaceType && reflectionType != ReflectorData::Type::objectType) 55 | continue; 56 | addReferencedType(type.name); 57 | for(List::Iterator i = type.baseTypes.begin(), end = type.baseTypes.end(); i != end; ++i) 58 | addReferencedType(*i); 59 | for(List::Iterator i = type.methods.begin(), end = type.methods.end(); i != end; ++i) 60 | { 61 | ParserData::TypeDecl::MethodDecl& method = *i; 62 | addReferencedType(method.getReturnType()); 63 | for(List::Iterator i = method.parameters.begin(), end = method.parameters.end(); i != end; ++i) 64 | addReferencedType(i->type); 65 | } 66 | } 67 | 68 | // create type reflection 69 | struct UnresolvedType 70 | { 71 | String name; 72 | ReflectorData::Type** type; 73 | }; 74 | List unresolvedTypes; 75 | for(HashMap::Iterator i = referencedTypes.begin(), end = referencedTypes.end(); i != end; ++i) 76 | { 77 | const ParserData::TypeDecl& type = **i; 78 | ReflectorData::Type& reflectedType = data.types.append(type.name, ReflectorData::Type()); 79 | reflectedType.name = type.name; 80 | reflectedType.description = extractClassDescriptions(type.comment); 81 | reflectedType.reflectionType = getReflectionType(type); 82 | reflectedType.external = type.file != headerFile; 83 | for(List::Iterator i = type.baseTypes.begin(), end = type.baseTypes.end(); i != end; ++i) 84 | unresolvedTypes.append({*i, &reflectedType.baseTypes.append(0)}); 85 | for(List::Iterator i = type.methods.begin(), end = type.methods.end(); i != end; ++i) 86 | { 87 | const ParserData::TypeDecl::MethodDecl& method = *i; 88 | if(!method.comment.find("@invokable")) 89 | continue; 90 | ReflectorData::Type::Method& reflectedMethod = reflectedType.methods.append({}); 91 | reflectedMethod.name = method.name; 92 | unresolvedTypes.append({method.getReturnType(), &reflectedMethod.type}); 93 | for(List::Iterator i = method.parameters.begin(), end = method.parameters.end(); i != end; ++i) 94 | { 95 | ParserData::TypeDecl::MethodDecl::Parameter& parameter = *i; 96 | ReflectorData::Type::Method::Parameter& reflectedParameter = reflectedMethod.parameters.append({}); 97 | reflectedParameter.name = parameter.name; 98 | reflectedParameter.value = parameter.value; 99 | if(Variant(reflectedParameter.value.toBool()).toString() == reflectedParameter.value.toString()) 100 | reflectedParameter.value = reflectedParameter.value.toBool(); 101 | else if(String::fromInt(reflectedParameter.value.toInt()) == reflectedParameter.value.toString()) 102 | reflectedParameter.value = reflectedParameter.value.toInt(); 103 | else if(String::fromUInt(reflectedParameter.value.toUInt()) == reflectedParameter.value.toString()) 104 | reflectedParameter.value = reflectedParameter.value.toUInt(); 105 | else if(String::fromInt64(reflectedParameter.value.toInt64()) == reflectedParameter.value.toString()) 106 | reflectedParameter.value = reflectedParameter.value.toInt(); 107 | else if(String::fromUInt64(reflectedParameter.value.toUInt64()) == reflectedParameter.value.toString()) 108 | reflectedParameter.value = reflectedParameter.value.toUInt64(); 109 | else if(String::fromDouble(reflectedParameter.value.toDouble()) == reflectedParameter.value.toString()) 110 | reflectedParameter.value = reflectedParameter.value.toDouble(); 111 | unresolvedTypes.append({parameter.type, &reflectedParameter.type}); 112 | } 113 | extractMethodDescriptions(method.comment, reflectedMethod); 114 | } 115 | } 116 | 117 | // resolve all unresolved types in type reflection 118 | for(List::Iterator i = unresolvedTypes.begin(), end = unresolvedTypes.end(); i != end; ++i) 119 | { 120 | HashMap::Iterator it = data.types.find(i->name); 121 | if(it == data.types.end()) 122 | { 123 | if(i->name == "int") 124 | { 125 | ReflectorData::Type& reflectedType = data.types.append(i->name, ReflectorData::Type()); 126 | reflectedType.name = i->name; 127 | reflectedType.reflectionType = ReflectorData::Type::buildinType; 128 | reflectedType.external = true; 129 | it = --HashMap::Iterator(data.types.end()); 130 | } 131 | else 132 | { 133 | Console::errorf("Unknown type '%s'\n", (const tchar_t*)i->name); 134 | return false; 135 | } 136 | } 137 | *i->type = &*it; 138 | } 139 | 140 | return true; 141 | } 142 | 143 | ReflectorData::Type::ReflectionType Reflector::getReflectionType(const ParserData::TypeDecl& type) 144 | { 145 | if(type.name == "Reflected") 146 | return ReflectorData::Type::objectType; 147 | ReflectorData::Type::ReflectionType refType = ReflectorData::Type::referencedType; 148 | for(List::Iterator i = type.baseTypes.begin(), end = type.baseTypes.end(); i != end; ++i) 149 | { 150 | HashMap::Iterator it = parserData->declarations.find(*i); 151 | if(it == parserData->declarations.end()) 152 | continue; 153 | ReflectorData::Type::ReflectionType baseRefType = getReflectionType(*it); 154 | if(baseRefType == ReflectorData::Type::objectType) 155 | return ReflectorData::Type::objectType; 156 | if(baseRefType == ReflectorData::Type::interfaceType) 157 | refType = ReflectorData::Type::interfaceType; 158 | } 159 | if(refType == ReflectorData::Type::interfaceType) 160 | return ReflectorData::Type::interfaceType; 161 | for(List::Iterator i = type.innerComments.begin(), end = type.innerComments.end(); i != end; ++i) 162 | if(i->find("@invokable") || i->find("@property")) 163 | return ReflectorData::Type::interfaceType; 164 | 165 | for(size_t i = 0; i < sizeof(buildinTypes)/sizeof(*buildinTypes); ++i) 166 | if(type.name == buildinTypes[i]) 167 | return ReflectorData::Type::buildinType; 168 | 169 | return ReflectorData::Type::referencedType; 170 | } 171 | 172 | String Reflector::getTemplateName(const String& type) 173 | { 174 | const tchar_t* end = type.find('<'); 175 | if(!end) 176 | return String(); 177 | return type.substr(0, end - (const tchar_t*)type); 178 | } 179 | 180 | String Reflector::extractClassDescriptions(const String& comment) 181 | { 182 | List lines; 183 | comment.split(lines, "\n\r"); 184 | if(lines.isEmpty()) 185 | return String(); 186 | if(lines.front().startsWith("/**")) 187 | lines.front() = lines.front().substr(3); 188 | if(lines.back().endsWith("*/")) 189 | lines.back() = lines.back().substr(0, lines.back().length() - 2); 190 | for(List::Iterator begin = lines.begin(), i = begin, end = lines.end(); i != end; ++i) 191 | { 192 | const tchar_t* p = *i; 193 | while(String::isSpace(*p)) 194 | ++p; 195 | if(*p == '*' && i != begin) 196 | { 197 | ++p; 198 | while(String::isSpace(*p)) 199 | ++p; 200 | } 201 | if(p != (const tchar_t*)*i) 202 | *i = i->substr(p - (const tchar_t*)*i); 203 | } 204 | String description; 205 | for(List::Iterator i = lines.begin(), end = lines.end(); i != end; ++i) 206 | { 207 | const String& line = *i; 208 | if(line.isEmpty()) 209 | continue; 210 | if(!description.isEmpty()) 211 | description.append(' '); 212 | description.append(line); 213 | } 214 | return description; 215 | } 216 | 217 | void_t Reflector::extractMethodDescriptions(const String& comment, ReflectorData::Type::Method& method) 218 | { 219 | List lines; 220 | comment.split(lines, "\n\r"); 221 | if(lines.isEmpty()) 222 | return; 223 | if(lines.front().startsWith("/**")) 224 | lines.front() = lines.front().substr(3); 225 | if(lines.back().endsWith("*/")) 226 | lines.back() = lines.back().substr(0, lines.back().length() - 2); 227 | for(List::Iterator begin = lines.begin(), i = begin, end = lines.end(); i != end; ++i) 228 | { 229 | const tchar_t* p = *i; 230 | while(String::isSpace(*p)) 231 | ++p; 232 | if(*p == '*' && i != begin) 233 | { 234 | ++p; 235 | while(String::isSpace(*p)) 236 | ++p; 237 | } 238 | if(p != (const tchar_t*)*i) 239 | *i = i->substr(p - (const tchar_t*)*i); 240 | } 241 | String* description = &method.description; 242 | for(List::Iterator i = lines.begin(), end = lines.end(); i != end; ++i) 243 | { 244 | const String& line = *i; 245 | if(line.isEmpty()) 246 | continue; 247 | if(line.startsWith("@") || line.startsWith("\\")) 248 | { 249 | const tchar_t* p = (const tchar_t*)line + 1; 250 | if(String::compare(p, "class", 5) == 0 || String::compare(p, "interface", 9) == 0 || String::compare(p, "invokable", 9) == 0) 251 | continue; 252 | if(String::compare(p, "param", 5) == 0) 253 | { 254 | p += 5; 255 | while(String::isSpace(*p)) 256 | ++p; 257 | if(*p == '[') 258 | { 259 | ++p; 260 | while(*p && *p != ']') 261 | ++p; 262 | while(String::isSpace(*p)) 263 | ++p; 264 | } 265 | const tchar_t* end = String::findOneOf(p, " \t"); 266 | if(!end) 267 | continue; 268 | String parameterName(p, end -p); 269 | p = end; 270 | while(String::isSpace(*p)) 271 | ++p; 272 | String paramDescription(p, line.length() - (p - (const tchar_t*)line)); 273 | for(List::Iterator i = method.parameters.begin(), end = method.parameters.end(); i != end; ++i) 274 | { 275 | ReflectorData::Type::Method::Parameter& parameter = *i; 276 | if(parameter.name == parameterName) 277 | { 278 | parameter.description = paramDescription; 279 | description = ¶meter.description; 280 | break; 281 | } 282 | } 283 | continue; 284 | } 285 | } 286 | if(!description->isEmpty()) 287 | description->append(' '); 288 | description->append(line); 289 | } 290 | 291 | 292 | /* 293 | const tchar_t* p = comment; 294 | if(String::compare(p, "/**", 3) == 0) 295 | p += 3; 296 | for(;; ++p) 297 | switch(*p) 298 | { 299 | case ' ': 300 | case '\t': 301 | continue; 302 | case '\n': 303 | while(String::isSpace(*p)) 304 | ++p; 305 | if(*p != '*') 306 | --p; 307 | continue; 308 | case '@': 309 | case '\\': 310 | ++p; 311 | if(String::compare(0, "param", 5) == 0) 312 | { 313 | p += 5; 314 | while(String::isSpace(*p)) 315 | ++p; 316 | if(*p == '[') 317 | { 318 | ++p; 319 | while(*p && *p != ']') 320 | ++p; 321 | while(String::isSpace(*p)) 322 | ++p; 323 | } 324 | 325 | } 326 | else if(String::compare(0, "class", 5) == 0 || String::compare(0, "interface", 9) == 0 || String::compare(0, "invokable", 9) == 0) 327 | { 328 | p = String::find(p, '\r'); 329 | if(!p) 330 | goto finish; 331 | } 332 | continue; 333 | default: 334 | ?? 335 | } 336 | finish: 337 | ; 338 | */ 339 | } 340 | -------------------------------------------------------------------------------- /Src/Parser.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | 6 | #include "Parser.h" 7 | 8 | class Parser::Private 9 | { 10 | public: 11 | class Cursor 12 | { 13 | public: 14 | Cursor() : cursor(clang_getNullCursor()) {} 15 | Cursor(const CXCursor& cursor) : cursor(cursor) {} 16 | operator size_t() const 17 | { 18 | size_t hashCode = cursor.kind; 19 | hashCode *= 16807; 20 | hashCode ^= cursor.xdata; 21 | for(size_t i = 0; i < sizeof(cursor.data) / sizeof(*cursor.data); ++i) 22 | { 23 | hashCode *= 16807; 24 | hashCode ^= (size_t)cursor.data[i]; 25 | } 26 | return hashCode; 27 | } 28 | bool operator==(const Cursor& other) const 29 | { 30 | if(clang_equalCursors(cursor, other.cursor)) 31 | return true; 32 | return false; 33 | } 34 | private: 35 | CXCursor cursor; 36 | }; 37 | 38 | enum Action 39 | { 40 | noAction, 41 | classAction, 42 | methodAction, 43 | paramAction, 44 | }; 45 | 46 | public: 47 | ParserData& data; 48 | CXSourceLocation lastLocation; 49 | Action lastAction; 50 | HashMap typesByCursor; 51 | HashMap methodsByCursor; 52 | 53 | public: 54 | Private(ParserData& data) : data(data) {} 55 | 56 | bool_t parse(const String& sourceFile, const String& headerFile, const List& additionalArgs) 57 | { 58 | data.headerFile = headerFile; 59 | 60 | Array args(additionalArgs.size()); 61 | for(List::Iterator i = additionalArgs.begin(), end = additionalArgs.end(); i != end; ++i) 62 | args.append(*i); 63 | 64 | CXIndex index = clang_createIndex(1, 1); 65 | CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile(index, sourceFile.isEmpty() ? (const char*)headerFile : (const char*)sourceFile, 66 | (int)args.size(), args, 0, 0); //clang_createTranslationUnit(index, sourceFile); 67 | CXCursor cursor = clang_getTranslationUnitCursor(tu); 68 | lastLocation = clang_getCursorLocation(cursor); 69 | lastAction = noAction; 70 | clang_visitChildren(cursor, visitChildrenCallback, this); 71 | 72 | clang_disposeTranslationUnit(tu); 73 | clang_disposeIndex(index); 74 | return true; 75 | } 76 | 77 | public: 78 | static CXChildVisitResult visitChildrenCallback(CXCursor cursor, CXCursor parent, CXClientData client_data) 79 | { 80 | Private& parser = *(Private*)client_data; 81 | 82 | Action action = noAction; 83 | 84 | switch(cursor.kind) 85 | { 86 | case CXCursor_CXXBaseSpecifier: 87 | { 88 | ParserData::TypeDecl* typeDecl = *parser.typesByCursor.find(parent); 89 | if(typeDecl) 90 | { 91 | CXType type = clang_getCursorType(cursor); 92 | CXString typeName = clang_getTypeSpelling(type); 93 | String name = String::fromCString(clang_getCString(typeName)); 94 | clang_disposeString(typeName); 95 | typeDecl->baseTypes.append(name); 96 | } 97 | break; 98 | } 99 | case CXCursor_ClassTemplate: 100 | { 101 | CXCursorKind curKind = clang_getTemplateCursorKind(cursor); 102 | if(clang_isDeclaration(curKind)) 103 | { 104 | CXString spell = clang_getCursorSpelling(cursor); 105 | String name = String::fromCString(clang_getCString(spell)); 106 | clang_disposeString(spell); 107 | 108 | CXCursor parent = clang_getCursorSemanticParent(cursor); 109 | while(parent.kind != CXCursor_TranslationUnit) 110 | { 111 | CXString parentName = clang_getCursorSpelling(parent); 112 | name.prepend("::"); 113 | name.prepend(String::fromCString(clang_getCString(parentName))); 114 | clang_disposeString(parentName); 115 | parent = clang_getCursorSemanticParent(parent); 116 | } 117 | //Console::printf("%s (template)\n", (const tchar_t*)name); 118 | HashMap::Iterator it = parser.data.templates.find(name); 119 | ParserData::TypeDecl& typeDecl = it == parser.data.templates.end() ? parser.data.templates.append(name, {}) : *it; 120 | typeDecl.name = name; 121 | typeDecl.type = ParserData::TypeDecl::classType; 122 | action = classAction; 123 | parser.typesByCursor.append(cursor, &typeDecl); 124 | } 125 | break; 126 | } 127 | case CXCursor_ClassDecl: 128 | case CXCursor_EnumDecl: 129 | case CXCursor_StructDecl: 130 | { 131 | CXType type = clang_getCursorType(cursor); 132 | switch(type.kind) 133 | { 134 | case CXType_Invalid: 135 | case CXType_Unexposed: 136 | break; 137 | default: 138 | { 139 | CXString typeName = clang_getTypeSpelling(type); 140 | String name = String::fromCString(clang_getCString(typeName)); 141 | //Console::printf("%s\n", (const tchar_t*)name); 142 | clang_disposeString(typeName); 143 | 144 | HashMap::Iterator it = parser.data.declarations.find(name); 145 | ParserData::TypeDecl& typeDecl = it == parser.data.declarations.end() ? parser.data.declarations.append(name, {}) : *it; 146 | typeDecl.name = name; 147 | typeDecl.type = cursor.kind == CXCursor_ClassDecl ? ParserData::TypeDecl::classType : (cursor.kind == CXCursor_EnumDecl ? ParserData::TypeDecl::enumType : ParserData::TypeDecl::structType); 148 | action = classAction; 149 | parser.typesByCursor.append(cursor, &typeDecl); 150 | break; 151 | } 152 | } 153 | break; 154 | } 155 | case CXCursor_CXXMethod: 156 | { 157 | ParserData::TypeDecl* typeDecl = *parser.typesByCursor.find(parent); 158 | if(typeDecl) 159 | { 160 | CXType type = clang_getCursorType(cursor); 161 | CXString spelling = clang_getCursorSpelling(cursor); 162 | CXString typeSpelling = clang_getTypeSpelling(type); 163 | //Console::printf("%s - %s\n", (const tchar_t*)extractReturnType(clang_getCString(typeSpelling)), clang_getCString(spelling)); 164 | ParserData::TypeDecl::MethodDecl& method = typeDecl->methods.append({String::fromCString(clang_getCString(spelling)), String::fromCString(clang_getCString(typeSpelling))}); 165 | clang_disposeString(typeSpelling); 166 | clang_disposeString(spelling); 167 | action = methodAction; 168 | parser.methodsByCursor.append(cursor, &method); 169 | } 170 | } 171 | break; 172 | case CXCursor_TemplateTypeParameter: 173 | case CXCursor_NonTypeTemplateParameter: 174 | case CXCursor_TemplateTemplateParameter: 175 | if(parent.kind == CXCursor_ClassTemplate) 176 | { 177 | ParserData::TypeDecl* typeDecl = *parser.typesByCursor.find(parent); 178 | if(typeDecl) 179 | { 180 | CXType type = clang_getCursorType(cursor); 181 | CXString typeSpelling = clang_getTypeSpelling(type); 182 | CXString paramSpelling = clang_getCursorSpelling(cursor); 183 | String typeName = String::fromCString(clang_getCString(typeSpelling)); 184 | String paramName = String::fromCString(clang_getCString(paramSpelling)); 185 | //Console::printf("%s - %s\n", (const tchar_t*)typeName, (const tchar_t*)paramName); 186 | clang_disposeString(typeSpelling); 187 | clang_disposeString(paramSpelling); 188 | typeDecl->templateParams.append(paramName, typeName); 189 | } 190 | } 191 | break; 192 | case CXCursor_ParmDecl: 193 | { 194 | ParserData::TypeDecl* typeDecl = *parser.typesByCursor.find(clang_getCursorSemanticParent(parent)); 195 | if(typeDecl) 196 | { 197 | ParserData::TypeDecl::MethodDecl* methodDecl = *parser.methodsByCursor.find(parent); 198 | if(methodDecl) 199 | { 200 | CXType type = clang_getCursorType(cursor); 201 | CXString typeSpelling = clang_getTypeSpelling(type); 202 | CXString paramSpelling = clang_getCursorSpelling(cursor); 203 | methodDecl->parameters.append({String::fromCString(clang_getCString(paramSpelling)), String::fromCString(clang_getCString(typeSpelling))}); 204 | if(methodDecl->parameters.back().name == "p0") 205 | { 206 | int k = 42; 207 | } 208 | clang_disposeString(typeSpelling); 209 | clang_disposeString(paramSpelling); 210 | action = paramAction; 211 | } 212 | } 213 | break; 214 | } 215 | case CXCursor_IntegerLiteral: 216 | case CXCursor_StringLiteral: 217 | case CXCursor_FloatingLiteral: 218 | { 219 | if(parser.lastAction == paramAction) 220 | { 221 | ParserData::TypeDecl::MethodDecl* methodDecl = *parser.methodsByCursor.find(clang_getCursorSemanticParent(parent)); 222 | if(methodDecl) 223 | { 224 | if(!methodDecl->parameters.isEmpty()) 225 | { 226 | CXSourceRange range = clang_getCursorExtent(cursor); 227 | CXToken *tokens = 0; 228 | unsigned int tokensCount = 0; 229 | CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor); 230 | clang_tokenize(tu, range, &tokens, &tokensCount); 231 | if(tokensCount) 232 | { 233 | CXString spelling = clang_getTokenSpelling(tu, tokens[0]); 234 | methodDecl->parameters.back().value = String::fromCString(clang_getCString(spelling)); 235 | clang_disposeString(spelling); 236 | } 237 | clang_disposeTokens(tu, tokens, tokensCount); 238 | } 239 | } 240 | } 241 | break; 242 | } 243 | default: 244 | //{ 245 | // CXString spelling = clang_getCursorSpelling(cursor); 246 | // if(String::fromCString(clang_getCString(spelling)) == "param1") 247 | // { 248 | // int k = 32; 249 | // } 250 | // clang_disposeString(spelling); 251 | //} 252 | break; 253 | } 254 | 255 | if(action == classAction) 256 | { 257 | ParserData::TypeDecl* typeDecl = parser.typesByCursor.back(); 258 | CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor); 259 | CXSourceRange classRange = clang_getCursorExtent(cursor); 260 | CXToken* tokens; 261 | unsigned int tokensCount; 262 | clang_tokenize(tu, classRange, &tokens, &tokensCount); 263 | int depth = 0; 264 | for(unsigned int i = 0; i < tokensCount; ++i) 265 | { 266 | CXToken& token = tokens[i]; 267 | switch(clang_getTokenKind(token)) 268 | { 269 | case CXToken_Comment: 270 | { 271 | if(depth == 1) 272 | { 273 | CXString spell = clang_getTokenSpelling(tu, tokens[i]); 274 | if(String::compare(clang_getCString(spell), "/**", 3) == 0) 275 | typeDecl->innerComments.append(String::fromCString(clang_getCString(spell))); 276 | clang_disposeString(spell); 277 | } 278 | break; 279 | } 280 | case CXToken_Punctuation: 281 | { 282 | CXString spell = clang_getTokenSpelling(tu, tokens[i]); 283 | const char* tokenCStr = clang_getCString(spell); 284 | if(String::compare(tokenCStr, "{") == 0) 285 | ++depth; 286 | else if(String::compare(tokenCStr, "}") == 0) 287 | --depth; 288 | clang_disposeString(spell); 289 | break; 290 | } 291 | default: 292 | break; 293 | } 294 | } 295 | clang_disposeTokens(tu, tokens, tokensCount); 296 | } 297 | 298 | CXSourceRange cursorRange = clang_getCursorExtent(cursor); 299 | CXSourceLocation location = clang_getRangeStart(cursorRange); 300 | if(action != noAction) 301 | { 302 | CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor); 303 | CXFile startFile, endFile; 304 | unsigned int startOffset, endOffset; 305 | clang_getFileLocation(parser.lastLocation, &startFile, 0, 0, &startOffset); 306 | clang_getFileLocation(location, &endFile, 0, 0, &endOffset); 307 | if(startFile != endFile || startOffset > endOffset) 308 | parser.lastLocation = clang_getLocationForOffset(tu, endFile, 0); 309 | CXSourceRange range = clang_getRange(parser.lastLocation, location); 310 | CXToken* tokens; 311 | unsigned int tokensCount; 312 | clang_tokenize(tu, range, &tokens, &tokensCount); 313 | 314 | String comment; 315 | for(unsigned int i = tokensCount; i > 0; --i) 316 | if(clang_getTokenKind(tokens[i - 1]) == CXToken_Comment) 317 | { 318 | CXString spell = clang_getTokenSpelling(tu, tokens[i - 1]); 319 | if(String::compare(clang_getCString(spell), "/**", 3) == 0) 320 | comment = String::fromCString(clang_getCString(spell)); 321 | clang_disposeString(spell); 322 | break; 323 | } 324 | clang_disposeTokens(tu, tokens, tokensCount); 325 | 326 | if(action == classAction) 327 | { 328 | CXString filename = clang_getFileName(endFile); 329 | parser.typesByCursor.back()->file = String::fromCString(clang_getCString(filename)); 330 | clang_disposeString(filename); 331 | } 332 | 333 | if(!comment.isEmpty()) 334 | { 335 | switch(action) 336 | { 337 | case classAction: 338 | parser.typesByCursor.back()->comment = comment; 339 | break; 340 | case methodAction: 341 | parser.methodsByCursor.back()->comment = comment; 342 | break; 343 | default: 344 | break; 345 | } 346 | } 347 | } 348 | parser.lastLocation = location; 349 | parser.lastAction = action; 350 | 351 | // visit children recursively 352 | clang_visitChildren(cursor, visitChildrenCallback, &parser); 353 | 354 | return CXChildVisit_Continue; 355 | } 356 | }; 357 | 358 | Parser::Parser() : p(new Private(data)) {} 359 | Parser::~Parser() {delete p;} 360 | bool_t Parser::parse(const String& sourceFile, const String& headerFile, const List& additionalArgs) {return p->parse(sourceFile, headerFile, additionalArgs);} 361 | 362 | --------------------------------------------------------------------------------