diff options
Diffstat (limited to 'src/compiler/compiler.zc')
| -rw-r--r-- | src/compiler/compiler.zc | 107 |
1 files changed, 100 insertions, 7 deletions
diff --git a/src/compiler/compiler.zc b/src/compiler/compiler.zc index 8335ab9..ac504d7 100644 --- a/src/compiler/compiler.zc +++ b/src/compiler/compiler.zc @@ -285,8 +285,12 @@ int fldst, fldi; // the one struct a bare address's field name resolved to char*[8] tpn; int ntp; // type parameters in scope // reading a return type: unknown names are type parameters declared after the function's name int tvauto; +// the typedefs of the blocks being compiled: three words each (the symbol, the block depth and the +// compile context it was made in), newest last. a block's end unlinks them from their names. +word tdstk; int ntd, tdcap; word readonly_types; int dty, dtag; // result of dtype() +int s_typedef; int s_lt, s_gt, s_shr, s_le, s_ge, s_eqeq, s_ne, s_plus, s_struct, s_type, s_typecheck, s_docs, s_small, s_std, s_icon, s_on, s_off, s_new, s_new_t; int s_o3, s_lfa, s_outside, s_new_raw, s_new_oz, s_oob; int s_ld8, s_st8, s_ld16, s_st16, s_ld32, s_st32; @@ -1102,6 +1106,7 @@ int source_lookup(char* name) { // drop the symbols above index to, which ends a scope. int popsyms(int to) { while (nsym > to) { nsym--; sname[nsym][-1] = snext[nsym]; } + while (ntd && tdstk[ntd * 3 - 3] >= to) ntd--; // local typedefs made above to went with them return 0; } // look a name up from a plain string. @@ -2952,6 +2957,7 @@ int block_close(int save) { while (i < save) { if (lhome[i] >= fdepth) { lstate[i] = S_DEAD; lhome[i] = fdepth - 1; } i++; } local_drop(save); fdrop(save); + td_end(fdepth); return 0; } @@ -4388,6 +4394,89 @@ int kw_type() { expect(s_semi); return 0; } +// does a parameter start with a type? a type name straight before , or ) is the parameter's +// own name (fn f(string)), not a type, since a typed parameter always has a name after it. +int paramstart() { + if (tk == T_OP) return tv == s_lk; + if (tk != T_ID) return 0; + if (tv == s_fn) return 1; + if (!istypename(tv)) return 0; + peek(); + return !(pk_tk == T_OP && (pk_tv == s_comma || pk_tv == s_rp)); +} +// does a typedef start here? typedef followed by a name is one, so typedef can still be +// a variable or a function's name. +int typedef_ahead() { + if (tk != T_ID || tv != s_typedef) return 0; + peekat(0); + return pk_tk == T_ID; +} +// unlink the symbol s from its name, leaving the rest of the name's chain as it was. +int td_unlink(int s) { + char* nm = sname[s]; int i = nm[-1] - 1; + if (i == s) { nm[-1] = snext[s]; return 0; } + while (i >= 0 && snext[i] - 1 != s) i = snext[i] - 1; + if (i >= 0) snext[i] = snext[s]; + return 0; +} +// end the scope of the local typedefs made at block depth depth or deeper in this +// compile context (and of any made in a context nested inside it). +int td_end(int depth) { + int k; + while (ntd) { + k = ntd * 3 - 3; + if (tdstk[k + 2] < ctxsp || (tdstk[k + 2] == ctxsp && tdstk[k + 1] < depth)) break; + td_unlink(tdstk[k]); + ntd--; + } + return 0; +} +// is the name q (as a symbol is named) already a typedef of the block being compiled? +int td_here(char* q) { + int k = ntd; + while (k) { + k--; + if (tdstk[k * 3 + 2] != ctxsp || tdstk[k * 3 + 1] != fdepth) break; + if (sname[tdstk[k * 3]] == q) return 1; + } + return 0; +} +// typedef T name; +// the C spelling of type name = T;. name becomes another way to write T: the very same +// type record, so the two are interchangeable everywhere. at the top level the name is +// global; in a function it lasts to the end of its block, like a local. a name that is +// already in use is an error, except the same type under the same name again. a tag +// (.u, .m, .d) belongs to a declaration, not to a type, so a typedef has none. +int kw_typedef() { + char* n; char* q; word t; int s, at, clash = 0, local = infn; + next(); + t = ptype(); + if (panic) return 0; + if (is_op(s_dot)) { die("a typedef names a type, which has no tag: .u, .m and .d go on a declaration"); return 0; } + at = toff; n = name(); + if (panic) return 0; + q = module_symbol(n); + if (local) { + s = findloc(n); + if ((s >= 0 && lhome[s] >= fdepth) || td_here(q)) clash = 1; + } else { + s = lookup_raw(q); + if (s < 0 && module_name) { s = lookup_raw(n); if (s >= 0 && skind[s] != K_TYPE && skind[s] != K_KW) s = 0 - 1; } + if (s >= 0 && skind[s] == K_TYPE && sval[s] == t) return expect(s_semi); // the same typedef again + if (s >= 0) clash = 1; + } + if (clash) serrn(n, "already defined"); + else { + s = addsym(n, K_TYPE, t); + rs_put(at, RS_SYM, rs_sym(s), s); + if (local) { + if (ntd == tdcap) { if (tdcap) tdcap = tdcap * 2; else tdcap = 16; tdstk = chk_resize(tdstk, ntd * 3, tdcap * 3); } + tdstk[ntd * 3] = s; tdstk[ntd * 3 + 1] = fdepth; tdstk[ntd * 3 + 2] = ctxsp; ntd++; + } + } + expect(s_semi); + return 0; +} // (T) or (T*) ahead of the current '(', within the lookahead we have // the parser sees ( and has to decide between a parenthesized expression and a // cast. a cast is ( type stars ) so peek ahead through the stars to the ). @@ -5556,6 +5645,7 @@ int types_init() { addsym(tword[2], K_TYPE, tword); addsym(tint[2], K_TYPE, tint); addsym(tchar[2], K_TYPE, tchar); addsym(tbool[2], K_TYPE, tbool); addsym(tvoid[2], K_TYPE, tvoid); addsym(tfloat[2], K_TYPE, tfloat); addsym(intern("f64"), K_TYPE, tfloat); + addsym(intern("string"), K_TYPE, tptr(tchar)); // string is char*, as if by typedef char* string; // f32: single precision. a variable holds the rounded value as a double; an element // of an array or pointer of f32 is packed two to a word, like the sized integers f32p = tnew(TY_FLOAT, 1, intern("f32"), 0); @@ -5570,7 +5660,7 @@ int types_init() { s_le = intern("<="); s_ge = intern(">="); s_eqeq = intern("=="); s_ne = intern("!="); s_plus = intern("+"); - s_struct = intern("struct"); s_type = intern("type"); s_typecheck = intern("typecheck"); s_docs = intern("docs"); s_std = intern("std"); s_icon = intern("icon"); s_small = intern("small"); + s_struct = intern("struct"); s_type = intern("type"); s_typedef = intern("typedef"); s_typecheck = intern("typecheck"); s_docs = intern("docs"); s_std = intern("std"); s_icon = intern("icon"); s_small = intern("small"); s_on = intern("on"); s_off = intern("off"); s_new = intern("rt.new"); @@ -6485,7 +6575,7 @@ int closure() { while (1) { pty[np] = tword; if (expected && expected[0] == TY_FN && np < expected[3]) pty[np] = expected[7 + np]; - if (!is_op(s_dot) && ((tk == T_OP && tv == s_lk) || (tk == T_ID && (tv == s_fn || istypename(tv))))) { + if (!is_op(s_dot) && paramstart()) { pty[np] = ptype(); if (pty[np][0] == TY_ARR) pty[np] = decay(pty[np]); } tag = 0; @@ -7660,7 +7750,7 @@ word stmtstart() { int s; if (tk == T_OP) return tv == s_semi || tv == s_lb || tstart(); if (tk != T_ID || findloc(tv) >= 0) return 0; - if (tstart()) return 1; + if (tstart() || typedef_ahead()) return 1; s = lookup(tv); return s >= 0 && skind[s] == K_KW && !(sflag[s] & F_EXPR); } @@ -7762,6 +7852,7 @@ int stmt_inner() { if (s >= 0 && skind[s] == K_KW && (sflag[s] & F_STMT)) { kwcall(s, 0); return 0; } } if (untyped_const()) { next(); localdecl(2); return 0; } + if (typedef_ahead() && findloc(tv) < 0) return kw_typedef(); if (tstart()) { localdecl(1); return 0; } if (tk == T_OP) { if (tv == s_semi) { next(); return 0; } @@ -8646,7 +8737,7 @@ int prescan(int kind, int obj) { if (is_op(s_lb)) depth++; else if (is_op(s_rb)) { depth--; pend = 0; po3 = 0; } else if (depth <= 0) { - if (is_id(s_type)) { while (tk != T_EOF && !is_op(s_semi)) next(); if (is_op(s_semi)) next(); pend = 0; po3 = 0; continue; } + if (is_id(s_type) || typedef_ahead()) { while (tk != T_EOF && !is_op(s_semi)) next(); if (is_op(s_semi)) next(); pend = 0; po3 = 0; continue; } if (tk == T_ID && rt.eq_w(tv, "namespace")) { kw_namespace(); continue; } if (is_op(s_semi)) { pend = 0; po3 = 0; } else if (is_op(s_dot)) { peek(); if (pk_tk == T_ID && pk_tv == s_u) pend = 1; } @@ -8795,6 +8886,7 @@ int epilogue() { infn = 0; local_drop(lbase); fdrop(lbase); + td_end(0); return 0; } // the statements of a function between its braces, then the end-of-function @@ -8850,7 +8942,7 @@ int fndef(int chk, int rty, int ret, int n) { t = 0; pty[np] = tword; pk = 0; - if (!is_op(s_dot) && ((tk == T_OP && tv == s_lk) || (tk == T_ID && (tv == s_fn || istypename(tv))))) { + if (!is_op(s_dot) && paramstart()) { pty[np] = ptype(); typed = 1; pk = 1; if (pty[np][0] == TY_ARR) pty[np] = decay(pty[np]); if (isagg(pty[np])) { @@ -9115,7 +9207,7 @@ int topsync() { while (tk != T_EOF) { if (is_op(s_lb)) depth++; else if (is_op(s_rb)) { depth--; if (depth < 0) depth = 0; } - else if (!depth && tk == T_ID && (tv == s_fn || tv == s_var || tv == s_const || tv == s_struct || tv == s_type + else if (!depth && tk == T_ID && (tv == s_fn || tv == s_var || tv == s_const || tv == s_struct || tv == s_type || tv == s_typedef || tv == s_enhance || tv == s_typecheck || tv == s_docs || tv == s_unchecked || tv == s_immediate || tv == s_o3 || tv == s_memdebug || tv == s_enum || tv == s_include)) break; next(); @@ -9225,6 +9317,7 @@ int topitem1() { if (is_id(s_var)) return gdecl(0); if (is_id(s_struct)) { kw_struct(); return 0; } if (is_id(s_type)) return kw_type(); + if (typedef_ahead()) return kw_typedef(); if (is_id(s_typecheck)) return kw_typecheck(); if (is_id(s_docs)) return kw_docs(); if (is_id(s_memdebug)) return kw_memdebug(); @@ -10088,7 +10181,7 @@ int zc_init() { poolend = R_POOLEND; poolblocks = 0; namecount = 0; rt.fill_w(namehash, 0, hashcap); nsym = 0; nfixu = 0; fixfree = 0; nbin = 0; nun = 0; nasg = 0; nkop = 0; seqtop = 0; - lsp = 0; ctxsp = 0; snaptop = 0; nloc = 0; lbase = 0; npm = 0; npe = 0; rt.fill_w(lkeys, 0, lkeycap); lkeyn = 0; + lsp = 0; ctxsp = 0; ntd = 0; snaptop = 0; nloc = 0; lbase = 0; npm = 0; npe = 0; rt.fill_w(lkeys, 0, lkeycap); lkeyn = 0; s_lp = intern("("); s_rp = intern(")"); s_lb = intern("{"); s_rb = intern("}"); s_lk = intern("["); s_rk = intern("]"); s_comma = intern(","); s_semi = intern(";"); s_eq = intern("="); s_arrow = intern("->"); s_inc = intern("++"); s_dec = intern("--"); |
