mirror of
https://github.com/libAthena/athena.git
synced 2025-07-13 16:46:04 +00:00
Merge pull request #13 from Antidote/atdna
Added `atdna` tool to Athena
This commit is contained in:
commit
791a355ace
@ -62,7 +62,8 @@ HEADERS += \
|
|||||||
$$PWD/include/utf8/unchecked.h \
|
$$PWD/include/utf8/unchecked.h \
|
||||||
$$PWD/include/Athena/FileInfo.hpp \
|
$$PWD/include/Athena/FileInfo.hpp \
|
||||||
$$PWD/include/Athena/Dir.hpp \
|
$$PWD/include/Athena/Dir.hpp \
|
||||||
$$PWD/include/gekko_support.h
|
$$PWD/include/gekko_support.h \
|
||||||
|
$$PWD/include/Athena/DNA.hpp
|
||||||
|
|
||||||
win32:HEADERS += \
|
win32:HEADERS += \
|
||||||
$$PWD/include/win32_largefilewrapper.h
|
$$PWD/include/win32_largefilewrapper.h
|
||||||
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2011-2015 Phillip "Antidote" Stephens, Jack Andersen, et al.
|
||||||
|
|
||||||
|
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.
|
6
PKGBUILD
6
PKGBUILD
@ -1,13 +1,13 @@
|
|||||||
# PKGBUILD for libAthena
|
# PKGBUILD for libAthena
|
||||||
_pkgname=libathena
|
_pkgname=libathena
|
||||||
pkgname=$_pkgname-git
|
pkgname=$_pkgname-git
|
||||||
pkgver=v1.0.0
|
pkgver=1.1.0.17.gfb722a9
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Basic cross platform IO library"
|
pkgdesc="Basic cross platform IO library"
|
||||||
arch=('i686' 'x86_64')
|
arch=('i686' 'x86_64')
|
||||||
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
|
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
|
||||||
options=(staticlibs)
|
options=(staticlibs)
|
||||||
license="GPL3"
|
license="MIT"
|
||||||
makedepends=('git qt5-base sed')
|
makedepends=('git qt5-base sed')
|
||||||
md5sums=('SKIP')
|
md5sums=('SKIP')
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
@ -19,7 +19,7 @@ pkgver() {
|
|||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "$srcdir/$_pkgname"
|
cd "$srcdir/$_pkgname"
|
||||||
qmake && make
|
qmake PREFIX="$pkgdir/usr" && make
|
||||||
}
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
|
30
atdna/PKGBUILD
Normal file
30
atdna/PKGBUILD
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# PKGBUILD for atdna
|
||||||
|
_pkgname=atdna
|
||||||
|
pkgname=$_pkgname-git
|
||||||
|
pkgver=1.1.0.23.g647f9c4
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Companion DNA utility for libAthena"
|
||||||
|
arch=('i686' 'x86_64')
|
||||||
|
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
|
||||||
|
options=(staticlibs)
|
||||||
|
license="MIT"
|
||||||
|
makedepends=('git qt5-base sed clang libathena-git')
|
||||||
|
depends=('libathena-git')
|
||||||
|
md5sums=('SKIP')
|
||||||
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd "$srcdir/$_pkgname"
|
||||||
|
git describe --tags | sed 's|-|.|g'
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$srcdir/$_pkgname/atdna"
|
||||||
|
qmake PREFIX="$pkgdir/usr" INSTALL_PREFIX="/usr" && make
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "$srcdir/$_pkgname/atdna"
|
||||||
|
qmake PREFIX="$pkgdir/usr" INSTALL_PREFIX="/usr" && make install
|
||||||
|
}
|
||||||
|
|
60
atdna/atdna.pro
Normal file
60
atdna/atdna.pro
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++11
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
QT =
|
||||||
|
DEFINES += __STDC_LIMIT_MACROS=1 __STDC_CONSTANT_MACROS=1
|
||||||
|
QMAKE_CXXFLAGS += -fno-rtti
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON = -Wno-unused-parameter
|
||||||
|
|
||||||
|
INCLUDEPATH += ../include
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release) {
|
||||||
|
# FOR FULL DEBUGGING, PLEASE UNCOMMENT THESE AND POINT THEM TO
|
||||||
|
# THE INSTALL PREFIX OF YOUR OWN DEBUG BUILD OF LLVM/CLANG!!
|
||||||
|
#INCLUDEPATH += /home/jacko/llvm-build/usr/include
|
||||||
|
#LIBS += -L/home/jacko/llvm-build/usr/lib
|
||||||
|
LIBS += -g
|
||||||
|
} else {
|
||||||
|
LIBS += -flto
|
||||||
|
}
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
LIBS += -lclangFrontend -lclangTooling -lclangDriver \
|
||||||
|
-lclangSerialization -lclangParse -lclangSema \
|
||||||
|
-lclangAnalysis -lclangEdit \
|
||||||
|
-lclangAST -lclangLex -lclangBasic \
|
||||||
|
-lLLVMOption -lLLVMMCParser -lLLVMBitReader \
|
||||||
|
-lLLVMMC -lLLVMSupport -lz -lpthread -lcurses -ldl
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
test.hpp
|
||||||
|
|
||||||
|
unix {
|
||||||
|
isEmpty(PREFIX) {
|
||||||
|
PREFIX = /usr/local
|
||||||
|
}
|
||||||
|
isEmpty(INSTALL_PREFIX) {
|
||||||
|
INSTALL_PREFIX = /usr/local
|
||||||
|
}
|
||||||
|
utilFiles.path = $$PREFIX/bin
|
||||||
|
utilFiles.files = $$OUT_PWD/atdna
|
||||||
|
INSTALLS += utilFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
isEmpty(PREFIX) {
|
||||||
|
PREFIX = $$PWD/pkg
|
||||||
|
}
|
||||||
|
isEmpty(INSTALL_PREFIX) {
|
||||||
|
INSTALL_PREFIX = $$PWD/pkg
|
||||||
|
}
|
||||||
|
utilFiles.path = $$PREFIX/bin
|
||||||
|
utilFiles.files = $$OUT_PWD/atdna
|
||||||
|
INSTALLS += utilFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINES += INSTALL_PREFIX="$$INSTALL_PREFIX"
|
||||||
|
|
456
atdna/main.cpp
Normal file
456
atdna/main.cpp
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
#include "clang/AST/ASTConsumer.h"
|
||||||
|
#include "clang/AST/RecursiveASTVisitor.h"
|
||||||
|
#include "clang/Frontend/CompilerInstance.h"
|
||||||
|
#include "clang/Frontend/FrontendAction.h"
|
||||||
|
#include "clang/Tooling/Tooling.h"
|
||||||
|
#include "clang/Lex/Preprocessor.h"
|
||||||
|
#include "clang/Sema/Sema.h"
|
||||||
|
#include "clang/AST/RecordLayout.h"
|
||||||
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
#include "clang/Basic/Version.h"
|
||||||
|
#include "llvm/Support/Format.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
|
#ifndef INSTALL_PREFIX
|
||||||
|
#define INSTALL_PREFIX /usr/local
|
||||||
|
#endif
|
||||||
|
#define XSTR(s) STR(s)
|
||||||
|
#define STR(s) #s
|
||||||
|
|
||||||
|
static llvm::cl::opt<bool> Help("h", llvm::cl::desc("Alias for -help"), llvm::cl::Hidden);
|
||||||
|
|
||||||
|
static llvm::cl::OptionCategory ATDNAFormatCategory("atdna options");
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string> OutputFilename("o",
|
||||||
|
llvm::cl::desc("Specify output filename"),
|
||||||
|
llvm::cl::value_desc("filename"),
|
||||||
|
llvm::cl::Prefix);
|
||||||
|
|
||||||
|
static llvm::cl::list<std::string> InputFilenames(llvm::cl::Positional,
|
||||||
|
llvm::cl::desc("<Input files>"),
|
||||||
|
llvm::cl::OneOrMore);
|
||||||
|
|
||||||
|
class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
|
||||||
|
{
|
||||||
|
clang::ASTContext& context;
|
||||||
|
llvm::raw_fd_ostream& fileOut;
|
||||||
|
|
||||||
|
std::string GetOpString(const clang::Type* theType, unsigned width,
|
||||||
|
std::string fieldName, bool writerPass)
|
||||||
|
{
|
||||||
|
if (writerPass)
|
||||||
|
{
|
||||||
|
if (theType->isBuiltinType())
|
||||||
|
{
|
||||||
|
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
|
||||||
|
if (bType->isUnsignedInteger())
|
||||||
|
{
|
||||||
|
if (width == 8)
|
||||||
|
return "writer.writeUByte(" + fieldName + ");";
|
||||||
|
else if (width == 16)
|
||||||
|
return "writer.writeUint16(" + fieldName + ");";
|
||||||
|
else if (width == 32)
|
||||||
|
return "writer.writeUint32(" + fieldName + ");";
|
||||||
|
else if (width == 64)
|
||||||
|
return "writer.writeUint64(" + fieldName + ");";
|
||||||
|
}
|
||||||
|
else if (bType->isSignedInteger())
|
||||||
|
{
|
||||||
|
if (width == 8)
|
||||||
|
return "writer.writeByte(" + fieldName + ");";
|
||||||
|
else if (width == 16)
|
||||||
|
return "writer.writeInt16(" + fieldName + ");";
|
||||||
|
else if (width == 32)
|
||||||
|
return "writer.writeInt32(" + fieldName + ");";
|
||||||
|
else if (width == 64)
|
||||||
|
return "writer.writeInt64(" + fieldName + ");";
|
||||||
|
}
|
||||||
|
else if (bType->isFloatingPoint())
|
||||||
|
{
|
||||||
|
if (width == 32)
|
||||||
|
return "writer.writeFloat(" + fieldName + ");";
|
||||||
|
else if (width == 64)
|
||||||
|
return "writer.writeDouble(" + fieldName + ");";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (theType->isRecordType())
|
||||||
|
{
|
||||||
|
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
|
||||||
|
for (const clang::FieldDecl* field : rDecl->fields())
|
||||||
|
{
|
||||||
|
if (!field->getNameAsString().compare("clangVec"))
|
||||||
|
{
|
||||||
|
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
|
||||||
|
if (vType->isVectorType())
|
||||||
|
{
|
||||||
|
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
|
||||||
|
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
|
||||||
|
context.getTypeInfo(eType).Width != 32)
|
||||||
|
continue;
|
||||||
|
if (vType->getNumElements() == 3)
|
||||||
|
return "writer.writeVec3f(" + fieldName + ");";
|
||||||
|
else if (vType->getNumElements() == 4)
|
||||||
|
return "writer.writeVec4f(" + fieldName + ");";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (theType->isBuiltinType())
|
||||||
|
{
|
||||||
|
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
|
||||||
|
if (bType->isUnsignedInteger())
|
||||||
|
{
|
||||||
|
if (width == 8)
|
||||||
|
return "reader.readUByte()";
|
||||||
|
else if (width == 16)
|
||||||
|
return "reader.readUint16()";
|
||||||
|
else if (width == 32)
|
||||||
|
return "reader.readUint32()";
|
||||||
|
else if (width == 64)
|
||||||
|
return "reader.readUint64()";
|
||||||
|
}
|
||||||
|
else if (bType->isSignedInteger())
|
||||||
|
{
|
||||||
|
if (width == 8)
|
||||||
|
return "reader.readByte()";
|
||||||
|
else if (width == 16)
|
||||||
|
return "reader.readInt16()";
|
||||||
|
else if (width == 32)
|
||||||
|
return "reader.readInt32()";
|
||||||
|
else if (width == 64)
|
||||||
|
return "reader.readInt64()";
|
||||||
|
}
|
||||||
|
else if (bType->isFloatingPoint())
|
||||||
|
{
|
||||||
|
if (width == 32)
|
||||||
|
return "reader.readFloat()";
|
||||||
|
else if (width == 64)
|
||||||
|
return "reader.readDouble()";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (theType->isRecordType())
|
||||||
|
{
|
||||||
|
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
|
||||||
|
for (const clang::FieldDecl* field : rDecl->fields())
|
||||||
|
{
|
||||||
|
if (!field->getNameAsString().compare("clangVec"))
|
||||||
|
{
|
||||||
|
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
|
||||||
|
if (vType->isVectorType())
|
||||||
|
{
|
||||||
|
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
|
||||||
|
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
|
||||||
|
context.getTypeInfo(eType).Width != 32)
|
||||||
|
continue;
|
||||||
|
if (vType->getNumElements() == 3)
|
||||||
|
return "reader.readVec3f()";
|
||||||
|
else if (vType->getNumElements() == 4)
|
||||||
|
return "reader.readVec4f()";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ATDNAEmitVisitor(clang::ASTContext& ctxin,
|
||||||
|
llvm::raw_fd_ostream& fo)
|
||||||
|
: context(ctxin), fileOut(fo) {}
|
||||||
|
|
||||||
|
bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl)
|
||||||
|
{
|
||||||
|
if (decl->isInvalidDecl() || !decl->hasDefinition())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!decl->getNumBases())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* First ensure this inherits from struct Athena::io::DNA */
|
||||||
|
bool foundDNA = false;
|
||||||
|
for (const clang::CXXBaseSpecifier& base : decl->bases())
|
||||||
|
{
|
||||||
|
clang::QualType canonType = base.getType().getCanonicalType();
|
||||||
|
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
|
||||||
|
{
|
||||||
|
foundDNA = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundDNA)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (int p=0 ; p<2 ; ++p)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::IStreamWriter& writer) const\n{\n";
|
||||||
|
else
|
||||||
|
fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::IStreamReader& reader)\n{\n";
|
||||||
|
int currentEndian = -1;
|
||||||
|
|
||||||
|
for (const clang::FieldDecl* field : decl->fields())
|
||||||
|
{
|
||||||
|
clang::QualType qualType = field->getType();
|
||||||
|
clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType);
|
||||||
|
const clang::Type* regType = qualType.getTypePtrOrNull();
|
||||||
|
if (regType->getTypeClass() == clang::Type::Elaborated)
|
||||||
|
regType = regType->getUnqualifiedDesugaredType();
|
||||||
|
|
||||||
|
if (regType->getTypeClass() == clang::Type::TemplateSpecialization)
|
||||||
|
{
|
||||||
|
const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType;
|
||||||
|
const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl();
|
||||||
|
const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters();
|
||||||
|
|
||||||
|
if (!tsDecl->getNameAsString().compare("Value"))
|
||||||
|
{
|
||||||
|
int endian = -1;
|
||||||
|
if (classParms->size() >= 2)
|
||||||
|
{
|
||||||
|
const clang::NamedDecl* endianParm = classParms->getParam(1);
|
||||||
|
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
|
||||||
|
{
|
||||||
|
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
|
||||||
|
const clang::Expr* defArg = nttParm->getDefaultArgument();
|
||||||
|
llvm::APSInt result;
|
||||||
|
if (defArg->isIntegerConstantExpr(result, context))
|
||||||
|
endian = result.getSExtValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ioOp;
|
||||||
|
const clang::TemplateArgument* typeArg = nullptr;
|
||||||
|
for (const clang::TemplateArgument& arg : *tsType)
|
||||||
|
{
|
||||||
|
if (arg.getKind() == clang::TemplateArgument::Type)
|
||||||
|
{
|
||||||
|
typeArg = &arg;
|
||||||
|
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
|
||||||
|
ioOp = GetOpString(type, regTypeInfo.Width, field->getName().str(), p);
|
||||||
|
}
|
||||||
|
else if (arg.getKind() == clang::TemplateArgument::Expression)
|
||||||
|
{
|
||||||
|
llvm::APSInt value;
|
||||||
|
if (arg.getAsExpr()->isIntegerConstantExpr(value, context))
|
||||||
|
endian = value.getSExtValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioOp.empty())
|
||||||
|
{
|
||||||
|
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
|
||||||
|
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
|
||||||
|
if (typeArg)
|
||||||
|
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentEndian != endian)
|
||||||
|
{
|
||||||
|
if (endian == 0)
|
||||||
|
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
|
||||||
|
else if (endian == 1)
|
||||||
|
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
|
||||||
|
currentEndian = endian;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
fileOut << " " << field->getName() << " = " << ioOp << ";\n";
|
||||||
|
else
|
||||||
|
fileOut << " " << ioOp << "\n";
|
||||||
|
}
|
||||||
|
else if (!tsDecl->getNameAsString().compare("Vector"))
|
||||||
|
{
|
||||||
|
int endian = -1;
|
||||||
|
if (classParms->size() >= 3)
|
||||||
|
{
|
||||||
|
const clang::NamedDecl* endianParm = classParms->getParam(2);
|
||||||
|
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
|
||||||
|
{
|
||||||
|
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
|
||||||
|
const clang::Expr* defArg = nttParm->getDefaultArgument();
|
||||||
|
llvm::APSInt result;
|
||||||
|
if (defArg->isIntegerConstantExpr(result, context))
|
||||||
|
endian = result.getSExtValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ioOp;
|
||||||
|
std::string sizeVar;
|
||||||
|
const clang::TemplateArgument* typeArg = nullptr;
|
||||||
|
const clang::TemplateArgument* sizeArg = nullptr;
|
||||||
|
size_t idx = 0;
|
||||||
|
for (const clang::TemplateArgument& arg : *tsType)
|
||||||
|
{
|
||||||
|
if (arg.getKind() == clang::TemplateArgument::Type)
|
||||||
|
{
|
||||||
|
typeArg = &arg;
|
||||||
|
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
|
||||||
|
clang::TypeInfo typeInfo = context.getTypeInfo(arg.getAsType().getCanonicalType());
|
||||||
|
ioOp = GetOpString(type, typeInfo.Width, "*it", p);
|
||||||
|
}
|
||||||
|
else if (arg.getKind() == clang::TemplateArgument::Expression)
|
||||||
|
{
|
||||||
|
const clang::Expr* expr = arg.getAsExpr();
|
||||||
|
if (idx == 1)
|
||||||
|
{
|
||||||
|
sizeArg = &arg;
|
||||||
|
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
|
||||||
|
if (uExpr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
|
||||||
|
uExpr->getKind() == clang::UETT_SizeOf)
|
||||||
|
{
|
||||||
|
const clang::Expr* argExpr = uExpr->getArgumentExpr();
|
||||||
|
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
|
||||||
|
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
|
||||||
|
if (argExpr->getStmtClass() == clang::Stmt::DeclRefExprClass)
|
||||||
|
{
|
||||||
|
const clang::DeclRefExpr* refExpr = (clang::DeclRefExpr*)argExpr;
|
||||||
|
sizeVar = refExpr->getFoundDecl()->getNameAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (idx == 2)
|
||||||
|
{
|
||||||
|
llvm::APSInt value;
|
||||||
|
if (expr->isIntegerConstantExpr(value, context))
|
||||||
|
endian = value.getSExtValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioOp.empty())
|
||||||
|
{
|
||||||
|
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
|
||||||
|
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
|
||||||
|
if (typeArg)
|
||||||
|
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeVar.empty())
|
||||||
|
{
|
||||||
|
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
|
||||||
|
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
|
||||||
|
if (sizeArg)
|
||||||
|
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*sizeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentEndian != endian)
|
||||||
|
{
|
||||||
|
if (endian == 0)
|
||||||
|
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
|
||||||
|
else if (endian == 1)
|
||||||
|
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
|
||||||
|
currentEndian = endian;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
fileOut << " " << field->getName() << ".clear();\n";
|
||||||
|
fileOut << " " << field->getName() << ".reserve(" << sizeVar << ");\n";
|
||||||
|
fileOut << " for (int i=0 ; i<" << sizeVar << " ; ++i)\n " << field->getName() << ".push_back(" << ioOp << ");\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fileOut << " for (int i=0, auto it=" << field->getName() << ".begin() ; i<" << sizeVar << " && it!=" << field->getName() << ".end() ; ++i, ++it)\n " << ioOp << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (regType->getTypeClass() == clang::Type::Record)
|
||||||
|
{
|
||||||
|
const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl();
|
||||||
|
if (cxxRDecl)
|
||||||
|
{
|
||||||
|
for (const clang::CXXBaseSpecifier& base : cxxRDecl->bases())
|
||||||
|
{
|
||||||
|
clang::QualType canonType = base.getType().getCanonicalType();
|
||||||
|
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
|
||||||
|
{
|
||||||
|
fileOut << " " << field->getNameAsString() << (p ? ".write(writer);\n" : ".read(reader);\n");
|
||||||
|
currentEndian = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOut << "}\n\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ATDNAConsumer : public clang::ASTConsumer
|
||||||
|
{
|
||||||
|
ATDNAEmitVisitor emitVisitor;
|
||||||
|
llvm::raw_fd_ostream& fileOut;
|
||||||
|
public:
|
||||||
|
explicit ATDNAConsumer(clang::ASTContext& context, llvm::raw_fd_ostream& fo)
|
||||||
|
: emitVisitor(context, fo),
|
||||||
|
fileOut(fo) {}
|
||||||
|
void HandleTranslationUnit(clang::ASTContext& context)
|
||||||
|
{
|
||||||
|
/* Write file head */
|
||||||
|
fileOut << "/* Auto generated atdna implementation */\n"
|
||||||
|
"#include <Athena/Global.hpp>\n"
|
||||||
|
"#include <Athena/IStreamReader.hpp>\n"
|
||||||
|
"#include <Athena/IStreamWriter.hpp>\n\n";
|
||||||
|
for (const std::string& inputf : InputFilenames)
|
||||||
|
fileOut << "#include \"" << inputf << "\"\n";
|
||||||
|
fileOut << "\n";
|
||||||
|
|
||||||
|
/* Second pass - emit file */
|
||||||
|
emitVisitor.TraverseDecl(context.getTranslationUnitDecl());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ATDNAAction : public clang::ASTFrontendAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ATDNAAction() {}
|
||||||
|
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler,
|
||||||
|
llvm::StringRef /*filename*/)
|
||||||
|
{
|
||||||
|
llvm::raw_fd_ostream* fileout;
|
||||||
|
if (OutputFilename.size())
|
||||||
|
fileout = compiler.createOutputFile(OutputFilename, false, true, "", "", true);
|
||||||
|
else
|
||||||
|
fileout = compiler.createDefaultOutputFile(false, "a", "cpp");
|
||||||
|
return std::unique_ptr<clang::ASTConsumer>(new ATDNAConsumer(compiler.getASTContext(), *fileout));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
llvm::cl::ParseCommandLineOptions(argc, argv, "Athena DNA Generator");
|
||||||
|
if (Help)
|
||||||
|
llvm::cl::PrintHelpMessage();
|
||||||
|
|
||||||
|
std::vector<std::string> args = {"clang-tool",
|
||||||
|
"-fsyntax-only",
|
||||||
|
"-std=c++11"};
|
||||||
|
args.push_back("-I" + std::string(XSTR(INSTALL_PREFIX)) + "/lib/clang/" + CLANG_VERSION_STRING + "/include");
|
||||||
|
args.push_back("-I" + std::string(XSTR(INSTALL_PREFIX)) + "/include/Athena");
|
||||||
|
for (int a=1 ; a<argc ; ++a)
|
||||||
|
args.push_back(argv[a]);
|
||||||
|
|
||||||
|
llvm::IntrusiveRefCntPtr<clang::FileManager> fman(new clang::FileManager(clang::FileSystemOptions()));
|
||||||
|
clang::tooling::ToolInvocation TI(args, new ATDNAAction, fman.get());
|
||||||
|
if (TI.run())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
32
atdna/test.hpp
Normal file
32
atdna/test.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <Athena/DNA.hpp>
|
||||||
|
|
||||||
|
using namespace Athena;
|
||||||
|
|
||||||
|
struct ANCSSubFile : public io::DNA<BigEndian>
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> sub1;
|
||||||
|
Value<atUint32> sub2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ANCSFile : public io::DNA<BigEndian>
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> var32;
|
||||||
|
Value<atUint16> var16;
|
||||||
|
Value<atVec3f> vec3;
|
||||||
|
Value<atVec4f> vec4;
|
||||||
|
|
||||||
|
struct ANCSNestedSubFile : public io::DNA<BigEndian>
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> nestSub1;
|
||||||
|
Value<atUint32> nestSub2;
|
||||||
|
} nestedSubFile;
|
||||||
|
|
||||||
|
ANCSSubFile subFile;
|
||||||
|
|
||||||
|
Value<atUint32> arrCount;
|
||||||
|
Vector<atUint32, sizeof(arrCount)> array;
|
||||||
|
};
|
||||||
|
|
43
include/Athena/DNA.hpp
Normal file
43
include/Athena/DNA.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef DNA_HPP
|
||||||
|
#define DNA_HPP
|
||||||
|
|
||||||
|
#include "Global.hpp"
|
||||||
|
#include "IStreamReader.hpp"
|
||||||
|
#include "IStreamWriter.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Athena
|
||||||
|
{
|
||||||
|
namespace io
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base DNA class used against 'atdna'
|
||||||
|
*
|
||||||
|
* Athena bundles a build-tool called 'atdna'. This tool functions
|
||||||
|
* just like the 'clang' compiler, except it emits
|
||||||
|
*/
|
||||||
|
template <Endian DNAE>
|
||||||
|
struct DNA
|
||||||
|
{
|
||||||
|
template <typename T, Endian VE = DNAE>
|
||||||
|
using Value = T;
|
||||||
|
|
||||||
|
template <typename T, size_t cntVar, Endian VE = DNAE>
|
||||||
|
using Vector = std::vector<T>;
|
||||||
|
|
||||||
|
virtual void read(IStreamReader&)=0;
|
||||||
|
virtual void write(IStreamWriter&) const=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Macro to automatically declare read/write methods in subclasses */
|
||||||
|
#define DECL_DNA \
|
||||||
|
void read(Athena::io::IStreamReader&); \
|
||||||
|
void write(Athena::io::IStreamWriter&) const; \
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DNA_HPP
|
||||||
|
|
@ -73,14 +73,14 @@ typedef struct stat64 stat64_t;
|
|||||||
|
|
||||||
namespace Athena
|
namespace Athena
|
||||||
{
|
{
|
||||||
enum class SeekOrigin
|
enum SeekOrigin
|
||||||
{
|
{
|
||||||
Begin,
|
Begin,
|
||||||
Current,
|
Current,
|
||||||
End
|
End
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Endian
|
enum Endian
|
||||||
{
|
{
|
||||||
LittleEndian,
|
LittleEndian,
|
||||||
BigEndian
|
BigEndian
|
||||||
|
@ -56,6 +56,34 @@ typedef unsigned long atUint32;
|
|||||||
typedef signed long long atInt64;
|
typedef signed long long atInt64;
|
||||||
typedef unsigned long long atUint64;
|
typedef unsigned long long atUint64;
|
||||||
|
|
||||||
|
// Vector types
|
||||||
|
#if __SSE__
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
#if __clang__
|
||||||
|
float clangVec __attribute__((__vector_size__(12)));
|
||||||
|
#endif
|
||||||
|
#if __SSE__
|
||||||
|
__m128 mVec128;
|
||||||
|
#endif
|
||||||
|
float vec[3];
|
||||||
|
} atVec3f;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
#if __clang__
|
||||||
|
float clangVec __attribute__((__vector_size__(16)));
|
||||||
|
#endif
|
||||||
|
#if __SSE__
|
||||||
|
__m128 mVec128;
|
||||||
|
#endif
|
||||||
|
float vec[4];
|
||||||
|
} atVec4f;
|
||||||
|
|
||||||
|
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define NULL 0
|
#define NULL 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user