Skip to content

Commit 0df9d2d

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 11eb436 commit 0df9d2d

File tree

9 files changed

+100
-11
lines changed

9 files changed

+100
-11
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()))
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: 2 additions & 1 deletion
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;
@@ -81,7 +82,7 @@ fn SrcLoc ExplicitCastExpr.getEndLoc(const ExplicitCastExpr* e) {
8182
return e.base.base.loc + e.base.base.explicitCastExprBits.src_len;
8283
}
8384

84-
fn void ExplicitCastExpr.printLiteral(const ExplicitCastExpr* e, string_buffer.Buf* out) {
85+
public fn void ExplicitCastExpr.printLiteral(const ExplicitCastExpr* e, string_buffer.Buf* out) {
8586
if (e.base.base.explicitCastExprBits.c_style) {
8687
out.add1('(');
8788
e.dest.print(out, true);

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/c2i_generator_expr.c2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ fn void Generator.emitExpr(Generator* gen, const Expr* e) {
106106
case BitOffset:
107107
break;
108108
case ExplicitCast:
109-
break;
109+
ExplicitCastExpr.printLiteral(cast<ExplicitCastExpr*>(e), out);
110+
return;
110111
case ImplicitCast:
111112
const ImplicitCastExpr* c = cast<ImplicitCastExpr*>(e);
112113
gen.emitExpr(c.getInner());

generator/c/c_generator_expr.c2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
130130
ExplicitCastExpr* c = cast<ExplicitCastExpr*>(e);
131131
out.add("((");
132132
gen.emitTypePre(out, c.getDestType());
133+
gen.emitTypePost(out, c.getDestType());
133134
if (c.getCStyle()) {
134135
out.add1(')');
135136
gen.emitExpr(out, c.getInner());
@@ -149,7 +150,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
149150
gen.emitExpr(out, b.getLHS());
150151
out.print(" ... ");
151152
gen.emitExpr(out, b.getRHS());
152-
return;
153+
break;
153154
}
154155
}
155156

generator/ir/ir_generator_expr.c2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ fn void Generator.emitExpr(Generator* gen, ir.Ref* result, const Expr* e) {
105105
break;
106106
case ExplicitCast:
107107
ExplicitCastExpr* ec = cast<ExplicitCastExpr*>(e);
108+
if (ec.getInner().isInitList()) {
109+
assert(0); // TODO
110+
break;
111+
}
108112
gen.emitExpr(result, ec.getInner());
109113
break;
110114
case ImplicitCast:

parser/c2_parser_expr.c2

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,16 +527,18 @@ 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)
537+
p.error("cast to array type is invalid");
538+
expr = p.parseCastExpr(false, false);
539539
}
540+
u32 src_len = p.prev_loc - loc;
541+
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
540542
}
541543

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