1- // bootstrap/compiler_core.nula — Stage 5: closures with env capture
1+ // bootstrap/compiler_core.nula — Stage 6: 4-slot env, 1- capture closures
22// Return: (value << 16) | pos. Entry: (hash << 32) + value.
33// Closure encoding (32-bit): flag(bit30) | (ph<<23) | (bs<<16) | (cap_h<<8) | cap_v
44// flag = 1 << 30 = 1073741824. Position is clean source pos.
5+ // Env: e0..e3 with elen 0..4. let pushes to next slot. Closures capture most recent.
56
67fn is_digit(c: Int) -> Bool { c >= 48 and c <= 57 }
78fn is_alpha(c: Int) -> Bool { (c >= 65 and c <= 90) or (c >= 97 and c <= 122) }
@@ -34,23 +35,18 @@ fn read_ident(src: String, pos: Int, len: Int, h: Int) -> Int {
3435 }
3536}
3637
37- fn env_lookup(e0: Int, e1: Int, elen: Int, h: Int) -> Int {
38+ // 4-slot environment lookup: search e3, e2, e1, e0 (most-recent first).
39+ fn env_lookup(e0: Int, e1: Int, e2: Int, e3: Int, elen: Int, h: Int) -> Int {
3840 if elen <= 0 then 0
39- else if elen >= 2 then {
40- let s1 = e1;
41- let h1 = s1 >> 32;
42- if h1 == h then s1 & 0xFFFFFFFF
43- else {
44- let s0 = e0;
45- let h0 = s0 >> 32;
46- if h0 == h then s0 & 0xFFFFFFFF
47- else 0
48- }
49- } else {
50- let s0 = e0;
51- let h0 = s0 >> 32;
52- if h0 == h then s0 & 0xFFFFFFFF
53- else 0
41+ else {
42+ // Check most recent slot first
43+ let slot = if elen >= 4 then e3
44+ else if elen >= 3 then e2
45+ else if elen >= 2 then e1
46+ else e0;
47+ let sh = slot >> 32;
48+ if sh == h then slot & 0xFFFFFFFF
49+ else env_lookup(e0, e1, e2, 0, elen - 1, h)
5450 }
5551}
5652
@@ -60,7 +56,7 @@ fn prec_of(c: Int) -> Int {
6056 else 0
6157}
6258
63- fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: Int, e1: Int, elen: Int) -> Int {
59+ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: Int, e1: Int, e2: Int, e3: Int, elen: Int) -> Int {
6460 let no_left = 1 << 40;
6561 let pair = if left == no_left then {
6662 let p = skip_ws(src, pos, len);
@@ -69,7 +65,7 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
6965 let c = perform String.charAt(src, p);
7066 if is_digit(c) then read_int(src, p, len, 0)
7167 else if c == 40 then {
72- let inner = parse_pratt(src, p + 1, len, no_left, 0, e0, e1, elen);
68+ let inner = parse_pratt(src, p + 1, len, no_left, 0, e0, e1, e2, e3, elen);
7369 let v = inner >> 16;
7470 let q = inner & 0xFFFF;
7571 let q2 = skip_ws(src, q, len);
@@ -83,6 +79,7 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
8379 let h = ident >> 16;
8480 let q = ident & 0xFFFF;
8581 if h == 3321 then {
82+ // "let" keyword
8683 let q2 = skip_ws(src, q, len);
8784 let var_id = read_ident(src, q2, len, 0);
8885 let vh = var_id >> 16;
@@ -91,7 +88,7 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
9188 if q4 < len then {
9289 let c3 = perform String.charAt(src, q4);
9390 if c3 == 61 then {
94- let bound = parse_pratt(src, q4 + 1, len, no_left, 0, e0, e1, elen);
91+ let bound = parse_pratt(src, q4 + 1, len, no_left, 0, e0, e1, e2, e3, elen);
9592 let bv = bound >> 16;
9693 let bp = bound & 0xFFFF;
9794 let bp2 = skip_ws(src, bp, len);
@@ -101,21 +98,26 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
10198 if ci == 105 and cn == 110 then {
10299 let entry = (vh << 32) + bv;
103100 if elen == 0 then {
104- parse_pratt(src, bp2 + 2, len, no_left, 0, entry, e1, 1)
101+ parse_pratt(src, bp2 + 2, len, no_left, 0, entry, 0, 0, 0, 1)
102+ } else if elen == 1 then {
103+ parse_pratt(src, bp2 + 2, len, no_left, 0, e0, entry, 0, 0, 2)
104+ } else if elen == 2 then {
105+ parse_pratt(src, bp2 + 2, len, no_left, 0, e0, e1, entry, 0, 3)
105106 } else {
106- parse_pratt(src, bp2 + 2, len, no_left, 0, e0, entry, 2 )
107+ parse_pratt(src, bp2 + 2, len, no_left, 0, e0, e1, e2, entry, 4 )
107108 }
108109 } else (bv << 16) + bp2
109110 } else (bv << 16) + bp2
110111 } else {
111- let v = env_lookup(e0, e1, elen, h);
112+ let v = env_lookup(e0, e1, e2, e3, elen, h);
112113 (v << 16) + q
113114 }
114115 } else {
115- let v = env_lookup(e0, e1, elen, h);
116+ let v = env_lookup(e0, e1, e2, e3, elen, h);
116117 (v << 16) + q
117118 }
118119 } else if h == 620 then {
120+ // "fn" keyword
119121 let q2 = skip_ws(src, q, len);
120122 if q2 < len then {
121123 let c1 = perform String.charAt(src, q2);
@@ -134,12 +136,15 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
134136 let c4 = perform String.charAt(src, q6 + 1);
135137 if c3 == 61 and c4 == 62 then {
136138 let body_start = q6 + 2;
137- let body_parsed = parse_pratt(src, body_start, len, no_left, 0, e0, e1, elen);
139+ let body_parsed = parse_pratt(src, body_start, len, no_left, 0, e0, e1, e2, e3, elen);
138140 let body_end = body_parsed & 0xFFFF;
139141 let flag = 1 << 30;
140142 let enc = flag + (ph << 23) + (((body_start & 0x7F) << 16));
141143 let cap_data = if elen > 0 then {
142- let cap_e = if elen >= 2 then e1 else e0;
144+ let cap_e = if elen >= 4 then e3
145+ else if elen >= 3 then e2
146+ else if elen >= 2 then e1
147+ else e0;
143148 let cap_h = (cap_e >> 32) & 0xFF;
144149 let cap_v = cap_e & 0xFFFF;
145150 (cap_h << 16) + cap_v
@@ -155,7 +160,7 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
155160 } else (0 << 16) + p
156161 } else (0 << 16) + p
157162 } else {
158- let v = env_lookup(e0, e1, elen, h);
163+ let v = env_lookup(e0, e1, e2, e3, elen, h);
159164 (v << 16) + q
160165 }
161166 } else (0 << 16) + p
@@ -171,7 +176,7 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
171176 else {
172177 let c = perform String.charAt(src, p);
173178 if c == 40 then {
174- let arg = parse_pratt(src, p + 1, len, no_left, 0, e0, e1, elen);
179+ let arg = parse_pratt(src, p + 1, len, no_left, 0, e0, e1, e2, e3, elen);
175180 let av = arg >> 16;
176181 let ap = arg & 0xFFFF;
177182 let ap2 = skip_ws(src, ap, len);
@@ -185,23 +190,23 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
185190 let cap_v = lv & 0xFF;
186191 let entry_param = (ph << 32) + av;
187192 if cap_h == 0 then {
188- parse_pratt(src, bs, len, no_left, 0, entry_param, 0, 1)
193+ parse_pratt(src, bs, len, no_left, 0, entry_param, 0, 0, 0, 1)
189194 } else {
190195 let entry_cap = (cap_h << 32) + cap_v;
191- parse_pratt(src, bs, len, no_left, 0, entry_cap, entry_param, 2)
196+ parse_pratt(src, bs, len, no_left, 0, entry_cap, entry_param, 0, 0, 2)
192197 }
193198 } else {
194199 (lv << 16) + ap2
195200 };
196201 let rv = result >> 16;
197- parse_pratt(src, ap2 + 1, len, rv, min_prec, e0, e1, elen)
202+ parse_pratt(src, ap2 + 1, len, rv, min_prec, e0, e1, e2, e3, elen)
198203 } else pair
199204 } else pair
200205 } else {
201206 let prec = prec_of(c);
202207 if prec == 0 or prec < min_prec then pair
203208 else {
204- let rhs = parse_pratt(src, p + 1, len, no_left, prec, e0, e1, elen);
209+ let rhs = parse_pratt(src, p + 1, len, no_left, prec, e0, e1, e2, e3, elen);
205210 let rv = rhs >> 16;
206211 let rp = rhs & 0xFFFF;
207212 let result = if c == 43 then lv + rv
@@ -210,15 +215,15 @@ fn parse_pratt(src: String, pos: Int, len: Int, left: Int, min_prec: Int, e0: In
210215 else if c == 47 then {
211216 if rv == 0 then lv else lv / rv
212217 } else lv;
213- parse_pratt(src, rp, len, result, min_prec, e0, e1, elen)
218+ parse_pratt(src, rp, len, result, min_prec, e0, e1, e2, e3, elen)
214219 }
215220 }
216221 }
217222}
218223
219224fn parse(src: String) -> Int {
220225 let len = perform String.length(src);
221- let result = parse_pratt(src, 0, len, 1 << 40, 0, 0, 0, 0);
226+ let result = parse_pratt(src, 0, len, 1 << 40, 0, 0, 0, 0, 0, 0 );
222227 result >> 16
223228}
224229
@@ -233,4 +238,7 @@ fn main() {
233238 perform IO.print(parse("let f = fn(x) => x + 1 in f(10)"))
234239 perform IO.print(parse("let a = 3 in (fn(x) => a + x)(5)"))
235240 perform IO.print(parse("let add = fn(a) => fn(b) => a + b in add(3)(4)"))
241+ // New tests: 3- and 4-deep let bindings
242+ perform IO.print(parse("let a = 1 in let b = 2 in let c = 3 in a + b + c"))
243+ perform IO.print(parse("let a = 1 in let b = 2 in let c = 3 in let d = 4 in a + b + c + d"))
236244}
0 commit comments