fsharp: step 4: Added list and comparison functions.
[jackhill/mal.git] / fsharp / reader.fs
CommitLineData
ed3a12f5
PS
1module Reader
2 open System
327bd967 3 open Tokenizer
ed3a12f5
PS
4 open Types
5
3b82891f 6 type MutableList = System.Collections.Generic.List<Node>
327bd967
PS
7 let inline addToMutableList (lst:MutableList) item = lst.Add(item); lst
8
6c47cf67
PS
9 let errExpectedButEOF tok = ReaderError(sprintf "Expected %s, got EOF" tok)
10 let errInvalid () = ReaderError("Invalid token")
11
327bd967
PS
12 let quote = Symbol("quote")
13 let quasiquote = Symbol("quasiquote")
14 let unquote = Symbol("unquote")
15 let spliceUnquote = Symbol("splice-unquote")
16 let deref = Symbol("deref")
17 let withMeta = Symbol("with-meta")
18
19 let rec readForm = function
20 | OpenParen::rest -> readList [] rest
21 | OpenBracket::rest -> readVector (MutableList()) rest
22 | OpenBrace::rest -> readMap [] rest
23 | SingleQuote::rest -> wrapForm quote rest
24 | Backtick::rest -> wrapForm quasiquote rest
25 | Tilde::rest -> wrapForm unquote rest
26 | SpliceUnquote::rest -> wrapForm spliceUnquote rest
27 | At::rest -> wrapForm deref rest
28 | Caret::rest -> readMeta rest
29 | tokens -> readAtom tokens
30
31 and wrapForm node tokens =
32 match readForm tokens with
33 | Some(form), rest -> Some(List([node; form])), rest
6c47cf67 34 | None, _ -> raise <| errExpectedButEOF "form"
3b82891f 35
327bd967
PS
36 and readList acc = function
37 | CloseParen::rest -> Some(List(acc |> List.rev)), rest
6c47cf67 38 | [] -> raise <| errExpectedButEOF "')'"
327bd967
PS
39 | tokens ->
40 match readForm tokens with
41 | Some(form), rest -> readList (form::acc) rest
6c47cf67 42 | None, _ -> raise <| errExpectedButEOF "')'"
327bd967
PS
43
44 and readVector acc = function
45 | CloseBracket::rest -> Some(Vector(acc.ToArray())), rest
6c47cf67 46 | [] -> raise <| errExpectedButEOF "']'"
327bd967
PS
47 | tokens ->
48 match readForm tokens with
49 | Some(form), rest -> readVector (addToMutableList acc form) rest
6c47cf67 50 | None, _ -> raise <| errExpectedButEOF "']'"
327bd967
PS
51
52 and readMap acc = function
53 | CloseBrace::rest -> Some(Map(acc |> List.rev |> Map.ofList)), rest
6c47cf67 54 | [] -> raise <| errExpectedButEOF "'}'"
327bd967
PS
55 | tokens ->
56 match readForm tokens with
57 | Some(key), rest ->
58 match readForm rest with
59 | Some(v), rest -> readMap ((key, v)::acc) rest
6c47cf67
PS
60 | None, _ -> raise <| errExpectedButEOF "'}'"
61 | None, _ -> raise <| errExpectedButEOF "'}'"
327bd967
PS
62
63 and readMeta = function
64 | OpenBrace::rest ->
65 let meta, rest = readMap [] rest
66 match readForm rest with
67 | Some(form), rest -> Some(List([withMeta; form; meta.Value])), rest
6c47cf67
PS
68 | None, _ -> raise <| errExpectedButEOF "form"
69 | _ -> raise <| errExpectedButEOF "map"
b856be1e 70
327bd967 71 and readAtom = function
a836d8f3
PS
72 | Token("nil")::rest -> SomeNIL, rest
73 | Token("true")::rest -> SomeTRUE, rest
74 | Token("false")::rest -> SomeFALSE, rest
327bd967
PS
75 | Tokenizer.String(str)::rest -> Some(String(str)), rest
76 | Tokenizer.Keyword(kw)::rest -> Some(Keyword(kw)), rest
77 | Tokenizer.Number(num)::rest -> Some(Number(Int64.Parse(num))), rest
78 | Token(sym)::rest -> Some(Symbol(sym)), rest
79 | [] -> None, []
6c47cf67 80 | _ -> raise <| errInvalid ()
3b82891f 81
327bd967
PS
82 let rec readForms acc = function
83 | [] -> List.rev acc
84 | tokens ->
85 match readForm tokens with
86 | Some(form), rest -> readForms (form::acc) rest
87 | None, rest -> readForms acc rest
88
ed3a12f5 89 let read_str str =
327bd967 90 tokenize str |> readForms []