Skip to content

Commit 41db61a

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 e80b1d4 commit 41db61a

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
@@ -377,12 +377,36 @@ fn QualType Analyser.analyseExplicitCast(Analyser* ma, Expr** e_ptr) {
377377
TypeRef* ref = c.getTypeRef();
378378
QualType destType = ma.analyseTypeRef(ref);
379379

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

382404
if (srcType.isInvalid() || destType.isInvalid()) return QualType_Invalid;
383405

384-
Expr* inner = c.getInner();
406+
inner = c.getInner();
385407
e.copyConstantFlags(inner);
408+
// TODO: this is probably incorrect: valType should be LValue for reinterpret
409+
// casts and RValue for conversion casts
386410
e.copyValType(inner);
387411
c.setDestType(destType);
388412

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
@@ -74,7 +74,7 @@ static_assert(elemsof(ExprKind), elemsof(exprKind_names));
7474

7575
/*
7676
An LValue may be on the left/right side of an assignment
77-
An RValue may only be on the left side
77+
An RValue may only be on the right side
7878
An NValue is an abstract object (cannot be used on either side)
7979

8080
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
}
168168
}
169169

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
@@ -526,16 +526,17 @@ fn Expr* Parser.parseParenExpr(Parser* p) {
526526
TypeRefHolder ref.init();
527527
p.parseTypeSpecifier(&ref);
528528
p.expectAndConsume(Kind.RParen);
529+
Expr* expr;
529530
if (p.tok.kind == Kind.LBrace) {
530531
// compound literal
531-
p.error("Compound literals are not supported");
532+
expr = p.parseInitList();
532533
} else {
533534
// C cast expression
534-
if (ref.isArray()) p.error("array types are not allowed here");
535-
Expr* expr = p.parseCastExpr(false, false);
536-
u32 src_len = p.prev_loc - loc;
537-
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
535+
if (ref.isArray()) p.error("cast to array type is invalid");
536+
expr = p.parseCastExpr(false, false);
538537
}
538+
u32 src_len = p.prev_loc - loc;
539+
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
539540
}
540541

541542
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)