20 func READ(str
string) (MalType
, error
) {
21 return reader
.Read_str(str
)
25 func is_pair(x MalType
) bool {
27 if e
!= nil { return false }
31 func quasiquote(ast MalType
) MalType
{
33 return List
{[]MalType
{Symbol
{"quote"}, ast
},nil}
35 slc
, _
:= GetSlice(ast
)
37 if Symbol_Q(a0
) && (a0
.(Symbol
).Val
== "unquote") {
39 } else if is_pair(a0
) {
40 slc0
, _
:= GetSlice(a0
)
42 if Symbol_Q(a00
) && (a00
.(Symbol
).Val
== "splice-unquote") {
43 return List
{[]MalType
{Symbol
{"concat"},
45 quasiquote(List
{slc
[1:],nil})},nil}
48 return List
{[]MalType
{Symbol
{"cons"},
50 quasiquote(List
{slc
[1:],nil})},nil}
54 func is_macro_call(ast MalType
, env EnvType
) bool {
56 slc
, _
:= GetSlice(ast
)
58 if Symbol_Q(a0
) && env
.Find(a0
.(Symbol
)) != nil {
59 mac
, e
:= env
.Get(a0
.(Symbol
))
60 if e
!= nil { return false }
62 return mac
.(MalFunc
).GetMacro()
69 func macroexpand(ast MalType
, env EnvType
) (MalType
, error
) {
72 for ; is_macro_call(ast
, env
) ; {
73 slc
, _
:= GetSlice(ast
)
75 mac
, e
= env
.Get(a0
.(Symbol
)); if e
!= nil { return nil, e
}
77 ast
, e
= Apply(fn
, slc
[1:]); if e
!= nil { return nil, e
}
82 func eval_ast(ast MalType
, env EnvType
) (MalType
, error
) {
83 //fmt.Printf("eval_ast: %#v\n", ast)
85 return env
.Get(ast
.(Symbol
))
86 } else if List_Q(ast
) {
88 for _
, a
:= range ast
.(List
).Val
{
89 exp
, e
:= EVAL(a
, env
)
90 if e
!= nil { return nil, e
}
91 lst
= append(lst
, exp
)
93 return List
{lst
,nil}, nil
94 } else if Vector_Q(ast
) {
96 for _
, a
:= range ast
.(Vector
).Val
{
97 exp
, e
:= EVAL(a
, env
)
98 if e
!= nil { return nil, e
}
99 lst
= append(lst
, exp
)
101 return Vector
{lst
,nil}, nil
102 } else if HashMap_Q(ast
) {
104 new_hm
:= HashMap
{map[string]MalType
{},nil}
105 for k
, v
:= range m
.Val
{
106 ke
, e1
:= EVAL(k
, env
)
107 if e1
!= nil { return nil, e1
}
108 if _
, ok
:= ke
.(string); !ok
{
109 return nil, errors
.New("non string hash-map key")
111 kv
, e2
:= EVAL(v
, env
)
112 if e2
!= nil { return nil, e2
}
113 new_hm
.Val
[ke
.(string)] = kv
121 func EVAL(ast MalType
, env EnvType
) (MalType
, error
) {
125 //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true))
127 case List
: // continue
128 default: return eval_ast(ast
, env
)
132 ast
, e
= macroexpand(ast
, env
); if e
!= nil { return nil, e
}
133 if (!List_Q(ast
)) { return ast
, nil }
135 a0
:= ast
.(List
).Val
[0]
136 var a1 MalType
= nil; var a2 MalType
= nil
137 switch len(ast
.(List
).Val
) {
141 a1
= ast
.(List
).Val
[1]; a2
= nil
143 a1
= ast
.(List
).Val
[1]; a2
= ast
.(List
).Val
[2]
145 a0sym
:= "__<*fn*>__"
146 if Symbol_Q(a0
) { a0sym
= a0
.(Symbol
).Val
}
149 res
, e
:= EVAL(a2
, env
)
150 if e
!= nil { return nil, e
}
151 return env
.Set(a1
.(Symbol
), res
), nil
153 let_env
, e
:= NewEnv(env
, nil, nil)
154 if e
!= nil { return nil, e
}
155 arr1
, e
:= GetSlice(a1
)
156 if e
!= nil { return nil, e
}
157 for i
:= 0; i
< len(arr1
); i
+=2 {
158 if !Symbol_Q(arr1
[i
]) {
159 return nil, errors
.New("non-symbol bind value")
161 exp
, e
:= EVAL(arr1
[i
+1], let_env
)
162 if e
!= nil { return nil, e
}
163 let_env
.Set(arr1
[i
].(Symbol
), exp
)
172 fn
, e
:= EVAL(a2
, env
)
173 fn
= fn
.(MalFunc
).SetMacro()
174 if e
!= nil { return nil, e
}
175 return env
.Set(a1
.(Symbol
), fn
), nil
177 return macroexpand(a1
, env
)
180 exp
, e
:= EVAL(a1
, env
)
184 if a2
!= nil && List_Q(a2
) {
185 a2s
, _
:= GetSlice(a2
)
186 if Symbol_Q(a2s
[0]) && (a2s
[0].(Symbol
).Val
== "catch*") {
188 case MalError
: exc
= e
.(MalError
).Obj
189 default: exc
= e
.Error()
191 binds
:= NewList(a2s
[1])
192 new_env
, e
:= NewEnv(env
, binds
, NewList(exc
))
193 if e
!= nil { return nil, e
}
194 exp
, e
= EVAL(a2s
[2], new_env
)
195 if e
== nil { return exp
, nil }
201 lst
:= ast
.(List
).Val
202 _
, e
:= eval_ast(List
{lst
[1:len(lst
)-1],nil}, env
)
203 if e
!= nil { return nil, e
}
204 if len(lst
) == 1 { return nil, nil }
205 ast
= lst
[len(lst
)-1]
207 cond
, e
:= EVAL(a1
, env
)
208 if e
!= nil { return nil, e
}
209 if cond
== nil || cond
== false {
210 if len(ast
.(List
).Val
) >= 4 {
211 ast
= ast
.(List
).Val
[3]
219 fn
:= MalFunc
{EVAL
, a2
, env
, a1
, false, NewEnv
, nil}
222 el
, e
:= eval_ast(ast
, env
)
223 if e
!= nil { return nil, e
}
224 f
:= el
.(List
).Val
[0]
228 env
, e
= NewEnv(fn
.Env
, fn
.Params
, List
{el
.(List
).Val
[1:],nil})
229 if e
!= nil { return nil, e
}
232 if !ok
{ return nil, errors
.New("attempt to call non-function") }
233 return fn
.Fn(el
.(List
).Val
[1:])
241 func PRINT(exp MalType
) (string, error
) {
242 return printer
.Pr_str(exp
, true), nil
246 var repl_env
, _
= NewEnv(nil, nil, nil)
249 func rep(str
string) (MalType
, error
) {
253 if exp
, e
= READ(str
); e
!= nil { return nil, e
}
254 if exp
, e
= EVAL(exp
, repl_env
); e
!= nil { return nil, e
}
255 if res
, e
= PRINT(exp
); e
!= nil { return nil, e
}
260 // core.go: defined using go
261 for k
, v
:= range core
.NS
{
262 repl_env
.Set(Symbol
{k
}, Func
{v
.(func([]MalType
)(MalType
,error
)),nil})
264 repl_env
.Set(Symbol
{"eval"}, Func
{func(a
[]MalType
) (MalType
, error
) {
265 return EVAL(a
[0], repl_env
) },nil})
266 repl_env
.Set(Symbol
{"*ARGV*"}, List
{})
268 // core.mal: defined using the language itself
269 rep("(def! *host-language* \"go\")")
270 rep("(def! not (fn* (a) (if a false true)))")
271 rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
272 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)))))))")
273 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))))))))")
275 // called with mal script to load and eval
276 if len(os
.Args
) > 1 {
277 args
:= make([]MalType
, 0, len(os
.Args
)-2)
278 for _
,a
:= range os
.Args
[2:] {
279 args
= append(args
, a
)
281 repl_env
.Set(Symbol
{"*ARGV*"}, List
{args
,nil})
282 if _
,e
:= rep("(load-file \"" + os
.Args
[1] + "\")"); e
!= nil {
283 fmt
.Printf("Error: %v\n", e
)
290 rep("(println (str \"Mal [\" *host-language* \"]\"))")
292 text
, err
:= readline
.Readline("user> ")
293 text
= strings
.TrimRight(text
, "\n");
299 if out
, e
= rep(text
); e
!= nil {
300 if e
.Error() == "<empty line>" { continue }
301 fmt
.Printf("Error: %v\n", e
)
304 fmt
.Printf("%v\n", out
)