Skip to content

Commit b89a3fa

Browse files
authored
Merge pull request #64 from kornilova-l/0.2
Changes that were merged to branch 0.2
2 parents d049a75 + b9656ae commit b89a3fa

17 files changed

+541
-26
lines changed

bindgen/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ add_executable(bindgen
2020
visitor/TreeVisitor.h
2121
visitor/TreeVisitor.cpp
2222
visitor/TreeConsumer.h
23+
defines/DefineFinderAction.h
24+
defines/DefineFinderAction.cpp
25+
defines/DefineFinder.cpp
26+
defines/DefineFinder.h
27+
defines/DefineFinderActionFactory.cpp
28+
defines/DefineFinderActionFactory.h
2329
TypeTranslator.h
2430
TypeTranslator.cpp
2531
HeaderManager.h
@@ -38,6 +44,10 @@ add_executable(bindgen
3844
ir/Enum.h
3945
ir/TypeAndName.cpp
4046
ir/TypeAndName.h
47+
ir/Define.h
48+
ir/Define.cpp
49+
ir/LiteralDefine.cpp
50+
ir/LiteralDefine.h
4151
)
4252

4353
set_target_properties(bindgen

bindgen/Main.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "defines/DefineFinderActionFactory.h"
12
#include "visitor/ScalaFrontendActionFactory.h"
23
#include <clang/Tooling/CommonOptionsParser.h>
34

@@ -71,9 +72,15 @@ int main(int argc, char *argv[]) {
7172
locations.clear();
7273

7374
IR ir(libName, linkName, objectName, Package.getValue());
74-
ScalaFrontendActionFactory actionFactory(ir);
7575

76-
int result = Tool.run(&actionFactory);
76+
DefineFinderActionFactory defineFinderActionFactory(ir);
77+
int result = Tool.run(&defineFinderActionFactory);
78+
if (result) {
79+
return result;
80+
}
81+
82+
ScalaFrontendActionFactory actionFactory(ir);
83+
result = Tool.run(&actionFactory);
7784

7885
auto printLoc = PrintHeadersLocation.getValue();
7986
if (printLoc) {

bindgen/defines/DefineFinder.cpp

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
#include "DefineFinder.h"
2+
3+
#include <llvm/ADT/APInt.h>
4+
#include <sstream>
5+
6+
DefineFinder::DefineFinder(IR &ir, const clang::CompilerInstance &compiler,
7+
clang::Preprocessor &pp)
8+
: ir(ir), compiler(compiler), pp(pp) {}
9+
10+
void DefineFinder::MacroDefined(const clang::Token &macroNameTok,
11+
const clang::MacroDirective *md) {
12+
clang::SourceManager &sm = compiler.getSourceManager();
13+
if (sm.isWrittenInMainFile(macroNameTok.getLocation()) && md->isDefined() &&
14+
!md->getMacroInfo()->isFunctionLike()) {
15+
/* save defines only from the given header.
16+
*
17+
* Ignore function-like definitions because they usually are meaningful
18+
* only inside C functions. */
19+
20+
std::vector<clang::Token> *tokens = expandDefine(*md);
21+
if (!tokens) { // there was function-like macro
22+
return;
23+
}
24+
std::string macroName = macroNameTok.getIdentifierInfo()->getName();
25+
26+
if (tokens->size() == 1 &&
27+
(*tokens)[0].getKind() == clang::tok::numeric_constant) {
28+
clang::Token numberToken = (*tokens)[0];
29+
std::string literal(numberToken.getLiteralData(),
30+
numberToken.getLength());
31+
addNumericConstantDefine(macroName, literal, numberToken);
32+
} else if (tokens->size() == 2 &&
33+
(*tokens)[0].getKind() == clang::tok::minus &&
34+
(*tokens)[1].getKind() == clang::tok::numeric_constant) {
35+
clang::Token numberToken = (*tokens)[1];
36+
std::string literal(numberToken.getLiteralData(),
37+
numberToken.getLength());
38+
addNumericConstantDefine(macroName, literal, numberToken, false);
39+
} else if (tokens->size() == 1 &&
40+
(*tokens)[0].getKind() == clang::tok::string_literal) {
41+
clang::Token stringToken = (*tokens)[0];
42+
std::string literal(stringToken.getLiteralData(),
43+
stringToken.getLength());
44+
ir.addLiteralDefine(macroName, "c" + literal, "native.CString");
45+
}
46+
std::free(tokens);
47+
}
48+
}
49+
50+
/**
51+
* @return array of tokens. Non of the returned tokens is a macro.
52+
*/
53+
std::vector<clang::Token> *
54+
DefineFinder::expandDefine(const clang::MacroDirective &md) {
55+
auto *expandedTokens = new std::vector<clang::Token>();
56+
clang::ArrayRef<clang::Token> tokens = md.getMacroInfo()->tokens();
57+
for (const auto &token : tokens) {
58+
if (isMacro(token)) {
59+
if (isFunctionLikeMacro(token)) {
60+
/* function-like macros are unsupported */
61+
return nullptr;
62+
}
63+
std::vector<clang::Token> *newTokens = expandDefine(
64+
*pp.getLocalMacroDirective(token.getIdentifierInfo()));
65+
if (!newTokens) {
66+
std::free(expandedTokens);
67+
return nullptr;
68+
}
69+
for (const auto &newToken : *newTokens) {
70+
(*expandedTokens).push_back(newToken);
71+
}
72+
std::free(newTokens);
73+
} else {
74+
(*expandedTokens).push_back(token);
75+
}
76+
}
77+
return expandedTokens;
78+
}
79+
80+
bool DefineFinder::isMacro(const clang::Token &token) {
81+
return token.isAnyIdentifier() &&
82+
token.getIdentifierInfo()->hasMacroDefinition();
83+
}
84+
85+
bool DefineFinder::isFunctionLikeMacro(const clang::Token &token) {
86+
clang::MacroDirective *md =
87+
pp.getLocalMacroDirective(token.getIdentifierInfo());
88+
return md->getMacroInfo()->isFunctionLike();
89+
}
90+
91+
void DefineFinder::MacroUndefined(const clang::Token &macroNameTok,
92+
const clang::MacroDefinition &md,
93+
const clang::MacroDirective *undef) {
94+
clang::SourceManager &sm = compiler.getSourceManager();
95+
if (sm.isWrittenInMainFile(macroNameTok.getLocation()) &&
96+
md.getMacroInfo() && !md.getMacroInfo()->isFunctionLike()) {
97+
std::string macroName = macroNameTok.getIdentifierInfo()->getName();
98+
ir.removeDefine(macroName);
99+
}
100+
}
101+
102+
void DefineFinder::addNumericConstantDefine(const std::string &macroName,
103+
std::string literal,
104+
const clang::Token &token,
105+
bool positive) {
106+
clang::NumericLiteralParser parser(literal, token.getLocation(), pp);
107+
std::string type;
108+
std::string scalaLiteral;
109+
if (parser.isIntegerLiteral()) {
110+
if (parser.isLongLong) {
111+
/* literal has `LL` ending. `long long` is represented as `Long`
112+
* in Scala Native */
113+
type = "native.CLongLong";
114+
115+
/* must fit into Scala integer type */
116+
if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) {
117+
type = "";
118+
}
119+
} else if (parser.isLong) {
120+
/* literal has `L` ending */
121+
type = "native.CLong";
122+
123+
/* must fit into Scala integer type */
124+
if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) {
125+
type = "";
126+
}
127+
} else {
128+
type = getTypeOfIntegerLiteral(parser, literal, positive);
129+
}
130+
131+
if (!type.empty()) {
132+
scalaLiteral = getDecimalLiteral(parser);
133+
if (type == "native.CLong" || type == "native.CLongLong") {
134+
scalaLiteral = scalaLiteral + "L";
135+
}
136+
}
137+
} else if (parser.isFloatingLiteral()) {
138+
if (fitsIntoDouble(parser)) {
139+
type = "native.CDouble";
140+
scalaLiteral = getDoubleLiteral(parser);
141+
}
142+
}
143+
144+
if (!type.empty()) {
145+
if (!positive) {
146+
scalaLiteral = "-" + scalaLiteral;
147+
}
148+
ir.addLiteralDefine(macroName, scalaLiteral, type);
149+
}
150+
}
151+
152+
std::string
153+
DefineFinder::getTypeOfIntegerLiteral(const clang::NumericLiteralParser &parser,
154+
const std::string &literal,
155+
bool positive) {
156+
157+
if (integerFitsIntoType<int, uint>(parser, positive)) {
158+
return "native.CInt";
159+
} else if (integerFitsIntoType<long, ulong>(parser, positive)) {
160+
return "native.CLong";
161+
} else {
162+
llvm::errs() << "Warning: integer value does not fit into 8 bytes: "
163+
<< literal << "\n";
164+
llvm::errs().flush();
165+
/**
166+
* `long long` value has mostly the same size as `long`.
167+
* Moreover in Scala Native the type is represented as `Long`:
168+
* @code
169+
* type CLongLong = Long
170+
* @endcode
171+
* Therefore the case of `long long` is not considered here.
172+
*/
173+
return "";
174+
}
175+
}
176+
177+
template <typename signedT, typename unsignedT>
178+
bool DefineFinder::integerFitsIntoType(clang::NumericLiteralParser parser,
179+
bool positive) {
180+
/* absolute value of minimum negative number will not fit
181+
* into (sizeof(signedT) * 8 - 1) bits */
182+
llvm::APInt uintValue(sizeof(signedT) * 8, 0, false);
183+
if (parser.GetIntegerValue(uintValue)) {
184+
/* absolute value of the number does not fit into (sizeof(signedT) * 8)
185+
* bits */
186+
return false;
187+
}
188+
auto uval = static_cast<unsignedT>(uintValue.getZExtValue());
189+
if (positive) {
190+
return uval <=
191+
static_cast<unsignedT>(std::numeric_limits<signedT>::max());
192+
} else {
193+
return uval <=
194+
static_cast<unsignedT>(-std::numeric_limits<signedT>::min());
195+
}
196+
}
197+
198+
std::string
199+
DefineFinder::getDecimalLiteral(clang::NumericLiteralParser parser) {
200+
llvm::APInt val(8 * 8, 0, false);
201+
parser.GetIntegerValue(val);
202+
return std::to_string(val.getZExtValue());
203+
}
204+
205+
std::string DefineFinder::getDoubleLiteral(clang::NumericLiteralParser parser) {
206+
llvm::APFloat val(.0); // double
207+
parser.GetFloatValue(val);
208+
std::ostringstream ss;
209+
ss << val.convertToDouble();
210+
return ss.str();
211+
}
212+
213+
bool DefineFinder::fitsIntoDouble(clang::NumericLiteralParser parser) {
214+
llvm::APFloat val(.0); // double
215+
parser.GetFloatValue(val);
216+
std::ostringstream ss;
217+
ss << val.convertToDouble();
218+
return ss.str() != "inf";
219+
}

bindgen/defines/DefineFinder.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef SCALA_NATIVE_BINDGEN_DEFINEFINDER_H
2+
#define SCALA_NATIVE_BINDGEN_DEFINEFINDER_H
3+
4+
#include "../ir/IR.h"
5+
#include <clang/Frontend/CompilerInstance.h>
6+
#include <clang/Lex/LiteralSupport.h>
7+
#include <clang/Lex/Preprocessor.h>
8+
9+
class DefineFinder : public clang::PPCallbacks {
10+
public:
11+
DefineFinder(IR &ir, const clang::CompilerInstance &compiler,
12+
clang::Preprocessor &pp);
13+
14+
void MacroDefined(const clang::Token &macroNameTok,
15+
const clang::MacroDirective *md) override;
16+
17+
void MacroUndefined(const clang::Token &macroNameTok,
18+
const clang::MacroDefinition &md,
19+
const clang::MacroDirective *undef) override;
20+
21+
private:
22+
IR &ir;
23+
const clang::CompilerInstance &compiler;
24+
clang::Preprocessor &pp;
25+
26+
void addNumericConstantDefine(const std::string &macroName,
27+
std::string literal,
28+
const clang::Token &token,
29+
bool positive = true);
30+
31+
/**
32+
* Check if the number fits into int or long variable.
33+
*
34+
* @return type of the number
35+
*/
36+
std::string
37+
getTypeOfIntegerLiteral(const clang::NumericLiteralParser &parser,
38+
const std::string &literal, bool positive);
39+
40+
std::vector<clang::Token> *expandDefine(const clang::MacroDirective &md);
41+
42+
bool isMacro(const clang::Token &token);
43+
44+
bool isFunctionLikeMacro(const clang::Token &token);
45+
46+
/**
47+
* @return true if number contained in parser fits into int type
48+
*/
49+
template <typename signedT, typename unsignedT>
50+
bool integerFitsIntoType(clang::NumericLiteralParser parser, bool positive);
51+
52+
std::string getDecimalLiteral(clang::NumericLiteralParser parser);
53+
54+
std::string getDoubleLiteral(clang::NumericLiteralParser parser);
55+
56+
bool fitsIntoDouble(clang::NumericLiteralParser parser);
57+
};
58+
59+
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDER_H
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include "DefineFinderAction.h"
2+
3+
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+
getCompilerInstance().getPreprocessor())));
10+
11+
clang::PreprocessOnlyAction::ExecuteAction();
12+
}

