forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstep4_if_fn_do.vim
More file actions
123 lines (113 loc) Β· 2.74 KB
/
step4_if_fn_do.vim
File metadata and controls
123 lines (113 loc) Β· 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
source readline.vim
source types.vim
source reader.vim
source printer.vim
source env.vim
source core.vim
function READ(str)
return ReadStr(a:str)
endfunction
function EvalAst(ast, env)
if SymbolQ(a:ast)
let varname = a:ast.val
return a:env.get(varname)
elseif ListQ(a:ast)
return ListNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
elseif VectorQ(a:ast)
return VectorNew(map(copy(a:ast.val), {_, e -> EVAL(e, a:env)}))
elseif HashQ(a:ast)
let ret = {}
for [k,v] in items(a:ast.val)
let keyobj = HashParseKey(k)
let newkey = EVAL(keyobj, a:env)
let newval = EVAL(v, a:env)
let keystring = HashMakeKey(newkey)
let ret[keystring] = newval
endfor
return HashNew(ret)
else
return a:ast
end
endfunction
function EVAL(ast, env)
if !ListQ(a:ast)
return EvalAst(a:ast, a:env)
end
if EmptyQ(a:ast)
return a:ast
endif
let first = ListFirst(a:ast)
let first_symbol = SymbolQ(first) ? first.val : ""
if first_symbol == "def!"
let a1 = a:ast.val[1]
let a2 = a:ast.val[2]
let ret = a:env.set(a1.val, EVAL(a2, a:env))
return ret
elseif first_symbol == "let*"
let a1 = a:ast.val[1]
let a2 = a:ast.val[2]
let let_env = NewEnv(a:env)
let let_binds = a1.val
let i = 0
while i < len(let_binds)
call let_env.set(let_binds[i].val, EVAL(let_binds[i+1], let_env))
let i = i + 2
endwhile
return EVAL(a2, let_env)
elseif first_symbol == "if"
let condvalue = EVAL(a:ast.val[1], a:env)
if FalseQ(condvalue) || NilQ(condvalue)
if len(a:ast.val) < 4
return g:MalNil
else
return EVAL(a:ast.val[3], a:env)
endif
else
return EVAL(a:ast.val[2], a:env)
endif
elseif first_symbol == "do"
let el = EvalAst(ListRest(a:ast), a:env)
return el.val[-1]
elseif first_symbol == "fn*"
let fn = NewFn(ListNth(a:ast, 2), a:env, ListNth(a:ast, 1))
return fn
else
" apply list
let el = EvalAst(a:ast, a:env)
let funcobj = ListFirst(el)
let args = ListRest(el)
if NativeFunctionQ(funcobj)
return NativeFuncInvoke(funcobj, args)
elseif FunctionQ(funcobj)
return FuncInvoke(funcobj, args)
else
throw "Not a function"
endif
endif
endfunction
function PRINT(exp)
return PrStr(a:exp, 1)
endfunction
function REP(str, env)
return PRINT(EVAL(READ(a:str), a:env))
endfunction
let repl_env = NewEnv("")
for [k, Fn] in items(CoreNs)
call repl_env.set(k, Fn)
endfor
call REP("(def! not (fn* (a) (if a false true)))", repl_env)
while 1
let [eof, line] = Readline("user> ")
if eof
break
endif
if line == ""
continue
endif
try
call PrintLn(REP(line, repl_env))
catch
call PrintLn("Error: " . v:exception)
endtry
endwhile
qall!