aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/setup.zc
blob: ac455db83a0597971018c38b5cfdfed38fe142e5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// ---- setup ----

// the collector's roots for the compiler's half of the memory map: the program
// area (globals live between functions), the genome's globals, the input source
// frames, the live frame stack and the live data stack. rt.zc declares this
// and calls it from gc().
int gc_roots() {
	int end = ptop; if (end > rt.CODE_END) end = rt.CODE_END;
	rt.markrange(0, end);
	if (!hdelta && here > ptop && ptop < rt.CODE_END) { end = here; if (end > rt.CODE_END) end = rt.CODE_END; rt.markrange(ptop, end); }	// globals of a unit still compiling
	rt.markrange(rt.GORG, rt.GORG[6]);
	rt.markrange(R_IH, R_POOLEND);
	rt.markrange(sval, sval + nsym);
	rt.markrange(R_TY, R_TYEND);
	rt.markrange(R_SRC, R_SRC + R_SRC_cap);
	rt.gc_frames();
	rt.markrange(rt.dsp(), rt.data_top);
	return 0;
}
// start-up in two parts. zc_init clears the intern table and interns the
// spellings the parser compares against; zc_tables fills the operator and
// keyword tables. an operator is a name, a precedence and a code sequence in
// the vm's own one-letter mnemonics (see seqasm), so "<=" is "~ < 1 ^": swap,
// less-than, flip the bit.
int zc_init() {
 receiver_methods = 0; closure_expected = 0;
 effect_floor = 0; effect_symbols = 0; effect_edges = 0; effect_requirements = 0; effect_current = 0;
	pooltop = R_POOL;
	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; 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("--");
	s_star = intern("*");
	s_slash = intern("/");
	s_amp = intern("&");
	s_colon = intern(":");
	s_hash = intern("#");
	s_minus = intern("-");
	s_dot = intern(".");
	s_q = intern("?");
	s_case = intern("case");
	s_default = intern("default");
	s_andand = intern("&&");
	s_oror = intern("||");
	s_fn = intern("fn"); s_var = intern("let"); s_const = intern("const"); s_else = intern("else");
	s_as = intern("as"); s_unchecked = intern("unchecked"); s_unbounded = intern("unbounded"); s_immediate = intern("immediate");
	s_m = intern("m"); s_d = intern("d"); s_u = intern("u"); s_static = intern("static");
	s_start = intern("run.start");
	s_main = intern("main");
	s_free = intern("rt.free");
	s_recycle = intern("rt.recycle"); s_copy_w = intern("rt.copy_w");
	s_do = intern("do");
	s_while = intern("while");
	s_enum = intern("enum");
	s_include = intern("include");
	s_memdebug = intern("memdebug"); s_scrub = intern("rt.scrub"); s_alloc = intern("rt.alloc_line");
	s_check = intern("rt.checkptr"); s_memset = intern("rt.mem_set");
	s_own = intern("rt.own"); s_qnew = intern("run.qnew"); s_fovf = intern("rt.frame_overflow");
	s_frame_floor = intern("rt.frame_floor"); s_frame_top = intern("rt.frame_top"); s_frame_node = intern("rt.frame_node");
	s_frame_busy = intern("rt.frame_busy"); s_frame_guard = intern("rt.frame_guard");
	s_frame_grow = intern("rt.frame_grow"); s_frame_leave = intern("rt.frame_leave");
	s_enhance = intern("enhance"); s_micro = intern("micro"); s_vm = intern("vm");
	return 0;
}
// operators and keywords. these are plain tables in memory: a program can
// add operators, change precedences or replace keywords with its own.
// (the order of the first binary operators matters: cexpr refers to * + - << >>
// & | by their index, and the comments mark which ones)
int zc_tables() {
	add_unop("!", "0 $ 0 ~ - | 63 > 1 +");	// index 0
	add_unop("!!", "0 $ 0 ~ - | 63 > 0 ~ -");	// index 1: normalize to 0 or 1
	add_unop("~", "-1 ^");				// index 2
	add_unop("-", "0 ~ -");
	add_binop("*", 10, "*");			// the first few indexes are used by cexpr
	add_binop("/", 10, "idiv");			// native divide, wired in by rt.zc
	add_binop("%", 10, "imod");
	add_binop("+", 9, "+");				// 3
	add_binop("-", 9, "-");				// 4
	add_binop("<<", 8, "ishl");			// 5
	add_binop(">>", 8, ">");			// 6
	add_binop("<", 7, "<");
	add_binop(">", 7, "~ <");
	add_binop("<=", 7, "~ < 1 ^");
	add_binop(">=", 7, "< 1 ^");
	add_binop("==", 6, "- 0 $ 0 ~ - | 63 > 1 +");
	add_binop("!=", 6, "- 0 $ 0 ~ - | 63 > 0 ~ -");
	add_binop("&", 5, "&");				// 13
	add_binop("^", 4, "^");
	add_binop("|", 3, "|");				// 15
	add_binop("&&", -1, 0);
	add_binop("||", -2, 0);
	addkop(s_eq); addkop(s_arrow); addkop(s_inc); addkop(s_dec);
	add_kw("let", kw_var, F_STMT);
	add_kw("if", kw_if, F_STMT);
	add_kw("while", kw_while, F_STMT);
	add_kw("for", kw_for, F_STMT);
	add_kw("do", kw_do, F_STMT);
	add_kw("enum", kw_enum, F_STMT | F_TOP);
	add_kw("include", kw_include, F_TOP | F_STMT);
	add_kw("embed", kw_embed, F_TOP | F_STMT);
	add_kw("run.method", kw_method, F_TOP | F_STMT);
	add_kw("run.share_value", kw_share_value, F_EXPR);
 add_kw("run.syntax", kw_syntax, F_TOP | F_STMT);
 add_kw("run.statement_hook", kw_statement_hook, F_TOP | F_STMT);
	add_kw("memdebug", kw_memdebug, F_STMT | F_TOP);
	add_kw("hints", kw_hints, F_STMT | F_TOP);
	add_kw("switch", kw_switch, F_STMT);
	add_kw("break", kw_break, F_STMT);
	add_kw("continue", kw_continue, F_STMT);
	add_kw("defer", kw_defer, F_STMT);
	add_kw("return", kw_return, F_STMT);
	add_kw("unchecked", kw_unchecked, F_STMT);
	add_kw("unbounded", kw_unbounded, F_STMT);
	add_kw("asm", kw_asm, F_STMT | F_EXPR);
	add_kw("quote", kw_quote, F_EXPR);
	add_kw("sizeof", kw_sizeof, F_EXPR);
	add_kw("typeof", kw_typeof, F_EXPR);
	add_kw("extern", kw_extern, F_TOP);
	add_kw("cfunc", kw_cfunc, F_EXPR);
	add_kw("o3", kw_o3, F_STMT);
	add_kw("len", kw_len, F_EXPR);
	add_kw("cap", kw_cap, F_EXPR);
	add_kw("push", kw_push, F_EXPR);
	add_kw("pop", kw_pop, F_EXPR);
	add_kw("resize", kw_resize, F_EXPR);
	return 0;
}
// the default map's type records sit in the last 16384 words of the heap.
// the type list is the first words of that range, so it cannot be kept aside
// as a buddy block: types_init would overwrite the header and the allocator
// would hand the range out again. cut the heap off at R_TY until the unit
// has been compiled, then put the tail back for the program.
int heldk;
// the size class of the type area, for the memory map.
int type_class() {
	int k = 0, n = R_TYEND - R_TY;
	while (k < 31 && rt.pow2[k] < n) k++;
	if (rt.pow2[k] != n) return 0 - 1;
	return k;
}
// keep the type area out of the collector's reach while it is in use.
int shield_types() {
	int k;
	heldk = 0 - 1;
	if (R_TY <= rt.HEAP_LO || R_TY >= rt.HEAP_HI || R_TYEND > rt.HEAP_HI) return 0;
	k = type_class();
	if (k < 0) return 0;
	if (R_TY + rt.pow2[k] != R_TYEND) return 0;
	if (rt.heap_reset(R_TY)) heldk = k;
	return 0;
}
// let the collector see the type area again.
int unshield_types() {
	if (heldk >= 0) { rt.heap_uncut(R_TY, heldk); heldk = 0 - 1; }
	return 0;
}
// the genome's entry point, run when the image boots: set up the heap and
// the compiler, then either run the language server (a genome that carries it)
// or compile the unit on stdin, collect the garbage that compiling made, and
// call main().
int start() {
	int s, f;
	rt.heap_init(); chk_heap = 1;
	shield_types();
	zc_init();
	blob_load(rt.GORG[5], 0);
	zc_tables();
	types_init();
	rt.frame_namer = sval[lookup(intern("run.frame_symbol"))];
	here = 0; hdelta = 0; hlimit = rt.CODE_END; ptop = 0;
	ubase = nsym; vislo = 0;
	// a genome that carries the language server runs it instead of compiling stdin
	s = lookup(intern("lsp.lsp_main"));
	if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); rt.halt(); }
	xc_init();
	unit_stdin();
	if (xc_on) rt.halt();	// --explain-checks: the records are out; main does not run
	if (here > ptop) ptop = here;
	rt.scrub();	// compilation's stale words would keep quarantined blocks alive
	rt.gc();
	// the type area stays out of the allocator. main() may compile again
	// (the self-host does) and a later new() would otherwise reuse it.
	if (mdbg_flags) rt.mem_set(mdbg_flags);
	// a unit that carries src/lib/std.zc has a libinit to fill argc/argv/envc/envp
	// with. it runs before main, the same way lsp_main runs instead of stdin.
	s = lookup(intern("std.libinit"));
	if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); }
	s = lookup(s_main);
	if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); }
	rt.halt();
	return 0;
}