Merge pull request #380 from bjh21/bjh21-bbc-basic
[jackhill/mal.git] / vb / step5_tco.vb
CommitLineData
ee7cd585
JM
1Imports System
2Imports System.IO
3Imports System.Collections.Generic
4Imports Mal
5Imports MalVal = Mal.types.MalVal
6Imports MalInt = Mal.types.MalInt
7Imports MalSymbol = Mal.types.MalSymbol
8Imports MalList = Mal.types.MalList
9Imports MalVector = Mal.types.MalVector
10Imports MalHashMap = Mal.types.MalHashMap
11Imports MalFunc = Mal.types.MalFunc
12Imports MalEnv = Mal.env.Env
13
14Namespace Mal
aaba2493 15 Class step5_tco
ee7cd585
JM
16 ' read
17 Shared Function READ(str As String) As MalVal
18 Return reader.read_str(str)
19 End Function
20
21 ' eval
22 Shared Function eval_ast(ast As MalVal, env As MalEnv) As MalVal
23 If TypeOf ast Is MalSymbol Then
b8ee29b2 24 return env.do_get(DirectCast(ast, MalSymbol))
ee7cd585
JM
25 Else If TypeOf ast Is MalList Then
26 Dim old_lst As MalList = DirectCast(ast, MalList)
27 Dim new_lst As MalList
28 If ast.list_Q() Then
29 new_lst = New MalList
30 Else
31 new_lst = DirectCast(New MalVector, MalList)
32 End If
33 Dim mv As MalVal
34 For Each mv in old_lst.getValue()
35 new_lst.conj_BANG(EVAL(mv, env))
36 Next
37 return new_lst
38 Else If TypeOf ast Is MalHashMap Then
39 Dim new_dict As New Dictionary(Of String, MalVal)
40 Dim entry As KeyValuePair(Of String, MalVal)
41 For Each entry in DirectCast(ast,MalHashMap).getValue()
42 new_dict.Add(entry.Key, EVAL(DirectCast(entry.Value,MalVal), env))
43 Next
44 return New MalHashMap(new_dict)
45 Else
46 return ast
47 End If
48 return ast
49 End Function
50
51 ' TODO: move to types.vb when it is ported
52 Class FClosure
53 Public ast As MalVal
54 Public params As MalList
55 Public env As MalEnv
56 Function fn(args as MalList) As MalVal
57 return EVAL(ast, new MalEnv(env, params, args))
58 End Function
59 End Class
60
61 Shared Function EVAL(orig_ast As MalVal, env As MalEnv) As MalVal
62 Do
63
64 'Console.WriteLine("EVAL: {0}", printer._pr_str(orig_ast, true))
65 If not orig_ast.list_Q() Then
66 return eval_ast(orig_ast, env)
67 End If
68
69 ' apply list
70 Dim ast As MalList = DirectCast(orig_ast, MalList)
71 If ast.size() = 0 Then
72 return ast
73 End If
74 Dim a0 As MalVal = ast(0)
75 Dim a0sym As String
76 If TypeOf a0 is MalSymbol Then
77 a0sym = DirectCast(a0,MalSymbol).getName()
78 Else
79 a0sym = "__<*fn*>__"
80 End If
81
82 Select a0sym
83 Case "def!"
84 Dim a1 As MalVal = ast(1)
85 Dim a2 As MalVal = ast(2)
86 Dim res As MalVal = EVAL(a2, env)
b8ee29b2 87 env.do_set(DirectCast(a1,MalSymbol), res)
ee7cd585
JM
88 return res
89 Case "let*"
90 Dim a1 As MalVal = ast(1)
91 Dim a2 As MalVal = ast(2)
92 Dim key As MalSymbol
93 Dim val as MalVal
94 Dim let_env As new MalEnv(env)
95 For i As Integer = 0 To (DirectCast(a1,MalList)).size()-1 Step 2
96 key = DirectCast(DirectCast(a1,MalList)(i),MalSymbol)
97 val = DirectCast(a1,MalList)(i+1)
b8ee29b2 98 let_env.do_set(key, EVAL(val, let_env))
ee7cd585
JM
99 Next
100 orig_ast = a2
101 env = let_env
102 Case "do"
103 eval_ast(ast.slice(1, ast.size()-1), env)
104 orig_ast = ast(ast.size()-1)
105 Case "if"
106 Dim a1 As MalVal = ast(1)
107 Dim cond As MalVal = EVAL(a1, env)
108 If cond Is Mal.types.Nil or cond Is Mal.types.MalFalse Then
109 ' eval false slot form
110 If ast.size() > 3 Then
111 orig_ast = ast(3)
112 Else
113 return Mal.types.Nil
114 End If
115 Else
116 ' eval true slot form
117 orig_ast = ast(2)
118
119 End If
120 Case "fn*"
121 Dim fc As New FClosure()
122 fc.ast = ast(2)
123 fc.params = DirectCast(ast(1),MalLIst)
124 fc.env = env
125 Dim f As Func(Of MalList, MalVal) = AddressOf fc.fn
126 Dim mf As new MalFunc(ast(2), env,
127 DirectCast(ast(1),MalList), f)
128 return DirectCast(mf,MalVal)
129 Case Else
130 Dim el As MalList = DirectCast(eval_ast(ast, env), MalList)
131 Dim f As MalFunc = DirectCast(el(0), MalFunc)
132 Dim fnast As MalVal = f.getAst()
133 If not fnast Is Nothing
134 orig_ast = fnast
135 env = f.genEnv(el.rest())
136 Else
137 Return f.apply(el.rest())
138 End If
139 End Select
140
141 Loop While True
142 End Function
143
144 ' print
145 Shared Function PRINT(exp As MalVal) As String
146 return printer._pr_str(exp, TRUE)
147 End Function
148
149 ' repl
150 Shared repl_env As MalEnv
151
152 Shared Function REP(str As String) As String
153 Return PRINT(EVAL(READ(str), repl_env))
154 End Function
155
156 Shared Function Main As Integer
157 Dim args As String() = Environment.GetCommandLineArgs()
158
159 repl_env = New MalEnv(Nothing)
160
161 ' core.vb: defined using VB.NET
162 For Each entry As KeyValuePair(Of String,MalVal) In core.ns()
b8ee29b2 163 repl_env.do_set(new MalSymbol(entry.Key), entry.Value)
ee7cd585
JM
164 Next
165
166 ' core.mal: defined using the language itself
167 REP("(def! not (fn* (a) (if a false true)))")
168
169 If args.Length > 1 AndAlso args(1) = "--raw" Then
170 Mal.readline.SetMode(Mal.readline.Modes.Raw)
171 End If
172
173 ' repl loop
174 Dim line As String
175 Do
176 Try
177 line = Mal.readline.Readline("user> ")
178 If line is Nothing Then
179 Exit Do
180 End If
181 If line = "" Then
182 Continue Do
183 End If
184 Catch e As IOException
185 Console.WriteLine("IOException: " & e.Message)
186 End Try
187 Try
188 Console.WriteLine(REP(line))
189 Catch e as Exception
190 Console.WriteLine("Error: " & e.Message)
191 Console.WriteLine(e.StackTrace)
192 Continue Do
193 End Try
194 Loop While True
195 End function
aaba2493 196 End Class
ee7cd585 197End Namespace