Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 68 additions & 9 deletions dstep/translator/MacroDefinition.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import std.array : Appender;
import std.traits;
import std.meta;
import std.variant;
import std.string;

import clang.c.Index;
import clang.Cursor;
Expand Down Expand Up @@ -87,27 +88,85 @@ struct ExpressionContext
}
}

private string normalizeLSuffix(string suffix)
{
for (int i = 0; i < suffix.length; i++)
{
if (suffix.length > i + 1 &&
((suffix[i] == 'l' && suffix[i + 1] == 'l') ||
(suffix[i] == 'L' && suffix[i + 1] == 'L')))
{
return suffix[0 .. i] ~ "L" ~ suffix[i + 2 .. $];
}
else if (suffix[i] == 'l')
{
return suffix[0 .. i] ~ "L" ~ suffix[i + 1 .. $];
}
}
return suffix;
}

private string normalizeDot(string number, string suffix)
{
auto dot = number.indexOf('.');
if (dot < 0 || (suffix.empty && dot == number.length - 1))
return number;

if (dot + 1 == number.length ||
number[dot + 1] == 'e' || number[dot + 1] == 'E' ||
number[dot + 1] == 'p' || number[dot + 1] == 'P')
return number[0 .. dot + 1] ~ "0" ~ number[dot + 1 .. $];

return number;
}

private string normalizeDecimalSuffix(string suffix)
{
import std.ascii : toLower;

if (suffix.length == 0 || toLower(suffix[0]) != 'd')
return suffix;

if (suffix.length == 1)
return "";

switch (toLower(suffix[1]))
{
case 'd': return "";
case 'l': return "L";
case 'f': return suffix[1 .. $];
default: return suffix;
}
}

string translate(Literal literal, ExpressionContext context)
{
import std.algorithm;
import std.ascii;
import std.range;

alias pred = (dchar x) => (x == 'u' || x == 'U' || x == 'L');
auto integer = literal.spelling.stripRight!pred;
auto uinteger = integer.stripLeft!(x => x == '+' || x == '-');
auto stripped = literal.spelling.stripLeft!(x => x == '+' || x == '-');
bool isHex = stripped.length >= 2 && stripped[0] == '0' &&
(stripped[1] == 'x' || stripped[1] == 'X');

string number = literal.spelling.stripRight!((dchar x) => (x == 'u' || x == 'U' || x == 'l' || x == 'L'));
if (!isHex || stripped.canFind('p') || stripped.canFind('P'))
{
number = number.stripRight!((dchar x) => (x == 'f' || x == 'F' || x == 'd' || x == 'D'));
}
string suffix = literal.spelling[number.length .. $];

suffix = normalizeDecimalSuffix(suffix);
suffix = normalizeLSuffix(suffix);

if (uinteger.length > 1 &&
uinteger.all!isDigit &&
uinteger.front == '0')
auto uinteger = number.stripLeft!(x => x == '+' || x == '-');
if (uinteger.length > 1 && uinteger.all!isDigit && uinteger.front == '0')
{
(*context.imports).add("std.conv : octal");
auto suffix = literal.spelling[integer.length .. $];
auto core = uinteger[0 .. $ - 1].stripLeft('0') ~ uinteger[$ - 1];
return "octal!" ~ core ~ suffix;
}

return literal.spelling;
return normalizeDot(number, suffix) ~ suffix;
}

string translate(Identifier identifier, ExpressionContext context)
Expand Down
127 changes: 127 additions & 0 deletions tests/unit/UnitTests.d
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,7 @@ unittest
#define some_0700UL 0700UL
#define some_minus_0700 -0700
#define some_minus_0700L -0700L
#define nonoctal 0700.
C", q"D
import std.conv : octal;

Expand All @@ -1051,6 +1052,132 @@ enum some_0700uL = octal!700uL;
enum some_0700UL = octal!700UL;
enum some_minus_0700 = -octal!700;
enum some_minus_0700L = -octal!700L;
enum nonoctal = 0700.;
D");

}

// Suffix normalization tests.
unittest
{
assertTranslates(q"C
#define longA 1l
#define longB 2LL
#define longC -3ll
#define longD 4uLL
#define longE 5Ull
#define longF 6LLU
#define longG 7llu
#define longH 8LLu
#define longI +9llU
#define longJ 1ull
#define longK 2ULL

#define floatA 3.
#define floatB 4.f
#define floatC 0.F
#define floatD -1.f
#define floatE +2.F
#define floatF 0.e+0
#define floatG 0e0
#define floatH 3.e7
#define floatI -1.2E+3
#define floatJ 4.5e-6
#define floatK 0x79.P6
#define floatL 0x8.p2F
C", q"D
extern (C):

enum longA = 1L;
enum longB = 2L;
enum longC = -3L;
enum longD = 4uL;
enum longE = 5UL;
enum longF = 6LU;
enum longG = 7Lu;
enum longH = 8Lu;
enum longI = +9LU;
enum longJ = 1uL;
enum longK = 2UL;

enum floatA = 3.;
enum floatB = 4.0f;
enum floatC = 0.0F;
enum floatD = -1.0f;
enum floatE = +2.0F;
enum floatF = 0.0e+0;
enum floatG = 0e0;
enum floatH = 3.0e7;
enum floatI = -1.2E+3;
enum floatJ = 4.5e-6;
enum floatK = 0x79.0P6;
enum floatL = 0x8.0p2F;
D");

}

// Hex numbers.
unittest
{
assertTranslates(q"C
#define hexA 0x000D
#define hexB 0xFFu
#define hexC 0xABCDUL
#define hexD 0x1234l
#define hexE 0XDEAD
#define hexF 0x0D0F
#define hexG 0XFF
#define hexH -0xFF
#define hexI 0xFFull
#define hexJ 0x1.0p3
#define hexK 0xDEADp4
#define hexL 0x1.0p5d
#define hexM 0x1.0p6D
#define hexN 0x1.0p7f
C", q"D
extern (C):

enum hexA = 0x000D;
enum hexB = 0xFFu;
enum hexC = 0xABCDUL;
enum hexD = 0x1234L;
enum hexE = 0XDEAD;
enum hexF = 0x0D0F;
enum hexG = 0XFF;
enum hexH = -0xFF;
enum hexI = 0xFFuL;
enum hexJ = 0x1.0p3;
enum hexK = 0xDEADp4;
enum hexL = 0x1.0p5;
enum hexM = 0x1.0p6;
enum hexN = 0x1.0p7f;
D");

}

// Decimal numbers.
unittest
{
assertTranslates(q"C
#define decimalA 0.df
#define decimalB 1.dd
#define decimalC 2.dl
#define decimalD 3.DF
#define decimalE 0.DD
#define decimalF 1.DL
#define decimalG 1.0d
#define decimalH 1.0D
C", q"D
extern (C):

enum decimalA = 0.0f;
enum decimalB = 1.;
enum decimalC = 2.0L;
enum decimalD = 3.0F;
enum decimalE = 0.;
enum decimalF = 1.0L;
enum decimalG = 1.0;
enum decimalH = 1.0;
D");

}
Expand Down