Skip to content

Commit f60f1ac

Browse files
committed
compiler: extend cast syntax for initlists
* parse compound cast expressions: depending on surrounding code, explicit casts can be more readable than implicit conversions as function arguments or return values. * add tests.
1 parent 86dfff8 commit f60f1ac

File tree

8 files changed

+96
-10
lines changed

8 files changed

+96
-10
lines changed

analyser/module_analyser_expr.c2

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,36 @@ fn QualType Analyser.analyseExplicitCast(Analyser* ma, Expr** e_ptr) {
384384
TypeRef* ref = c.getTypeRef();
385385
QualType destType = ma.analyseTypeRef(ref);
386386

387+
Expr* inner = c.getInner();
388+
if (inner.isInitList()) {
389+
InitListExpr* initList = cast<InitListExpr*>(inner);
390+
if (destType.isInvalid())
391+
return QualType_Invalid;
392+
if (destType.isArray() || destType.isStruct()) {
393+
if (!ma.analyseInitListExpr(initList, destType))
394+
return QualType_Invalid;
395+
} else {
396+
u32 num_values = initList.getNumValues();
397+
Expr** values = initList.getValues();
398+
if (num_values != 1 || values[0].isInitList()) {
399+
ma.error(inner.getLoc(), "invalid initializer");
400+
return QualType_Invalid;
401+
}
402+
if (!ma.analyseInitExpr(&values[0], destType, values[0].getLoc(), false, false))
403+
return QualType_Invalid;
404+
}
405+
e.setLValue();
406+
c.setDestType(destType);
407+
return destType;
408+
}
387409
QualType srcType = ma.analyseExpr(c.getInner2(), true, RHS);
388410

389411
if (srcType.isInvalid() || destType.isInvalid()) return QualType_Invalid;
390412

391-
Expr* inner = c.getInner();
413+
inner = c.getInner();
392414
e.copyConstantFlags(inner);
415+
// TODO: this is probably incorrect: valType should be LValue for reinterpret
416+
// casts and RValue for conversion casts
393417
e.copyValType(inner);
394418
c.setDestType(destType);
395419

ast/explicit_cast_expr.c2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public fn ExplicitCastExpr* ExplicitCastExpr.create(ast_context.Context* c,
3939
{
4040
u32 size = sizeof(ExplicitCastExpr) + ref.getExtraSize();
4141
ExplicitCastExpr* e = c.alloc(size);
42+
// TODO ValType.LValue for compound
4243
e.base.init(ExprKind.ExplicitCast, loc, 0, 0, 0, ValType.NValue);
4344
e.base.base.explicitCastExprBits.c_style = c_style;
4445
e.base.base.explicitCastExprBits.src_len = src_len;

ast/expr.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static_assert(elemsof(ExprKind), elemsof(exprKind_names));
7676

7777
/*
7878
An LValue may be on the left/right side of an assignment
79-
An RValue may only be on the left side
79+
An RValue may only be on the right side
8080
An NValue is an abstract object (cannot be used on either side)
8181

8282
Lvalue:

generator/c/c_generator_expr.c2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fn void Generator.emitExpr2(Generator* gen, string_buffer.Buf* out, Expr* e, C_P
140140
case ExplicitCast:
141141
ExplicitCastExpr* c = (ExplicitCastExpr*)e;
142142
if (prec > Prefix) out.lparen();
143-
gen.emitCast(out, c.getDestType(), false);
143+
gen.emitCast(out, c.getDestType(), true);
144144
if (c.getCStyle()) {
145145
gen.emitExpr2(out, c.getInner(), Prefix);
146146
} else {
@@ -163,7 +163,7 @@ fn void Generator.emitExpr2(Generator* gen, string_buffer.Buf* out, Expr* e, C_P
163163
out.add(" ... ");
164164
gen.emitExpr(out, b.getRHS());
165165
if (prec > Assignment) out.rparen();
166-
return;
166+
break;
167167
case NamedArgument:
168168
NamedArgument* n = (NamedArgument*)e;
169169
gen.emitExpr(out, n.getInner());

generator/ir/ir_generator_expr.c2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ fn void Generator.emitExpr(Generator* gen, ir.Ref* result, const Expr* e) {
9090
break;
9191
case ExplicitCast:
9292
ExplicitCastExpr* ec = (ExplicitCastExpr*)e;
93+
if (ec.getInner().isInitList()) {
94+
assert(0); // TODO
95+
break;
96+
}
9397
gen.emitExpr(result, ec.getInner());
9498
break;
9599
case ImplicitCast:

parser/c2_parser_expr.c2

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,16 +535,17 @@ fn Expr* Parser.parseParenExpr(Parser* p) {
535535
TypeRefHolder ref.init();
536536
p.parseTypeSpecifier(&ref);
537537
p.expectAndConsume(Kind.RParen);
538+
Expr* expr;
538539
if (p.tok.kind == Kind.LBrace) {
539540
// compound literal
540-
p.error("Compound literals are not supported");
541+
expr = p.parseInitList();
541542
} else {
542543
// C cast expression
543-
if (ref.isArray()) p.error("array types are not allowed here");
544-
Expr* expr = p.parseCastExpr(false, false);
545-
u32 src_len = p.prev_loc - loc;
546-
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
544+
if (ref.isArray()) p.error("cast to array type is invalid");
545+
expr = p.parseCastExpr(false, false);
547546
}
547+
u32 src_len = p.prev_loc - loc;
548+
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
548549
}
549550

550551
Expr* res = p.parseExpr();

test/expr/explicit_cast/explicit_c_cast_array.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
module test;
33

44
fn void test1a(i32 a) {
5-
char[2] b1 = (char[2])(a); // @error{array types are not allowed here}
5+
char[2] b1 = (char[2])(a); // @error{cast to array type is invalid}
66
}
77

test/literals/compound_literals.c2

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// @warnings{no-unused}
2+
module test;
3+
4+
import stdio local;
5+
6+
type Foo struct {
7+
i32 x;
8+
i32 y;
9+
}
10+
11+
fn void test_foo(Foo foo) {}
12+
fn void Foo.bar(Foo* foo) {}
13+
fn Foo Foo.create(i32 x, i32 y) { return (Foo){ x, y }; }
14+
15+
fn i32 sum(i32 *p, u32 count) {
16+
i32 total = 0;
17+
for (i32 i = 0; i < count; i++) total += p[i];
18+
return total;
19+
}
20+
21+
public fn i32 main() {
22+
Foo[] foos = {
23+
{ },
24+
{ 0, 1 },
25+
(Foo){ 1, 2 },
26+
(Foo){ .x = 2, .y = 3 },
27+
[4] = { },
28+
[5] = { 3, 4 },
29+
[6] = (Foo){ 4, 5 },
30+
[7] = (Foo){ .x = 5, .y = 6 },
31+
}
32+
33+
test_foo({});
34+
test_foo({ 1, 2 });
35+
test_foo({ .x = 1, .y = 2 });
36+
test_foo((Foo){});
37+
test_foo((Foo){ 1, 2 });
38+
test_foo((Foo){ .x = 1, .y = 2 });
39+
40+
foos[0].bar();
41+
(Foo){1, 2}.bar();
42+
43+
printf("%d\n", sum((i32[]){ 1 }, 1));
44+
printf("%d\n", sum((i32[]){ 1, 2 }, 2));
45+
printf("%d\n", sum((i32[]){ 1, 2, 3 }, 3));
46+
printf("%d\n", sum((i32[1]){ 1 }, 1));
47+
printf("%d\n", sum((i32[2]){ 1, 2 }, 2));
48+
printf("%d\n", sum((i32[10]){ 1, 2, 3 }, 10));
49+
50+
// Enable these tests once arrays are implied for pointer arguments
51+
//printf("%d\n", sum({ 1 }, 1));
52+
//printf("%d\n", sum({ 1, 2 }, 2));
53+
//printf("%d\n", sum({ 1, 2, 3 }, 3));
54+
55+
return 0;
56+
}

0 commit comments

Comments
 (0)