import "libc.hff"; import "mem.hff"; import "option.hff"; /// Types struct Type; struct Decl; struct Expr; struct Env; struct Loc { fileid i16, col i16, line int, idx isize, } #[lax] enum TokT : i32 { // !sorted kw_alignof, kw_and, kw_as, kw_bitfield, kw_break, kw_case, kw_const, kw_continue, kw_def, kw_defer, kw_defmacro, kw_do, kw_else, kw_enum, kw_extern, kw_fn, kw_for, kw_if, kw_import, kw_let, kw_offsetof, kw_or, kw_return, kw_sizeof, kw_static, kw_struct, kw_switch, kw_typedef, kw_typeof, kw_union, kw_while, NUM_KEYWORDS, int = -100, flo, bool, str, chr, null, ident, macident, gensym, label, strify, typearg, eof, } def NUM_KEYWORDS = as(int)TokT:NUM_KEYWORDS; struct Tok { t TokT, loc Loc, ty *const Type, u union { int i64, uint u64, flo f64, bool bool, str [#]const u8, ident *const u8, }, } enum AggKind { Struct, Union, EUnion, } struct AggField { name *const u8, ty *const Type, off usize, } struct EnumVal { name *const u8, i i64 } struct BitFField { name *const u8, ty *const Type, off u16, size u16 } enum union TeplArg; struct Type { size usize, align usize, konst bool, id uint, u enum union { Void, Bool, Int struct { sgn bool }, Flo, Ptr *const Type, Arr struct { child *const Type, length i64 }, Slice *const Type, Fn struct { params [#]*const 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, enumty *const Type, tpargs [#]TeplArg, flds [#]AggField, decls *Env, }, BitF struct { intty *const Type, name *const u8, id int, flds [#]BitFField, }, VaList, }, fn is(ty *const Type, tag typeof((Type{}).u.#tag)) bool { return ty.u.#tag == tag; } } struct Fn; struct Expan; struct Block; struct Parser { fp *FILE, alloc *Allocator, tlalloc *Allocator, curfile *const u8, curfn *Fn, curenv *Env, curloop int, curblock *Block, curexpan *Expan, expanno int, loopid int, varid int, targty *const Type, tokloc Loc, curloc Loc, eof bool, error bool, is_header bool, peekchr Option, peektok Option, } enum UnOp { neg, not, compl, deref, addrof, postinc, preinc, postdec, predec, } struct Stmt; struct Defers; struct Block { sts [#]Stmt, defers *Defers, id int, } struct Expr { loc Loc, ty *const Type, u enum union { IntLit union { i i64, u u64 }, FloLit f64, StrLit [#]const u8, BoolLit bool, NullLit, Symbol *Decl, BinOp struct { op TokT, lhs *Expr, rhs *Expr }, UnOp struct { op UnOp, ex *Expr }, Cond struct { test *Expr, t *Expr, f *Expr }, Cast *Expr, Dot struct { lhs *Expr, fld *const AggField }, BitDot struct { lhs *Expr, fld *const BitFField }, SLen *Expr, SPtr *Expr, EUTag *Expr, BitRaw *Expr, Index struct { lhs *Expr, rhs *Expr }, Slice struct { lhs *Expr, begin *Expr, end *Expr }, Call struct { lhs *Expr, args [#]Expr }, ZeroIni, EnumIni i64, EUnionIni struct { var *const AggField, ex *Expr }, AggIni struct { flds [#]*const AggField, exs [#]Expr }, ArrIni struct { idxs [#]u32, exs [#]Expr, maxn i64 }, VaStart *Expr, VaArg *Expr, VaCopy struct { dst *Expr, src *Expr }, VaEnd *Expr, Stmt Block, } } struct Defers { next *Defers, blockid int, age int, ex Expr } struct ISwitchCase { es [#]Expr, t Block } struct EUSwitchCase { capt *const u8, captptr bool, captid int, variant int, captty *const Type, fld *AggField, t Block } struct CSwitchCase { test Expr, t Block, } struct Stmt { loc Loc, u enum union { Block Block, If struct { test Expr, t Block, f Block }, While struct { test Expr, body Block, id int }, DoWhile struct { test Expr, body Block, id int }, For struct { ini Block, test Expr, next Option, body Block, id int, }, Break #{loopid} int, Continue #{loopid} int, Return struct { ex Option, deferage int }, Expr Expr, Decl *Decl, ISwitch struct { ex Expr, cs [#]ISwitchCase, f Block }, EUSwitch struct { lvalue bool, ex Expr, cs [#]EUSwitchCase, f Block }, CSwitch struct { cs [#]CSwitchCase, f Block } } } struct Fn { ty *const Type, paramnames [#]*const u8, variadic bool, id int, body Option } struct Var { ty *const Type, ini Option, fwd bool, fnid int, id int, } struct MacroCase { variadic bool, bodyarg bool, params [#]*const u8, body [#]Tok, } struct Macro { cs [#]MacroCase } struct TeplParam { name *const u8, u enum union { Ty, Val *const Type, } } enum union TeplArg { Ty *const Type, Val Tok, } struct TeplCache { next *TeplCache, args [#]TeplArg, ty *const Type, } struct Tepl { kind AggKind, env *Env, params [#]TeplParam, toks [#]Tok, cache *TeplCache, } struct Decl { name *const u8, loc Loc, externp bool, toplevel bool, u enum union { Let Var, Static Var, Ty *const Type, Def Expr, Fn Fn, Macro Macro, Tepl Tepl, Label #{loopid} int, }, myenv *Env, } fn islvalue(ex *Expr) bool { switch ex.u { case Symbol decl; return decl.u.#tag == :Let or decl.u.#tag == :Static; case UnOp u; return u.op == :deref; case Index idx; return idx.lhs.ty->is(:Ptr) or islvalue(idx.lhs); case Dot dot; return dot.lhs.ty->is(:Ptr) or islvalue(dot.lhs); case BitDot bdot; return bdot.lhs.ty->is(:Ptr) or islvalue(bdot.lhs); case BitRaw ex; return ex.ty->is(:Ptr) or islvalue(ex); case EUTag; return #t; } return #f; } def ATTR_LAX = 1u32; struct ExpanArg { name *const u8, toks [#]Tok, } struct Expan { prev *Expan, args [#]ExpanArg, toks [#]Tok, name *const u8, loc Loc, tepl bool, peektok Option, idx int, } struct DeclList { link *DeclList, decl Decl, } struct Targ { name *const u8, ptrsize u8, intsize u8, i64align u8, longsize u8, longalign u8, llongsize u8, llongalign u8, sizesize u8, f64align u8, valistsize u8, valistalign u8, valistllvmty *const u8, charsigned bool, shortenum bool, triple *const u8, } // parse.cff extern static keyword2str [NUM_KEYWORDS]*const u8; extern fn parser_init(*Parser, path *const u8) void; extern fn parse(*Parser) [#]Decl; // fmt.cff extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, va_list) void; 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; extern fn ssfmt(fmt *const u8, ...) *const u8; extern fn warn(P *Parser, Loc, fmt *const u8, ...) void; extern fn err(P *Parser, Loc, fmt *const u8, ...) void; extern fn fatal(*Parser, Loc, fmt *const u8, ...) void; // targ.cff extern static g_targ Targ; extern static host_target_triple const *const u8; extern fn targ_ini(name *const u8) bool; extern fn triple2targ(triple *const u8) *const u8; // 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, ty_c_char *const Type, ty_c_long *const Type, ty_c_ulong *const Type, ty_c_llong *const Type, ty_c_ullong *const Type, ty_c_valist *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 unconstify(ty *const Type) *const Type { if !ty.konst { return ty; } let ty2 = *ty; ty2.konst = #f; 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) }); } extern fn mkslicetype(child *const Type) *const Type; fn childtype(ty *const Type) *const Type { switch ty.u { case Ptr t; return t; case Arr a; return a.child; case Slice t; return t; } return #null; } extern fn completetype(ty *const Type) bool; fn isnumtype(ty *const Type) bool { return ty->is(:Int) or ty->is(:Flo) or (ty->is(:Enum) and ty.u.Enum.lax); } extern fn typeof2(a *const Type, b *const Type) *const Type; extern fn visittypes(*fn(*const Type, *void) void, *void) void; // env.cff extern fn mkenv(parent *Env, alloc *Allocator) *Env; extern fn envparent(*Env) *Env; extern fn envput(*Env, Decl, **const Decl) *Decl; extern fn envput_alloc(*Env, *Allocator, 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; // llvm.cff extern fn llvm_addtype(*const Type) void; extern fn llvm_addglobl(*Decl, staticp bool) void; extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void; extern fn llvm_genstatic(externp bool, name *const u8, var *Var) void; extern fn llvm_init(*FILE) void; extern fn llvm_fini() void;