aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-17 22:47:36 +0200
committerlemon <lsof@mailbox.org>2022-08-17 22:47:36 +0200
commit1c25c197d860ad49bb6a84e077a54e5aaf441bbd (patch)
tree8f7b963d1c891cfaa2d490a2f651ac0b8fa83c42 /src/parse.cff
parent86242b6cc1f53a86fcce1312211d3232661bf454 (diff)
parse defmacro
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff162
1 files changed, 157 insertions, 5 deletions
diff --git a/src/parse.cff b/src/parse.cff
index c2c1817..f19b586 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -566,8 +566,37 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl {
// Types Parsing //
///////////////////
+fn parseexpr(P *Parser) Expr;
fn parsetype(P *Parser) *const Type;
+fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
+ lexexpect(P, '{');
+ let iota = 0i64;
+ let max = iota;
+ let vals Vec<EnumVal> = {};
+ while !lexmatch(P, #null, '}') {
+ let name = lexexpects(P, :ident, "variant name").u.ident;
+ if lexmatch(P, #null, '=') {
+ let ex = parseexpr(P);
+ if !fold(&ex) or !ex.ty->is(:Int) {
+ err(P, ex.loc, "expected constant integer expression");
+ }
+ iota = ex.u.IntLit.i;
+ }
+ vals->push({
+ name,
+ iota++,
+ });
+ if !lexmatch(P, #null, ',') {
+ lexexpect(P, '}');
+ break;
+ }
+ }
+ let intty *const Type = #null;
+ static id int = 0;
+ return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
+}
+
fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type {
let loc = P.tokloc;
let tok Tok #?;
@@ -598,7 +627,7 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type
let flds Vec<AggField> = {};
while !lexmatch(P, #null, '}') {
let off = size;
- let name = lexexpect(P, :ident).u.ident;
+ let name = lexexpects(P, :ident, "field name").u.ident;
let type = parsetype(P);
if type {
off = ALIGNUP(off, type.align);
@@ -730,8 +759,6 @@ fn islvalue(ex Expr) bool {
return #f;
}
-fn parseexpr(P *Parser) Expr;
-
fn pexprimary(P *Parser) Expr {
let tok Tok = lex(P);
switch tok.t {
@@ -764,14 +791,23 @@ fn pexprimary(P *Parser) Expr {
return { tok.loc, var.ty, .u: :Symbol(decl) };
case Static var;
return { tok.loc, var.ty, .u: :Symbol(decl) };
+ case Def ex;
+ ex.loc = tok.loc;
+ return ex;
}
case :kw_sizeof;
+ let ty *const Type #?;
if lexmatch(P, &tok, '(') {
let ex = parseexpr(P);
lexexpect(P, ')');
- return { ex.loc, ty_usize, :IntLit { ex.ty.size }};
+ ty = ex.ty;
+ } else {
+ ty = parsetype(P);
}
- return { tok.loc, ty_usize, :IntLit { parsetype(P).size }};
+ if !completetype(ty) {
+ err(P, tok.loc, "sizeof incomplete type (%t)", ty);
+ }
+ return { tok.loc, ty_usize, :IntLit { ty.size }};
case '(';
let ex = parseexpr(P);
@@ -1448,6 +1484,106 @@ fn doimport(P *Parser, path *const u8) [#]Decl {
return decls;
}
+fn parsemacro(P *Parser, name *const u8) *Decl {
+ fn parsemacrocase(P *Parser) MacroCase {
+ let tok Tok #?;
+ let c MacroCase = {};
+ let params Vec<*const u8> = {};
+ let body Vec<Tok> = {};
+ static gensymid int = 0;
+ struct Gensyms {
+ next *Gensyms,
+ name *const u8,
+ tok Tok,
+ };
+ let gensyms *Gensyms = #null;
+ lexexpect(P, '(');
+ while !lexmatch(P, &tok, ')') {
+ if lexmatch(P, &tok, '...') {
+ params->push(lexexpects(P, :ident, "parameter name").u.ident);
+ c.variadic = #t;
+ lexmatch(P, &tok, ',');
+ lexexpect(P, ')');
+ break;
+ } else {
+ params->push(lexexpects(P, :ident, "parameter name").u.ident);
+ if !lexmatch(P, &tok, ',') {
+ lexexpect(P, ')');
+ break;
+ }
+ }
+ }
+ let eloc = tok.loc;
+ lexexpect(P, '[');
+
+ let bal = 1;
+ while bal != 0 {
+ tok = lex(P);
+ switch tok.t {
+ case '['; ++bal;
+ case ']'; --bal;
+ case :eof;
+ fatal(P, eloc, "unterminated macro definition");
+ }
+ if tok.t == :ident {
+ vec_each(par, _, params,
+ if streq(par, tok.u.ident) {
+ tok.t = :macident;
+ }
+ )
+ } else if tok.t == :gensym {
+ let gs *Gensyms #?;
+ let found = #f;
+ for gs = gensyms; gs; gs = gs.next {
+ if streq(gs.name, tok.u.ident) {
+ tok = gs.tok;
+ found = #t;
+ break;
+ }
+ }
+ if !found {
+ gs = xcalloc(1, sizeof(*gs));
+ gs.name = tok.u.ident;
+ gs.tok.t = :ident;
+ gs.tok.loc = tok.loc;
+ let s [300]u8 = {};
+ snprintf(s, sizeof(s) - 1, "#<gensym %s %d>", tok.u.ident, gensymid++);
+ gs.tok.u.ident = internstr(s);
+ tok = gs.tok;
+ gs.next = gensyms;
+ gensyms = gs;
+ }
+ }
+ body->push(tok);
+ }
+ body->pop();
+
+ for let gs = gensyms, next *Gensyms #?; gs; gs = next {
+ next = gs.next;
+ free(gs);
+ }
+
+ c.params = params->move(P.alloc);
+ c.body = body->move(P.alloc);
+ return c;
+ }
+
+ let tok Tok #?;
+ let cs Vec<MacroCase> = {};
+ if lexpeek(P).t == '(' {
+ cs->push(parsemacrocase(P));
+ } else {
+ lexexpect(P, '{');
+ while !lexmatch(P, &tok, '}') {
+ cs->push(parsemacrocase(P));
+ if !lexmatch(P, &tok, ',') {
+ lexexpect(P, '}');
+ break;
+ }
+ }
+ }
+}
+
fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
let tok = Tok { .loc: P.tokloc },
decl *Decl = {},
@@ -1478,6 +1614,17 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
lexexpect(P, ';');
return;
+ case lexmatch(P, &tok, :kw_enum);
+ if lexmatch(P, &tok, :kw_union) {
+ let name = lexexpect(P, :ident).u.ident;
+ parseagg(P, :EUnion, name, &decl);
+ } else {
+ let name = lexexpect(P, :ident).u.ident;
+ let loc = P.tokloc;
+ let ty = parseenum(P, name, #{lax} #f);
+ decl = putdecl(P, loc, { name, loc, .u: :Ty(ty) });
+ }
+
case lexmatch(P, &tok, :kw_struct);
let name = lexexpect(P, :ident).u.ident;
parseagg(P, :Struct, name, &decl);
@@ -1531,6 +1678,7 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
if !typematchestarg(ty, ini.ty) {
err(P, ini.loc, "incompatible initializer (%t, expected %t)", ini.ty, ty);
}
+ fold(&ini);
yield(putdecl(P, tok.loc, {
name, tok.loc, .u: :Def(ini)
}), yarg);
@@ -1540,6 +1688,10 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
}
} while !lexmatch(P, &tok, ';');
return;
+
+ case lexmatch(P, &tok, :kw_defmacro);
+ let name = lexexpects(P, :ident, "macro name").u.ident;
+ decl = parsemacro(P, name);
case else;
fatal(P, tok.loc, "expected declaration (near %qT)", tok);