1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 11:23:59 +03:00
mal/fsharp/node.fs
2016-02-14 20:51:37 -05:00

89 lines
2.8 KiB
Forth

module Node
open Types
let TRUE = Bool(true)
let SomeTRUE = Some(TRUE)
let FALSE = Bool(false)
let SomeFALSE = Some(FALSE)
let NIL = Nil
let SomeNIL = Some(NIL)
let ZERO = Number(0L)
let makeVector seg = Vector(NIL, seg)
let makeList lst = List(NIL, lst)
let makeMap map = Map(NIL, map)
let EmptyLIST = [] |> makeList
let EmptyVECTOR = System.ArraySegment([| |]) |> makeVector
let EmptyMAP = Map.empty |> makeMap
let ofArray arr = System.ArraySegment(arr) |> makeVector
let ofChar chr = sprintf "%c" chr |> String
let toArray = function
| List(_, lst) -> Array.ofList lst
| Vector(_, seg) -> Array.sub seg.Array seg.Offset seg.Count
| node -> [| node |]
let length = function
| List(_, lst) -> List.length lst
| Vector(_, seg) -> seg.Count
| Map(_, m) -> m.Count
| _ -> 1
(* Active Patterns to help with pattern matching nodes *)
let inline (|Elements|_|) num node =
let rec accumList acc idx lst =
let len = Array.length acc
match lst with
| [] when idx = len -> Some(Elements acc)
| h::t when idx < len ->
acc.[idx] <- h
accumList acc (idx + 1) t
| _ -> None
match node with
| List(_, lst) -> accumList (Array.zeroCreate num) 0 lst
| Vector(_, seg) when seg.Count = num -> Some(toArray node)
| _ -> None
let inline (|Cons|_|) node =
match node with
| List(_, h::t) -> Some(Cons(h, makeList t))
| Vector(_, seg) when seg.Count > 0 ->
let h = seg.Array.[seg.Offset]
let t = System.ArraySegment(seg.Array, seg.Offset + 1, seg.Count - 1)
|> makeVector
Some(Cons(h, t))
| _ -> None
let inline (|Empty|_|) node =
match node with
| List(_, []) -> Some(Empty)
| Vector(_, seg) when seg.Count = 0 -> Some(Empty)
| _ -> None
let inline (|Pair|_|) node =
match node with
| List(_, a::b::t) -> Some(a, b, makeList t)
| List(_, []) -> None
| List(_, _) -> raise <| Error.expectedEvenNodeCount ()
| Vector(_, seg) ->
match seg.Count with
| 0 -> None
| 1 -> raise <| Error.expectedEvenNodeCount ()
| _ ->
let a = seg.Array.[seg.Offset]
let b = seg.Array.[seg.Offset + 1]
let t = System.ArraySegment(seg.Array, seg.Offset + 2, seg.Count - 2)
|> makeVector
Some(a, b, t)
| _ -> None
let inline (|Seq|_|) node =
match node with
| List(_, lst) -> Some(Seq.ofList lst)
| Vector(_, seg) -> Some(seg :> Node seq)
| _ -> None