basic: args file that doesn't rely on return value.
[jackhill/mal.git] / vb / step7_quote.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 MalString = Mal.types.MalString
8Imports MalSymbol = Mal.types.MalSymbol
9Imports MalList = Mal.types.MalList
10Imports MalVector = Mal.types.MalVector
11Imports MalHashMap = Mal.types.MalHashMap
12Imports MalFunc = Mal.types.MalFunc
13Imports MalEnv = Mal.env.Env
14
15Namespace Mal
aaba2493 16 Class step7_quote
ee7cd585
JM
17 ' read
18 Shared Function READ(str As String) As MalVal
19 Return reader.read_str(str)
20 End Function
21
22 ' eval
23 Shared Function is_pair(x As MalVal) As Boolean
24 return TypeOf x Is MalList AndAlso _
25 DirectCast(x,MalList).size() > 0
26 End Function
27
28 Shared Function quasiquote(ast As MalVal) As MalVal
29 If not is_pair(ast) Then
30 return New MalList(New MalSymbol("quote"), ast)
31 Else
32 Dim a0 As MalVal = DirectCast(ast,MalList)(0)
33 If TypeOf a0 Is MalSymbol AndAlso _
34 DirectCast(a0,MalSymbol).getName() = "unquote" Then
35 return DirectCast(ast,MalList)(1)
36 Else If is_pair(a0) Then
37 Dim a00 As MalVal = DirectCast(a0,MalList)(0)
38 If TypeOf a00 is MalSymbol AndAlso _
39 DirectCast(a00,MalSymbol).getName() = "splice-unquote" Then
40 return New MalList(New MalSymbol("concat"),
41 DirectCast(a0,MalList)(1),
42 quasiquote(DirectCast(ast,MalList).rest()))
43 End If
44 End If
45 return New MalList(New MalSymbol("cons"),
46 quasiquote(a0),
47 quasiquote(DirectCast(ast,MalList).rest()))
48 End If
49 End Function
50
51
52 Shared Function eval_ast(ast As MalVal, env As MalEnv) As MalVal
53 If TypeOf ast Is MalSymbol Then
b8ee29b2 54 return env.do_get(DirectCast(ast, MalSymbol))
ee7cd585
JM
55 Else If TypeOf ast Is MalList Then
56 Dim old_lst As MalList = DirectCast(ast, MalList)
57 Dim new_lst As MalList
58 If ast.list_Q() Then
59 new_lst = New MalList
60 Else
61 new_lst = DirectCast(New MalVector, MalList)
62 End If
63 Dim mv As MalVal
64 For Each mv in old_lst.getValue()
65 new_lst.conj_BANG(EVAL(mv, env))
66 Next
67 return new_lst
68 Else If TypeOf ast Is MalHashMap Then
69 Dim new_dict As New Dictionary(Of String, MalVal)
70 Dim entry As KeyValuePair(Of String, MalVal)
71 For Each entry in DirectCast(ast,MalHashMap).getValue()
72 new_dict.Add(entry.Key, EVAL(DirectCast(entry.Value,MalVal), env))
73 Next
74 return New MalHashMap(new_dict)
75 Else
76 return ast
77 End If
78 return ast
79 End Function
80
81 ' TODO: move to types.vb when it is ported
82 Class FClosure
83 Public ast As MalVal
84 Public params As MalList
85 Public env As MalEnv
86 Function fn(args as MalList) As MalVal
87 return EVAL(ast, new MalEnv(env, params, args))
88 End Function
89 End Class
90
91 Shared Function EVAL(orig_ast As MalVal, env As MalEnv) As MalVal
92 Do
93
94 'Console.WriteLine("EVAL: {0}", printer._pr_str(orig_ast, true))
95 If not orig_ast.list_Q() Then
96 return eval_ast(orig_ast, env)
97 End If
98
99 ' apply list
100 Dim ast As MalList = DirectCast(orig_ast, MalList)
101 If ast.size() = 0 Then
102 return ast
103 End If
104 Dim a0 As MalVal = ast(0)
105 Dim a0sym As String
106 If TypeOf a0 is MalSymbol Then
107 a0sym = DirectCast(a0,MalSymbol).getName()
108 Else
109 a0sym = "__<*fn*>__"
110 End If
111
112 Select a0sym
113 Case "def!"
114 Dim a1 As MalVal = ast(1)
115 Dim a2 As MalVal = ast(2)
116 Dim res As MalVal = EVAL(a2, env)
b8ee29b2 117 env.do_set(DirectCast(a1,MalSymbol), res)
ee7cd585
JM
118 return res
119 Case "let*"
120 Dim a1 As MalVal = ast(1)
121 Dim a2 As MalVal = ast(2)
122 Dim key As MalSymbol
123 Dim val as MalVal
124 Dim let_env As new MalEnv(env)
125 For i As Integer = 0 To (DirectCast(a1,MalList)).size()-1 Step 2
126 key = DirectCast(DirectCast(a1,MalList)(i),MalSymbol)
127 val = DirectCast(a1,MalList)(i+1)
b8ee29b2 128 let_env.do_set(key, EVAL(val, let_env))
ee7cd585
JM
129 Next
130 orig_ast = a2
131 env = let_env
132 Case "quote"
133 return ast(1)
134 Case "quasiquote"
135 orig_ast = quasiquote(ast(1))
136 Case "do"
137 eval_ast(ast.slice(1, ast.size()-1), env)
138 orig_ast = ast(ast.size()-1)
139 Case "if"
140 Dim a1 As MalVal = ast(1)
141 Dim cond As MalVal = EVAL(a1, env)
142 If cond Is Mal.types.Nil or cond Is Mal.types.MalFalse Then
143 ' eval false slot form
144 If ast.size() > 3 Then
145 orig_ast = ast(3)
146 Else
147 return Mal.types.Nil
148 End If
149 Else
150 ' eval true slot form
151 orig_ast = ast(2)
152
153 End If
154 Case "fn*"
155 Dim fc As New FClosure()
156 fc.ast = ast(2)
157 fc.params = DirectCast(ast(1),MalLIst)
158 fc.env = env
159 Dim f As Func(Of MalList, MalVal) = AddressOf fc.fn
160 Dim mf As new MalFunc(ast(2), env,
161 DirectCast(ast(1),MalList), f)
162 return DirectCast(mf,MalVal)
163 Case Else
164 Dim el As MalList = DirectCast(eval_ast(ast, env), MalList)
165 Dim f As MalFunc = DirectCast(el(0), MalFunc)
166 Dim fnast As MalVal = f.getAst()
167 If not fnast Is Nothing
168 orig_ast = fnast
169 env = f.genEnv(el.rest())
170 Else
171 Return f.apply(el.rest())
172 End If
173 End Select
174
175 Loop While True
176 End Function
177
178 ' print
179 Shared Function PRINT(exp As MalVal) As String
180 return printer._pr_str(exp, TRUE)
181 End Function
182
183 ' repl
184 Shared repl_env As MalEnv
185
186 Shared Function REP(str As String) As String
187 Return PRINT(EVAL(READ(str), repl_env))
188 End Function
189
190 Shared Function do_eval(args As MalList) As MalVal
191 Return EVAL(args(0), repl_env)
192 End Function
193
194 Shared Function Main As Integer
195 Dim args As String() = Environment.GetCommandLineArgs()
196
197 repl_env = New MalEnv(Nothing)
198
199 ' core.vb: defined using VB.NET
200 For Each entry As KeyValuePair(Of String,MalVal) In core.ns()
b8ee29b2 201 repl_env.do_set(new MalSymbol(entry.Key), entry.Value)
ee7cd585 202 Next
b8ee29b2 203 repl_env.do_set(new MalSymbol("eval"), new MalFunc(AddressOf do_eval))
aaba2493
JM
204 Dim fileIdx As Integer = 1
205 If args.Length > 1 AndAlso args(1) = "--raw" Then
206 Mal.readline.SetMode(Mal.readline.Modes.Raw)
207 fileIdx = 2
208 End If
ee7cd585 209 Dim argv As New MalList()
aaba2493 210 For i As Integer = fileIdx+1 To args.Length-1
ee7cd585
JM
211 argv.conj_BANG(new MalString(args(i)))
212 Next
b8ee29b2 213 repl_env.do_set(new MalSymbol("*ARGV*"), argv)
ee7cd585
JM
214
215 ' core.mal: defined using the language itself
216 REP("(def! not (fn* (a) (if a false true)))")
217 REP("(def! load-file (fn* (f) (eval (read-string (str ""(do "" (slurp f) "")"")))))")
218
ee7cd585
JM
219 If args.Length > fileIdx Then
220 REP("(load-file """ & args(fileIdx) & """)")
221 return 0
222 End If
223
224 ' repl loop
225 Dim line As String
226 Do
227 Try
228 line = Mal.readline.Readline("user> ")
229 If line is Nothing Then
230 Exit Do
231 End If
232 If line = "" Then
233 Continue Do
234 End If
235 Catch e As IOException
236 Console.WriteLine("IOException: " & e.Message)
237 End Try
238 Try
239 Console.WriteLine(REP(line))
240 Catch e as Exception
241 Console.WriteLine("Error: " & e.Message)
242 Console.WriteLine(e.StackTrace)
243 Continue Do
244 End Try
245 Loop While True
246 End function
aaba2493 247 End Class
ee7cd585 248End Namespace