From f0214ff61b5a94b9629db6f43d7a5b010bd4ffbc Mon Sep 17 00:00:00 2001 From: lemon Date: Thu, 18 Aug 2022 09:47:54 +0200 Subject: fix bodyarg --- src/parse.cff | 179 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 149 insertions(+), 30 deletions(-) (limited to 'src/parse.cff') diff --git a/src/parse.cff b/src/parse.cff index f19b586..7d083fb 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -407,9 +407,9 @@ fn lex(P *Parser) Tok { fatal(P, P.tokloc, "too long multichar literal %qs", str.dat); } tok.u.uint = 0; - vec_each(c0, i, str, + vec_each(c0, i, str) { tok.u.uint = (tok.u.uint << 8) | c0; - ) + } } return tok; } @@ -540,6 +540,16 @@ defmacro lexexpect(P, t) [lexexpects(P, t, #null)] static primenv *Env = {}; +fn pushenv(P *Parser, env *Env) void { + assert(P.curenv == envparent(env), "pushenv"); + P.curenv = env; +} + +fn popenv(P *Parser) void { + P.curenv = envparent(P.curenv); + assert(P.curenv != #null, "popenv"); +} + fn finddecl(P *Parser, name *const u8) *Decl { let p = envfind(primenv, name); return p ?? envfind(P.curenv, name); @@ -568,6 +578,8 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl { fn parseexpr(P *Parser) Expr; fn parsetype(P *Parser) *const Type; +typedef DeclYielder *fn(*Decl, *void) void; +fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void; fn parseenum(P *Parser, name *const u8, lax bool) *const Type { lexexpect(P, '{'); @@ -597,6 +609,15 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type { return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }}); } +fn isdecltokt(t TokT) bool { + switch t { + case :kw_fn, :kw_static, :kw_def, :kw_defmacro, :kw_struct, :kw_union, :kw_enum, + :kw_extern; + return #t; + } + return #f; +} + fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type { let loc = P.tokloc; let tok Tok #?; @@ -625,7 +646,12 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type lexexpect(P, '{'); let size = 0, align = 1; let flds Vec = {}; + let havedecls = #f; while !lexmatch(P, #null, '}') { + if isdecltokt(lexpeek(P).t) { + havedecls = #t; + break; + } let off = size; let name = lexexpects(P, :ident, "field name").u.ident; let type = parsetype(P); @@ -645,6 +671,14 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type ty.size = size; ty.align = align; agg.flds = flds.dat[0::flds.len]; + if havedecls { + agg.decls = mkenv(P.curenv, P.alloc); + pushenv(P, agg.decls); + while !lexmatch(P, #null, '}') { + parsedecls(P, #null, #null, #{toplevel} #f); + } + popenv(P); + } } return ty; } @@ -716,6 +750,22 @@ fn parsetype(P *Parser) *const Type { case lexmatch(P, &tok, '*'); return mkptrtype(parsetype(P)); + case lexmatch(P, &tok, '['); + let len = -1i64; + if lexmatch(P, &tok, '#') { + lexexpect(P, ']'); + return mkslicetype(parsetype(P)); + } else if !lexmatch(P, &tok, ']') { + let ex = parseexpr(P); + lexexpect(P, ']'); + if !fold(&ex) or ex.u.#tag != :IntLit or ex.u.IntLit.i < 0 { + fatal(P, ex.loc, "expected constant non-negative integer expression for array length"); + } + len = ex.u.IntLit.i; + } + let child = parsetype(P); + return mkarrtype(len, #f, child); + case lexmatch(P, &tok, :ident); return xident2type(P, tok.loc, tok.u.ident); @@ -755,28 +805,31 @@ fn islvalue(ex Expr) bool { return u.op == :deref; case Index; return #t; + case Dot; + return #t; } return #f; } fn pexprimary(P *Parser) Expr { let tok Tok = lex(P); + let ex Expr #?; switch tok.t { case :int, :chr; - return { tok.loc, tok.ty, .u: :IntLit { tok.u.int }}; + ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }}; case :flo; - return { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) }; + ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) }; case :bool; - return { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) }; + ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) }; case :null; - return { tok.loc, ty_voidptr, .u: :NullLit }; + ex = { tok.loc, ty_voidptr, .u: :NullLit }; case :str; let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8); - return { tok.loc, ty, .u: :StrLit(tok.u.str) }; + ex = { tok.loc, ty, .u: :StrLit(tok.u.str) }; case :ident; let ident = tok.u.ident; @@ -786,14 +839,14 @@ fn pexprimary(P *Parser) Expr { } switch decl.u { case Fn f; - return { tok.loc, f.ty, .u: :Symbol(decl) }; + ex = { tok.loc, f.ty, .u: :Symbol(decl) }; case Let var; - return { tok.loc, var.ty, .u: :Symbol(decl) }; + ex = { 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; + ex = { tok.loc, var.ty, .u: :Symbol(decl) }; + case Def dex; + dex.loc = tok.loc; + ex = dex; } case :kw_sizeof; let ty *const Type #?; @@ -807,16 +860,27 @@ fn pexprimary(P *Parser) Expr { if !completetype(ty) { err(P, tok.loc, "sizeof incomplete type (%t)", ty); } - return { tok.loc, ty_usize, :IntLit { ty.size }}; + ex = { tok.loc, ty_usize, :IntLit { ty.size }}; case '('; - let ex = parseexpr(P); + ex = parseexpr(P); lexexpect(P, ')'); - return ex; + case '{'; + if P.targty == #null { + fatal(P, tok.loc, "cannot infer type for initializer"); + } + let ty = P.targty; + if lexmatch(P, #null, '}') { + ex = { tok.loc, ty, .u: :ZeroIni }; + } else { + assert(#f, "NYI"); + } case else; fatal(P, tok.loc, "expected expression (near %qT)", tok); } + P.targty = #null; + return ex; } fn pexpostfix(P *Parser) Expr { @@ -890,8 +954,33 @@ fn pexpostfix(P *Parser) Expr { tok.t == '++' ? :postinc : :postdec, exprdup(P.alloc, ex) } }; + case lexmatch(P, &tok, '.'); + let name = (tok = lexexpects(P, :ident, "field name")).u.ident; + let ty = ex.ty; + if ty->is(:Ptr) { + ty = ty.u.Ptr; + } + if !ty->is(:Agg) { + fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty); + } + let agg = &ty.u.Agg; + let fld *AggField = #null; + foreach(f, i, agg.flds) { + if streq(name, f.name) { + fld = &agg.flds[i]; + break; + } + } + if fld == #null { + fatal(P, tok.loc, "%t has no such field %qT", ty, tok); + } + if fld.ty == #null { + fatal(P, tok.loc, "field %qT has no type", tok); + } + ex = { tok.loc, fld.ty, :Dot { exprdup(P.alloc, ex), fld }}; + case else; - break; + break; } } return ex; @@ -956,6 +1045,15 @@ fn pexprefix(P *Parser) Expr { err(P, ex.loc, "invalid operand to `&': not an lvalue"); } return { tok.loc, ty2, .u: :UnOp { :addrof, exprdup(P.alloc, ex) }}; + + case lexmatch(P, &tok, :kw_as); + let loc = tok.loc; + lexexpect(P, '('); + let ty = parsetype(P); + lexexpect(P, ')'); + let ex = pexprefix(P); + // TODO check valid cast + return { loc, ty, :Cast(exprdup(P.alloc, ex)) }; } return pexpostfix(P); } @@ -1161,7 +1259,6 @@ fn stmtdup(alloc *Allocator, st Stmt) *Stmt { return memcpy(alloc->alloc(sizeof(st)), &st, sizeof(st)); } -typedef DeclYielder *fn(*Decl, *void) void; typedef StmtYielder *fn(Stmt, *void) void; fn parseblock(P *Parser) [#]Stmt; fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void; @@ -1314,6 +1411,18 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { lexexpect(P, ';'); return yield({ tok.loc, :Continue(P.curloop) }, yarg); + case isdecltokt(tok.t); + struct Arg { + P *Parser, + yield StmtYielder, + yarg *void, + } + fn declyield(decl *Decl, arg *void) void { + let a *Arg = arg; + a.yield({ decl.loc, :Decl(decl) }, a.yarg); + } + parsedecls(P, &declyield, &Arg { P, yield, yarg }, #{toplevel?} #f); + case else; let ex = parseexpr(P); lexexpect(P, ';'); @@ -1324,6 +1433,8 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { fn parseblock0(P *Parser) [#]Stmt { let sts Vec = {}; let tok Tok = {}; + let env = mkenv(P.curenv, P.alloc); + pushenv(P, env); while (tok = lexpeek(P)).t != '}' and tok.t != :kw_case and tok.t != '}' { if lexmatch(P, #null, ';') { continue; } fn pushstmt(st Stmt, arg *void) void { @@ -1332,6 +1443,7 @@ fn parseblock0(P *Parser) [#]Stmt { } parsestmts(P, &pushstmt, &sts); } + popenv(P); return sts->move(P.alloc); } @@ -1362,6 +1474,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie ty = parsetype(P); if lexmatch(P, #null, '=') { + P.targty = ty; ini = :Some(parseexpr(P)); } else if lexmatch(P, #null, '#?') { ini = :None; @@ -1400,10 +1513,10 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl { }; let Fn = &decl.u.Fn, - tok Tok = {}, paramnames Vec<*const u8> = {}, paramtys Vec<*const Type> = {}; + let loc = P.tokloc; parsefnparams(P, &Fn.variadic, ¶mnames, ¶mtys); Fn.paramnames = paramnames->move(P.alloc); let retty = parsetype(P); @@ -1412,7 +1525,7 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl { }}); static id int = 0; Fn.id = ++id; - let decl = putdecl(P, tok.loc, decl); + let decl = putdecl(P, loc, decl); if !lexmatch(P, #null, '{') { lexexpects(P, ';', "';' or '{'"); @@ -1422,16 +1535,16 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl { with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }, with_tmpchange(P.curfn, Fn, let env = mkenv(P.curenv, P.alloc); - P.curenv = env; - foreach(name, i, Fn.paramnames, + pushenv(P, env); + foreach(name, i, Fn.paramnames) { if name { - putdecl(P, tok.loc, { name, tok.loc, .u: :Let { + putdecl(P, loc, { name, loc, .u: :Let { Fn.ty.u.Fn.params[i], :None, #f, Fn.id, }}); } - ) + } Fn.body = :Some(parseblock(P)); - P.curenv = envparent(env); + popenv(P); envfree(env); (as(*Arena)P.alloc.a)->destroy(); ); @@ -1467,7 +1580,7 @@ fn doimport(P *Parser, path *const u8) [#]Decl { snprintf(path2, sizeof(path2) - 1, "%s/%s", basedir, path); let rpath *const u8 = realpath(path2, _rpath); if rpath == #null { - fatal(P, P.tokloc, "import %qs: %s", path, strerror(c_errno())); + fatal(P, P.tokloc, "import %qs: %s", path, strerror(errno)); } let d0 = seen->get(rpath); if d0 != #null { @@ -1505,6 +1618,12 @@ fn parsemacro(P *Parser, name *const u8) *Decl { lexmatch(P, &tok, ','); lexexpect(P, ')'); break; + } else if lexmatch(P, &tok, '&') { + params->push(lexexpects(P, :ident, "parameter name").u.ident); + c.bodyarg = #t; + lexmatch(P, &tok, ','); + lexexpect(P, ')'); + break; } else { params->push(lexexpects(P, :ident, "parameter name").u.ident); if !lexmatch(P, &tok, ',') { @@ -1526,11 +1645,11 @@ fn parsemacro(P *Parser, name *const u8) *Decl { fatal(P, eloc, "unterminated macro definition"); } if tok.t == :ident { - vec_each(par, _, params, + vec_each(par, _, params) { if streq(par, tok.u.ident) { tok.t = :macident; } - ) + } } else if tok.t == :gensym { let gs *Gensyms #?; let found = #f; @@ -1605,12 +1724,12 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { case lexmatch(P, &tok, :kw_import); let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr; let decls = doimport(P, path); - foreach(decl, _, decls, + foreach(decl, _, decls) { let decl = putdecl(P, tok.loc, decl); if yield { yield(decl, yarg); } - ) + } lexexpect(P, ';'); return; -- cgit v1.2.3