Skip to content

Commit 1ce2e45

Browse files
committed
Generate Scala code for literal definitions
1 parent 2efe884 commit 1ce2e45

14 files changed

+158
-30
lines changed

bindgen/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ add_executable(bindgen
2626
defines/DefineFinder.h
2727
defines/DefineFinderActionFactory.cpp
2828
defines/DefineFinderActionFactory.h
29-
ir/Define.h
30-
ir/Define.cpp
3129
TypeTranslator.h
3230
TypeTranslator.cpp
3331
HeaderManager.h
@@ -46,6 +44,10 @@ add_executable(bindgen
4644
ir/Enum.h
4745
ir/TypeAndName.cpp
4846
ir/TypeAndName.h
47+
ir/Define.h
48+
ir/Define.cpp
49+
ir/LiteralDefine.cpp
50+
ir/LiteralDefine.h
4951
)
5052

5153
set_target_properties(bindgen

bindgen/defines/DefineFinder.cpp

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,60 @@ DefineFinder::DefineFinder(IR &ir, const clang::CompilerInstance &compiler)
88

99
void DefineFinder::MacroDefined(const clang::Token &MacroNameTok,
1010
const clang::MacroDirective *MD) {
11-
std::string name = MacroNameTok.getIdentifierInfo()->getName();
1211
clang::SourceManager &sm = compiler.getSourceManager();
13-
if (sm.isWrittenInMainFile(MacroNameTok.getLocation())) {
14-
llvm::errs() << name << "\n";
15-
for (const auto &tok : MD->getMacroInfo()->tokens()) {
16-
llvm::errs() << tok.getName() << "\n";
12+
if (sm.isWrittenInMainFile(MacroNameTok.getLocation()) && MD->isDefined() &&
13+
!MD->getMacroInfo()->isFunctionLike()) {
14+
/* save defines only from the given header.
15+
*
16+
* Ignore function-like definitions because they usually are meaningful
17+
* only inside C functions. */
18+
19+
clang::ArrayRef<clang::Token> tokens = MD->getMacroInfo()->tokens();
20+
if (tokens.size() != 1) {
21+
/* process only simple definitions that contain only 1 token */
22+
return;
23+
}
24+
std::string macroName = MacroNameTok.getIdentifierInfo()->getName();
25+
26+
clang::Token token = tokens[0];
27+
const clang::Token *finalToken;
28+
if (token.isAnyIdentifier()) {
29+
/* current token might be another definition */
30+
finalToken = getFinalIdentifier(token);
31+
} else {
32+
finalToken = &token;
33+
}
34+
if (!finalToken) {
35+
return;
1736
}
37+
if (finalToken->isLiteral()) {
38+
/* might be converted directly to Scala code */
39+
std::string literal(finalToken->getLiteralData(),
40+
finalToken->getLength());
41+
switch (finalToken->getKind()) {
42+
case clang::tok::numeric_constant:
43+
ir.addLiteralDefine(macroName, literal);
44+
break;
45+
case clang::tok::string_literal:
46+
ir.addLiteralDefine(macroName, "c" + literal, "native.CString");
47+
break;
48+
default:
49+
llvm::errs() << "Warning: type of literal "
50+
<< finalToken->getName() << " is unsupported\n";
51+
llvm::errs().flush();
52+
}
53+
} else if (finalToken->isAnyIdentifier()) {
54+
// TODO: save identifier and get its type in ScalaFrontendAction
55+
}
56+
}
57+
}
58+
59+
const clang::Token *
60+
DefineFinder::getFinalIdentifier(const clang::Token &token) const {
61+
assert(token.isAnyIdentifier());
62+
if (!token.getIdentifierInfo()->hasMacroDefinition()) {
63+
return &token;
1864
}
65+
// TODO: token is another definition. Find the original value
66+
return nullptr;
1967
}

bindgen/defines/DefineFinder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class DefineFinder : public clang::PPCallbacks {
1515
private:
1616
IR &ir;
1717
const clang::CompilerInstance &compiler;
18+
19+
const clang::Token *getFinalIdentifier(const clang::Token &token) const;
1820
};
1921

2022
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDER_H
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
#include "DefineFinderAction.h"
22

33
DefineFinderAction::DefineFinderAction(IR &ir) : ir(ir) {}
4+
5+
void DefineFinderAction::ExecuteAction() {
6+
getCompilerInstance().getPreprocessor().addPPCallbacks(
7+
std::unique_ptr<clang::PPCallbacks>(
8+
new DefineFinder(ir, getCompilerInstance())));
9+
10+
clang::PreprocessOnlyAction::ExecuteAction();
11+
}

bindgen/defines/DefineFinderAction.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@ class DefineFinderAction : public clang::PreprocessOnlyAction {
1010
explicit DefineFinderAction(IR &ir);
1111

1212
protected:
13-
void ExecuteAction() override {
14-
getCompilerInstance().getPreprocessor().addPPCallbacks(
15-
std::unique_ptr<clang::PPCallbacks>(
16-
new DefineFinder(ir, getCompilerInstance())));
17-
18-
clang::PreprocessOnlyAction::ExecuteAction();
19-
}
13+
void ExecuteAction() override;
2014

2115
private:
2216
IR &ir;

bindgen/ir/Define.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
#include "Define.h"
22

3-
Define::Define(const std::string &name, const std::string &type)
4-
: TypeAndName(name, type) {}
3+
Define::Define(std::string name) : name(std::move(name)) {}

bindgen/ir/Define.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
#include "TypeAndName.h"
55

6-
class Define : TypeAndName {
6+
class Define {
77
public:
8-
Define(const std::string &name, const std::string &type);
8+
explicit Define(std::string name);
9+
10+
protected:
11+
const std::string name;
912
};
1013

1114
#endif // SCALA_NATIVE_BINDGEN_DEFINE_H

bindgen/ir/IR.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
IR::IR(std::string libName, std::string linkName, std::string objectName,
55
std::string packageName)
66
: libName(std::move(libName)), linkName(std::move(linkName)),
7-
objectName(std::move(objectName)), packageName(packageName) {}
7+
objectName(std::move(objectName)), packageName(std::move(packageName)) {}
88

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

35-
void IR::addDefine(std::string name, std::string type) {
36-
defines.emplace_back(std::move(name), std::move(type));
35+
void IR::addLiteralDefine(std::string name, std::string literal) {
36+
literalDefines.emplace_back(std::move(name), std::move(literal));
37+
}
38+
39+
void IR::addLiteralDefine(std::string name, std::string literal,
40+
std::string type) {
41+
literalDefines.emplace_back(std::move(name), std::move(literal),
42+
std::move(type));
3743
}
3844

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

51-
if (!ir.libObjEmpty() || !ir.enums.empty()) {
57+
if (!ir.libObjEmpty() || !ir.enums.empty() || !ir.literalDefines.empty()) {
5258
s << "import scala.scalanative._\n"
5359
<< "import scala.scalanative.native._\n\n";
5460
}
@@ -74,6 +80,14 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
7480
s << "}\n\n";
7581
}
7682

83+
if (!ir.literalDefines.empty()) {
84+
s << "object " << ir.libName << "Defines {\n";
85+
for (const auto &literalDefine : ir.literalDefines) {
86+
s << literalDefine;
87+
}
88+
s << "}\n\n";
89+
}
90+
7791
if (!ir.enums.empty() || ir.hasHelperMethods()) {
7892
s << "import " << objectName << "._\n\n";
7993
}

bindgen/ir/IR.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#ifndef SCALA_NATIVE_BINDGEN_INTERMEDIATEREPRESENTATION_H
22
#define SCALA_NATIVE_BINDGEN_INTERMEDIATEREPRESENTATION_H
33

4-
#include "Define.h"
54
#include "Enum.h"
65
#include "Function.h"
6+
#include "LiteralDefine.h"
77
#include "Struct.h"
88
#include "TypeDef.h"
99

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

32-
void addDefine(std::string name, std::string type);
32+
void addLiteralDefine(std::string name, std::string literal);
33+
34+
void addLiteralDefine(std::string name, std::string literal,
35+
std::string type);
3336

3437
/**
3538
* @return true if there are no functions, types,
@@ -115,7 +118,7 @@ class IR {
115118
std::vector<Struct> structs;
116119
std::vector<Union> unions;
117120
std::vector<Enum> enums;
118-
std::vector<Define> defines;
121+
std::vector<LiteralDefine> literalDefines;
119122
bool generated = false; // generate type defs only once
120123
std::string packageName;
121124
};

bindgen/ir/LiteralDefine.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "LiteralDefine.h"
2+
3+
LiteralDefine::LiteralDefine(std::string name, std::string literal)
4+
: Define(std::move(name)), literal(std::move(literal)) {}
5+
6+
LiteralDefine::LiteralDefine(std::string name, std::string literal,
7+
std::string type)
8+
: Define(std::move(name)), literal(std::move(literal)),
9+
type(std::move(type)) {}
10+
11+
llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
12+
const LiteralDefine &literalDefine) {
13+
s << " val " << literalDefine.name;
14+
if (!literalDefine.type.empty()) {
15+
s << ": " << literalDefine.type;
16+
}
17+
s << " = " << literalDefine.literal << "\n";
18+
return s;
19+
}

0 commit comments

Comments
 (0)