From ffc52a0ecb61d0f7488f91d9b124344e50f7855f Mon Sep 17 00:00:00 2001 From: lemon Date: Wed, 17 Aug 2022 11:11:22 +0200 Subject: ack check --- src/cffc.hff | 22 ++++++++ src/env.cff | 5 ++ src/parse.cff | 172 +++++++++++++++++++++++++++++++++++++++++++++++----------- src/type.cff | 18 ++++++ 4 files changed, 184 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/cffc.hff b/src/cffc.hff index 6147377..32683eb 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -57,6 +57,18 @@ struct Tok { }, } +enum AggKind { + Struct, + Union, + EUnion, +} + +struct AggField { + name *const u8, + ty *const Type, + off usize, +} + struct Type { size usize, align usize, @@ -75,6 +87,14 @@ struct Type { variadic bool, ret *const Type, }, + Agg struct { + kind AggKind, + name *const u8, + id int, + fwd bool, + flds [#]AggField, + decls [#]*Decl, + }, }, fn is(ty *const Type, tag typeof((Type{}).u.#tag)) bool { @@ -172,6 +192,7 @@ struct Decl { u enum union { Let Var, Static Var, + Def Expr, Fn Fn, Ty *const Type, }, @@ -289,4 +310,5 @@ extern fn mkenv(parent *Env, alloc *Allocator) *Env; extern fn envparent(*Env) *Env; extern fn envput(*Env, Decl, **const Decl) *Decl; extern fn envfind(*Env, *const u8) *Decl; +extern fn envfind_noparent(*Env, *const u8) *Decl; extern fn envfree(*Env) void; diff --git a/src/env.cff b/src/env.cff index 001e92c..f18fe49 100644 --- a/src/env.cff +++ b/src/env.cff @@ -50,6 +50,11 @@ extern fn envfind(env *Env, name *const u8) *Decl { return &l.decl; } +extern fn envfind_noparent(env *Env, name *const u8) *Decl { + let l **DeclList = env.decls->get(name); + return l ? &(*l).decl : #null; +} + extern fn envfree(env *Env) void { env.decls->clear(); free(env); 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 = {}; 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 { diff --git a/src/type.cff b/src/type.cff index a4a4e3d..b18c5c4 100644 --- a/src/type.cff +++ b/src/type.cff @@ -29,7 +29,16 @@ struct TypeTraits { case Slice child; h = fnv1a_i(h, child.id); + case Fn f; + h = fnv1a_i(h, f.ret.id); + foreach(p, _, f.params, + h = fnv1a_i(h, p.id); + ) + + case Agg agg; + h = fnv1a_i(h, agg.id); } + return h; } @@ -40,15 +49,20 @@ struct TypeTraits { } switch a.u { case Void; case Bool; case Flo; + case Int i; return i.sgn == b.u.Int.sgn; + case Ptr child; return child == b.u.Ptr; + case Arr arr; let brr = b.u.Arr; return arr.length == brr.length and arr.child == brr.child; + case Slice child; return child == b.u.Slice; + case Fn f0; let f1 = b.u.Fn; if f0.variadic != f1.variadic { @@ -66,6 +80,10 @@ struct TypeTraits { } ) return #t; + + case Agg agg; + let bgg = b.u.Agg; + return agg.id == bgg.id; } return #f; } -- cgit v1.2.3