feat: implement M3 aggregate types and iteration

This commit is contained in:
2026-08-16 08:49:50 +09:00
parent 57b47a574a
commit 8e6a409637
32 changed files with 1729 additions and 94 deletions
+436 -14
View File
@@ -22,9 +22,305 @@ static const char *cname(FeNode *n, const char *fallback)
return n && n->cname ? n->cname : fallback;
}
static void emit_one_type(FeEmitter *e, FeType *t);
static void emit_type_deps(FeEmitter *e, FeType *t)
{
unsigned i,j;
if (!t) return;
if (t->kind == FE_TYPE_ARRAY) emit_one_type(e,t->elem);
if (t->kind == FE_TYPE_STRUCT)
for (i=0;i<t->field_count;i++) emit_one_type(e,t->fields[i].type);
if (t->kind == FE_TYPE_ENUM)
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);
}
static void emit_one_type(FeEmitter *e, FeType *t)
{
unsigned i,j;
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->emit_state=1;
emit_type_deps(e,t);
if(t->kind==FE_TYPE_STRUCT) {
fputs(t->cname,e->out); fputs(" {\n",e->out);
for(i=0;i<t->field_count;i++) { fputs(" ",e->out); fputs(fe_type_c_name(t->fields[i].type,e->pointer_bits),e->out); fputc(' ',e->out); fputs(t->fields[i].name,e->out); fputs(";\n",e->out); }
fputs("};\n",e->out);
} else if(t->kind==FE_TYPE_ARRAY) {
fputs(t->cname,e->out); fputs(" { ",e->out); fputs(fe_type_c_name(t->elem,e->pointer_bits),e->out); fputs(" a[",e->out); fprintf(e->out,"%lu",t->length); fputs("]; };\n",e->out);
} 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_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);
for(j=0;j<t->variants[i].field_count;j++) { fputs(" ",e->out); fputs(fe_type_c_name(t->variants[i].fields[j].type,e->pointer_bits),e->out); fputc(' ',e->out); fputs(t->variants[i].fields[j].name,e->out); fputc(';',e->out); }
fputs(" };\n",e->out);
}
fputs(t->cname,e->out); fputs(" { ",e->out); fputs(t->bits>8 ? "unsigned short" : "unsigned char",e->out); fputs(" tag; union { ",e->out);
for(i=0;i<t->variant_count;i++) { if(t->variants[i].field_count==0) fputs("unsigned char",e->out); else if(t->variants[i].field_count==1) fputs(fe_type_c_name(t->variants[i].fields[0].type,e->pointer_bits),e->out); else fprintf(e->out,"struct fe_payload_%s_%s",t->name,t->variants[i].name); fputc(' ',e->out); fputs(t->variants[i].name,e->out); fputc(';',e->out); }
fputs(" } payload; };\n",e->out);
}
t->emit_state=2;
}
static void emit_type_defs(FeEmitter *e)
{
FeType *t;
fputs("typedef struct { const unsigned char *p; unsigned long n; } fe_str;\n",e->out);
fputs("static fe_str fe_make_str(const unsigned char *p, unsigned long n) { fe_str s; s.p=p; s.n=n; return s; }\n",e->out);
/* Every fixed array has a slice conversion helper, even if this unit
only indexes the array. Intern those result types before emission so
their typedefs are present before helper definitions. */
for(t=e->check->types.types;t;t=t->next)
if(t->kind==FE_TYPE_ARRAY) fe_type_slice(&e->check->types,t->elem);
for(t=e->check->types.types;t;t=t->next) emit_one_type(e,t);
}
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_STRUCT && 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); }
fputs(") { ",e->out); fprintf(e->out,"%s v;",t->cname);
for(i=0;i<t->field_count;i++) fprintf(e->out," v.%s=p%u;",t->fields[i].name,i);
fputs(" return v; }\n",e->out);
} else if(t->kind==FE_TYPE_ARRAY && t->maker) {
fprintf(e->out,"static %s %s(",t->cname,t->maker);
for(i=0;i<t->length;i++) { if(i) fputs(", ",e->out); fputs(fe_type_c_name(t->elem,e->pointer_bits),e->out); fprintf(e->out," p%u",i); }
fputs(") { ",e->out); fprintf(e->out,"%s v;",t->cname);
for(i=0;i<t->length;i++) fprintf(e->out," v.a[%u]=p%u;",i,i);
fputs(" return v; }\n",e->out);
} else if(t->kind==FE_TYPE_ENUM) {
for(i=0;i<t->variant_count;i++) {
FeVariantType *v=&t->variants[i];
fprintf(e->out,"static %s %s(",t->cname,v->maker);
for(j=0;j<v->field_count;j++) { if(j) fputs(", ",e->out); fputs(fe_type_c_name(v->fields[j].type,e->pointer_bits),e->out); fprintf(e->out," p%u",j); }
fputs(") { ",e->out); fprintf(e->out,"%s x; x.tag=%u;",t->cname,v->tag);
for(j=0;j<v->field_count;j++) { if(v->field_count==1) fprintf(e->out," x.payload.%s=p%u;",v->name,j); else fprintf(e->out," x.payload.%s.%s=p%u;",v->name,v->fields[j].name,j); }
fputs(" return x; }\n",e->out);
}
}
}
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) { ",
fe_type_c_name(t->elem,e->pointer_bits),t->indexer,t->cname);
if(!e->no_checks) fprintf(e->out,"if (i >= %lu) fe_trap_bounds(); ",t->length);
fprintf(e->out,"return x.a[i]; }\n");
fprintf(e->out,"static %s %s(%s x, unsigned long a, unsigned long b) { ",
fe_type_c_name(fe_type_slice(&e->check->types,t->elem),e->pointer_bits),t->slicer,t->cname);
if(!e->no_checks) fputs("if (a > b || b > ",e->out), fprintf(e->out,"%lu",t->length), fputs(") fe_trap_bounds(); ",e->out);
fprintf(e->out,"return %s(x.a+a,b-a); }\n",fe_type_slice(&e->check->types,t->elem)->maker);
fprintf(e->out,"static %s %s(%s x) { return %s(x,0,%lu); }\n",fe_type_c_name(fe_type_slice(&e->check->types,t->elem),e->pointer_bits),t->full_slicer,t->cname,t->slicer,t->length);
fprintf(e->out,"static %s %s(%s x, unsigned long a) { return %s(x,a,%lu); }\n",fe_type_c_name(fe_type_slice(&e->check->types,t->elem),e->pointer_bits),t->tail_slicer,t->cname,t->slicer,t->length);
} else if (t->kind==FE_TYPE_SLICE && t->indexer) {
fprintf(e->out,"static %s %s(%s x, unsigned long i) { ",
fe_type_c_name(t->elem,e->pointer_bits),t->indexer,t->cname);
if(!e->no_checks) fputs("if (i >= x.n) fe_trap_bounds(); ",e->out);
fputs("return x.p[i]; }\n",e->out);
fprintf(e->out,"static %s %s(%s x, unsigned long a, unsigned long b) { ",
fe_type_c_name(t,e->pointer_bits),t->slicer,t->cname);
if(!e->no_checks) fputs("if (a > b || b > x.n) fe_trap_bounds(); ",e->out);
fprintf(e->out,"return %s(x.p+a,b-a); }\n",t->maker);
fprintf(e->out,"static %s %s(%s x) { return %s(x,0,x.n); }\n",t->cname,t->full_slicer,t->cname,t->slicer);
fprintf(e->out,"static %s %s(%s x, unsigned long a) { return %s(x,a,x.n); }\n",t->cname,t->tail_slicer,t->cname,t->slicer);
}
}
fputs("static unsigned char fe_idx_str(fe_str x, unsigned long i) { ",e->out);
if(!e->no_checks) fputs("if (i >= x.n) fe_trap_bounds(); ",e->out);
fputs("return x.p[i]; }\n",e->out);
fputs("static fe_str fe_slice_str(fe_str x, unsigned long a, unsigned long b) { ",e->out);
if(!e->no_checks) fputs("if (a > b || b > x.n) fe_trap_bounds(); ",e->out);
fputs("return fe_make_str(x.p+a,b-a); }\n",e->out);
fputs("static fe_str fe_full_slice_str(fe_str x) { return fe_slice_str(x,0,x.n); }\n",e->out);
fputs("static fe_str fe_tail_slice_str(fe_str x, unsigned long a) { return fe_slice_str(x,a,x.n); }\n",e->out);
}
static void emit_expr(FeEmitter *e, FeNode *n);
static void emit_stmt(FeEmitter *e, FeNode *n);
static int stmt_definitely_returns(FeNode *n);
static int match_is_exhaustive(FeNode *n)
{
FeType *t;
FeNode *arm;
unsigned i;
int found;
if (!n || !n->a) return 0;
t=n->a->sem_type;
if (!t || t->kind!=FE_TYPE_ENUM) return 0;
for (arm=n->children; arm; arm=arm->next)
if (arm->text && strcmp(arm->text,"_")==0) return 1;
for (i=0; i<t->variant_count; ++i) {
found=0;
for (arm=n->children; arm; arm=arm->next)
if (arm->text && strcmp(arm->text,t->variants[i].name)==0) {
found=1;
break;
}
if (!found) return 0;
}
return 1;
}
static int match_definitely_returns(FeNode *n)
{
FeNode *arm;
if (!match_is_exhaustive(n)) return 0;
for (arm=n->children; arm; arm=arm->next)
if (!stmt_definitely_returns(arm->a)) return 0;
return 1;
}
static int stmt_definitely_returns(FeNode *n)
{
FeNode *last;
if (!n) return 0;
if (n->kind==FE_N_RETURN) return 1;
if (n->kind==FE_N_MATCH) return match_definitely_returns(n);
if (n->kind==FE_N_BLOCK) {
last=n->children;
if (!last) return 0;
while (last->next) last=last->next;
return stmt_definitely_returns(last);
}
if (n->kind==FE_N_IF)
return n->b && n->c && stmt_definitely_returns(n->b) &&
stmt_definitely_returns(n->c);
return 0;
}
static int hex_value(int c)
{
if (c>='0' && c<='9') return c-'0';
if (c>='a' && c<='f') return c-'a'+10;
if (c>='A' && c<='F') return c-'A'+10;
return -1;
}
static void emit_byte(FILE *out, unsigned value)
{
fprintf(out,"\\%03o",value & 255U);
}
static void emit_codepoint(FILE *out, unsigned long cp)
{
if (cp<=0x7fUL) emit_byte(out,(unsigned)cp);
else if (cp<=0x7ffUL) {
emit_byte(out,(unsigned)(0xc0UL | (cp>>6)));
emit_byte(out,(unsigned)(0x80UL | (cp&0x3fUL)));
} else if (cp<=0xffffUL) {
emit_byte(out,(unsigned)(0xe0UL | (cp>>12)));
emit_byte(out,(unsigned)(0x80UL | ((cp>>6)&0x3fUL)));
emit_byte(out,(unsigned)(0x80UL | (cp&0x3fUL)));
} else {
emit_byte(out,(unsigned)(0xf0UL | (cp>>18)));
emit_byte(out,(unsigned)(0x80UL | ((cp>>12)&0x3fUL)));
emit_byte(out,(unsigned)(0x80UL | ((cp>>6)&0x3fUL)));
emit_byte(out,(unsigned)(0x80UL | (cp&0x3fUL)));
}
}
static void emit_c_literal(FILE *out, const char *text, int string)
{
unsigned long i;
unsigned long cp;
int h0,h1,h2,h3;
int c;
char quote=string ? '"' : '\'';
if (!text) { fputs(string ? "\"\"" : "'\\000'",out); return; }
fputc(quote,out);
for(i=1;text[i] && text[i]!=quote;i++) {
c=(unsigned char)text[i];
if(c!='\\') {
if(c==quote || c=='\\') fputc('\\',out);
fputc(c,out);
continue;
}
++i; c=(unsigned char)text[i];
if(c=='u' && text[i+1] && text[i+2] && text[i+3] && text[i+4]) {
h0=hex_value(text[i+1]); h1=hex_value(text[i+2]);
h2=hex_value(text[i+3]); h3=hex_value(text[i+4]);
if(h0>=0 && h1>=0 && h2>=0 && h3>=0) {
cp=(unsigned long)((h0<<12)|(h1<<8)|(h2<<4)|h3);
emit_codepoint(out,cp); i+=4; continue;
}
}
if(c=='x' && text[i+1] && text[i+2]) {
h0=hex_value(text[i+1]); h1=hex_value(text[i+2]);
if(h0>=0 && h1>=0) { emit_byte(out,(unsigned)((h0<<4)|h1)); i+=2; continue; }
}
if(c=='n') emit_byte(out,10U);
else if(c=='r') emit_byte(out,13U);
else if(c=='t') emit_byte(out,9U);
else if(c=='0') emit_byte(out,0U);
else emit_byte(out,(unsigned char)c);
}
fputc(quote,out);
}
static void emit_lvalue(FeEmitter *e, FeNode *n)
{
FeType *bt;
if (!n) { fputs("fe_bad_lvalue",e->out); return; }
if (n->kind==FE_N_IDENT) { fputs(cname(n,"fe_local"),e->out); return; }
if (n->kind==FE_N_MEMBER) {
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 { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); }
return;
}
if (n->kind==FE_N_INDEX) {
bt=n->a ? n->a->sem_type : 0;
emit_lvalue(e,n->a); fputs(bt && bt->kind==FE_TYPE_ARRAY ? ".a[" : ".p[",e->out);
emit_expr(e,n->b); fputc(']',e->out); return;
}
emit_expr(e,n);
}
static FeNode *init_field(FeNode *n, const char *name)
{
FeNode *f;
for(f=n ? n->children : 0;f;f=f->next)
if(f->kind==FE_N_FIELD && f->text && name && strcmp(f->text,name)==0) return f;
return 0;
}
static void emit_slice_call(FeEmitter *e, FeNode *n)
{
FeType *bt=n->a ? n->a->sem_type : 0;
const char *maker=bt && bt->slicer ? bt->slicer : "fe_slice_str";
if (!n->b && !n->c && bt && bt->full_slicer) {
fputs(bt->full_slicer,e->out); fputc('(',e->out); emit_expr(e,n->a); fputc(')',e->out); return;
}
if (!n->c && bt && bt->tail_slicer) {
fputs(bt->tail_slicer,e->out); fputc('(',e->out); emit_expr(e,n->a); fputs(", ",e->out);
if (n->b) emit_expr(e,n->b); else fputs("0",e->out);
fputc(')',e->out); return;
}
fputs(maker,e->out); fputc('(',e->out); emit_expr(e,n->a); fputs(", ",e->out);
if(n->b) emit_expr(e,n->b); else fputs("0",e->out);
fputs(", ",e->out);
if(n->c) emit_expr(e,n->c);
else if(bt && bt->kind==FE_TYPE_ARRAY) fprintf(e->out,"%lu",bt->length);
else fputs("((unsigned long)",e->out), emit_expr(e,n->a), fputs(".n)",e->out);
fputc(')',e->out);
}
static void emit_slice(FeEmitter *e, FeNode *n)
{
emit_slice_call(e,n);
}
static void emit_expr(FeEmitter *e, FeNode *n)
{
FeNode *x;
@@ -40,8 +336,43 @@ static void emit_expr(FeEmitter *e, FeNode *n)
case FE_N_LITERAL:
if (n->text && strcmp(n->text, "true") == 0) fputs("1", e->out);
else if (n->text && strcmp(n->text, "false") == 0) fputs("0", e->out);
else if (n->text && n->text[0]=='"') { fputs("fe_make_str((const unsigned char*)",e->out); emit_c_literal(e->out,n->text,1); fputs(", sizeof(",e->out); emit_c_literal(e->out,n->text,1); fputs(")-1)",e->out); }
else if (n->text && n->text[0]=='\'') emit_c_literal(e->out,n->text,0);
else fputs(n->text ? n->text : "0", e->out);
break;
case FE_N_STRUCT_INIT: {
FeVariantType *v;
FeNode *f;
unsigned i;
if(n->sem_type && n->a && n->a->kind==FE_N_MEMBER) {
v=fe_type_variant(n->sem_type,n->a->b ? n->a->b->text : "");
if(v) { fputs(v->maker,e->out); fputc('(',e->out); for(i=0;i<v->field_count;i++){f=init_field(n,v->fields[i].name);if(i)fputs(", ",e->out);if(f)emit_expr(e,f->a);else fputs("0",e->out);} fputc(')',e->out); }
else fputs("0",e->out);
} else if(n->sem_type && n->sem_type->maker) {
fputs(n->sem_type->maker,e->out); fputc('(',e->out);
if(n->sem_type->kind==FE_TYPE_STRUCT) { for(i=0;i<n->sem_type->field_count;i++){f=init_field(n,n->sem_type->fields[i].name);if(i)fputs(", ",e->out);if(f)emit_expr(e,f->a);else fputs("0",e->out);} }
fputc(')',e->out);
} else fputs("0",e->out);
break;
}
case FE_N_ARRAY_INIT: {
int first=1;
if(n->sem_type && n->sem_type->maker) { fputs(n->sem_type->maker,e->out); fputc('(',e->out); for(x=n->children;x;x=x->next){if(!first)fputs(", ",e->out);emit_expr(e,x);first=0;} fputc(')',e->out); } else fputs("0",e->out);
break;
}
case FE_N_INDEX: {
FeType *bt;
bt=n->a ? n->a->sem_type : 0;
if(n->c || !n->b) {
emit_slice(e,n);
} else {
if (bt && bt->indexer) {
fputs(bt->indexer,e->out); fputc('(',e->out);
emit_expr(e,n->a); fputs(", ",e->out); emit_expr(e,n->b); fputc(')',e->out);
} else fputs("0",e->out);
}
break;
}
case FE_N_UNARY:
op = n->text ? n->text : "";
if (strcmp(op, "not") == 0) fputs("(!", e->out);
@@ -71,21 +402,35 @@ static void emit_expr(FeEmitter *e, FeNode *n)
fputc(')', e->out);
} else emit_expr(e, n->a);
break;
case FE_N_CALL:
if (n->a) emit_expr(e, n->a);
case FE_N_CALL: {
FeVariantType *v;
int special=0;
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->a->kind==FE_N_MEMBER && n->a->a && n->a->a->sem_type && n->a->a->sem_type->kind==FE_TYPE_ENUM) {
v=fe_type_variant(n->a->a->sem_type,n->a->b ? n->a->b->text : "");
if(v) fputs(v->maker,e->out); else fputs("fe_bad_variant",e->out);
} else if (n->a) emit_expr(e, n->a);
else fputs(n->text ? n->text : "fe_builtin", e->out);
fputc('(', e->out);
for (x = n->children; x; x = x->next) {
if (x != n->children) fputs(", ", e->out);
emit_expr(e, x);
if(!special) {
fputc('(', e->out);
for (x = n->children; x; x = x->next) {
if (x != n->children) fputs(", ", e->out);
emit_expr(e, x);
}
fputc(')', e->out);
}
fputc(')', e->out);
break;
case FE_N_MEMBER:
emit_expr(e, n->a);
fputc('.', e->out);
if (n->b) fputs(n->b->text ? n->b->text : "member", e->out);
}
case FE_N_MEMBER: {
FeVariantType *v;
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_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;
}
default:
fputs("0", e->out);
break;
@@ -125,6 +470,38 @@ static void emit_block(FeEmitter *e, FeNode *n)
fputc('}', e->out);
}
static void emit_match(FeEmitter *e, FeNode *n, int value_context)
{
FeNode *arm;
FeType *t=n->a ? n->a->sem_type : 0;
FeVariantType *v;
FeNode *b;
unsigned i;
char temp[32];
sprintf(temp,"fe_match_%u",e->temp_serial++);
pad(e); fputs("{\n",e->out); ++e->indent;
pad(e); fputs(fe_type_c_name(t,e->pointer_bits),e->out); fputc(' ',e->out);
fputs(temp,e->out); fputs(" = ",e->out); emit_expr(e,n->a); fputs(";\n",e->out);
pad(e); fputs("switch (",e->out); fputs(temp,e->out); fputs(".tag) {\n",e->out); ++e->indent;
for(arm=n->children;arm;arm=arm->next) {
if(arm->text && strcmp(arm->text,"_")==0) { pad(e); fputs("default: ",e->out); }
else { v=t && t->kind==FE_TYPE_ENUM ? fe_type_variant(t,arm->text) : 0; if(!v) continue; fprintf(e->out,"case %u: ",v->tag); }
fputs("{\n",e->out); ++e->indent;
v=t && t->kind==FE_TYPE_ENUM ? fe_type_variant(t,arm->text) : 0;
if(v) for(i=0,b=arm->children;i<v->field_count && b;i++,b=b->next) {
pad(e); fputs(fe_type_c_name(v->fields[i].type,e->pointer_bits),e->out); fputc(' ',e->out); fputs(cname(b,"fe_match"),e->out); fputs(" = ",e->out); fputs(temp,e->out); fputs(".payload.",e->out); fputs(v->name,e->out); if(v->field_count>1){fputc('.',e->out);fputs(v->fields[i].name,e->out);} fputs(";\n",e->out);
}
if(arm->a && arm->a->kind==FE_N_BLOCK) emit_stmt(e,arm->a); else { pad(e); emit_expr(e,arm->a); fputs(";\n",e->out); }
pad(e); fputs("break;\n",e->out); --e->indent; pad(e); fputs("}\n",e->out);
}
--e->indent; pad(e); fputs("}\n",e->out);
--e->indent; pad(e); fputs("}\n",e->out);
if (value_context || match_definitely_returns(n)) {
pad(e); fputs("fe_trap_bounds();\n",e->out);
pad(e); fputs("return 0;\n",e->out);
}
}
static void emit_stmt(FeEmitter *e, FeNode *n)
{
if (!n) return;
@@ -145,7 +522,7 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
break;
case FE_N_ASSIGN:
pad(e);
emit_expr(e, n->a);
emit_lvalue(e, n->a);
fputc(' ', e->out);
fputs(n->text ? n->text : "=", e->out);
fputs(" ", e->out);
@@ -159,6 +536,10 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
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);
@@ -189,6 +570,38 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
else emit_block(e, 0);
fputc('\n', e->out);
break;
case FE_N_FOR:
pad(e); fputs("{\n",e->out); ++e->indent;
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);
pad(e); fputs("for (; ",e->out); fputs(cname(n,"fe_index"),e->out); fputs(" < ",e->out); emit_expr(e,n->c); fputs("; ++",e->out); fputs(cname(n,"fe_index"),e->out); fputs(") ",e->out); emit_block(e,n->b); fputc('\n',e->out);
} else {
FeType *bt=n->a ? n->a->sem_type : 0;
FeType *et=bt ? bt->elem : 0;
char temp[32];
int mutable_iter=(n->flags & 4U) != 0;
sprintf(temp,"fe_iter_%u",e->temp_serial++);
pad(e); fputs(fe_type_c_name(bt,e->pointer_bits),e->out); if (mutable_iter) fputs(" *",e->out); fputc(' ',e->out); fputs(temp,e->out); fputs(" = ",e->out); if (mutable_iter) fputc('&',e->out); emit_expr(e,n->a); fputs(";\n",e->out);
if (n->aux_text) {
pad(e); fputs("unsigned long ",e->out); fputs(cname(n,"fe_index"),e->out); fputs(";\n",e->out);
} else {
pad(e); fputs(fe_type_c_name(n->sem_type ? n->sem_type : fe_type_ref(&e->check->types,et,0),e->pointer_bits),e->out); fputc(' ',e->out); fputs(cname(n,"fe_item"),e->out); fputs(";\n",e->out);
}
pad(e); fputs("{ unsigned long fe_i; for (fe_i = 0; fe_i < ",e->out);
if(bt && bt->kind==FE_TYPE_ARRAY) fprintf(e->out,"%lu",bt->length); else { if(mutable_iter) fputs("(*",e->out); fputs(temp,e->out); if(mutable_iter) fputs(").n",e->out); else fputs(".n",e->out); }
fputs("; ++fe_i) { ",e->out);
if(n->aux_text) {
fputs(fe_type_c_name(fe_type_ref(&e->check->types,et,(n->flags & 4U) != 0),e->pointer_bits),e->out); fputc(' ',e->out); fputs(n->aux_cname ? n->aux_cname : "fe_item",e->out); fputs("; ",e->out);
fputs(cname(n,"fe_index"),e->out); fputs(" = fe_i; ",e->out);
fputs(n->aux_cname ? n->aux_cname : "fe_item",e->out); fputs(" = ",e->out);
} else { fputs(cname(n,"fe_item"),e->out); fputs(" = ",e->out); }
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;
case FE_N_MATCH:
emit_match(e,n,0); break;
default:
break;
}
@@ -237,19 +650,28 @@ static void emit_main_wrapper(FeEmitter *e, FeNode *fn)
}
void fe_emit_c_init(FeEmitter *e, FILE *out, FeCheck *check,
unsigned pointer_bits)
unsigned pointer_bits, int no_checks)
{
e->out = out;
e->check = check;
e->pointer_bits = pointer_bits;
e->indent = 0;
e->no_checks = no_checks;
e->temp_serial = 0;
}
void fe_emit_c_program(FeEmitter *e)
{
FeNode *n;
FeNode *main_fn = 0;
fputs("/* generated by fec M2 */\n#include <stddef.h>\n\n", e->out);
fputs("/* generated by fec M3 */\n#include <stddef.h>\n#include <stdlib.h>\ntypedef char fe_assert_u8[(sizeof(unsigned char)==1) ? 1 : -1];\ntypedef char fe_assert_u16[(sizeof(unsigned short)==2) ? 1 : -1];\ntypedef char fe_assert_u32[(sizeof(unsigned long)==4) ? 1 : -1];\n", e->out);
if (e->pointer_bits==16)
fputs("typedef char fe_assert_usize[(sizeof(unsigned short)==2) ? 1 : -1];\n",e->out);
else
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);
emit_type_defs(e);
emit_type_helpers(e);
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
n; n = n->next) {
if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) {