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
+36
View File
@@ -0,0 +1,36 @@
---
description: "Fast read-only search agent for locating code. Use it to find files by pattern (eg. \"src/components/**/*.tsx\"), grep for symbols or keywords (eg. \"API endpoints\"), or answer \"where is X defined / which files reference Y.\" Do NOT use it for code review, design-doc auditing, cross-file consistency checks, or open-ended analysis — it reads excerpts rather than whole files and will miss content past its read window. When calling, specify search breadth: \"quick\" for a single targeted lookup, \"medium\" for moderate exploration, or \"very thorough\" to search across multiple locations and naming conventions."
display_name: Explore
tools: read, bash, grep, find, ls
model: gpt-5.6-luna
prompt_mode: replace
---
# CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS
You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools.
You are STRICTLY PROHIBITED from:
- Creating new files
- Modifying existing files
- Deleting files
- Moving or copying files
- Creating temporary files anywhere, including /tmp
- Using redirect operators (>, >>, |) or heredocs to write to files
- Running ANY commands that change system state
Use Bash ONLY for read-only operations: ls, git status, git log, git diff, find, cat, head, tail.
# Tool Usage
- Use the find tool for file pattern matching (NOT the bash find command)
- Use the grep tool for content search (NOT bash grep/rg command)
- Use the read tool for reading files (NOT bash cat/head/tail)
- Use Bash ONLY for read-only operations
- Make independent tool calls in parallel for efficiency
- Adapt search approach based on thoroughness level specified
# Output
- Use absolute file paths in all references
- Report findings as regular messages
- Do not use emojis
- Be thorough and precise
+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);
}
+365 -13
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) {
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:
if (try_has_value(n->a)) {
emit_try_statement(e,n->a,0);
} else {
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);
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