diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 226 |
1 files changed, 154 insertions, 72 deletions
diff --git a/src/parse.cff b/src/parse.cff index 760c0f9..e731d47 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -81,7 +81,7 @@ fn issep(c u8) bool { case '(', ')', '[', ']', '{', '}', '.', ',', ';', '?', '+', '-', '*', '/', '&', '|', '^', '~', '=', '\'', '"', '<', '>', ':', - '@', '#', '\\', '`'; + '@', '#', '\\', '`', '%', '!'; return #t; } return #f; @@ -100,7 +100,7 @@ fn ishsep(c u8) bool { } fn readtilsep(P *Parser, buf [#]u8, dot bool) int { - let i = 0, + let i = 0z, c u8 #?; while (!issep(c = chrpeek(P))) or (dot and c == '.') { chr(P); @@ -114,7 +114,7 @@ fn readtilsep(P *Parser, buf [#]u8, dot bool) int { } fn readtilhsep(P *Parser, buf [#]u8, dot bool) int { - let i = 0, + let i = 0z, c u8 #?, pred = &ishsep; while (!pred(c = chrpeek(P))) or (dot and c == '.') { @@ -151,8 +151,8 @@ extern static keyword2str [NUM_KEYWORDS]*const u8 = { }; fn str2keyword(s *const u8) int { - let i = 0zs, - j = keyword2str.#len - 1; + let i isize = 0, + j isize = keyword2str.#len - 1; while i <= j { let k = (j + i) / 2; let cmp = strcmp(keyword2str[k], s); @@ -452,7 +452,9 @@ fn lex(P *Parser) Tok { if delim == '"' { tok.t = :str; + str->push('\0'); tok.u.str = str->move(P.alloc); + tok.u.str = tok.u.str[0::tok.u.str.#len - 1]; } else { tok.t = :chr; if str.len == 0 { @@ -627,6 +629,18 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl { return d; } +fn putdecl_alloc(P *Parser, alloc *Allocator, eloc Loc, decl Decl) *Decl { + if envfind(primenv, decl.name) { + fatal(P, eloc, "cannot shadow primitive `%s'", decl.name); + } + let d0 *const Decl; + let d = envput_alloc(P.curenv, alloc, decl, &d0); + if d == #null { + fatal(P, eloc, "attempt to redefine `%s' (previously defined at %l)", decl.name, d0.loc); + } + return d; +} + /////////////////// // Types Parsing // /////////////////// @@ -669,8 +683,8 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type { } } let intty *const Type = intty ?? ( - max < 1u64 << ((g_targ.intsize * 8) - 1) ? ty_int - : max < 1u64 << 31 ? ty_i32 + max < 1i64 << ((g_targ.intsize * 8) - 1) ? ty_int + : max < 1i64 << 31 ? ty_i32 : ty_i64); static id int = 0; return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }}); @@ -716,10 +730,10 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c if !lexmatch(P, &tok, ';') { agg.fwd = #f; lexexpect(P, '{'); - let size = 0, align = 1; + let size = 0z, align = 1z; let flds Vec<AggField> = {}; let havedecls = #f; - let f0align = -1i64; + let f0align = -1zs; while !lexmatch(P, &tok, '}') { if isdecltokt(lexpeek(P).t) { havedecls = #t; @@ -895,7 +909,7 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type { #'search for cache = tepl.cache; cache; cache = cache.next { - for let i = 0; i < nparam; ++i { + for let i = 0z; i < nparam; ++i { let arg = &tpargs[i]; switch cache.args[i] { case Ty ty; @@ -1102,7 +1116,7 @@ fn parseaggini(P *Parser, loc Loc, ty *const Type) Expr { let tok Tok #?; let flds Vec<*const AggField> = {}; let exs Vec<Expr> = {}; - let iota = 0; + let iota = 0u64; while !lexmatch(P, &tok, '}') { let fld *AggField #?; let ex Expr #?; @@ -1299,49 +1313,32 @@ fn parseexpandmacro(P *Parser, loc Loc, mac *Macro) void { } -fn parseblock0(P *Parser) [#]Stmt; +fn parseblock0(P *Parser) Block; fn pexprimary(P *Parser) Expr { let tok Tok = lex(P); let ex Expr #?; - switch tok.t { - case :int, :chr; - ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }}; - - case :flo; - ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) }; - case :bool; - ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) }; - - case :null; - ex = { tok.loc, ty_voidptr, .u: :NullLit }; - - case :str; - let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8); - ex = { tok.loc, ty, .u: :StrLit(tok.u.str) }; - - case :ident; - let ident = tok.u.ident; - let decl = finddecl(P, ident); - let fakedecl Decl = {}; + let fakedecl Decl #?; + fn resolvedecl(P *Parser, tok Tok, decl *Decl, ex *Expr) void { + let fakedecl Decl #?; if decl == #null { fatal(P, tok.loc, "%qT is not defined", tok); } while #t { switch decl.u { case Fn f; - ex = { tok.loc, f.ty, .u: :Symbol(decl) }; + *ex = { tok.loc, f.ty, .u: :Symbol(decl) }; case Let var; - ex = { tok.loc, var.ty, .u: :Symbol(decl) }; + *ex = { tok.loc, var.ty, .u: :Symbol(decl) }; case Static var; - ex = { tok.loc, var.ty, .u: :Symbol(decl) }; + *ex = { tok.loc, var.ty, .u: :Symbol(decl) }; case Def dex; dex.loc = tok.loc; - ex = dex; + *ex = dex; case Macro *mac; parseexpandmacro(P, tok.loc, mac); - ex = parseexpr(P); + *ex = parseexpr(P); case Ty ty; if (tok = lexpeek(P)).t != ':' and tok.t != '{' { lexexpects(P, ':', "`:' or `{' after type name"); @@ -1356,9 +1353,10 @@ fn pexprimary(P *Parser) Expr { continue; } else if !ty->is(:Agg) and !ty->is(:Enum) { fatal(P, tok.loc, "type is not aggregate or enum"); - } else { + } else {; P.targty = ty; - return parseexpr(P); + *ex = parseexpr(P); + return; } case Tepl *tepl; fakedecl = { .u: :Ty(parseexpandtepl(P, tepl)) }; @@ -1367,6 +1365,34 @@ fn pexprimary(P *Parser) Expr { } break; } + } + + switch tok.t { + case :int, :chr; + ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }}; + + case :flo; + ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) }; + + case :bool; + ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) }; + + case :null; + ex = { tok.loc, ty_voidptr, .u: :NullLit }; + + case :str; + let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8); + ex = { tok.loc, ty, .u: :StrLit(tok.u.str) }; + + case :ident; + let ident = tok.u.ident; + let decl = finddecl(P, ident); + resolvedecl(P, tok, decl, &ex); + + case :typearg; + fakedecl = { .u: :Ty(tok.ty) }; + resolvedecl(P, tok, &fakedecl, &ex); + case :kw_sizeof; let ty *const Type #?; if lexmatch(P, &tok, '(') { @@ -1418,7 +1444,8 @@ fn pexprimary(P *Parser) Expr { case '('; if lexmatch(P, &tok, :kw_do) { - let st = parseblock0(P); + let block = parseblock0(P); + let st = block.sts; lexexpect(P, ')'); if st.#len == 0 or st[st.#len - 1].u.#tag != :Expr { ex = { tok.loc, ty_void, :Stmt(st) }; @@ -1840,7 +1867,11 @@ fn pexcmp(P *Parser) Expr { fatal(P, tok.loc, "invalid non-numeric operands %t and %t to relational operator %qT", ex.ty, rhs.ty, tok); } - if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn { + fn ispositiveintlit(ex Expr) bool { + return ex.u.#tag == :IntLit and ex.u.IntLit.i >- 0; + } + if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn + and !(ispositiveintlit(ex) or ispositiveintlit(rhs)) { warn(P, tok.loc, "comparing integers of different signedness (%t and %t)", ex.ty, rhs.ty); } } @@ -1889,13 +1920,16 @@ fn pexlog(P *Parser) Expr { fn pexcond(P *Parser) Expr { let tok Tok = {}; + let targty = P.targty; let ex = pexlog(P); if (lexmatch(P, &tok, '?')) { + P.targty = targty; let ex2 = parseexpr(P); if !ex.ty->is(:Bool) and !ex.ty->is(:Ptr) { fatal(P, ex.loc, "invalid test operand to conditional operator (%t)", ex.ty); } lexexpect(P, ':'); + P.targty = targty; let ex3 = pexcond(P); let ty = typeof2(ex2.ty, ex3.ty); if ty == #null { @@ -1971,7 +2005,7 @@ fn stmtdup(alloc *Allocator, st Stmt) *Stmt { } typedef StmtYielder *fn(Stmt, *void) void; -fn parseblock(P *Parser) [#]Stmt; +fn parseblock(P *Parser) Block; fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void; fn pstlet(P *Parser, yield StmtYielder, yarg *void) void { @@ -1998,7 +2032,7 @@ fn pstif(P *Parser, loc Loc) Stmt { if lexmatch(P, &tok, :kw_else) { if lexmatch(P, &tok, :kw_if) { let f = stmtdup(P.alloc, pstif(P, tok.loc)); - return { loc, :If { test, t, f[0::1] }}; + return { loc, :If { test, t, { f[0::1] } }}; } else { lexexpect(P, '{'); let f = parseblock(P); @@ -2008,7 +2042,7 @@ fn pstif(P *Parser, loc Loc) Stmt { return { loc, :If { test, t }}; } -fn pstreturn(P *Parser, loc Loc) Stmt { +fn pstreturn(P *Parser, loc Loc, deferage int) Stmt { if P.curfn == #null { fatal(P, loc, "return outside function"); } @@ -2017,7 +2051,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt { if retty != ty_void { err(P, loc, "return with no value in function returning %t", retty); } - return { loc, :Return{} }; + return { loc, :Return{ :None, deferage} }; } else { P.targty = retty; let ex = parseexpr(P); @@ -2026,7 +2060,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt { err(P, ex.loc, "incompatible type in return statement (%t, expected %t)", ex.ty, retty); } - return { loc, :Return(:Some(ex)) }; + return { loc, :Return{:Some(ex), deferage} }; } } @@ -2036,7 +2070,7 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt { err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty); } lexexpect(P, '{'); - let body [#]Stmt #?; + let body Block #?; with_tmpchange(P.curloop, ++P.loopid) { let env = mkenv(P.curenv, P.alloc); defer envfree(env); @@ -2050,8 +2084,29 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt { return { loc, :While { test, body, P.loopid }}; } +fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt { + lexexpect(P, '{'); + let body Block #?; + with_tmpchange(P.curloop, ++P.loopid) { + let env = mkenv(P.curenv, P.alloc); + defer envfree(env); + pushenv(P, env); + if label { + putdecl(P, loc, { label, loc, .u: :Label(P.loopid) }); + } + body = parseblock(P); + popenv(P); + } + lexexpect(P, :kw_while); + let test = parseexpr(P); + if !test.ty->is(:Bool) and !test.ty->is(:Ptr) { + err(P, test.loc, "do-while condition must be bool or pointer (%t)", test.ty); + } + return { loc, :DoWhile { test, body, P.loopid }}; +} + fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { - let ini [#]Stmt = {}; + let ini Block = {}; let test Expr #?; let next = Option<Expr>:None; let tok Tok #?; @@ -2062,12 +2117,12 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { sts->push(st); } pstlet(P, &yieldlet, &sts); - ini = sts->move(P.alloc); + ini = { sts->move(P.alloc) }; } else if lexmatch(P, #null, ';') { // pass } else { let ex = parseexpr(P); - ini = stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1]; + ini = { stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1] }; lexexpect(P, ';'); } @@ -2085,7 +2140,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { next = :Some(parseexpr(P)); lexexpect(P, '{'); } - let body [#]Stmt #?; + let body Block #?; let id = ++P.loopid; with_tmpchange(P.curloop, id) { let env = mkenv(P.curenv, P.alloc); @@ -2103,7 +2158,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { let tok Tok #?; let cs Vec<ISwitchCase> = {}; - let f [#]Stmt = {}; + let f Block = {}; let elsep = #f; while !lexmatch(P, &tok, '}') { lexexpect(P, :kw_case); @@ -2140,7 +2195,7 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { let cs Vec<EUSwitchCase> = {}; let tok Tok #?; - let f [#]Stmt = {}; + let f Block = {}; let elsep = #f; while !lexmatch(P, &tok, '}') { @@ -2196,7 +2251,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { fn pstcswitch(P *Parser, loc Loc) Stmt { let cs Vec<CSwitchCase> = {}; let tok Tok #?; - let f [#]Stmt = {}; + let f Block = {}; let elsep = #f; while !lexmatch(P, &tok, '}') { @@ -2237,6 +2292,7 @@ fn pstswitch(P *Parser, loc Loc) Stmt { } fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { + static deferage int = {}; let tok Tok = {}; switch { case lexmatch(P, &tok, '{'); @@ -2251,7 +2307,7 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { return yield(pstif(P, tok.loc), yarg); case lexmatch(P, &tok, :kw_return); - return yield(pstreturn(P, tok.loc), yarg); + return yield(pstreturn(P, tok.loc, deferage), yarg); case lexmatch(P, &tok, :label); let label = tok.u.ident; @@ -2260,6 +2316,8 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { return yield(pstwhile(P, tok.loc, label), yarg); case lexmatch(P, &tok, :kw_for); return yield(pstfor(P, tok.loc, label), yarg); + case lexmatch(P, &tok, :kw_do); + return yield(pstdowhile(P, tok.loc, label), yarg); case else fatal(P, tok.loc, "label can only precede looping statement"); } @@ -2270,6 +2328,10 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { case lexmatch(P, &tok, :kw_for); return yield(pstfor(P, tok.loc, #null), yarg); + case lexmatch(P, &tok, :kw_do); + return yield(pstdowhile(P, tok.loc, #null), yarg); + + case lexmatch(P, &tok, :kw_break) or lexmatch(P, &tok, :kw_continue); if P.curloop == 0 { err(P, tok.loc, "%s outside loop", tok.t == :kw_break ? "break" : "continue"); @@ -2287,6 +2349,20 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { lexexpect(P, ';'); return yield({ tok.loc, tok.t == :kw_break ? :Break(loop) : :Continue(loop) }, yarg); + case lexmatch(P, &tok, :kw_defer); + if P.curblock == #null { + fatal(P, tok.loc, "defer outside function"); + } + let ex = parseexpr(P); + lexexpect(P, ';'); + let defr *Defers = anew(P.alloc, Defers); + defr.age = deferage++; + defr.ex = ex; + defr.blockid = P.curblock.id; + defr.next = P.curblock.defers; + P.curblock.defers = defr; + return; + case lexmatch(P, &tok, :kw_switch); return yield(pstswitch(P, tok.loc), yarg); @@ -2317,25 +2393,30 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { } } -fn parseblock0(P *Parser) [#]Stmt { +fn parseblock0(P *Parser) Block { + static id int = 1; + let block Block = { .id: id++, .defers: P.curblock ? P.curblock.defers : #null }; let sts Vec<Stmt> = {}; let tok Tok = {}; let env = mkenv(P.curenv, P.alloc); defer envfree(env); 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 { - let sts *Vec<Stmt> = arg; - sts->push(st); + with_tmpchange(P.curblock, &block) { + 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 { + let sts *Vec<Stmt> = arg; + sts->push(st); + } + parsestmts(P, &pushstmt, &sts); } - parsestmts(P, &pushstmt, &sts); } popenv(P); - return sts->move(P.alloc); + block.sts = sts->move(P.alloc); + return block; } -fn parseblock(P *Parser) [#]Stmt { +fn parseblock(P *Parser) Block { let b = parseblock0(P); lexexpect(P, '}'); return b; @@ -2429,7 +2510,8 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec }}); static id int = 0; Fn.id = ++id; - let decl = putdecl(P, loc, decl); + // TODO tlalloc necessary for templates. but it leaks some memory + let decl = putdecl_alloc(P, P.tlalloc, loc, decl); decl.toplevel = toplevel; if !lexmatch(P, #null, '{') { @@ -2443,7 +2525,6 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec let varid = P.varid, loopid = P.loopid; P.varid = 0; P.loopid = 0; - with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) { with_tmpchange(P.curfn, Fn) { let env = mkenv(P.curenv, P.alloc); defer envfree(env); @@ -2455,12 +2536,13 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec }}); } } - Fn.body = :Some(parseblock(P)); - popenv(P); - // ir_genfn(P.irctx, Fn); - llvm_genfn(externp, name, Fn); - (as(*Arena)P.alloc.a)->destroy(); - } + with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) { + Fn.body = :Some(parseblock(P)); + popenv(P); + // ir_genfn(P.irctx, Fn); + llvm_genfn(externp, name, Fn); + (as(*Arena)P.alloc.a)->destroy(); + } } if toplevel { llvm_addfn(decl); |