Skip to content

Commit 2db8071

Browse files
committed
Convert C literals to Scala literals
1 parent e288ac9 commit 2db8071

File tree

4 files changed

+95
-35
lines changed

4 files changed

+95
-35
lines changed

bindgen/defines/DefineFinder.cpp

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "DefineFinder.h"
22

33
#include <llvm/ADT/APInt.h>
4+
#include <sstream>
45

56
DefineFinder::DefineFinder(IR &ir, const clang::CompilerInstance &compiler,
67
clang::Preprocessor &pp)
@@ -92,7 +93,7 @@ void DefineFinder::MacroUndefined(const clang::Token &macroNameTok,
9293
const clang::MacroDirective *undef) {
9394
clang::SourceManager &sm = compiler.getSourceManager();
9495
if (sm.isWrittenInMainFile(macroNameTok.getLocation()) &&
95-
!md.getMacroInfo()->isFunctionLike()) {
96+
md.getMacroInfo() && !md.getMacroInfo()->isFunctionLike()) {
9697
std::string macroName = macroNameTok.getIdentifierInfo()->getName();
9798
ir.removeDefine(macroName);
9899
}
@@ -104,47 +105,59 @@ void DefineFinder::addNumericConstantDefine(const std::string &macroName,
104105
bool positive) {
105106
clang::NumericLiteralParser parser(literal, token.getLocation(), pp);
106107
std::string type;
108+
std::string scalaLiteral;
107109
if (parser.isIntegerLiteral()) {
108-
std::replace(literal.begin(), literal.end(), 'l', 'L');
109110
if (parser.isLongLong) {
110-
/* literal has `LL` ending but `long long` is represented as
111-
* `Long` in Scala Native */
112-
literal = literal.substr(0, literal.length() - 1); // remove last L
111+
/* literal has `LL` ending. `long long` is represented as `Long`
112+
* in Scala Native */
113113
type = "native.CLongLong";
114+
115+
/* must fit into Scala integer type */
116+
if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) {
117+
type = "";
118+
}
114119
} else if (parser.isLong) {
115-
/* literal already has `L` ending */
120+
/* literal has `L` ending */
116121
type = "native.CLong";
122+
123+
/* must fit into Scala integer type */
124+
if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) {
125+
type = "";
126+
}
117127
} else {
118-
/* literal may not have `l` or `ll` ending but still be of long type
119-
* NumericLiteralParser does not recognize that 10000000000
120-
* is a long value.
121-
* Therefore we need to check that value fits into certain number
122-
* of bits. */
123-
getTypeOfIntLiteralWithoutEnding(parser, literal, type, positive);
128+
type = getTypeOfIntegerLiteral(parser, literal, positive);
124129
}
125-
} else {
126-
if (parser.isFloatingLiteral()) {
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)) {
127139
type = "native.CDouble";
128-
// TODO: distinguish between float and double
140+
scalaLiteral = getDoubleLiteral(parser);
129141
}
130142
}
143+
131144
if (!type.empty()) {
132145
if (!positive) {
133-
literal = "-" + literal;
146+
scalaLiteral = "-" + scalaLiteral;
134147
}
135-
ir.addLiteralDefine(macroName, literal, type);
148+
ir.addLiteralDefine(macroName, scalaLiteral, type);
136149
}
137150
}
138151

