feat: implement M3 aggregate types and iteration
This commit is contained in:
+4
-10
@@ -6,16 +6,10 @@ if exist BUILD.OK del BUILD.OK
|
||||
if exist BUILD.FAIL del BUILD.FAIL
|
||||
if exist fec.exe del fec.exe
|
||||
if exist __wcl__.lnk del __wcl__.lnk
|
||||
if exist arena.obj del arena.obj
|
||||
if exist diag.obj del diag.obj
|
||||
if exist lexer.obj del lexer.obj
|
||||
if exist ast.obj del ast.obj
|
||||
if exist parser.obj del parser.obj
|
||||
if exist types.obj del types.obj
|
||||
if exist check.obj del check.obj
|
||||
if exist emitc.obj del emitc.obj
|
||||
if exist emit_c.obj del emit_c.obj
|
||||
if exist driver.obj del driver.obj
|
||||
rem WCL writes test objects into the current directory. Remove all prior build
|
||||
rem artifacts before the wildcard link so 32-bit test objects cannot enter the
|
||||
rem 16-bit compiler executable.
|
||||
if exist *.obj del *.obj
|
||||
|
||||
if "%WATCOM%"=="" set WATCOM=C:\DEVEL\WATCOMC
|
||||
if not exist %WATCOM%\BINW\WCL.EXE goto build_fail
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ FeNode *fe_node(FeAst *a, FeNodeKind k, FeLoc loc, const char *text, unsigned lo
|
||||
FeNode *n=(FeNode *)fe_arena_alloc(&a->arena,sizeof(FeNode));
|
||||
if (!n) return 0;
|
||||
n->kind=k; n->loc=loc; n->text=text?fe_arena_strdup(&a->arena,text,len):0;
|
||||
n->a=n->b=n->c=n->children=n->next=0; n->cname=0; n->sem_type=0; return n;
|
||||
n->a=n->b=n->c=n->children=n->next=0; n->cname=0; n->aux_text=0; n->aux_cname=0; n->sem_type=0; n->flags=0; return n;
|
||||
}
|
||||
void fe_node_add(FeNode *parent, FeNode *child)
|
||||
{
|
||||
@@ -33,7 +33,7 @@ void fe_ast_dump(const FeNode *n, int indent, FILE *out)
|
||||
}
|
||||
const char *fe_node_name(FeNodeKind k)
|
||||
{
|
||||
static const char *names[] = {"unit","import","fn","struct","enum","error","const","global","field","param","variant","block","let","var","expr-stmt","assign","if","while","for","match","arm","return","break","continue","defer","unsafe","asm","type","expr","binary","unary","call","index","member","literal","ident","struct-init","error"};
|
||||
static const char *names[] = {"unit","import","fn","struct","enum","error","const","global","field","param","variant","block","let","var","expr-stmt","assign","if","while","for","match","arm","return","break","continue","defer","unsafe","asm","type","expr","binary","unary","call","index","member","literal","ident","struct-init","array-init","error"};
|
||||
if ((unsigned)k >= sizeof(names)/sizeof(names[0])) return "node";
|
||||
return names[k];
|
||||
}
|
||||
|
||||
+4
-1
@@ -11,7 +11,7 @@ typedef enum FeNodeKind {
|
||||
FE_N_EXPR_STMT, FE_N_ASSIGN, FE_N_IF, FE_N_WHILE, FE_N_FOR, FE_N_MATCH, FE_N_ARM,
|
||||
FE_N_RETURN, FE_N_BREAK, FE_N_CONTINUE, FE_N_DEFER, FE_N_UNSAFE, FE_N_ASM,
|
||||
FE_N_TYPE, FE_N_EXPR, FE_N_BINARY, FE_N_UNARY, FE_N_CALL, FE_N_INDEX, FE_N_MEMBER,
|
||||
FE_N_LITERAL, FE_N_IDENT, FE_N_STRUCT_INIT, FE_N_ERROR_NODE
|
||||
FE_N_LITERAL, FE_N_IDENT, FE_N_STRUCT_INIT, FE_N_ARRAY_INIT, FE_N_ERROR_NODE
|
||||
} FeNodeKind;
|
||||
|
||||
typedef struct FeNode FeNode;
|
||||
@@ -27,7 +27,10 @@ struct FeNode {
|
||||
FeNode *next;
|
||||
/* Semantic information filled by checking; kept out of AST dumps. */
|
||||
char *cname;
|
||||
char *aux_text;
|
||||
char *aux_cname;
|
||||
FeType *sem_type;
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
typedef struct FeAst {
|
||||
|
||||
+358
-8
@@ -45,6 +45,25 @@ static int known(FeType *t)
|
||||
|
||||
static int compatible(FeType *want, FeType *got, FeNode *value)
|
||||
{
|
||||
FeNode *item;
|
||||
unsigned long count;
|
||||
if (want && got && value && value->kind==FE_N_ARRAY_INIT &&
|
||||
want->kind==FE_TYPE_ARRAY && got->kind==FE_TYPE_ARRAY) {
|
||||
if (want->length != got->length) return 0;
|
||||
count=0;
|
||||
for (item=value->children; item; item=item->next) {
|
||||
if (!compatible(want->elem,item->sem_type,item)) return 0;
|
||||
if (item->kind==FE_N_LITERAL && item->text &&
|
||||
fe_type_is_integer(want->elem) &&
|
||||
fe_type_is_integer(item->sem_type) &&
|
||||
item->text[0]!='\'' && item->text[0]!='"')
|
||||
item->sem_type=want->elem;
|
||||
++count;
|
||||
}
|
||||
if (count!=want->length) return 0;
|
||||
value->sem_type=want;
|
||||
return 1;
|
||||
}
|
||||
if (fe_type_equal(want, got)) return 1;
|
||||
if (!known(want) || !known(got)) return 1;
|
||||
return fe_type_is_integer(want) && fe_type_is_integer(got) && value &&
|
||||
@@ -52,6 +71,13 @@ static int compatible(FeType *want, FeType *got, FeNode *value)
|
||||
value->text[0] != '\'' && value->text[0] != '"';
|
||||
}
|
||||
|
||||
static int explicit_castable(FeType *a, FeType *b)
|
||||
{
|
||||
if (!a || !b) return 0;
|
||||
return (fe_type_is_integer(a) || a->kind == FE_TYPE_CHAR) &&
|
||||
(fe_type_is_integer(b) || b->kind == FE_TYPE_CHAR);
|
||||
}
|
||||
|
||||
static FeType *node_type(FeCheck *c, FeNode *n)
|
||||
{
|
||||
FeType *t;
|
||||
@@ -174,22 +200,114 @@ static FeSym *add_symbol(FeCheckerState *s, FeScope *scope,
|
||||
}
|
||||
|
||||
void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags,
|
||||
unsigned pointer_bits)
|
||||
unsigned pointer_bits, int no_checks)
|
||||
{
|
||||
c->ast = ast;
|
||||
c->diags = diags;
|
||||
c->pointer_bits = pointer_bits;
|
||||
c->local_serial = 0;
|
||||
c->no_checks = no_checks;
|
||||
fe_types_init(&c->types, &ast->arena, pointer_bits);
|
||||
c->types.unit_name = ast->root && ast->root->text ? ast->root->text : "unit";
|
||||
}
|
||||
|
||||
static FeType *check_expr(FeCheckerState *s, FeNode *n);
|
||||
static void check_match(FeCheckerState *s, FeNode *n);
|
||||
static void check_stmt(FeCheckerState *s, FeNode *n);
|
||||
|
||||
static int lvalue_writable(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeSym *sym;
|
||||
FeType *t;
|
||||
if (!n) return 0;
|
||||
if (n->kind == FE_N_IDENT) {
|
||||
sym=find_symbol(s->scope,n->text ? n->text : "");
|
||||
return sym ? sym->mutable : 0;
|
||||
}
|
||||
if (n->kind == FE_N_MEMBER) {
|
||||
t=n->a ? n->a->sem_type : 0;
|
||||
if (t && t->kind==FE_TYPE_REF && n->b && n->b->text &&
|
||||
strcmp(n->b->text,"^")==0) return t->ref_mut;
|
||||
return lvalue_writable(s,n->a);
|
||||
}
|
||||
if (n->kind == FE_N_INDEX) return lvalue_writable(s,n->a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int has_field(FeNode *list, const char *name)
|
||||
{
|
||||
FeNode *f;
|
||||
for (f=list; f; f=f->next)
|
||||
if (f->text && name && strcmp(f->text,name)==0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FeType *check_struct_init(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeType *t;
|
||||
FeFieldType *field;
|
||||
FeNode *f;
|
||||
FeType *v;
|
||||
FeType *et;
|
||||
FeVariantType *variant;
|
||||
unsigned i;
|
||||
if (n->a && n->a->kind == FE_N_MEMBER) {
|
||||
et=check_expr(s,n->a->a);
|
||||
variant=et && et->kind==FE_TYPE_ENUM ?
|
||||
fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0;
|
||||
if (!variant) { err(s->c,n->loc,"invalid enum variant"); return unknown(s->c); }
|
||||
if (variant->field_count != 0) {
|
||||
for (f=n->children; f; f=f->next) {
|
||||
if (f->kind != FE_N_FIELD) continue;
|
||||
field=0;
|
||||
if (variant->fields) {
|
||||
unsigned i;
|
||||
for(i=0;i<variant->field_count;i++) if(strcmp(variant->fields[i].name,f->text)==0) field=&variant->fields[i];
|
||||
}
|
||||
if (!field) { err(s->c,f->loc,"invalid enum payload field"); continue; }
|
||||
v=check_expr(s,f->a);
|
||||
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");
|
||||
n->sem_type=et; return et;
|
||||
}
|
||||
t=fe_type_intern(&s->c->types,n->text ? n->text : "<unknown>");
|
||||
if (!t || t->kind!=FE_TYPE_STRUCT) { err(s->c,n->loc,"unknown struct type"); return unknown(s->c); }
|
||||
for(f=n->children;f;f=f->next) if(f->kind==FE_N_FIELD) {
|
||||
if(has_field(f->next,f->text)) { err(s->c,f->loc,"duplicate struct field"); }
|
||||
field=fe_type_field(t,f->text);
|
||||
if(!field) { err(s->c,f->loc,"invalid struct field"); continue; }
|
||||
v=check_expr(s,f->a);
|
||||
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");
|
||||
n->sem_type=t; return t;
|
||||
}
|
||||
|
||||
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; }
|
||||
if(!elem) elem=unknown(s->c);
|
||||
n->sem_type=fe_type_array(&s->c->types,count,elem); return n->sem_type;
|
||||
}
|
||||
|
||||
static FeType *check_index(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeType *base=check_expr(s,n->a); FeType *idx; FeType *elem;
|
||||
if(!fe_type_is_indexable(base)) { err(s->c,n->loc,"indexing requires an array or slice"); return unknown(s->c); }
|
||||
if(n->b) { idx=check_expr(s,n->b); if(known(idx)&&!fe_type_is_integer(idx)) err(s->c,n->loc,"index must be an integer"); }
|
||||
if(n->c || !n->b) { if(n->c) { idx=check_expr(s,n->c); if(known(idx)&&!fe_type_is_integer(idx)) err(s->c,n->loc,"slice bound must be an integer"); } elem=base->elem; n->sem_type=fe_type_slice(&s->c->types,elem); if(base->kind==FE_TYPE_STR) n->flags|=2U; return n->sem_type; }
|
||||
n->sem_type=base->elem; return n->sem_type;
|
||||
}
|
||||
|
||||
static FeType *check_identifier(FeCheckerState *s, FeNode *n, int read)
|
||||
{
|
||||
FeSym *sym;
|
||||
sym = find_symbol(s->scope, n->text ? n->text : "");
|
||||
if (!sym) {
|
||||
FeType *named=fe_type_intern(&s->c->types,n->text ? n->text : "");
|
||||
if(named->kind==FE_TYPE_STRUCT || named->kind==FE_TYPE_ENUM) { n->sem_type=named; return named; }
|
||||
err(s->c, n->loc, "unknown name");
|
||||
return unknown(s->c);
|
||||
}
|
||||
@@ -209,6 +327,9 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
FeNode *x;
|
||||
FeNode *param;
|
||||
FeNode *arg;
|
||||
FeType *et;
|
||||
FeFieldType *field;
|
||||
FeVariantType *variant;
|
||||
const char *op;
|
||||
if (!n) return unknown(c);
|
||||
if (n->kind == FE_N_IDENT)
|
||||
@@ -218,14 +339,18 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
if (strcmp(n->text, "true") == 0 || strcmp(n->text, "false") == 0)
|
||||
a = fe_type_intern(&c->types, "bool");
|
||||
else if (n->text[0] == '\'')
|
||||
a = fe_type_intern(&c->types, "u8");
|
||||
a = fe_type_intern(&c->types, "char");
|
||||
else if (n->text[0] == '"')
|
||||
a = unknown(c);
|
||||
a = fe_type_intern(&c->types, "str");
|
||||
else
|
||||
a = fe_type_intern(&c->types, "i32");
|
||||
n->sem_type = a;
|
||||
return a;
|
||||
}
|
||||
if (n->kind == FE_N_STRUCT_INIT) return check_struct_init(s,n);
|
||||
if (n->kind == FE_N_ARRAY_INIT) return check_array_init(s,n);
|
||||
if (n->kind == FE_N_INDEX) return check_index(s,n);
|
||||
if (n->kind == FE_N_MATCH) { check_match(s,n); n->sem_type=unknown(c); return n->sem_type; }
|
||||
if (n->kind == FE_N_UNARY) {
|
||||
a = check_expr(s, n->a);
|
||||
op = n->text ? n->text : "";
|
||||
@@ -245,9 +370,8 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
b = node_type(c, n->b);
|
||||
if (b->kind == FE_TYPE_VOID)
|
||||
err(c, n->loc, "cast target cannot be void");
|
||||
else if ((known(a) && !fe_type_is_integer(a)) ||
|
||||
(known(b) && !fe_type_is_integer(b)))
|
||||
err(c, n->loc, "'as' requires integer types");
|
||||
else if (known(a) && known(b) && !explicit_castable(a,b))
|
||||
err(c, n->loc, "'as' requires integer or char types");
|
||||
n->sem_type = b;
|
||||
return b;
|
||||
}
|
||||
@@ -279,6 +403,24 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
return a;
|
||||
}
|
||||
if (n->kind == FE_N_CALL) {
|
||||
if (!n->a && n->text && (strcmp(n->text,"@size_of")==0 || strcmp(n->text,"@align_of")==0)) {
|
||||
FeNode *type_arg=n->children;
|
||||
FeType *target=type_arg && type_arg->kind==FE_N_IDENT ? fe_type_intern(&c->types,type_arg->text) : unknown(c);
|
||||
if(!target || !known(target)) err(c,n->loc,"size/align requires a known type");
|
||||
n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type;
|
||||
}
|
||||
if (n->a && n->a->kind == FE_N_MEMBER) {
|
||||
et=check_expr(s,n->a->a);
|
||||
variant=et && et->kind==FE_TYPE_ENUM ?
|
||||
fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0;
|
||||
arg=n->children;
|
||||
if (!variant) { err(c,n->loc,"invalid enum variant constructor"); return unknown(c); }
|
||||
if (variant->field_count==1 && arg) {
|
||||
FeType *av=check_expr(s,arg);
|
||||
if(!compatible(variant->fields[0].type,av,arg)&&av->kind!=FE_TYPE_UNKNOWN) err(c,arg->loc,"enum payload type mismatch");
|
||||
} else if (variant->field_count != 0 || arg) err(c,n->loc,"wrong enum payload arity");
|
||||
n->sem_type=et; return et;
|
||||
}
|
||||
if (n->a && n->a->kind == FE_N_IDENT) {
|
||||
sym = find_symbol(s->scope, n->a->text ? n->a->text : "");
|
||||
if (!sym) {
|
||||
@@ -310,7 +452,25 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
return unknown(c);
|
||||
}
|
||||
if (n->kind == FE_N_MEMBER) {
|
||||
check_expr(s, n->a);
|
||||
a=check_expr(s,n->a);
|
||||
if (a->kind == FE_TYPE_REF && 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); }
|
||||
n->sem_type=field->type; return field->type;
|
||||
}
|
||||
if(a->kind==FE_TYPE_ENUM) {
|
||||
if(!fe_type_variant(a,n->b ? n->b->text : "")) err(c,n->loc,"unknown enum variant");
|
||||
n->sem_type=a; return a;
|
||||
}
|
||||
if((a->kind==FE_TYPE_SLICE || a->kind==FE_TYPE_STR) && n->b &&
|
||||
strcmp(n->b->text,"n")==0) {
|
||||
n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type;
|
||||
}
|
||||
return unknown(c);
|
||||
}
|
||||
return unknown(c);
|
||||
@@ -319,6 +479,8 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
|
||||
{
|
||||
FeSym *sym;
|
||||
FeType *base;
|
||||
FeFieldType *field;
|
||||
if (n && n->kind == FE_N_IDENT) {
|
||||
sym = find_symbol(s->scope, n->text ? n->text : "");
|
||||
if (!sym) {
|
||||
@@ -337,6 +499,32 @@ static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
|
||||
err(s->c, n->loc, "use of uninitialized variable");
|
||||
return sym->type;
|
||||
}
|
||||
if (n && n->kind == FE_N_MEMBER) {
|
||||
base=check_expr(s,n->a);
|
||||
if (base && base->kind == FE_TYPE_REF && n->b && n->b->text &&
|
||||
strcmp(n->b->text,"^")==0) {
|
||||
if (!base->ref_mut)
|
||||
err(s->c,n->loc,"cannot write through shared reference");
|
||||
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;
|
||||
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 (n && n->kind == FE_N_INDEX) {
|
||||
if (n->a && n->a->sem_type && n->a->sem_type->kind == FE_TYPE_STR) {
|
||||
err(s->c, n->loc, "str is immutable");
|
||||
}
|
||||
if (n->a && n->a->kind == FE_N_INDEX && (n->a->flags & 2U))
|
||||
err(s->c, n->loc, "str slice is immutable");
|
||||
if (!lvalue_writable(s,n->a))
|
||||
err(s->c,n->loc,"cannot assign through immutable value");
|
||||
base=check_index(s,n);
|
||||
return base;
|
||||
}
|
||||
if (n) err(s->c, n->loc, "assignment requires a variable");
|
||||
return unknown(s->c);
|
||||
}
|
||||
@@ -346,6 +534,153 @@ static int compound_operator(const char *op)
|
||||
return op && strcmp(op, "=") != 0;
|
||||
}
|
||||
|
||||
static void check_match(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeType *value;
|
||||
FeNode *arm;
|
||||
FeVariantType *variant;
|
||||
int seen[256];
|
||||
int wildcard=0;
|
||||
unsigned i;
|
||||
for(i=0;i<256U;i++) seen[i]=0;
|
||||
value=check_expr(s,n->a);
|
||||
if(!value || value->kind!=FE_TYPE_ENUM) { err(s->c,n->loc,"match requires an enum value"); return; }
|
||||
for(arm=n->children;arm;arm=arm->next) {
|
||||
FeScope *old=s->scope;
|
||||
if(arm->text && strcmp(arm->text,"_")==0) wildcard=1;
|
||||
else {
|
||||
variant=fe_type_variant(value,arm->text);
|
||||
if(!variant) { err(s->c,arm->loc,"unknown match variant"); continue; }
|
||||
if(variant->tag<256U) {
|
||||
if(seen[variant->tag]) err(s->c,arm->loc,"duplicate match variant");
|
||||
seen[variant->tag]=1;
|
||||
}
|
||||
s->scope=scope_new(s,old);
|
||||
if(variant->field_count==1 && arm->children) {
|
||||
add_symbol(s,s->scope,arm->children->text,variant->fields[0].type,0,0,1,
|
||||
local_cname(s->c,arm->children->text),arm->children);
|
||||
} else if(variant->field_count>0) {
|
||||
FeNode *b=arm->children;
|
||||
for(i=0;i<variant->field_count && b;i++,b=b->next) {
|
||||
FeFieldType *f=&variant->fields[i];
|
||||
add_symbol(s,s->scope,b->text,f->type,0,0,1,
|
||||
local_cname(s->c,b->text),b);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(arm->a && arm->a->kind==FE_N_BLOCK) check_stmt(s,arm->a);
|
||||
else if(arm->a) check_expr(s,arm->a);
|
||||
s->scope=old;
|
||||
}
|
||||
if(!wildcard) for(i=0;i<value->variant_count && i<256U;i++) if(!seen[i]) err(s->c,n->loc,"non-exhaustive match");
|
||||
}
|
||||
|
||||
static void check_for(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeType *start;
|
||||
FeType *finish;
|
||||
FeType *elem;
|
||||
FeType *ref_type;
|
||||
FeSym *iter_sym;
|
||||
char *index_cname;
|
||||
char *item_cname;
|
||||
int iter_mut;
|
||||
FeScope *old=s->scope;
|
||||
if(!n->c) {
|
||||
start=check_expr(s,n->a);
|
||||
if (!fe_type_is_indexable(start)) {
|
||||
err(s->c,n->loc,"for iterable must be an array, slice, or str");
|
||||
return;
|
||||
}
|
||||
elem=start->elem;
|
||||
iter_sym=0;
|
||||
if (n->a && n->a->kind==FE_N_IDENT)
|
||||
iter_sym=find_symbol(s->scope,n->a->text ? n->a->text : "");
|
||||
else if (n->a && n->a->kind==FE_N_INDEX && n->a->a &&
|
||||
n->a->a->kind==FE_N_IDENT)
|
||||
iter_sym=find_symbol(s->scope,n->a->a->text ? n->a->a->text : "");
|
||||
iter_mut=iter_sym && iter_sym->mutable;
|
||||
if (start->kind==FE_TYPE_STR) iter_mut=0;
|
||||
ref_type=fe_type_ref(&s->c->types,elem,iter_mut);
|
||||
if (iter_mut) n->flags |= 4U;
|
||||
s->scope=scope_new(s,old);
|
||||
if (n->aux_text) {
|
||||
index_cname=local_cname(s->c,n->text ? n->text : "index");
|
||||
item_cname=local_cname(s->c,n->aux_text);
|
||||
add_symbol(s,s->scope,n->text,fe_type_intern(&s->c->types,"usize"),0,0,1,
|
||||
index_cname,n);
|
||||
add_symbol(s,s->scope,n->aux_text,ref_type,0,iter_mut,1,
|
||||
item_cname,0);
|
||||
n->cname=index_cname;
|
||||
n->aux_cname=item_cname;
|
||||
} else {
|
||||
item_cname=local_cname(s->c,n->text ? n->text : "item");
|
||||
add_symbol(s,s->scope,n->text,ref_type,0,iter_mut,1,
|
||||
item_cname,n);
|
||||
n->cname=item_cname;
|
||||
}
|
||||
check_stmt(s,n->b);
|
||||
s->scope=old;
|
||||
return;
|
||||
}
|
||||
start=check_expr(s,n->a);
|
||||
finish=check_expr(s,n->c);
|
||||
if(known(start)&&!fe_type_is_integer(start)) err(s->c,n->loc,"range start must be integer");
|
||||
if(known(finish)&&!fe_type_is_integer(finish)) err(s->c,n->loc,"range end must be integer");
|
||||
s->scope=scope_new(s,old);
|
||||
index_cname=local_cname(s->c,n->text ? n->text : "index");
|
||||
add_symbol(s,s->scope,n->text,fe_type_intern(&s->c->types,"usize"),0,0,1,
|
||||
index_cname,n);
|
||||
n->cname=index_cname;
|
||||
check_stmt(s,n->b);
|
||||
s->scope=old;
|
||||
}
|
||||
|
||||
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_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;
|
||||
if (t->cycle_state == 1) {
|
||||
if (c->ast->root) err(c, c->ast->root->loc, "by-value recursive type");
|
||||
return;
|
||||
}
|
||||
if (t->cycle_state == 2) return;
|
||||
t->cycle_state = 1;
|
||||
if (t->kind == FE_TYPE_ARRAY) {
|
||||
check_type_cycle(c,t->elem);
|
||||
} else if (t->kind == FE_TYPE_STRUCT) {
|
||||
for (i=0;i<t->field_count;i++) {
|
||||
if (!t->fields[i].type && t->fields[i].ast_node)
|
||||
t->fields[i].type=fe_type_from_ast(&c->types,t->fields[i].ast_node->a);
|
||||
check_type_cycle(c,t->fields[i].type);
|
||||
}
|
||||
} else 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 (!t->variants[i].fields[j].type && t->variants[i].fields[j].ast_node)
|
||||
t->variants[i].fields[j].type=fe_type_from_ast(&c->types,
|
||||
t->variants[i].fields[j].ast_node->a);
|
||||
next=t->variants[i].fields[j].type;
|
||||
check_type_cycle(c,next);
|
||||
}
|
||||
}
|
||||
}
|
||||
t->cycle_state=2;
|
||||
}
|
||||
|
||||
static void check_type_cycles(FeCheck *c)
|
||||
{
|
||||
FeType *t;
|
||||
for (t=c->types.types;t;t=t->next) t->cycle_state=0;
|
||||
for (t=c->types.types;t;t=t->next) check_type_cycle(c,t);
|
||||
}
|
||||
|
||||
static void check_stmt(FeCheckerState *s, FeNode *n)
|
||||
{
|
||||
FeCheck *c = s->c;
|
||||
@@ -418,12 +753,19 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
|
||||
err(c, n->loc, "while condition must be bool");
|
||||
check_stmt(s, n->b);
|
||||
break;
|
||||
case FE_N_FOR:
|
||||
check_for(s,n);
|
||||
break;
|
||||
case FE_N_MATCH:
|
||||
check_match(s,n);
|
||||
break;
|
||||
case FE_N_RETURN:
|
||||
b = n->a ? check_expr(s, n->a) : fe_type_intern(&c->types, "void");
|
||||
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) &&
|
||||
b->kind != FE_TYPE_UNKNOWN)
|
||||
b->kind != FE_TYPE_UNKNOWN &&
|
||||
!compatible(s->ret,b,n->a))
|
||||
err(c, n->loc, "return type mismatch");
|
||||
break;
|
||||
case FE_N_UNSAFE:
|
||||
@@ -468,6 +810,13 @@ int fe_check_program(FeCheck *c)
|
||||
s.scope = scope_new(&s, 0);
|
||||
s.globals = s.scope;
|
||||
s.ret = fe_type_intern(&c->types, "void");
|
||||
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
|
||||
if (n->kind == FE_N_STRUCT)
|
||||
fe_type_declare_struct(&c->types, n, (n->flags & 1U) != 0);
|
||||
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
|
||||
if (n->kind == FE_N_ENUM) fe_type_declare_enum(&c->types, n);
|
||||
check_type_cycles(c);
|
||||
fe_type_layout_all(&c->types);
|
||||
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) {
|
||||
if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) {
|
||||
t = n->a ? node_type(c, n->a) : unknown(c);
|
||||
@@ -501,6 +850,7 @@ int fe_check_program(FeCheck *c)
|
||||
}
|
||||
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);
|
||||
fe_type_layout_all(&c->types);
|
||||
return c->diags->errors == 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -10,9 +10,11 @@ typedef struct FeCheck {
|
||||
FeDiags *diags;
|
||||
unsigned pointer_bits;
|
||||
unsigned local_serial;
|
||||
int no_checks;
|
||||
} FeCheck;
|
||||
|
||||
void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags, unsigned pointer_bits);
|
||||
void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags,
|
||||
unsigned pointer_bits, int no_checks);
|
||||
int fe_check_program(FeCheck *c);
|
||||
FeType *fe_check_expr_type(FeCheck *c, FeNode *n);
|
||||
|
||||
|
||||
+4
-4
@@ -17,15 +17,15 @@ static void usage(void)
|
||||
{ puts("usage: fec [--dump-ast|--emit-c] file.fe [--target=bits16|bits32] [-o output.c]"); }
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i,dump=0,emit=0; const char *file=0,*outname=0; unsigned long n; char *src; FeDiags d; FeAst ast; FeParser p; FeCheck check; FeEmitter emitter; FILE *out; unsigned pointer_bits=32;
|
||||
int i,dump=0,emit=0,no_checks=0; const char *file=0,*outname=0; unsigned long n; char *src; FeDiags d; FeAst ast; FeParser p; FeCheck check; FeEmitter emitter; FILE *out; unsigned pointer_bits=32;
|
||||
(void)emit;
|
||||
if(argc<2){usage();return 2;}
|
||||
for(i=1;i<argc;i++) { if(strcmp(argv[i],"--dump-ast")==0) dump=1; else if(strcmp(argv[i],"--emit-c")==0) emit=1; else if(strcmp(argv[i],"-o")==0){if(i+1>=argc){fprintf(stderr,"fec: -o needs a path\n");return 2;}outname=argv[++i];} else if(strncmp(argv[i],"-o",2)==0 && argv[i][2]) outname=argv[i]+2; else if(strncmp(argv[i],"--target=bits16",15)==0) pointer_bits=16; else if(strncmp(argv[i],"--target=bits32",15)==0) pointer_bits=32; else if(strncmp(argv[i],"--target=",9)==0 || strncmp(argv[i],"--model=",8)==0 || strcmp(argv[i],"--no-checks")==0 || strcmp(argv[i],"--strip-error-names")==0) { } else if(argv[i][0]!='-') file=argv[i]; else if(strcmp(argv[i],"--help")==0){usage();return 0;} else {fprintf(stderr,"fec: unknown option %s\n",argv[i]);return 2;} }
|
||||
for(i=1;i<argc;i++) { if(strcmp(argv[i],"--dump-ast")==0) dump=1; else if(strcmp(argv[i],"--emit-c")==0) emit=1; else if(strcmp(argv[i],"-o")==0){if(i+1>=argc){fprintf(stderr,"fec: -o needs a path\n");return 2;}outname=argv[++i];} else if(strncmp(argv[i],"-o",2)==0 && argv[i][2]) outname=argv[i]+2; else if(strncmp(argv[i],"--target=bits16",15)==0) pointer_bits=16; else if(strncmp(argv[i],"--target=bits32",15)==0) pointer_bits=32; else if(strcmp(argv[i],"--no-checks")==0) no_checks=1; else if(strncmp(argv[i],"--target=",9)==0 || strncmp(argv[i],"--model=",8)==0 || strcmp(argv[i],"--strip-error-names")==0) { } else if(argv[i][0]!='-') file=argv[i]; else if(strcmp(argv[i],"--help")==0){usage();return 0;} else {fprintf(stderr,"fec: unknown option %s\n",argv[i]);return 2;} }
|
||||
if(!file){fprintf(stderr,"fec: no input file\n");return 2;}
|
||||
src=read_file(file,&n);if(!src)return 2;d.errors=0;d.warnings=0;fe_ast_init(&ast);fe_parser_init(&p,&ast,src,n,file,&d);ast.root=fe_parse_unit(&p);
|
||||
if(dump) { fe_ast_dump(ast.root,0,stdout); fe_ast_destroy(&ast); free(src); return d.errors?1:0; }
|
||||
fe_check_init(&check,&ast,&d,pointer_bits); if(!fe_check_program(&check)){fe_ast_destroy(&ast);free(src);return 1;}
|
||||
fe_check_init(&check,&ast,&d,pointer_bits,no_checks); if(!fe_check_program(&check)){fe_ast_destroy(&ast);free(src);return 1;}
|
||||
out=outname?fopen(outname,"w"):stdout; if(!out){fprintf(stderr,"fec: cannot create %s\n",outname);fe_ast_destroy(&ast);free(src);return 2;}
|
||||
fe_emit_c_init(&emitter,out,&check,pointer_bits);fe_emit_c_program(&emitter);if(outname)fclose(out);
|
||||
fe_emit_c_init(&emitter,out,&check,pointer_bits,no_checks);fe_emit_c_program(&emitter);if(outname)fclose(out);
|
||||
fe_ast_destroy(&ast); free(src); return d.errors?1:0;
|
||||
}
|
||||
|
||||
+431
-9
@@ -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);
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
||||
+4
-1
@@ -8,9 +8,12 @@ typedef struct FeEmitter {
|
||||
FeCheck *check;
|
||||
unsigned pointer_bits;
|
||||
int indent;
|
||||
int no_checks;
|
||||
unsigned temp_serial;
|
||||
} FeEmitter;
|
||||
|
||||
void fe_emit_c_init(FeEmitter *e, FILE *out, FeCheck *check, unsigned pointer_bits);
|
||||
void fe_emit_c_init(FeEmitter *e, FILE *out, FeCheck *check,
|
||||
unsigned pointer_bits, int no_checks);
|
||||
void fe_emit_c_program(FeEmitter *e);
|
||||
|
||||
#endif
|
||||
|
||||
+101
-15
@@ -11,13 +11,14 @@ static int want(FeParser *p, FeTokKind k, const char *what)
|
||||
{ if(eat(p,k)) return 1; error(p,what); return 0; }
|
||||
static int is_name(FeParser *p) { return is(p,FE_TOK_IDENT)||is(p,FE_TOK_SELF)||is(p,FE_TOK_SELFTYPE); }
|
||||
static FeNode *expr(FeParser *p, int minprec);
|
||||
static FeNode *delimited_expr(FeParser *p);
|
||||
static FeNode *type(FeParser *p);
|
||||
static FeNode *statement(FeParser *p);
|
||||
static FeNode *block(FeParser *p);
|
||||
|
||||
void fe_parser_init(FeParser *p, FeAst *ast, const char *src, unsigned long length, const char *file, FeDiags *d)
|
||||
{
|
||||
p->ast=ast; p->diags=d; fe_lexer_init(&p->lexer,src,length,file,d);
|
||||
p->ast=ast; p->diags=d; p->forbid_struct_literal=0; fe_lexer_init(&p->lexer,src,length,file,d);
|
||||
p->previous=p->current=fe_lexer_next(&p->lexer);
|
||||
}
|
||||
|
||||
@@ -81,10 +82,19 @@ static int precedence(FeTokKind k)
|
||||
static FeNode *primary(FeParser *p)
|
||||
{
|
||||
FeToken t=p->current; FeNode *n;
|
||||
if (is(p,FE_TOK_LBRACKET)) {
|
||||
FeNode *a=toknode(p,FE_N_ARRAY_INIT,t); next(p);
|
||||
while(!is(p,FE_TOK_RBRACKET)&&!is(p,FE_TOK_EOF)) {
|
||||
fe_node_add(a,delimited_expr(p));
|
||||
if(!eat(p,FE_TOK_COMMA)) break;
|
||||
}
|
||||
want(p,FE_TOK_RBRACKET,"expected ']' after array literal");
|
||||
return a;
|
||||
}
|
||||
if(is(p,FE_TOK_INT)||is(p,FE_TOK_CHAR)||is(p,FE_TOK_STRING)||is(p,FE_TOK_TRUE)||is(p,FE_TOK_FALSE)||is(p,FE_TOK_NULL)||is(p,FE_TOK_UNDEFINED)) {next(p);return toknode(p,FE_N_LITERAL,t);}
|
||||
if(is_name(p) || is(p,FE_TOK_ERROR_KW)) {
|
||||
next(p); n=toknode(p,FE_N_IDENT,t);
|
||||
if(is(p,FE_TOK_LBRACE)) {
|
||||
if(is(p,FE_TOK_LBRACE) && !p->forbid_struct_literal) {
|
||||
FeNode *s=toknode(p,FE_N_STRUCT_INIT,t); next(p);
|
||||
while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)) { FeNode *f;
|
||||
if(!is_name(p)){error(p,"expected field name");recover(p);break;} f=toknode(p,FE_N_FIELD,p->current);next(p);want(p,FE_TOK_COLON,"expected ':' after field");f->a=expr(p,0);fe_node_add(s,f);if(!eat(p,FE_TOK_COMMA))break;
|
||||
@@ -92,11 +102,11 @@ static FeNode *primary(FeParser *p)
|
||||
}
|
||||
return n;
|
||||
}
|
||||
if(eat(p,FE_TOK_LPAREN)) { n=expr(p,0); want(p,FE_TOK_RPAREN,"expected ')'"); return n; }
|
||||
if(eat(p,FE_TOK_LPAREN)) { int old=p->forbid_struct_literal; p->forbid_struct_literal=0; n=expr(p,0); p->forbid_struct_literal=old; want(p,FE_TOK_RPAREN,"expected ')'"); return n; }
|
||||
if(eat(p,FE_TOK_AT)) {
|
||||
FeToken name=p->current; if(!is_name(p)){error(p,"expected builtin name after '@'");return fe_node(p->ast,FE_N_ERROR_NODE,t.loc,"builtin",7);} next(p);
|
||||
n=toknode(p,FE_N_CALL,name); n->text=fe_arena_strdup(&p->ast->arena,name.begin-1,name.length+1);
|
||||
if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,expr(p,0));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after builtin");}
|
||||
if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,delimited_expr(p));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after builtin");}
|
||||
return n;
|
||||
}
|
||||
error(p,"expected expression"); next(p); return fe_node(p->ast,FE_N_ERROR_NODE,t.loc,"expression",10);
|
||||
@@ -106,9 +116,29 @@ static FeNode *postfix(FeParser *p)
|
||||
FeNode *n=primary(p);
|
||||
for(;;) {
|
||||
FeToken t=p->current; FeNode *m;
|
||||
if(eat(p,FE_TOK_LPAREN)) { m=toknode(p,FE_N_CALL,t); m->a=n; while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(m,expr(p,0));if(!eat(p,FE_TOK_COMMA))break;} want(p,FE_TOK_RPAREN,"expected ')' after call"); n=m; }
|
||||
else if(eat(p,FE_TOK_LBRACKET)) { m=toknode(p,FE_N_INDEX,t);m->a=n;m->b=expr(p,0);if(eat(p,FE_TOK_DOTDOT)){m->c=expr(p,0);}want(p,FE_TOK_RBRACKET,"expected ']' after index");n=m; }
|
||||
else if(eat(p,FE_TOK_DOT)) { m=toknode(p,FE_N_MEMBER,t);m->a=n;if(is_name(p)){m->b=toknode(p,FE_N_IDENT,p->current);next(p);}else if(eat(p,FE_TOK_QUESTION)){m->text=fe_arena_strdup(&p->ast->arena,".?",2);}else error(p,"expected member name");n=m; }
|
||||
if(eat(p,FE_TOK_LPAREN)) { m=toknode(p,FE_N_CALL,t); m->a=n; while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(m,delimited_expr(p));if(!eat(p,FE_TOK_COMMA))break;} want(p,FE_TOK_RPAREN,"expected ')' after call"); n=m; }
|
||||
else if(eat(p,FE_TOK_LBRACKET)) {
|
||||
m=toknode(p,FE_N_INDEX,t);m->a=n;
|
||||
if(is(p,FE_TOK_DOTDOT)) m->b=0; else m->b=delimited_expr(p);
|
||||
if(eat(p,FE_TOK_DOTDOT)) { if(!is(p,FE_TOK_RBRACKET)) m->c=delimited_expr(p); }
|
||||
want(p,FE_TOK_RBRACKET,"expected ']' after index");n=m;
|
||||
}
|
||||
else if(eat(p,FE_TOK_DOT)) {
|
||||
m=toknode(p,FE_N_MEMBER,t);m->a=n;
|
||||
if(is_name(p)){m->b=toknode(p,FE_N_IDENT,p->current);next(p);}
|
||||
else if(eat(p,FE_TOK_QUESTION)){m->text=fe_arena_strdup(&p->ast->arena,".?",2);}
|
||||
else if(eat(p,FE_TOK_XOR)){m->text=fe_arena_strdup(&p->ast->arena,".^",2);m->b=fe_node(p->ast,FE_N_IDENT,p->previous.loc,"^",1);}
|
||||
else error(p,"expected member name");
|
||||
n=m;
|
||||
if(is(p,FE_TOK_LBRACE) && !p->forbid_struct_literal) {
|
||||
FeNode *s=toknode(p,FE_N_STRUCT_INIT,t); s->a=n; next(p);
|
||||
while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)) { FeNode *f;
|
||||
if(!is_name(p)){error(p,"expected variant field");recover(p);break;}
|
||||
f=toknode(p,FE_N_FIELD,p->current);next(p);want(p,FE_TOK_COLON,"expected ':' after variant field");f->a=expr(p,0);fe_node_add(s,f);if(!eat(p,FE_TOK_COMMA))break;
|
||||
}
|
||||
want(p,FE_TOK_RBRACE,"expected '}' in variant constructor");n=s;
|
||||
}
|
||||
}
|
||||
else if(eat(p,FE_TOK_AS)) { m=toknode(p,FE_N_TYPE,t);m->a=n;m->b=type(p);n=m; }
|
||||
else break;
|
||||
}
|
||||
@@ -123,6 +153,29 @@ static FeNode *expr(FeParser *p, int minprec)
|
||||
return left;
|
||||
}
|
||||
|
||||
/* A control-flow header is followed by a body '{'. Do not let that body
|
||||
brace be consumed as the postfix struct-literal brace; callers can use
|
||||
parentheses when a struct literal is intended in the header. */
|
||||
static FeNode *header_expr(FeParser *p)
|
||||
{
|
||||
FeNode *n;
|
||||
int old=p->forbid_struct_literal;
|
||||
p->forbid_struct_literal=1;
|
||||
n=expr(p,0);
|
||||
p->forbid_struct_literal=old;
|
||||
return n;
|
||||
}
|
||||
|
||||
static FeNode *delimited_expr(FeParser *p)
|
||||
{
|
||||
FeNode *n;
|
||||
int old=p->forbid_struct_literal;
|
||||
p->forbid_struct_literal=0;
|
||||
n=expr(p,0);
|
||||
p->forbid_struct_literal=old;
|
||||
return n;
|
||||
}
|
||||
|
||||
static FeNode *params(FeParser *p)
|
||||
{
|
||||
FeNode *list=fe_node(p->ast,FE_N_BLOCK,p->current.loc,"params",6);
|
||||
@@ -147,7 +200,7 @@ static FeNode *field(FeParser *p)
|
||||
}
|
||||
static FeNode *decl(FeParser *p)
|
||||
{
|
||||
int pub=0, external=0, interrupt=0, interrupt_safe=0, shared=0, atomic=0; FeToken t=p->current; FeNode *n;
|
||||
int pub=0, external=0, interrupt=0, interrupt_safe=0, shared=0, atomic=0; FeToken t=p->current; FeNode *n; FeTokKind before;
|
||||
(void)shared; (void)atomic;
|
||||
if(eat(p,FE_TOK_PUB)) pub=1;
|
||||
if(eat(p,FE_TOK_EXTERN)) { external=1; if(is(p,FE_TOK_STRING)) next(p); }
|
||||
@@ -156,12 +209,14 @@ static FeNode *decl(FeParser *p)
|
||||
if(!is(p,FE_TOK_PACKED)) t=p->current;
|
||||
if(is(p,FE_TOK_FN)) return fn_decl(p,pub,external,interrupt,interrupt_safe);
|
||||
if(eat(p,FE_TOK_PACKED)) t=p->previous;
|
||||
if(eat(p,FE_TOK_STRUCT)) { n=toknode(p,FE_N_STRUCT,t);if(!is_name(p)){error(p,"expected struct name");return n;}next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,type(p));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after generic parameters");}want(p,FE_TOK_LBRACE,"expected '{' in struct");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){if(is(p,FE_TOK_PUB))next(p);if(is(p,FE_TOK_FN))fe_node_add(n,fn_decl(p,0,0,0,0));else fe_node_add(n,field(p));}want(p,FE_TOK_RBRACE,"expected '}' after struct");return n; }
|
||||
if(eat(p,FE_TOK_STRUCT)) { n=toknode(p,FE_N_STRUCT,t);if(t.kind==FE_TOK_PACKED)n->flags|=1U;if(!is_name(p)){error(p,"expected struct name");return n;}next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);if(eat(p,FE_TOK_LPAREN)){while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(n,type(p));if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RPAREN,"expected ')' after generic parameters");}want(p,FE_TOK_LBRACE,"expected '{' in struct");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){if(is(p,FE_TOK_PUB))next(p);if(is(p,FE_TOK_FN))fe_node_add(n,fn_decl(p,0,0,0,0));else fe_node_add(n,field(p));}want(p,FE_TOK_RBRACE,"expected '}' after struct");return n; }
|
||||
if(eat(p,FE_TOK_ENUM)) { n=toknode(p,FE_N_ENUM,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected enum name");want(p,FE_TOK_LBRACE,"expected '{' in enum");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected variant name");recover(p);break;}if(eat(p,FE_TOK_LPAREN)){v->a=type(p);want(p,FE_TOK_RPAREN,"expected ')' in variant");}else if(eat(p,FE_TOK_LBRACE)){while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF))fe_node_add(v,field(p));want(p,FE_TOK_RBRACE,"expected '}' in variant");}fe_node_add(n,v);if(!eat(p,FE_TOK_COMMA))break;}want(p,FE_TOK_RBRACE,"expected '}' after enum");return n; }
|
||||
if(eat(p,FE_TOK_ERROR_KW)) { n=toknode(p,FE_N_ERROR_DECL,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected error name");want(p,FE_TOK_LBRACE,"expected '{' in error declaration");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *v=toknode(p,FE_N_VARIANT,p->current);if(is_name(p))next(p);else{error(p,"expected error member");recover(p);break;}want(p,FE_TOK_EQ,"expected '=' in error member");v->a=expr(p,0);want(p,FE_TOK_COMMA,"expected ',' in error declaration");fe_node_add(n,v);}want(p,FE_TOK_RBRACE,"expected '}' after error");return n; }
|
||||
if(eat(p,FE_TOK_SHARED)) { shared=1; if(eat(p,FE_TOK_ATOMIC)) atomic=1; if(!is(p,FE_TOK_VAR)) error(p,"expected 'var' after shared"); }
|
||||
if(is(p,FE_TOK_CONST)||is(p,FE_TOK_STATIC)||is(p,FE_TOK_VAR)) { FeTokKind kk=p->current.kind;next(p);n=toknode(p,kk==FE_TOK_CONST?FE_N_CONST:FE_N_GLOBAL,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected declaration name");if(eat(p,FE_TOK_COLON))n->a=type(p);want(p,FE_TOK_EQ,"expected '=' in declaration");n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';' after declaration");return n; }
|
||||
error(p,"expected declaration"); recover(p); return 0;
|
||||
error(p,"expected declaration"); before=p->current.kind; recover(p);
|
||||
if (p->current.kind==before && p->current.kind!=FE_TOK_EOF) next(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FeNode *block(FeParser *p)
|
||||
@@ -175,11 +230,42 @@ static FeNode *statement(FeParser *p)
|
||||
if(eat(p,FE_TOK_LET)) { n=toknode(p,FE_N_LET,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected variable name");if(eat(p,FE_TOK_COLON))n->a=type(p);want(p,FE_TOK_EQ,"expected '=' in let");n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';'");return n; }
|
||||
if(eat(p,FE_TOK_VAR)) { n=toknode(p,FE_N_VAR,t);if(is_name(p)){next(p);n->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected variable name");if(eat(p,FE_TOK_COLON))n->a=type(p);if(eat(p,FE_TOK_EQ))n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';'");return n; }
|
||||
if(eat(p,FE_TOK_CONST)) { n=toknode(p,FE_N_CONST,t);if(is_name(p))next(p);else error(p,"expected constant name");if(eat(p,FE_TOK_COLON))n->a=type(p);want(p,FE_TOK_EQ,"expected '=' in const");n->b=expr(p,0);want(p,FE_TOK_SEMI,"expected ';'");return n; }
|
||||
if(eat(p,FE_TOK_IF)) { n=toknode(p,FE_N_IF,t);if(eat(p,FE_TOK_LET)){n->text=fe_arena_strdup(&p->ast->arena,"if let",6);if(is_name(p))next(p);if(eat(p,FE_TOK_LPAREN)){if(is_name(p))next(p);want(p,FE_TOK_RPAREN,"expected ')' in if let pattern");}want(p,FE_TOK_EQ,"expected '=' in if let");}n->a=expr(p,0);n->b=block(p);if(eat(p,FE_TOK_ELSE))n->c=is(p,FE_TOK_IF)?statement(p):block(p);return n; }
|
||||
if(eat(p,FE_TOK_COMPTIME)) { n=toknode(p,FE_N_IF,t);want(p,FE_TOK_IF,"expected 'if' after comptime");n->text=fe_arena_strdup(&p->ast->arena,"comptime if",11);n->a=expr(p,0);n->b=block(p);if(eat(p,FE_TOK_ELSE))n->c=is(p,FE_TOK_IF)?statement(p):block(p);return n; }
|
||||
if(eat(p,FE_TOK_WHILE)) {n=toknode(p,FE_N_WHILE,t);n->a=expr(p,0);n->b=block(p);return n;}
|
||||
if(eat(p,FE_TOK_FOR)) {n=toknode(p,FE_N_FOR,t);if(is_name(p))next(p);else error(p,"expected loop variable");if(eat(p,FE_TOK_COMMA)){if(is_name(p))next(p);else error(p,"expected second loop variable");}want(p,FE_TOK_IN,"expected 'in' in for");n->a=expr(p,0);if(eat(p,FE_TOK_DOTDOT))n->c=expr(p,0);n->b=block(p);return n;}
|
||||
if(eat(p,FE_TOK_MATCH)) { n=toknode(p,FE_N_MATCH,t);n->a=expr(p,0);want(p,FE_TOK_LBRACE,"expected '{' after match expression");while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)){FeNode *arm=toknode(p,FE_N_ARM,p->current);if(is_name(p)||is(p,FE_TOK_INT)||is(p,FE_TOK_CHAR)||is(p,FE_TOK_NULL)||is(p,FE_TOK_TRUE)||is(p,FE_TOK_FALSE)||is(p,FE_TOK_IDENT)){arm->text=fe_arena_strdup(&p->ast->arena,p->current.begin,p->current.length);next(p);}else{error(p,"expected match pattern");recover(p);continue;}while(is(p,FE_TOK_LPAREN)||is(p,FE_TOK_LBRACE)){FeTokKind close=is(p,FE_TOK_LPAREN)?FE_TOK_RPAREN:FE_TOK_RBRACE;next(p);while(!is(p,close)&&!is(p,FE_TOK_EOF))next(p);want(p,close,"expected end of match pattern");}want(p,FE_TOK_FATARROW,"expected '=>' in match arm");if(is(p,FE_TOK_LBRACE))arm->a=block(p);else{arm->a=expr(p,0);want(p,FE_TOK_SEMI,"expected ';' in match arm");}fe_node_add(n,arm);}want(p,FE_TOK_RBRACE,"expected '}' after match");return n;}
|
||||
if(eat(p,FE_TOK_IF)) { n=toknode(p,FE_N_IF,t);if(eat(p,FE_TOK_LET)){n->text=fe_arena_strdup(&p->ast->arena,"if let",6);if(is_name(p))next(p);if(eat(p,FE_TOK_LPAREN)){if(is_name(p))next(p);want(p,FE_TOK_RPAREN,"expected ')' in if let pattern");}want(p,FE_TOK_EQ,"expected '=' in if let");}n->a=header_expr(p);n->b=block(p);if(eat(p,FE_TOK_ELSE))n->c=is(p,FE_TOK_IF)?statement(p):block(p);return n; }
|
||||
if(eat(p,FE_TOK_COMPTIME)) { n=toknode(p,FE_N_IF,t);want(p,FE_TOK_IF,"expected 'if' after comptime");n->text=fe_arena_strdup(&p->ast->arena,"comptime if",11);n->a=header_expr(p);n->b=block(p);if(eat(p,FE_TOK_ELSE))n->c=is(p,FE_TOK_IF)?statement(p):block(p);return n; }
|
||||
if(eat(p,FE_TOK_WHILE)) {n=toknode(p,FE_N_WHILE,t);n->a=header_expr(p);n->b=block(p);return n;}
|
||||
if(eat(p,FE_TOK_FOR)) {n=toknode(p,FE_N_FOR,t);if(is_name(p)){n->text=fe_arena_strdup(&p->ast->arena,p->current.begin,p->current.length);next(p);}else error(p,"expected loop variable");if(eat(p,FE_TOK_COMMA)){if(is_name(p)){n->aux_text=fe_arena_strdup(&p->ast->arena,p->current.begin,p->current.length);next(p);}else error(p,"expected second loop variable");}want(p,FE_TOK_IN,"expected 'in' in for");n->a=header_expr(p);if(eat(p,FE_TOK_DOTDOT))n->c=header_expr(p);n->b=block(p);return n;}
|
||||
if(eat(p,FE_TOK_MATCH)) {
|
||||
int old=p->forbid_struct_literal;
|
||||
n=toknode(p,FE_N_MATCH,t); p->forbid_struct_literal=1; n->a=header_expr(p); p->forbid_struct_literal=old;
|
||||
want(p,FE_TOK_LBRACE,"expected '{' after match expression");
|
||||
while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)) {
|
||||
FeNode *arm=toknode(p,FE_N_ARM,p->current);
|
||||
FeToken pt=p->current;
|
||||
if(is_name(p)||is(p,FE_TOK_INT)||is(p,FE_TOK_CHAR)||is(p,FE_TOK_NULL)||is(p,FE_TOK_TRUE)||is(p,FE_TOK_FALSE)) {
|
||||
arm->text=fe_arena_strdup(&p->ast->arena,pt.begin,pt.length); next(p);
|
||||
} else { error(p,"expected match pattern"); recover(p); continue; }
|
||||
if(eat(p,FE_TOK_LPAREN)) {
|
||||
while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)) {
|
||||
if(is_name(p)) { fe_node_add(arm,toknode(p,FE_N_IDENT,p->current)); next(p); }
|
||||
else { error(p,"expected pattern binding"); recover(p); break; }
|
||||
if(!eat(p,FE_TOK_COMMA)) break;
|
||||
}
|
||||
want(p,FE_TOK_RPAREN,"expected ')' after match pattern");
|
||||
} else if(eat(p,FE_TOK_LBRACE)) {
|
||||
while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)) {
|
||||
if(is_name(p)) { fe_node_add(arm,toknode(p,FE_N_IDENT,p->current)); next(p); }
|
||||
else { error(p,"expected field binding"); recover(p); break; }
|
||||
if(!eat(p,FE_TOK_COMMA)) break;
|
||||
}
|
||||
want(p,FE_TOK_RBRACE,"expected '}' after match pattern");
|
||||
}
|
||||
want(p,FE_TOK_FATARROW,"expected '=>' in match arm");
|
||||
if(is(p,FE_TOK_LBRACE)) arm->a=block(p);
|
||||
else { arm->a=expr(p,0); want(p,FE_TOK_SEMI,"expected ';' in match arm"); }
|
||||
fe_node_add(n,arm);
|
||||
}
|
||||
want(p,FE_TOK_RBRACE,"expected '}' after match"); return n;
|
||||
}
|
||||
if(eat(p,FE_TOK_RETURN)) {n=toknode(p,FE_N_RETURN,t);if(!is(p,FE_TOK_SEMI))n->a=expr(p,0);want(p,FE_TOK_SEMI,"expected ';' after return");return n;}
|
||||
if(eat(p,FE_TOK_BREAK)){n=toknode(p,FE_N_BREAK,t);want(p,FE_TOK_SEMI,"expected ';'");return n;}
|
||||
if(eat(p,FE_TOK_CONTINUE)){n=toknode(p,FE_N_CONTINUE,t);want(p,FE_TOK_SEMI,"expected ';'");return n;}
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef struct FeParser {
|
||||
FeToken previous;
|
||||
FeAst *ast;
|
||||
FeDiags *diags;
|
||||
int forbid_struct_literal;
|
||||
} FeParser;
|
||||
|
||||
void fe_parser_init(FeParser *p, FeAst *ast, const char *src, unsigned long length, const char *file, FeDiags *d);
|
||||
|
||||
+459
-36
@@ -1,50 +1,473 @@
|
||||
#include "types.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static FeType *new_type(FeTypeCtx *ctx, const char *name, FeTypeKind kind)
|
||||
{
|
||||
FeType *t;
|
||||
unsigned i;
|
||||
t = (FeType *)fe_arena_alloc(ctx->arena, sizeof(FeType));
|
||||
if (!t) return 0;
|
||||
for (i = 0; i + 1U < sizeof(t->name) && name && name[i]; ++i)
|
||||
t->name[i] = name[i];
|
||||
t->name[i] = '\0';
|
||||
t->kind = kind;
|
||||
t->cname = 0;
|
||||
t->maker = 0;
|
||||
t->indexer = 0;
|
||||
t->slicer = 0;
|
||||
t->full_slicer = 0;
|
||||
t->tail_slicer = 0;
|
||||
t->bits = 0;
|
||||
t->is_unsigned = 0;
|
||||
t->packed = 0;
|
||||
t->length = 0;
|
||||
t->size = 0;
|
||||
t->align = 1;
|
||||
t->elem = 0;
|
||||
t->ref_mut = 0;
|
||||
t->fields = 0;
|
||||
t->field_count = 0;
|
||||
t->variants = 0;
|
||||
t->variant_count = 0;
|
||||
t->next = ctx->types;
|
||||
t->emit_state = 0;
|
||||
t->cycle_state = 0;
|
||||
ctx->types = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
void fe_types_init(FeTypeCtx *ctx, FeArena *arena, unsigned pointer_bits)
|
||||
{ ctx->arena=arena; ctx->types=0; ctx->pointer_bits=pointer_bits; }
|
||||
{
|
||||
ctx->arena = arena;
|
||||
ctx->types = 0;
|
||||
ctx->pointer_bits = pointer_bits;
|
||||
ctx->unit_name = "unit";
|
||||
ctx->generated_serial = 0;
|
||||
}
|
||||
|
||||
FeType *fe_type_intern(FeTypeCtx *ctx, const char *name)
|
||||
{
|
||||
FeType *t; unsigned i; unsigned bits=0; int uns=0; FeTypeKind kind=FE_TYPE_UNKNOWN;
|
||||
if (!name) name="<unknown>";
|
||||
for (t=ctx->types;t;t=t->next) if(strcmp(t->name,name)==0) return t;
|
||||
if(strcmp(name,"void")==0) kind=FE_TYPE_VOID;
|
||||
else if(strcmp(name,"bool")==0) kind=FE_TYPE_BOOL;
|
||||
else if(strcmp(name,"i8")==0||strcmp(name,"u8")==0){kind=FE_TYPE_INT;bits=8;uns=name[0]=='u';}
|
||||
else if(strcmp(name,"i16")==0||strcmp(name,"u16")==0){kind=FE_TYPE_INT;bits=16;uns=name[0]=='u';}
|
||||
else if(strcmp(name,"i32")==0||strcmp(name,"u32")==0){kind=FE_TYPE_INT;bits=32;uns=name[0]=='u';}
|
||||
else if(strcmp(name,"usize")==0||strcmp(name,"isize")==0){kind=FE_TYPE_INT;bits=ctx->pointer_bits;uns=name[0]=='u';}
|
||||
t=(FeType *)fe_arena_alloc(ctx->arena,sizeof(FeType)); if(!t)return 0;
|
||||
for(i=0;i<sizeof(t->name)-1 && name[i];i++) t->name[i]=name[i];
|
||||
t->name[i]='\0';
|
||||
t->kind=kind;t->bits=bits;t->is_unsigned=uns;t->next=ctx->types;ctx->types=t;return t;
|
||||
FeType *t;
|
||||
unsigned bits = 0;
|
||||
int uns = 0;
|
||||
FeTypeKind kind = FE_TYPE_UNKNOWN;
|
||||
if (!name) name = "<unknown>";
|
||||
for (t = ctx->types; t; t = t->next)
|
||||
if (strcmp(t->name, name) == 0) return t;
|
||||
if (strcmp(name, "void") == 0) kind = FE_TYPE_VOID;
|
||||
else if (strcmp(name, "bool") == 0) kind = FE_TYPE_BOOL;
|
||||
else if (strcmp(name, "char") == 0) kind = FE_TYPE_CHAR;
|
||||
else if (strcmp(name, "str") == 0) kind = FE_TYPE_STR;
|
||||
else if (strcmp(name, "i8") == 0 || strcmp(name, "u8") == 0) {
|
||||
kind = FE_TYPE_INT; bits = 8; uns = name[0] == 'u';
|
||||
} else if (strcmp(name, "i16") == 0 || strcmp(name, "u16") == 0) {
|
||||
kind = FE_TYPE_INT; bits = 16; uns = name[0] == 'u';
|
||||
} else if (strcmp(name, "i32") == 0 || strcmp(name, "u32") == 0) {
|
||||
kind = FE_TYPE_INT; bits = 32; uns = name[0] == 'u';
|
||||
} else if (strcmp(name, "usize") == 0 || strcmp(name, "isize") == 0) {
|
||||
kind = FE_TYPE_INT; bits = ctx->pointer_bits; uns = name[0] == 'u';
|
||||
}
|
||||
t = new_type(ctx, name, kind);
|
||||
if (!t) return 0;
|
||||
t->bits = bits;
|
||||
t->is_unsigned = uns;
|
||||
if (kind == FE_TYPE_STR) {
|
||||
t->cname = fe_arena_strdup(ctx->arena, "fe_str", 6);
|
||||
t->elem = fe_type_intern(ctx, "u8");
|
||||
t->indexer = "fe_idx_str";
|
||||
t->slicer = "fe_slice_str";
|
||||
t->full_slicer = "fe_full_slice_str";
|
||||
t->tail_slicer = "fe_tail_slice_str";
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static char *generated_name(FeTypeCtx *ctx, const char *prefix,
|
||||
const char *name)
|
||||
{
|
||||
char number[24];
|
||||
unsigned long n;
|
||||
char *p;
|
||||
sprintf(number, "%u", ctx->generated_serial++);
|
||||
n = (unsigned long)strlen(prefix) + (unsigned long)strlen(name) +
|
||||
(unsigned long)strlen(number) + 2UL;
|
||||
p = (char *)fe_arena_alloc(ctx->arena, n);
|
||||
if (!p) return 0;
|
||||
strcpy(p, prefix);
|
||||
strcat(p, name);
|
||||
strcat(p, "_");
|
||||
strcat(p, number);
|
||||
return p;
|
||||
}
|
||||
|
||||
FeType *fe_type_array(FeTypeCtx *ctx, unsigned long length, FeType *elem)
|
||||
{
|
||||
char key[96];
|
||||
FeType *t;
|
||||
sprintf(key, "[%lu]%s", length, elem ? elem->name : "?");
|
||||
t = fe_type_intern(ctx, key);
|
||||
if (t->kind == FE_TYPE_UNKNOWN) {
|
||||
t->kind = FE_TYPE_ARRAY;
|
||||
t->length = length;
|
||||
t->elem = elem;
|
||||
t->cname = generated_name(ctx, "struct fe_arr_", "type");
|
||||
t->maker = generated_name(ctx, "fe_make_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");
|
||||
t->tail_slicer = generated_name(ctx, "fe_tail_arr_", "type");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
FeType *fe_type_slice(FeTypeCtx *ctx, FeType *elem)
|
||||
{
|
||||
char key[96];
|
||||
FeType *t;
|
||||
sprintf(key, "[]%s", elem ? elem->name : "?");
|
||||
t = fe_type_intern(ctx, key);
|
||||
if (t->kind == FE_TYPE_UNKNOWN) {
|
||||
t->kind = FE_TYPE_SLICE;
|
||||
t->elem = elem;
|
||||
t->cname = generated_name(ctx, "fe_slice_", "type");
|
||||
t->maker = generated_name(ctx, "fe_make_slice_", "type");
|
||||
t->indexer = generated_name(ctx, "fe_idx_slice_", "type");
|
||||
t->slicer = generated_name(ctx, "fe_slice_slice_", "type");
|
||||
t->full_slicer = generated_name(ctx, "fe_full_slice_", "type");
|
||||
t->tail_slicer = generated_name(ctx, "fe_tail_slice_", "type");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable)
|
||||
{
|
||||
char key[128];
|
||||
FeType *t;
|
||||
sprintf(key,"%s%s",mutable ? "&mut " : "&",elem ? elem->name : "?");
|
||||
t=fe_type_intern(ctx,key);
|
||||
if(t->kind==FE_TYPE_UNKNOWN) {
|
||||
t->kind=FE_TYPE_REF;
|
||||
t->elem=elem;
|
||||
t->ref_mut=mutable;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
|
||||
{
|
||||
FeType *t;
|
||||
FeNode *f;
|
||||
unsigned count = 0;
|
||||
unsigned i = 0;
|
||||
char *cname;
|
||||
if (!node || !node->text) return 0;
|
||||
t = fe_type_intern(ctx, node->text);
|
||||
if (t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_STRUCT) return t;
|
||||
if (t->kind == FE_TYPE_STRUCT) return t;
|
||||
t->kind = FE_TYPE_STRUCT;
|
||||
t->packed = packed;
|
||||
cname = (char *)fe_arena_alloc(ctx->arena,
|
||||
(unsigned long)strlen("struct fe_") + strlen(ctx->unit_name) +
|
||||
strlen(node->text) + 2UL);
|
||||
if (!cname) return t;
|
||||
strcpy(cname, "struct fe_");
|
||||
strcat(cname, ctx->unit_name);
|
||||
strcat(cname, "_");
|
||||
strcat(cname, node->text);
|
||||
t->cname = cname;
|
||||
t->maker = generated_name(ctx, "fe_make_", node->text);
|
||||
for (f = node->children; f; f = f->next)
|
||||
if (f->kind == FE_N_FIELD) ++count;
|
||||
t->field_count = count;
|
||||
if (count) {
|
||||
t->fields = (FeFieldType *)fe_arena_alloc(ctx->arena,
|
||||
count * sizeof(FeFieldType));
|
||||
if (!t->fields) return t;
|
||||
for (f = node->children; f; f = f->next) if (f->kind == FE_N_FIELD) {
|
||||
t->fields[i].name = f->text;
|
||||
t->fields[i].type = 0;
|
||||
t->fields[i].offset = 0;
|
||||
t->fields[i].ast_node = f;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node)
|
||||
{
|
||||
FeType *t;
|
||||
FeNode *v;
|
||||
unsigned count = 0;
|
||||
unsigned i = 0;
|
||||
char *cname;
|
||||
if (!node || !node->text) return 0;
|
||||
t = fe_type_intern(ctx, node->text);
|
||||
if (t->kind != FE_TYPE_UNKNOWN && t->kind != FE_TYPE_ENUM) return t;
|
||||
if (t->kind == FE_TYPE_ENUM) return t;
|
||||
t->kind = FE_TYPE_ENUM;
|
||||
cname = (char *)fe_arena_alloc(ctx->arena,
|
||||
(unsigned long)strlen("struct fe_") + strlen(ctx->unit_name) +
|
||||
strlen(node->text) + 2UL);
|
||||
if (!cname) return t;
|
||||
strcpy(cname, "struct fe_");
|
||||
strcat(cname, ctx->unit_name);
|
||||
strcat(cname, "_");
|
||||
strcat(cname, node->text);
|
||||
t->cname = cname;
|
||||
for (v = node->children; v; v = v->next) ++count;
|
||||
t->variant_count = count;
|
||||
if (count) {
|
||||
t->variants = (FeVariantType *)fe_arena_alloc(ctx->arena,
|
||||
count * sizeof(FeVariantType));
|
||||
if (!t->variants) return t;
|
||||
for (v = node->children; v; v = v->next) {
|
||||
t->variants[i].name = v->text;
|
||||
t->variants[i].fields = 0;
|
||||
t->variants[i].field_count = 0;
|
||||
t->variants[i].tag = i;
|
||||
t->variants[i].ast_node = v;
|
||||
t->variants[i].maker = generated_name(ctx, "fe_make_variant_", v->text ? v->text : "variant");
|
||||
if (v->a && v->a->kind == FE_N_TYPE) {
|
||||
t->variants[i].field_count = 1;
|
||||
t->variants[i].fields = (FeFieldType *)fe_arena_alloc(ctx->arena, sizeof(FeFieldType));
|
||||
if (t->variants[i].fields) {
|
||||
t->variants[i].fields[0].name = "value";
|
||||
t->variants[i].fields[0].type = fe_type_from_ast(ctx, v->a);
|
||||
t->variants[i].fields[0].offset = 0;
|
||||
t->variants[i].fields[0].ast_node = v;
|
||||
}
|
||||
}
|
||||
if (!v->a) {
|
||||
FeNode *f;
|
||||
unsigned fc = 0;
|
||||
unsigned j = 0;
|
||||
for (f = v->children; f; f = f->next)
|
||||
if (f->kind == FE_N_FIELD) ++fc;
|
||||
t->variants[i].field_count = fc;
|
||||
if (fc) {
|
||||
t->variants[i].fields = (FeFieldType *)fe_arena_alloc(
|
||||
ctx->arena, fc * sizeof(FeFieldType));
|
||||
if (t->variants[i].fields) for (f = v->children; f; f = f->next)
|
||||
if (f->kind == FE_N_FIELD) {
|
||||
t->variants[i].fields[j].name = f->text;
|
||||
t->variants[i].fields[j].type = 0;
|
||||
t->variants[i].fields[j].offset = 0;
|
||||
t->variants[i].fields[j].ast_node = f;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static unsigned long round_up(unsigned long x, unsigned a)
|
||||
{
|
||||
unsigned long rem;
|
||||
if (a <= 1U) return x;
|
||||
rem = x % (unsigned long)a;
|
||||
return rem ? x + (unsigned long)a - rem : x;
|
||||
}
|
||||
|
||||
unsigned long fe_type_size(const FeType *t)
|
||||
{
|
||||
return t ? t->size : 0;
|
||||
}
|
||||
|
||||
unsigned fe_type_align(const FeType *t)
|
||||
{
|
||||
return t && t->align ? t->align : 1U;
|
||||
}
|
||||
|
||||
static void layout_type(FeTypeCtx *ctx, FeType *t)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned align;
|
||||
unsigned long off;
|
||||
unsigned long max_size;
|
||||
unsigned max_align;
|
||||
if (!t || t->size) return;
|
||||
if (t->cycle_state == 1) {
|
||||
/* The checker reports this as an invalid by-value cycle. Give the
|
||||
layout walk a sentinel size so error recovery cannot recurse. */
|
||||
t->size = 1;
|
||||
t->align = 1;
|
||||
return;
|
||||
}
|
||||
t->cycle_state = 1;
|
||||
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_BOOL || t->kind == FE_TYPE_CHAR) {
|
||||
t->size = 1; t->align = 1; t->cycle_state = 2; return;
|
||||
}
|
||||
if (t->kind == FE_TYPE_INT) {
|
||||
t->size = (t->bits + 7U) / 8U;
|
||||
t->align = ctx->pointer_bits == 16 ? 1U : t->size;
|
||||
if (t->size > 4UL) t->size = ctx->pointer_bits == 16 ? 2UL : 4UL;
|
||||
t->cycle_state = 2; return;
|
||||
}
|
||||
if (t->kind == FE_TYPE_REF) {
|
||||
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;
|
||||
t->cycle_state = 2; return;
|
||||
}
|
||||
if (t->kind == FE_TYPE_ARRAY) {
|
||||
layout_type(ctx, t->elem);
|
||||
t->align = t->packed || ctx->pointer_bits == 16 ? 1U : fe_type_align(t->elem);
|
||||
t->size = t->length * fe_type_size(t->elem);
|
||||
t->cycle_state = 2; return;
|
||||
}
|
||||
if (t->kind == FE_TYPE_STRUCT) {
|
||||
off = 0; max_align = 1;
|
||||
for (i = 0; i < t->field_count; ++i) {
|
||||
if (!t->fields[i].type && t->fields[i].ast_node)
|
||||
t->fields[i].type = fe_type_from_ast(ctx, t->fields[i].ast_node->a);
|
||||
layout_type(ctx, t->fields[i].type);
|
||||
align = t->packed || ctx->pointer_bits == 16 ? 1U : fe_type_align(t->fields[i].type);
|
||||
if (align > max_align) max_align = align;
|
||||
off = round_up(off, align);
|
||||
t->fields[i].offset = off;
|
||||
off += fe_type_size(t->fields[i].type);
|
||||
}
|
||||
t->align = max_align;
|
||||
t->size = round_up(off, max_align);
|
||||
t->cycle_state = 2;
|
||||
return;
|
||||
}
|
||||
if (t->kind == FE_TYPE_ENUM) {
|
||||
max_size = 0; max_align = 1;
|
||||
for (i = 0; i < t->variant_count; ++i) {
|
||||
unsigned j;
|
||||
off = 0;
|
||||
for (j = 0; j < t->variants[i].field_count; ++j) {
|
||||
if (!t->variants[i].fields[j].type && t->variants[i].fields[j].ast_node)
|
||||
t->variants[i].fields[j].type = fe_type_from_ast(
|
||||
ctx, t->variants[i].fields[j].ast_node->a);
|
||||
layout_type(ctx, t->variants[i].fields[j].type);
|
||||
if (fe_type_align(t->variants[i].fields[j].type) > max_align)
|
||||
max_align = fe_type_align(t->variants[i].fields[j].type);
|
||||
off += fe_type_size(t->variants[i].fields[j].type);
|
||||
}
|
||||
if (off > max_size) max_size = off;
|
||||
}
|
||||
t->bits = t->variant_count > 256U ? 16U : 8U;
|
||||
off = ctx->pointer_bits == 16 ? t->bits / 8U : round_up(t->bits / 8U, max_align);
|
||||
t->size = round_up(off + max_size, ctx->pointer_bits == 16 ? 1U : max_align);
|
||||
t->align = ctx->pointer_bits == 16 ? 1U : max_align;
|
||||
t->cycle_state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void fe_type_layout_all(FeTypeCtx *ctx)
|
||||
{
|
||||
FeType *t;
|
||||
for (t = ctx->types; t; t = t->next) layout_type(ctx, t);
|
||||
}
|
||||
|
||||
FeFieldType *fe_type_field(FeType *t, const char *name)
|
||||
{
|
||||
unsigned i;
|
||||
if (!t || t->kind != FE_TYPE_STRUCT || !name) return 0;
|
||||
for (i = 0; i < t->field_count; ++i)
|
||||
if (strcmp(t->fields[i].name, name) == 0) return &t->fields[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
FeVariantType *fe_type_variant(FeType *t, const char *name)
|
||||
{
|
||||
unsigned i;
|
||||
if (!t || t->kind != FE_TYPE_ENUM || !name) return 0;
|
||||
for (i = 0; i < t->variant_count; ++i)
|
||||
if (strcmp(t->variants[i].name, name) == 0) return &t->variants[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
FeType *fe_type_from_ast(FeTypeCtx *ctx, const FeNode *node)
|
||||
{
|
||||
if(!node)return fe_type_intern(ctx,"<unknown>");
|
||||
if(node->kind!=FE_N_TYPE)return fe_type_intern(ctx,"<unknown>");
|
||||
if(node->text && (strcmp(node->text,"?")==0||strcmp(node->text,"!")==0||strcmp(node->text,"^")==0||strcmp(node->text,"&")==0||strcmp(node->text,"*")==0||strcmp(node->text,"far")==0))return fe_type_intern(ctx,"<unknown>");
|
||||
if(node->text && strcmp(node->text,"as")==0)return fe_type_from_ast(ctx,node->b);
|
||||
if(node->text && strcmp(node->text,"fn")==0)return fe_type_intern(ctx,"<unknown>");
|
||||
return fe_type_intern(ctx,node->text);
|
||||
unsigned long length = 0;
|
||||
if (!node) return fe_type_intern(ctx, "<unknown>");
|
||||
if (node->kind != FE_N_TYPE) return fe_type_intern(ctx, "<unknown>");
|
||||
if (node->text && strcmp(node->text, "as") == 0)
|
||||
return fe_type_from_ast(ctx, node->b);
|
||||
if (node->text && strcmp(node->text, "str") == 0)
|
||||
return fe_type_intern(ctx, "str");
|
||||
if (node->text && (strcmp(node->text, "&") == 0 ||
|
||||
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) {
|
||||
if (node->a) {
|
||||
if (node->a->kind == FE_N_LITERAL && node->a->text)
|
||||
length = strtoul(node->a->text, 0, 0);
|
||||
return fe_type_array(ctx, length, fe_type_from_ast(ctx, node->b));
|
||||
}
|
||||
return fe_type_slice(ctx, fe_type_from_ast(ctx, node->b));
|
||||
}
|
||||
if (node->text && (strcmp(node->text, "?") == 0 ||
|
||||
strcmp(node->text, "!") == 0 ||
|
||||
strcmp(node->text, "^") == 0 ||
|
||||
strcmp(node->text, "&") == 0 ||
|
||||
strcmp(node->text, "&mut") == 0 ||
|
||||
strcmp(node->text, "*") == 0 ||
|
||||
strcmp(node->text, "far") == 0))
|
||||
return fe_type_intern(ctx, "<unknown>");
|
||||
if (node->text && strcmp(node->text, "fn") == 0)
|
||||
return fe_type_intern(ctx, "<unknown>");
|
||||
return fe_type_intern(ctx, node->text);
|
||||
}
|
||||
int fe_type_equal(const FeType *a,const FeType *b){return a==b || (a&&b&&strcmp(a->name,b->name)==0);}
|
||||
int fe_type_is_integer(const FeType *t){return t&&t->kind==FE_TYPE_INT;}
|
||||
const char *fe_type_c_name(const FeType *t,unsigned pointer_bits)
|
||||
|
||||
int fe_type_equal(const FeType *a, const FeType *b)
|
||||
{
|
||||
if(!t)return "int";
|
||||
if(t->kind==FE_TYPE_VOID)return "void";
|
||||
if(t->kind==FE_TYPE_BOOL)return "unsigned char";
|
||||
if(t->kind!=FE_TYPE_INT)return "int";
|
||||
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";
|
||||
if(strcmp(t->name,"i8")==0)return "signed char";
|
||||
if(strcmp(t->name,"u8")==0)return "unsigned char";
|
||||
if(strcmp(t->name,"i16")==0)return "short";
|
||||
if(strcmp(t->name,"u16")==0)return "unsigned short";
|
||||
if(strcmp(t->name,"i32")==0)return "long";
|
||||
if(strcmp(t->name,"u32")==0)return "unsigned long";
|
||||
return "int";
|
||||
return a == b || (a && b && strcmp(a->name, b->name) == 0);
|
||||
}
|
||||
|
||||
int fe_type_is_integer(const FeType *t)
|
||||
{
|
||||
return t && t->kind == FE_TYPE_INT;
|
||||
}
|
||||
|
||||
int fe_type_is_indexable(const FeType *t)
|
||||
{
|
||||
return t && (t->kind == FE_TYPE_ARRAY || t->kind == FE_TYPE_SLICE ||
|
||||
t->kind == FE_TYPE_STR);
|
||||
}
|
||||
|
||||
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_BOOL || t->kind == FE_TYPE_CHAR) return "unsigned char";
|
||||
if (t->kind == FE_TYPE_REF) {
|
||||
static char ref_name[128];
|
||||
if (t->ref_mut) {
|
||||
strcpy(ref_name,fe_type_c_name(t->elem,pointer_bits));
|
||||
strcat(ref_name," *");
|
||||
} else {
|
||||
strcpy(ref_name,"const ");
|
||||
strcat(ref_name,fe_type_c_name(t->elem,pointer_bits));
|
||||
strcat(ref_name," *");
|
||||
}
|
||||
return ref_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";
|
||||
if (strcmp(t->name, "i8") == 0) return "signed char";
|
||||
if (strcmp(t->name, "u8") == 0) return "unsigned char";
|
||||
if (strcmp(t->name, "i16") == 0) return "short";
|
||||
if (strcmp(t->name, "u16") == 0) return "unsigned short";
|
||||
if (strcmp(t->name, "i32") == 0) return "long";
|
||||
if (strcmp(t->name, "u32") == 0) return "unsigned long";
|
||||
return "long";
|
||||
}
|
||||
|
||||
+54
-2
@@ -4,28 +4,80 @@
|
||||
#include "ast.h"
|
||||
|
||||
typedef enum FeTypeKind {
|
||||
FE_TYPE_ERROR, FE_TYPE_VOID, FE_TYPE_BOOL, FE_TYPE_INT, FE_TYPE_UNKNOWN
|
||||
FE_TYPE_ERROR, 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
|
||||
} FeTypeKind;
|
||||
|
||||
typedef struct FeFieldType FeFieldType;
|
||||
typedef struct FeVariantType FeVariantType;
|
||||
|
||||
struct FeFieldType {
|
||||
char *name;
|
||||
FeType *type;
|
||||
unsigned long offset;
|
||||
const FeNode *ast_node;
|
||||
};
|
||||
|
||||
struct FeVariantType {
|
||||
char *name;
|
||||
FeFieldType *fields;
|
||||
unsigned field_count;
|
||||
unsigned tag;
|
||||
const FeNode *ast_node;
|
||||
char *maker;
|
||||
};
|
||||
|
||||
struct FeType {
|
||||
FeTypeKind kind;
|
||||
char name[16];
|
||||
char name[64];
|
||||
char *cname;
|
||||
char *maker;
|
||||
char *indexer;
|
||||
char *slicer;
|
||||
char *full_slicer;
|
||||
char *tail_slicer;
|
||||
unsigned bits;
|
||||
int is_unsigned;
|
||||
int packed;
|
||||
unsigned long length;
|
||||
unsigned long size;
|
||||
unsigned align;
|
||||
FeType *elem;
|
||||
int ref_mut;
|
||||
FeFieldType *fields;
|
||||
unsigned field_count;
|
||||
FeVariantType *variants;
|
||||
unsigned variant_count;
|
||||
FeType *next;
|
||||
int emit_state;
|
||||
int cycle_state;
|
||||
};
|
||||
|
||||
typedef struct FeTypeCtx {
|
||||
FeArena *arena;
|
||||
FeType *types;
|
||||
unsigned pointer_bits;
|
||||
const char *unit_name;
|
||||
unsigned generated_serial;
|
||||
} FeTypeCtx;
|
||||
|
||||
void fe_types_init(FeTypeCtx *ctx, FeArena *arena, unsigned pointer_bits);
|
||||
FeType *fe_type_intern(FeTypeCtx *ctx, const char *name);
|
||||
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_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed);
|
||||
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node);
|
||||
void fe_type_layout_all(FeTypeCtx *ctx);
|
||||
FeFieldType *fe_type_field(FeType *t, const char *name);
|
||||
FeVariantType *fe_type_variant(FeType *t, const char *name);
|
||||
int fe_type_equal(const FeType *a, const FeType *b);
|
||||
int fe_type_is_integer(const FeType *t);
|
||||
int fe_type_is_indexable(const FeType *t);
|
||||
const char *fe_type_c_name(const FeType *t, unsigned pointer_bits);
|
||||
unsigned long fe_type_size(const FeType *t);
|
||||
unsigned fe_type_align(const FeType *t);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,6 +93,102 @@ if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M2\BAD-VO.FE -o TESTS\M2\BAD-VO.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
|
||||
if exist TESTS\M3\STRUCT.C del TESTS\M3\STRUCT.C
|
||||
if exist TESTS\M3\STRUCT.EXE del TESTS\M3\STRUCT.EXE
|
||||
if exist TESTS\M3\ENUM.C del TESTS\M3\ENUM.C
|
||||
if exist TESTS\M3\ENUM.EXE del TESTS\M3\ENUM.EXE
|
||||
if exist TESTS\M3\ARRAY.C del TESTS\M3\ARRAY.C
|
||||
if exist TESTS\M3\ARRAY.EXE del TESTS\M3\ARRAY.EXE
|
||||
if exist TESTS\M3\STR.C del TESTS\M3\STR.C
|
||||
if exist TESTS\M3\STR.EXE del TESTS\M3\STR.EXE
|
||||
if exist TESTS\M3\FOR.C del TESTS\M3\FOR.C
|
||||
if exist TESTS\M3\FOR.EXE del TESTS\M3\FOR.EXE
|
||||
if exist TESTS\M3\NESTED.C del TESTS\M3\NESTED.C
|
||||
if exist TESTS\M3\NESTED.EXE del TESTS\M3\NESTED.EXE
|
||||
if exist TESTS\M3\CHAR.C del TESTS\M3\CHAR.C
|
||||
if exist TESTS\M3\CHAR.EXE del TESTS\M3\CHAR.EXE
|
||||
if exist TESTS\M3\ARRAYCTX.C del TESTS\M3\ARRAYCTX.C
|
||||
if exist TESTS\M3\ARRAYCTX.EXE del TESTS\M3\ARRAYCTX.EXE
|
||||
if exist TESTS\M3\BOUNDS.C del TESTS\M3\BOUNDS.C
|
||||
if exist TESTS\M3\BOUNDS.EXE del TESTS\M3\BOUNDS.EXE
|
||||
if exist TESTS\M3\BOUNDS-N.C del TESTS\M3\BOUNDS-N.C
|
||||
if exist TESTS\M3\BOUNDS-N.EXE del TESTS\M3\BOUNDS-N.EXE
|
||||
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\STRUCT.FE -o TESTS\M3\STRUCT.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\STRUCT.EXE TESTS\M3\STRUCT.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\STRUCT.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\ENUM.FE -o TESTS\M3\ENUM.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\ENUM.EXE TESTS\M3\ENUM.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\ENUM.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\ARRAY.FE -o TESTS\M3\ARRAY.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\ARRAY.EXE TESTS\M3\ARRAY.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\ARRAY.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\STR.FE -o TESTS\M3\STR.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\STR.EXE TESTS\M3\STR.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\STR.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\FOR.FE -o TESTS\M3\FOR.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\FOR.EXE TESTS\M3\FOR.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\FOR.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\NESTED.FE -o TESTS\M3\NESTED.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\NESTED.EXE TESTS\M3\NESTED.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\NESTED.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\CHAR.FE -o TESTS\M3\CHAR.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\CHAR.EXE TESTS\M3\CHAR.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\CHAR.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\ARRAYCTX.FE -o TESTS\M3\ARRAYCTX.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\ARRAYCTX.EXE TESTS\M3\ARRAYCTX.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\ARRAYCTX.EXE
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BOUNDS.FE -o TESTS\M3\BOUNDS.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\BOUNDS.EXE TESTS\M3\BOUNDS.C
|
||||
if errorlevel 1 goto test_fail
|
||||
TESTS\M3\BOUNDS.EXE
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --no-checks --emit-c TESTS\M3\BOUNDS.FE -o TESTS\M3\BOUNDS-N.C > nul
|
||||
if errorlevel 1 goto test_fail
|
||||
wcl386 -q -za -bt=dos -fe=TESTS\M3\BOUNDS-N.EXE TESTS\M3\BOUNDS-N.C
|
||||
if errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADFLD.FE -o TESTS\M3\BADFLD.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADMAT.FE -o TESTS\M3\BADMAT.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADARR.FE -o TESTS\M3\BADARR.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADCYCLE.FE -o TESTS\M3\BADCYCLE.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADSTR.FE -o TESTS\M3\BADSTR.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADCHAR.FE -o TESTS\M3\BADCHAR.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADFIELD.FE -o TESTS\M3\BADFIELD.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M3\BADINDEX.FE -o TESTS\M3\BADINDEX.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
|
||||
echo OK>TEST.OK
|
||||
cd C:\FEC
|
||||
goto test_done
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
unit m3_array;
|
||||
|
||||
fn main() -> i32 {
|
||||
let a: [3]i32 = [1, 2, 3];
|
||||
let s: []i32 = a[..];
|
||||
let t: []i32 = s[1..3];
|
||||
if a[0] + s[1] + t[0] == 5 and s.n == 3 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
unit m3_arrayctx;
|
||||
|
||||
fn main() -> i32 {
|
||||
let bytes: [3]u8 = [1, 2, 3];
|
||||
if bytes[0] == 1 and bytes[2] == 3 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
unit fail_m3_array;
|
||||
fn main() -> i32 {
|
||||
let a: [2]i32 = [1, true, 3];
|
||||
return a[0];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit fail_m3_char;
|
||||
|
||||
fn main() -> i32 {
|
||||
let u: u8 = 'A';
|
||||
return u;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit fail_m3_cycle;
|
||||
|
||||
struct A { b: B, }
|
||||
struct B { a: A, }
|
||||
|
||||
fn main() -> i32 { return 0; }
|
||||
@@ -0,0 +1,8 @@
|
||||
unit fail_m3_let_field;
|
||||
|
||||
struct Point { x: i32, y: i32, }
|
||||
fn main() -> i32 {
|
||||
let p: Point = Point{ x: 1, y: 2 };
|
||||
p.x = 3;
|
||||
return p.x;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit fail_m3_fields;
|
||||
struct Point { x: i32, y: i32, }
|
||||
fn main() -> i32 {
|
||||
let p: Point = Point{ x: 1 };
|
||||
return p.z;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
unit fail_m3_let_index;
|
||||
|
||||
fn main() -> i32 {
|
||||
let a: [2]i32 = [1, 2];
|
||||
a[0] = 3;
|
||||
return a[0];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit fail_m3_match;
|
||||
enum Shape { Empty, Circle(i32), }
|
||||
fn main() -> i32 {
|
||||
match Shape.Empty { Empty => 0; }
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit fail_m3_str;
|
||||
fn main() -> i32 {
|
||||
var text: str = "abc";
|
||||
text[0] = 'z';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
unit m3_bounds;
|
||||
|
||||
fn main() -> i32 {
|
||||
let a: [2]i32 = [1, 2];
|
||||
return a[2];
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
unit m3_char;
|
||||
|
||||
fn main() -> i32 {
|
||||
let c: char = '\u0041';
|
||||
let u: u8 = c as u8;
|
||||
let d: char = u as char;
|
||||
if c == d and u == ('A' as u8) { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
unit m3_enum;
|
||||
|
||||
enum Shape { Empty, Circle(i32), Rect { w: i32, h: i32, }, }
|
||||
|
||||
fn score(s: Shape) -> i32 {
|
||||
match s {
|
||||
Empty => { return 0; }
|
||||
Circle(value) => { return value; }
|
||||
Rect { w, h } => { return w * h; }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> i32 {
|
||||
if score(Shape.Circle(5)) == 5 and score(Shape.Rect{ w: 2, h: 3 }) == 6 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
unit m3_for;
|
||||
|
||||
fn main() -> i32 {
|
||||
var total: i32 = 0;
|
||||
let a: [3]i32 = [1, 2, 3];
|
||||
let s: []i32 = a[..];
|
||||
var m: [1]i32 = [1];
|
||||
let ready: bool = true;
|
||||
if ready { total += 0; }
|
||||
while false { total += 100; }
|
||||
for x in a { total += x.^; }
|
||||
for i, x in a { if i == 1 and x.^ == 2 { total += 1; } }
|
||||
for x in "ab" { if x.^ == ('a' as u8) { total += 1; } }
|
||||
for x in s { if x.^ == 3 { total += 1; } }
|
||||
for x in m { x.^ = 2; }
|
||||
if total == 9 and m[0] == 2 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
unit m3_nested;
|
||||
|
||||
struct Outer { inner: Inner, }
|
||||
struct Inner { value: i32, }
|
||||
|
||||
fn main() -> i32 {
|
||||
let x: Outer = Outer{ inner: Inner{ value: 7 } };
|
||||
if x.inner.value == 7 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
unit m3_str;
|
||||
|
||||
fn main() -> i32 {
|
||||
let text: str = "abc";
|
||||
if text[1] == ('b' as u8) and text.n == 3 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
unit m3_struct;
|
||||
|
||||
struct Point { x: i32, y: i32, }
|
||||
packed struct PackedPoint { x: u8, y: i32, }
|
||||
struct Natural { a: u8, b: i32, }
|
||||
|
||||
fn main() -> i32 {
|
||||
let p: Point = Point{ x: 3, y: 4 };
|
||||
let q: PackedPoint = PackedPoint{ x: 1, y: 6 };
|
||||
let n: Natural = Natural{ a: 1, b: 2 };
|
||||
if p.x + p.y == 7 and q.y == 6 and n.b == 2 and
|
||||
(Point{ x: 1, y: 2 }.x == 1) and @size_of(Natural) == 8 { return 0; }
|
||||
return 1;
|
||||
}
|
||||
@@ -40,3 +40,24 @@ for f in bad-condition bad-cast bad-assign bad-unknown bad-arity bad-types bad-r
|
||||
fi
|
||||
done
|
||||
echo "M2 tests: integer control-flow smoke passed"
|
||||
|
||||
m3tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$m2tmp" "$m3tmp"' EXIT HUP INT TERM
|
||||
for f in struct enum array arrayctx str for nested char; do
|
||||
"$root"/fec --target=bits32 --emit-c "$root"/tests/m3/$f.fe -o "$m3tmp/$f.c"
|
||||
${CC:-cc} -std=c89 -pedantic "$m3tmp/$f.c" -o "$m3tmp/$f"
|
||||
"$m3tmp/$f"
|
||||
done
|
||||
"$root"/fec --target=bits32 --emit-c "$root"/tests/m3/bounds.fe -o "$m3tmp/bounds.c"
|
||||
${CC:-cc} -std=c89 -pedantic "$m3tmp/bounds.c" -o "$m3tmp/bounds"
|
||||
if "$m3tmp/bounds"; then
|
||||
echo "FAIL (bounds trap did not fire): tests/m3/bounds.fe"
|
||||
exit 1
|
||||
fi
|
||||
for f in badfld badmat badarr badcycle badstr badchar badfield badindex; do
|
||||
if "$root"/fec --target=bits32 --emit-c "$root"/tests/m3/$f.fe -o "$m3tmp/$f.c" >/dev/null 2>/dev/null; then
|
||||
echo "FAIL (accepted M3 semantic error): $f.fe"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "M3 tests: structs, enums, arrays, slices, str, match, and bounds passed"
|
||||
|
||||
@@ -7,6 +7,7 @@ if not exist C:\FEC\TESTS md C:\FEC\TESTS
|
||||
if not exist C:\FEC\TESTS\PASS md C:\FEC\TESTS\PASS
|
||||
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 exist C:\FEC\VM.FAIL del C:\FEC\VM.FAIL
|
||||
if exist C:\FEC\STAGE.FAIL del C:\FEC\STAGE.FAIL
|
||||
|
||||
@@ -106,6 +107,41 @@ if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M2\CAST-W~1.FE C:\FEC\TESTS\M2\CAST-W.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
|
||||
copy D:\FEC\TESTS\M3\STRUCT.FE C:\FEC\TESTS\M3\STRUCT.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\ENUM.FE C:\FEC\TESTS\M3\ENUM.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\ARRAY.FE C:\FEC\TESTS\M3\ARRAY.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\STR.FE C:\FEC\TESTS\M3\STR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\FOR.FE C:\FEC\TESTS\M3\FOR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\NESTED.FE C:\FEC\TESTS\M3\NESTED.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\CHAR.FE C:\FEC\TESTS\M3\CHAR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\ARRAYCTX.FE C:\FEC\TESTS\M3\ARRAYCTX.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BOUNDS.FE C:\FEC\TESTS\M3\BOUNDS.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADFLD.FE C:\FEC\TESTS\M3\BADFLD.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADMAT.FE C:\FEC\TESTS\M3\BADMAT.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADARR.FE C:\FEC\TESTS\M3\BADARR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADCYCLE.FE C:\FEC\TESTS\M3\BADCYCLE.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADSTR.FE C:\FEC\TESTS\M3\BADSTR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADCHAR.FE C:\FEC\TESTS\M3\BADCHAR.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADFIELD.FE C:\FEC\TESTS\M3\BADFIELD.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
copy D:\FEC\TESTS\M3\BADINDEX.FE C:\FEC\TESTS\M3\BADINDEX.FE > nul
|
||||
if errorlevel 1 goto stage_fail
|
||||
|
||||
call C:\FEC\TEST-DOS.BAT
|
||||
if exist C:\FEC\TEST.OK goto vm_success
|
||||
echo FAIL>C:\FEC\VM.FAIL
|
||||
|
||||
Reference in New Issue
Block a user