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