diff options
| -rw-r--r-- | bootstrap/all.h | 2 | ||||
| -rw-r--r-- | bootstrap/parse.c | 46 | ||||
| -rw-r--r-- | bootstrap/test.cff | 1 | ||||
| -rw-r--r-- | src/cffc.hff | 4 | ||||
| -rw-r--r-- | src/common.hff | 5 | ||||
| -rw-r--r-- | src/parse.cff | 18 |
6 files changed, 63 insertions, 13 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index 34bab40..1bfe919 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -30,6 +30,7 @@ struct span { /* must be alpha sorted */ #define LIST_KEYWORDS(_) \ + _(alignof) \ _(and) \ _(as) \ _(break) \ @@ -47,6 +48,7 @@ struct span { _(if) \ _(import) \ _(let) \ + _(offsetof) \ _(or) \ _(return) \ _(sizeof) \ diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 0abaf45..31469df 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -907,8 +907,10 @@ structidx2fld(const struct type *ty, int idx) { } static int -structfldnam2idx(const struct type *ty, const char *name) { +aggfldnam2idx(const struct type *ty, const char *name) { assert(name); + if (ty->t != TYunion && ty->t != TYstruct && ty->t != TYeunion) + return -1; for (int i = 0; i < ty->agg.flds.n; ++i) if (!strcmp(name, ty->agg.flds.d[i].name)) return i; @@ -917,7 +919,7 @@ structfldnam2idx(const struct type *ty, const char *name) { static struct aggfield * findaggfield(const struct type *ty, const char *name) { - int i = structfldnam2idx(ty, name); + int i = aggfldnam2idx(ty, name); return i < 0 ? NULL : &ty->agg.flds.d[i]; } @@ -957,7 +959,7 @@ parsestructini(struct parser *P, const struct type *ty) { if (lexmatch(P, &tok, '.')) { const char *fnam = (tok = lexexpect(P, TKident)).str; lexexpect(P, ':'); - idx = structfldnam2idx(ty, fnam); + idx = aggfldnam2idx(ty, fnam); if (idx < 0) fatal(P, tok.span, "%s %t has no field `%s'", kind, ty, fnam); } @@ -1225,7 +1227,7 @@ pexprimary(struct parser *P) { ex.span = tok.span; } else if (lexmatch(P, &tok, TKkw_sizeof)) { ex.t = Eintlit; - ex.ty = ty_isize; + ex.ty = ty_usize; if (lexmatch(P, &tok, '(')) { struct expr exp = parseexpr(P); ex.i = exp.ty->size; @@ -1234,6 +1236,40 @@ pexprimary(struct parser *P) { const struct type *ty = parsetype(P); ex.i = ty->size; } + } else if (lexmatch(P, &tok, TKkw_alignof)) { + ex.t = Eintlit; + ex.ty = ty_usize; + if (lexmatch(P, &tok, '(')) { + struct expr exp = parseexpr(P); + ex.i = exp.ty->align; + lexexpect(P, ')'); + } else { + const struct type *ty = parsetype(P); + ex.i = ty->align; + } + } else if (lexmatch(P, &tok, TKkw_offsetof)) { + lexexpect(P, '('); + const struct type *ty = parsetype(P); + lexexpect(P, ','); + size_t off = 0; + for (;;) { + const char *name = (tok = lexexpect(P, TKident)).str; + struct aggfield *fld = findaggfield(ty, name); + if (!fld) { + fatal(P, tok.span, "%t has no such field %T", ty, tok); + } + off += fld->off; + ty = fld->ty; + if (!lexmatch(P, &tok, '.')) { + lexmatch(P, &tok, ','); + lexexpect(P, ')'); + break; + } + } + ex.t = Eintlit; + ex.ty = ty_usize; + ex.u = off; + } else { experr: fatal(P, tok.span, "expected expression (near %s)", tok2str(tok)); @@ -1424,7 +1460,7 @@ pexpostfix(struct parser *P) { bool konst = ty->konst; ty = unconstify(ty); if (ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion) { - int idx = structfldnam2idx(ty, fnam); + int idx = aggfldnam2idx(ty, fnam); struct aggfield *fld = &ty->agg.flds.d[idx]; if (idx < 0) fatal(P, tok.span, "%t has no such field `%s'", ty, fnam); diff --git a/bootstrap/test.cff b/bootstrap/test.cff index 5e384af..ef0bbfb 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -107,6 +107,7 @@ extern fn main (argc int, argv **u8) int { printf("sizeof(is) = %zu\n", sizeof(is)); printf("sizeof *void = %zu\n", sizeof *void); + printf("alignof f64= %zu\n", alignof f64); printf("1.2 -> %#.8x\n", transmute(u32, 1.2f)); switch is.#len { diff --git a/src/cffc.hff b/src/cffc.hff index d4b0ec1..af5bd6a 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -19,10 +19,10 @@ struct Loc { #[lax] enum TokT : i32 { // !sorted - kw_and, kw_as, kw_break, kw_case, kw_const, + kw_alignof, kw_and, kw_as, kw_break, kw_case, kw_const, kw_continue, kw_def, kw_defmacro, kw_do, kw_else, kw_enum, kw_extern, kw_fn, - kw_for, kw_if, kw_import, kw_let, + kw_for, kw_if, kw_import, kw_let, kw_offsetof, kw_or, kw_return, kw_sizeof, kw_static, kw_struct, kw_switch, kw_typedef, kw_typeof, kw_union, kw_while, diff --git a/src/common.hff b/src/common.hff index 6643dda..187fbf3 100644 --- a/src/common.hff +++ b/src/common.hff @@ -52,11 +52,8 @@ defmacro with_tmpchange(var,x,&body) [ defmacro MAX(a,b) [((a) > (b) ? (a) : (b))] -defmacro offsetof_(T, fld) [ - (as(isize)(&(as(*T)#null).fld)) -] defmacro container_of(x, T, fld) [ - (as(*T)(as(*void)(x) - offsetof_(T, fld))) + (as(*T)(as(*void)(x) - offsetof(T, fld))) ] // Inline functions diff --git a/src/parse.cff b/src/parse.cff index a2071f8..b42d45a 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -141,10 +141,10 @@ fn eatspaces(P *Parser) void { // !sorted extern static keyword2str [NUM_KEYWORDS]*const u8 = { - "and", "as", "break", "case", "const", + "alignof", "and", "as", "break", "case", "const", "continue", "def", "defmacro", "do", "else", "enum", "extern", "fn", - "for", "if", "import", "let", + "for", "if", "import", "let", "offsetof", "or", "return", "sizeof", "static", "struct", "switch", "typedef", "typeof", "union", "while", @@ -1152,6 +1152,20 @@ fn pexprimary(P *Parser) Expr { } ex = { tok.loc, ty_usize, :IntLit { ty.size }}; + case :kw_alignof; + let ty *const Type #?; + if lexmatch(P, &tok, '(') { + let ex = parseexpr(P); + lexexpect(P, ')'); + ty = ex.ty; + } else { + ty = parsetype(P); + } + if !completetype(ty) { + err(P, tok.loc, "alignof incomplete type (%t)", ty); + } + ex = { tok.loc, ty_usize, :IntLit { ty.align }}; + case '('; if lexmatch(P, &tok, :kw_do) { let st = parseblock0(P); |