diff options
| author | Joel Martin <github@martintribe.org> | 2014-11-15 23:15:09 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:47 -0600 |
| commit | ee7cd5859e56423983f025088c8cef36b7ed09dd (patch) | |
| tree | da9f2011f4feaa34c96a63407fa4e8720eb1d4dc /vb/step9_try.vb | |
| parent | c3b508af92800f63bf99f41af68f026535f454f5 (diff) | |
| download | mal-ee7cd5859e56423983f025088c8cef36b7ed09dd.tar.gz mal-ee7cd5859e56423983f025088c8cef36b7ed09dd.zip | |
VB.Net: port of C# version.
Diffstat (limited to 'vb/step9_try.vb')
| -rw-r--r-- | vb/step9_try.vb | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/vb/step9_try.vb b/vb/step9_try.vb new file mode 100644 index 0000000..0b888b7 --- /dev/null +++ b/vb/step9_try.vb @@ -0,0 +1,318 @@ +Imports System +Imports System.IO +Imports System.Collections.Generic +Imports Mal +Imports MalVal = Mal.types.MalVal +Imports MalInt = Mal.types.MalInt +Imports MalString = Mal.types.MalString +Imports MalSymbol = Mal.types.MalSymbol +Imports MalList = Mal.types.MalList +Imports MalVector = Mal.types.MalVector +Imports MalHashMap = Mal.types.MalHashMap +Imports MalFunc = Mal.types.MalFunc +Imports MalEnv = Mal.env.Env + +Namespace Mal + Class step9_try + ' read + Shared Function READ(str As String) As MalVal + Return reader.read_str(str) + End Function + + ' eval + Shared Function is_pair(x As MalVal) As Boolean + return TypeOf x Is MalList AndAlso _ + DirectCast(x,MalList).size() > 0 + End Function + + Shared Function quasiquote(ast As MalVal) As MalVal + If not is_pair(ast) Then + return New MalList(New MalSymbol("quote"), ast) + Else + Dim a0 As MalVal = DirectCast(ast,MalList)(0) + If TypeOf a0 Is MalSymbol AndAlso _ + DirectCast(a0,MalSymbol).getName() = "unquote" Then + return DirectCast(ast,MalList)(1) + Else If is_pair(a0) Then + Dim a00 As MalVal = DirectCast(a0,MalList)(0) + If TypeOf a00 is MalSymbol AndAlso _ + DirectCast(a00,MalSymbol).getName() = "splice-unquote" Then + return New MalList(New MalSymbol("concat"), + DirectCast(a0,MalList)(1), + quasiquote(DirectCast(ast,MalList).rest())) + End If + End If + return New MalList(New MalSymbol("cons"), + quasiquote(a0), + quasiquote(DirectCast(ast,MalList).rest())) + End If + End Function + + Shared Function is_macro_call(ast As MalVal, env As MalEnv) As Boolean + If TypeOf ast Is MalList Then + Dim a0 As MalVal = DirectCast(ast,MalList)(0) + If TypeOf a0 Is MalSymbol AndAlso _ + env.find(DirectCast(a0,MalSymbol).getName()) IsNot Nothing Then + Dim mac As MalVal = env.do_get(DirectCast(a0,MalSymbol).getName()) + If TypeOf mac Is MalFunc AndAlso _ + DirectCast(mac,MalFunc).isMacro() Then + return True + End If + End If + End If + return False + End Function + + Shared Function macroexpand(ast As MalVal, env As MalEnv) As MalVal + While is_macro_call(ast, env) + Dim a0 As MalSymbol = DirectCast(DirectCast(ast,MalList)(0),MalSymbol) + Dim mac As MalFunc = DirectCast(env.do_get(a0.getName()),MalFunc) + ast = mac.apply(DirectCast(ast,MalList).rest()) + End While + return ast + End Function + + Shared Function eval_ast(ast As MalVal, env As MalEnv) As MalVal + If TypeOf ast Is MalSymbol Then + Dim sym As MalSymbol = DirectCast(ast, MalSymbol) + return env.do_get(sym.getName()) + Else If TypeOf ast Is MalList Then + Dim old_lst As MalList = DirectCast(ast, MalList) + Dim new_lst As MalList + If ast.list_Q() Then + new_lst = New MalList + Else + new_lst = DirectCast(New MalVector, MalList) + End If + Dim mv As MalVal + For Each mv in old_lst.getValue() + new_lst.conj_BANG(EVAL(mv, env)) + Next + return new_lst + Else If TypeOf ast Is MalHashMap Then + Dim new_dict As New Dictionary(Of String, MalVal) + Dim entry As KeyValuePair(Of String, MalVal) + For Each entry in DirectCast(ast,MalHashMap).getValue() + new_dict.Add(entry.Key, EVAL(DirectCast(entry.Value,MalVal), env)) + Next + return New MalHashMap(new_dict) + Else + return ast + End If + return ast + End Function + + ' TODO: move to types.vb when it is ported + Class FClosure + Public ast As MalVal + Public params As MalList + Public env As MalEnv + Function fn(args as MalList) As MalVal + return EVAL(ast, new MalEnv(env, params, args)) + End Function + End Class + + Shared Function EVAL(orig_ast As MalVal, env As MalEnv) As MalVal + Do + + 'Console.WriteLine("EVAL: {0}", printer._pr_str(orig_ast, true)) + If not orig_ast.list_Q() Then + return eval_ast(orig_ast, env) + End If + + ' apply list + Dim expanded As MalVal = macroexpand(orig_ast, env) + if not expanded.list_Q() Then + return expanded + End If + Dim ast As MalList = DirectCast(expanded, MalList) + + If ast.size() = 0 Then + return ast + End If + Dim a0 As MalVal = ast(0) + Dim a0sym As String + If TypeOf a0 is MalSymbol Then + a0sym = DirectCast(a0,MalSymbol).getName() + Else + a0sym = "__<*fn*>__" + End If + + Select a0sym + Case "def!" + Dim a1 As MalVal = ast(1) + Dim a2 As MalVal = ast(2) + Dim res As MalVal = EVAL(a2, env) + env.do_set(DirectCast(a1,MalSymbol).getName(), res) + return res + Case "let*" + Dim a1 As MalVal = ast(1) + Dim a2 As MalVal = ast(2) + Dim key As MalSymbol + Dim val as MalVal + Dim let_env As new MalEnv(env) + For i As Integer = 0 To (DirectCast(a1,MalList)).size()-1 Step 2 + key = DirectCast(DirectCast(a1,MalList)(i),MalSymbol) + val = DirectCast(a1,MalList)(i+1) + let_env.do_set(key.getName(), EVAL(val, let_env)) + Next + orig_ast = a2 + env = let_env + Case "quote" + return ast(1) + Case "quasiquote" + orig_ast = quasiquote(ast(1)) + Case "defmacro!" + Dim a1 As MalVal = ast(1) + Dim a2 As MalVal = ast(2) + Dim res As MalVal = EVAL(a2, env) + DirectCast(res,MalFunc).setMacro() + env.do_set(DirectCast(a1,MalSymbol).getName(), res) + return res + Case "macroexpand" + Dim a1 As MalVal = ast(1) + return macroexpand(a1, env) + Case "try*" + Try + return EVAL(ast(1), env) + Catch e As Exception + If ast.size() > 2 Then + Dim exc As MalVal + Dim a2 As MalVal = ast(2) + Dim a20 As MalVal = DirectCast(a2,MalList)(0) + If DirectCast(a20,MalSymbol).getName() = "catch*" Then + If TypeOf e Is Mal.types.MalException Then + exc = DirectCast(e,Mal.types.MalException).getValue() + Else + exc = New MalString(e.StackTrace) + End If + return EVAL( + DirectCast(a2,MalList)(2), + New MalEnv(env, + DirectCast(a2,MalList).slice(1,2), + New MalList(exc))) + End If + Throw e + End If + End Try + Case "do" + eval_ast(ast.slice(1, ast.size()-1), env) + orig_ast = ast(ast.size()-1) + Case "if" + Dim a1 As MalVal = ast(1) + Dim cond As MalVal = EVAL(a1, env) + If cond Is Mal.types.Nil or cond Is Mal.types.MalFalse Then + ' eval false slot form + If ast.size() > 3 Then + orig_ast = ast(3) + Else + return Mal.types.Nil + End If + Else + ' eval true slot form + orig_ast = ast(2) + + End If + Case "fn*" + Dim fc As New FClosure() + fc.ast = ast(2) + fc.params = DirectCast(ast(1),MalLIst) + fc.env = env + Dim f As Func(Of MalList, MalVal) = AddressOf fc.fn + Dim mf As new MalFunc(ast(2), env, + DirectCast(ast(1),MalList), f) + return DirectCast(mf,MalVal) + Case Else + Dim el As MalList = DirectCast(eval_ast(ast, env), MalList) + Dim f As MalFunc = DirectCast(el(0), MalFunc) + Dim fnast As MalVal = f.getAst() + If not fnast Is Nothing + orig_ast = fnast + env = f.genEnv(el.rest()) + Else + Return f.apply(el.rest()) + End If + End Select + + Loop While True + End Function + + ' print + Shared Function PRINT(exp As MalVal) As String + return printer._pr_str(exp, TRUE) + End Function + + ' repl + Shared repl_env As MalEnv + + Shared Function REP(str As String) As String + Return PRINT(EVAL(READ(str), repl_env)) + End Function + + Shared Function do_eval(args As MalList) As MalVal + Return EVAL(args(0), repl_env) + End Function + + Shared Function Main As Integer + Dim args As String() = Environment.GetCommandLineArgs() + + repl_env = New MalEnv(Nothing) + + ' core.vb: defined using VB.NET + For Each entry As KeyValuePair(Of String,MalVal) In core.ns() + repl_env.do_set(entry.Key, entry.Value) + Next + repl_env.do_set("eval", new MalFunc(AddressOf do_eval)) + Dim argv As New MalList() + For i As Integer = 0 To args.Length()-1 + argv.conj_BANG(new MalString(args(i))) + Next + repl_env.do_set("*ARGV*", argv) + + ' core.mal: defined using the language itself + REP("(def! *host-language* ""VB.NET"")") + REP("(def! not (fn* (a) (if a false true)))") + REP("(def! load-file (fn* (f) (eval (read-string (str ""(do "" (slurp f) "")"")))))") + REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons 'cond (rest (rest xs)))))))") + REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") + + Dim fileIdx As Integer = 1 + If args.Length > 1 AndAlso args(1) = "--raw" Then + Mal.readline.SetMode(Mal.readline.Modes.Raw) + fileIdx = 2 + End If + If args.Length > fileIdx Then + REP("(load-file """ & args(fileIdx) & """)") + return 0 + End If + + ' repl loop + Dim line As String + REP("(println (str ""Mal ["" *host-language* ""]""))") + Do + Try + line = Mal.readline.Readline("user> ") + If line is Nothing Then + Exit Do + End If + If line = "" Then + Continue Do + End If + Catch e As IOException + Console.WriteLine("IOException: " & e.Message) + End Try + Try + Console.WriteLine(REP(line)) + Catch e As Mal.types.MalException + Console.WriteLine("Error: " & _ + printer._pr_str(e.getValue(), False)) + Continue Do + Catch e As Exception + Console.WriteLine("Error: " & e.Message) + Console.WriteLine(e.StackTrace) + Continue Do + End Try + Loop While True + End function + End Class +End Namespace |
