aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/all.h8
-rw-r--r--bootstrap/cgen.c19
-rw-r--r--bootstrap/parse.c33
-rw-r--r--src/all.hff5
-rw-r--r--src/fmt.cff34
-rw-r--r--src/parse.cff59
6 files changed, 147 insertions, 11 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index ceb9841..9bbab37 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -421,6 +421,7 @@ enum stmttype {
Seuswitch,
Sbreak,
Scontinue,
+ Scswitch,
};
struct iswitchcase {
@@ -471,6 +472,13 @@ struct stmt {
struct {
int id;
} brkcon;
+ struct {
+ slice_t(struct cswitchcase {
+ struct expr test;
+ struct blockstmt t;
+ }) cs;
+ struct blockstmt *f;
+ } cswitch;
};
};
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index 7519982..baf8999 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -442,6 +442,17 @@ genstmt(struct stmt *stmt) {
case Scontinue:
pri("goto _cont%d;\n", stmt->brkcon.id);
break;
+ case Scswitch:
+ pri("if (0) ;\n");
+ for (int i = 0; i < stmt->cswitch.cs.n; ++i) {
+ pri("else if (%e)\n", &stmt->cswitch.cs.d[i].test);
+ genblock(stmt->cswitch.cs.d[i].t);
+ }
+ if (stmt->cswitch.f) {
+ pri("else\n");
+ genblock(*stmt->cswitch.f);
+ }
+ break;
}
}
@@ -626,6 +637,14 @@ liftnested(struct stmt *stmt) {
break;
case Sbreak: case Scontinue:
break;
+ case Scswitch:
+ for (int i = 0; i < stmt->cswitch.cs.n; ++i) {
+ liftnestedex(&stmt->cswitch.cs.d[i].test);
+ liftnested(blocktostmt(stmt->cswitch.cs.d[i].t));
+ }
+ if (stmt->cswitch.f)
+ liftnested(blocktostmt(*stmt->cswitch.f));
+ break;
}
}
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index bf6b534..74ab2e2 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -2113,6 +2113,37 @@ psteuswitch(struct parser *P, const struct expr *test) {
}
static struct stmt
+pstcswitch(struct parser *P) {
+ struct stmt st = {Scswitch};
+ struct tok tok;
+ vec_t(struct cswitchcase) cs = {0};
+ struct blockstmt *f = NULL;
+
+ while (!lexmatch(P, &tok, '}')) {
+ struct cswitchcase c = {0};
+
+ lexexpect(P, TKkw_case);
+
+ if (lexmatch(P, &tok, TKkw_else)) {
+ if (f)
+ fatal(P, tok.span, "duplicate 'case else' block");
+ f = malloc(sizeof *f);
+ *f = parseblock0(P);
+ } else {
+ c.test = parseexpr(P);
+ lexexpect(P, ';');
+ c.t = parseblock0(P);
+ vec_push(&cs, c);
+ }
+ }
+
+ vec_slice_cpy(&st.cswitch.cs, &cs);
+ st.cswitch.f = f;
+ return st;
+
+}
+
+static struct stmt
pstswitch(struct parser *P) {
struct tok tok;
struct expr test;
@@ -2126,7 +2157,7 @@ pstswitch(struct parser *P) {
else
fatal(P, test.span, "bad switch test expression (%t)", test.ty);
} else {
- assert(0 && "NYI");
+ return pstcswitch(P);
}
}
diff --git a/src/all.hff b/src/all.hff
index e090570..895657a 100644
--- a/src/all.hff
+++ b/src/all.hff
@@ -128,3 +128,8 @@ fn bswap32(x u32) u32 {
| ((x << 8) & 0xFF0000)
| (x << 24);
}
+
+fn bswap64(x u64) u64 {
+ return (as(u64)bswap32(x) << 32)
+ | (bswap32(x >> 32));
+}
diff --git a/src/fmt.cff b/src/fmt.cff
index ecf7d74..ad28bbd 100644
--- a/src/fmt.cff
+++ b/src/fmt.cff
@@ -10,13 +10,14 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
defmacro pch(ch) [ {
extern fn isprint(int) int;
- if isprint(ch) != 0 {
- p(ch);
+ let $ch = ch;
+ if isprint($ch) != 0 {
+ p($ch);
} else {
p('\\');
- p('0' + (ch % 8));
- p('0' + ((ch / 8) % 8));
- p('0' + ((ch / 8 / 8) % 8));
+ p('0' + ($ch % 8));
+ p('0' + (($ch / 8) % 8));
+ p('0' + (($ch / 8 / 8) % 8));
}
} ]
@@ -27,12 +28,31 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
case :int;
sprintf(buf, "%lld", tok.u.int);
ps(buf);
+ case :flo;
+ sprintf(buf, "%.14f", tok.u.flo);
+ ps(buf);
+ case :bool;
+ ps(tok.u.bool ? "#t" : "#f");
case :str;
pfmt(proc, parg, "%S", tok.u.str);
- case :ident;
+ case :chr;
+ let t = bswap64(tok.u.uint);
+ p('\'');
+ while t != 0 {
+ if t & 0xFF != 0 {
+ pch(t & 0xFF);
+ }
+ t >>= 8;
+ }
+ p('\'');
+ case :null;
+ ps("#null");
+ case :ident, :macident, :gensym, :label;
if quote { p('`'); }
ps(tok.u.ident);
if quote { p('\''); }
+ case :type;
+ pfmt(proc, parg, "%t", tok.ty);
case else
if tok.t >= 0 and tok.t < NUM_KEYWORDS {
if quote { p('`'); }
@@ -41,14 +61,12 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list)
} else if tok.t > 0 {
if quote { p('`'); }
let t = bswap32(tok.t);
- let i = 0;
while t != 0 {
if t & 0xFF != 0 {
p(t);
}
t >>= 8;
}
- buf[i] = '\0';
if quote { p('\''); }
}
}
diff --git a/src/parse.cff b/src/parse.cff
index bcb5763..07158fb 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -84,6 +84,18 @@ fn issep(c u8) bool {
return #f;
}
+fn ishsep(c u8) bool {
+ if isspace(c) {
+ return #t;
+ }
+ switch (c) {
+ case '(', ')', '[', ']', '{',
+ '}', '.', ',', ';', '"';
+ return #t;
+ }
+ return #f;
+}
+
fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
let i = 0,
c u8 #?;
@@ -98,6 +110,24 @@ fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
return i;
}
+fn readtilhsep(P *Parser, buf [#]u8, dot bool) int {
+ let i = 0,
+ c u8 #?,
+ pred = &ishsep;
+ while (not pred(c = chrpeek(P))) or (dot and c == '.') {
+ chr(P);
+ if not issep(c) {
+ pred = &issep;
+ }
+ if i >= buf.#len - 1 {
+ return -1;
+ }
+ buf[i++] = c;
+ }
+ buf[i++] = 0;
+ return i;
+}
+
fn eatspaces(P *Parser) void {
for ;;chr(P) {
if not isspace(chrpeek(P)) {
@@ -226,6 +256,18 @@ fn lex(P *Parser) Tok {
}
return tok;
}
+ if c == '#' {
+ let s [100]u8 = {};
+ if readtilhsep(P, s[0::], #f) < 0 {
+ fatal(P, P.tokloc, "invalid #keyword");
+ }
+ switch {
+ case streq(s, "#");
+ tok.t = '#';
+ case else
+ fatal(P, P.tokloc, "invalid #keyword");
+ }
+ }
if c == '"' or c == '\'' {
chr(P);
let delim = c;
@@ -255,8 +297,21 @@ fn lex(P *Parser) Tok {
}
}
- tok.t = :str;
- tok.u.str = str->compact();
+ if delim == '"' {
+ tok.t = :str;
+ tok.u.str = str->compact();
+ } else {
+ tok.t = :chr;
+ if str.len == 0 {
+ fatal(P, P.tokloc, "empty char literal");
+ } else if str.len > 8 {
+ fatal(P, P.tokloc, "too long multichar literal %qs", str.dat);
+ }
+ tok.u.uint = 0;
+ vec_each(c0, i, str,
+ tok.u.uint = (tok.u.uint << 8) | c0;
+ )
+ }
return tok;
}
switch c = chr(P) {