diff options
| -rw-r--r-- | examples/hello-world.cff | 6 | ||||
| -rw-r--r-- | misc/cff.vim | 2 | ||||
| -rw-r--r-- | src/cffc.hff | 24 | ||||
| -rw-r--r-- | src/fmt.cff | 7 | ||||
| -rw-r--r-- | src/fold.cff | 66 | ||||
| -rw-r--r-- | src/parse.cff | 162 | ||||
| -rw-r--r-- | src/type.cff | 11 | ||||
| -rw-r--r-- | src/vec.hff | 4 |
8 files changed, 268 insertions, 14 deletions
diff --git a/examples/hello-world.cff b/examples/hello-world.cff index 29a1c03..3eb198c 100644 --- a/examples/hello-world.cff +++ b/examples/hello-world.cff @@ -1,10 +1,6 @@ -extern fn printf(fmt *const u8, ...) int; -extern fn cos(x f32) f32; +import "libc.hff"; extern fn main(argc int, argv *const *const u8) int { - let x = argv, - z = 3; - let foo = x + z; printf("hello world\n"); } diff --git a/misc/cff.vim b/misc/cff.vim index 00f586a..0379e90 100644 --- a/misc/cff.vim +++ b/misc/cff.vim @@ -14,7 +14,7 @@ syn keyword Macro defmacro syn keyword Type i8 u8 i16 u16 i32 u32 i64 u64 syn keyword Type int uint isize usize iptrint uptrint syn keyword Type c_char c_long c_ulong c_llong c_ullong -syn keyword Type bool void f32 f64 typeof +syn keyword Type bool intbool void f32 f64 typeof syn keyword Structure struct enum union syn keyword Operator sizeof as and or diff --git a/src/cffc.hff b/src/cffc.hff index 2252373..aad2ee4 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -68,6 +68,7 @@ struct AggField { ty *const Type, off usize, } +struct EnumVal { name *const u8, i i64 } struct Type { size usize, @@ -87,13 +88,20 @@ struct Type { variadic bool, ret *const Type, }, + Enum struct { + intty *const Type, + name *const u8, + lax bool, + id int, + vals [#]EnumVal, + }, Agg struct { kind AggKind, name *const u8, id int, fwd bool, flds [#]AggField, - decls [#]*Decl, + decls *Env, }, }, @@ -190,6 +198,16 @@ struct Var { fnid int, } +struct MacroCase { + variadic bool, + params [#]*const u8, + body [#]Tok, +} + +struct Macro { + cs [#]MacroCase +} + struct Decl { name *const u8, loc Loc, @@ -199,6 +217,7 @@ struct Decl { Static Var, Def Expr, Fn Fn, + Macro Macro, Ty *const Type, }, } @@ -317,3 +336,6 @@ 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; + +// fold.cff +extern fn fold(*Expr) bool; diff --git a/src/fmt.cff b/src/fmt.cff index 00b9b54..755bbda 100644 --- a/src/fmt.cff +++ b/src/fmt.cff @@ -138,7 +138,7 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) } switch ty.u { case Void; ps("void"); - case Bool; ps("bool"); + case Bool; ps(ty.size == 1 ? "bool" : "intbool"); case Int i; p(i.sgn ? 'i' : 'u'); sprintf(buf, "%zu", ty.size * 8); @@ -165,6 +165,11 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) ps("..."); } pfmt(proc, parg, ") %t", f.ret); + case Agg agg; + if agg.name { + ps(agg.name); + } else { + } } } diff --git a/src/fold.cff b/src/fold.cff new file mode 100644 index 0000000..7b393e5 --- /dev/null +++ b/src/fold.cff @@ -0,0 +1,66 @@ +import "cffc.hff"; +import "common.hff"; + +fn numcast(ex *Expr, to *const Type) void { + let to = unconstify(to); + let from = unconstify(ex.ty); + let iu = &ex.u.IntLit; + let f = &ex.u.FloLit; + let b = &ex.u.BoolLit; + switch { + case to == from; + // pass + case to->is(:Int) and from->is(:Flo); + iu.i = from.size == 4 ? as(f32)*f : *f; + case to->is(:Flo) and to.size == 4 and from->is(:Flo); + *f = as(f32)*f; + case to->is(:Flo) and to.size == 8 and from->is(:Flo); + *f = *f; + case from->is(:Bool); + iu.i = *b ? 1 : 0; + case from->is(:Int) and to == ty_u8; + iu.i = as(i8)iu.i; + case from->is(:Int) and to == ty_u8; + iu.i = as(u8)iu.i; + case from->is(:Int) and to == ty_i16; + iu.i = as(i16)iu.i; + case from->is(:Int) and to == ty_u16; + iu.i = as(u8)iu.i; + case from->is(:Int) and to == ty_i32; + iu.i = as(i32)iu.i; + case from->is(:Int) and to == ty_i64; + iu.i = as(i64)iu.i; + case from->is(:Int) and to == ty_u64; + iu.u = iu.u; + case to == ty_f64 and from == ty_u64; + *f = iu.u; + case to == ty_f32 and from == ty_u64; + *f = as(f32)iu.u; + case to == ty_f64; + *f = iu.i; + case to == ty_f32; + *f = as(f32)iu.i; + case to->is(:Bool) and from->is(:Int); + *b = iu.u == 0; + case else; + assert(#f, "bad numcast"); + } + + ex.ty = to; + ex.u.#tag = to->is(:Flo) ? :FloLit + : to->is(:Int) ? :IntLit + : :BoolLit; +} + +extern fn fold(ex *Expr) bool { + switch ex.u.#tag { + case :IntLit, :FloLit, :BoolLit; + numcast(ex, ex.ty); + return #t; + case :StrLit, :NullLit; + return #t; + case else; + return #f; + } + +} diff --git a/src/parse.cff b/src/parse.cff index c2c1817..f19b586 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -566,8 +566,37 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl { // Types Parsing // /////////////////// +fn parseexpr(P *Parser) Expr; fn parsetype(P *Parser) *const Type; +fn parseenum(P *Parser, name *const u8, lax bool) *const Type { + lexexpect(P, '{'); + let iota = 0i64; + let max = iota; + let vals Vec<EnumVal> = {}; + while !lexmatch(P, #null, '}') { + let name = lexexpects(P, :ident, "variant name").u.ident; + if lexmatch(P, #null, '=') { + let ex = parseexpr(P); + if !fold(&ex) or !ex.ty->is(:Int) { + err(P, ex.loc, "expected constant integer expression"); + } + iota = ex.u.IntLit.i; + } + vals->push({ + name, + iota++, + }); + if !lexmatch(P, #null, ',') { + lexexpect(P, '}'); + break; + } + } + let intty *const Type = #null; + static id int = 0; + return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }}); +} + fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type { let loc = P.tokloc; let tok Tok #?; @@ -598,7 +627,7 @@ fn parseagg(P *Parser, kind AggKind, name *const u8, retdecl **Decl) *const Type let flds Vec<AggField> = {}; while !lexmatch(P, #null, '}') { let off = size; - let name = lexexpect(P, :ident).u.ident; + let name = lexexpects(P, :ident, "field name").u.ident; let type = parsetype(P); if type { off = ALIGNUP(off, type.align); @@ -730,8 +759,6 @@ fn islvalue(ex Expr) bool { return #f; } -fn parseexpr(P *Parser) Expr; - fn pexprimary(P *Parser) Expr { let tok Tok = lex(P); switch tok.t { @@ -764,14 +791,23 @@ fn pexprimary(P *Parser) Expr { return { 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; } case :kw_sizeof; + let ty *const Type #?; if lexmatch(P, &tok, '(') { let ex = parseexpr(P); lexexpect(P, ')'); - return { ex.loc, ty_usize, :IntLit { ex.ty.size }}; + ty = ex.ty; + } else { + ty = parsetype(P); } - return { tok.loc, ty_usize, :IntLit { parsetype(P).size }}; + if !completetype(ty) { + err(P, tok.loc, "sizeof incomplete type (%t)", ty); + } + return { tok.loc, ty_usize, :IntLit { ty.size }}; case '('; let ex = parseexpr(P); @@ -1448,6 +1484,106 @@ fn doimport(P *Parser, path *const u8) [#]Decl { return decls; } +fn parsemacro(P *Parser, name *const u8) *Decl { + fn parsemacrocase(P *Parser) MacroCase { + let tok Tok #?; + let c MacroCase = {}; + let params Vec<*const u8> = {}; + let body Vec<Tok> = {}; + static gensymid int = 0; + struct Gensyms { + next *Gensyms, + name *const u8, + tok Tok, + }; + let gensyms *Gensyms = #null; + lexexpect(P, '('); + while !lexmatch(P, &tok, ')') { + if lexmatch(P, &tok, '...') { + params->push(lexexpects(P, :ident, "parameter name").u.ident); + c.variadic = #t; + lexmatch(P, &tok, ','); + lexexpect(P, ')'); + break; + } else { + params->push(lexexpects(P, :ident, "parameter name").u.ident); + if !lexmatch(P, &tok, ',') { + lexexpect(P, ')'); + break; + } + } + } + let eloc = tok.loc; + lexexpect(P, '['); + + let bal = 1; + while bal != 0 { + tok = lex(P); + switch tok.t { + case '['; ++bal; + case ']'; --bal; + case :eof; + fatal(P, eloc, "unterminated macro definition"); + } + if tok.t == :ident { + vec_each(par, _, params, + if streq(par, tok.u.ident) { + tok.t = :macident; + } + ) + } else if tok.t == :gensym { + let gs *Gensyms #?; + let found = #f; + for gs = gensyms; gs; gs = gs.next { + if streq(gs.name, tok.u.ident) { + tok = gs.tok; + found = #t; + break; + } + } + if !found { + gs = xcalloc(1, sizeof(*gs)); + gs.name = tok.u.ident; + gs.tok.t = :ident; + gs.tok.loc = tok.loc; + let s [300]u8 = {}; + snprintf(s, sizeof(s) - 1, "#<gensym %s %d>", tok.u.ident, gensymid++); + gs.tok.u.ident = internstr(s); + tok = gs.tok; + gs.next = gensyms; + gensyms = gs; + } + } + body->push(tok); + } + body->pop(); + + for let gs = gensyms, next *Gensyms #?; gs; gs = next { + next = gs.next; + free(gs); + } + + c.params = params->move(P.alloc); + c.body = body->move(P.alloc); + return c; + } + + let tok Tok #?; + let cs Vec<MacroCase> = {}; + if lexpeek(P).t == '(' { + cs->push(parsemacrocase(P)); + } else { + lexexpect(P, '{'); + while !lexmatch(P, &tok, '}') { + cs->push(parsemacrocase(P)); + if !lexmatch(P, &tok, ',') { + lexexpect(P, '}'); + break; + } + } + } +} + fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { let tok = Tok { .loc: P.tokloc }, decl *Decl = {}, @@ -1478,6 +1614,17 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { lexexpect(P, ';'); return; + case lexmatch(P, &tok, :kw_enum); + if lexmatch(P, &tok, :kw_union) { + let name = lexexpect(P, :ident).u.ident; + parseagg(P, :EUnion, name, &decl); + } else { + let name = lexexpect(P, :ident).u.ident; + let loc = P.tokloc; + let ty = parseenum(P, name, #{lax} #f); + decl = putdecl(P, loc, { name, loc, .u: :Ty(ty) }); + } + case lexmatch(P, &tok, :kw_struct); let name = lexexpect(P, :ident).u.ident; parseagg(P, :Struct, name, &decl); @@ -1531,6 +1678,7 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { if !typematchestarg(ty, ini.ty) { err(P, ini.loc, "incompatible initializer (%t, expected %t)", ini.ty, ty); } + fold(&ini); yield(putdecl(P, tok.loc, { name, tok.loc, .u: :Def(ini) }), yarg); @@ -1540,6 +1688,10 @@ fn parsedecls(P *Parser, yield DeclYielder, yarg *void, toplevel bool) void { } } while !lexmatch(P, &tok, ';'); return; + + case lexmatch(P, &tok, :kw_defmacro); + let name = lexexpects(P, :ident, "macro name").u.ident; + decl = parsemacro(P, name); case else; fatal(P, tok.loc, "expected declaration (near %qT)", tok); diff --git a/src/type.cff b/src/type.cff index e3989c7..980a83a 100644 --- a/src/type.cff +++ b/src/type.cff @@ -10,7 +10,10 @@ struct TypeTraits { h = fnv1a_i(h, ty.konst ? 1 : 0); switch ty.u { - case Void; case Bool; + case Void; + + case Bool; + h = fnv1a_i(h, ty.size); case Flo; h = fnv1a_i(h, ty.size); @@ -121,12 +124,14 @@ extern fn completetype(ty *const Type) bool { case Void; return #f; case Fn; return #f; case Arr a; return a.length >= 0; + case Agg agg; return !agg.fwd; } return #t; } extern static ty_void *const Type = {}, ty_bool *const Type = {}, + ty_intbool *const Type = {}, ty_i8 *const Type = {}, ty_u8 *const Type = {}, ty_i16 *const Type = {}, @@ -159,6 +164,7 @@ extern fn putprimtypes(env *Env) void { { "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 }}}, + { "intbool",&ty_intbool,{ .size: g_targ.intsize, .u: :Bool }}, { "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 }}}, @@ -242,6 +248,9 @@ extern fn typeof2(a *const Type, b *const Type) *const Type { if a == unconstify(b) { return b; } + if a->is(:Bool) and b->is(:Bool) { + return a.size > b.size ? a : b; + } if a->is(:Arr) and b->is(:Arr) { a = arraydecay(a); } diff --git a/src/vec.hff b/src/vec.hff index 9933038..003b13a 100644 --- a/src/vec.hff +++ b/src/vec.hff @@ -19,6 +19,10 @@ struct Vec<T> { vec.dat[vec.len++] = x; } + fn pop(vec *Vec) T { + return vec.dat[--vec.len]; + } + fn clear(vec *Vec) void { free(vec.dat); *vec = {}; |