feat: complete M5 ownership and cleanup

This commit is contained in:
2026-08-16 18:48:35 +09:00
parent 351e5dbb23
commit deafd27939
13 changed files with 545 additions and 81 deletions
+3 -7
View File
@@ -63,12 +63,8 @@ VM 안에서 반복해서 물렸던 것들. 어기면 원인 찾기 어려운
## 현재 상태 ## 현재 상태
- M1~M4 완료 및 QEMU/Open Watcom 검증됨. - M1~M5 완료 및 QEMU/Open Watcom 검증됨.
- M5(`^T`, drop, defer, 이동 검사) 진행 중. 남은 것: 모든 경로에서 정확히 1회 - 다음은 M6(R1~R8 대여 검사)다. 착수할 때 소유권 로직을 `check.c`/`emit_c.c`에서
cleanup, defer와 drop의 선언 역순 병합, `try` 전파 경로 cleanup, `MaybeMoved` `own.c/h`로 분리한다 (`SPEC.md` §11.3).
런타임 live flag, struct drop과 필드 역순 drop, 분기/루프 상태 합류,
누수·이중해제 카운터 harness.
- `own.c/h`가 아직 없고 소유권 로직이 `check.c`/`emit_c.c`에 들어가 있다. R1~R8
전체를 다루는 **M6 착수 시점에 분리한다** (`SPEC.md` §11.3).
- v0.1.6에서 R8(파생 반환), R6(마지막 사용까지 대여), R10(전역 대여 금지)이 - v0.1.6에서 R8(파생 반환), R6(마지막 사용까지 대여), R10(전역 대여 금지)이
바뀌었다. 셋 다 own.c의 상태 기계를 건드리므로 분리 이후에 함께 구현한다. 바뀌었다. 셋 다 own.c의 상태 기계를 건드리므로 분리 이후에 함께 구현한다.
+189 -16
View File
@@ -72,7 +72,15 @@ static int is_copy_type(FeType *t)
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t) static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
{ {
FeSym *sym; FeSym *sym;
if (!n || !t || is_copy_type(t) || n->kind!=FE_N_IDENT) return; if (!n || !t || is_copy_type(t)) return;
if(n->kind==FE_N_INDEX && t->kind==FE_TYPE_SLICE &&
(n->c || !n->b)) return;
if(n->kind==FE_N_MEMBER || n->kind==FE_N_INDEX) {
err(s->c,n->loc,
"cannot move a non-Copy value out of a projection; use mem.replace");
return;
}
if(n->kind!=FE_N_IDENT) return;
sym=find_symbol(s->scope,n->text ? n->text : ""); sym=find_symbol(s->scope,n->text ? n->text : "");
if (sym) { if (sym) {
if (s->defer_depth) { if (s->defer_depth) {
@@ -258,6 +266,31 @@ void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags,
} }
static FeType *check_expr(FeCheckerState *s, FeNode *n); static FeType *check_expr(FeCheckerState *s, FeNode *n);
static FeNode *find_method(FeCheck *c, FeType *owner, const char *name)
{
FeNode *decl;
FeNode *method;
if(!owner || !name) return 0;
for(decl=c->ast->root ? c->ast->root->children : 0; decl; decl=decl->next)
if(decl->kind==FE_N_STRUCT && decl->text &&
strcmp(decl->text,owner->name)==0)
for(method=decl->children; method; method=method->next)
if(method->kind==FE_N_FN && method->text &&
strcmp(method->text,name)==0) return method;
return 0;
}
static FeType *method_type(FeCheck *c, FeNode *node, FeType *owner)
{
if(node && node->kind==FE_N_TYPE && node->text &&
strcmp(node->text,"Self")==0) return owner;
if(node && node->kind==FE_N_TYPE && node->text &&
(strcmp(node->text,"&")==0 || strcmp(node->text,"&mut")==0) &&
node->a && node->a->text && strcmp(node->a->text,"Self")==0)
return fe_type_ref(&c->types,owner,strcmp(node->text,"&mut")==0);
return node_type(c,node);
}
static void check_match(FeCheckerState *s, FeNode *n); static void check_match(FeCheckerState *s, FeNode *n);
static void check_stmt(FeCheckerState *s, FeNode *n); static void check_stmt(FeCheckerState *s, FeNode *n);
@@ -666,14 +699,44 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
return n->sem_type; return n->sem_type;
} }
if (strcmp(n->a->b->text,"create")==0) { if (strcmp(n->a->b->text,"create")==0) {
if (!arg || arg->next || arg->kind!=FE_N_IDENT) if (!arg || arg->next)
err(c,n->loc,"mem.create requires exactly one type argument"); err(c,n->loc,"mem.create requires exactly one value");
a=arg && arg->kind==FE_N_IDENT ? a=arg ? check_expr(s,arg) : unknown(c);
fe_type_owned(&c->types,fe_type_intern(&c->types,arg->text)) : if(arg) mark_moved(s,arg,a);
fe_type_owned(&c->types,unknown(c)); a=fe_type_owned(&c->types,a);
n->sem_type=fe_type_error_union(&c->types,a); n->sem_type=fe_type_error_union(&c->types,a);
return n->sem_type; return n->sem_type;
} }
if (strcmp(n->a->b->text,"alloc_slice")==0) {
FeNode *count=arg ? arg->next : 0;
FeType *item;
if(!arg || arg->kind!=FE_N_IDENT || !count || count->next)
err(c,n->loc,"mem.alloc_slice requires a type and length");
item=arg && arg->kind==FE_N_IDENT ?
fe_type_intern(&c->types,arg->text) : unknown(c);
b=count ? check_expr(s,count) : unknown(c);
if(known(b) && !fe_type_is_integer(b))
err(c,count->loc,"slice length must be an integer");
a=fe_type_owned(&c->types,fe_type_slice(&c->types,item));
n->sem_type=fe_type_error_union(&c->types,a);
return n->sem_type;
}
if (strcmp(n->a->b->text,"replace")==0) {
FeNode *value=arg ? arg->next : 0;
if(!arg || !value || value->next)
err(c,n->loc,"mem.replace requires destination and value");
a=arg ? check_expr(s,arg) : unknown(c);
if(!a || a->kind!=FE_TYPE_REF || !a->ref_mut ||
!arg->a || !lvalue_writable(s,arg->a))
err(c,n->loc,"mem.replace destination must be a mutable place");
b=value ? check_expr(s,value) : unknown(c);
if(a && a->kind==FE_TYPE_REF && !compatible(a->elem,b,value))
err(c,value->loc,"mem.replace value type mismatch");
if(value) mark_moved(s,value,b);
n->sem_type=a && a->kind==FE_TYPE_REF ? a->elem : unknown(c);
fe_type_require_replace(&c->types,n->sem_type);
return n->sem_type;
}
} }
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a && if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text && n->a->a->kind==FE_N_IDENT && n->a->a->text &&
@@ -701,7 +764,39 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type; n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type;
} }
if (n->a && n->a->kind == FE_N_MEMBER) { if (n->a && n->a->kind == FE_N_MEMBER) {
FeNode *method;
FeNode *self_param;
et=check_expr(s,n->a->a); et=check_expr(s,n->a->a);
method=et && et->kind==FE_TYPE_STRUCT ?
find_method(c,et,n->a->b ? n->a->b->text : "") : 0;
if(method) {
self_param=method->a ? method->a->children : 0;
if(!self_param) {
err(c,n->loc,"method requires self parameter");
return unknown(c);
}
a=method_type(c,self_param->a,et);
if(a->kind==FE_TYPE_REF && a->ref_mut &&
!lvalue_writable(s,n->a->a))
err(c,n->loc,"mutable method requires a mutable receiver");
if(a->kind!=FE_TYPE_REF) mark_moved(s,n->a->a,et);
param=self_param->next;
arg=n->children;
while(param && arg) {
a=check_expr(s,arg);
b=method_type(c,param->a,et);
if(!compatible(b,a,arg) && a->kind!=FE_TYPE_UNKNOWN)
err(c,arg->loc,"method argument type mismatch");
mark_moved(s,arg,a);
param=param->next;
arg=arg->next;
}
if(param || arg) err(c,n->loc,"wrong number of method arguments");
n->sem_decl=method;
n->sem_type=method->b ? method_type(c,method->b,et) :
fe_type_intern(&c->types,"void");
return n->sem_type;
}
variant=et && et->kind==FE_TYPE_ENUM ? variant=et && et->kind==FE_TYPE_ENUM ?
fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0; fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0;
arg=n->children; arg=n->children;
@@ -761,6 +856,13 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
n->sem_type=a->elem; n->sem_type=a->elem;
return a->elem; return a->elem;
} }
if(a->kind==FE_TYPE_REF && a->elem &&
a->elem->kind==FE_TYPE_STRUCT) {
field=fe_type_field(a->elem,n->b ? n->b->text : "");
if(!field) { err(c,n->loc,"unknown struct field"); return unknown(c); }
n->sem_type=field->type;
return field->type;
}
if (a->kind == FE_TYPE_OWNED && n->b && n->b->text && if (a->kind == FE_TYPE_OWNED && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) { strcmp(n->b->text,"^")==0) {
n->sem_type=a->elem; n->sem_type=a->elem;
@@ -816,6 +918,15 @@ static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
n->sem_type=base->elem; n->sem_type=base->elem;
return base->elem; return base->elem;
} }
if(base && base->kind==FE_TYPE_REF && base->elem &&
base->elem->kind==FE_TYPE_STRUCT) {
if(!base->ref_mut)
err(s->c,n->loc,"cannot write through shared reference");
field=fe_type_field(base->elem,n->b ? n->b->text : "");
if(!field) { err(s->c,n->loc,"assignment requires a valid struct field"); return unknown(s->c); }
n->sem_type=field->type;
return field->type;
}
if (base && base->kind == FE_TYPE_OWNED && n->b && n->b->text && if (base && base->kind == FE_TYPE_OWNED && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) { strcmp(n->b->text,"^")==0) {
n->sem_type=base->elem; n->sem_type=base->elem;
@@ -855,12 +966,17 @@ static void check_match(FeCheckerState *s, FeNode *n)
FeVariantType *variant; FeVariantType *variant;
int seen[256]; int seen[256];
int wildcard=0; int wildcard=0;
FeFlowSlot base[64], merged[64], current[64];
unsigned flow_count;
int have_merged=0;
unsigned i; unsigned i;
for(i=0;i<256U;i++) seen[i]=0; for(i=0;i<256U;i++) seen[i]=0;
value=check_expr(s,n->a); value=check_expr(s,n->a);
if(!value || value->kind!=FE_TYPE_ENUM) { err(s->c,n->loc,"match requires an enum value"); return; } if(!value || value->kind!=FE_TYPE_ENUM) { err(s->c,n->loc,"match requires an enum value"); return; }
flow_count=flow_capture(s->scope,base,64);
for(arm=n->children;arm;arm=arm->next) { for(arm=n->children;arm;arm=arm->next) {
FeScope *old=s->scope; FeScope *old=s->scope;
flow_restore(base,flow_count);
if(arm->text && strcmp(arm->text,"_")==0) wildcard=1; if(arm->text && strcmp(arm->text,"_")==0) wildcard=1;
else { else {
variant=fe_type_variant(value,arm->text); variant=fe_type_variant(value,arm->text);
@@ -885,7 +1001,19 @@ static void check_match(FeCheckerState *s, FeNode *n)
if(arm->a && arm->a->kind==FE_N_BLOCK) check_stmt(s,arm->a); if(arm->a && arm->a->kind==FE_N_BLOCK) check_stmt(s,arm->a);
else if(arm->a) check_expr(s,arm->a); else if(arm->a) check_expr(s,arm->a);
s->scope=old; s->scope=old;
flow_capture(s->scope,current,flow_count);
if(!have_merged) {
for(i=0;i<flow_count;++i) merged[i]=current[i];
have_merged=1;
} else {
for(i=0;i<flow_count;++i) {
merged[i].moved=merged[i].moved==1 && current[i].moved==1 ? 1 :
(merged[i].moved || current[i].moved ? 2 : 0);
merged[i].initialized=merged[i].initialized && current[i].initialized;
} }
}
}
if(have_merged) flow_restore(merged,flow_count);
if(!wildcard) for(i=0;i<value->variant_count && i<256U;i++) if(!seen[i]) err(s->c,n->loc,"non-exhaustive match"); if(!wildcard) for(i=0;i<value->variant_count && i<256U;i++) if(!seen[i]) err(s->c,n->loc,"non-exhaustive match");
} }
@@ -1073,12 +1201,12 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
--s->defer_depth; --s->defer_depth;
break; break;
case FE_N_IF: { case FE_N_IF: {
FeFlowSlot base[128], left[128], right[128]; FeFlowSlot base[64], left[64], right[64];
unsigned flow_count; unsigned flow_count;
a = check_expr(s, n->a); a = check_expr(s, n->a);
if (known(a) && a->kind != FE_TYPE_BOOL) if (known(a) && a->kind != FE_TYPE_BOOL)
err(c, n->loc, "if condition must be bool"); err(c, n->loc, "if condition must be bool");
flow_count=flow_capture(s->scope,base,128); flow_count=flow_capture(s->scope,base,64);
check_stmt(s, n->b); check_stmt(s, n->b);
flow_capture(s->scope,left,flow_count); flow_capture(s->scope,left,flow_count);
flow_restore(base,flow_count); flow_restore(base,flow_count);
@@ -1092,25 +1220,32 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
break; break;
} }
case FE_N_WHILE: { case FE_N_WHILE: {
FeFlowSlot base[128], body[128]; FeFlowSlot base[64], body[64], entry2[64];
unsigned flow_count; unsigned flow_count;
unsigned i;
a = check_expr(s, n->a); a = check_expr(s, n->a);
if (known(a) && a->kind != FE_TYPE_BOOL) if (known(a) && a->kind != FE_TYPE_BOOL)
err(c, n->loc, "while condition must be bool"); err(c, n->loc, "while condition must be bool");
flow_count=flow_capture(s->scope,base,128); flow_count=flow_capture(s->scope,base,64);
if (s->loop_depth < 255U) ++s->loop_depth; if (s->loop_depth < 255U) ++s->loop_depth;
check_stmt(s, n->b); check_stmt(s, n->b);
if (s->loop_depth) --s->loop_depth; if (s->loop_depth) --s->loop_depth;
flow_capture(s->scope,body,flow_count); flow_capture(s->scope,body,flow_count);
flow_restore(base,flow_count);
{
unsigned i;
for (i=0;i<flow_count;++i) { for (i=0;i<flow_count;++i) {
if (body[i].moved) base[i].moved=2; entry2[i]=base[i];
if (!body[i].initialized) base[i].initialized=0; if(body[i].moved!=base[i].moved) entry2[i].moved=2;
if(!body[i].initialized) entry2[i].initialized=0;
} }
flow_restore(entry2,flow_count);
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);
for(i=0;i<flow_count;++i) {
if(body[i].moved) entry2[i].moved=2;
if(!body[i].initialized) entry2[i].initialized=0;
} }
flow_restore(base,flow_count); flow_restore(entry2,flow_count);
break; break;
} }
case FE_N_FOR: case FE_N_FOR:
@@ -1168,6 +1303,28 @@ static void check_fn(FeCheck *c, FeNode *fn, FeScope *globals)
s.scope = old; s.scope = old;
} }
static void check_method(FeCheck *c, FeNode *fn, FeScope *globals,
FeType *owner)
{
FeCheckerState s;
FeNode *x;
FeType *t;
s.c=c;
s.globals=globals;
s.scope=scope_new(&s,globals);
s.ret=fn->b ? method_type(c,fn->b,owner) : 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=method_type(c,x->a,owner);
x->sem_type=t;
add_symbol(&s,s.scope,x->text,t,0,1,1,
local_cname(c,x->text ? x->text : "arg"),x);
}
if(fn->c) check_stmt(&s,fn->c);
}
int fe_check_program(FeCheck *c) int fe_check_program(FeCheck *c)
{ {
FeCheckerState s; FeCheckerState s;
@@ -1189,6 +1346,15 @@ int fe_check_program(FeCheck *c)
check_type_cycles(c); check_type_cycles(c);
fe_type_layout_all(&c->types); fe_type_layout_all(&c->types);
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) { for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) {
if(n->kind==FE_N_STRUCT) {
FeNode *m;
char method_name[128];
for(m=n->children; m; m=m->next) if(m->kind==FE_N_FN) {
sprintf(method_name,"%s_%s",n->text ? n->text : "Type",
m->text ? m->text : "method");
m->cname=unit_cname(c,method_name);
}
}
if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) { if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) {
t = n->a ? node_type(c, n->a) : unknown(c); t = n->a ? node_type(c, n->a) : unknown(c);
add_symbol(&s, s.globals, n->text, t, 0, add_symbol(&s, s.globals, n->text, t, 0,
@@ -1221,6 +1387,13 @@ int fe_check_program(FeCheck *c)
} }
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
if (n->kind == FE_N_FN) check_fn(c, n, s.globals); if (n->kind == FE_N_FN) check_fn(c, n, s.globals);
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
if(n->kind==FE_N_STRUCT) {
FeNode *m;
t=fe_type_intern(&c->types,n->text);
for(m=n->children; m; m=m->next)
if(m->kind==FE_N_FN) check_method(c,m,s.globals,t);
}
fe_type_layout_all(&c->types); fe_type_layout_all(&c->types);
return c->diags->errors == 0; return c->diags->errors == 0;
} }
+157 -32
View File
@@ -63,6 +63,8 @@ static void emit_one_type(FeEmitter *e, FeType *t)
if (!t || t->emit_state || if (!t || t->emit_state ||
(t->kind != FE_TYPE_STRUCT && t->kind != FE_TYPE_ENUM && (t->kind != FE_TYPE_STRUCT && t->kind != FE_TYPE_ENUM &&
t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE && t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE &&
!(t->kind == FE_TYPE_OWNED && t->elem &&
t->elem->kind == FE_TYPE_SLICE) &&
t->kind != FE_TYPE_ERROR_UNION) || t->kind != FE_TYPE_ERROR_UNION) ||
(t->kind == FE_TYPE_ERROR_UNION && (t->kind == FE_TYPE_ERROR_UNION &&
(!t->error_value || t->error_value->kind == FE_TYPE_VOID))) return; (!t->error_value || t->error_value->kind == FE_TYPE_VOID))) return;
@@ -79,6 +81,15 @@ static void emit_one_type(FeEmitter *e, FeType *t)
if(!t->ref_mut) fputs("const ",e->out); if(!t->ref_mut) fputs("const ",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); 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%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",t->cname,t->maker,t->ref_mut ? "" : "const ",fe_type_c_name(t->elem,e->pointer_bits),t->cname); fprintf(e->out,"static %s %s(%s%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",t->cname,t->maker,t->ref_mut ? "" : "const ",fe_type_c_name(t->elem,e->pointer_bits),t->cname);
} else if(t->kind==FE_TYPE_OWNED && t->elem &&
t->elem->kind==FE_TYPE_SLICE) {
FeType *item=t->elem->elem;
fputs("typedef struct { ",e->out);
fputs(fe_type_c_name(item,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(item,e->pointer_bits),t->cname);
} else if(t->kind==FE_TYPE_ERROR_UNION) { } else if(t->kind==FE_TYPE_ERROR_UNION) {
fputs(t->cname,e->out); fputs(" { unsigned short e; ",e->out); 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(fe_type_c_name(t->error_value,e->pointer_bits),e->out);
@@ -128,13 +139,21 @@ static void emit_drop_fields(FeEmitter *e, FeType *t)
if (!type_needs_drop(ft)) continue; if (!type_needs_drop(ft)) continue;
if (ft->kind==FE_TYPE_OWNED) { if (ft->kind==FE_TYPE_OWNED) {
fputs("if (self->",e->out); fputs(t->fields[i-1].name,e->out); fputs("if (self->",e->out); fputs(t->fields[i-1].name,e->out);
if(ft->elem && ft->elem->kind==FE_TYPE_SLICE) fputs(".p",e->out);
fputs(") { ",e->out); fputs(") { ",e->out);
if (ft->elem && type_needs_drop(ft->elem) && ft->elem->drop_cname) { if(ft->elem && ft->elem->kind==FE_TYPE_SLICE) {
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs(".p); self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs(".p=0; ",e->out);
} else 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); fprintf(e->out,"%s(self->%s); ",ft->elem->drop_cname,t->fields[i-1].name);
} }
if(!(ft->elem && ft->elem->kind==FE_TYPE_SLICE)) {
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out); 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("); self->",e->out); fputs(t->fields[i-1].name,e->out);
fputs("=0; }\n",e->out); fputs("=0; ",e->out);
}
fputs("}\n",e->out);
} else if (ft->kind==FE_TYPE_STRUCT && ft->drop_cname) { } 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); 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) { } else if (ft->kind==FE_TYPE_ARRAY && ft->drop_cname) {
@@ -147,7 +166,10 @@ static void emit_drop_helpers(FeEmitter *e)
{ {
FeType *t; FeType *t;
FeNode *method; FeNode *method;
FeNode *param; for (t=e->check->types.types; t; t=t->next)
if(t->kind==FE_TYPE_STRUCT && (method=find_drop_method(e,t->name))!=0)
fprintf(e->out,"void %s(%s *self);\n",
cname(method,"fe_drop_method"),t->cname);
for (t=e->check->types.types; t; t=t->next) for (t=e->check->types.types; t; t=t->next)
if ((t->kind==FE_TYPE_STRUCT || t->kind==FE_TYPE_ARRAY) && if ((t->kind==FE_TYPE_STRUCT || t->kind==FE_TYPE_ARRAY) &&
type_needs_drop(t) && t->drop_cname) type_needs_drop(t) && t->drop_cname)
@@ -157,10 +179,7 @@ static void emit_drop_helpers(FeEmitter *e)
fprintf(e->out,"static void %s(%s *self) {\n",t->drop_cname,t->cname); fprintf(e->out,"static void %s(%s *self) {\n",t->drop_cname,t->cname);
method=find_drop_method(e,t->name); method=find_drop_method(e,t->name);
if (method) { if (method) {
param=method->a ? method->a->children : 0; fprintf(e->out,"%s(self);\n",cname(method,"fe_drop_method"));
if (param) param->cname="self";
if (method->c) emit_block(e,method->c);
fputc('\n',e->out);
} }
emit_drop_fields(e,t); emit_drop_fields(e,t);
fputs("}\n",e->out); fputs("}\n",e->out);
@@ -189,14 +208,29 @@ static void emit_type_helpers(FeEmitter *e)
t->error_value->kind!=FE_TYPE_VOID) { 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", 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); t->cname,t->maker,fe_type_c_name(t->error_value,e->pointer_bits),t->cname);
if (t->error_value->kind==FE_TYPE_OWNED) 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->error_value->elem &&
t->error_value->elem->kind==FE_TYPE_SLICE) {
FeType *item=t->error_value->elem->elem;
fprintf(e->out,"static %s %s(unsigned long n) { %s r; r.v.p=(%s*)malloc(sizeof(%s)*n); r.v.n=n; r.e=(r.v.p || !n) ? 0 : 1; return r; }\n",
t->cname,t->alloc_cname,t->cname, t->cname,t->alloc_cname,t->cname,
fe_type_c_name(item,e->pointer_bits),
fe_type_c_name(item,e->pointer_bits));
} else if (t->error_value->kind==FE_TYPE_OWNED) {
fprintf(e->out,"static %s %s(%s v) { %s r; r.v=(%s)malloc(sizeof(%s)); if(r.v) *r.v=v; r.e=r.v ? 0 : 1; return r; }\n",
t->cname,t->alloc_cname,
fe_type_c_name(t->error_value->elem,e->pointer_bits),t->cname,
fe_type_c_name(t->error_value,e->pointer_bits), fe_type_c_name(t->error_value,e->pointer_bits),
fe_type_c_name(t->error_value->elem,e->pointer_bits)); fe_type_c_name(t->error_value->elem,e->pointer_bits));
} }
} }
}
for(t=e->check->types.types;t;t=t->next) { for(t=e->check->types.types;t;t=t->next) {
if(t->replace_cname) {
const char *ct=fe_type_c_name(t,e->pointer_bits);
fprintf(e->out,"static %s %s(%s *dst, %s value) { %s old=*dst; *dst=value; return old; }\n",
ct,t->replace_cname,ct,ct,ct);
}
if(t->kind==FE_TYPE_STRUCT && t->maker) { if(t->kind==FE_TYPE_STRUCT && t->maker) {
fprintf(e->out,"static %s %s(",t->cname,t->maker); fprintf(e->out,"static %s %s(",t->cname,t->maker);
for(i=0;i<t->field_count;i++) { if(i) fputs(", ",e->out); fputs(fe_type_c_name(t->fields[i].type,e->pointer_bits),e->out); fprintf(e->out," p%u",i); } for(i=0;i<t->field_count;i++) { if(i) fputs(", ",e->out); fputs(fe_type_c_name(t->fields[i].type,e->pointer_bits),e->out); fprintf(e->out," p%u",i); }
@@ -599,6 +633,10 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
} else if (n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED && } 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) { n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out); 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_REF) {
emit_expr(e,n->a); fputs("->",e->out);
fputs(n->b ? n->b->text : "member",e->out);
} else { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); } } else { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); }
return; return;
} }
@@ -612,10 +650,17 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
static void emit_destroy_expr(FeEmitter *e, FeNode *n) static void emit_destroy_expr(FeEmitter *e, FeNode *n)
{ {
fputs("(free(",e->out); emit_expr(e,n); fputs(")",e->out); fputs("(free(",e->out); emit_expr(e,n);
if(n && n->sem_type && n->sem_type->kind==FE_TYPE_OWNED &&
n->sem_type->elem && n->sem_type->elem->kind==FE_TYPE_SLICE)
fputs(".p",e->out);
fputs(")",e->out);
if (n && n->kind==FE_N_IDENT) { if (n && n->kind==FE_N_IDENT) {
fputs(", ",e->out); emit_lvalue(e,n); fputs(", ",e->out); emit_lvalue(e,n);
fputs("=0, fe_live_",e->out); fputs(cname(n,"owned"),e->out); if(n->sem_type && n->sem_type->elem &&
n->sem_type->elem->kind==FE_TYPE_SLICE) fputs(".p=0",e->out);
else fputs("=0",e->out);
fputs(", fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs("=0",e->out); fputs("=0",e->out);
} else { } else {
fputs(", ",e->out); emit_lvalue(e,n); fputs("=0",e->out); fputs(", ",e->out); emit_lvalue(e,n); fputs("=0",e->out);
@@ -698,7 +743,12 @@ static void emit_expr(FeEmitter *e, FeNode *n)
} }
switch (n->kind) { switch (n->kind) {
case FE_N_IDENT: case FE_N_IDENT:
fputs(cname(n, "fe_missing"), e->out); if((n->flags & 0x100U) && n->sem_type &&
type_needs_drop(n->sem_type)) {
fputs("(fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs("=0, ",e->out); fputs(cname(n,"fe_missing"),e->out);
fputc(')',e->out);
} else fputs(cname(n, "fe_missing"), e->out);
break; break;
case FE_N_LITERAL: case FE_N_LITERAL:
if (n->text && strcmp(n->text, "true") == 0) fputs("1", e->out); if (n->text && strcmp(n->text, "true") == 0) fputs("1", e->out);
@@ -760,7 +810,7 @@ static void emit_expr(FeEmitter *e, FeNode *n)
if (strcmp(op, "not") == 0) fputs("(!", e->out); if (strcmp(op, "not") == 0) fputs("(!", e->out);
else { else {
fputc('(', e->out); fputc('(', e->out);
fputs(op, e->out); fputs(strcmp(op,"&mut")==0 ? "&" : op, e->out);
} }
emit_expr(e, n->a); emit_expr(e, n->a);
fputc(')', e->out); fputc(')', e->out);
@@ -801,19 +851,55 @@ static void emit_expr(FeEmitter *e, FeNode *n)
n->a->a->kind==FE_N_IDENT && n->a->a->text && n->a->a->kind==FE_N_IDENT && n->a->a->text &&
strcmp(n->a->a->text,"mem")==0 && n->a->b && strcmp(n->a->a->text,"mem")==0 && n->a->b &&
n->a->b->text && strcmp(n->a->b->text,"create")==0 && n->a->b->text && strcmp(n->a->b->text,"create")==0 &&
n->children && n->children->kind==FE_N_IDENT) { n->children) {
FeType *created=fe_type_intern(&e->check->types,n->children->text); FeType *created=n->children->sem_type;
FeType *owned=fe_type_owned(&e->check->types,created); FeType *owned=fe_type_owned(&e->check->types,created);
FeType *result=fe_type_error_union(&e->check->types,owned); FeType *result=fe_type_error_union(&e->check->types,owned);
if (result->alloc_cname) fputs(result->alloc_cname,e->out); if (result->alloc_cname) fputs(result->alloc_cname,e->out);
else fputs("fe_bad_alloc",e->out); else fputs("fe_bad_alloc",e->out);
fputs("()",e->out); fputc('(',e->out); emit_expr(e,n->children); fputc(')',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,"mem")==0 && n->a->b &&
n->a->b->text && strcmp(n->a->b->text,"alloc_slice")==0 &&
n->children && n->children->next) {
FeType *result=n->sem_type;
if(result && result->alloc_cname) fputs(result->alloc_cname,e->out);
else fputs("fe_bad_slice_alloc",e->out);
fputc('(',e->out); emit_expr(e,n->children->next); fputc(')',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,"mem")==0 && n->a->b &&
n->a->b->text && strcmp(n->a->b->text,"replace")==0 &&
n->children && n->children->next && n->sem_type) {
fputs(n->sem_type->replace_cname ? n->sem_type->replace_cname :
"fe_bad_replace",e->out);
fputc('(',e->out); emit_expr(e,n->children); fputs(", ",e->out);
emit_expr(e,n->children->next); fputc(')',e->out);
special=1; special=1;
} }
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a && else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
n->a->a->kind==FE_N_IDENT && n->a->a->text && 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 && strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
strcmp(n->a->b->text,"null_writer")==0) { fputs("fe_m4_null_writer()",e->out); special=1; } strcmp(n->a->b->text,"null_writer")==0) { fputs("fe_m4_null_writer()",e->out); special=1; }
else if(n->a && n->a->kind==FE_N_MEMBER && n->sem_decl &&
n->sem_decl->kind==FE_N_FN) {
FeNode *mp=n->sem_decl->a ? n->sem_decl->a->children : 0;
FeNode *ma;
fputs(cname(n->sem_decl,"fe_method"),e->out); fputc('(',e->out);
if(mp && mp->sem_type && mp->sem_type->kind==FE_TYPE_REF) {
fputc('&',e->out); emit_lvalue(e,n->a->a);
} else emit_expr(e,n->a->a);
for(ma=n->children; ma; ma=ma->next) {
fputs(", ",e->out); emit_expr(e,ma);
}
fputc(')',e->out);
special=1;
}
else if(!n->a && n->text && strcmp(n->text,"@size_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%lu",fe_type_size(fe_type_intern(&e->check->types,n->children->text))); special=1; } else if(!n->a && n->text && strcmp(n->text,"@size_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%lu",fe_type_size(fe_type_intern(&e->check->types,n->children->text))); special=1; }
else if(!n->a && n->text && strcmp(n->text,"@align_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%u",fe_type_align(fe_type_intern(&e->check->types,n->children->text))); special=1; } else if(!n->a && n->text && strcmp(n->text,"@align_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%u",fe_type_align(fe_type_intern(&e->check->types,n->children->text))); special=1; }
else if (n->a && n->a->kind==FE_N_MEMBER && n->a->a && n->a->a->sem_type && n->a->a->sem_type->kind==FE_TYPE_ENUM) { else if (n->a && n->a->kind==FE_N_MEMBER && n->a->a && n->a->a->sem_type && n->a->a->sem_type->kind==FE_TYPE_ENUM) {
@@ -860,7 +946,10 @@ static void emit_expr(FeEmitter *e, FeNode *n)
n->b && n->b->text && strcmp(n->b->text,"^")==0) { n->b && n->b->text && strcmp(n->b->text,"^")==0) {
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out); 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 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); } else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_REF) {
emit_expr(e,n->a); fputs("->",e->out);
if(n->b) fputs(n->b->text ? n->b->text : "member",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; break;
} }
default: default:
@@ -887,7 +976,7 @@ static void emit_decl(FeEmitter *e, FeNode *n)
} }
fputs(";\n", e->out); fputs(";\n", e->out);
if ((n->kind==FE_N_LET || n->kind==FE_N_VAR) && n->sem_type && if ((n->kind==FE_N_LET || n->kind==FE_N_VAR) && n->sem_type &&
n->sem_type->kind==FE_TYPE_OWNED) { type_needs_drop(n->sem_type)) {
pad(e); fputs("unsigned char fe_live_",e->out); pad(e); fputs("unsigned char fe_live_",e->out);
fputs(cname(n,"owned"),e->out); fputs("=0;\n",e->out); fputs(cname(n,"owned"),e->out); fputs("=0;\n",e->out);
} }
@@ -895,7 +984,7 @@ static void emit_decl(FeEmitter *e, FeNode *n)
static void emit_owned_live(FeEmitter *e, FeNode *n, int value) static void emit_owned_live(FeEmitter *e, FeNode *n, int value)
{ {
if (n && n->sem_type && n->sem_type->kind==FE_TYPE_OWNED) { if (n && n->sem_type && type_needs_drop(n->sem_type)) {
pad(e); fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out); pad(e); fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fprintf(e->out,"=%d;\n",value); fprintf(e->out,"=%d;\n",value);
} }
@@ -909,14 +998,21 @@ static void emit_value_drop(FeEmitter *e, FeNode *n)
if (t->kind==FE_TYPE_OWNED) { if (t->kind==FE_TYPE_OWNED) {
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"owned"),e->out); pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs(") { ",e->out); fputs(") { ",e->out);
if (t->elem && type_needs_drop(t->elem) && t->elem->drop_cname) { if(t->elem && t->elem->kind==FE_TYPE_SLICE) {
fprintf(e->out,"%s(%s); ",t->elem->drop_cname,cname(n,"owned"));
}
fputs("free(",e->out); fputs(cname(n,"owned"),e->out); fputs("free(",e->out); fputs(cname(n,"owned"),e->out);
fputs("); fe_live_",e->out); fputs(cname(n,"owned"),e->out); fputs(".p); ",e->out);
} else 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("); ",e->out);
} else {
fputs("free(",e->out); fputs(cname(n,"owned"),e->out); fputs("); ",e->out);
}
fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
fputs("=0; }\n",e->out); fputs("=0; }\n",e->out);
} else if (t->drop_cname) { } else if (t->drop_cname) {
pad(e); fprintf(e->out,"%s(&%s);\n",t->drop_cname,cname(n,"local")); pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"local"),e->out);
fprintf(e->out,") { %s(&%s); fe_live_",t->drop_cname,cname(n,"local"));
fputs(cname(n,"local"),e->out); fputs("=0; }\n",e->out);
} }
} }
@@ -1006,7 +1102,7 @@ static void emit_block(FeEmitter *e, FeNode *n)
if (e->current_fn && e->current_fn->c==n && e->current_fn->a) { if (e->current_fn && e->current_fn->c==n && e->current_fn->a) {
FeNode *param; FeNode *param;
for (param=e->current_fn->a->children; param; param=param->next) for (param=e->current_fn->a->children; param; param=param->next)
if (param->sem_type && param->sem_type->kind==FE_TYPE_OWNED) { if (param->sem_type && type_needs_drop(param->sem_type)) {
pad(e); fputs("unsigned char fe_live_",e->out); pad(e); fputs("unsigned char fe_live_",e->out);
fputs(cname(param,"owned"),e->out); fputs("=1;\n",e->out); fputs(cname(param,"owned"),e->out); fputs("=1;\n",e->out);
} }
@@ -1126,12 +1222,26 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
n->a->sem_type->kind==FE_TYPE_OWNED) { n->a->sem_type->kind==FE_TYPE_OWNED) {
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"owned"),e->out); pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
fputs(") { ",e->out); fputs(") { ",e->out);
if (n->a->sem_type->elem && type_needs_drop(n->a->sem_type->elem) && if(n->a->sem_type->elem &&
n->a->sem_type->elem->kind==FE_TYPE_SLICE) {
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out);
fputs(".p); ",e->out);
} else if (n->a->sem_type->elem && type_needs_drop(n->a->sem_type->elem) &&
n->a->sem_type->elem->drop_cname) n->a->sem_type->elem->drop_cname)
fprintf(e->out,"%s(%s); ",n->a->sem_type->elem->drop_cname,cname(n->a,"owned")); 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); if(!(n->a->sem_type->elem &&
fputs("); fe_live_",e->out); fputs(cname(n->a,"owned"),e->out); n->a->sem_type->elem->kind==FE_TYPE_SLICE)) {
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out); fputs("); ",e->out);
}
fputs("fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
fputs("=0; }\n",e->out); fputs("=0; }\n",e->out);
} else if(n->a && n->a->kind==FE_N_IDENT && n->a->sem_type &&
type_needs_drop(n->a->sem_type) &&
n->a->sem_type->drop_cname) {
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"local"),e->out);
fprintf(e->out,") { %s(&%s); fe_live_",
n->a->sem_type->drop_cname,cname(n->a,"local"));
fputs(cname(n->a,"local"),e->out); fputs("=0; }\n",e->out);
} }
pad(e); pad(e);
emit_lvalue(e, n->a); emit_lvalue(e, n->a);
@@ -1153,12 +1263,12 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
pad(e); pad(e);
if (n->a && n->a->kind==FE_N_UNARY && n->a->text && if (n->a && n->a->kind==FE_N_UNARY && n->a->text &&
strcmp(n->a->text,"try")==0 && n->a->a) { strcmp(n->a->text,"try")==0 && n->a->a) {
fputs("if ((fe_m4_error = ",e->out); fputs("if ((fe_error_temp = ",e->out);
emit_expr(e,n->a->a); emit_expr(e,n->a->a);
fputs(") != 0) {\n",e->out); fputs(") != 0) {\n",e->out);
++e->indent; ++e->indent;
emit_cleanup_all(e); emit_cleanup_all(e);
pad(e); fputs("return fe_m4_error;\n",e->out); pad(e); fputs("return fe_error_temp;\n",e->out);
--e->indent; --e->indent;
pad(e); fputs("}\n",e->out); pad(e); fputs("}\n",e->out);
} else { } else {
@@ -1275,7 +1385,8 @@ static void emit_fn(FeEmitter *e, FeNode *fn, int prototype)
if (!p) fputs("void", e->out); if (!p) fputs("void", e->out);
while (p) { while (p) {
if (p != fn->a->children) fputs(", ", e->out); if (p != fn->a->children) fputs(", ", e->out);
fputs(ctype(e, p->a), e->out); fputs(p->sem_type ? fe_type_c_name(p->sem_type,e->pointer_bits) :
ctype(e,p->a),e->out);
fputc(' ', e->out); fputc(' ', e->out);
fputs(cname(p, "fe_arg"), e->out); fputs(cname(p, "fe_arg"), e->out);
p = p->next; p = p->next;
@@ -1343,7 +1454,7 @@ void fe_emit_c_program(FeEmitter *e)
fputs("typedef char fe_assert_usize[(sizeof(unsigned short)==2) ? 1 : -1];\n",e->out); fputs("typedef char fe_assert_usize[(sizeof(unsigned short)==2) ? 1 : -1];\n",e->out);
else else
fputs("typedef char fe_assert_usize[(sizeof(unsigned long)==4) ? 1 : -1];\n",e->out); fputs("typedef char fe_assert_usize[(sizeof(unsigned long)==4) ? 1 : -1];\n",e->out);
fputs("static void fe_trap_bounds(void) { abort(); }\n\n", e->out); fputs("static void fe_trap_bounds(void) { abort(); }\nstatic unsigned short fe_error_temp;\n\n", e->out);
emit_type_defs(e); emit_type_defs(e);
if (need_m4) emit_m4_runtime(e); if (need_m4) emit_m4_runtime(e);
emit_type_helpers(e); emit_type_helpers(e);
@@ -1373,10 +1484,24 @@ void fe_emit_c_program(FeEmitter *e)
emit_fn(e, n, 1); emit_fn(e, n, 1);
if (n->text && strcmp(n->text, "main") == 0) main_fn = n; if (n->text && strcmp(n->text, "main") == 0) main_fn = n;
} }
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
n; n = n->next) if(n->kind==FE_N_STRUCT) {
FeNode *m;
for(m=n->children; m; m=m->next)
if(m->kind==FE_N_FN)
emit_fn(e,m,1);
}
fputc('\n', e->out); fputc('\n', e->out);
for (n = e->check->ast->root ? e->check->ast->root->children : 0; for (n = e->check->ast->root ? e->check->ast->root->children : 0;
n; n = n->next) n; n = n->next)
if (n->kind == FE_N_FN) emit_fn(e, n, 0); if (n->kind == FE_N_FN) emit_fn(e, n, 0);
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
n; n = n->next) if(n->kind==FE_N_STRUCT) {
FeNode *m;
for(m=n->children; m; m=m->next)
if(m->kind==FE_N_FN)
emit_fn(e,m,0);
}
if (main_fn) { if (main_fn) {
fputc('\n', e->out); fputc('\n', e->out);
emit_main_wrapper(e, main_fn); emit_main_wrapper(e, main_fn);
+14 -1
View File
@@ -21,6 +21,7 @@ static FeType *new_type(FeTypeCtx *ctx, const char *name, FeTypeKind kind)
t->tail_slicer = 0; t->tail_slicer = 0;
t->drop_cname = 0; t->drop_cname = 0;
t->alloc_cname = 0; t->alloc_cname = 0;
t->replace_cname = 0;
t->bits = 0; t->bits = 0;
t->is_unsigned = 0; t->is_unsigned = 0;
t->packed = 0; t->packed = 0;
@@ -200,6 +201,10 @@ FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem)
if(t->kind==FE_TYPE_UNKNOWN) { if(t->kind==FE_TYPE_UNKNOWN) {
t->kind=FE_TYPE_OWNED; t->kind=FE_TYPE_OWNED;
t->elem=elem; t->elem=elem;
if(elem && elem->kind==FE_TYPE_SLICE) {
t->cname=generated_name(ctx,"fe_owned_slice_","type");
t->maker=generated_name(ctx,"fe_make_owned_slice_","type");
}
} }
return t; return t;
} }
@@ -222,6 +227,12 @@ FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value)
return t; return t;
} }
void fe_type_require_replace(FeTypeCtx *ctx, FeType *type)
{
if(type && !type->replace_cname)
type->replace_cname=generated_name(ctx,"fe_replace_","type");
}
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed) FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
{ {
FeType *t; FeType *t;
@@ -410,7 +421,9 @@ static void layout_type(FeTypeCtx *ctx, FeType *t)
t->cycle_state = 2; return; t->cycle_state = 2; return;
} }
if (t->kind == FE_TYPE_OWNED) { if (t->kind == FE_TYPE_OWNED) {
t->size = ctx->pointer_bits == 16 ? 2UL : 4UL; t->size = t->elem && t->elem->kind==FE_TYPE_SLICE ?
(ctx->pointer_bits == 16 ? 4UL : 8UL) :
(ctx->pointer_bits == 16 ? 2UL : 4UL);
t->align = ctx->pointer_bits == 16 ? 1U : 4U; t->align = ctx->pointer_bits == 16 ? 1U : 4U;
t->cycle_state = 2; return; t->cycle_state = 2; return;
} }
+2
View File
@@ -39,6 +39,7 @@ struct FeType {
char *tail_slicer; char *tail_slicer;
char *drop_cname; char *drop_cname;
char *alloc_cname; char *alloc_cname;
char *replace_cname;
unsigned bits; unsigned bits;
int is_unsigned; int is_unsigned;
int packed; int packed;
@@ -77,6 +78,7 @@ FeType *fe_type_mut_slice(FeTypeCtx *ctx, FeType *elem);
FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable); FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable);
FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem); FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem);
FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value); FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value);
void fe_type_require_replace(FeTypeCtx *ctx, FeType *type);
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed); FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed);
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node); FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node);
FeType *fe_type_declare_error(FeTypeCtx *ctx, const FeNode *node); FeType *fe_type_declare_error(FeTypeCtx *ctx, const FeNode *node);
+4 -2
View File
@@ -1,8 +1,10 @@
unit mem; unit mem;
pub fn create(T: type) -> !^T; pub fn create(value: T) -> !^T;
pub fn destroy(p: *void); pub fn destroy(p: *void);
pub fn copy(dst: []u8, src: []u8); pub fn alloc_slice(T: type, n: usize) -> !^[]T;
pub fn replace(dst: &mut T, value: T) -> T;
pub fn copy(dst: []mut u8, src: []u8);
pub struct Arena { pub struct Arena {
ptr: *void, ptr: *void,
pub fn init() -> Arena { return Arena{ ptr: null }; } pub fn init() -> Arena { return Arena{ ptr: null }; }
+9 -3
View File
@@ -259,14 +259,20 @@ fec.exe --target=bits32 --emit-c TESTS\M5\BAD-DBL.FE -o TESTS\M5\BAD-DBL.C > nul
if not errorlevel 1 goto test_fail if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-COND.FE -o TESTS\M5\BAD-COND.C > nul fec.exe --target=bits32 --emit-c TESTS\M5\BAD-COND.FE -o TESTS\M5\BAD-COND.C > nul
if not errorlevel 1 goto test_fail if not errorlevel 1 goto test_fail
if exist TESTS\M5\RUNTIME-G.C del TESTS\M5\RUNTIME-G.C fec.exe --target=bits32 --emit-c TESTS\M5\BAD-PROJ.FE -o TESTS\M5\BAD-PROJ.C > nul
if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-CLOS.FE -o TESTS\M5\BAD-CLOS.C > nul
if not errorlevel 1 goto test_fail
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-LOOP.FE -o TESTS\M5\BAD-LOOP.C > nul
if not errorlevel 1 goto test_fail
if exist TESTS\M5\RUNT-G.C del TESTS\M5\RUNT-G.C
if exist TESTS\M5\RUNTIME.O del TESTS\M5\RUNTIME.O if exist TESTS\M5\RUNTIME.O del TESTS\M5\RUNTIME.O
if exist TESTS\M5\RUNTIME.EXE del TESTS\M5\RUNTIME.EXE 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 fec.exe --target=bits32 --emit-c TESTS\M5\RUNTIME.FE -o TESTS\M5\RUNT-G.C > nul
if errorlevel 1 goto test_fail if errorlevel 1 goto test_fail
rem Compile generated source and the C89 runtime harness in one WCL386 invocation 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. rem so both objects use the same DOS/4GW startup and runtime library.
wcl386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\M5\RUNTIME.EXE TESTS\M5\RUNTIME-G.C TESTS\M5\RUNTIME.C wcl386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\M5\RUNTIME.EXE TESTS\M5\RUNT-G.C TESTS\M5\RUNTIME.C
if errorlevel 1 goto test_fail if errorlevel 1 goto test_fail
TESTS\M5\RUNTIME.EXE TESTS\M5\RUNTIME.EXE
if errorlevel 1 goto test_fail if errorlevel 1 goto test_fail
+13
View File
@@ -0,0 +1,13 @@
unit m5_bad_consuming_close;
struct FileLike {
handle: i32,
fn close(self: Self) -> !void { self.handle = 0; }
fn drop(self: &mut Self) { self.handle = 0; }
}
fn bad() -> !void {
let file: FileLike = FileLike{ handle: 7 };
try file.close();
file.close();
}
+7
View File
@@ -0,0 +1,7 @@
unit m5_bad_loop_move;
fn take(p: ^i32) -> void { mem.destroy(p); }
fn bad(p: ^i32, again: bool) -> void {
while again { take(p); }
}
+8
View File
@@ -0,0 +1,8 @@
unit m5_bad_projection_move;
struct Holder { p: ^i32 }
fn take(p: ^i32) -> void { mem.destroy(p); }
fn bad(h: Holder) -> void {
take(h.p);
}
+2 -2
View File
@@ -1,8 +1,8 @@
unit m5_owned; unit m5_owned;
fn main() -> void { fn main() -> void {
var p: ^i32 = try mem.create(i32); var p: ^i32 = try mem.create(0);
p = try mem.create(i32); p = try mem.create(0);
p.^ = 7; p.^ = 7;
let value: i32 = p.^; let value: i32 = p.^;
defer { mem.destroy(p); } defer { mem.destroy(p); }
+55 -9
View File
@@ -4,21 +4,43 @@
#undef malloc #undef malloc
#undef free #undef free
extern void *malloc(size_t size);
extern void free(void *p);
extern long fe_m5_runtime_run(long mode); extern long fe_m5_runtime_run(long mode);
extern void fe_m5_runtime_conditional(unsigned char flag); extern unsigned short fe_m5_runtime_conditional(unsigned char flag);
extern void fe_m5_runtime_argument_cleanup(void); extern unsigned short fe_m5_runtime_argument_cleanup(void);
extern unsigned short fe_m5_runtime_owned_slice(unsigned long n);
extern unsigned short fe_m5_runtime_replace_field(void);
extern unsigned short fe_m5_runtime_loop_cleanup(void);
extern unsigned short fe_m5_runtime_try_cleanup(void);
extern unsigned short fe_m5_runtime_field_order(void);
extern unsigned short fe_m5_runtime_defer_order(void);
extern unsigned short fe_m5_runtime_match_cleanup(unsigned char flag);
extern unsigned short fe_m5_runtime_close_once(void);
extern unsigned short fe_m5_runtime_reassign_struct(void);
static void *live_ptrs[64]; static void *live_ptrs[64];
static unsigned live_count; static unsigned live_count;
static unsigned alloc_count; static unsigned alloc_count;
static unsigned free_count; static unsigned free_count;
static unsigned double_free_count; static unsigned double_free_count;
static long fail_after = -1;
static unsigned malloc_attempts;
static int track_order;
static void *order_ptrs[2];
static unsigned order_allocs;
static unsigned order_frees;
static unsigned order_bad;
void *m5_malloc(size_t size) void *m5_malloc(size_t size)
{ {
void *p = malloc(size); void *p;
if (fail_after >= 0 && (long)malloc_attempts++ == fail_after) return 0;
p = malloc(size);
if (p && live_count < 64) live_ptrs[live_count++] = p; if (p && live_count < 64) live_ptrs[live_count++] = p;
if (p) ++alloc_count; if (p) ++alloc_count;
if (p && track_order && order_allocs < 2) order_ptrs[order_allocs++] = p;
return p; return p;
} }
@@ -28,6 +50,9 @@ void m5_free(void *p)
if (!p) return; if (!p) return;
for (i = 0; i < live_count; ++i) { for (i = 0; i < live_count; ++i) {
if (live_ptrs[i] == p) { if (live_ptrs[i] == p) {
if (track_order && order_frees < 2 &&
p != order_ptrs[1-order_frees]) ++order_bad;
if (track_order && order_frees < 2) ++order_frees;
live_ptrs[i] = live_ptrs[--live_count]; live_ptrs[i] = live_ptrs[--live_count];
++free_count; ++free_count;
free(p); free(p);
@@ -42,11 +67,32 @@ int main(void)
if (fe_m5_runtime_run(0) != 0) return 1; if (fe_m5_runtime_run(0) != 0) return 1;
if (fe_m5_runtime_run(1) != 9) return 2; if (fe_m5_runtime_run(1) != 9) return 2;
if (fe_m5_runtime_run(2) != 0) return 3; if (fe_m5_runtime_run(2) != 0) return 3;
fe_m5_runtime_conditional(0); if (fe_m5_runtime_conditional(0) != 0) return 4;
fe_m5_runtime_conditional(1); if (fe_m5_runtime_conditional(1) != 0) return 5;
fe_m5_runtime_argument_cleanup(); if (fe_m5_runtime_argument_cleanup() != 0) return 6;
if (double_free_count != 0) return 4; if (fe_m5_runtime_owned_slice(17) != 0) return 7;
if (live_count != 0) return 5; if (fe_m5_runtime_replace_field() != 0) return 8;
if (alloc_count != free_count) return 6; if (fe_m5_runtime_loop_cleanup() != 0) return 9;
fail_after=1;
malloc_attempts=0;
if (fe_m5_runtime_try_cleanup() == 0) return 10;
fail_after=-1;
track_order=1;
order_allocs=order_frees=order_bad=0;
if (fe_m5_runtime_field_order() != 0) return 11;
track_order=0;
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 12;
track_order=1;
order_allocs=order_frees=order_bad=0;
if (fe_m5_runtime_defer_order() != 0) return 13;
track_order=0;
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 14;
if (fe_m5_runtime_match_cleanup(0) != 0) return 15;
if (fe_m5_runtime_match_cleanup(1) != 0) return 16;
if (fe_m5_runtime_close_once() != 0) return 17;
if (fe_m5_runtime_reassign_struct() != 0) return 18;
if (double_free_count != 0) return 19;
if (live_count != 0) return 20;
if (alloc_count != free_count) return 21;
return 0; return 0;
} }
+79 -6
View File
@@ -3,11 +3,11 @@ unit m5_runtime;
fn take(p: ^i32) -> void { mem.destroy(p); } fn take(p: ^i32) -> void { mem.destroy(p); }
pub fn run(mode: i32) -> i32 { pub fn run(mode: i32) -> i32 {
var p: ^i32 = try mem.create(i32); var p: ^i32 = try mem.create(0);
defer { mem.destroy(p); } defer { mem.destroy(p); }
p.^ = 7; p.^ = 7;
if mode == 1 { if mode == 1 {
p = try mem.create(i32); p = try mem.create(0);
p.^ = 9; p.^ = 9;
return p.^; return p.^;
} }
@@ -16,12 +16,85 @@ pub fn run(mode: i32) -> i32 {
return p.^ - 7; return p.^ - 7;
} }
pub fn conditional(flag: bool) -> void { pub fn conditional(flag: bool) -> !void {
var p: ^i32 = try mem.create(i32); var p: ^i32 = try mem.create(0);
if flag { take(p); } if flag { take(p); }
} }
pub fn argument_cleanup() -> void { pub fn argument_cleanup() -> !void {
let p: ^i32 = try mem.create(i32); let p: ^i32 = try mem.create(0);
take(p); take(p);
} }
pub fn owned_slice(n: usize) -> !void {
let bytes: ^[]u8 = try mem.alloc_slice(u8, n);
}
struct Holder { p: ^i32 }
pub fn replace_field() -> !void {
let first: ^i32 = try mem.create(1);
var h: Holder = Holder{ p: first };
let second: ^i32 = try mem.create(2);
let old: ^i32 = mem.replace(&mut h.p, second);
mem.destroy(old);
}
pub fn loop_cleanup() -> !void {
var i: i32 = 0;
while i < 2 {
let p: ^i32 = try mem.create(i);
i += 1;
if i == 1 { continue; }
break;
}
}
pub fn try_cleanup() -> !void {
let first: ^i32 = try mem.create(1);
let second: ^i32 = try mem.create(2);
}
struct PairOwners { first: ^i32, second: ^i32 }
pub fn field_order() -> !void {
let first: ^i32 = try mem.create(1);
let second: ^i32 = try mem.create(2);
let pair: PairOwners = PairOwners{ first: first, second: second };
}
pub fn defer_order() -> !void {
let first: ^i32 = try mem.create(1);
defer { mem.destroy(first); }
let second: ^i32 = try mem.create(2);
}
enum Choice { A, B }
pub fn match_cleanup(flag: bool) -> !void {
var choice: Choice = Choice.A;
if flag { choice = Choice.B; }
let p: ^i32 = try mem.create(1);
match choice {
A => { take(p); }
B => { take(p); }
}
}
struct FileLike {
handle: i32,
fn close(self: Self) -> !void { self.handle = 0; }
fn drop(self: &mut Self) { self.handle = 0; }
}
pub fn close_once() -> !void {
let file: FileLike = FileLike{ handle: 7 };
try file.close();
}
pub fn reassign_struct() -> !void {
let first: ^i32 = try mem.create(1);
var owner: Holder = Holder{ p: first };
let second: ^i32 = try mem.create(2);
owner = Holder{ p: second };
}