Travis: add remaining implementations.
[jackhill/mal.git] / fsharp / node.fs
1 module Node
2
3 open Types
4
5 let TRUE = Bool(true)
6 let SomeTRUE = Some(TRUE)
7 let FALSE = Bool(false)
8 let SomeFALSE = Some(FALSE)
9 let NIL = Nil
10 let SomeNIL = Some(NIL)
11 let ZERO = Number(0L)
12
13 let makeVector seg = Vector(NIL, seg)
14 let makeList lst = List(NIL, lst)
15 let makeMap map = Map(NIL, map)
16
17 let EmptyLIST = [] |> makeList
18 let EmptyVECTOR = System.ArraySegment([| |]) |> makeVector
19 let EmptyMAP = Map.empty |> makeMap
20
21 let ofArray arr = System.ArraySegment(arr) |> makeVector
22
23 let toArray = function
24 | List(_, lst) -> Array.ofList lst
25 | Vector(_, seg) -> Array.sub seg.Array seg.Offset seg.Count
26 | node -> [| node |]
27
28 let length = function
29 | List(_, lst) -> List.length lst
30 | Vector(_, seg) -> seg.Count
31 | Map(_, m) -> m.Count
32 | _ -> 1
33
34 (* Active Patterns to help with pattern matching nodes *)
35 let inline (|Elements|_|) num node =
36 let rec accumList acc idx lst =
37 let len = Array.length acc
38 match lst with
39 | [] when idx = len -> Some(Elements acc)
40 | h::t when idx < len ->
41 acc.[idx] <- h
42 accumList acc (idx + 1) t
43 | _ -> None
44 match node with
45 | List(_, lst) -> accumList (Array.zeroCreate num) 0 lst
46 | Vector(_, seg) when seg.Count = num -> Some(toArray node)
47 | _ -> None
48
49 let inline (|Cons|_|) node =
50 match node with
51 | List(_, h::t) -> Some(Cons(h, makeList t))
52 | Vector(_, seg) when seg.Count > 0 ->
53 let h = seg.Array.[seg.Offset]
54 let t = System.ArraySegment(seg.Array, seg.Offset + 1, seg.Count - 1)
55 |> makeVector
56 Some(Cons(h, t))
57 | _ -> None
58
59 let inline (|Empty|_|) node =
60 match node with
61 | List(_, []) -> Some(Empty)
62 | Vector(_, seg) when seg.Count = 0 -> Some(Empty)
63 | _ -> None
64
65 let inline (|Pair|_|) node =
66 match node with
67 | List(_, a::b::t) -> Some(a, b, makeList t)
68 | List(_, []) -> None
69 | List(_, _) -> raise <| Error.expectedEvenNodeCount ()
70 | Vector(_, seg) ->
71 match seg.Count with
72 | 0 -> None
73 | 1 -> raise <| Error.expectedEvenNodeCount ()
74 | _ ->
75 let a = seg.Array.[seg.Offset]
76 let b = seg.Array.[seg.Offset + 1]
77 let t = System.ArraySegment(seg.Array, seg.Offset + 2, seg.Count - 2)
78 |> makeVector
79 Some(a, b, t)
80 | _ -> None
81
82 let inline (|Seq|_|) node =
83 match node with
84 | List(_, lst) -> Some(Seq.ofList lst)
85 | Vector(_, seg) -> Some(seg :> Node seq)
86 | _ -> None