Travis: add remaining implementations.
[jackhill/mal.git] / fsharp / core.fs
CommitLineData
6c47cf67
PS
1module 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 ()