Commit | Line | Data |
---|---|---|
6c47cf67 PS |
1 | module Core |
2 | ||
a836d8f3 | 3 | open Types |
6c47cf67 | 4 | |
f877bf26 | 5 | let inline toBool b = if b then Node.TRUE else Node.FALSE |
6c47cf67 | 6 | |
a836d8f3 PS |
7 | let inline twoNumberOp (f : int64 -> int64 -> Node) = function |
8 | | [Number(a); Number(b)] -> f a b | |
6d809e32 PS |
9 | | [_; _] -> raise <| Error.argMismatch () |
10 | | _ -> raise <| Error.wrongArity () | |
a836d8f3 PS |
11 | |
12 | let inline twoNodeOp (f : Node -> Node -> Node) = function | |
13 | | [a; b] -> f a b | |
6d809e32 | 14 | | _ -> raise <| Error.wrongArity () |
a836d8f3 PS |
15 | |
16 | let add = twoNumberOp (fun a b -> a + b |> Number) | |
17 | let subtract = twoNumberOp (fun a b -> a - b |> Number) | |
18 | let multiply = twoNumberOp (fun a b -> a * b |> Number) | |
19 | let divide = twoNumberOp (fun a b -> a / b |> Number) | |
20 | let lt = twoNodeOp (fun a b -> a < b |> toBool) | |
21 | let le = twoNodeOp (fun a b -> a <= b |> toBool) | |
22 | let ge = twoNodeOp (fun a b -> a >= b |> toBool) | |
23 | let gt = twoNodeOp (fun a b -> a > b |> toBool) | |
7822be33 | 24 | let eq = twoNodeOp (fun a b -> a = b |> toBool) |
6c47cf67 | 25 | |
a71aefe1 | 26 | let list = Node.makeList |
a836d8f3 | 27 | let isList = function |
a71aefe1 | 28 | | [List(_, _)] -> Node.TRUE |
f877bf26 | 29 | | [_] -> Node.FALSE |
6d809e32 | 30 | | _ -> raise <| Error.wrongArity () |
6c47cf67 | 31 | |
a836d8f3 | 32 | let isEmpty = function |
a71aefe1 PS |
33 | | [List(_, [])] -> Node.TRUE |
34 | | [Vector(_, seg)] when seg.Count <= 0 -> Node.TRUE | |
f877bf26 | 35 | | _ -> Node.FALSE |
6c47cf67 | 36 | |
a836d8f3 | 37 | let count = function |
a71aefe1 PS |
38 | | [List(_, lst)] -> lst |> List.length |> int64 |> Number |
39 | | [Vector(_, seg)] -> seg.Count |> int64 |> Number | |
f877bf26 | 40 | | [Nil] -> Node.ZERO |
6d809e32 PS |
41 | | [_] -> raise <| Error.argMismatch () |
42 | | _ -> raise <| Error.wrongArity () | |
6a4627fb PS |
43 | |
44 | let pr_str nodes = nodes |> Printer.pr_str |> String | |
45 | let str nodes = nodes |> Printer.str |> String | |
46 | let prn nodes = nodes |> Printer.prn |> printfn "%s"; Nil | |
47 | let println nodes = nodes |> Printer.println |> printfn "%s"; Nil | |
8d4a06e0 PS |
48 | |
49 | let read_str = function | |
50 | | [String(s)] -> | |
51 | match Reader.read_str s with | |
52 | | [node] -> node | |
a71aefe1 | 53 | | nodes -> Symbol("do")::nodes |> Node.makeList |
6d809e32 PS |
54 | | [_] -> raise <| Error.argMismatch () |
55 | | _ -> raise <| Error.wrongArity () | |
8d4a06e0 PS |
56 | |
57 | let slurp = function | |
58 | | [String(s)] -> System.IO.File.ReadAllText s |> String | |
6d809e32 PS |
59 | | [_] -> raise <| Error.argMismatch () |
60 | | _ -> raise <| Error.wrongArity () | |
aa2e1438 PS |
61 | |
62 | let cons = function | |
a71aefe1 PS |
63 | | [node; List(_, lst)] -> node::lst |> Node.makeList |
64 | | [node; Vector(_, seg)] -> node::(List.ofSeq seg) |> Node.makeList | |
6d809e32 PS |
65 | | [_; _] -> raise <| Error.argMismatch () |
66 | | _ -> raise <| Error.wrongArity () | |
aa2e1438 PS |
67 | |
68 | let concat nodes = | |
aac99bed PS |
69 | let cons st node = node::st |
70 | let accumNode acc = function | |
a71aefe1 PS |
71 | | List(_, lst) -> lst |> List.fold cons acc |
72 | | Vector(_, seg) -> seg |> Seq.fold cons acc | |
6d809e32 | 73 | | _ -> raise <| Error.argMismatch () |
aac99bed | 74 | |
aa2e1438 | 75 | nodes |
aac99bed PS |
76 | |> List.fold accumNode [] |
77 | |> List.rev | |
a71aefe1 | 78 | |> Node.makeList |
f0e1608b PS |
79 | |
80 | let nth = function | |
a71aefe1 | 81 | | [List(_, lst); Number(n)] -> |
f0e1608b PS |
82 | let rec nth_list n = function |
83 | | [] -> raise <| Error.indexOutOfBounds () | |
84 | | h::_ when n = 0L -> h | |
85 | | _::t -> nth_list (n - 1L) t | |
86 | nth_list n lst | |
a71aefe1 | 87 | | [Vector(_, seg); Number(n)] -> |
f0e1608b PS |
88 | if n < 0L || n >= int64(seg.Count) then |
89 | raise <| Error.indexOutOfBounds () | |
90 | else | |
91 | seg.Array.[int(n)] | |
92 | | [_; _] -> raise <| Error.argMismatch () | |
93 | | _ -> raise <| Error.wrongArity () | |
94 | ||
95 | let first = function | |
a71aefe1 PS |
96 | | [List(_, [])] -> Node.NIL |
97 | | [List(_, h::_)] -> h | |
98 | | [Vector(_, seg)] when seg.Count > 0 -> seg.Array.[0] | |
99 | | [Vector(_, _)] -> Node.NIL | |
f0e1608b PS |
100 | | [Nil] -> Node.NIL |
101 | | [_] -> raise <| Error.argMismatch () | |
102 | | _ -> raise <| Error.wrongArity () | |
103 | ||
104 | let rest = function | |
a71aefe1 PS |
105 | | [List(_, [])] -> Node.EmptyLIST |
106 | | [List(_, _::t)] -> t |> Node.makeList | |
107 | | [Vector(_, seg)] when seg.Count < 2 -> Node.EmptyLIST | |
108 | | [Vector(_, seg)] -> seg |> Seq.skip 1 |> List.ofSeq |> Node.makeList | |
f0e1608b PS |
109 | | [_] -> raise <| Error.argMismatch () |
110 | | _ -> raise <| Error.wrongArity () | |
224d2396 PS |
111 | |
112 | let throw = function | |
113 | | [node] -> raise <| Error.MalError(node) | |
114 | | _ -> raise <| Error.wrongArity () | |
115 | ||
116 | let map = function | |
a71aefe1 PS |
117 | | [BuiltInFunc(_, _, f); Node.Seq seq] |
118 | | [Func(_, _, f, _, _, _); Node.Seq seq] -> | |
119 | seq |> Seq.map (fun node -> f [node]) |> List.ofSeq |> Node.makeList | |
224d2396 PS |
120 | | [_; _] -> raise <| Error.argMismatch () |
121 | | _ -> raise <| Error.wrongArity () | |
122 | ||
123 | let apply = function | |
a71aefe1 PS |
124 | | BuiltInFunc(_, _, f)::rest |
125 | | Func(_, _, f, _, _, _)::rest -> | |
224d2396 PS |
126 | let rec getArgsAndCall acc = function |
127 | | [] -> raise <| Error.wrongArity () | |
128 | | [Node.Seq seq] -> | |
129 | seq |> Seq.fold (fun acc node -> node::acc) acc |> List.rev |> f | |
130 | | [_] -> raise <| Error.argMismatch () | |
131 | | h::rest -> getArgsAndCall (h::acc) rest | |
132 | getArgsAndCall [] rest | |
133 | | _::_ -> raise <| Error.argMismatch () | |
134 | | [] -> raise <| Error.wrongArity () | |
135 | ||
136 | let isConst cmp = function | |
137 | | [node] -> if node = cmp then Node.TRUE else Node.FALSE | |
138 | | _ -> raise <| Error.wrongArity () | |
139 | ||
0fb8a944 PS |
140 | let isPattern f = function |
141 | | [node] -> if f node then Node.TRUE else Node.FALSE | |
142 | | _ -> raise <| Error.wrongArity () | |
143 | ||
144 | let isSymbol = isPattern (function Symbol(_) -> true | _ -> false) | |
145 | let isKeyword = isPattern (function Keyword(_) -> true | _ -> false) | |
146 | let isSequential = isPattern (function Node.Seq(_) -> true | _ -> false) | |
a71aefe1 PS |
147 | let isVector = isPattern (function Vector(_, _) -> true | _ -> false) |
148 | let isMap = isPattern (function Map(_, _) -> true | _ -> false) | |
149 | let isAtom = isPattern (function Atom(_, _) -> true | _ -> false) | |
0fb8a944 PS |
150 | |
151 | let fromString f = function | |
152 | | [String(str)] -> f str | |
153 | | [_] -> raise <| Error.argMismatch () | |
224d2396 | 154 | | _ -> raise <| Error.wrongArity () |
0fb8a944 PS |
155 | |
156 | let symbol = fromString (fun s -> Symbol(s)) | |
157 | let keyword = fromString (fun s -> Keyword(s)) | |
158 | let vector lst = lst |> Array.ofList |> Node.ofArray | |
159 | ||
160 | let rec getPairs lst = | |
161 | seq { | |
162 | match lst with | |
163 | | first::second::t -> | |
164 | yield first, second | |
165 | yield! getPairs t | |
166 | | [_] -> raise <| Error.expectedEvenNodeCount () | |
167 | | [] -> () | |
168 | } | |
169 | ||
170 | let mapOpN f = function | |
a71aefe1 | 171 | | Map(_, map)::rest -> f rest map |
0fb8a944 PS |
172 | | [_] -> raise <| Error.argMismatch () |
173 | | _ -> raise <| Error.wrongArity () | |
174 | ||
175 | let mapOp1 f = | |
176 | mapOpN (fun rest map -> | |
177 | match rest with | |
178 | | [v] -> f v map | |
179 | | _ -> raise <| Error.wrongArity ()) | |
180 | ||
181 | let mapOp0 f = | |
182 | mapOpN (fun rest map -> | |
183 | match rest with | |
184 | | [] -> f map | |
185 | | _ -> raise <| Error.wrongArity ()) | |
186 | ||
187 | let mapKV f = | |
a71aefe1 | 188 | mapOp0 (fun map -> map |> Map.toSeq |> Seq.map f |> List.ofSeq |> Node.makeList) |
0fb8a944 | 189 | |
a71aefe1 | 190 | let hashMap lst = lst |> getPairs |> Map.ofSeq |> Node.makeMap |
0fb8a944 PS |
191 | let assoc = mapOpN (fun rest map -> |
192 | rest | |
193 | |> getPairs | |
194 | |> Seq.fold (fun map (k, v) -> Map.add k v map) map | |
a71aefe1 | 195 | |> Node.makeMap) |
0fb8a944 PS |
196 | let dissoc = mapOpN (fun keys map -> |
197 | keys | |
198 | |> List.fold (fun map k -> Map.remove k map) map | |
a71aefe1 | 199 | |> Node.makeMap) |
0fb8a944 PS |
200 | let get = function |
201 | | [Nil; _] -> Node.NIL | |
202 | | _ as rest -> | |
203 | rest |> mapOp1 (fun key map -> | |
204 | match Map.tryFind key map with | |
205 | | Some(node) -> node | |
206 | | None -> Node.NIL) | |
207 | let containsKey key map = if Map.containsKey key map then Node.TRUE else Node.FALSE | |
208 | let contains = mapOp1 containsKey | |
209 | let keys = mapKV (fun (k, v) -> k) | |
210 | let vals = mapKV (fun (k, v) -> v) | |
66913ea4 PS |
211 | |
212 | let atom nextValue = function | |
213 | | [node] -> Atom((nextValue ()), ref node) | |
214 | | _ -> raise <| Error.wrongArity () | |
215 | ||
216 | let deref = function | |
217 | | [Atom(_, r)] -> !r | |
218 | | [_] -> raise <| Error.argMismatch () | |
219 | | _ -> raise <| Error.wrongArity () | |
220 | ||
221 | let reset = function | |
222 | | [Atom(_, r); node] -> | |
223 | r := node | |
224 | !r | |
225 | | [_; _] -> raise <| Error.argMismatch () | |
226 | | _ -> raise <| Error.wrongArity () | |
227 | ||
228 | let swap = function | |
229 | | Atom(_, r) | |
a71aefe1 | 230 | ::(BuiltInFunc(_, _, f) | Func(_, _, f, _, _, _)) |
66913ea4 PS |
231 | ::rest -> |
232 | r := f (!r::rest) | |
233 | !r | |
234 | | [_; _] -> raise <| Error.argMismatch () | |
235 | | _ -> raise <| Error.wrongArity () | |
a71aefe1 PS |
236 | |
237 | let conj = function | |
238 | | List(_, lst)::rest -> | |
239 | rest | |
240 | |> List.fold (fun lst node -> node::lst) lst | |
241 | |> Node.makeList | |
242 | | Vector(_, seg)::rest -> | |
243 | (* Might be nice to implement a persistent vector here someday. *) | |
244 | let cnt = List.length rest | |
245 | if cnt > 0 then | |
246 | let target : Node array = seg.Count + cnt |> Array.zeroCreate | |
247 | System.Array.Copy(seg.Array :> System.Array, seg.Offset, | |
248 | target :> System.Array, 0, seg.Count) | |
249 | let rec copyElem i = function | |
250 | | h::t -> | |
251 | Array.set target i h | |
252 | copyElem (i + 1) t | |
253 | | [] -> () | |
254 | copyElem (seg.Count) rest | |
255 | target |> Node.ofArray | |
256 | else | |
257 | seg |> Node.makeVector | |
258 | | [_; _] -> raise <| Error.argMismatch () | |
259 | | _ -> raise <| Error.wrongArity () | |
260 | ||
261 | let withMeta = function | |
262 | | [List(_, lst); m] -> List(m, lst) | |
263 | | [Vector(_, seg); m] -> Vector(m, seg) | |
264 | | [Map(_, map); m] -> Map(m, map) | |
265 | | [BuiltInFunc(_, tag, f); m] -> BuiltInFunc(m, tag, f) | |
266 | | [Func(_, tag, f, a, b, c); m] -> Func(m, tag, f, a, b, c) | |
267 | | [Macro(_, tag, f, a, b, c); m] -> Macro(m, tag, f, a, b, c) | |
268 | | [_; _] -> raise <| Error.argMismatch () | |
269 | | _ -> raise <| Error.wrongArity () | |
270 | ||
271 | let meta = function | |
272 | | [List(m, _)] | |
273 | | [Vector(m, _)] | |
274 | | [Map(m, _)] | |
275 | | [BuiltInFunc(m, _, _)] | |
276 | | [Func(m, _, _, _, _, _)] | |
277 | | [Macro(m, _, _, _, _, _)] -> m | |
278 | | [_] -> Node.NIL | |
279 | | _ -> raise <| Error.wrongArity () |