aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff92
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;