From 3c69bf1b9a5a23bb8c36f4028f8943ea940bd5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mos=C4=81ns?= Date: Sun, 8 Mar 2026 22:10:33 +0200 Subject: [PATCH 1/2] Fix integers with LL suffix Consider a.h with: ```c #define LARGE 3LL ``` Currently dstep would produce: ```d extern (C): enum LARGE = 3LL; ``` Which is not valid D code because D language doesn't have LL suffix. This PR fixes this so such case will become: ```d extern (C): enum LARGE = 3L; ``` --- dstep/translator/MacroDefinition.d | 51 ++++++++++++++++++++----- tests/unit/UnitTests.d | 61 ++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 9 deletions(-) diff --git a/dstep/translator/MacroDefinition.d b/dstep/translator/MacroDefinition.d index 1775c982..af23fb0b 100644 --- a/dstep/translator/MacroDefinition.d +++ b/dstep/translator/MacroDefinition.d @@ -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; @@ -87,27 +88,59 @@ 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; +} + 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 == '-'); + alias pred = (dchar x) => (x == 'u' || x == 'U' || x == 'l' || x == 'L' || + x == 'f' || x == 'F'); + auto number = literal.spelling.stripRight!pred; + auto suffix = literal.spelling[number.length .. $]; + + 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) diff --git a/tests/unit/UnitTests.d b/tests/unit/UnitTests.d index 87acea3c..59fcab65 100644 --- a/tests/unit/UnitTests.d +++ b/tests/unit/UnitTests.d @@ -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; @@ -1051,6 +1052,66 @@ 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"); } From 194d14659369ef9e76978d7bd9e463e02745654a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mos=C4=81ns?= Date: Mon, 22 Jun 2026 21:11:29 +0300 Subject: [PATCH 2/2] Support macros with decimals (eg. `1.dd`) --- dstep/translator/MacroDefinition.d | 34 +++++++++++++-- tests/unit/UnitTests.d | 66 ++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/dstep/translator/MacroDefinition.d b/dstep/translator/MacroDefinition.d index af23fb0b..c47f63dc 100644 --- a/dstep/translator/MacroDefinition.d +++ b/dstep/translator/MacroDefinition.d @@ -120,16 +120,42 @@ private string normalizeDot(string number, string suffix) 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; - alias pred = (dchar x) => (x == 'u' || x == 'U' || x == 'l' || x == 'L' || - x == 'f' || x == 'F'); - auto number = literal.spelling.stripRight!pred; - auto suffix = literal.spelling[number.length .. $]; + 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); auto uinteger = number.stripLeft!(x => x == '+' || x == '-'); diff --git a/tests/unit/UnitTests.d b/tests/unit/UnitTests.d index 59fcab65..d019ce89 100644 --- a/tests/unit/UnitTests.d +++ b/tests/unit/UnitTests.d @@ -1116,6 +1116,72 @@ 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"); + +} + @("public global import") unittest {