wip: advance M5 ownership cleanup

This commit is contained in:
2026-08-16 14:22:03 +09:00
parent 6acfc5918d
commit 631d2ebb48
15 changed files with 752 additions and 33 deletions
+177 -5
View File
@@ -12,6 +12,7 @@ struct FeSym {
FeNode *fn;
int mutable;
int initialized;
int moved;
FeNode *decl;
};
@@ -22,11 +23,15 @@ struct FeScope {
unsigned capacity;
};
static FeSym *find_symbol(FeScope *scope, const char *name);
typedef struct FeCheckerState {
FeCheck *c;
FeScope *scope;
FeScope *globals;
FeType *ret;
unsigned loop_depth;
unsigned defer_depth;
} FeCheckerState;
static FeType *unknown(FeCheck *c)
@@ -44,6 +49,41 @@ static int known(FeType *t)
return t && t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_ERROR;
}
static int is_copy_type(FeType *t)
{
unsigned i;
if (!t) return 1;
if (t->kind==FE_TYPE_OWNED) return 0;
if (t->kind==FE_TYPE_REF) return !t->ref_mut;
if (t->kind==FE_TYPE_ARRAY) return is_copy_type(t->elem);
if (t->kind==FE_TYPE_STRUCT) {
if (t->has_drop) return 0;
for (i=0;i<t->field_count;i++) if (!is_copy_type(t->fields[i].type)) return 0;
}
if (t->kind==FE_TYPE_ENUM)
for (i=0;i<t->variant_count;i++) {
unsigned j;
for (j=0;j<t->variants[i].field_count;j++)
if (!is_copy_type(t->variants[i].fields[j].type)) return 0;
}
return 1;
}
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
{
FeSym *sym;
if (!n || !t || is_copy_type(t) || n->kind!=FE_N_IDENT) return;
sym=find_symbol(s->scope,n->text ? n->text : "");
if (sym) {
if (s->defer_depth) {
if (sym->decl) sym->decl->flags |= 0x200U;
} else {
sym->moved=1;
if (sym->decl) sym->decl->flags |= 0x100U;
}
}
}
static int compatible(FeType *want, FeType *got, FeNode *value)
{
FeNode *item;
@@ -193,6 +233,7 @@ static FeSym *add_symbol(FeCheckerState *s, FeScope *scope,
sym->fn = fn;
sym->mutable = mutable;
sym->initialized = initialized;
sym->moved = 0;
sym->decl = decl;
if (decl) {
decl->cname = cname;
@@ -217,6 +258,47 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n);
static void check_match(FeCheckerState *s, FeNode *n);
static void check_stmt(FeCheckerState *s, FeNode *n);
typedef struct FeFlowSlot {
FeSym *sym;
int moved;
int initialized;
} FeFlowSlot;
static unsigned flow_capture(FeScope *scope, FeFlowSlot *slots, unsigned cap)
{
unsigned count=0;
unsigned i;
FeScope *p;
for (p=scope; p && count<cap; p=p->parent)
for (i=0; i<p->count && count<cap; ++i) {
slots[count].sym=&p->items[i];
slots[count].moved=p->items[i].moved;
slots[count].initialized=p->items[i].initialized;
++count;
}
return count;
}
static void flow_restore(FeFlowSlot *slots, unsigned count)
{
unsigned i;
for (i=0; i<count; ++i) {
slots[i].sym->moved=slots[i].moved;
slots[i].sym->initialized=slots[i].initialized;
}
}
static void flow_merge(FeFlowSlot *base, FeFlowSlot *left, FeFlowSlot *right,
unsigned count)
{
unsigned i;
for (i=0; i<count; ++i) {
base[i].sym->moved = left[i].moved==1 && right[i].moved==1 ? 1 :
(left[i].moved || right[i].moved ? 2 : 0);
base[i].sym->initialized = left[i].initialized && right[i].initialized;
}
}
static FeNode *find_const_node(FeCheck *c, const char *name)
{
FeNode *n;
@@ -390,6 +472,7 @@ static FeType *check_struct_init(FeCheckerState *s, FeNode *n)
}
if (!field) { err(s->c,f->loc,"invalid enum payload field"); continue; }
v=check_expr(s,f->a);
mark_moved(s,f->a,v);
if (!compatible(field->type,v,f->a) && v->kind!=FE_TYPE_UNKNOWN) err(s->c,f->loc,"enum payload type mismatch");
}
} else if (n->children) err(s->c,n->loc,"empty enum variant cannot have payload");
@@ -402,6 +485,7 @@ static FeType *check_struct_init(FeCheckerState *s, FeNode *n)
field=fe_type_field(t,f->text);
if(!field) { err(s->c,f->loc,"invalid struct field"); continue; }
v=check_expr(s,f->a);
mark_moved(s,f->a,v);
if(!compatible(field->type,v,f->a) && v->kind!=FE_TYPE_UNKNOWN) err(s->c,f->loc,"struct field type mismatch");
}
for(i=0;i<t->field_count;i++) if(!has_field(n->children,t->fields[i].name)) err(s->c,n->loc,"missing struct field");
@@ -411,7 +495,7 @@ static FeType *check_struct_init(FeCheckerState *s, FeNode *n)
static FeType *check_array_init(FeCheckerState *s, FeNode *n)
{
FeNode *x; FeType *elem=0; FeType *v; unsigned long count=0;
for(x=n->children;x;x=x->next) { v=check_expr(s,x); if(!elem) elem=v; else if(!compatible(elem,v,x)&&v->kind!=FE_TYPE_UNKNOWN) err(s->c,x->loc,"array element type mismatch"); ++count; }
for(x=n->children;x;x=x->next) { v=check_expr(s,x); mark_moved(s,x,v); if(!elem) elem=v; else if(!compatible(elem,v,x)&&v->kind!=FE_TYPE_UNKNOWN) err(s->c,x->loc,"array element type mismatch"); ++count; }
if(!elem) elem=unknown(s->c);
n->sem_type=fe_type_array(&s->c->types,count,elem); return n->sem_type;
}
@@ -446,6 +530,8 @@ static FeType *check_identifier(FeCheckerState *s, FeNode *n, int read)
}
n->cname = sym->cname;
n->sem_type = sym->type;
if (sym->moved == 1) err(s->c,n->loc,"use of moved value");
else if (sym->moved == 2) err(s->c,n->loc,"use of possibly moved value");
if (read && !sym->initialized && !sym->fn)
err(s->c, n->loc, "use of uninitialized variable");
return sym->type;
@@ -545,6 +631,34 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
return a;
}
if (n->kind == FE_N_CALL) {
if (n->a && n->a->kind==FE_N_MEMBER && n->a->b && n->a->b->text &&
strcmp(n->a->b->text,"drop")==0) {
err(c,n->loc,"drop may only be invoked by scope cleanup");
return unknown(c);
}
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"mem")==0 && n->a->b && n->a->b->text) {
FeNode *arg=n->children;
if (strcmp(n->a->b->text,"destroy")==0) {
a=arg ? check_expr(s,arg) : unknown(c);
if (!arg || arg->next || !a || a->kind!=FE_TYPE_OWNED)
err(c,n->loc,"mem.destroy requires exactly one owned pointer");
else
mark_moved(s,arg,a);
n->sem_type=fe_type_intern(&c->types,"void");
return n->sem_type;
}
if (strcmp(n->a->b->text,"create")==0) {
if (!arg || arg->next || arg->kind!=FE_N_IDENT)
err(c,n->loc,"mem.create requires exactly one type argument");
a=arg && arg->kind==FE_N_IDENT ?
fe_type_owned(&c->types,fe_type_intern(&c->types,arg->text)) :
fe_type_owned(&c->types,unknown(c));
n->sem_type=fe_type_error_union(&c->types,a);
return n->sem_type;
}
}
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
@@ -606,6 +720,7 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
arg = n->children;
while (param && arg) {
a = check_expr(s, arg);
mark_moved(s,arg,a);
b = node_type(c, param->a);
if (!compatible(b, a, arg) && a->kind != FE_TYPE_UNKNOWN)
err(c, arg->loc, "argument type mismatch");
@@ -634,6 +749,11 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
n->sem_type=a->elem;
return a->elem;
}
if (a->kind == FE_TYPE_OWNED && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) {
n->sem_type=a->elem;
return a->elem;
}
if(a->kind==FE_TYPE_STRUCT) {
field=fe_type_field(a,n->b ? n->b->text : "");
if(!field) { err(c,n->loc,"unknown struct field"); return unknown(c); }
@@ -684,6 +804,11 @@ static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
n->sem_type=base->elem;
return base->elem;
}
if (base && base->kind == FE_TYPE_OWNED && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) {
n->sem_type=base->elem;
return base->elem;
}
if (!lvalue_writable(s,n->a))
err(s->c,n->loc,"cannot assign through immutable value");
field=base && base->kind==FE_TYPE_STRUCT ? fe_type_field(base,n->b ? n->b->text : "") : 0;
@@ -817,7 +942,7 @@ static void check_type_cycle(FeCheck *c, FeType *t)
unsigned i;
FeType *next;
if (!t || t->kind == FE_TYPE_SLICE || t->kind == FE_TYPE_STR ||
t->kind == FE_TYPE_REF ||
t->kind == FE_TYPE_REF || t->kind == FE_TYPE_OWNED ||
t->kind == FE_TYPE_INT || t->kind == FE_TYPE_BOOL ||
t->kind == FE_TYPE_CHAR || t->kind == FE_TYPE_VOID ||
t->kind == FE_TYPE_UNKNOWN || t->kind == FE_TYPE_ERROR) return;
@@ -889,6 +1014,7 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
err(c, n->loc, "initializer type mismatch");
if (b->kind == FE_TYPE_VOID)
err(c, n->loc, "void expression cannot initialize a variable");
mark_moved(s,n->b,b);
add_symbol(s, s->scope, n->text, a, 0, 0, 1,
local_cname(c, n->text ? n->text : "local"), n);
break;
@@ -904,6 +1030,7 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
err(c, n->loc, "initializer type mismatch");
if (b->kind == FE_TYPE_VOID)
err(c, n->loc, "void expression cannot initialize a variable");
mark_moved(s,n->b,b);
initialized = n->b != 0;
add_symbol(s, s->scope, n->text, a, 0, 1, initialized,
local_cname(c, n->text ? n->text : "local"), n);
@@ -913,6 +1040,7 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
a = check_lvalue(s, n->a, compound_operator(n->text));
if (!compatible(a, b, n->b) && b->kind != FE_TYPE_UNKNOWN)
err(c, n->loc, "assignment type mismatch");
mark_moved(s,n->b,b);
sym = n->a && n->a->kind == FE_N_IDENT ?
find_symbol(s->scope, n->a->text) : 0;
if (sym && sym->mutable) sym->initialized = 1;
@@ -924,27 +1052,67 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
(!s->ret || s->ret->kind!=FE_TYPE_ERROR_UNION))
err(c,n->loc,"try requires an enclosing error result");
break;
case FE_N_IF:
case FE_N_DEFER:
++s->defer_depth;
check_stmt(s,n->a);
--s->defer_depth;
break;
case FE_N_IF: {
FeFlowSlot base[128], left[128], right[128];
unsigned flow_count;
a = check_expr(s, n->a);
if (known(a) && a->kind != FE_TYPE_BOOL)
err(c, n->loc, "if condition must be bool");
flow_count=flow_capture(s->scope,base,128);
check_stmt(s, n->b);
check_stmt(s, n->c);
flow_capture(s->scope,left,flow_count);
flow_restore(base,flow_count);
if (n->c) check_stmt(s, n->c);
if (n->c) flow_capture(s->scope,right,flow_count);
else {
unsigned i;
for (i=0;i<flow_count;++i) right[i]=base[i];
}
flow_merge(base,left,right,flow_count);
break;
case FE_N_WHILE:
}
case FE_N_WHILE: {
FeFlowSlot base[128], body[128];
unsigned flow_count;
a = check_expr(s, n->a);
if (known(a) && a->kind != FE_TYPE_BOOL)
err(c, n->loc, "while condition must be bool");
flow_count=flow_capture(s->scope,base,128);
if (s->loop_depth < 255U) ++s->loop_depth;
check_stmt(s, n->b);
if (s->loop_depth) --s->loop_depth;
flow_capture(s->scope,body,flow_count);
flow_restore(base,flow_count);
{
unsigned i;
for (i=0;i<flow_count;++i) {
if (body[i].moved) base[i].moved=2;
if (!body[i].initialized) base[i].initialized=0;
}
}
flow_restore(base,flow_count);
break;
}
case FE_N_FOR:
if (s->loop_depth < 255U) ++s->loop_depth;
check_for(s,n);
if (s->loop_depth) --s->loop_depth;
break;
case FE_N_MATCH:
check_match(s,n);
break;
case FE_N_BREAK:
case FE_N_CONTINUE:
if (!s->loop_depth) err(c,n->loc,"break or continue outside loop");
break;
case FE_N_RETURN:
b = n->a ? check_expr(s, n->a) : fe_type_intern(&c->types, "void");
mark_moved(s,n->a,b);
if (known(b) && b->kind == FE_TYPE_VOID && s->ret->kind != FE_TYPE_VOID)
err(c, n->loc, "void expression returned from value function");
else if (known(s->ret) && known(b) && !fe_type_equal(s->ret, b) &&
@@ -970,6 +1138,8 @@ static void check_fn(FeCheck *c, FeNode *fn, FeScope *globals)
s.globals = globals;
s.scope = scope_new(&s, globals);
s.ret = fn->b ? node_type(c, fn->b) : fe_type_intern(&c->types, "void");
s.loop_depth=0;
s.defer_depth=0;
fn->sem_type = s.ret;
for (x = fn->a ? fn->a->children : 0; x; x = x->next) {
t = node_type(c, x->a);
@@ -1047,5 +1217,7 @@ FeType *fe_check_expr_type(FeCheck *c, FeNode *n)
s.scope = scope_new(&s, 0);
s.globals = s.scope;
s.ret = fe_type_intern(&c->types, "void");
s.loop_depth=0;
s.defer_depth=0;
return check_expr(&s, n);
}
+377 -25
View File
@@ -2,6 +2,10 @@
#include <stdio.h>
#include <string.h>
static void emit_expr(FeEmitter *e, FeNode *n);
static void emit_stmt(FeEmitter *e, FeNode *n);
static void emit_block(FeEmitter *e, FeNode *n);
static void pad(FeEmitter *e)
{
int i;
@@ -24,6 +28,19 @@ static const char *cname(FeNode *n, const char *fallback)
static void emit_one_type(FeEmitter *e, FeType *t);
static int type_needs_drop(FeType *t)
{
unsigned i;
if (!t) return 0;
if (t->kind==FE_TYPE_OWNED) return 1;
if (t->kind==FE_TYPE_ARRAY) return type_needs_drop(t->elem);
if (t->kind==FE_TYPE_STRUCT) {
if (t->has_drop) return 1;
for (i=0;i<t->field_count;i++) if (type_needs_drop(t->fields[i].type)) return 1;
}
return 0;
}
static void emit_type_deps(FeEmitter *e, FeType *t)
{
unsigned i,j;
@@ -35,6 +52,8 @@ static void emit_type_deps(FeEmitter *e, FeType *t)
for (i=0;i<t->variant_count;i++)
for (j=0;j<t->variants[i].field_count;j++)
emit_one_type(e,t->variants[i].fields[j].type);
if (t->kind == FE_TYPE_ERROR_UNION && t->error_value)
emit_one_type(e,t->error_value);
}
static void emit_one_type(FeEmitter *e, FeType *t)
@@ -43,7 +62,10 @@ static void emit_one_type(FeEmitter *e, FeType *t)
if (t && strcmp(t->name,"io.Writer")==0) return;
if (!t || t->emit_state ||
(t->kind != FE_TYPE_STRUCT && t->kind != FE_TYPE_ENUM &&
t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE)) return;
t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE &&
t->kind != FE_TYPE_ERROR_UNION) ||
(t->kind == FE_TYPE_ERROR_UNION &&
(!t->error_value || t->error_value->kind == FE_TYPE_VOID))) return;
t->emit_state=1;
emit_type_deps(e,t);
if(t->kind==FE_TYPE_STRUCT) {
@@ -55,6 +77,10 @@ static void emit_one_type(FeEmitter *e, FeType *t)
} else if(t->kind==FE_TYPE_SLICE && t->cname) {
fputs("typedef struct { ",e->out); fputs(fe_type_c_name(t->elem,e->pointer_bits),e->out); fputs(" *p; unsigned long n; } ",e->out); fputs(t->cname,e->out); fputs(";\n",e->out);
fprintf(e->out,"static %s %s(%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",t->cname,t->maker,fe_type_c_name(t->elem,e->pointer_bits),t->cname);
} else if(t->kind==FE_TYPE_ERROR_UNION) {
fputs(t->cname,e->out); fputs(" { unsigned short e; ",e->out);
fputs(fe_type_c_name(t->error_value,e->pointer_bits),e->out);
fputs(" v; } ;\n",e->out);
} else if(t->kind==FE_TYPE_ENUM) {
for(i=0;i<t->variant_count;i++) if(t->variants[i].field_count>1) {
fprintf(e->out,"struct fe_payload_%s_%s {",t->name,t->variants[i].name);
@@ -81,10 +107,95 @@ static void emit_type_defs(FeEmitter *e)
for(t=e->check->types.types;t;t=t->next) emit_one_type(e,t);
}
static FeNode *find_drop_method(FeEmitter *e, const char *name)
{
FeNode *n;
FeNode *m;
for (n=e->check->ast->root ? e->check->ast->root->children : 0; n; n=n->next)
if (n->kind==FE_N_STRUCT && n->text && name && strcmp(n->text,name)==0)
for (m=n->children; m; m=m->next)
if (m->kind==FE_N_FN && m->text && strcmp(m->text,"drop")==0)
return m;
return 0;
}
static void emit_drop_fields(FeEmitter *e, FeType *t)
{
unsigned i;
FeType *ft;
for (i=t->field_count; i>0; --i) {
ft=t->fields[i-1].type;
if (!type_needs_drop(ft)) continue;
if (ft->kind==FE_TYPE_OWNED) {
fputs("if (self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs(") { ",e->out);
if (ft->elem && type_needs_drop(ft->elem) && ft->elem->drop_cname) {
fprintf(e->out,"%s(self->%s); ",ft->elem->drop_cname,t->fields[i-1].name);
}
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs("); self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs("=0; }\n",e->out);
} else if (ft->kind==FE_TYPE_STRUCT && ft->drop_cname) {
fprintf(e->out,"%s(&self->%s);\n",ft->drop_cname,t->fields[i-1].name);
} else if (ft->kind==FE_TYPE_ARRAY && ft->drop_cname) {
fprintf(e->out,"%s(&self->%s);\n",ft->drop_cname,t->fields[i-1].name);
}
}
}
static void emit_drop_helpers(FeEmitter *e)
{
FeType *t;
FeNode *method;
FeNode *param;
for (t=e->check->types.types; t; t=t->next)
if ((t->kind==FE_TYPE_STRUCT || t->kind==FE_TYPE_ARRAY) &&
type_needs_drop(t) && t->drop_cname)
fprintf(e->out,"static void %s(%s *self);\n",t->drop_cname,t->cname);
for (t=e->check->types.types; t; t=t->next) {
if (t->kind!=FE_TYPE_STRUCT || !type_needs_drop(t) || !t->drop_cname) continue;
fprintf(e->out,"static void %s(%s *self) {\n",t->drop_cname,t->cname);
method=find_drop_method(e,t->name);
if (method) {
param=method->a ? method->a->children : 0;
if (param) param->cname="self";
if (method->c) emit_block(e,method->c);
fputc('\n',e->out);
}
emit_drop_fields(e,t);
fputs("}\n",e->out);
}
for (t=e->check->types.types; t; t=t->next)
if (t->kind==FE_TYPE_ARRAY && type_needs_drop(t) && t->drop_cname) {
fprintf(e->out,"static void %s(%s *self) { unsigned long i; for (i=0; i<%lu; ++i) { ",
t->drop_cname,t->cname,t->length);
if (t->elem->kind==FE_TYPE_OWNED) {
fputs("if (self->a[i]) { ",e->out);
if (t->elem->elem && type_needs_drop(t->elem->elem) && t->elem->elem->drop_cname)
fprintf(e->out,"%s(self->a[i]); ",t->elem->elem->drop_cname);
fputs("free(self->a[i]); self->a[i]=0; }",e->out);
} else if (t->elem->drop_cname)
fprintf(e->out,"%s(&self->a[i]);",t->elem->drop_cname);
fputs(" } }\n",e->out);
}
}
static void emit_type_helpers(FeEmitter *e)
{
FeType *t;
unsigned i,j;
for(t=e->check->types.types;t;t=t->next) {
if (t->kind==FE_TYPE_ERROR_UNION && t->error_value &&
t->error_value->kind!=FE_TYPE_VOID) {
fprintf(e->out,"static %s %s(unsigned short e, %s v) { %s r; r.e=e; r.v=v; return r; }\n",
t->cname,t->maker,fe_type_c_name(t->error_value,e->pointer_bits),t->cname);
if (t->error_value->kind==FE_TYPE_OWNED)
fprintf(e->out,"static %s %s(void) { %s r; r.v=(%s)malloc(sizeof(%s)); r.e=r.v ? 0 : 1; return r; }\n",
t->cname,t->alloc_cname,t->cname,
fe_type_c_name(t->error_value,e->pointer_bits),
fe_type_c_name(t->error_value->elem,e->pointer_bits));
}
}
for(t=e->check->types.types;t;t=t->next) {
if(t->kind==FE_TYPE_STRUCT && t->maker) {
fprintf(e->out,"static %s %s(",t->cname,t->maker);
@@ -109,6 +220,7 @@ static void emit_type_helpers(FeEmitter *e)
}
}
}
emit_drop_helpers(e);
for(t=e->check->types.types;t;t=t->next) {
if (t->kind==FE_TYPE_ARRAY && t->indexer) {
fprintf(e->out,"static %s %s(%s x, unsigned long i) { ",
@@ -501,6 +613,9 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
if (n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_REF &&
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
} else if (n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED &&
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
} else { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); }
return;
}
@@ -512,6 +627,19 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
emit_expr(e,n);
}
static void emit_destroy_expr(FeEmitter *e, FeNode *n)
{
fputs("(free(",e->out); emit_expr(e,n); fputs(")",e->out);
if (n && n->kind==FE_N_IDENT) {
fputs(", ",e->out); emit_lvalue(e,n);
fputs("=0, fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs("=0",e->out);
} else {
fputs(", ",e->out); emit_lvalue(e,n); fputs("=0",e->out);
}
fputs(", 0)",e->out);
}
static FeNode *init_field(FeNode *n, const char *name)
{
FeNode *f;
@@ -609,7 +737,15 @@ static void emit_expr(FeEmitter *e, FeNode *n)
}
case FE_N_UNARY:
op = n->text ? n->text : "";
if (strcmp(op, "try") == 0) { emit_expr(e,n->a); break; }
if (strcmp(op, "try") == 0) {
if (n->a && n->a->sem_type &&
n->a->sem_type->kind==FE_TYPE_ERROR_UNION &&
n->a->sem_type->error_value &&
n->a->sem_type->error_value->kind!=FE_TYPE_VOID) {
fputc('(',e->out); emit_expr(e,n->a); fputs(").v",e->out);
} else emit_expr(e,n->a);
break;
}
if (strcmp(op, "not") == 0) fputs("(!", e->out);
else {
fputc('(', e->out);
@@ -641,6 +777,27 @@ static void emit_expr(FeEmitter *e, FeNode *n)
FeVariantType *v;
int special=0;
if(n->text && (strcmp(n->text,"@print")==0 || strcmp(n->text,"@fprint")==0 || strcmp(n->text,"@sprint")==0)) { emit_m4_builtin(e,n); special=1; }
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
n->a->b->text && strcmp(n->a->b->text,"destroy")==0 &&
n->children) {
emit_destroy_expr(e,n->children);
special=1;
}
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
n->a->b->text && strcmp(n->a->b->text,"create")==0 &&
n->children && n->children->kind==FE_N_IDENT) {
FeType *created=fe_type_intern(&e->check->types,n->children->text);
FeType *owned=fe_type_owned(&e->check->types,created);
FeType *result=fe_type_error_union(&e->check->types,owned);
if (result->alloc_cname) fputs(result->alloc_cname,e->out);
else fputs("fe_bad_alloc",e->out);
fputs("()",e->out);
special=1;
}
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
@@ -660,7 +817,11 @@ static void emit_expr(FeEmitter *e, FeNode *n)
fputc('(', e->out);
for (x = n->children; x; x = x->next) {
if (x != n->children) fputs(", ", e->out);
emit_expr(e, x);
if ((x->flags & 0x100U) && x->kind==FE_N_IDENT &&
x->sem_type && x->sem_type->kind==FE_TYPE_OWNED) {
fputs("(fe_live_",e->out); fputs(cname(x,"owned"),e->out);
fputs("=0, ",e->out); emit_expr(e,x); fputc(')',e->out);
} else emit_expr(e, x);
}
fputc(')', e->out);
}
@@ -674,6 +835,9 @@ static void emit_expr(FeEmitter *e, FeNode *n)
else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_REF &&
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
} else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED &&
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
} else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_ENUM) { v=fe_type_variant(n->a->sem_type,n->b ? n->b->text : ""); if(v) fputs(v->maker,e->out); else fputs("0",e->out); if(v)fputs("()",e->out); }
else { emit_expr(e, n->a); fputc('.', e->out); if (n->b) fputs(n->b->text ? n->b->text : "member", e->out); }
break;
@@ -701,6 +865,89 @@ static void emit_decl(FeEmitter *e, FeNode *n)
} else emit_expr(e,n->b);
}
fputs(";\n", e->out);
if ((n->kind==FE_N_LET || n->kind==FE_N_VAR) && n->sem_type &&
n->sem_type->kind==FE_TYPE_OWNED) {
pad(e); fputs("unsigned char fe_live_",e->out);
fputs(cname(n,"owned"),e->out); fputs("=0;\n",e->out);
}
}
static void emit_owned_live(FeEmitter *e, FeNode *n, int value)
{
if (n && n->sem_type && n->sem_type->kind==FE_TYPE_OWNED) {
pad(e); fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fprintf(e->out,"=%d;\n",value);
}
}
static void emit_value_drop(FeEmitter *e, FeNode *n)
{
FeType *t=n ? n->sem_type : 0;
if (!n || !t || !type_needs_drop(t) || (n->flags & 0x100U) ||
(n->flags & 0x200U)) return;
if (t->kind==FE_TYPE_OWNED) {
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs(") { ",e->out);
if (t->elem && type_needs_drop(t->elem) && t->elem->drop_cname) {
fprintf(e->out,"%s(%s); ",t->elem->drop_cname,cname(n,"owned"));
}
fputs("free(",e->out); fputs(cname(n,"owned"),e->out);
fputs("); fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs("=0; }\n",e->out);
} else if (t->drop_cname) {
pad(e); fprintf(e->out,"%s(&%s);\n",t->drop_cname,cname(n,"local"));
}
}
static void emit_cleanup_block(FeEmitter *e, FeNode *n)
{
FeNode *x;
unsigned count=0;
unsigned index;
unsigned seen=0xffffffffU;
unsigned depth;
/* A defer becomes active only after its declaration statement was
reached. In particular, a failing initializer must not run a later
defer merely because it shares this AST block. */
for (depth=0; depth<e->block_depth; ++depth)
if (e->block_stack[depth]==n) { seen=e->block_seen[depth]; break; }
for (x=n ? n->children : 0, index=0; x; x=x->next, ++index)
if (index<seen &&
(x->kind==FE_N_DEFER || x->kind==FE_N_LET || x->kind==FE_N_VAR)) ++count;
while (count) {
index=0;
for (x=n->children; x; x=x->next)
if ((x->kind==FE_N_DEFER || x->kind==FE_N_LET || x->kind==FE_N_VAR) &&
index++==count-1) {
if (x->kind==FE_N_DEFER) emit_stmt(e,x->a); else emit_value_drop(e,x);
break;
}
--count;
}
}
static void emit_cleanup_to(FeEmitter *e, unsigned floor)
{
unsigned i;
for (i=e->block_depth; i>floor; --i) emit_cleanup_block(e,e->block_stack[i-1]);
}
static void emit_cleanup_all(FeEmitter *e)
{
emit_cleanup_to(e,0);
}
static void emit_error_return(FeEmitter *e, const char *error_expr)
{
if (e->current_ret && e->current_ret->kind==FE_TYPE_ERROR_UNION &&
e->current_ret->error_value && e->current_ret->error_value->kind!=FE_TYPE_VOID) {
fputs("return ",e->out); fputs(e->current_ret->maker,e->out);
fputs("(",e->out); fputs(error_expr,e->out); fputs(", (",e->out);
fputs(fe_type_c_name(e->current_ret->error_value,e->pointer_bits),e->out);
fputs(")0);\n",e->out);
} else {
fputs("return ",e->out); fputs(error_expr,e->out); fputs(";\n",e->out);
}
}
static void emit_block(FeEmitter *e, FeNode *n)
@@ -718,12 +965,30 @@ static void emit_block(FeEmitter *e, FeNode *n)
pad(e);
fputs("{\n", e->out);
++e->indent;
if (e->block_depth<32U) {
e->block_stack[e->block_depth]=n;
e->block_seen[e->block_depth]=0;
++e->block_depth;
}
/* C89 requires declarations before statements in each actual block. */
for (x = n->children; x; x = x->next)
if (x->kind == FE_N_LET || x->kind == FE_N_VAR ||
x->kind == FE_N_CONST) emit_decl(e, x);
for (x = n->children; x; x = x->next) emit_stmt(e, x);
if (e->current_ret && e->current_ret->kind!=FE_TYPE_VOID) {
pad(e); fputs(fe_type_c_name(e->current_ret,e->pointer_bits),e->out);
fputs(" fe_return_value;\n",e->out);
}
{
unsigned seen=0;
for (x = n->children; x; x = x->next) {
++seen;
if (e->block_depth) e->block_seen[e->block_depth-1]=seen;
emit_stmt(e, x);
}
}
--e->indent;
emit_cleanup_block(e,n);
if (e->block_depth) --e->block_depth;
if (e->fallthrough_block==n) {
pad(e);
fputs("return 0;\n",e->out);
@@ -765,6 +1030,37 @@ static void emit_match(FeEmitter *e, FeNode *n, int value_context)
}
}
static int try_has_value(FeNode *n)
{
return n && n->kind==FE_N_UNARY && n->text && strcmp(n->text,"try")==0 &&
n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_ERROR_UNION &&
n->a->sem_type->error_value && n->a->sem_type->error_value->kind!=FE_TYPE_VOID;
}
static void emit_try_statement(FeEmitter *e, FeNode *try_node, FeNode *target)
{
char temp[40];
char error[48];
FeType *result=try_node->a->sem_type;
sprintf(temp,"fe_try_%u",e->temp_serial++);
sprintf(error,"%s.e",temp);
pad(e); fputs("{ ",e->out); fputs(fe_type_c_name(result,e->pointer_bits),e->out);
fputc(' ',e->out); fputs(temp,e->out); fputs(" = ",e->out);
emit_expr(e,try_node->a); fputs("; if (",e->out); fputs(temp,e->out);
fputs(".e) {\n",e->out); ++e->indent;
emit_cleanup_all(e);
pad(e); emit_error_return(e,error);
--e->indent; pad(e); fputs("} ",e->out);
if (target) {
if (target->kind==FE_N_LET || target->kind==FE_N_VAR)
fputs(cname(target,"fe_local"),e->out);
else
emit_lvalue(e,target);
fputs(" = ",e->out); fputs(temp,e->out); fputs(".v;\n",e->out);
}
fputs("}\n",e->out);
}
static void emit_stmt(FeEmitter *e, FeNode *n)
{
if (!n) return;
@@ -776,46 +1072,91 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
case FE_N_LET:
case FE_N_VAR:
if (n->b) {
pad(e);
fputs(cname(n, "fe_local"), e->out);
fputs(" = ", e->out);
emit_expr(e, n->b);
fputs(";\n", e->out);
if (try_has_value(n->b)) emit_try_statement(e,n->b,n);
else {
pad(e);
fputs(cname(n, "fe_local"), e->out);
fputs(" = ", e->out);
emit_expr(e, n->b);
fputs(";\n", e->out);
}
emit_owned_live(e,n,1);
}
break;
case FE_N_ASSIGN:
if (n->a && n->a->kind==FE_N_IDENT && n->a->sem_type &&
n->a->sem_type->kind==FE_TYPE_OWNED) {
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
fputs(") { ",e->out);
if (n->a->sem_type->elem && type_needs_drop(n->a->sem_type->elem) &&
n->a->sem_type->elem->drop_cname)
fprintf(e->out,"%s(%s); ",n->a->sem_type->elem->drop_cname,cname(n->a,"owned"));
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out);
fputs("); fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
fputs("=0; }\n",e->out);
}
pad(e);
emit_lvalue(e, n->a);
fputc(' ', e->out);
fputs(n->text ? n->text : "=", e->out);
fputs(" ", e->out);
emit_expr(e, n->b);
if (n->b && (n->b->flags & 0x100U) && n->b->kind==FE_N_IDENT &&
n->b->sem_type && n->b->sem_type->kind==FE_TYPE_OWNED) {
fputs("(fe_live_",e->out); fputs(cname(n->b,"owned"),e->out);
fputs("=0, ",e->out); emit_expr(e,n->b); fputc(')',e->out);
} else emit_expr(e, n->b);
fputs(";\n", e->out);
if (n->a && n->a->kind==FE_N_IDENT) emit_owned_live(e,n->a,1);
break;
case FE_N_EXPR_STMT:
pad(e);
if (n->a && n->a->kind==FE_N_UNARY && n->a->text &&
strcmp(n->a->text,"try")==0 && n->a->a) {
fputs("if ((fe_m4_error = ",e->out);
emit_expr(e,n->a->a);
fputs(") != 0) return fe_m4_error;\n",e->out);
if (try_has_value(n->a)) {
emit_try_statement(e,n->a,0);
} else {
emit_expr(e, n->a);
fputs(";\n", e->out);
pad(e);
if (n->a && n->a->kind==FE_N_UNARY && n->a->text &&
strcmp(n->a->text,"try")==0 && n->a->a) {
fputs("if ((fe_m4_error = ",e->out);
emit_expr(e,n->a->a);
fputs(") != 0) {\n",e->out);
++e->indent;
emit_cleanup_all(e);
pad(e); fputs("return fe_m4_error;\n",e->out);
--e->indent;
pad(e); fputs("}\n",e->out);
} else {
emit_expr(e, n->a);
fputs(";\n", e->out);
}
}
break;
case FE_N_BREAK:
case FE_N_CONTINUE:
if (e->loop_depth) {
emit_cleanup_to(e,e->loop_floor[e->loop_depth-1]);
pad(e); fputs(n->kind==FE_N_BREAK ? "break;\n" : "continue;\n",e->out);
}
break;
case FE_N_RETURN:
pad(e);
if (n->a && n->a->kind == FE_N_MATCH) {
emit_match(e,n->a,1);
break;
}
fputs("return", e->out);
if (n->a) {
fputc(' ', e->out);
emit_expr(e, n->a);
/* Evaluate before cleanup: `return p.^` must not dereference p after
its owned cleanup has run. The block-local temporary is declared
before all statements to retain C89 declaration ordering. */
if (n->a && e->current_ret && e->current_ret->kind!=FE_TYPE_VOID) {
pad(e); fputs("fe_return_value = ",e->out);
if ((n->a->flags & 0x100U) && n->a->kind==FE_N_IDENT &&
n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED) {
fputs("(fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
fputs("=0, ",e->out); emit_expr(e,n->a); fputc(')',e->out);
} else emit_expr(e,n->a);
fputs(";\n",e->out);
}
fputs(";\n", e->out);
emit_cleanup_all(e);
pad(e); fputs("return",e->out);
if (n->a) fputs(" fe_return_value",e->out);
fputs(";\n",e->out);
break;
case FE_N_IF:
pad(e);
@@ -836,12 +1177,15 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
fputs("while (", e->out);
emit_expr(e, n->a);
fputs(") ", e->out);
if (e->loop_depth<16U) e->loop_floor[e->loop_depth++]=e->block_depth;
if (n->b && n->b->kind == FE_N_BLOCK) emit_block(e, n->b);
else emit_block(e, 0);
if (e->loop_depth) --e->loop_depth;
fputc('\n', e->out);
break;
case FE_N_FOR:
pad(e); fputs("{\n",e->out); ++e->indent;
if (e->loop_depth<16U) e->loop_floor[e->loop_depth++]=e->block_depth;
if (n->c) {
pad(e); fputs("unsigned long ",e->out); fputs(cname(n,"fe_index"),e->out); fputs(";\n",e->out);
pad(e); fputs(cname(n,"fe_index"),e->out); fputs(" = ",e->out); emit_expr(e,n->a); fputs(";\n",e->out);
@@ -869,7 +1213,9 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
fputc('&',e->out); if(mutable_iter) fputs("(*",e->out); fputs(temp,e->out); if(mutable_iter) fputs(")",e->out); if(bt && bt->kind==FE_TYPE_ARRAY) fputs(".a[fe_i]",e->out); else fputs(".p[fe_i]",e->out); fputs("; ",e->out);
emit_block(e,n->b); fputs(" } }\n",e->out);
}
--e->indent; pad(e); fputs("}\n",e->out); break;
--e->indent;
if (e->loop_depth) --e->loop_depth;
pad(e); fputs("}\n",e->out); break;
case FE_N_MATCH:
emit_match(e,n,0); break;
default:
@@ -899,12 +1245,15 @@ static void emit_fn(FeEmitter *e, FeNode *fn, int prototype)
fputc(')', e->out);
if (prototype) fputs(";\n", e->out);
else {
FeType *old_ret=e->current_ret;
e->current_ret=fn->sem_type;
fputs(" ", e->out);
if (fn->sem_type && fn->sem_type->kind==FE_TYPE_ERROR_UNION &&
fn->sem_type->error_value &&
fn->sem_type->error_value->kind==FE_TYPE_VOID)
e->fallthrough_block=fn->c;
emit_block(e, fn->c);
e->current_ret=old_ret;
fputc('\n', e->out);
}
}
@@ -933,6 +1282,9 @@ void fe_emit_c_init(FeEmitter *e, FILE *out, FeCheck *check,
e->no_checks = no_checks;
e->temp_serial = 0;
e->fallthrough_block = 0;
e->block_depth = 0;
e->loop_depth = 0;
e->current_ret = 0;
}
void fe_emit_c_program(FeEmitter *e)
+6
View File
@@ -11,6 +11,12 @@ typedef struct FeEmitter {
int no_checks;
unsigned temp_serial;
FeNode *fallthrough_block;
FeNode *block_stack[32];
unsigned block_seen[32];
unsigned block_depth;
unsigned loop_floor[16];
unsigned loop_depth;
FeType *current_ret;
} FeEmitter;
void fe_emit_c_init(FeEmitter *e, FILE *out, FeCheck *check,
+53 -2
View File
@@ -19,10 +19,13 @@ static FeType *new_type(FeTypeCtx *ctx, const char *name, FeTypeKind kind)
t->slicer = 0;
t->full_slicer = 0;
t->tail_slicer = 0;
t->drop_cname = 0;
t->alloc_cname = 0;
t->bits = 0;
t->is_unsigned = 0;
t->packed = 0;
t->is_error = 0;
t->has_drop = 0;
t->length = 0;
t->size = 0;
t->align = 1;
@@ -125,6 +128,7 @@ FeType *fe_type_array(FeTypeCtx *ctx, unsigned long length, FeType *elem)
t->elem = elem;
t->cname = generated_name(ctx, "struct fe_arr_", "type");
t->maker = generated_name(ctx, "fe_make_arr_", "type");
t->drop_cname = generated_name(ctx, "fe_drop_arr_", "type");
t->indexer = generated_name(ctx, "fe_idx_arr_", "type");
t->slicer = generated_name(ctx, "fe_slice_arr_", "type");
t->full_slicer = generated_name(ctx, "fe_full_arr_", "type");
@@ -166,6 +170,19 @@ FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable)
return t;
}
FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem)
{
char key[128];
FeType *t;
sprintf(key,"^%s",elem ? elem->name : "?");
t=fe_type_intern(ctx,key);
if(t->kind==FE_TYPE_UNKNOWN) {
t->kind=FE_TYPE_OWNED;
t->elem=elem;
}
return t;
}
FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value)
{
char key[128];
@@ -175,6 +192,11 @@ FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value)
if(t->kind==FE_TYPE_UNKNOWN) {
t->kind=FE_TYPE_ERROR_UNION;
t->error_value=value;
if (value && value->kind != FE_TYPE_VOID) {
t->cname=generated_name(ctx,"struct fe_result_","value");
t->maker=generated_name(ctx,"fe_make_result_","value");
t->alloc_cname=generated_name(ctx,"fe_alloc_result_","value");
}
}
return t;
}
@@ -192,6 +214,9 @@ FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
if (t->kind == FE_TYPE_STRUCT) return t;
t->kind = FE_TYPE_STRUCT;
t->packed = packed;
for (f = node->children; f; f = f->next)
if (f->kind==FE_N_FN && f->text && strcmp(f->text,"drop")==0)
t->has_drop=1;
cname = (char *)fe_arena_alloc(ctx->arena,
(unsigned long)strlen("struct fe_") + strlen(ctx->unit_name) +
strlen(node->text) + 2UL);
@@ -202,6 +227,7 @@ FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
strcat(cname, node->text);
t->cname = cname;
t->maker = generated_name(ctx, "fe_make_", node->text);
t->drop_cname = generated_name(ctx, "fe_drop_", node->text);
for (f = node->children; f; f = f->next)
if (f->kind == FE_N_FIELD) ++count;
t->field_count = count;
@@ -337,7 +363,15 @@ static void layout_type(FeTypeCtx *ctx, FeType *t)
if (t->kind == FE_TYPE_VOID || t->kind == FE_TYPE_UNKNOWN ||
t->kind == FE_TYPE_ERROR) { t->size = 0; t->align = 1; t->cycle_state = 2; return; }
if (t->kind == FE_TYPE_ERROR_UNION) {
t->size = 2; t->align = ctx->pointer_bits == 16 ? 1U : 2U;
if (t->error_value && t->error_value->kind != FE_TYPE_VOID) {
layout_type(ctx,t->error_value);
t->align=ctx->pointer_bits==16 ? 1U : fe_type_align(t->error_value);
t->size=round_up(2UL,t->align)+fe_type_size(t->error_value);
t->size=round_up(t->size,t->align);
} else {
t->size=2;
t->align=ctx->pointer_bits==16 ? 1U : 2U;
}
t->cycle_state = 2; return;
}
if (t->kind == FE_TYPE_BOOL || t->kind == FE_TYPE_CHAR) {
@@ -354,6 +388,11 @@ static void layout_type(FeTypeCtx *ctx, FeType *t)
t->align = ctx->pointer_bits == 16 ? 1U : 4U;
t->cycle_state = 2; return;
}
if (t->kind == FE_TYPE_OWNED) {
t->size = ctx->pointer_bits == 16 ? 2UL : 4UL;
t->align = ctx->pointer_bits == 16 ? 1U : 4U;
t->cycle_state = 2; return;
}
if (t->kind == FE_TYPE_SLICE || t->kind == FE_TYPE_STR) {
t->size = ctx->pointer_bits == 16 ? 4UL : 8UL;
t->align = ctx->pointer_bits == 16 ? 1U : 4U;
@@ -449,6 +488,8 @@ FeType *fe_type_from_ast(FeTypeCtx *ctx, const FeNode *node)
strcmp(node->text, "&mut") == 0))
return fe_type_ref(ctx, fe_type_from_ast(ctx,node->a),
strcmp(node->text,"&mut") == 0);
if (node->text && strcmp(node->text,"^")==0)
return fe_type_owned(ctx,fe_type_from_ast(ctx,node->a));
if (node->text && strcmp(node->text, "[") == 0) {
if (node->a) {
if (node->a->kind == FE_N_LITERAL && node->a->text)
@@ -495,7 +536,11 @@ const char *fe_type_c_name(const FeType *t, unsigned pointer_bits)
if (!t) return "long";
if (t->cname) return t->cname;
if (t->kind == FE_TYPE_VOID) return "void";
if (t->kind == FE_TYPE_ERROR_UNION) return "unsigned short";
if (t->kind == FE_TYPE_ERROR_UNION) {
if (t->error_value && t->error_value->kind != FE_TYPE_VOID && t->cname)
return t->cname;
return "unsigned short";
}
if (t->kind == FE_TYPE_BOOL || t->kind == FE_TYPE_CHAR) return "unsigned char";
if (t->kind == FE_TYPE_REF) {
static char ref_name[128];
@@ -509,6 +554,12 @@ const char *fe_type_c_name(const FeType *t, unsigned pointer_bits)
}
return ref_name;
}
if (t->kind == FE_TYPE_OWNED) {
static char owned_name[128];
strcpy(owned_name,fe_type_c_name(t->elem,pointer_bits));
strcat(owned_name," *");
return owned_name;
}
if (t->kind != FE_TYPE_INT) return "long";
if (strcmp(t->name, "usize") == 0) return pointer_bits == 16 ? "unsigned short" : "unsigned long";
if (strcmp(t->name, "isize") == 0) return pointer_bits == 16 ? "short" : "long";
+5 -1
View File
@@ -6,7 +6,7 @@
typedef enum FeTypeKind {
FE_TYPE_ERROR, FE_TYPE_ERROR_UNION, FE_TYPE_VOID, FE_TYPE_BOOL, FE_TYPE_CHAR, FE_TYPE_INT,
FE_TYPE_STRUCT, FE_TYPE_ENUM, FE_TYPE_ARRAY, FE_TYPE_SLICE, FE_TYPE_STR,
FE_TYPE_REF, FE_TYPE_UNKNOWN
FE_TYPE_REF, FE_TYPE_OWNED, FE_TYPE_UNKNOWN
} FeTypeKind;
typedef struct FeFieldType FeFieldType;
@@ -37,10 +37,13 @@ struct FeType {
char *slicer;
char *full_slicer;
char *tail_slicer;
char *drop_cname;
char *alloc_cname;
unsigned bits;
int is_unsigned;
int packed;
int is_error;
int has_drop;
unsigned long length;
unsigned long size;
unsigned align;
@@ -71,6 +74,7 @@ FeType *fe_type_from_ast(FeTypeCtx *ctx, const FeNode *node);
FeType *fe_type_array(FeTypeCtx *ctx, unsigned long length, FeType *elem);
FeType *fe_type_slice(FeTypeCtx *ctx, FeType *elem);
FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable);
FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem);
FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value);
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed);
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node);
+19
View File
@@ -227,6 +227,25 @@ fec.exe --target=bits32 --emit-c TESTS\M4\BAD-OPEN.FE -o TESTS\M4\BAD-OPEN.C > n
if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M4\BAD-CLS.FE -o TESTS\M4\BAD-CLS.C > nul
if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\DEFER.FE -o TESTS\M5\DEFER.C > nul
if errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\OWNED.FE -o TESTS\M5\OWNED.C > nul
if errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-MOVE.FE -o TESTS\M5\BAD-MOVE.C > nul
if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-DES.FE -o TESTS\M5\BAD-DES.C > nul
if not errorlevel 1 goto test_fail
if exist TESTS\M5\RUNTIME-G.C del TESTS\M5\RUNTIME-G.C
if exist TESTS\M5\RUNTIME.O del TESTS\M5\RUNTIME.O
if exist TESTS\M5\RUNTIME.EXE del TESTS\M5\RUNTIME.EXE
fec.exe --target=bits32 --emit-c TESTS\M5\RUNTIME.FE -o TESTS\M5\RUNTIME-G.C > nul
if errorlevel 1 goto test_fail
rem Compile generated source and the C89 runtime harness in one WCL386 invocation
rem so both objects use the same DOS/4GW startup and runtime library.
wcl386 -q -za -bt=dos -fe=TESTS\M5\RUNTIME.EXE TESTS\M5\RUNTIME-G.C TESTS\M5\RUNTIME.C
if errorlevel 1 goto test_fail
TESTS\M5\RUNTIME.EXE
if errorlevel 1 goto test_fail
echo OK>TEST.OK
cd C:\FEC
+5
View File
@@ -0,0 +1,5 @@
unit m5_bad_destroy;
fn bad(x: i32) -> void {
mem.destroy(x);
}
+8
View File
@@ -0,0 +1,8 @@
unit m5_bad_move;
fn take(p: ^i32) -> void { mem.destroy(p); }
fn twice(p: ^i32) -> void {
take(p);
take(p);
}
+5
View File
@@ -0,0 +1,5 @@
unit m5_defer;
pub fn cleanup(p: ^i32) -> void {
defer { mem.destroy(p); }
}
+9
View File
@@ -0,0 +1,9 @@
unit m5_owned;
fn main() -> void {
var p: ^i32 = try mem.create(i32);
p = try mem.create(i32);
p.^ = 7;
let value: i32 = p.^;
defer { mem.destroy(p); }
}
+9
View File
@@ -0,0 +1,9 @@
extern long fe_m5_runtime_run(long mode);
int main(void)
{
if (fe_m5_runtime_run(0) != 0) return 1;
if (fe_m5_runtime_run(1) != 9) return 2;
if (fe_m5_runtime_run(2) != 0) return 3;
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
unit m5_runtime;
pub fn run(mode: i32) -> i32 {
var p: ^i32 = try mem.create(i32);
defer { mem.destroy(p); }
p.^ = 7;
if mode == 1 {
p = try mem.create(i32);
p.^ = 9;
return p.^;
}
while true {
break;
}
if mode == 2 {
return 0;
}
return p.^ - 7;
}
+11
View File
@@ -91,3 +91,14 @@ for f in bad-many bad-open bad-cls; do
fi
done
echo "M4 tests: formatting builtins passed"
for f in defer owned; do
"$root"/fec --target=bits32 --emit-c "$root"/tests/m5/$f.fe -o "$m4tmp/m5-$f.c"
done
for f in bad-move bad-destroy; do
if "$root"/fec --target=bits32 --emit-c "$root"/tests/m5/$f.fe -o "$m4tmp/m5-$f.c" >/dev/null 2>/dev/null; then
echo "FAIL (accepted M5 ownership error): $f.fe"
exit 1
fi
done
echo "M5 tests: owned move/defer checks passed"
+13
View File
@@ -9,6 +9,7 @@ if not exist C:\FEC\TESTS\FAIL md C:\FEC\TESTS\FAIL
if not exist C:\FEC\TESTS\M2 md C:\FEC\TESTS\M2
if not exist C:\FEC\TESTS\M3 md C:\FEC\TESTS\M3
if not exist C:\FEC\TESTS\M4 md C:\FEC\TESTS\M4
if not exist C:\FEC\TESTS\M5 md C:\FEC\TESTS\M5
if exist C:\FEC\VM.FAIL del C:\FEC\VM.FAIL
if exist C:\FEC\STAGE.FAIL del C:\FEC\STAGE.FAIL
@@ -169,6 +170,18 @@ copy D:\FEC\TESTS\M4\BAD-OPEN.FE C:\FEC\TESTS\M4\BAD-OPEN.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M4\BAD-CLS.FE C:\FEC\TESTS\M4\BAD-CLS.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\DEFER.FE C:\FEC\TESTS\M5\DEFER.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\OWNED.FE C:\FEC\TESTS\M5\OWNED.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\BAD-MOVE.FE C:\FEC\TESTS\M5\BAD-MOVE.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\BAD-DES~1.FE C:\FEC\TESTS\M5\BAD-DES.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\RUNTIME.FE C:\FEC\TESTS\M5\RUNTIME.FE > nul
if errorlevel 1 goto stage_fail
copy D:\FEC\TESTS\M5\RUNTIME.C C:\FEC\TESTS\M5\RUNTIME.C > nul
if errorlevel 1 goto stage_fail
call C:\FEC\TEST-DOS.BAT
if exist C:\FEC\TEST.OK goto vm_success