aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-18 09:47:54 +0200
committerlemon <lsof@mailbox.org>2022-08-18 09:47:54 +0200
commitf0214ff61b5a94b9629db6f43d7a5b010bd4ffbc (patch)
treec8517b4950bc3937e82ff49c757fb24a7364e3b0 /src/parse.cff
parent8c81c70b904a41b8a0d44dc418b7c39bf325c2a2 (diff)
fix bodyarg
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff179
1 files changed, 149 insertions, 30 deletions
diff --git a/src/parse.cff b/src/parse.cff
index f19b586..7d083fb 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -407,9 +407,9 @@ fn lex(P *Parser) Tok {
fatal(P, P.tokloc, "too long multichar literal %qs", str.dat);
}
tok.u.uint = 0;
- vec_each(c0, i, str,
+ vec_each(c0, i, str) {
tok.u.uint = (tok.u.uint << 8) | c0;
- )
+ }
}
return tok;
}
@@ -540,6 +540,16 @@ defmacro lexexpect(P, t) [lexexpects(P, t, #null)]
static primenv *Env = {};
+fn pushenv(P *Parser, env *Env) void {
+ assert(P.curenv == envparent(env), "pushenv");
+ P.curenv = env;
+}
+
+fn popenv(P *Parser) void {
+ P.curenv = envparent(P.curenv);
+ assert(P.curenv != #null, "popenv");
+}
+
fn finddecl(P *Parser, name *const u8) *Decl {
let p = envfind(primenv, name);
return p ?? envfind(P.curenv, name);
@@ -568,6 +578,8 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl {
fn parseexpr(P *Parser) Expr;
fn parsetype(P *Parser) *const Type;
+typedef DeclYielder *fn(*Decl, *void) void;
+fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void;
fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
lexexpect(P, '{');
@@ -597,6 +609,15 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
}
+fn isdecltokt(t TokT) bool {
+ switch t {
+ case :kw_fn, :kw_static, :kw_def, :kw_defmacro, :kw_struct, :kw_union, :kw_enum,
+ :kw_extern;
+ return #t;
+ }
+ return #f;
+}
+
fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type {
let loc = P.tokloc;
let tok Tok #?;
@@ -625,7 +646,12 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type
lexexpect(P, '{');
let size = 0, align = 1;
let flds Vec<AggField> = {};
+ let havedecls = #f;
while !lexmatch(P, #null, '}') {
+ if isdecltokt(lexpeek(P).t) {
+ havedecls = #t;
+ break;
+ }
let off = size;
let name = lexexpects(P, :ident, "field name").u.ident;
let type = parsetype(P);
@@ -645,6 +671,14 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type
ty.size = size;
ty.align = align;
agg.flds = flds.dat[0::flds.len];
+ if havedecls {
+ agg.decls = mkenv(P.curenv, P.alloc);
+ pushenv(P, agg.decls);
+ while !lexmatch(P, #null, '}') {
+ parsedecls(P, #null, #null, #{toplevel} #f);
+ }
+ popenv(P);
+ }
}
return ty;
}
@@ -716,6 +750,22 @@ fn parsetype(P *Parser) *const Type {
case lexmatch(P, &tok, '*');
return mkptrtype(parsetype(P));
+ case lexmatch(P, &tok, '[');
+ let len = -1i64;
+ if lexmatch(P, &tok, '#') {
+ lexexpect(P, ']');
+ return mkslicetype(parsetype(P));
+ } else if !lexmatch(P, &tok, ']') {
+ let ex = parseexpr(P);
+ lexexpect(P, ']');
+ if !fold(&ex) or ex.u.#tag != :IntLit or ex.u.IntLit.i < 0 {
+ fatal(P, ex.loc, "expected constant non-negative integer expression for array length");
+ }
+ len = ex.u.IntLit.i;
+ }
+ let child = parsetype(P);
+ return mkarrtype(len, #f, child);
+
case lexmatch(P, &tok, :ident);
return xident2type(P, tok.loc, tok.u.ident);
@@ -755,28 +805,31 @@ fn islvalue(ex Expr) bool {
return u.op == :deref;
case Index;
return #t;
+ case Dot;
+ return #t;
}
return #f;
}
fn pexprimary(P *Parser) Expr {
let tok Tok = lex(P);
+ let ex Expr #?;
switch tok.t {
case :int, :chr;
- return { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
+ ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
case :flo;
- return { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
+ ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
case :bool;
- return { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
+ ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
case :null;
- return { tok.loc, ty_voidptr, .u: :NullLit };
+ ex = { tok.loc, ty_voidptr, .u: :NullLit };
case :str;
let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
- return { tok.loc, ty, .u: :StrLit(tok.u.str) };
+ ex = { tok.loc, ty, .u: :StrLit(tok.u.str) };
case :ident;
let ident = tok.u.ident;
@@ -786,14 +839,14 @@ fn pexprimary(P *Parser) Expr {
}
switch decl.u {
case Fn f;
- return { tok.loc, f.ty, .u: :Symbol(decl) };
+ ex = { tok.loc, f.ty, .u: :Symbol(decl) };
case Let var;
- return { tok.loc, var.ty, .u: :Symbol(decl) };
+ ex = { tok.loc, var.ty, .u: :Symbol(decl) };
case Static var;
- return { tok.loc, var.ty, .u: :Symbol(decl) };
- case Def ex;
- ex.loc = tok.loc;
- return ex;
+ ex = { tok.loc, var.ty, .u: :Symbol(decl) };
+ case Def dex;
+ dex.loc = tok.loc;
+ ex = dex;
}
case :kw_sizeof;
let ty *const Type #?;
@@ -807,16 +860,27 @@ fn pexprimary(P *Parser) Expr {
if !completetype(ty) {
err(P, tok.loc, "sizeof incomplete type (%t)", ty);
}
- return { tok.loc, ty_usize, :IntLit { ty.size }};
+ ex = { tok.loc, ty_usize, :IntLit { ty.size }};
case '(';
- let ex = parseexpr(P);
+ ex = parseexpr(P);
lexexpect(P, ')');
- return ex;
+ case '{';
+ if P.targty == #null {
+ fatal(P, tok.loc, "cannot infer type for initializer");
+ }
+ let ty = P.targty;
+ if lexmatch(P, #null, '}') {
+ ex = { tok.loc, ty, .u: :ZeroIni };
+ } else {
+ assert(#f, "NYI");
+ }
case else;
fatal(P, tok.loc, "expected expression (near %qT)", tok);
}
+ P.targty = #null;
+ return ex;
}
fn pexpostfix(P *Parser) Expr {
@@ -890,8 +954,33 @@ fn pexpostfix(P *Parser) Expr {
tok.t == '++' ? :postinc : :postdec, exprdup(P.alloc, ex)
}
};
+ case lexmatch(P, &tok, '.');
+ let name = (tok = lexexpects(P, :ident, "field name")).u.ident;
+ let ty = ex.ty;
+ if 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 fld *AggField = #null;
+ foreach(f, i, agg.flds) {
+ if streq(name, f.name) {
+ fld = &agg.flds[i];
+ break;
+ }
+ }
+ if fld == #null {
+ fatal(P, tok.loc, "%t has no such field %qT", ty, tok);
+ }
+ if fld.ty == #null {
+ fatal(P, tok.loc, "field %qT has no type", tok);
+ }
+ ex = { tok.loc, fld.ty, :Dot { exprdup(P.alloc, ex), fld }};
+
case else;
- break;
+ break;
}
}
return ex;
@@ -956,6 +1045,15 @@ fn pexprefix(P *Parser) Expr {
err(P, ex.loc, "invalid operand to `&': not an lvalue");
}
return { tok.loc, ty2, .u: :UnOp { :addrof, exprdup(P.alloc, ex) }};
+
+ case lexmatch(P, &tok, :kw_as);
+ let loc = tok.loc;
+ lexexpect(P, '(');
+ let ty = parsetype(P);
+ lexexpect(P, ')');
+ let ex = pexprefix(P);
+ // TODO check valid cast
+ return { loc, ty, :Cast(exprdup(P.alloc, ex)) };
}
return pexpostfix(P);
}
@@ -1161,7 +1259,6 @@ fn stmtdup(alloc *Allocator, st Stmt) *Stmt {
return memcpy(alloc->alloc(sizeof(st)), &st, sizeof(st));
}
-typedef DeclYielder *fn(*Decl, *void) void;
typedef StmtYielder *fn(Stmt, *void) void;
fn parseblock(P *Parser) [#]Stmt;
fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void;
@@ -1314,6 +1411,18 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
lexexpect(P, ';');
return yield({ tok.loc, :Continue(P.curloop) }, yarg);
+ case isdecltokt(tok.t);
+ struct Arg {
+ P *Parser,
+ yield StmtYielder,
+ yarg *void,
+ }
+ fn declyield(decl *Decl, arg *void) void {
+ let a *Arg = arg;
+ a.yield({ decl.loc, :Decl(decl) }, a.yarg);
+ }
+ parsedecls(P, &declyield, &Arg { P, yield, yarg }, #{toplevel?} #f);
+
case else;
let ex = parseexpr(P);
lexexpect(P, ';');
@@ -1324,6 +1433,8 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
fn parseblock0(P *Parser) [#]Stmt {
let sts Vec<Stmt> = {};
let tok Tok = {};
+ let env = mkenv(P.curenv, P.alloc);
+ 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 {
@@ -1332,6 +1443,7 @@ fn parseblock0(P *Parser) [#]Stmt {
}
parsestmts(P, &pushstmt, &sts);
}
+ popenv(P);
return sts->move(P.alloc);
}
@@ -1362,6 +1474,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie
ty = parsetype(P);
if lexmatch(P, #null, '=') {
+ P.targty = ty;
ini = :Some(parseexpr(P));
} else if lexmatch(P, #null, '#?') {
ini = :None;
@@ -1400,10 +1513,10 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl {
};
let Fn = &decl.u.Fn,
- tok Tok = {},
paramnames Vec<*const u8> = {},
paramtys Vec<*const Type> = {};
+ let loc = P.tokloc;
parsefnparams(P, &Fn.variadic, &paramnames, &paramtys);
Fn.paramnames = paramnames->move(P.alloc);
let retty = parsetype(P);
@@ -1412,7 +1525,7 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl {
}});
static id int = 0;
Fn.id = ++id;
- let decl = putdecl(P, tok.loc, decl);
+ let decl = putdecl(P, loc, decl);
if !lexmatch(P, #null, '{') {
lexexpects(P, ';', "';' or '{'");
@@ -1422,16 +1535,16 @@ fn parsefn(P *Parser, externp bool, name *const u8) *Decl {
with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf },
with_tmpchange(P.curfn, Fn,
let env = mkenv(P.curenv, P.alloc);
- P.curenv = env;
- foreach(name, i, Fn.paramnames,
+ pushenv(P, env);
+ foreach(name, i, Fn.paramnames) {
if name {
- putdecl(P, tok.loc, { name, tok.loc, .u: :Let {
+ putdecl(P, loc, { name, loc, .u: :Let {
Fn.ty.u.Fn.params[i], :None, #f, Fn.id,
}});
}
- )
+ }
Fn.body = :Some(parseblock(P));
- P.curenv = envparent(env);
+ popenv(P);
envfree(env);
(as(*Arena)P.alloc.a)->destroy();
);
@@ -1467,7 +1580,7 @@ fn doimport(P *Parser, path *const u8) [#]Decl {
snprintf(path2, sizeof(path2) - 1, "%s/%s", basedir, path);
let rpath *const u8 = realpath(path2, _rpath);
if rpath == #null {
- fatal(P, P.tokloc, "import %qs: %s", path, strerror(c_errno()));
+ fatal(P, P.tokloc, "import %qs: %s", path, strerror(errno));
}
let d0 = seen->get(rpath);
if d0 != #null {
@@ -1505,6 +1618,12 @@ fn parsemacro(P *Parser, name *const u8) *Decl {
lexmatch(P, &tok, ',');
lexexpect(P, ')');
break;
+ } else if lexmatch(P, &tok, '&') {
+ params->push(lexexpects(P, :ident, "parameter name").u.ident);
+ c.bodyarg = #t;
+ lexmatch(P, &tok, ',');
+ lexexpect(P, ')');
+ break;
} else {
params->push(lexexpects(P, :ident, "parameter name").u.ident);
if !lexmatch(P, &tok, ',') {
@@ -1526,11 +1645,11 @@ fn parsemacro(P *Parser, name *const u8) *Decl {
fatal(P, eloc, "unterminated macro definition");
}
if tok.t == :ident {
- vec_each(par, _, params,
+ vec_each(par, _, params) {
if streq(par, tok.u.ident) {
tok.t = :macident;
}
- )
+ }
} else if tok.t == :gensym {
let gs *Gensyms #?;
let found = #f;
@@ -1605,12 +1724,12 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void {
case lexmatch(P, &tok, :kw_import);
let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr;
let decls = doimport(P, path);
- foreach(decl, _, decls,
+ foreach(decl, _, decls) {
let decl = putdecl(P, tok.loc, decl);
if yield {
yield(decl, yarg);
}
- )
+ }
lexexpect(P, ';');
return;