aboutsummaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/builtins.zc12
-rw-r--r--src/compiler/decl.zc26
-rw-r--r--src/compiler/expr.zc25
-rw-r--r--src/compiler/lex.zc8
4 files changed, 58 insertions, 13 deletions
diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc
index 9a89052..cbc380e 100644
--- a/src/compiler/builtins.zc
+++ b/src/compiler/builtins.zc
@@ -71,8 +71,10 @@ int ptagged(word t) {
// enum name { A, B = 5 } is a plain enum: each member is a constant, plain (A)
// and scoped (name.A). a member with a block of fields makes it a tagged enum
// (see enum_tagged): enum name { circle { int r; }, dot }.
+// the first member of the enum being read, so a member's value can name the members before it; -1 outside
+int enum_open = 0 - 1;
int kw_enum() {
- char* n; char* en = 0; int first = npm, cnt = 0, tagged = 0, gi, nf, v = 0, et = 0, sk, ft; char* fname;
+ char* n; char* en = 0; int first = npm, cnt = 0, tagged = 0, gi, nf, v = 0, et = 0, sk, ft, rv = 0; char* fname;
stmtonly();
next();
if (tk == T_ID) { en = tv; next(); }
@@ -97,7 +99,9 @@ int kw_enum() {
expect(s_semi);
}
expect(s_rb);
- } else if (accept(s_eq)) { pm_val[gi] = cexpr(); pm_exp[gi] = 1; }
+ } else { enum_open = first; if (accept(s_eq)) { pm_val[gi] = cexpr(); pm_exp[gi] = 1; } enum_open = 0 - 1; }
+ if (pm_exp[gi]) rv = pm_val[gi]; else if (!pm_nf[gi]) pm_val[gi] = rv; // the running value, read by cprim
+ rv++;
cnt++;
if (!accept(s_comma)) break;
if (is_op(s_rb)) break;
@@ -312,6 +316,7 @@ int inc_compile(char* buf, char* name, char*.d dir) {
int kw_include() {
int pp, sv; char* path; char* buf;
stmtonly();
+ if (infn) { die("include is top level only"); return 0; } // appendix b.2.9
next();
if (tk == T_ID) {
while (1) {
@@ -701,7 +706,8 @@ int array_len(word t) {
return 0;
}
if (t[0] == TY_ARR) { op(O_DROP); lit(t[3]); }
- else { tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); }
+ else { if (!tc_on && t[0] == TY_PTR && t[4][0] == TY_CHAR) serr("len needs an array, not a char* (use rt.len_w, or a bstr)"); // b.2.14: it would read word 0
+ tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); }
xty = tint;
xlenloc = -1; xstamp = 0;
if (a >= 0 && t[0] == TY_DYN && t[3]) xlenloc = a; // the whole expression is len of a fixed array
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 3a02b90..87281ad 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -282,12 +282,17 @@ int body() {
// into stype, checked against any earlier prototype or prescan result, and
// where the o3 region for an o3 function is handed to the core)
int fndef(int chk, int rty, int ret, int n) {
- int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline;
+ int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline, redef, amb = 0, nonm = 0;
o3nxt = 0;
if (rty || ntp) typed = 1;
if (!dnm) dnm = n;
s = lookup(n);
- if (s < 0 || s < ubase || skind[s] != K_FN || (sflag[s] & F_DEF)) {
+ redef = 0; // a function this module already defined: a prototype after it keeps it (b.2.4), a second body is defined twice (b.2.3)
+ if (s >= ubase && skind[s] == K_FN && (sflag[s] & F_DEF) && !(sflag[s] & F_TPL) && !ginst && !ntp) {
+ word qn = n; if (module_name) qn = module_symbol(n);
+ redef = rt.eq_w(sname[s], qn);
+ }
+ if (!redef && (s < 0 || s < ubase || skind[s] != K_FN || (sflag[s] & F_DEF))) {
s = addsym(n, K_FN, 0);
sflag[s] = 0;
}
@@ -322,7 +327,9 @@ int fndef(int chk, int rty, int ret, int n) {
} else if (tv == s_d) t = 2; else die("a parameter tag is .m or .d");
next();
}
- pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff); pn[np] = name();
+ pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff);
+ if (!pk && !t && tk == T_ID && istypename(tv)) amb = amb | (1 << np); // int f(int): a name, or a type if this is a prototype
+ if (pk && tk == T_OP && (tv == s_comma || tv == s_rp)) { pn[np] = 0; nonm = 1; } else pn[np] = name(); // int f(int*, int): a prototype's parameters may be unnamed
if (o3f && pty[np] == tword) serr("o3 parameters need a type");
if (np >= 12 && t) die("only the first 12 parameters can be tagged");
pt[np] = t;
@@ -333,6 +340,13 @@ int fndef(int chk, int rty, int ret, int n) {
}
}
expect(s_rp);
+ if (is_op(s_semi)) { // a prototype: a lone type name is an unnamed parameter of that type (b.2.13)
+ i = 0;
+ while (i < np) {
+ if (((amb >> i) & 1) && pn[i]) { t = lookup(pn[i]); if (t >= 0 && skind[t] == K_TYPE) { pty[i] = sval[t]; typed = 1; } }
+ i++;
+ }
+ } else if (nonm) serr("a parameter needs a name");
sig = ret + np + np + tags * 64;
if ((sflag[s] & F_SIG) && !(sflag[s] & F_PRE)) {
if (ssig[s] != sig) serrn(n, "doesn't match its earlier declaration");
@@ -475,8 +489,12 @@ int gdecl2(int t, int tg, int n) {
if (arraytype[0] != TY_ARR || !is_op(s_lb)) serr("a global compound literal needs an array initializer");
else { array_literal(arraytype); vv = xcval; *(a + hdelta) = vv; if (!t) stype[s] = decay(xty); }
}
+ else if (t && isfl(t) && tk == T_FLT) { // float g = 1.5; (appendix b.2.7)
+ vv = tv; next(); if (t == tf32) vv = rt.zs2f(rt.zf2s(vv)); *(a + hdelta) = vv; // an f32 scalar is a rounded double
+ }
else {
- vv = cnorm(t, cexpr()); *(a + hdelta) = vv;
+ vv = cnorm(t, cexpr()); if (t && isfl(t)) { vv = vf_i2f(vv); if (t == tf32) vv = rt.zs2f(rt.zf2s(vv)); } // float g = 2; is 2.0
+ *(a + hdelta) = vv;
if (gok) { if (!gty) gty = tint; else if (gty != tint) gok = 0; }
}
} else if (gok) gok = 0; // no initializer: nothing says what it is
diff --git a/src/compiler/expr.zc b/src/compiler/expr.zc
index 4c77ceb..e449508 100644
--- a/src/compiler/expr.zc
+++ b/src/compiler/expr.zc
@@ -647,7 +647,7 @@ word closure_layout(int closure_index, int count) {
// variable in. ctx_push / ctx_pop save and restore the enclosing function's
// compiler state around the body.
int closure() {
- int np = 0; char*[20] pn; word[20] pty; int hop, entry, i, t, envl, ncap, c, result, declared = 0, tags = 0, tag, lt, lfl = tline; word[20] ptags;
+ int np = 0; char*[24] pn; word[24] pty; int hop, entry, i, t, envl, ncap, c, result, declared = 0, tags = 0, tag, lt, lfl = tline; word[24] ptags;
word expected = closure_expected; closure_expected = 0;
reserve_closures(nclo + 1);
if (o3on) serr("closures can't be made inside an o3 region");
@@ -668,8 +668,8 @@ int closure() {
if (expected && expected[0] == TY_FN && !tag && (isptr(pty[np]) || pty[np][0] == TY_DYN || pty[np][0] == TY_FN)) ptags[np] = 1;
pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff); pn[np] = name();
np++;
- if (np >= 20) { die("too many parameters"); break; }
if (!accept(s_comma)) break;
+ if (np >= 24) { die("too many parameters"); break; } // 24, like a function
}
}
expect(s_rp);
@@ -1561,12 +1561,17 @@ int postfix_tail(int c) {
}
return c;
}
+// a global variable or array named u, m or d: then u*x is a multiplication (spec 1.6.3)
+int tag_is_global(int n) {
+ int s = lookup(n);
+ return s >= 0 && (skind[s] == K_GVAR || skind[s] == K_GARR);
+}
// prefix operators: the u*x / d*x / m*x recasts (the star has to touch the
// tag), casts like (int)x and (node*)x, dereference, address-of, prefix ++ and
// --, and any unary operator a program added (- ! ~ built in).
int unary() {
int c, un, t, place, constant, value; word storage, dependency;
- if (tk == T_ID && (tv == s_u || tv == s_m || tv == s_d) && findloc(tv) < 0) { // u*x, d*x, m*x: recast only when * is glued and the tag is not a local's name
+ if (tk == T_ID && (tv == s_u || tv == s_m || tv == s_d) && findloc(tv) < 0 && !tag_is_global(tv)) { // u*x, d*x, m*x: recast only when * is glued and the tag is not a local's name
peek();
if (pk_tk == T_OP && pk_tv == s_star && pq_gl[0]) {
t = S_M; if (tv == s_u) t = S_U; if (tv == s_d) t = S_D;
@@ -1777,7 +1782,7 @@ int storekeep(int t) {
// restored for the second side) and then joined, so a variable can't be given
// away on one side only. both sides are fresh objects, or neither is.
int ternary(int c) {
- int a, b, s0, sa, livea, live0 = live, n0 = nloc, ca, cb, ta, ba, bb; word temp_a, temp_b, mask_a, mask_b;
+ int a, b, s0, sa, livea, live0 = live, n0 = nloc, ca, cb, ta, ba, bb, conv, skip, back; word temp_a, temp_b, mask_a, mask_b;
rval(); plainuse(c);
ftest();
next();
@@ -1785,6 +1790,7 @@ int ternary(int c) {
s0 = snap_push();
ca = expr(); rval(); ta = xty; ba = xbor; temp_a = xaf; mask_a = effect_mask(ca);
if (ca != C_FRESH) plainuse(ca);
+ conv = -1; if (isnum(ta) && !isfl(ta) && ta != tword) { conv = hole(); op(O_JMP); back = here; setlit(conv, back); } // a jump to the next word, redirected below if the other side is a float (appendix b.2.5)
livea = live; sa = snap_push();
b = hole(); op(O_JMP);
expect(s_colon);
@@ -1792,11 +1798,14 @@ int ternary(int c) {
snap_restore(s0); live = live0;
cb = expr(); rval(); bb = xbor; temp_b = xaf; mask_b = effect_mask(cb);
if (cb != C_FRESH) plainuse(cb);
+ if (isfl(ta) && !isfl(xty)) { op(OP_I2F); xfloat = 1; xty = tfloat; } // on the second side's path only
join2(sa, livea, b, live, n0, "ends the two sides of ?: in different states");
snap_pop(s0);
- if (isfl(ta) && !isfl(xty)) { op(OP_I2F); xfloat = 1; xty = tfloat; }
+ if (conv >= 0 && isfl(xty)) { // the first side was an integer: convert it out of line
+ skip = hole(); op(O_JMP); setlit(conv, here); op(OP_I2F); lit(back); op(O_JMP); setlit(skip, here);
+ }
if (!compat(ta, xty) && !compat(xty, ta)) tcerr("the two sides of ?:", ta, xty);
- if (ta != tword && !isfl(ta)) xty = ta;
+ if (ta != tword && !isfl(ta) && !(conv >= 0 && isfl(xty))) xty = ta;
else if (isfl(ta) || isfl(xty)) { xty = tfloat; xfloat = 1; }
if_value = 0;
effect_value = mask_a | mask_b;
@@ -1950,6 +1959,10 @@ word cprim() {
}
}
}
+ if (tk == T_ID && enum_open >= 0) { // an earlier member of the enum being read (spec 2.8.1)
+ mc = npm - 1;
+ while (mc > enum_open) { mc--; if (pm_name[mc] == tv && !pm_nf[mc]) { next(); return pm_val[mc]; } }
+ }
die("expected a constant");
return 0;
}
diff --git a/src/compiler/lex.zc b/src/compiler/lex.zc
index 0348cae..712eff8 100644
--- a/src/compiler/lex.zc
+++ b/src/compiler/lex.zc
@@ -298,6 +298,12 @@ int fcoerce(word dst) {
if (dst == tf32 && xty != tf32 && !ispk(xty)) { xenh("zf2s"); xenh("zs2f"); xty = tf32; }
return 0;
}
+ if (dst[0] == TY_BOOL && xty[0] != TY_BOOL) { // bool holds 0 or 1: any nonzero value is 1 (spec 2.1)
+ if (xfloat) { op(OP_FLIT); emit(0); op(OP_FEQ); lit(1); op(18); xfloat = 0; }
+ else { lit(0); op(O_PICK); lit(0); op(O_SWAP); op(O_SUB); op(17); lit(63); op(19); lit(0); op(O_SWAP); op(O_SUB); }
+ if (compat(dst, xty)) xty = tbool; // (otherwise keep the type, so a type check after this still sees it)
+ return 0;
+ }
if (!xfloat) {
if (tbytes(dst) && !samesz(dst, xty)) tnorm(dst);
return 0;
@@ -423,6 +429,7 @@ int docblock(int nl) {
doc_char(c);
if (c == 10) bol = 1;
}
+ if (ch < 0) { tline = line; serr("unterminated comment"); }
while (dn && (dbuf[dn - 1] == 32 || dbuf[dn - 1] == 9 || dbuf[dn - 1] == 10 || dbuf[dn - 1] == 13)) dn--;
doc_char(10); dlast = cl; docpending = 1;
if (adj) dn = 0;
@@ -484,6 +491,7 @@ int lex1() {
if (docs_on) { docblock(nl); tglue = 0; continue; }
nextch();
while (ch >= 0) { if (ch == '*') { nextch(); if (ch == '/') break; } else nextch(); }
+ if (ch < 0) { tline = line; serr("unterminated comment"); } // a /* with no */ (spec 1.2.2)
nextch(); tglue = 0; continue;
}
tline = line; toff = cpos() - 1; tbuf[0] = '/'; oplex(1); return 0;