ea2b4d69dafbe05865bbd822699c8117365c6601
[jackhill/mal.git] / fsharp / reader.fs
1 module Reader
2 open System
3 open Tokenizer
4 open Types
5
6 type MutableList = System.Collections.Generic.List<Node>
7 let inline addToMutableList (lst:MutableList) item = lst.Add(item); lst
8
9 let errExpectedButEOF tok = ReaderError(sprintf "Expected %s, got EOF" tok)
10 let errInvalid () = ReaderError("Invalid token")
11
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
34 | None, _ -> raise <| errExpectedButEOF "form"
35
36 and readList acc = function
37 | CloseParen::rest -> Some(List(acc |> List.rev)), rest
38 | [] -> raise <| errExpectedButEOF "')'"
39 | tokens ->
40 match readForm tokens with
41 | Some(form), rest -> readList (form::acc) rest
42 | None, _ -> raise <| errExpectedButEOF "')'"
43
44 and readVector acc = function
45 | CloseBracket::rest -> Some(Vector(acc.ToArray())), rest
46 | [] -> raise <| errExpectedButEOF "']'"
47 | tokens ->
48 match readForm tokens with
49 | Some(form), rest -> readVector (addToMutableList acc form) rest
50 | None, _ -> raise <| errExpectedButEOF "']'"
51
52 and readMap acc = function
53 | CloseBrace::rest -> Some(Map(acc |> List.rev |> Map.ofList)), rest
54 | [] -> raise <| errExpectedButEOF "'}'"
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
60 | None, _ -> raise <| errExpectedButEOF "'}'"
61 | None, _ -> raise <| errExpectedButEOF "'}'"
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
68 | None, _ -> raise <| errExpectedButEOF "form"
69 | _ -> raise <| errExpectedButEOF "map"
70
71 and readAtom = function
72 | Token("nil")::rest -> Some(Nil), rest
73 | Token("true")::rest -> Some(Bool(true)), rest
74 | Token("false")::rest -> Some(Bool(false)), rest
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, []
80 | _ -> raise <| errInvalid ()
81
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
89 let read_str str =
90 tokenize str |> readForms []