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