aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h26
-rw-r--r--bootstrap/cgen.c30
-rw-r--r--bootstrap/dump.c1
-rw-r--r--bootstrap/fold.c48
-rw-r--r--bootstrap/parse.c210
-rw-r--r--bootstrap/test.cff25
-rw-r--r--bootstrap/types.c6
7 files changed, 303 insertions, 43 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index 762e978..cb221da 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -30,12 +30,14 @@ struct span {
/* must be alpha sorted */
#define LIST_KEYWORDS(_) \
_(and) \
+ _(as) \
_(break) \
_(case) \
_(const) \
_(defmacro) \
_(do) \
_(else) \
+ _(enum) \
_(extern) \
_(fn) \
_(for) \
@@ -45,9 +47,11 @@ struct span {
_(or) \
_(return) \
_(static) \
+ _(struct) \
_(switch) \
_(typedef) \
_(typeof) \
+ _(union) \
_(while)
enum toktype {
@@ -64,7 +68,6 @@ enum toktype {
TKmacident,
TKgensym,
TKeof,
- NUM_LEXTOKENS
};
#define NUM_KEYWORDS TKintlit
@@ -119,6 +122,8 @@ struct parser {
int idx;
} *curexpan; // macro expansions
int expanno;
+ const struct type *targty;
+ bool used_targetty;
};
enum typetype {
@@ -130,6 +135,7 @@ enum typetype {
TYarr,
TYslice,
TYfn,
+ TYenum,
};
struct type {
@@ -147,8 +153,17 @@ struct type {
const struct type *retty;
bool variadic;
} fn;
+ struct {
+ const struct type *intty;
+ const char *name;
+ slice_t(struct enumfield {
+ const char *name;
+ i64 i;
+ }) vals;
+ int id;
+ } enu;
};
- // cgen.c (mutated later, not hashed or involved in equality)
+ // for cgen.c hack (mutated later, not hashed or involved in equality)
const char *_cname;
};
@@ -225,6 +240,8 @@ enum exprtype {
Ecall,
Eindex,
Eblock,
+ Eas,
+ Eenumval,
};
struct blockstmt {
@@ -266,6 +283,11 @@ struct expr {
struct expr *lhs, *rhs;
} index;
struct blockstmt block;
+ struct expr *child; // cast
+ struct {
+ i64 i;
+ const char *vname;
+ } enu;
};
};
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index 4bc6280..aac0893 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -27,13 +27,13 @@ gentype(const struct type *ty) {
case TYarr:
assert(ty->length >= 0);
case TYslice:
- assert(ty->_cname);
- pri("%s", ty->_cname);
- return;
case TYfn:
assert(ty->_cname);
pri("%s", ty->_cname);
return;
+ case TYenum:
+ gentype(ty->enu.intty);
+ break;
}
if (ty->konst)
pri(" const");
@@ -97,7 +97,8 @@ pri(const char *fmt, ...) {
fprintf(outfp, "%.20f", va_arg(ap, double));
break;
case 's':
- fprintf(outfp, "%s", va_arg(ap, const char *));
+ S = va_arg(ap, const char *);
+ fprintf(outfp, "%s", S ? S : "(null)");
break;
case 'w':
ws = va_arg(ap, int);
@@ -130,6 +131,7 @@ genexpr(struct expr *ex) {
const struct type *ty = unconstify(ex->ty);
switch (ex->t) {
case Eintlit:
+ intlit:
if (ty == ty_int)
pri("%I", ex->i);
else if (ty == ty_u64)
@@ -184,8 +186,14 @@ genexpr(struct expr *ex) {
genblock(ex->block);
pri(")");
break;
- default:
- assert(0);
+ case Eas:
+ pri("((%t)%e)", ex->ty, ex->child);
+ break;
+ case Eenumval:
+ pri("/*%s:%s*/", ex->ty->enu.name, ex->enu.vname);
+ ty = ex->ty->enu.intty;
+ goto intlit;
+ break;
}
}
@@ -292,6 +300,7 @@ liftnestedex(struct expr *ex) {
switch (ex->t) {
case Eintlit: case Eflolit: case Estrlit:
case Eboolit: case Enullit: case Ename:
+ case Eenumval:
break;
case Eprefix:
liftnestedex(ex->unop.child);
@@ -320,8 +329,9 @@ liftnestedex(struct expr *ex) {
case Eblock:
liftnested(blocktostmt(ex->block));
break;
- default:
- assert(0);
+ case Eas:
+ liftnestedex(ex->child);
+ break;
}
}
@@ -484,9 +494,9 @@ defctype(const struct type *ty, void *_) {
if (ty->fn.variadic)
pri("...");
pri(");\n");
-
-
break;
+ case TYenum:
+ *cname = xasprintf("__ty%d", id++);
}
}
diff --git a/bootstrap/dump.c b/bootstrap/dump.c
index 4b337b7..d01f4a7 100644
--- a/bootstrap/dump.c
+++ b/bootstrap/dump.c
@@ -41,6 +41,7 @@ pritype(const struct type *ty) {
if (ty->fn.variadic)
pri("...");
pri(") %t", ty->fn.retty);
+ case TYenum:
}
}
diff --git a/bootstrap/fold.c b/bootstrap/fold.c
index dfd6509..f7962d4 100644
--- a/bootstrap/fold.c
+++ b/bootstrap/fold.c
@@ -12,8 +12,8 @@ numcast(struct expr *ex, const struct type *to) {
const struct type *ufrom = unconstify(from);
int size = to->size;
bool sgn = to->int_signed;
- assert(t0 == TYint || t0 == TYfloat || t0 == TYbool);
- assert(t1 == TYint || t1 == TYfloat || t1 == TYbool);
+ assert(t0 == TYint || t0 == TYfloat || t0 == TYbool || t0 == TYenum);
+ assert(t1 == TYint || t1 == TYfloat || t1 == TYbool || t1 == TYenum);
if (ufrom == uto)
/* pass */;
@@ -201,13 +201,50 @@ findex(struct expr *ex) {
free(r);
}
+static void
+trysetenumvname(struct expr *ex) {
+ const struct type *t = ex->ty;
+ for (int i = 0; i < t->enu.vals.n; ++i)
+ if (ex->enu.i == t->enu.vals.d[i].i) {
+ ex->enu.vname = t->enu.vals.d[i].name;
+ break;
+ }
+}
+
+static void
+fas(struct expr *ex) {
+ struct expr *child = ex->child;
+ const struct type *to = ex->ty,
+ *from = child->ty;
+
+ if (!fold(child))
+ return;
+ if (!isnumtype(to) && to->t != TYenum)
+ return;
+ ex->i = child->i;
+ if (from->t == TYenum) {
+ child->ty = child->ty->enu.intty;
+ }
+ ex->ty = child->ty;
+ ex->i = child->i;
+ if (to->t == TYenum) {
+ numcast(ex, to->enu.intty);
+ ex->ty = to;
+ ex->t = Eenumval;
+ trysetenumvname(ex);
+ } else {
+ numcast(ex, to);
+ }
+ free(child);
+}
+
int
fold(struct expr *ex) {
switch (ex->t) {
case Eintlit: case Eflolit: case Eboolit:
numcast(ex, ex->ty);
return 1;
- case Estrlit:case Enullit:
+ case Estrlit:case Enullit: case Eenumval:
return 1;
case Eprefix:
funary(ex);
@@ -221,13 +258,16 @@ fold(struct expr *ex) {
case Eindex:
findex(ex);
break;
+ case Eas:
+ fas(ex);
+ break;
default:
break;
}
switch (ex->t) {
case Eintlit: case Eflolit: case Estrlit:
- case Eboolit: case Enullit:
+ case Eboolit: case Enullit: case Eenumval:
return 1;
default:
return 0;
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 3cb6924..0804a73 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -1,4 +1,7 @@
#include "all.h"
+#include "vec.h"
+#include <stdint.h>
+#include <strings.h>
/***********/
/** Lexer **/
@@ -81,7 +84,7 @@ aissep(char c) {
case ';': case '?': case '+': case '-':
case '*': case '/': case '&': case '|':
case '^': case '~': case '=': case '\'':
- case '"': case '<': case '>':
+ case '"': case '<': case '>': case ':':
return 1;
return 0;
}
@@ -139,7 +142,7 @@ str2keyword(const char *s) {
}
static bool
-str2number(struct tok *res, const char *s) {
+readnumber(struct tok *res, const char *s) {
char c;
u64 acc = 0;
double accf = 0.0;
@@ -147,6 +150,7 @@ str2number(struct tok *res, const char *s) {
int base = 10;
bool flt = 0;
int nused = 0;
+ const char *suffix = NULL;
for (int i = 0; (c = s[i]); ++i) {
extern int tolower(int);
@@ -167,10 +171,11 @@ str2number(struct tok *res, const char *s) {
if (nused > 0 && c == '_')
continue;
- if (base == 16 && !aisxdigit(c))
- return 0;
- else if (base != 16 && (c < '0' || c > '0' + base - 1))
- return 0;
+ if ((base == 16 && !aisxdigit(c))
+ || (base != 16 && (c < '0' || c > '0' + base - 1))) {
+ suffix = s + i;
+ break;
+ }
++nused;
if (flt) {
@@ -185,9 +190,29 @@ str2number(struct tok *res, const char *s) {
if (flt) {
res->t = TKflolit;
res->flit.f = accf;
+
+ if (!suffix) ;
+ else if (!strcasecmp(suffix, "f")) res->flit.ty = ty_f32;
+ else if (!strcasecmp(suffix, "f32")) res->flit.ty = ty_f32;
+ else if (!strcasecmp(suffix, "f64")) res->flit.ty = ty_f64;
} else {
res->t = TKintlit;
res->ilit.i = acc;
+
+ if (!suffix) ;
+ else if (!strcasecmp(suffix, "u")) res->ilit.ty = ty_uint;
+ else if (!strcasecmp(suffix , "u8")) res->ilit.ty = ty_u8;
+ else if (!strcasecmp(suffix , "i8")) res->ilit.ty = ty_i8;
+ else if (!strcasecmp(suffix, "u16")) res->ilit.ty = ty_u16;
+ else if (!strcasecmp(suffix, "i16")) res->ilit.ty = ty_i16;
+ else if (!strcasecmp(suffix, "u32")) res->ilit.ty = ty_u32;
+ else if (!strcasecmp(suffix, "i32")) res->ilit.ty = ty_i32;
+ else if (!strcasecmp(suffix, "u64")) res->ilit.ty = ty_u64;
+ else if (!strcasecmp(suffix, "i64")) res->ilit.ty = ty_i64;
+ else if (!strcasecmp(suffix, "z")) res->ilit.ty = ty_usize;
+ else if (!strcasecmp(suffix, "zs")) res->ilit.ty = ty_isize;
+ else if (!strcasecmp(suffix, "p")) res->ilit.ty = ty_uptrint;
+ else if (!strcasecmp(suffix, "ps")) res->ilit.ty = ty_iptrint;
}
return 1;
}
@@ -294,7 +319,7 @@ lex(struct parser *P) {
if (readtilsep(P, s, sizeof s, 1) < 0)
fatal(P, P->tokspan, "number literal too long");
- if (!str2number(&tok, s))
+ if (!readnumber(&tok, s))
fatal(P, P->tokspan, "invalid number literal");
tok.span = P->tokspan;
return tok;
@@ -555,7 +580,7 @@ parsetype(struct parser *P) {
}
static const struct type *
-ilittype(struct parser *P, u64 n) {
+ilittype(u64 n) {
if (n <= INT_MAX)
return ty_int;
if (n <= INT32_MAX)
@@ -606,11 +631,13 @@ pexprimary(struct parser *P) {
struct expr ex = {0};
struct tok tok;
+ P->used_targetty = 0;
+
if (lexmatch(P, &tok, TKintlit) || lexmatch(P, &tok, TKchrlit)) {
ex.t = Eintlit;
ex.span = tok.span;
ex.i = tok.ilit.i;
- ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(P, ex.u);
+ ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(ex.u);
} else if (lexmatch(P, &tok, TKflolit)) {
ex.t = Eflolit;
ex.span = tok.span;
@@ -647,10 +674,17 @@ pexprimary(struct parser *P) {
if (!decl)
fatal(P, tok.span, "%s is not defined", tok2str(tok));
if (decl->t == Dtype) {
- assert(0);
+ const struct type *ty = decl->ty;
+ if (ty->t == TYenum) {
+ lexexpect(P, ':');
+ P->targty = ty;
+ goto enumlit;
+ } else {
+ goto experr;
+ }
} else if (decl->t == Dmacro) {
parseexpandmacro(P, &decl->macro);
- return parseexpr(P);
+ ex = parseexpr(P);
} else {
ex.t = Ename;
ex.span = tok.span;
@@ -685,9 +719,29 @@ pexprimary(struct parser *P) {
ex = parseexpr(P);
}
lexexpect(P, ')');
+ } else if (lexmatch(P, &tok, ':')) {
+ const char *vname;
+ int i;
+ enumlit:
+ vname = (tok = lexexpect(P, TKident)).str;
+ if (!(ex.ty = P->targty) || ex.ty->t != TYenum)
+ fatal(P, tok.span, "cannot infer type for enum literal `:%s'", vname);
+ for (i = 0; i < ex.ty->enu.vals.n; ++i)
+ if (!strcmp(ex.ty->enu.vals.d[i].name, vname))
+ goto found;
+ fatal(P, tok.span, "enum `%s' contains no variant `%s'",
+ ex.ty->enu.name, vname);
+ found:
+ P->used_targetty = 1;
+ ex.t = Eenumval;
+ ex.enu.vname = vname;
+ ex.enu.i = ex.ty->enu.vals.d[i].i;
} else {
+ experr:
fatal(P, tok.span, "expected expression (near %s)", tok2str(tok));
}
+
+ P->targty = NULL;
return ex;
}
@@ -696,6 +750,8 @@ pexpostfix(struct parser *P) {
struct expr ex = pexprimary(P);
struct tok tok;
+ if (P->used_targetty) return ex;
+
for (;;) if (lexmatch(P, &tok, '(')) {
vec_t(struct expr) args = {0};
int i = 0, n = ex.ty->fn.params.n;
@@ -703,10 +759,13 @@ pexpostfix(struct parser *P) {
if (ex.ty->t != TYfn)
fatal(P, ex.span, "callee is not a function");
while (!lexmatch(P, NULL, ')')) {
- struct expr arg = parseexpr(P);
+ struct expr arg;
if (i == n && ! ex.ty->fn.variadic)
fatal(P, arg.span, "too many args for call");
+ if (i < n)
+ P->targty = ex.ty->fn.params.d[i];
+ arg = parseexpr(P);
if (i < n && !typeof2(arg.ty, ex.ty->fn.params.d[i++]))
fatal(P, arg.span, "call argument #%d type mismatch", i);
@@ -824,6 +883,30 @@ pexprefix(struct parser *P) {
'&', exprdup(ex)
}
};
+ } else if (lexmatch(P, &tok, TKkw_as)) {
+ const struct type *to, *from;
+ struct expr ex;
+ lexexpect(P, '(');
+ to = parsetype(P);
+ lexexpect(P, ')');
+ P->targty = to;
+ ex = pexprefix(P);
+ from = ex.ty;
+
+ if (typeof2(to, from)) ;
+ else if (to->t == TYint && from->t == TYptr && to->size == from->size) ;
+ else if (from->t == TYint && to->t == TYptr && to->size == from->size) ;
+ else if (from->t == TYbool && to->t == TYint) ;
+ else if (from->t == TYint && to->t == TYbool) ;
+ else if (from->t == TYenum && to->t == TYint) ;
+ else if (from->t == TYint && to->t == TYenum) ;
+ else
+ fatal(P, tok.span, "invalid cast"); // TODO better diagnostics...
+
+ P->targty = to;
+ return (struct expr) {
+ Eas, tok.span, to, .child = exprdup(ex)
+ };
}
return pexpostfix(P);
@@ -855,6 +938,7 @@ pexbitarith(struct parser *P) {
int oret;
ex = pexprefix(P);
+ if (P->used_targetty) return ex;
if (!(oret = peeksbitarithop(P, &tok)))
return ex;
tokt = tok.t;
@@ -930,6 +1014,7 @@ pexcmp(struct parser *P) {
struct tok tok;
ex = pexbitarith(P);
+ if (P->used_targetty) return ex;
if (matchcmpop(P, &tok)) {
struct expr rhs = pexbitarith(P);
if (!typeof2(ex.ty, rhs.ty))
@@ -954,6 +1039,7 @@ pexlog(struct parser *P) {
int tokt;
ex = pexcmp(P);
+ if (P->used_targetty) return ex;
tok = lexpeek(P);
tokt = tok.t;
if (tokt != TKkw_and && tokt != TKkw_or)
@@ -981,6 +1067,7 @@ pexcond(struct parser *P) {
struct tok tok;
ex = pexlog(P);
+ if (P->used_targetty) return ex;
if (lexmatch(P, &tok, '?')) {
struct expr ex2 = parseexpr(P);
struct expr ex3;
@@ -1025,6 +1112,7 @@ pexassign(struct parser *P) {
int oret;
ex = pexcond(P);
+ if (P->used_targetty) return ex;
if ((oret = matchassignop(P, &tok))) {
struct expr rhs = pexcond(P);
if (!islvalue(&ex))
@@ -1081,6 +1169,7 @@ parsevardecl(struct parser *P, struct decl *decl) {
} else {
ty = parsetype(P);
if (lexmatch(P, NULL, '=')) {
+ P->targty = ty;
ini = exprdup(parseexpr(P));
} else if (decl->t == Dlet) {
fatal(P, tok.span, "variable must be initialized");
@@ -1197,8 +1286,13 @@ pstiswitch(struct parser *P, const struct expr *test) {
*f = parseblock0(P);
} else {
do {
- struct expr ex = parseexpr(P);
- assert(ex.ty->t == TYint);
+ struct expr ex;
+ P->targty = test->ty;
+ ex = parseexpr(P);
+ if (!fold(&ex))
+ fatal(P, ex.span, "case expression is not constant");
+ if (!typeof2(ex.ty, test->ty))
+ fatal(P, ex.span, "case expression has incorrect type");
vec_push(&es, ex);
if (!lexmatch(P, &tok, ',')) {
lexexpect(P, TKkw_do);
@@ -1224,7 +1318,7 @@ pstswitch(struct parser *P) {
if (!lexmatch(P, &tok, '{')) {
test = parseexpr(P);
- if (test.ty->t == TYint)
+ if (test.ty->t == TYint || test.ty->t == TYenum)
return pstiswitch(P, &test);
else
assert(0 && "NYI");
@@ -1239,7 +1333,8 @@ static bool
isdecltokt(int tokt) {
switch (tokt)
case TKkw_extern: case TKkw_fn: case TKkw_typedef:
- case TKkw_defmacro: case TKkw_static:
+ case TKkw_defmacro: case TKkw_static: case TKkw_enum:
+ case TKkw_struct: case TKkw_union:
return 1;
return 0;
}
@@ -1378,6 +1473,7 @@ parsestmt(struct parser *P) {
st.t = Sreturn;
st.span = tok.span;
if (!lexmatch(P, &tok, ';')) {
+ P->targty = P->curfn->retty;
st.retex = exprdup(parseexpr(P));
lexexpect(P, ';');
if (!typeof2(st.retex->ty, P->curfn->retty))
@@ -1470,7 +1566,7 @@ parsefn(struct decl *decl, struct parser *P) {
fn->name = name;
lexexpect(P, '(');
- while (!lexmatch(P, NULL, ')')) {
+ while (!lexmatch(P, &tok, ')')) {
struct fnparam param;
if (lexmatch(P, NULL, '...')) {
fn->variadic = 1;
@@ -1479,7 +1575,7 @@ parsefn(struct decl *decl, struct parser *P) {
param.ty = parsetype(P);
vec_push(&params, param);
}
- if (!lexmatch(P, NULL, ',')) {
+ if (!lexmatch(P, &tok, ',')) {
lexexpect(P, ')');
break;
} else if (fn->variadic) {
@@ -1630,17 +1726,78 @@ parsemacro(struct parser *P) {
return macro;
}
+static const struct type *
+parseenum(struct parser *P, const char *name) {
+ struct tok tok;
+ struct type ty = {TYenum};
+ static int id = 0;
+ i64 iota = 0, max = 0, min = 0;
+ vec_t(struct enumfield) vals = {0};
+
+ if (lexmatch(P, &tok, ':')) {
+ ty.enu.intty = unconstify(parsetype(P));
+ if (ty.enu.intty->t != TYint)
+ fatal(P, tok.span, "enum backing type is not integral");
+ }
+
+ lexexpect(P, '{');
+ while (!lexmatch(P, &tok, '}')) {
+ const char *fnam = lexexpect(P, TKident).str;
+ i64 val;
+
+ if (lexmatch(P, &tok, '=')) {
+ struct expr ex = parseexpr(P);
+ if (!fold(&ex) || ex.t != Eintlit)
+ fatal(P, ex.span,
+ "enum initializer must be compile-time integral constant");
+ assert(ex.ty != ty_u64 || ex.u <= INT64_MAX);
+ val = ex.i;
+ } else {
+ val = iota;
+ }
+ if (val < min)
+ min = val;
+ if (val > max)
+ max = val;
+ iota = val + 1;
+ vec_push(&vals, ((struct enumfield) { fnam, val }));
+
+ if (!lexmatch(P, &tok, ',')) {
+ lexexpect(P, '}');
+ break;
+ }
+ }
+
+ if (!ty.enu.intty) {
+ if (min >= 0)
+ ty.enu.intty = ilittype(max);
+ else {
+ if (min >= INT_MIN && max <= INT_MAX) ty.enu.intty = ty_int;
+ if (min >= INT32_MIN && max <= INT32_MAX) ty.enu.intty = ty_int;
+ if (min >= INT64_MIN && max <= INT64_MAX) ty.enu.intty = ty_int;
+ }
+ assert(ty.enu.intty);
+ }
+
+ ty.enu.name = name;
+ ty.enu.id = id++;
+ vec_slice_cpy(&ty.enu.vals, &vals);
+
+ return interntype(ty);
+}
+
static void
parsedecl(struct decl *decl, struct parser *P, bool toplevel) {
struct tok tok = { .span = P->tokspan };
bool externp = 0;
+ const char *name ;
memset(decl, 0, sizeof *decl);
if (lexmatch(P, &tok, TKkw_extern))
externp = 1;
if (lexmatch(P, &tok, TKkw_fn)) {
- const char *name = lexexpects(P, TKident, "function name").str;
+ name = lexexpects(P, TKident, "function name").str;
decl->t = Dfn;
decl->name = decl->fn.name = name;
@@ -1660,21 +1817,24 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) {
"extern static variable inside function cannot be initialized");
lexexpect(P, ';');
} else if (lexmatch(P, &tok, TKkw_typedef)) {
- if (externp)
- fatal(P, tok.span, "typedef cannot be `extern'");
+ if (externp) fatal(P, tok.span, "typedef cannot be `extern'");
decl->t = Dtype;
decl->name = lexexpects(P, TKident, "typedef name").str;
decl->ty = parsetype(P);
decl->_cname = xcalloc(1, sizeof(char *));
lexexpect(P, ';');
} else if (lexmatch(P, &tok, TKkw_defmacro)) {
- if (externp)
- fatal(P, tok.span, "macro cannot be `extern'");
- const char *name = lexexpects(P, TKident, "macro name").str;
+ if (externp) fatal(P, tok.span, "macro cannot be `extern'");
+ name = lexexpects(P, TKident, "macro name").str;
decl->t = Dmacro;
decl->name = name;
decl->macro = parsemacro(P);
decl->macro.name = name;
+ } else if (lexmatch(P, &tok, TKkw_enum)) {
+ if (externp) fatal(P, tok.span, "enum cannot be `extern'");
+ decl->name = lexexpects(P, TKident, "enum name").str;
+ decl->ty = parseenum(P, decl->name);
+
} else {
fatal(P, tok.span, "expected declaration (near %s)",
tok2str(tok));
@@ -1697,7 +1857,7 @@ parse(struct transunit *tu, struct parser *P) {
void
initparser(struct parser *P, const char *fname) {
- assert(NUM_LEXTOKENS - 1 < '!');
+ assert(NUM_KEYWORDS - 1 < '!');
memset(P, 0, sizeof *P);
P->curfile = fname;
if (!(P->fp = fopen(fname, "r")))
diff --git a/bootstrap/test.cff b/bootstrap/test.cff
index ba47c6d..d962b16 100644
--- a/bootstrap/test.cff
+++ b/bootstrap/test.cff
@@ -1,7 +1,30 @@
-typedef v3f ["!"[~-1] - 30]f32;
+typedef v3f ["!"[~-1] - as(int)30.0]f32;
+
+enum Color {
+ Red = 7,
+ Green = -10,
+ Blue,
+}
+
+fn best() Color {
+ return :Green;
+}
+
+fn hex(c Color) u32 {
+ switch (c) {
+ case :Red do return 0xFF0000;
+ case :Green do return 0x00FF00;
+ case :Blue do return 0x0000FF;
+ }
+}
extern fn main (argc int, argv **u8) void {
extern fn printf(fmt *const u8, ...) int;
+
+ printf("red %d\n", Color:Red);
+ printf("green %d\n", Color:Green);
+ printf("blue %d\n", Color:Blue);
+ printf("red ! %.8X\n", hex(:Red));
return;
}
diff --git a/bootstrap/types.c b/bootstrap/types.c
index 401f9e6..0353041 100644
--- a/bootstrap/types.c
+++ b/bootstrap/types.c
@@ -52,7 +52,9 @@ hashtype(const struct type *ty) {
h = jkhashv(h, ty->fn.params.n);
for (int i = 0; i < ty->fn.params.n; ++i)
h = jkhashv(h, ty->fn.params.d[i]);
-
+ case TYenum:
+ h = jkhashv(h, ty->enu.id);
+ break;
}
return h;
}
@@ -82,6 +84,8 @@ typeeql(const struct type *lhs, const struct type *rhs) {
if (!typeeql(lhs->fn.params.d[i], rhs->fn.params.d[i]))
return 0;
return 1;
+ case TYenum:
+ return 0;
}
assert(0 && "unreachable");
}