Skip to content

Commit 1c8c32c

Browse files
committed
parser: accept generalized types and expressions in sizeof
* Use case of identifier to resolve ambiguity at parse time for `sizeof(a[x])`: * accept `sizeof(Name[10])` as size of array of 10 objects of type `Name` * and `sizeof(name[10])` as size of array element `name[10]` * if `Name` is a global constant array, this will generate an error as `Name` is not a type, but this case is unlikely to occur in regular code. fixes #210
1 parent 0644c56 commit 1c8c32c

File tree

4 files changed

+71
-58
lines changed

4 files changed

+71
-58
lines changed

parser/c2_parser_expr.c2

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -599,32 +599,16 @@ fn Expr* Parser.parseSizeof(Parser* p) {
599599
p.expectAndConsume(Kind.LParen);
600600

601601
Expr* res = nil;
602-
bool has_brackets = false;
603602
SrcLoc type_loc = p.tok.loc;
604-
if (p.parseAsType(&has_brackets)) {
605-
if (has_brackets) {
606-
while (p.tok.kind != Kind.LSquare) p.consumeToken();
607-
p.error("arrays or subscripts expressions are not allowed inside a sizeof expression");
608-
}
609-
TypeRefHolder ref.init();
610-
p.parseTypeSpecifier(&ref, false, true);
603+
if (p.parseAsType()) {
604+
TypeRefHolder ref;
605+
ref.init();
606+
p.parseTypeSpecifier(&ref, true, true);
611607
u32 src_len = p.prev_loc - type_loc;
612608
res = p.builder.actOnTypeExpr(type_loc, src_len, &ref);
613-
} else { // parse as variable
614-
if (p.tok.kind != Kind.Identifier) {
615-
p.error("expect a type or variable name");
616-
}
617-
res = p.parseFullIdentifier();
618-
619-
// parse optional array indexes (like array[0])
620-
while (p.tok.kind == Kind.LSquare) {
621-
SrcLoc loc1 = p.tok.loc;
622-
p.consumeToken();
623-
Expr* idx = p.parseExpr();
624-
u32 src_len = p.tok.loc + 1 - loc1;
625-
p.expectAndConsume(Kind.RSquare);
626-
res = p.builder.actOnArraySubscriptExpr(loc1, src_len, res, idx);
627-
}
609+
} else {
610+
// parse as expression
611+
res = p.parseExpr();
628612
}
629613

630614
u32 src_len = p.tok.loc + 1 - loc;
@@ -807,11 +791,9 @@ fn Expr* Parser.parseFullIdentifier(Parser* p) {
807791
/*
808792
parsing sizeof() is nasty, since the inner argument can be either an Expr or a Type!
809793

810-
The reason we forbid brackets [] inside a sizeof is that its ambiguous; it can be
811-
an array (eg Foo[2]) or a subscript expression (a[2]). Also there is no real reason
812-
to keep them. Keep it simple.
813-
814-
also: Foo can be type or Constant, just return Identifier (or Member if prefixed)
794+
The reason we test brackets [] inside a sizeof is that it is potentially ambiguous;
795+
it can be an array (eg Foo[2]) or a subscript expression (a[2]). We assume Foo to be
796+
a type, but it could be a global Constant, in which case an error will be generated later.
815797

816798
i8,u8,. - type
817799
X* - type
@@ -822,41 +804,67 @@ fn Expr* Parser.parseFullIdentifier(Parser* p) {
822804
test.Foo - member (upper case, can be Constant or Type)
823805
f.a - member (lower case)
824806
test.f.a - member (lower case)
825-
Foo[..] - error ([] not allowed)
826-
test.Foo[..] - error ([] not allowed)
827-
(test.)a[..] - error ([] not allowed)
828-
Foo.a - error (need instantiation)
829-
test.Foo.a - error (need instantiation)
830-
(test.)a* - type (but will give error later)
807+
Foo[..] - can be Constant element or Type array, assume Type array
808+
test.Foo[..] - can be Constant element or Type array, assume Type array
809+
a[..] - subscript expression
810+
test.a[..] - subscript expression
811+
Foo.a - error (need instantiation, should accept as extension)
812+
test.Foo.a - error (need instantiation, should accept as extension)
813+
a* - type (but will give error later)
814+
test.a* - type (but will give error later)
831815
*/
832-
fn bool Parser.parseAsType(Parser* p, bool* has_brackets) {
833-
const Kind kind = p.tok.kind;
816+
fn bool Parser.parseAsType(Parser* p) {
817+
Token t2 = p.tok;
818+
bool is_lower = false;
819+
u32 ahead = 1;
820+
821+
Kind kind = t2.kind;
834822
if (kind.isQualifier()) return true;
835823
if (p.tok.kind != Kind.Identifier) {
836824
if (kind.isBuiltinType())
837825
return (p.tokenizer.lookahead(1, nil) != Kind.Dot);
838826
}
839827

840-
u32 lookahead = 1;
841-
while (1) {
842-
switch (p.tokenizer.lookahead(lookahead, nil)) {
843-
case Identifier:
828+
// parse member list
829+
for (;;) {
830+
// is_lower is true if the last identifier starts with a lowercase letter
831+
is_lower = islower(p.pool.idx2str(t2.name_idx)[0]);
832+
if (p.tokenizer.lookahead(ahead, nil) != Kind.Dot)
844833
break;
834+
ahead++;
835+
if (p.tokenizer.lookahead(ahead, &t2) != Kind.Identifier)
836+
return false;
837+
ahead++;
838+
}
839+
i32 stars = 0;
840+
while (1) {
841+
switch (p.tokenizer.lookahead(ahead, nil)) {
845842
case Star:
846-
return true;
847-
case Dot:
843+
if (stars) return true; // sizeof(a**...)
844+
stars++;
845+
ahead++;
848846
break;
847+
case RParen:
848+
if (stars) return true; // sizeof(a.b*)
849+
return false; // unknown
849850
case LSquare:
850-
*has_brackets = true;
851+
if (stars) return true; // sizeof(MyType*[...])
852+
// if last identifier starts with lowercase, it must be a variable
853+
// hence reject as type and parse as expression
854+
if (is_lower) return false;
855+
// otherwise cannot distinguish typename from global constant
856+
// let's assume capitalized name is type (eg: sizeof(MyType[20]))
857+
// cannot handle sizeof(GlobalConst[0])
851858
return true;
852859
case Less:
853-
return true;
860+
// parametric type sizeof(Type<X>)
861+
if (is_lower) return false;
862+
return true; // sizeof(a < b)
854863
default:
855864
return false;
856865
}
857-
lookahead++;
858866
}
859-
867+
// never reached
860868
return false;
861869
}
862870

test/expr/sizeof/array.c2

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

44
type Handle struct { i32 x; }
55

6-
i32 f = sizeof(Handle[3]); // @error{arrays or subscripts expressions are not allowed inside a sizeof expression}
6+
i32 f = sizeof(Handle[3]);
77

8+
static_assert(sizeof(Handle[3]), 12);

test/parser/sizeof_addrof.c2

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
// @warnings{no-unused}
22
module test;
33

4+
i32 aa = 10;
5+
i32 cc = sizeof(&aa);
6+
static_assert(sizeof(&aa), sizeof(usize));
7+
48
fn void test1() {
59
i32 a = 10;
6-
i32 c = sizeof(&a); // @error{expect a type or variable name}
10+
i32 c = sizeof(&a);
711
}
812

test/parser/sizeof_expr_ok.c2

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,33 +48,33 @@ static_assert(sizeof(MyStruct*), sizeof(usize));
4848
static_assert(sizeof(MyStruct*), sizeof(sp));
4949
static_assert(sizeof(sp), sizeof(MyStruct*));
5050
static_assert(sizeof(sp), sizeof(sp));
51-
//static_assert(sizeof(const MyStruct[10]), sizeof(MyStruct) * 10);
52-
//static_assert(sizeof(MyStruct[10]), sizeof(MyStruct) * 10);
51+
static_assert(sizeof(const MyStruct[10]), sizeof(MyStruct) * 10);
52+
static_assert(sizeof(MyStruct[10]), sizeof(MyStruct) * 10);
5353
static_assert(sizeof(s), 32);
54-
//static_assert(sizeof(*&s), 32);
54+
static_assert(sizeof(*&s), 32);
5555
static_assert(sizeof(s), sizeof(s));
5656
static_assert(sizeof(s), sizeof(MyStruct));
57-
//static_assert(sizeof(s), sizeof(MyStruct[1]));
57+
static_assert(sizeof(s), sizeof(MyStruct[1]));
5858
static_assert(sizeof(MyStruct), sizeof(s));
5959
static_assert(sizeof(MyStruct), sizeof(MyStruct));
6060
static_assert(32, sizeof(MyStruct));
6161
static_assert(sizeof(s.p), sizeof(usize));
6262
static_assert(sizeof(s.def), 16);
63-
//static_assert(sizeof(*s.def), 1);
64-
//static_assert(sizeof(s.def[1]), 1);
63+
static_assert(sizeof(*s.def), 1);
64+
static_assert(sizeof(s.def[1]), 1);
6565

6666
i32[20] aa;
6767

6868
static_assert(sizeof(aa), 80);
69-
//static_assert(sizeof(aa[0]), 4);
70-
//static_assert(sizeof(*aa), 4);
69+
static_assert(sizeof(aa[0]), 4);
70+
static_assert(sizeof(*aa), 4);
7171

7272
i32 cond = 1;
7373

7474
static_assert(sizeof(cond), 4);
75-
//static_assert(sizeof(cond + cond), 4);
75+
static_assert(sizeof(cond + cond), 4);
7676

7777
const char[] Error = "error";
7878

7979
static_assert(sizeof(Error), 6);
80-
//static_assert(sizeof(*Error), 1);
80+
static_assert(sizeof(*Error), 1);

0 commit comments

Comments
 (0)