bindgen/defines/DefineFinderAction.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef SCALA_NATIVE_BINDGEN_DEFINEFINDERACTION_H
2+
#define SCALA_NATIVE_BINDGEN_DEFINEFINDERACTION_H
3+
4+
#include "DefineFinder.h"
5+
#include <clang/Frontend/FrontendActions.h>
6+
7+
class DefineFinderAction : public clang::PreprocessOnlyAction {
8+
public:
9+
explicit DefineFinderAction(IR &ir);
10+
11+
protected:
12+
void ExecuteAction() override;
13+
14+
private:
15+
IR &ir;
16+
};
17+
18+
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDERACTION_H
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "DefineFinderActionFactory.h"
2+
#include "DefineFinderAction.h"
3+
4+
DefineFinderActionFactory::DefineFinderActionFactory(IR &ir) : ir(ir) {}
5+
6+
clang::FrontendAction *DefineFinderActionFactory::create() {
7+
return new DefineFinderAction(ir);
8+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef SCALA_NATIVE_BINDGEN_DEFINEFINDERACTIONFACTORY_H
2+
#define SCALA_NATIVE_BINDGEN_DEFINEFINDERACTIONFACTORY_H
3+
4+
#include "../ir/IR.h"
5+
#include <clang/Tooling/Tooling.h>
6+
7+
class DefineFinderActionFactory : public clang::tooling::FrontendActionFactory {
8+
public:
9+
explicit DefineFinderActionFactory(IR &ir);
10+
11+
clang::FrontendAction *create() override;
12+
13+
private:
14+
IR &ir;
15+
};
16+
17+
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDERACTIONFACTORY_H

bindgen/ir/Define.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "Define.h"
2+
3+
Define::Define(std::string name) : name(std::move(name)) {}
4+
5+
std::string Define::getName() { return name; }

0 commit comments

Comments
 (0)