summaryrefslogtreecommitdiff
path: root/ocaml/lib/nock.ml
blob: 64daa91819832c468f5fdd78ba2271cbd4e1ff14 (plain)
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
open Noun

(** Nock interpreter with trampoline to match C's tail-call optimization

    This is a more direct port of the C version which uses continue for tail calls
*)

(* Trace tracking *)
let call_count = ref 0
let depth = ref 0
let max_calls = 100
let max_mug_depth = ref (-1)
let show_mugs = ref false

let indent () =
  match !depth with
  | 0 -> ""
  | 1 -> "  "
  | 2 -> "    "
  | 3 -> "      "
  | 4 -> "        "
  | _ -> "          "

let opcode_name op =
  match op with
  | 0 -> "0(slot)"
  | 1 -> "1(const)"
  | 2 -> "2(eval)"
  | 3 -> "3(cell?)"
  | 4 -> "4(inc)"
  | 5 -> "5(eq)"
  | 6 -> "6(if)"
  | 7 -> "7(compose)"
  | 8 -> "8(extend)"
  | 9 -> "9(invoke)"
  | 10 -> "10(edit)"
  | 11 -> "11(hint)"
  | n -> Printf.sprintf "%d(?)" n

(** Main nock evaluation using trampoline pattern like C *)
let rec nock_on init_bus init_fol =
  let bus = ref init_bus in
  let fol = ref init_fol in
  let my_call = !call_count in

  (* Check if this is opcode 0 (slot lookup) - C doesn't log these *)
  let is_slot = match init_fol with
    | Cell { h = Atom { z = op; _ }; _ } when Z.fits_int op && Z.to_int op = 0 -> true
    | _ -> false
  in

  let should_log = my_call < max_calls && not is_slot in

  (* Log entry ONCE at function entry *)
  if should_log then begin
    let opcode_str = match init_fol with
      | Cell { h = Atom { z = op; _ }; _ } when Z.fits_int op -> opcode_name (Z.to_int op)
      | Cell { h = Cell _; _ } -> "CELL(dist)"
      | _ -> "?"
    in
    if !show_mugs || !depth <= !max_mug_depth then begin
      let bus_mug = mug init_bus in
      Printf.eprintf "%s>>> ENTER call #%d depth=%d opcode=%s bus=%s[mug=0x%lx]\n%!"
        (indent ()) my_call !depth opcode_str
        (if is_cell init_bus then "cell" else "atom")
        bus_mug
    end else begin
      Printf.eprintf "%s>>> ENTER call #%d depth=%d opcode=%s bus=%s\n%!"
        (indent ()) my_call !depth opcode_str
        (if is_cell init_bus then "cell" else "atom")
    end;
    incr call_count
  end;

  (* Increment depth ONCE at function entry *)
  incr depth;

  let rec loop () =

    try
      let result = match !fol with
      | Cell { h = hib; t = gal; _ } when is_cell hib ->
          (* Distribution *)
          let poz = nock_on !bus hib in
          let riv = nock_on !bus gal in
          cell poz riv

      | Cell { h = Atom { z = op; _ }; t = gal; _ } ->
          if Z.compare op (Z.of_int max_int) > 0 then raise Exit;
          let opcode = Z.to_int op in

          (match opcode with
          | 0 ->
              if not (is_atom gal) then raise Exit
              else slot (match gal with Atom { z = n; _ } -> n | _ -> raise Exit) !bus

          | 1 ->
              gal

          | 2 ->
              (* Tail-call optimization: set bus/fol and loop *)
              if not (is_cell gal) then raise Exit;
              let c_gal = tail gal in
              let b_gal = head gal in

              (* Debug first call *)
              if my_call = 0 then begin
                Printf.eprintf "[Op2 Debug] Computing formula (tail gal):\n%!";
                Printf.eprintf "  c_gal mug: 0x%lx\n%!" (mug c_gal);
              end;

              let nex = nock_on !bus c_gal in

              if my_call = 0 then begin
                Printf.eprintf "  nex mug: 0x%lx\n%!" (mug nex);
                Printf.eprintf "[Op2 Debug] Computing subject (head gal):\n%!";
                Printf.eprintf "  b_gal mug: 0x%lx\n%!" (mug b_gal);
              end;

              let seb = nock_on !bus b_gal in

              if my_call = 0 then begin
                Printf.eprintf "  seb mug: 0x%lx\n%!" (mug seb);
              end;

              bus := seb;
              fol := nex;
              loop ()

          | 3 ->
              let gof = nock_on !bus gal in
              if is_cell gof then atom 0 else atom 1

          | 4 ->
              let gof = nock_on !bus gal in
              inc gof

          | 5 ->
              let wim = nock_on !bus gal in
              if not (is_cell wim) then raise Exit;
              let a = head wim in
              let b = tail wim in
              if equal a b then atom 0 else atom 1

          | 6 ->
              (* Tail-call optimization *)
              if not (is_cell gal) then raise Exit;
              let b_gal = head gal in
              let cd_gal = tail gal in
              if not (is_cell cd_gal) then raise Exit;
              let c_gal = head cd_gal in
              let d_gal = tail cd_gal in
              let tys = nock_on !bus b_gal in
              let nex = match tys with
                | Atom { z = n; _ } when Z.equal n Z.zero -> c_gal
                | Atom { z = n; _ } when Z.equal n Z.one -> d_gal
                | _ -> raise Exit
              in
              fol := nex;
              (* Don't decr depth for tail calls *)
              loop ()

          | 7 ->
              (* Tail-call optimization *)
              if not (is_cell gal) then raise Exit;
              let b_gal = head gal in
              let c_gal = tail gal in
              let bod = nock_on !bus b_gal in
              bus := bod;
              fol := c_gal;
              (* Don't decr depth for tail calls *)
              loop ()

          | 8 ->
              (* Tail-call optimization *)
              if not (is_cell gal) then raise Exit;
              let b_gal = head gal in
              let c_gal = tail gal in
              let heb = nock_on !bus b_gal in
              let bod = cell heb !bus in
              bus := bod;
              fol := c_gal;
              (* Don't decr depth for tail calls *)
              loop ()

          | 9 ->
              if not (is_cell gal) then raise Exit;
              let b_gal = head gal in
              let c_gal = tail gal in
              if not (is_atom b_gal) then raise Exit;
              let seb = nock_on !bus c_gal in
              let nex = slot (match b_gal with Atom { z; _ } -> z | _ -> raise Exit) seb in
              nock_on seb nex

          | 10 ->
              if not (is_cell gal) then raise Exit;
              let _p_gal = head gal in
              let q_gal = tail gal in
              nock_on !bus q_gal

          | 11 ->
              if not (is_cell gal) then raise Exit;
              let p_gal = head gal in
              let q_gal = tail gal in
              if is_cell p_gal then
                nock_on !bus q_gal
              else
                nock_on !bus q_gal

          | _ ->
              raise Exit
          )

      | _ ->
          raise Exit
      in

      (* Log exit and return *)
      decr depth;
      if should_log then begin
        if !show_mugs || !depth <= !max_mug_depth then begin
          let result_mug = mug result in
          Printf.eprintf "%s<<< EXIT  call #%d depth=%d returns=%s[mug=0x%lx]\n%!"
            (indent ()) my_call !depth
            (if is_cell result then "cell" else "atom")
            result_mug
        end else begin
          Printf.eprintf "%s<<< EXIT  call #%d depth=%d returns=%s\n%!"
            (indent ()) my_call !depth
            (if is_cell result then "cell" else "atom")
        end
      end;
      result

    with e ->
      decr depth;
      raise e
  in

  loop ()

let nock subject formula =
  nock_on subject formula