diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 222 |
1 files changed, 122 insertions, 100 deletions
diff --git a/src/parse.cff b/src/parse.cff index 2e6cec9..3be70cf 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -439,7 +439,7 @@ fn lex(P *Parser) Tok { case '"'; str->push('"'); case 'n'; str->push('\n'); case 'r'; str->push('\r'); case 't'; str->push('\t'); case 'v'; str->push('\v'); case 'f'; str->push('\f'); - case '0'; str->push('\0'); + case '0'; str->push('\0'); case 'e'; str->push('\e'); case 'x'; let x0 = xdigit2num(chr(P)), x1 = xdigit2num(chr(P)); @@ -1172,26 +1172,6 @@ fn exprdup(alloc *Allocator, ex Expr) *Expr { return memcpy(alloc->alloc(sizeof(ex), alignof(ex)), &ex, sizeof(ex)); } -fn islvalue(ex *Expr) bool { - switch ex.u { - case Symbol decl; - return decl.u.#tag == :Let or decl.u.#tag == :Static; - case UnOp u; - return u.op == :deref; - case Index; - return #t; - case Dot; - return #t; - case BitDot bdot; - return islvalue(bdot.lhs); - case BitRaw ex; - return islvalue(ex); - case EUTag; - return #t; - } - return #f; -} - fn parseaggini(P *Parser, loc Loc, ty *const Type) Expr { let loc = loc; let tok Tok #?; @@ -1540,9 +1520,9 @@ fn pexprimary(P *Parser) Expr { 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) }; + ex = { tok.loc, ty_void, :Stmt(block) }; } else { - ex = { tok.loc, st[st.#len - 1].u.Expr.ty, :Stmt(st) }; + ex = { tok.loc, st[st.#len - 1].u.Expr.ty, :Stmt(block) }; } } else { ex = parseexpr(P); @@ -1581,6 +1561,9 @@ fn pexprimary(P *Parser) Expr { if fld.ty == #null { fatal(P, iex.loc, "%t variant %qT is empty", ty, tok); } + if !typematchestarg(fld.ty, iex.ty) { + fatal(P, iex.loc, "bad enum union initializer (%t, expected %t)", iex.ty, fld.ty); + } } else if fld.ty { fatal(P, tok.loc, "%t variant %qT must be initialized", ty, tok); } @@ -1656,7 +1639,7 @@ fn pexpostfix(P *Parser) Expr { if !lhs.ty->is(:Ptr) and !lhs.ty->is(:Arr) and !lhs.ty->is(:Slice) { fatal(P, lhs.loc, "indexee is not array or pointer type (%t)", lhs.ty); } - if !rhs.ty->is(:Int) { + if !rhs.ty->is(:Int) and !(rhs.ty->is(:Enum) and rhs.ty.u.Enum.lax){ err(P, lhs.loc, "index expression type is not integral (%t)", rhs.ty); } @@ -1781,78 +1764,115 @@ fn pexpostfix(P *Parser) Expr { } case lexmatch(P, &tok, '->'); - let name = (tok = lexexpects(P, :ident, "method name")).u.ident; let ty = ex.ty; let exptr = #f; if (exptr = 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 decl *Decl = agg.decls ? envfind_noparent(agg.decls, name) : #null; - if decl == #null { - fatal(P, tok.loc, "%t has no such method %qT", ty, tok); - } - lexexpect(P, '('); - switch decl.u { - case Fn f; - let Fn = &f.ty.u.Fn; - if Fn.params.#len == 0 { - fatal(P, tok.loc, "function takes no arguments"); + let name = (tok = lexexpects(P, :ident, "method name")).u.ident; + switch ty.u { + case Agg *agg; + let decl *Decl = agg.decls ? envfind_noparent(agg.decls, name) : #null; + if decl == #null { + fatal(P, tok.loc, "%t has no such method %qT", ty, tok); } + lexexpect(P, '('); + switch decl.u { + case Fn f; + let Fn = &f.ty.u.Fn; + if Fn.params.#len == 0 { + fatal(P, tok.loc, "function takes no arguments"); + } - let args Vec<Expr> = {}; - let recv0 = Fn.params[0], recv = recv0; - let metptr = #f; - if (metptr = recv->is(:Ptr)) { - recv = recv.u.Ptr; - } - if unconstify(ty) != unconstify(recv) { - err(P, tok.loc, "method receiver type mismatch for `->%s' (%t, expected %t)", - name, ty, recv0); - } - switch { - case !exptr and !metptr; - - case exptr and !metptr; - ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}}; - - case !exptr and metptr; - if !islvalue(&ex) { - err(P, tok.loc, "cannot call `->%s' by reference, lhs is not an lvalue", name); - } else if ty.konst and !recv.konst { - err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty); + let args Vec<Expr> = {}; + let recv0 = Fn.params[0], recv = recv0; + let metptr = #f; + if (metptr = recv->is(:Ptr)) { + recv = recv.u.Ptr; + } + if unconstify(ty) != unconstify(recv) { + err(P, tok.loc, "method receiver type mismatch for `->%s' (%t, expected %t)", + name, ty, recv0); + } + switch { + case !exptr and !metptr; + + case exptr and !metptr; + ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}}; + + case !exptr and metptr; + if !islvalue(&ex) { + err(P, tok.loc, "cannot call `->%s' by reference, lhs is not an lvalue", name); + } else if ty.konst and !recv.konst { + err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty); + } + ex = { ex.loc, mkptrtype(ty), :UnOp{:addrof, exprdup(P.alloc, ex)}}; + + case exptr and metptr; + if ty.konst and !recv.konst { + err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty); + } + } + args->push(ex); + let param = &Fn.params[1]; + while !lexmatch(P, #null, ')') { + P.targty = *param++; + args->push(parseexpr(P)); + if args.len > Fn.params.#len and !Fn.variadic { + fatal(P, args->last().loc, "too many args (%z, expected %z)", args.len, Fn.params.#len); } - ex = { ex.loc, mkptrtype(ty), :UnOp{:addrof, exprdup(P.alloc, ex)}}; - - case exptr and metptr; - if ty.konst and !recv.konst { - err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty); + if !lexmatch(P, #null, ',') { + lexexpect(P, ')'); + break; } - } - args->push(ex); - let param = &Fn.params[1]; - while !lexmatch(P, #null, ')') { - P.targty = *param++; - args->push(parseexpr(P)); - if args.len > Fn.params.#len and !Fn.variadic { - fatal(P, args->last().loc, "too many args (%z, expected %z)", args.len, Fn.params.#len); } - if !lexmatch(P, #null, ',') { - lexexpect(P, ')'); - break; + if args.len < Fn.params.#len { + err(P, ex.loc, "too few args (%z, expected %z)", args.len, Fn.params.#len); } + let met Expr = { tok.loc, f.ty, :Symbol(decl) }; + ex = { tok.loc, .ty: Fn.ret, .u: :Call { exprdup(P.alloc, met), args->move(P.alloc) }}; + + case else; + fatal(P, tok.loc, "cannot call `->%s': not a function or macro", name); } - if args.len < Fn.params.#len { - err(P, ex.loc, "too few args (%z, expected %z)", args.len, Fn.params.#len); + + case VaList; + if !islvalue(&ex) { + err(P, ex.loc, "variadic list receiver must be lvalue"); + } + if exptr { + ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}}; } - let met Expr = { tok.loc, f.ty, :Symbol(decl) }; - ex = { tok.loc, .ty: Fn.ret, .u: :Call { exprdup(P.alloc, met), args->move(P.alloc) }}; + switch { + case streq(name, "start"); + lexexpect(P, '('); + if !lexmatch(P, #null, ')') { + let _ = parseexpr(P); + lexmatch(P, #null, ','); + warn(P, ex.loc, "variadic list `start' doesn't need an argument"); + lexexpect(P, ')'); + } + ex = { tok.loc, ty_void, :VaStart(exprdup(P.alloc, ex)) }; - case else; - fatal(P, tok.loc, "cannot call `->%s': not a function or macro", name); + case streq(name, "arg"); + lexexpect(P, '('); + let type = parsetype(P); + lexmatch(P, #null, ','); + lexexpect(P, ')'); + ex = { tok.loc, type, :VaArg(exprdup(P.alloc, ex)) }; + + case streq(name, "end"); + lexexpect(P, '('); + lexmatch(P, #null, ','); + lexexpect(P, ')'); + ex = { tok.loc, ty_void, :VaEnd(exprdup(P.alloc, ex)) }; + + case else + fatal(P, tok.loc, "`%s' is not a valid method for variadic list", name); + } + + case else + fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty); } case else; @@ -2241,28 +2261,30 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt { } lexexpect(P, '{'); let body Block #?; - with_tmpchange(P.curloop, ++P.loopid) { + let loopid = ++P.loopid; + with_tmpchange(P.curloop, 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) }); + putdecl(P, loc, { label, loc, .u: :Label(loopid) }); } body = parseblock(P); popenv(P); } - return { loc, :While { test, body, P.loopid }}; + return { loc, :While { test, body, loopid }}; } fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt { lexexpect(P, '{'); let body Block #?; - with_tmpchange(P.curloop, ++P.loopid) { + let loopid = ++P.loopid; + with_tmpchange(P.curloop, 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) }); + putdecl(P, loc, { label, loc, .u: :Label(loopid) }); } body = parseblock(P); popenv(P); @@ -2272,7 +2294,7 @@ fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt { 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 }}; + return { loc, :DoWhile { test, body, loopid }}; } fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { @@ -2311,18 +2333,18 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt { lexexpect(P, '{'); } let body Block #?; - let id = ++P.loopid; - with_tmpchange(P.curloop, id) { + let loopid = ++P.loopid; + with_tmpchange(P.curloop, loopid) { let env = mkenv(P.curenv, P.alloc); defer envfree(env); pushenv(P, env); if label { - putdecl(P, loc, { label, loc, .u: :Label(id) }); + putdecl(P, loc, { label, loc, .u: :Label(loopid) }); } body = parseblock(P); popenv(P); } - return { loc, :For { ini, test, next, body, id }}; + return { loc, :For { ini, test, next, body, loopid }}; } fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { @@ -2755,10 +2777,10 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec return decl; } -fn parse4import(P *Parser) [#]Decl; -fn doimport(P *Parser, loc Loc, path *const u8) [#]Decl { +fn parse4import(P *Parser) [#]*Decl; +fn doimport(P *Parser, loc Loc, path *const u8) [#]*Decl { struct Entry { - decls [#]Decl, + decls [#]*Decl, wip bool, } static seen Map<*const u8, Entry, struct { @@ -2993,7 +3015,7 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr; let decls = doimport(P, tok.loc, path); foreach(decl, _, decls) { - let decl = putdecl(P, decl.loc, decl); + let decl = putdecl(P, decl.loc, *decl); if yield { yield(decl, yarg); } @@ -3131,14 +3153,14 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) } } -fn parse4import(P *Parser) [#]Decl { - let decls Vec<Decl> = {}; +fn parse4import(P *Parser) [#]*Decl { + let decls Vec<*Decl> = {}; P.curenv = mkenv(#null, P.alloc); while !P.eof { fn yield(decl *Decl, arg *void) void { - let decls *Vec<Decl> = arg; - decls->push(*decl); + let decls *Vec<*Decl> = arg; + decls->push(decl); } parsedecls(P, P.tokloc, &yield, &decls, #{toplevel} #t); if lexmatch(P, #null, :eof) { |