139-
void DefineFinder::getTypeOfIntLiteralWithoutEnding(
140-
clang::NumericLiteralParser parser, std::string &literal, std::string &type,
141-
bool positive) {
152+
std::string
153+
DefineFinder::getTypeOfIntegerLiteral(const clang::NumericLiteralParser &parser,
154+
const std::string &literal,
155+
bool positive) {
142156

143-
if (fitsIntoType<int, uint>(parser, positive)) {
144-
type = "native.CInt";
145-
} else if (fitsIntoType<long, ulong>(parser, positive)) {
146-
type = "native.CLong";
147-
literal = literal + "L";
157+
if (integerFitsIntoType<int, uint>(parser, positive)) {
158+
return "native.CInt";
159+
} else if (integerFitsIntoType<long, ulong>(parser, positive)) {
160+
return "native.CLong";
148161
} else {
149162
llvm::errs() << "Waring: integer value does not fit into 8 bytes: "
150163
<< literal << "\n";
@@ -157,12 +170,13 @@ void DefineFinder::getTypeOfIntLiteralWithoutEnding(
157170
* @endcode
158171
* Therefore the case of `long long` is not considered here.
159172
*/
173+
return "";
160174
}
161175
}
162176

163177
template <typename signedT, typename unsignedT>
164-
bool DefineFinder::fitsIntoType(clang::NumericLiteralParser parser,
165-
bool positive) {
178+
bool DefineFinder::integerFitsIntoType(clang::NumericLiteralParser parser,
179+
bool positive) {
166180
/* absolute value of minimum negative number will not fit
167181
* into (sizeof(signedT) * 8 - 1) bits */
168182
llvm::APInt uintValue(sizeof(signedT) * 8, 0, false);
@@ -180,3 +194,26 @@ bool DefineFinder::fitsIntoType(clang::NumericLiteralParser parser,
180194
static_cast<unsignedT>(-std::numeric_limits<signedT>::min());
181195
}
182196
}
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: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,13 @@ class DefineFinder : public clang::PPCallbacks {
2929
bool positive = true);
3030

3131
/**
32-
* Check if a number without `l` or `ll` ending fits into int or long
33-
* variable. Supports only non-negative numbers
32+
* Check if the number fits into int or long variable.
3433
*
35-
* Updates `literal` and `type` parameters.
34+
* @return type of the number
3635
*/
37-
void getTypeOfIntLiteralWithoutEnding(clang::NumericLiteralParser parser,
38-
std::string &literal,
39-
std::string &type, bool positive);
36+
std::string
37+
getTypeOfIntegerLiteral(const clang::NumericLiteralParser &parser,
38+
const std::string &literal, bool positive);
4039

4140
std::vector<clang::Token> *expandDefine(const clang::MacroDirective &md);
4241

@@ -48,7 +47,13 @@ class DefineFinder : public clang::PPCallbacks {
4847
* @return true if number contained in parser fits into int type
4948
*/
5049
template <typename signedT, typename unsignedT>
51-
bool fitsIntoType(clang::NumericLiteralParser parser, bool positive);
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);
5257
};
5358

5459
#endif // SCALA_NATIVE_BINDGEN_DEFINEFINDER_H

tests/samples/LiteralDefine.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#define MINIMUM_SIGNED_LONG -9223372036854775808 // OK
1313
#define LESS_THEN_MINIMUM_SIGNED_LONG -9223372036854775809 // excluded
1414

15-
#define FLOAT 5.6
15+
#define FLOAT 5.6f
1616

1717
#define INT 42
1818
#define MAXIMUM_INT 2147483647
@@ -40,3 +40,14 @@ extern int a;
4040
#endif
4141

4242
#undef DEFINED_ONLY_IN_HEADER
43+
44+
// integer literals
45+
#define OCTAL 0213 // 139
46+
#define HEXADECIMAL 0x4b // 75
47+
48+
// floating point literals
49+
#define EXPONENT 1e-10L
50+
#define DOT_EXPONENT 1.e-2
51+
#define HEXADECIMAL_WITHOUT_RADIX 0x1ffp10
52+
#define HEXADECIMAL_WITH_RADIX 0xf.p-1
53+
#define HEXADECIMAL_FRACTIONAL_WITH_RADIX 0x0.123p-1

tests/samples/LiteralDefine.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@ object LiteralDefineDefines {
1616
val NEW_INT: native.CInt = 42
1717
val NEG_INT: native.CInt = -42
1818
val SHOULD_BE_DEFINED: native.CString = c"Because INT is not equal to 0"
19+
val OCTAL: native.CInt = 139
20+
val HEXADECIMAL: native.CInt = 75
21+
val EXPONENT: native.CDouble = 1e-10
22+
val DOT_EXPONENT: native.CDouble = 0.01
23+
val HEXADECIMAL_WITHOUT_RADIX: native.CDouble = 523264
24+
val HEXADECIMAL_WITH_RADIX: native.CDouble = 7.5
25+
val HEXADECIMAL_FRACTIONAL_WITH_RADIX: native.CDouble = 0.0355225
1926
}

0 commit comments

Comments
 (0)