aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-29 21:57:58 +0200
committerlemon <lsof@mailbox.org>2022-08-29 21:57:58 +0200
commit2f243de6ce9402f880677a07b832c0e56a7f688d (patch)
tree7f2844b121f52b0acbb5e03d2bdc83c51c187abc /src
parente0385225b5a4a0d7b391d3d71c19228efe06ed04 (diff)
many things ,varags
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff31
-rw-r--r--src/fmt.cff2
-rw-r--r--src/fold.cff20
-rw-r--r--src/llvm.cff164
-rw-r--r--src/parse.cff222
5 files changed, 291 insertions, 148 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index e329965..11adba6 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -41,7 +41,7 @@ enum TokT : i32 {
typearg,
eof,
}
-def NUM_KEYWORDS int = TokT:NUM_KEYWORDS;
+def NUM_KEYWORDS = as(int)TokT:NUM_KEYWORDS;
struct Tok {
t TokT,
@@ -89,9 +89,9 @@ struct Type {
Bool,
Int struct { sgn bool },
Flo,
- Ptr *Type,
+ Ptr *const Type,
Arr struct { child *const Type, length i64 },
- Slice *Type,
+ Slice *const Type,
Fn struct {
params [#]*const Type,
variadic bool,
@@ -204,11 +204,14 @@ struct Expr {
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,
@@ -333,6 +336,26 @@ struct Decl {
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 {
diff --git a/src/fmt.cff b/src/fmt.cff
index 39b9e5b..27bfe0e 100644
--- a/src/fmt.cff
+++ b/src/fmt.cff
@@ -204,6 +204,8 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
} else {
ps("(anonymous)");
}
+ case VaList;
+ ps("va_list")
}
}
diff --git a/src/fold.cff b/src/fold.cff
index 2e7cae3..8814d32 100644
--- a/src/fold.cff
+++ b/src/fold.cff
@@ -7,6 +7,12 @@ fn numcast(ex *Expr, to *const Type) void {
let iu = &ex.u.IntLit;
let f = &ex.u.FloLit;
let b = &ex.u.BoolLit;
+ if to->is(:Enum) {
+ to = unconstify(to.u.Enum.intty);
+ }
+ if from->is(:Enum) {
+ from = unconstify(from.u.Enum.intty);
+ }
switch {
case to == from;
// pass
@@ -43,6 +49,7 @@ fn numcast(ex *Expr, to *const Type) void {
case to->is(:Bool) and from->is(:Int);
*b = iu.u == 0;
case else;
+ efmt("%t <- %t\n",to,from);
assert(#f, "bad numcast");
}
@@ -192,7 +199,15 @@ fn findex(ex *Expr) void {
} else {
assert(#f,"bad");
}
-
+}
+fn fas(ex *Expr) void {
+ let src = ex.u.Cast;
+ if !fold(src) or !(ex.ty->is(:Int) or ex.ty->is(:Flo) or ex.ty->is(:Enum) or ex.ty->is(:Bool)) {
+ return;
+ }
+ let ty = ex.ty;
+ *ex = *src;
+ numcast(ex, ty);
}
extern fn fold(ex *Expr) bool {
@@ -213,6 +228,9 @@ extern fn fold(ex *Expr) bool {
case :Cond;
fcond(ex);
+ case :Cast;
+ fas(ex);
+
case :Index;
findex(ex);
diff --git a/src/llvm.cff b/src/llvm.cff
index eb13919..1a7f24a 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -23,7 +23,7 @@ struct Value {
}
}
-static ty_i1 *Type = as(*void)&outfp; // dummy
+static ty_i1 Type = {}; // dummy
fn gen(fmt *const u8, ...) void;
extern fn genagg(ty *const Type) void {
@@ -87,7 +87,7 @@ fn gen(fmt *const u8, ...) void {
ap->start(fmt);
fn pritype(ty *const Type) void {
- if ty == ty_i1 {
+ if ty == &ty_i1 {
gen("i1");
return;
}
@@ -121,7 +121,8 @@ fn gen(fmt *const u8, ...) void {
}
}
gen(") ");
- case VaList; gen("%s", g_targ.valistllvmty);
+ case VaList; gen("%%.type.valist");
+ case else assert(#f, "type?");
}
}
@@ -142,7 +143,7 @@ fn gen(fmt *const u8, ...) void {
fputc('"', outfp);
foreach(c, _, str) {
extern fn isprint(int) int;
- if isprint(c) == 0 {
+ if isprint(c) == 0 or c == '"' or c == '\\' {
fprintf(outfp, "\\%.2X", c);
} else {
fputc(c, outfp);
@@ -344,6 +345,12 @@ fn genref(f *Fn, ex *Expr) Ref {
gen("\tstore %t %v, %t %v\n", fex.ty, convert(f, ty.u.Arr.child, fex), ptr.ty, ptr);
}
return :Addr(tmp);
+
+ case else
+ let it = genexpr(f, ex);
+ let tmp = gentmp(mkptrtype(ex.ty), "alloca %t", ex.ty);
+ gen("store %t %v, %t %v", it.ty, it, tmp.ty, tmp);
+ return :Addr(tmp);
}
assert(#f, "genref %d", ex.u.#tag);
}
@@ -362,7 +369,7 @@ fn genload(f *Fn, ref Ref) Value {
let res = mktmp(fld.ty);
switch {
case dot.fld.ty->is(:Bool);
- let tmp = gentmp(ty_i1, "icmp ne i%d %v, 0", fld.size, truncd);
+ let tmp = gentmp(&ty_i1, "icmp ne i%d %v, 0", fld.size, truncd);
gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty);
case dot.fld.ty->is(:Int);
gen("\t%v = %s i%d %v to %t\n", res,
@@ -402,21 +409,18 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
if from->is(:Enum) { from = from.u.Enum.intty; }
defmacro cvt(inst) [
- (do let t = mktmp(to),
+ (do let $t = mktmp(to),
val = genexpr(f, ex);
- gen("\t%v = %s %t %v to %t\n", t, inst, from, val, to);
- t;
+ gen("\t%v = %s %t %v to %t\n", $t, inst, from, val, to);
+ $t;
)
]
switch {
case from == to;
return genexpr(f, ex);
- case to->is(:Int) and from->is(:Int) and to.size == from.size and to.u.Int.sgn != from.u.Int.sgn;
- return genexpr(f, ex);
-
case to->is(:Int) and from->is(:Int) and to.size == from.size;
- return cvt("bitcast");
+ return genexpr(f, ex);
case to->is(:Int) and from->is(:Int) and to.size < from.size;
return cvt("trunc");
@@ -454,25 +458,24 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
return cvt(to.u.Int.sgn ? "fptosi" : "fptoui");
case to->is(:Int) and from->is(:Bool);
- let t0 = mktmp(ty_i1);
+ let t0 = mktmp(&ty_i1);
gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
let t1 = mktmp(to);
gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
return t1;
case to->is(:Bool) and from->is(:Int);
- let t0 = mktmp(ty_i1);
+ let t0 = mktmp(&ty_i1);
gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
let t1 = mktmp(to);
gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
return t1;
-
case to->is(:Ptr) and from->is(:Ptr);
- let t = mktmp(to),
- val = genexpr(f, ex);
- gen("\t%v = bitcast %t %v to %t\n", t, from, val, to);
- return t;
+ return genexpr(f, ex);
+
+ case to->is(:Slice) and from->is(:Slice);
+ return genexpr(f, ex);
case to->is(:Ptr) and from->is(:Arr);
let addr = genref(f, ex).Addr;
@@ -483,11 +486,9 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
case to->is(:Arr) and from->is(:Arr);
return genexpr(f, ex);
-
- case else
- efmt("%t %t\n",from,to);
- assert(#f, "convert");
}
+ efmt("%t %t\n",from,to);
+ assert(#f, "convert");
}
fn genblock(f *Fn, block Block) Option<Value>;
@@ -537,8 +538,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
$t, lhs.ty.u.Ptr, lhs.ty, lhs, rhs.ty, rhs);
res = $t;
} else if rhs.ty->is(:Ptr) {
+ let $t = mktmp(type);
+ gen("\t%v = getelementptr %t, %t %v, %t %v\n",
+ $t, rhs.ty.u.Ptr, rhs.ty, rhs, rhs.ty, lhs);
+ res = $t;
} else {
- assert(#f, "bad sub");
+ assert(#f, "bad ad");
}
res;
)
@@ -546,7 +551,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
defmacro gensub(type, lhs, rhs) [
(do
let res Value #?;
- if isnumtype(type) {
+ if isnumtype(type) and !lhs.ty->is(:Ptr) {
let $t = mktmp(type);
gen("\t%v = %s %t %v, %v\n", $t, ex.ty->is(:Flo) ? "fsub" : "sub", ex.ty, lhs, rhs);
res = $t;
@@ -555,10 +560,16 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("\t%v = sub %t 0, %v\n", $off, rhs.ty, rhs);
let $t = mktmp(type);
gen("\t%v = getelementptr %t, %t %v, %t %v\n",
- $t, lhs.ty.u.Ptr, lhs.ty, lhs, $off.ty, $off);
+ $t, lhs.ty.u.Ptr == ty_void ? ty_i8 : lhs.ty.u.Ptr, lhs.ty, lhs, $off.ty, $off);
res = $t;
+ } else if lhs.ty->is(:Ptr) and rhs.ty->is(:Ptr) {
+ let $l = gentmp(ty_isize, "ptrtoint ptr %v to %t", lhs, ty_isize);
+ let $r = gentmp(ty_isize, "ptrtoint ptr %v to %t", rhs, ty_isize);
+ let $diff = gentmp(ty_isize, "sub %t %v, %v", ty_isize, $l, $r);
+ let $res = gentmp(ty_isize, "sdiv %t %v, %v", ty_isize, $l, $r);
+ return $res;
} else {
- assert(#f, "bad add");
+ assert(#f, "bad sub");
}
res;
)
@@ -637,7 +648,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static orid int = {};
let id = orid++;
let lhs = genexpr(f, b.lhs);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -656,7 +667,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static andid int = {};
let id = andid++;
let lhs = genexpr(f, b.lhs);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -670,6 +681,25 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("AndF%d: ", id);
gen("\t%v = load %t, %t %v\n", res, ex.ty, tmpvar.ty, tmpvar);
return res;
+
+ case '??';
+ static orid int = {};
+ let id = orid++;
+ let lhs = genexpr(f, b.lhs);
+ let cnd = mktmp(&ty_i1);
+ let tmpvar = mktmp(mkptrtype(ex.ty));
+ let res = mktmp(ex.ty);
+ gen("\t%v = alloca %t\n", tmpvar, ex.ty);
+ gen("\tstore %t %v, %t %v\n", ex.ty, lhs, tmpvar.ty, tmpvar);
+ gen("\t%v = icmp ne %t %v, null\n", cnd, lhs.ty, lhs);
+ gen("\tbr i1 %v, label %%OrT%d, label %%OrF%d\n", cnd, id, id);
+ gen("OrF%d: ", id);
+ let rhs = genexpr(f, b.rhs);
+ gen("\tstore %t %v, %t %v\n", ex.ty, rhs, tmpvar.ty, tmpvar);
+ gen("\tbr label %%OrT%d\n", cnd, id, id);
+ gen("OrT%d: ", id);
+ gen("\t%v = load %t, %t %v\n", res, ex.ty, tmpvar.ty, tmpvar);
+ return res;
case else
assert(#f, "binop? %c", b.op);
@@ -678,7 +708,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static condid int = {};
let id = condid++;
let lhs = genexpr(f, cond.test);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -713,7 +743,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
return tmp;
case :not;
- let tmp = mktmp(ty_i1);
+ let tmp = mktmp(&ty_i1);
gen("\t%v = xor i1 1, %v\n", tmp, ex.ty, llvmbool(f, un.ex));
let res = mktmp(ex.ty);
gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty);
@@ -863,13 +893,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
let ty = i < fnty.params.#len ? fnty.params[i] : varargpromote(arg.ty);
args[i] = convert(f, ty, arg);
}
- let t Value #?;
+ let t Value = mktmp(ex.ty);
if fnty.ret->is(:Void) {
- t = {ty_void};
- gen("\tcall %t %v(", call.lhs.ty, lhs);
+ gen("\tcall void %v(", lhs);
} else {
t = mktmp(ex.ty);
- gen("\t%v = call %t %v(", t, call.lhs.ty, lhs);
+ gen("\t%v = call %t %v(", t, call.lhs.ty->is(:Ptr) ? call.lhs.ty.u.Ptr : call.lhs.ty, lhs);
}
foreach_ptr(arg, i, call.args) {
let ty = i < fnty.params.#len ? fnty.params[i] : varargpromote(arg.ty);
@@ -910,6 +939,17 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("\t%v = load %t, %t %v\n", res, res.ty, t0.ty, t0);
return res;
+ case VaStart ap;
+ gen("\tcall void @llvm.va_start(ptr %v)\n", genref(f, ap).Addr);
+ return mktmp(ty_void);
+
+ case VaArg ap;
+ return gentmp(ex.ty, "va_arg ptr %v, %t", genref(f, ap).Addr, ex.ty);
+
+ case VaEnd ap;
+ gen("\tcall void @llvm.va_end(ptr %v)\n", genref(f, ap).Addr);
+ return mktmp(ty_void);
+
case Stmt block;
switch genblock(f, block) {
case Some val; return val;
@@ -923,7 +963,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
fn llvmbool(f *Fn, ex *Expr) Value {
let v = genexpr(f, ex);
- let t = mktmp(ty_i1);
+ let t = mktmp(&ty_i1);
if v.ty->is(:Bool) or v.ty->is(:Int) {
gen("\t%v = icmp ne %t %v, 0\n", t, v.ty, v);
} else {
@@ -951,9 +991,10 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void {
let nam = decl.name,
ty = var.ty;
gen("\t%%%s.%d = alloca %t\n", nam, var.id, ty);
- if !var.ini->empty() {
+ switch var.ini {
+ case Some *ex;
gen("\tstore %t %v, %t %%%s.%d\n",
- ty, convert(f, ty, &var.ini.Some), mkptrtype(ty), nam, var.id);
+ ty, convert(f, ty, ex), mkptrtype(ty), nam, var.id);
}
}
case If *cnd;
@@ -1234,9 +1275,9 @@ extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void {
gen("}\n");
}
-struct I64Traits {
- fn hash(x i64) u32 { return x ^ 7; }
- fn eq(a i64, b i64) bool { return a == b; }
+struct IntTraits<T> {
+ fn hash(x T) u32 { return x ^ 7; }
+ fn eq(a T, b T) bool { return a == b; }
}
fn gendata(ty *const Type, ex *Expr) void {
@@ -1249,6 +1290,10 @@ fn gendata(ty *const Type, ex *Expr) void {
if !decl.externp { gen("@%s.%d", decl.name, f.id);
} else { gen("@%s", decl.name); }
return;
+ case Static v;
+ if !decl.externp { gen("@%s.%d", decl.name, v.id);
+ } else { gen("@%s", decl.name); }
+ return;
}
}
assert(#f, "bad static addr");
@@ -1276,7 +1321,7 @@ fn gendata(ty *const Type, ex *Expr) void {
case ArrIni ini;
assert(ty->is(:Arr), "not arr arr ini");
- let map Map<i64, *Expr, I64Traits> = {};
+ let map Map<i64, *Expr, IntTraits<i64>,> = {};
defer map->clear();
foreach (idx, i, ini.idxs) {
map->put(idx, &ini.exs[i]);
@@ -1295,7 +1340,36 @@ fn gendata(ty *const Type, ex *Expr) void {
}
}
gen(" ]");
- return;
+ return;
+
+ case AggIni ini;
+ assert(ty->is(:Agg), "not agg agg ini");
+
+ let map Map<u16, *Expr, IntTraits<u16>,> = {};
+ defer map->clear();
+ if ty.u.Agg.kind == :Struct {
+ foreach (fld, i, ini.flds) {
+ let idx = fld - ty.u.Agg.flds.#ptr;
+ map->put(idx, &ini.exs[i]);
+ }
+ gen("{ ");
+ for let i = 0z; i < ty.u.Agg.flds.#len; ++i {
+ gen("%t ", ty.u.Agg.flds[i].ty);
+ let ex **Expr = map->get(i);
+ if ex {
+ gendata(ty.u.Agg.flds[i].ty, *ex);
+ } else {
+ gen("zeroinitializer");
+ }
+ if i < ty.u.Agg.flds.#len - 1 {
+ gen(", ");
+ }
+ }
+ gen(" }");
+ } else {
+ assert(#f, "NYI static");
+ }
+ return;
}
assert(#f, "bad static %d", ex.u.#tag);
}
@@ -1312,6 +1386,9 @@ extern fn llvm_genstatic(externp bool, name *const u8, var *Var) void {
}
extern fn llvm_fini() void {
+ gen("declare void @llvm.va_start(ptr)\n");
+ gen("declare void @llvm.va_copy(ptr, ptr)\n");
+ gen("declare void @llvm.va_end(ptr)\n");
vec_each(s, i, strs) {
gen("@.str.%z = private unnamed_addr constant [%z x i8] c%S;\n", i, s.#len + 1, s);
}
@@ -1356,5 +1433,6 @@ extern fn llvm_init(out *FILE) void {
outfp = out;
gen("target triple = \"%s\"\n", g_targ.triple);
gen("%%.type.opaque = type opaque\n");
+ gen("%%.type.valist = type %s\n", g_targ.valistllvmty);
gen("\n");
}
diff --git a/src/parse.cff b/src/parse.cff
index 2e6cec9..3be70cf 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -439,7 +439,7 @@ fn lex(P *Parser) Tok {
case '"'; str->push('"'); case 'n'; str->push('\n');
case 'r'; str->push('\r'); case 't'; str->push('\t');
case 'v'; str->push('\v'); case 'f'; str->push('\f');
- case '0'; str->push('\0');
+ case '0'; str->push('\0'); case 'e'; str->push('\e');
case 'x';
let x0 = xdigit2num(chr(P)),
x1 = xdigit2num(chr(P));
@@ -1172,26 +1172,6 @@ fn exprdup(alloc *Allocator, ex Expr) *Expr {
return memcpy(alloc->alloc(sizeof(ex), alignof(ex)), &ex, sizeof(ex));
}
-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;
- return #t;
- case Dot;
- return #t;
- case BitDot bdot;
- return islvalue(bdot.lhs);
- case BitRaw ex;
- return islvalue(ex);
- case EUTag;
- return #t;
- }
- return #f;
-}
-
fn parseaggini(P *Parser, loc Loc, ty *const Type) Expr {
let loc = loc;
let tok Tok #?;
@@ -1540,9 +1520,9 @@ fn pexprimary(P *Parser) Expr {
let st = block.sts;
lexexpect(P, ')');
if st.#len == 0 or st[st.#len - 1].u.#tag != :Expr {
- ex = { tok.loc, ty_void, :Stmt(st) };
+ ex = { tok.loc, ty_void, :Stmt(block) };
} else {
- ex = { tok.loc, st[st.#len - 1].u.Expr.ty, :Stmt(st) };
+ ex = { tok.loc, st[st.#len - 1].u.Expr.ty, :Stmt(block) };
}
} else {
ex = parseexpr(P);
@@ -1581,6 +1561,9 @@ fn pexprimary(P *Parser) Expr {
if fld.ty == #null {
fatal(P, iex.loc, "%t variant %qT is empty", ty, tok);
}
+ if !typematchestarg(fld.ty, iex.ty) {
+ fatal(P, iex.loc, "bad enum union initializer (%t, expected %t)", iex.ty, fld.ty);
+ }
} else if fld.ty {
fatal(P, tok.loc, "%t variant %qT must be initialized", ty, tok);
}
@@ -1656,7 +1639,7 @@ fn pexpostfix(P *Parser) Expr {
if !lhs.ty->is(:Ptr) and !lhs.ty->is(:Arr) and !lhs.ty->is(:Slice) {
fatal(P, lhs.loc, "indexee is not array or pointer type (%t)", lhs.ty);
}
- if !rhs.ty->is(:Int) {
+ if !rhs.ty->is(:Int) and !(rhs.ty->is(:Enum) and rhs.ty.u.Enum.lax){
err(P, lhs.loc, "index expression type is not integral (%t)", rhs.ty);
}
@@ -1781,78 +1764,115 @@ fn pexpostfix(P *Parser) Expr {
}
case lexmatch(P, &tok, '->');
- let name = (tok = lexexpects(P, :ident, "method name")).u.ident;
let ty = ex.ty;
let exptr = #f;
if (exptr = ty->is(:Ptr)) {
ty = ty.u.Ptr;
}
- if !ty->is(:Agg) {
- fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty);
- }
- let agg = &ty.u.Agg;
- let decl *Decl = agg.decls ? envfind_noparent(agg.decls, name) : #null;
- if decl == #null {
- fatal(P, tok.loc, "%t has no such method %qT", ty, tok);
- }
- lexexpect(P, '(');
- switch decl.u {
- case Fn f;
- let Fn = &f.ty.u.Fn;
- if Fn.params.#len == 0 {
- fatal(P, tok.loc, "function takes no arguments");
+ let name = (tok = lexexpects(P, :ident, "method name")).u.ident;
+ switch ty.u {
+ case Agg *agg;
+ let decl *Decl = agg.decls ? envfind_noparent(agg.decls, name) : #null;
+ if decl == #null {
+ fatal(P, tok.loc, "%t has no such method %qT", ty, tok);
}
+ lexexpect(P, '(');
+ switch decl.u {
+ case Fn f;
+ let Fn = &f.ty.u.Fn;
+ if Fn.params.#len == 0 {
+ fatal(P, tok.loc, "function takes no arguments");
+ }
- let args Vec<Expr> = {};
- let recv0 = Fn.params[0], recv = recv0;
- let metptr = #f;
- if (metptr = recv->is(:Ptr)) {
- recv = recv.u.Ptr;
- }
- if unconstify(ty) != unconstify(recv) {
- err(P, tok.loc, "method receiver type mismatch for `->%s' (%t, expected %t)",
- name, ty, recv0);
- }
- switch {
- case !exptr and !metptr;
-
- case exptr and !metptr;
- ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}};
-
- case !exptr and metptr;
- if !islvalue(&ex) {
- err(P, tok.loc, "cannot call `->%s' by reference, lhs is not an lvalue", name);
- } else if ty.konst and !recv.konst {
- err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty);
+ let args Vec<Expr> = {};
+ let recv0 = Fn.params[0], recv = recv0;
+ let metptr = #f;
+ if (metptr = recv->is(:Ptr)) {
+ recv = recv.u.Ptr;
+ }
+ if unconstify(ty) != unconstify(recv) {
+ err(P, tok.loc, "method receiver type mismatch for `->%s' (%t, expected %t)",
+ name, ty, recv0);
+ }
+ switch {
+ case !exptr and !metptr;
+
+ case exptr and !metptr;
+ ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}};
+
+ case !exptr and metptr;
+ if !islvalue(&ex) {
+ err(P, tok.loc, "cannot call `->%s' by reference, lhs is not an lvalue", name);
+ } else if ty.konst and !recv.konst {
+ err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty);
+ }
+ ex = { ex.loc, mkptrtype(ty), :UnOp{:addrof, exprdup(P.alloc, ex)}};
+
+ case exptr and metptr;
+ if ty.konst and !recv.konst {
+ err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty);
+ }
+ }
+ args->push(ex);
+ let param = &Fn.params[1];
+ while !lexmatch(P, #null, ')') {
+ P.targty = *param++;
+ args->push(parseexpr(P));
+ if args.len > Fn.params.#len and !Fn.variadic {
+ fatal(P, args->last().loc, "too many args (%z, expected %z)", args.len, Fn.params.#len);
}
- ex = { ex.loc, mkptrtype(ty), :UnOp{:addrof, exprdup(P.alloc, ex)}};
-
- case exptr and metptr;
- if ty.konst and !recv.konst {
- err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty);
+ if !lexmatch(P, #null, ',') {
+ lexexpect(P, ')');
+ break;
}
- }
- args->push(ex);
- let param = &Fn.params[1];
- while !lexmatch(P, #null, ')') {
- P.targty = *param++;
- args->push(parseexpr(P));
- if args.len > Fn.params.#len and !Fn.variadic {
- fatal(P, args->last().loc, "too many args (%z, expected %z)", args.len, Fn.params.#len);
}
- if !lexmatch(P, #null, ',') {
- lexexpect(P, ')');
- break;
+ if args.len < Fn.params.#len {
+ err(P, ex.loc, "too few args (%z, expected %z)", args.len, Fn.params.#len);
}
+ let met Expr = { tok.loc, f.ty, :Symbol(decl) };
+ ex = { tok.loc, .ty: Fn.ret, .u: :Call { exprdup(P.alloc, met), args->move(P.alloc) }};
+
+ case else;
+ fatal(P, tok.loc, "cannot call `->%s': not a function or macro", name);
}
- if args.len < Fn.params.#len {
- err(P, ex.loc, "too few args (%z, expected %z)", args.len, Fn.params.#len);
+
+ case VaList;
+ if !islvalue(&ex) {
+ err(P, ex.loc, "variadic list receiver must be lvalue");
+ }
+ if exptr {
+ ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}};
}
- let met Expr = { tok.loc, f.ty, :Symbol(decl) };
- ex = { tok.loc, .ty: Fn.ret, .u: :Call { exprdup(P.alloc, met), args->move(P.alloc) }};
+ switch {
+ case streq(name, "start");
+ lexexpect(P, '(');
+ if !lexmatch(P, #null, ')') {
+ let _ = parseexpr(P);
+ lexmatch(P, #null, ',');
+ warn(P, ex.loc, "variadic list `start' doesn't need an argument");
+ lexexpect(P, ')');
+ }
+ ex = { tok.loc, ty_void, :VaStart(exprdup(P.alloc, ex)) };
- case else;
- fatal(P, tok.loc, "cannot call `->%s': not a function or macro", name);
+ case streq(name, "arg");
+ lexexpect(P, '(');
+ let type = parsetype(P);
+ lexmatch(P, #null, ',');
+ lexexpect(P, ')');
+ ex = { tok.loc, type, :VaArg(exprdup(P.alloc, ex)) };
+
+ case streq(name, "end");
+ lexexpect(P, '(');
+ lexmatch(P, #null, ',');
+ lexexpect(P, ')');
+ ex = { tok.loc, ty_void, :VaEnd(exprdup(P.alloc, ex)) };
+
+ case else
+ fatal(P, tok.loc, "`%s' is not a valid method for variadic list", name);
+ }
+
+ case else
+ fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty);
}
case else;
@@ -2241,28 +2261,30 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
}
lexexpect(P, '{');
let body Block #?;
- with_tmpchange(P.curloop, ++P.loopid) {
+ let loopid = ++P.loopid;
+ with_tmpchange(P.curloop, loopid) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
pushenv(P, env);
if label {
- putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ putdecl(P, loc, { label, loc, .u: :Label(loopid) });
}
body = parseblock(P);
popenv(P);
}
- return { loc, :While { test, body, P.loopid }};
+ return { loc, :While { test, body, loopid }};
}
fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt {
lexexpect(P, '{');
let body Block #?;
- with_tmpchange(P.curloop, ++P.loopid) {
+ let loopid = ++P.loopid;
+ with_tmpchange(P.curloop, loopid) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
pushenv(P, env);
if label {
- putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ putdecl(P, loc, { label, loc, .u: :Label(loopid) });
}
body = parseblock(P);
popenv(P);
@@ -2272,7 +2294,7 @@ fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt {
if !test.ty->is(:Bool) and !test.ty->is(:Ptr) {
err(P, test.loc, "do-while condition must be bool or pointer (%t)", test.ty);
}
- return { loc, :DoWhile { test, body, P.loopid }};
+ return { loc, :DoWhile { test, body, loopid }};
}
fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
@@ -2311,18 +2333,18 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
lexexpect(P, '{');
}
let body Block #?;
- let id = ++P.loopid;
- with_tmpchange(P.curloop, id) {
+ let loopid = ++P.loopid;
+ with_tmpchange(P.curloop, loopid) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
pushenv(P, env);
if label {
- putdecl(P, loc, { label, loc, .u: :Label(id) });
+ putdecl(P, loc, { label, loc, .u: :Label(loopid) });
}
body = parseblock(P);
popenv(P);
}
- return { loc, :For { ini, test, next, body, id }};
+ return { loc, :For { ini, test, next, body, loopid }};
}
fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
@@ -2755,10 +2777,10 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
return decl;
}
-fn parse4import(P *Parser) [#]Decl;
-fn doimport(P *Parser, loc Loc, path *const u8) [#]Decl {
+fn parse4import(P *Parser) [#]*Decl;
+fn doimport(P *Parser, loc Loc, path *const u8) [#]*Decl {
struct Entry {
- decls [#]Decl,
+ decls [#]*Decl,
wip bool,
}
static seen Map<*const u8, Entry, struct {
@@ -2993,7 +3015,7 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr;
let decls = doimport(P, tok.loc, path);
foreach(decl, _, decls) {
- let decl = putdecl(P, decl.loc, decl);
+ let decl = putdecl(P, decl.loc, *decl);
if yield {
yield(decl, yarg);
}
@@ -3131,14 +3153,14 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
}
}
-fn parse4import(P *Parser) [#]Decl {
- let decls Vec<Decl> = {};
+fn parse4import(P *Parser) [#]*Decl {
+ let decls Vec<*Decl> = {};
P.curenv = mkenv(#null, P.alloc);
while !P.eof {
fn yield(decl *Decl, arg *void) void {
- let decls *Vec<Decl> = arg;
- decls->push(*decl);
+ let decls *Vec<*Decl> = arg;
+ decls->push(decl);
}
parsedecls(P, P.tokloc, &yield, &decls, #{toplevel} #t);
if lexmatch(P, #null, :eof) {