diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/src/parse.cff b/src/parse.cff index cbeccb1..2f5fbe2 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -299,7 +299,9 @@ fn lex(P *Parser) Tok { --P.expanno; free(ep.args.#ptr); P.curexpan = ep.prev; - P.peektok = ep.peektok; + if !ep.tepl { + P.peektok = ep.peektok; + } free(ep); return lex(P); } @@ -395,11 +397,15 @@ fn lex(P *Parser) Tok { tok.t = '#len'; case streq(s, "#tag"); tok.t = '#tag'; + case streq(s, "#FILE"); + tok.t = '#FIL'; + case streq(s, "#LINE"); + tok.t = '#LIN'; case streq(s, "#?"); tok.t = '#?'; case s[0] == '#' and s[1] == '\''; tok.t = :label; - tok.u.str = spanz(internstr(s)); + tok.u.ident = internstr(s); case else fatal(P, P.tokloc, "invalid #keyword `%s'", s); } @@ -677,6 +683,8 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c if !ty->is(:Agg) or !ty.u.Agg.fwd or ty.u.Agg.kind != kind { decl = #null; } + case else + decl = #null; } } let ty = decl ? decl.u.Ty : interntype({ .u: :Agg { kind, name, id++ }}); @@ -904,12 +912,14 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type { let env = mkenv(tepl.env, P.alloc); with_tmpchange(P.curenv, env) { let decl *Decl #?; - let expan Expan = { P.curexpan, args[0::nparam], tepl.toks, tname, tok.loc, #{tepl?} #t }; + let expan Expan = { + P.curexpan, args[0::nparam], tepl.toks, tname, tok.loc, #{tepl?} #t, + }; ++P.expanno; P.curexpan = memcpy(xmalloc(sizeof Expan), &expan, sizeof Expan); ty = parseagg(P, loc, tepl.kind, tname, &decl); - } + P.peektok = :None; envfree(env); (as(*Type)ty).u.Agg.tpargs = tpargs; cache = P.alloc->alloc(sizeof(*cache), alignof(*cache)); @@ -1275,6 +1285,7 @@ fn pexprimary(P *Parser) Expr { case :ident; let ident = tok.u.ident; let decl = finddecl(P, ident); + let fakedecl Decl = {}; if decl == #null { fatal(P, tok.loc, "%qT is not defined", tok); } @@ -1294,7 +1305,7 @@ fn pexprimary(P *Parser) Expr { ex = parseexpr(P); case Ty ty; if (tok = lexpeek(P)).t != ':' and tok.t != '{' { - fatal(P, tok.loc, "expected `:' or `{' after type name"); + lexexpects(P, ':', "`:' or `{' after type name"); } if tok.t == ':' and ty->is(:Agg) and ty.u.Agg.kind != :EUnion { lex(P); @@ -1310,6 +1321,10 @@ fn pexprimary(P *Parser) Expr { P.targty = ty; return parseexpr(P); } + case Tepl *tepl; + fakedecl = { .u: :Ty(parseexpandtepl(P, tepl)) }; + decl = &fakedecl; + continue; } break; } @@ -1949,20 +1964,27 @@ fn pstreturn(P *Parser, loc Loc) Stmt { } } -fn pstwhile(P *Parser, loc Loc) Stmt { +fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt { let test = parseexpr(P); if !test.ty->is(:Bool) and !test.ty->is(:Ptr) { err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty); } lexexpect(P, '{'); - let t [#]Stmt #?; + let body [#]Stmt #?; with_tmpchange(P.curloop, ++P.loopid) { - t = parseblock(P); + let env = mkenv(P.curenv, P.alloc); + pushenv(P, env); + if label { + putdecl(P, loc, { label, loc, .u: :Label(P.loopid) }); + } + body = parseblock(P); + popenv(P); + envfree(env); } - return { loc, :While { test, t, P.loopid }}; + return { loc, :While { test, body, P.loopid }}; } -fn pstfor(P *Parser, loc Loc) Stmt { +fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { let ini [#]Stmt = {}; let test Expr #?; let next = Option<Expr>:None; @@ -1998,7 +2020,14 @@ fn pstfor(P *Parser, loc Loc) Stmt { } let body [#]Stmt #?; with_tmpchange(P.curloop, ++P.loopid) { + let env = mkenv(P.curenv, P.alloc); + pushenv(P, env); + if label { + putdecl(P, loc, { label, loc, .u: :Label(P.loopid) }); + } body = parseblock(P); + popenv(P); + envfree(env); } return { loc, :For { ini, test, next, body, P.loopid }}; } @@ -2129,25 +2158,39 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { case lexmatch(P, &tok, :kw_return); return yield(pstreturn(P, tok.loc), yarg); + case lexmatch(P, &tok, :label); + let label = tok.u.ident; + switch { + case lexmatch(P, &tok, :kw_while); + return yield(pstwhile(P, tok.loc, label), yarg); + case lexmatch(P, &tok, :kw_for); + return yield(pstfor(P, tok.loc, label), yarg); + case else + fatal(P, tok.loc, "label can only precede looping statement"); + } + case lexmatch(P, &tok, :kw_while); - return yield(pstwhile(P, tok.loc), yarg); + return yield(pstwhile(P, tok.loc, #null), yarg); case lexmatch(P, &tok, :kw_for); - return yield(pstfor(P, tok.loc), yarg); + return yield(pstfor(P, tok.loc, #null), yarg); - case lexmatch(P, &tok, :kw_break); + case lexmatch(P, &tok, :kw_break) or lexmatch(P, &tok, :kw_continue); if P.curloop == 0 { - err(P, tok.loc, "break outside loop"); + err(P, tok.loc, "%s outside loop", tok.t == :kw_break ? "break" : "continue"); } - lexexpect(P, ';'); - return yield({ tok.loc, :Break(P.curloop) }, yarg); - - case lexmatch(P, &tok, :kw_continue); - if P.curloop == 0 { - err(P, tok.loc, "continue outside loop"); + let tok2 Tok #?; + let loop = P.curloop; + if lexmatch(P, &tok2, :label) { + let decl = finddecl(P, tok2.u.ident); + if decl == #null { + fatal(P, tok2.loc, "no such label %qT", tok2); + } + assert(decl.u.#tag == :Label, "label?"); + loop = decl.u.Label; } lexexpect(P, ';'); - return yield({ tok.loc, :Continue(P.curloop) }, yarg); + return yield({ tok.loc, tok.t == :kw_break ? :Break(loop) : :Continue(loop) }, yarg); case lexmatch(P, &tok, :kw_switch); return yield(pstswitch(P, tok.loc), yarg); @@ -2622,9 +2665,10 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) 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); + decl = putdecl(P, tok.loc, { name, tok.loc, .u: :Def(ini) }); + if yield { + yield(decl, yarg); + } if !lexmatch(P, &tok, ',') { lexexpects(P, ';', "`,' or `;'"); break; |