diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 162 |
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); |