Skip to content

Commit

Permalink
Generate Scala code for literal definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
kornilova203 committed Jun 17, 2018
1 parent 2efe884 commit 1ce2e45
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 30 deletions.
6 changes: 4 additions & 2 deletions bindgen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ add_executable(bindgen
defines/DefineFinder.h
defines/DefineFinderActionFactory.cpp
defines/DefineFinderActionFactory.h
ir/Define.h
ir/Define.cpp
TypeTranslator.h
TypeTranslator.cpp
HeaderManager.h
Expand All @@ -46,6 +44,10 @@ add_executable(bindgen
ir/Enum.h
ir/TypeAndName.cpp
ir/TypeAndName.h
ir/Define.h
ir/Define.cpp
ir/LiteralDefine.cpp
ir/LiteralDefine.h
)

set_target_properties(bindgen
Expand Down
58 changes: 53 additions & 5 deletions bindgen/defines/DefineFinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,60 @@ DefineFinder::DefineFinder(IR &ir, const clang::CompilerInstance &compiler)

void DefineFinder::MacroDefined(const clang::Token &MacroNameTok,
const clang::MacroDirective *MD) {
std::string name = MacroNameTok.getIdentifierInfo()->getName();
clang::SourceManager &sm = compiler.getSourceManager();
if (sm.isWrittenInMainFile(MacroNameTok.getLocation())) {
llvm::errs() << name << "\n";
for (const auto &tok : MD->getMacroInfo()->tokens()) {
llvm::errs() << tok.getName() << "\n";
if (sm.isWrittenInMainFile(MacroNameTok.getLocation()) && MD->isDefined() &&
!MD->getMacroInfo()->isFunctionLike()) {
/* save defines only from the given header.
*
* Ignore function-like definitions because they usually are meaningful
* only inside C functions. */

clang::ArrayRef<clang::Token> tokens = MD->getMacroInfo()->tokens();
if (tokens.size() != 1) {
/* process only simple definitions that contain only 1 token */
return;
}
std::string macroName = MacroNameTok.getIdentifierInfo()->getName();

clang::Token token = tokens[0];
const clang::Token *finalToken;
if (token.isAnyIdentifier()) {
/* current token might be another definition */
finalToken = getFinalIdentifier(token);
} else {
finalToken = &token;
}
if (!finalToken) {
return;
}
if (finalToken->isLiteral()) {
/* might be converted directly to Scala code */
std::string literal(finalToken->getLiteralData(),
finalToken->getLength());
switch (finalToken->getKind()) {
case clang::tok::numeric_constant:
ir.addLiteralDefine(macroName, literal);
break;
case clang::tok::string_literal:
ir.addLiteralDefine(macroName, "c" + literal, "native.CString");
break;
default:
llvm::errs() << "Warning: type of literal "
<< finalToken->getName() << " is unsupported\n";
llvm::errs().flush();
}
} else if (finalToken->isAnyIdentifier()) {
// TODO: save identifier and get its type in ScalaFrontendAction
}
}
}

const clang::Token *
DefineFinder::getFinalIdentifier(const clang::Token &token) const {
assert(token.isAnyIdentifier());
if (!token.getIdentifierInfo()->hasMacroDefinition()) {
return &token;
}
// TODO: token is another definition. Find the original value
return nullptr;
}
2 changes: 2 additions & 0 deletions bindgen/defines/DefineFinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class DefineFinder : public clang::PPCallbacks {
private:
IR &ir;
const clang::CompilerInstance &compiler;

const clang::Token *getFinalIdentifier(const clang::Token &token) const;
};

#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDER_H
8 changes: 8 additions & 0 deletions bindgen/defines/DefineFinderAction.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
#include "DefineFinderAction.h"

DefineFinderAction::DefineFinderAction(IR &ir) : ir(ir) {}

void DefineFinderAction::ExecuteAction() {
getCompilerInstance().getPreprocessor().addPPCallbacks(
std::unique_ptr<clang::PPCallbacks>(
new DefineFinder(ir, getCompilerInstance())));

clang::PreprocessOnlyAction::ExecuteAction();
}
8 changes: 1 addition & 7 deletions bindgen/defines/DefineFinderAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@ class DefineFinderAction : public clang::PreprocessOnlyAction {
explicit DefineFinderAction(IR &ir);

protected:
void ExecuteAction() override {
getCompilerInstance().getPreprocessor().addPPCallbacks(
std::unique_ptr<clang::PPCallbacks>(
new DefineFinder(ir, getCompilerInstance())));

clang::PreprocessOnlyAction::ExecuteAction();
}
void ExecuteAction() override;

private:
IR &ir;
Expand Down
3 changes: 1 addition & 2 deletions bindgen/ir/Define.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include "Define.h"

Define::Define(const std::string &name, const std::string &type)
: TypeAndName(name, type) {}
Define::Define(std::string name) : name(std::move(name)) {}
7 changes: 5 additions & 2 deletions bindgen/ir/Define.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

#include "TypeAndName.h"

class Define : TypeAndName {
class Define {
public:
Define(const std::string &name, const std::string &type);
explicit Define(std::string name);

protected:
const std::string name;
};

#endif // SCALA_NATIVE_BINDGEN_DEFINE_H
22 changes: 18 additions & 4 deletions bindgen/ir/IR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
IR::IR(std::string libName, std::string linkName, std::string objectName,
std::string packageName)
: libName(std::move(libName)), linkName(std::move(linkName)),
objectName(std::move(objectName)), packageName(packageName) {}
objectName(std::move(objectName)), packageName(std::move(packageName)) {}

void IR::addFunction(std::string name, std::vector<Parameter> parameters,
std::string retType, bool isVariadic) {
Expand Down Expand Up @@ -32,8 +32,14 @@ void IR::addUnion(std::string name, std::vector<Field> fields,
unions.emplace_back(std::move(name), std::move(fields), maxSize);
}

void IR::addDefine(std::string name, std::string type) {
defines.emplace_back(std::move(name), std::move(type));
void IR::addLiteralDefine(std::string name, std::string literal) {
literalDefines.emplace_back(std::move(name), std::move(literal));
}

void IR::addLiteralDefine(std::string name, std::string literal,
std::string type) {
literalDefines.emplace_back(std::move(name), std::move(literal),
std::move(type));
}

bool IR::libObjEmpty() const {
Expand All @@ -48,7 +54,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
s << "package " << ir.packageName << "\n\n";
}

if (!ir.libObjEmpty() || !ir.enums.empty()) {
if (!ir.libObjEmpty() || !ir.enums.empty() || !ir.literalDefines.empty()) {
s << "import scala.scalanative._\n"
<< "import scala.scalanative.native._\n\n";
}
Expand All @@ -74,6 +80,14 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
s << "}\n\n";
}

if (!ir.literalDefines.empty()) {
s << "object " << ir.libName << "Defines {\n";
for (const auto &literalDefine : ir.literalDefines) {
s << literalDefine;
}
s << "}\n\n";
}

if (!ir.enums.empty() || ir.hasHelperMethods()) {
s << "import " << objectName << "._\n\n";
}
Expand Down
9 changes: 6 additions & 3 deletions bindgen/ir/IR.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef SCALA_NATIVE_BINDGEN_INTERMEDIATEREPRESENTATION_H
#define SCALA_NATIVE_BINDGEN_INTERMEDIATEREPRESENTATION_H

#include "Define.h"
#include "Enum.h"
#include "Function.h"
#include "LiteralDefine.h"
#include "Struct.h"
#include "TypeDef.h"

Expand All @@ -29,7 +29,10 @@ class IR {
void addUnion(std::string name, std::vector<Field> fields,
uint64_t maxSize);

void addDefine(std::string name, std::string type);
void addLiteralDefine(std::string name, std::string literal);

void addLiteralDefine(std::string name, std::string literal,
std::string type);

/**
* @return true if there are no functions, types,
Expand Down Expand Up @@ -115,7 +118,7 @@ class IR {
std::vector<Struct> structs;
std::vector<Union> unions;
std::vector<Enum> enums;
std::vector<Define> defines;
std::vector<LiteralDefine> literalDefines;
bool generated = false; // generate type defs only once
std::string packageName;
};
Expand Down
19 changes: 19 additions & 0 deletions bindgen/ir/LiteralDefine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "LiteralDefine.h"

LiteralDefine::LiteralDefine(std::string name, std::string literal)
: Define(std::move(name)), literal(std::move(literal)) {}

LiteralDefine::LiteralDefine(std::string name, std::string literal,
std::string type)
: Define(std::move(name)), literal(std::move(literal)),
type(std::move(type)) {}

llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
const LiteralDefine &literalDefine) {
s << " val " << literalDefine.name;
if (!literalDefine.type.empty()) {
s << ": " << literalDefine.type;
}
s << " = " << literalDefine.literal << "\n";
return s;
}
21 changes: 21 additions & 0 deletions bindgen/ir/LiteralDefine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef SCALA_NATIVE_BINDGEN_LITERALDEFINE_H
#define SCALA_NATIVE_BINDGEN_LITERALDEFINE_H

#include "Define.h"
#include <llvm/Support/raw_ostream.h>

class LiteralDefine : Define {
public:
LiteralDefine(std::string name, std::string literal);

LiteralDefine(std::string name, std::string literal, std::string type);

friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
const LiteralDefine &literalDefine);

private:
std::string literal;
std::string type; // might be empty
};

#endif // SCALA_NATIVE_BINDGEN_LITERALDEFINE_H
5 changes: 0 additions & 5 deletions bindgen/visitor/ScalaFrontendActionFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,5 @@
ScalaFrontendActionFactory::ScalaFrontendActionFactory(IR &ir) : ir(ir) {}

clang::FrontendAction *ScalaFrontendActionFactory::create() {
if (!ir.libObjEmpty() || ir.hasEnums()) {
llvm::errs() << "IR is not empty. Please use new instance of "
"ScalaFrontendActionFactory.\n";
llvm::errs().flush();
}
return new ScalaFrontendAction(ir);
}
10 changes: 10 additions & 0 deletions tests/samples/Define.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#define STRING "Hello, World!"

#define INT 42
// #define LONG 10000000000 // this will fail
#define FLOAT 5.6

#define NEW_INT INT // unsupported

extern int a;
#define MY_A a // unsupported
10 changes: 10 additions & 0 deletions tests/samples/Define.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.scalanative.bindgen.samples

import scala.scalanative._
import scala.scalanative.native._

object DefineDefines {
val STRING: native.CString = c"Hello, World!"
val INT = 42
val FLOAT = 5.6
}

0 comments on commit 1ce2e45

Please sign in to comment.