diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cffc.hff | 103 | ||||
| -rw-r--r-- | src/common.hff | 13 | ||||
| -rw-r--r-- | src/env.cff | 23 | ||||
| -rw-r--r-- | src/fmt.cff | 121 | ||||
| -rw-r--r-- | src/libc.hff | 1 | ||||
| -rw-r--r-- | src/map.hff | 27 | ||||
| -rw-r--r-- | src/mem.hff | 4 | ||||
| -rw-r--r-- | src/parse.cff | 327 | ||||
| -rw-r--r-- | src/targ.cff | 1 | ||||
| -rw-r--r-- | src/type.cff | 146 | ||||
| -rw-r--r-- | src/util.cff | 13 | ||||
| -rw-r--r-- | src/util.hff | 2 |
12 files changed, 714 insertions, 67 deletions
diff --git a/src/cffc.hff b/src/cffc.hff index dcb91f7..6910179 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -41,8 +41,7 @@ enum TokT : i32 { strify, eof, } -def NUM_KEYWORDS = TokT:NUM_KEYWORDS; - +def NUM_KEYWORDS int = TokT:NUM_KEYWORDS; struct Tok { t TokT, @@ -69,8 +68,13 @@ struct Type { Int struct { sgn bool }, Flo, Ptr *Type, - Arr struct { child *Type, length i64 }, + Arr struct { child *const Type, length i64 }, Slice *Type, + Fn struct { + params [#]*const Type, + variadic bool, + ret *const Type, + }, } } @@ -78,6 +82,7 @@ struct Parser { fp *FILE, alloc *Allocator, curfile *const u8, + curenv *Env, tokloc Loc, curloc Loc, eof bool, @@ -85,8 +90,41 @@ struct Parser { peektok Option<Tok>, } +struct Expr { + loc Loc, + ty *const Type, + u enum union { + IntLit union { i i64, u u64 }, + FloLit f64, + StrLit [#]const u8, + BoolLit bool, + NullLit, + } +} + +struct Stmt { + loc Loc, + u enum union { + Block [#]Stmt, + Expr Expr, + } +} + +struct Fn { + ty *const Type, + paramnames [#]*const u8, + variadic bool, + id int, + body Option<[#]Stmt> +} + struct Decl { name *const u8, + loc Loc, + u enum union { + Fn Fn, + Ty *const Type, + }, } struct DeclList { @@ -98,6 +136,7 @@ struct Targ { name *const u8, ptrsize u8, intsize u8, + i64align u8, longsize u8, longalign u8, llongsize u8, llongalign u8, sizesize u8, @@ -108,6 +147,7 @@ struct Targ { } // parse.cff +extern static keyword2str [NUM_KEYWORDS]*const u8; extern fn parser_init(*Parser, path *const u8) void; extern fn parse(*Parser) [#]Decl; @@ -116,16 +156,59 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, va_list) vo extern fn pfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ...) void; extern fn vefmt(fmt *const u8, ap va_list) void; extern fn efmt(fmt *const u8, ...) void; - -// .. util.cff .. +extern fn ssfmt(fmt *const u8, ...) *const u8; extern fn fatal(*Parser, Loc, fmt *const u8, ...) void; +// targ.cff +extern static g_targ *const Targ; +extern fn targ_ini(name *const u8) bool; + // type.cff +extern static ty_void *const Type, + ty_bool *const Type, + ty_i8 *const Type, + ty_u8 *const Type, + ty_i16 *const Type, + ty_u16 *const Type, + ty_i32 *const Type, + ty_u32 *const Type, + ty_int *const Type, + ty_uint *const Type, + ty_i64 *const Type, + ty_u64 *const Type, + ty_isize *const Type, + ty_usize *const Type, + ty_iptrint *const Type, + ty_uptrint *const Type, + ty_f32 *const Type, + ty_f64 *const Type, + ty_voidptr *const Type; +extern fn interntype(Type) *const Type; +extern fn putprimtypes(env *Env) void; +fn constify(ty *const Type) *const Type { + if ty.konst or ty.u.#tag == :Fn { + return ty; + } + let ty2 = *ty; + ty2.konst = #t; + return interntype(ty2); +} +fn mkarrtype(len i64, konst bool, child *const Type) *const Type { + return interntype({ + len * child.size, + child.align, + .u: :Arr { konst ? constify(child) : child, len } + }); +} +fn mkptrtype(child *const Type) *const Type { + return interntype({ + g_targ.ptrsize, + .u: :Ptr child + }); +} // env.cff extern fn mkenv(parent *Env, alloc *Allocator) *Env; -extern fn envput(*Env, *const Decl) *Decl; - -// targ.cff -extern static g_targ *const Targ; -extern fn targ_ini(name *const u8) bool; +extern fn envput(*Env, Decl, **const Decl) *Decl; +extern fn envfind(*Env, *const u8) *Decl; +extern fn envfree(*Env) void; diff --git a/src/common.hff b/src/common.hff index aac733e..fe90e09 100644 --- a/src/common.hff +++ b/src/common.hff @@ -26,6 +26,19 @@ defmacro foreach(x, i, a, ...body) [ ] defmacro streq(a,b) [ (strcmp(a,b) == 0) ] +defmacro strcieq(a,b) [ (strcasecmp(a,b) == 0) ] + +defmacro coalesce(a,b) [ + (do let $x = a; + $x ? $x : b; ) +] + +defmacro with_tmpchange(var,x,...body) [ + { let $tmp = (var); + (var) = x; + { body } + (var) = $tmp; } +] // Inline functions fn bswap32(x u32) u32 { diff --git a/src/env.cff b/src/env.cff index d1eab07..0ae465a 100644 --- a/src/env.cff +++ b/src/env.cff @@ -1,6 +1,7 @@ import "cffc.hff"; import "map.hff"; import "util.hff"; +import "common.hff"; struct StringKeyTraits { fn hash(s *const u8) u32 { return fnv1a_s(FNV1A_INI, s); } @@ -19,11 +20,27 @@ extern fn mkenv(parent *Env, alloc *Allocator) *Env { return env; } -extern fn envput(env *Env, decl *const Decl) *Decl { +extern fn envput(env *Env, decl Decl, old **const Decl) *Decl { let l **DeclList = env.decls->get_slot(decl.name); - let n *DeclList = env.alloc->alloc(sizeof *DeclList); + let n *DeclList = anew(env.alloc, DeclList); + if *l { // decl with this name exists + *old = &(*l).decl; + return #null; + } n.link = *l; - n.decl = *decl; + n.decl = decl; *l = n; return &n.decl; } + +extern fn envfind(env *Env, name *const u8) *Decl { + let l **DeclList = env.decls->get(name); + if l == #null { return #null; } + let l = *l; + assert(l != #null, "l?"); + return &l.decl; +} + +extern fn envfree(env *Env) void { + env.decls->clear(); +} diff --git a/src/fmt.cff b/src/fmt.cff index 90fcd47..5635103 100644 --- a/src/fmt.cff +++ b/src/fmt.cff @@ -1,5 +1,6 @@ import "cffc.hff"; import "common.hff"; +import "util.hff"; extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) void { defmacro p(x) [ proc(x, parg) ] @@ -67,6 +68,8 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) if quote { p('\''); } case :type; pfmt(proc, parg, "%t", tok.ty); + case :eof; + ps("<end of file>"); case else if tok.t >= 0 and tok.t < NUM_KEYWORDS { if quote { p('`'); } @@ -86,6 +89,83 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) } } + fn pritokt(proc typeof(proc), parg *void, t TokT) void { + switch t { + case :int; + ps("integer literal"); + case :flo; + ps("float literal"); + case :bool; + ps("boolean literal"); + case :str; + ps("string literal"); + case :chr; + ps("character literal"); + case :null; + ps("#null"); + case :ident, :macident; + ps("identifier"); + case :label; + ps("label"); + case :gensym; + ps("gensym"); + case :type; + ps("type argument"); + case else + if t >= 0 and t < NUM_KEYWORDS { + p('`'); + ps(keyword2str[t]); + p('\''); + } else if t > 0 { + p('`'); + let t = bswap32(t); + while t != 0 { + if t & 0xFF != 0 { + p(t); + } + t >>= 8; + } + p('\''); + } + } + } + + fn pritype(proc typeof(proc), parg *void, ty *const Type) void { + if ty.konst { + ps("const "); + } + switch ty.u { + case Void; ps("void"); + case Bool; ps("bool"); + case Int i; + p(i.sgn ? 'i' : 'u'); + sprintf(buf, "%zu", ty.size * 8); + ps(buf); + case Flo; + p('f'); + sprintf(buf, "%zu", ty.size * 8); + ps(buf); + case Ptr child; + pfmt(proc, parg, "*%t", child); + case Arr arr; + pfmt(proc, parg, "[%I]%t", arr.length, arr.child); + case Slice child; + pfmt(proc, parg, "[#]%t", child); + case Fn f; + ps("fn ("); + foreach(ty, i, f.params, + pritype(proc, parg, ty); + if f.variadic or i < f.params.#len - 1 { + ps(", "); + } + ) + if f.variadic { + ps("..."); + } + pfmt(proc, parg, ") %t", f.ret); + } + } + for let c u8 = *fmt; c != 0; c = *++fmt { assert(c != 0, "?"); if c != '%' { @@ -102,6 +182,12 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) case 'i', 'd'; sprintf(buf, "%d", ap->arg(int)); ps(buf); + case 'I', 'D'; + sprintf(buf, "%lld", as(c_llong)ap->arg(i64)); + ps(buf); + case 'z'; + sprintf(buf, "%zu", ap->arg(usize)); + ps(buf); case 'p'; sprintf(buf, "%p", ap->arg(*void)); ps(buf); @@ -147,6 +233,11 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) case 'T'; let tok = ap->arg(Tok); pritok(proc, parg, quote, &tok); + case 'k'; + let tokt = ap->arg(TokT); + pritokt(proc, parg, tokt); + case 't'; + pritype(proc, parg, ap->arg(*const Type)); case else assert(#f, "bad fmt '%c'", c); } @@ -175,3 +266,33 @@ extern fn efmt(fmt *const u8, ...) void { vefmt(fmt, ap); ap->end(); } + +extern fn ssfmt(fmt *const u8, ...) *const u8 { + static buf [1024]u8 = {}; + let ap va_list #?; + ap->start(fmt); + fn sputc(c u8, arg *void) void { + let pidx *int = arg; + if *pidx < buf.#len - 1 { + buf[*pidx++] = c; + } + } + let idx = 0; + vpfmt(&sputc, &idx, fmt, ap); + ap->end(); +} + +extern fn vdiag(P *Parser, loc Loc, kind *const u8, fmt *const u8, ap va_list) void { + efmt("%s:%i:%i: %s: ", fileid2path(loc.fileid), loc.line, loc.col, kind); + vefmt(fmt, ap); + efmt("\n"); +} + +extern fn fatal(P *Parser, loc Loc, fmt *const u8, ...) void { + let ap va_list #?; + ap->start(fmt); + vdiag(P, loc, "error", fmt, ap); + ap->end(); + exit(1); +} + diff --git a/src/libc.hff b/src/libc.hff index 488a495..a269f42 100644 --- a/src/libc.hff +++ b/src/libc.hff @@ -25,6 +25,7 @@ extern fn free(p *void) void; // string.h extern fn strlen(s *const u8) usize; extern fn strcmp(a *const u8, b *const u8) int; +extern fn strcasecmp(a *const u8, b *const u8) int; extern fn memcpy(*void, *const void, usize) *void; extern fn strcpy(*u8, *const u8) *u8; diff --git a/src/map.hff b/src/map.hff index d7883dd..f97ea7e 100644 --- a/src/map.hff +++ b/src/map.hff @@ -29,7 +29,7 @@ struct Map<K, V, KTraits> { } i = (i + 1) & (self.N - 1); } while i != h; - assert(#f, "unreachable"); + assert(#f, "unreachable1"); } fn _reallockvb(self *Map) void { @@ -53,16 +53,17 @@ struct Map<K, V, KTraits> { b = (oldbmp[i/8] & (1 << (i%8))) != 0; if (b) { let h u32 = KTraits:hash(k); - let i = h & (self.N - 1); + let j = h & (self.N - 1); for ;; { - if self->_iempty(i) { - self.keys[i] = k; - self.vals[i] = v; - self.bitmap[i/8] |= 1 << (i%8); - } else if KTraits:eq(self.keys[i], k) { - assert(#f, "unreachable"); + if self->_iempty(j) { + self.keys[j] = k; + self.vals[j] = v; + self.bitmap[j/8] |= 1 << (j%8); + break; + } else if KTraits:eq(self.keys[j], k) { + assert(#f, "unreachable2"); } - i = (i + 1) & (self.N - 1); + j = (j + 1) & (self.N - 1); } } @@ -87,6 +88,7 @@ struct Map<K, V, KTraits> { if self->_iempty(i) { self.bitmap[i/8] |= (1 << (i%8)); ++self.count; + self.keys[i] = key; self.vals[i] = {}; return &self.vals[i]; } else if KTraits:eq(self.keys[i], key) { @@ -94,7 +96,7 @@ struct Map<K, V, KTraits> { } i = (i + 1) & (self.N - 1); } while i != h; - assert(#f, "unreachable"); + assert(#f, "unreachable3"); } @@ -102,4 +104,9 @@ struct Map<K, V, KTraits> { *self->get_slot(key) = val; } + fn clear(self *Map) void { + free(self.keys); + *self = {}; + } + } diff --git a/src/mem.hff b/src/mem.hff index 805c3ce..7858f4d 100644 --- a/src/mem.hff +++ b/src/mem.hff @@ -1,7 +1,7 @@ import "libc.hff"; defmacro ALIGNUP(x,a) [ (((x) + ((a) - 1)) & -(a)) ] -def ARENA_SIZE = 16 * 1024; +def ARENA_SIZE = 4 * 1024; extern fn xmalloc(n usize) *void; extern fn xcalloc(n usize, m usize) *void; extern fn xrealloc(p *void, n usize) *void; @@ -68,3 +68,5 @@ struct Allocator { } } } + +defmacro anew(a, T) [ ((a)->alloc(sizeof T)) ] diff --git a/src/parse.cff b/src/parse.cff index 25a2617..0f06259 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -139,7 +139,7 @@ fn eatspaces(P *Parser) void { } // !sorted -static keyword2str []*const u8 = { +extern static keyword2str [NUM_KEYWORDS]*const u8 = { "and", "as", "break", "case", "const", "continue", "def", "defmacro", "do", "else", "enum", "extern", "fn", @@ -214,14 +214,64 @@ fn readnumber(s *const u8) Option<Tok> { } let tok = Tok {}; - assert(suffix == #null,"sufx"); if flt { tok.t = :flo; tok.u.flo = accf; + + switch { + case suffix == #null; tok.ty = ty_f64; + case strcieq(suffix, "f"); tok.ty = ty_f32; + case strcieq(suffix, "f32"); tok.ty = ty_f32; + case strcieq(suffix, "f64"); tok.ty = ty_f64; + case else; return :None; + } + return :Some tok; } else { tok.t = :int; tok.u.uint = acc; + + fn ty4intX(i u64) *const Type { + if i < 1u64 << ((g_targ.intsize * 8) - 1) { + return ty_int; + } + if i < 1u64 << 31 { + return ty_i32; + } + if i < 1u64 << 63 { + return ty_i64; + } + return ty_u64; + } + + fn ty4uintX(i u64) *const Type { + if i < 1u64 << (g_targ.intsize * 8) { + return ty_uint; + } + if i < 1u64 << 32 { + return ty_u32; + } + return ty_u64; + } + + switch { + case suffix == #null; tok.ty = ty4intX(tok.u.uint); + case strcieq(suffix, "u"); tok.ty = ty4uintX(tok.u.uint); + case strcieq(suffix, "u8"); tok.ty = ty_u8; + case strcieq(suffix, "i8"); tok.ty = ty_i8; + case strcieq(suffix, "u16"); tok.ty = ty_u16; + case strcieq(suffix, "i16"); tok.ty = ty_i16; + case strcieq(suffix, "u32"); tok.ty = ty_u32; + case strcieq(suffix, "i32"); tok.ty = ty_i32; + case strcieq(suffix, "u64"); tok.ty = ty_u64; + case strcieq(suffix, "i64"); tok.ty = ty_i64; + case strcieq(suffix, "z"); tok.ty = ty_usize; + case strcieq(suffix, "zs"); tok.ty = ty_isize; + case strcieq(suffix, "p"); tok.ty = ty_uptrint; + case strcieq(suffix, "ps"); tok.ty = ty_iptrint; + case else; return :None; + } + return :Some tok; } } @@ -445,23 +495,280 @@ fn lex(P *Parser) Tok { fatal(P, tok.loc, "stray %qc in program", c); } -extern fn parse(P *Parser) [#]Decl { - fn mallocator_allocf(*void, n usize) *void { - return xmalloc(n); +fn lexpeek(P *Parser) Tok { + switch P.peektok { + case Some t; return t; } + let tok = lex(P); + P.peektok = :Some tok; + return tok; +} - fn mallocator_freef(*void, ptr *void) void { - free(ptr); +fn lexmatch(P *Parser, tokp *Tok, t TokT) bool { + let tok = lexpeek(P); + if tokp { + *tokp = tok; } + if tok.t == t { + lex(P); + return #t; + } + return #f; +} + +fn lexexpects(P *Parser, t TokT, what *const u8) Tok { + let tok = Tok {}; + if not lexmatch(P, &tok, t) { + if what { + fatal(P, tok.loc, "expected %s (near %qT)", what, tok); + } else { + fatal(P, tok.loc, "expected %qk (near %qT)", t, tok); + } + } + return tok; +} +defmacro lexexpect(P, t) [lexexpects(P, t, #null)] +//////////// +// Parser // +//////////// + +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 ? p : envfind(P.curenv, name); +} + +fn putdecl(P *Parser, decl Decl) *Decl { + assert(primenv != #null, "primenv"); + if envfind(primenv, decl.name) { + fatal(P, decl.loc, "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'", decl.name); + } + return d; +} + +/////////////////// +// Types Parsing // +/////////////////// + +fn parsetype(P *Parser) *const Type { + let tok Tok = {}; + switch { + case lexmatch(P, &tok, :kw_const); + return constify(parsetype(P)); + 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; + + case else; + fatal(P, tok.loc, "expected type (near %qT)", tok); + } +} + +///////////////////////// +// Expressions Parsing // +///////////////////////// + +fn pexprimary(P *Parser) Expr { + let tok Tok = lex(P); + switch tok.t { + case :int, :chr; + return { tok.loc, tok.ty, .u: :IntLit { tok.u.int }}; + case :flo; + return { tok.loc, tok.ty, .u: :FloLit tok.u.flo }; + case :bool; + return { tok.loc, ty_bool, .u: :BoolLit tok.u.bool }; + case :null; + return { tok.loc, ty_voidptr, .u: :NullLit }; + case :str; + return { tok.loc, .u: :StrLit tok.u.str }; + case else; + fatal(P, tok.loc, "expected expression (near %qT)", tok); + } +} + +fn pexpostfix(P *Parser) Expr { + let ex = pexprimary(P); + return ex; +} + +fn pexprefix(P *Parser) Expr { + return pexpostfix(P); +} + +fn pexbitarith(P *Parser) Expr { + let ex = pexprefix(P); + return ex; +} + +fn pexcmp(P *Parser) Expr { + let ex = pexbitarith(P); + return ex; +} + +fn pexlog(P *Parser) Expr { + let ex = pexcmp(P); + return ex; +} + +fn pexcond(P *Parser) Expr { + let ex = pexlog(P); + return ex; +} + +fn pexassign(P *Parser) Expr { + let ex = pexcond(P); + return ex; +} + +fn parseexpr(P *Parser) Expr { + return pexassign(P); +} + +//////////////////////// +// Statements Parsing // +//////////////////////// + +typedef DeclYielder *fn(*Decl, *void) void; +typedef StmtYielder *fn(Stmt, *void) void; + +fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void { + let tok Tok = {}; + switch { + case lexmatch(P, &tok, :kw_if); + case else; + return yield({ tok.loc, .u: :Expr parseexpr(P) }, yarg); + } +} + +fn parseblock0(P *Parser) [#]Stmt { + let sts Vec<Stmt> = {}; + let tok Tok = {}; + 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 { + let sts *Vec<Stmt> = arg; + sts->push(st); + } + parsestmts(P, &pushstmt, &sts); + } + return sts->move(P.alloc); +} + +fn parseblock(P *Parser) [#]Stmt { + let b = parseblock0(P); + lexexpect(P, '}'); + return b; +} + +/////////////////// +// Decls Parsing // +/////////////////// + +fn parsefn(P *Parser, decl *Decl, externp bool, name *const u8) void { + decl.name = name; + decl.u = :Fn {}; + + let Fn = &decl.u.Fn, + tok Tok = {}, + paramnames Vec<*const u8> = {}, + paramtys Vec<*const Type> = {}; + + lexexpect(P, '('); + while not lexmatch(P, &tok, ')') { + if lexmatch(P, #null, '...') { + Fn.variadic = #t; + lexmatch(P, #null, ','); + lexexpect(P, ')'); + break; + } + let name = lexexpect(P, :ident).u.ident; + let type = parsetype(P); + paramnames->push(name); + paramtys->push(type); + if not lexmatch(P, &tok, ',') { + lexexpect(P, ')'); + break; + } + } + Fn.paramnames = paramnames->move(P.alloc); + let retty = parsetype(P); + Fn.ty = interntype({ .size: 0, .align: 1, .u: :Fn { + paramtys->move(P.alloc), Fn.variadic, retty + }}); + static id int = 0; + Fn.id = ++id; + + if not lexmatch(P, #null, '{') { + lexexpects(P, ';', "';' or '{'"); + return; + } + + with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }, + Fn.body = :Some parseblock(P); + (as(*Arena)P.alloc.a)->destroy(); + ); +} + +fn parsedecls(P *Parser, yield DeclYielder, yarg *void) void { + let tok = Tok { .loc: P.tokloc }, + decl = Decl {}, + externp = #f, + name *const u8 = #null; + + if lexmatch(P, &tok, :kw_extern) { + externp = #t; + } + + switch { + case lexmatch(P, &tok, :kw_fn); + let name = lexmatch(P, &tok, :ident) ? tok.u.ident : #null; + parsefn(P, &decl, externp, name); + decl.loc = tok.loc; + case else; + fatal(P, tok.loc, "expected declaration (near %qT)", tok); + } + + yield(putdecl(P, decl), yarg); +} + +extern fn parse(P *Parser) [#]Decl { let aralloc = Arena {}; let alloc = Allocator { &aralloc, &Arena:allocf, #null }; + let decls Vec<*Decl> = {}; P.alloc = &alloc; + P.curenv = mkenv(#null, P.alloc); + while not P.eof { - let tok = lex(P); - if tok.t == :eof { break; } - efmt("* tok: %qT\n", tok); + fn yield(decl *Decl, arg *void) void { + let decls *Vec<*Decl> = arg; + decls->push(decl); + } + parsedecls(P, &yield, &decls); + if lexmatch(P, #null, :eof) { + break; + } } + + envfree(P.curenv); aralloc->destroy(); } diff --git a/src/targ.cff b/src/targ.cff index 59078a0..c74e1d3 100644 --- a/src/targ.cff +++ b/src/targ.cff @@ -6,6 +6,7 @@ static const targs []const Targ = { "amd64-sysv", .ptrsize: 8, .intsize: 4, + .i64align: 8, .longsize: 8, .longalign: 8, .llongsize: 8, .llongalign: 8, .sizesize: 8, diff --git a/src/type.cff b/src/type.cff index a3c7021..33d78e6 100644 --- a/src/type.cff +++ b/src/type.cff @@ -1,32 +1,138 @@ import "cffc.hff"; import "util.hff"; +import "common.hff"; +import "set.hff"; -fn hashtype(ty *const Type) u32 { - let h = FNV1A_INI; - h = fnv1a_i(h, ty.konst ? 1 : 0); +struct TypeTraits { + fn hash(ty *const Type) u32 { + let h = FNV1A_INI; + h = fnv1a_i(h, as(int)ty.u.#tag); + h = fnv1a_i(h, ty.konst ? 1 : 0); - switch ty.u { - case Void; case Bool; + switch ty.u { + case Void; case Bool; - case Flo; - h = fnv1a_i(h, ty.size); - h = fnv1a_i(h, ty.align); + case Flo; + h = fnv1a_i(h, ty.size); - case Int i; - h = fnv1a_i(h, i.sgn ? 1 : 0); - h = fnv1a_i(h, ty.size); - h = fnv1a_i(h, ty.align); + case Int i; + h = fnv1a_i(h, i.sgn ? 1 : 0); + h = fnv1a_i(h, ty.size); - case Ptr child; - h = fnv1a_i(h, child.id); + case Ptr child; + h = fnv1a_i(h, child.id); - case Arr arr; - h = fnv1a_i(h, arr.child.id); - h = fnv1a_i(h, arr.length); + case Arr arr; + h = fnv1a_i(h, arr.child.id); + h = fnv1a_i(h, arr.length); - case Slice child; - h = fnv1a_i(h, child.id); + case Slice child; + h = fnv1a_i(h, child.id); + } + return h; } - return h; + + fn eq(a *const Type, b *const Type) bool { + if a.u.#tag != b.u.#tag or a.size != b.size + or a.align != b.align or a.konst != b.konst { + return #f; + } + 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 { + return #f; + } + if f0.ret != f1.ret { + return #f; + } + if f0.params.#len != f1.params.#len { + return #f; + } + foreach(p, i, f0.params, + if p != f1.params[i] { + return #f; + } + ) + return #t; + } + return #f; + } + + fn dup(ty *const Type) *const Type { + let p *Type = xmalloc(sizeof Type); + static id int = 0; + *p = *ty; + p.id = id++; + return p; + } +} + +extern fn interntype(ty0 Type) *const Type { + static set Set<*const Type, TypeTraits> = {}; + + if ty0.align == 0 { + ty0.align = ty0.size; + } + + return *set->intern(&ty0); +} + +extern static ty_void *const Type = {}, + ty_bool *const Type = {}, + ty_i8 *const Type = {}, + ty_u8 *const Type = {}, + ty_i16 *const Type = {}, + ty_u16 *const Type = {}, + ty_i32 *const Type = {}, + ty_u32 *const Type = {}, + ty_int *const Type = {}, + ty_uint *const Type = {}, + ty_i64 *const Type = {}, + ty_u64 *const Type = {}, + ty_isize *const Type = {}, + ty_usize *const Type = {}, + ty_iptrint *const Type = {}, + ty_uptrint *const Type = {}, + ty_f32 *const Type = {}, + ty_f64 *const Type = {}, + ty_voidptr *const Type = {}; + +extern fn putprimtypes(env *Env) void { + let types []struct { name *const u8, gty **const Type, ty Type } = { + { "void", &ty_void, { .size: 0, .align: 1, .u: :Void }}, + { "bool", &ty_bool, { .size: 1, .align: 1, .u: :Bool }}, + { "f32", &ty_f32, { .size: 4, .u: :Flo }}, + { "f64", &ty_f64, { .size: 8, g_targ.f64align, .u: :Flo }}, + { "i8", &ty_i8, { .size: 1, .u: :Int { .sgn: #t }}}, + { "u8", &ty_u8, { .size: 1, .u: :Int { .sgn: #f }}}, + { "i16", &ty_i16, { .size: 2, .u: :Int { .sgn: #t }}}, + { "u16", &ty_u16, { .size: 2, .u: :Int { .sgn: #f }}}, + { "i32", &ty_i32, { .size: 4, .u: :Int { .sgn: #t }}}, + { "u32", &ty_u32, { .size: 4, .u: :Int { .sgn: #f }}}, + { "int", &ty_int, { g_targ.intsize, .u: :Int { .sgn: #t }}}, + { "uint", &ty_uint, { g_targ.intsize, .u: :Int { .sgn: #f }}}, + { "isize", &ty_isize,{ g_targ.sizesize, .u: :Int { .sgn: #t }}}, + { "usize", &ty_usize,{ g_targ.sizesize, .u: :Int { .sgn: #f }}}, + { "i64", &ty_i64, { .size: 8, g_targ.i64align, .u: :Int { .sgn: #t }}}, + { "u64", &ty_u64, { .size: 8, g_targ.i64align, .u: :Int { .sgn: #f }}}, + { "iptrint",&ty_iptrint, { g_targ.ptrsize, .u: :Int { .sgn: #t }}}, + { "uptrint",&ty_uptrint, { g_targ.ptrsize, .u: :Int { .sgn: #f }}}, + }; + + foreach(type, _, types[0::], + envput(env, { type.name, .u: :Ty (*type.gty = interntype(type.ty)) }, #null); + ) + ty_voidptr = interntype({ .size: g_targ.ptrsize, .u: :Ptr ty_void }); } diff --git a/src/util.cff b/src/util.cff index 1b81ab4..d3e40bb 100644 --- a/src/util.cff +++ b/src/util.cff @@ -67,24 +67,13 @@ extern fn addfilepath(s *const u8) int { return i; } -fn fileid2path(id int) *const u8 { +extern fn fileid2path(id int) *const u8 { assert(id >= 0 and id < filepaths.#len, "fileid"); let s = filepaths[id]; assert(s != #null, "fileid"); return s; } -extern fn fatal(P *Parser, loc Loc, fmt *const u8, ...) void { - let ap va_list #?; - ap->start(fmt); - - efmt("%s:%i:%i: error: ", fileid2path(loc.fileid), loc.line, loc.col); - vefmt(fmt, ap); - efmt("\n"); - ap->end(); - exit(1); -} - extern fn internstr(s *const u8) *const u8 { static set Set<*const u8, struct { fn hash(s *const u8) u32 { return fnv1a_s(FNV1A_INI, s); } diff --git a/src/util.hff b/src/util.hff index 5eb9c88..19c8c41 100644 --- a/src/util.hff +++ b/src/util.hff @@ -8,5 +8,5 @@ extern fn fnv1a(h u32, [#]const u8) u32; extern fn fnv1a_s(h u32, *const u8) u32; extern fn fnv1a_i(h u32, i64) u32; extern fn addfilepath(*const u8) int; -// extern fn fatal(*Parser, Loc, fmt *const u8, ...) void; +extern fn fileid2path(id int) *const u8; extern fn internstr(*const u8) *const u8; |