Skip to content

Commit d8cdbe1

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 d433b89 commit d8cdbe1

File tree

8 files changed

+96
-9
lines changed

8 files changed

+96
-9
lines changed

analyser/module_analyser_expr.c2

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

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

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

383-
Expr* inner = c.getInner();
405+
inner = c.getInner();
384406
e.copyConstantFlags(inner);
407+
// TODO: this is probably incorrect: valType should be LValue for reinterpret
408+
// casts and RValue for conversion casts
385409
e.copyValType(inner);
386410
c.setDestType(destType);
387411

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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
133133
ExplicitCastExpr* c = cast<ExplicitCastExpr*>(e);
134134
out.add("((");
135135
gen.emitTypePre(out, c.getDestType());
136+
gen.emitTypePost(out, c.getDestType());
136137
if (c.getCStyle()) {
137138
out.add1(')');
138139
gen.emitExpr(out, c.getInner());
@@ -152,7 +153,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
152153
gen.emitExpr(out, b.getLHS());
153154
out.add(" ... ");
154155
gen.emitExpr(out, b.getRHS());
155-
return;
156+
break;
156157
}
157158
}
158159

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

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