diff options
| author | 2022-08-17 11:11:22 +0200 | |
|---|---|---|
| committer | 2022-08-17 11:11:22 +0200 | |
| commit | ffc52a0ecb61d0f7488f91d9b124344e50f7855f (patch) | |
| tree | 22a0f55e0adc570aae26160acc655f323d738943 /src/parse.cff | |
| parent | d378b8c2bc4b3896e0041bd1c48407800a088ef3 (diff) | |
ack check
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 172 |
1 files changed, 139 insertions, 33 deletions
diff --git a/src/parse.cff b/src/parse.cff index 098d916..13c89f5 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -541,26 +541,23 @@ defmacro lexexpect(P, t) [lexexpects(P, t, #null)] static primenv *Env = {}; fn finddecl(P *Parser, name *const u8) *Decl { - if primenv == #null { - primenv = mkenv(#null, P.alloc); - putprimtypes(primenv); - } let p = envfind(primenv, name); return p ?? envfind(P.curenv, name); } -fn putdecl(P *Parser, decl Decl) *Decl { - if primenv == #null { - primenv = mkenv(#null, P.alloc); - putprimtypes(primenv); - } +fn finddecl_noparent(P *Parser, name *const u8) *Decl { + let p = envfind(primenv, name); + return p ?? envfind_noparent(P.curenv, name); +} + +fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl { if envfind(primenv, decl.name) { - fatal(P, decl.loc, "cannot shadow primitive `%s'", decl.name); + fatal(P, eloc, "cannot shadow primitive `%s'", decl.name); } let d0 *const Decl; let d = envput(P.curenv, decl, &d0); if d == #null { - fatal(P, decl.loc, "attempt to redefine `%s' (previously defined at %l)", decl.name, d0.loc); + fatal(P, eloc, "attempt to redefine `%s' (previously defined at %l)", decl.name, d0.loc); } return d; } @@ -569,6 +566,45 @@ fn putdecl(P *Parser, decl Decl) *Decl { // Types Parsing // /////////////////// +fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type { + let loc = P.tokloc; + let tok Tok #?; + static id int = 0; + let decl *Decl = name ? finddecl_noparent(P, name) : #null; + if decl { + switch decl.u { + case Ty ty; if !ty->is(:Agg) or !ty.u.Agg.fwd { decl = #null; } + } + } + let ty = decl ? decl.u.Ty : interntype({ .u: :Agg { kind, name, id++ }}); + let agg = &(as(*Type)ty).u.Agg; + + if name != #null and lexmatch(P, &tok, ';') { + agg.fwd = #t; + if decl == #null { + decl = putdecl(P, loc, { name, loc, .u: :Ty(ty)}); + if retdecl { + *retdecl = decl; + } + } + return ty; + } else { + agg.fwd = #f; + + } +} + +fn xident2type(P *Parser, eloc Loc, name *const u8) *const Type { + let decl = finddecl(P, name); + if decl == #null { + fatal(P, eloc, "`%s' is not defined", name); + } + if decl.u.#tag != :Ty { + fatal(P, eloc, "`%s' is not a type", name); + } + return decl.u.Ty; +} + fn parsetype(P *Parser) *const Type { let tok Tok = {}; switch { @@ -577,15 +613,7 @@ fn parsetype(P *Parser) *const Type { case lexmatch(P, &tok, '*'); return mkptrtype(parsetype(P)); case lexmatch(P, &tok, :ident); - let decl = finddecl(P, tok.u.ident); - if decl == #null { - fatal(P, tok.loc, "%qT is not defined", tok); - } - if decl.u.#tag != :Ty { - fatal(P, tok.loc, "%qT is not a type", tok); - } - return decl.u.Ty; - + return xident2type(P, tok.loc, tok.u.ident); case else; fatal(P, tok.loc, "expected type (near %qT)", tok); } @@ -1186,6 +1214,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie } else if lexmatch(P, #null, '#?') { ini = :None; } else { + ini = :None; fwd = #t; } } @@ -1201,7 +1230,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie if !letp { decl.u.#tag = :Static; } - yield(putdecl(P, decl), yarg); + yield(putdecl(P, tok.loc, decl), yarg); if !lexmatch(P, &tok, ',') { lexexpects(P, ';', "`,' or `;'"); @@ -1210,7 +1239,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie } while !lexmatch(P, &tok, ';'); } -fn parsefn(P *Parser, externp bool, name *const u8) void { +fn parsefn(P *Parser, externp bool, name *const u8) *Decl { let decl Decl = { name, P.tokloc, @@ -1231,8 +1260,19 @@ fn parsefn(P *Parser, externp bool, name *const u8) void { lexexpect(P, ')'); break; } - let name = lexexpect(P, :ident).u.ident; - let type = parsetype(P); + let name *const u8 = #null; + let type *const Type #?; + if lexmatch(P, &tok, :ident) { + let tok2 Tok #?; + if (tok2 = lexpeek(P)).t == ',' or tok2.t == ')' { + type = xident2type(P, tok.loc, tok.u.ident); + } else { + name = tok.u.ident; + type = parsetype(P); + } + } else { + type = parsetype(P); + } paramnames->push(name); paramtys->push(type); if !lexmatch(P, &tok, ',') { @@ -1247,11 +1287,11 @@ fn parsefn(P *Parser, externp bool, name *const u8) void { }}); static id int = 0; Fn.id = ++id; - putdecl(P, decl); + let decl = putdecl(P, tok.loc, decl); if !lexmatch(P, #null, '{') { lexexpects(P, ';', "';' or '{'"); - return; + return decl; } with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }, @@ -1260,7 +1300,7 @@ fn parsefn(P *Parser, externp bool, name *const u8) void { P.curenv = env; foreach(name, i, Fn.paramnames, if name { - putdecl(P, { name, tok.loc, .u: :Let { + putdecl(P, tok.loc, { name, tok.loc, .u: :Let { Fn.ty.u.Fn.params[i], :None, #f, Fn.id, }}); } @@ -1271,6 +1311,7 @@ fn parsefn(P *Parser, externp bool, name *const u8) void { (as(*Arena)P.alloc.a)->destroy(); ); ); + return decl; } fn doimport(P *Parser, path *const u8) [#]Decl { @@ -1313,13 +1354,14 @@ fn doimport(P *Parser, path *const u8) [#]Decl { P2.is_header = #t; let e = seen->put(rpath, { {}, #t }); let decls = parse(&P2); + *e = { decls, #f }; return decls; } fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { let tok = Tok { .loc: P.tokloc }, - decl = Decl {}, + decl *Decl = {}, externp = #f, name *const u8 = #null; @@ -1333,25 +1375,85 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { switch { case lexmatch(P, &tok, :kw_fn); let name = lexmatch(P, &tok, :ident) ? tok.u.ident : #null; - parsefn(P, externp, name); - return; + decl = parsefn(P, externp, name); + 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, - let decl = putdecl(P, decl); + let decl = putdecl(P, tok.loc, decl); if yield { yield(decl, yarg); } ) lexexpect(P, ';'); return; + + case lexmatch(P, &tok, :kw_struct); + let name = lexexpect(P, :ident).u.ident; + parseagg(P, :Struct, name, &decl); + + case lexmatch(P, &tok, :kw_static); + struct Arg { + P *Parser, + externp bool, + toplevel bool, + yield DeclYielder, + yarg *void, + } + fn varyield(decl *Decl, arg *void) void { + let a *Arg = arg; + let Var = decl.u.Static; + if !a.toplevel and !a.externp and Var.fwd { + err(a.P, decl.loc, "static variable inside function cannot be forward-declared"); + } + if !a.toplevel and a.externp and !Var.fwd { + err(a.P, decl.loc, "extern variable inside function cannot be initialized"); + } + if a.P.is_header and a.externp and !Var.fwd { + err(a.P, decl.loc, "extern variable inside header cannot be initialized"); + } + if a.yield { + a.yield(decl, a.yarg); + } + } + parsevardecl(P, toplevel, externp, #{let?} #t, &varyield, &Arg { P, externp, toplevel, yield, yarg }); + return; + + case lexmatch(P, &tok, :kw_def); + do { + let tok = lexexpect(P, :ident), + name = tok.u.ident, + ini Expr #?, + ty *const Type = #null; + + if lexmatch(P, #null, '=') { + ini = parseexpr(P); + ty = unconstify(ini.ty); + } else { + ty = parsetype(P); + lexexpect(P, '='); + ini = parseexpr(P); + } + if !typematchestarg(ty, ini.ty) { + err(P, ini.loc, "incompatible initializer (%t, expected %t)", ini.ty, ty); + } + yield(putdecl(P, tok.loc, { + name, tok.loc, .u: :Def(ini) + }), yarg); + if !lexmatch(P, &tok, ',') { + lexexpects(P, ';', "`,' or `;'"); + break; + } + } while !lexmatch(P, &tok, ';'); + return; + case else; fatal(P, tok.loc, "expected declaration (near %qT)", tok); } - if yield { - yield(putdecl(P, decl), yarg); + if yield != #null and decl != #null { + yield(decl, yarg); } } @@ -1361,6 +1463,10 @@ extern fn parse(P *Parser) [#]Decl { let decls Vec<Decl> = {}; P.alloc = &alloc; P.curenv = mkenv(#null, P.alloc); + if primenv == #null { + primenv = mkenv(#null, P.alloc); + putprimtypes(primenv); + } while !P.eof { fn yield(decl *Decl, arg *void) void { |