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