diff --git a/dstep/translator/MacroDefinition.d b/dstep/translator/MacroDefinition.d index 1775c982..5382822f 100644 --- a/dstep/translator/MacroDefinition.d +++ b/dstep/translator/MacroDefinition.d @@ -188,6 +188,11 @@ string translate(CallExpr expression, ExpressionContext context) expression.args.map!fmap.join(", ")); } +string translate(BracedExpr expr, ExpressionContext context) +{ + return "null /* FIXME: " ~ expr.expr ~ " */"; +} + string translate(Expression expression, ExpressionContext context) { import std.format : format; @@ -350,6 +355,10 @@ string translate(Expression expression, ExpressionContext context) condExpr.expr.translate(context), condExpr.left.translate(context), condExpr.right.translate(context)); + }, + delegate string(BracedExpr expr) + { + return expr.translate(context); }); } diff --git a/dstep/translator/MacroParser.d b/dstep/translator/MacroParser.d index 8f3686e5..a6851bf0 100644 --- a/dstep/translator/MacroParser.d +++ b/dstep/translator/MacroParser.d @@ -503,6 +503,23 @@ class CondExpr } } +struct BracedExpr +{ + string expr; + + this (string expr) + { + this.expr = expr; + } + + string toString() + { + import std.format : format; + + return format("BracedExpr(expr = %s)", expr); + } +} + alias Expression = Algebraic!( Identifier, TypeIdentifier, @@ -530,7 +547,8 @@ alias Expression = Algebraic!( OrExpr, LogicalAndExpr, LogicalOrExpr, - CondExpr); + CondExpr, + BracedExpr); Expression debraced(Expression expression) { @@ -1032,6 +1050,40 @@ Expression parseCondExpr(ref Token[] tokens, Cursor[string] table, bool defined) return expr; } +Expression parseBracedExpr(ref Token[] tokens) +{ + if (tokens.empty) + return Expression.init; + + auto local = tokens; + + while (local.length >= 2 && + acceptPunctuation!("(")(local) && + local[$ - 1].kind == TokenKind.punctuation && + local[$ - 1].spelling == ")") + { + local = local[0 .. $ - 1]; + } + + if (!local.empty && + local.front.kind == TokenKind.punctuation && + local.front.spelling == "{" && + local.back.kind == TokenKind.punctuation && + local.back.spelling == "}") + { + auto buffer = appender!string(); + foreach (token; tokens) + { + buffer.put(token.spelling); + } + auto expr = Expression(BracedExpr(buffer.data)); + tokens = []; + return expr; + } + + return Expression.init; +} + bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] table) { import std.meta : AliasSeq; @@ -1430,6 +1482,10 @@ Expression parseExpr(ref Token[] tokens, Cursor[string] table, bool defined) if (condExpr.hasValue) return condExpr; + auto bracedExpr = parseBracedExpr(tokens); + if (bracedExpr.hasValue) + return bracedExpr; + return Expression.init; } @@ -1437,7 +1493,7 @@ Expression parseExpr(ref Token[] tokens, bool defined) { Cursor[string] table; - return parseCondExpr(tokens, table, defined); + return parseExpr(tokens, table, defined); } Expression parseEnumMember(Token[] tokens, Cursor[string] table) diff --git a/dstep/translator/TypeInference.d b/dstep/translator/TypeInference.d index 65934f16..3951760f 100644 --- a/dstep/translator/TypeInference.d +++ b/dstep/translator/TypeInference.d @@ -234,6 +234,10 @@ InferredType inferExpressionType(Expression expression) return commonType( condExpr.left.inferExpressionType(), condExpr.right.inferExpressionType()); + }, + delegate InferredType(BracedExpr objectExpr) + { + return InferredType(Generic.init); }); } diff --git a/tests/unit/MacroParsingTests.d b/tests/unit/MacroParsingTests.d index a77a1afc..28fa6ef5 100644 --- a/tests/unit/MacroParsingTests.d +++ b/tests/unit/MacroParsingTests.d @@ -84,6 +84,37 @@ unittest assert(d !is null && d.expr.hasValue && d.expr.peek!CallExpr !is null); } +unittest +{ + auto a = parse(`#define NESTED { .inner = { 1, 2 } }`); + assert(a !is null); + assert(a.expr.hasValue); + assert(a.expr.peek!BracedExpr !is null); + auto braced1 = a.expr.get!BracedExpr; + assert(braced1.expr == `{.inner={1,2}}`); + + auto b = parse(`#define MAKE(a) { .data = (a) }`); + assert(b !is null); + assert(b.expr.hasValue); + assert(b.expr.peek!BracedExpr !is null); + auto braced2 = b.expr.get!BracedExpr; + assert(braced2.expr == `{.data=(a)}`); + + auto c = parse(`#define UUID { 0x5ae69b6a, 0xd191, 0x4609, {0xb7, 0xdc, 0x24, 0x80, 0x8e, 0xf9, 0x97, 0xb5 } }`); + assert(c !is null); + assert(c.expr.hasValue); + assert(c.expr.peek!BracedExpr !is null); + auto braced3 = c.expr.get!BracedExpr; + assert(braced3.expr == `{0x5ae69b6a,0xd191,0x4609,{0xb7,0xdc,0x24,0x80,0x8e,0xf9,0x97,0xb5}}`); + + auto d = parse(`#define D (({ {1, 2}, {3, 4} }))`); + assert(d !is null); + assert(d.expr.hasValue); + assert(d.expr.peek!BracedExpr !is null); + auto braced4 = d.expr.get!BracedExpr; + assert(braced4.expr == `(({{1,2},{3,4}}))`); +} + // Test collection of type names. unittest { diff --git a/tests/unit/MacroTranslTests.d b/tests/unit/MacroTranslTests.d index 6a7cb3c3..a5c59954 100644 --- a/tests/unit/MacroTranslTests.d +++ b/tests/unit/MacroTranslTests.d @@ -841,3 +841,33 @@ extern (D) auto fun(T)(auto ref T a) } D"); } + +unittest +{ + assertTMD(q"C +#define NESTED { .inner = { 1, 2 } } +C", q"D +enum NESTED = null /* FIXME: {.inner={1,2}} */; +D"); + + assertTMD(q"C +#define INIT(val) { .data = (val), .len = sizeof(val) } +C", q"D +extern (D) auto INIT(T)(auto ref T val) +{ + return null /* FIXME: {.data=(val),.len=sizeof(val)} */; +} +D"); + + assertTMD(q"C +#define UUID { 0x5ae69b6a, 0xd191, 0x4609, {0xb7, 0xdc, 0x24, 0x80, 0x8e, 0xf9, 0x97, 0xb5 } } +C", q"D +enum UUID = null /* FIXME: {0x5ae69b6a,0xd191,0x4609,{0xb7,0xdc,0x24,0x80,0x8e,0xf9,0x97,0xb5}} */; +D"); + + assertTMD(q"C +#define D (({ {1, 2}, {3, 4} })) +C", q"D +enum D = null /* FIXME: (({{1,2},{3,4}})) */; +D"); +}