summaryrefslogtreecommitdiff
path: root/ocaml/lib/nock_alt.ml
blob: 037c0d006e9289c24943369f152ec52025d90f29 (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
open Noun

(** Nock interpreter

    Based on the reference implementation from vere/pkg/noun/nock.c

    The Nock spec has 12 opcodes (0-11):
    - 0: slot/fragment lookup
    - 1: constant
    - 2: nock (recursion)
    - 3: is-cell test
    - 4: increment
    - 5: equality test
    - 6: if-then-else
    - 7: composition
    - 8: push
    - 9: call with axis
    - 10: hint (ignored in reference implementation)
    - 11: scry (errors in reference implementation)
*)

(** Main nock evaluation function: nock(subject, formula)

    In Nock notation: *[subject formula]

    This is a direct port of _n_nock_on from nock.c:157-396
*)
let rec nock_on bus fol =
  match fol with
  | Cell (hib, gal) when is_cell hib ->
      (* [a b] -> compute both sides and cons *)
      let poz = nock_on bus hib in
      let riv = nock_on bus gal in
      cell poz riv

  | Cell (Atom op, gal) ->
      (match Z.to_int op with
      | 0 ->
          (* /[axis subject] - slot/fragment lookup *)
          if not (is_atom gal) then raise Exit
          else slot (match gal with Atom n -> n | _ -> raise Exit) bus

      | 1 ->
          (* =[constant subject] - return constant *)
          gal

      | 2 ->
          (* *[subject formula new_subject] - evaluate with new subject *)
          if not (is_cell gal) then raise Exit;
          let b_gal = head gal in
          let c_gal = tail gal in
          let seb = nock_on bus b_gal in
          let nex = nock_on bus c_gal in
          nock_on seb nex

      | 3 ->
          (* ?[subject formula] - is-cell test *)
          let gof = nock_on bus gal in
          if is_cell gof then atom 0 else atom 1

      | 4 ->
          (* +[subject formula] - increment *)
          let gof = nock_on bus gal in
          inc gof

      | 5 ->
          (* =[subject formula] - equality test *)
          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 ->
          (* if-then-else *)
          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 n when Z.equal n Z.zero -> c_gal
            | Atom n when Z.equal n Z.one -> d_gal
            | _ -> raise Exit
          in
          nock_on bus nex

      | 7 ->
          (* composition: *[*[subject b] c] *)
          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
          nock_on bod c_gal

      | 8 ->
          (* push: *[[*[subject b] subject] c] *)
          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
          nock_on bod c_gal

      | 9 ->
          (* call: *[*[subject c] axis] *)
          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 n -> n | _ -> raise Exit) seb in
          nock_on seb nex

      | 10 ->
          (* hint - in reference implementation, hints are mostly ignored *)
          (* gal must be a cell: [hint-spec formula] *)
          if not (is_cell gal) then raise Exit;
          let nex = tail gal in
          nock_on bus nex

      | 11 ->
          (* scry - not implemented in reference nock, raises error *)
          raise Exit

      | _ ->
          (* Invalid opcode *)
          raise Exit
      )

  | _ ->
      (* Invalid formula structure *)
      raise Exit

(** Convenience function: nock(subject, formula) *)
let nock subject formula =
  nock_on subject formula

(** slam: apply gate to sample
    slam(gate, sample) = *[gate [9 2 [0 1] [0 6] [1 sample] [0 7]]]

    In practice this evaluates the gate (which is a core with a formula at axis 2)
    with a modified sample (at axis 6).
*)
let slam gat sam =
  let cor = cell (head gat) (cell sam (tail (tail gat))) in
  let formula = slot (Z.of_int 2) cor in
  nock_on cor formula

(** kick: fire gate without changing sample
    kick(gate) = *[gate 9 2 0 1]
*)
let kick gat =
  let formula = slot (Z.of_int 2) gat in
  nock_on gat formula