Skip to content

Commit

Permalink
Make hex strings implicitly convert to integer arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
dkorpel authored and thewilsonator committed Mar 3, 2024
1 parent 552315e commit 9da69ee
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 38 deletions.
16 changes: 6 additions & 10 deletions changelog/dmd.hexstring-cast.dd
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
Hex strings can now be cast to integer arrays
Hex strings now convert to integer arrays

Hex strings are the most efficient way to embed binary data into source files.
However, they couldn't easily be used to initialize a `short[]`, `int[]` or `long[]` because re-interpret casting arrays is not allowed during CTFE.
Now, hex strings can be cast to integer arrays with element types larger than `byte`.
Now, hex strings implicitly convert to all integer arrays.
A big endian byte order is assumed, consistent with how integer literals are written.

---
immutable uint[] data = cast(immutable uint[]) x"AABBCCDD";
immutable uint[] data = x"AABBCCDD";

static assert(data[0] == 0xAABBCCDD);
---

Character postfixes can now also be used for integers of size 2 or 4, while an `L` postfix can be used for size 8:
Character postfixes can now also be used to explicitly set an element size of 2 or 4.

---
immutable ushort[] f = x"80 3F"w;
static assert(f[0] == 0x803F);

immutable int[] g = x"80 35 FF FD"d;
static assert(g[0] == 0x803FFFFD);

auto h = x"0011 2233 4455 6677"L;
static assert(h[0] == 0x0011_2233_4455_6677);
static assert(is(typeof(h) == immutable ulong[]));
immutable ubyte[] g = x"80 35"w; // error: size mismatch
---

Formerly, they would pad each byte with 1 or 3 zeros, which did not serve a purpose (See [Issue 24363](https://issues.dlang.org/show_bug.cgi?id=24363)).
Expand Down
29 changes: 18 additions & 11 deletions compiler/src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,11 @@ MATCH implicitConvTo(Expression e, Type t)
return MATCH.nomatch;
m = MATCH.constant;
}
if (e.hexString && tn.isintegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
{
m = MATCH.convert;
return m;
}
if (!e.committed)
{
switch (tn.ty)
Expand All @@ -719,9 +724,6 @@ MATCH implicitConvTo(Expression e, Type t)
if (e.postfix != 'd')
m = MATCH.convert;
return m;
case Tint8:
case Tuns8:
break;
case Tenum:
if (tn.isTypeEnum().sym.isSpecial())
{
Expand All @@ -735,14 +737,6 @@ MATCH implicitConvTo(Expression e, Type t)
break;
}
}
if (e.hexString)
{
if (tn.isintegral && tn.size == e.sz)
{
m = MATCH.convert;
return m;
}
}
break;

default:
Expand Down Expand Up @@ -1884,6 +1878,19 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
Type tb = t.toBasetype();
Type typeb = e.type.toBasetype();

if (e.hexString && !e.committed)
{
const szx = cast(ubyte) tb.nextOf().size();
if (szx != se.sz && (e.len % szx) == 0)
{
import dmd.utils: arrayCastBigEndian;
const data = cast(const ubyte[]) e.peekString();
se.setData(arrayCastBigEndian(data, szx).ptr, data.length / szx, szx);
se.type = t;
return se;
}
}

//printf("\ttype = %s\n", e.type.toChars());
if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
{
Expand Down
11 changes: 5 additions & 6 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4245,22 +4245,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

if (e.hexString)
{
const data = cast(const ubyte[]) e.peekString();
const data = cast(const ubyte[]) e.peekString(); // peek before size is set to something larger than 1
switch (e.postfix)
{
case 'L':
e.sz = 8;
e.type = Type.tuns64.immutableOf().arrayOf();
break;
case 'd':
e.committed = true;
e.sz = 4;
e.type = Type.tdstring;
break;
case 'w':
e.committed = true;
e.sz = 2;
e.type = Type.twstring;
break;
case 'c':
e.committed = true;
goto default;
default:
e.type = Type.tstring;
e.sz = 1;
Expand All @@ -4271,7 +4271,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type.toChars(), e.sz, cast(int) e.len);

e.setData(arrayCastBigEndian(data, e.sz).ptr, e.len / e.sz, e.sz);
e.committed = true;
}
else switch (e.postfix)
{
Expand Down
6 changes: 0 additions & 6 deletions compiler/src/dmd/lexer.d
Original file line number Diff line number Diff line change
Expand Up @@ -1569,12 +1569,6 @@ class Lexer
}
t.setString(stringbuffer);
stringPostfix(t);
if (*p == 'L')
{
t.postfix = 'L';
p++;
}

return TOK.hexadecimalString;
default:
if (c >= '0' && c <= '9')
Expand Down
3 changes: 2 additions & 1 deletion compiler/test/fail_compilation/hexstring.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(
fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string
fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5
fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"44332211"d` of type `dstring` to `immutable(float[])`
fail_compilation/hexstring.d(42): Error: cannot implicitly convert expression `x"2211"w` of type `wstring` to `immutable(ubyte[])`
fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]`
---
*/

immutable ubyte[] s0 = x"123F";
static assert(s0[0] == 0x12);
static assert(s0[1] == 0x3F);
Expand All @@ -39,3 +39,4 @@ immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ "");
immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c;
immutable uint[] f12 = x"1122334455"d;
immutable float[] f13 = x"11223344"d;
immutable ubyte[] f14 = x"1122"w;
7 changes: 3 additions & 4 deletions compiler/test/runnable/literal.d
Original file line number Diff line number Diff line change
Expand Up @@ -247,14 +247,13 @@ void testHexstring()
static assert(x[0] == 0xFFAADDEE);
assert(x[0] == 0xFFAADDEE);

static assert(is(typeof(x""L) == immutable(ulong)[]));
static immutable ulong[] y = x"1122334455667788AABBCCDDEEFF0099"L;
static immutable ulong[] y = x"1122334455667788AABBCCDDEEFF0099";
static assert(y[0] == 0x1122334455667788);
static assert(y[1] == 0xAABBCCDDEEFF0099);
assert(y[0] == 0x1122334455667788);
assert(y[1] == 0xAABBCCDDEEFF0099);

immutable long[] c = x"1122334455667788AABBCCDDEEFF0099"L;
immutable long[] c = x"1122334455667788AABBCCDDEEFF0099";
assert(c[0] == 0x1122334455667788);
assert(c[1] == 0xAABBCCDDEEFF0099);

Expand All @@ -264,7 +263,7 @@ void testHexstring()

// Test printing StringExp with size 8
enum toStr(immutable ulong[] v) = v.stringof;
static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"L`);
static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`);

// Hex string postfixes
// https://issues.dlang.org/show_bug.cgi?id=24363
Expand Down

0 comments on commit 9da69ee

Please sign in to comment.