aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-09 21:37:00 -0500
committerJoel Martin <github@martintribe.org>2014-10-09 21:37:00 -0500
commitf2544a9467ea032aff505b3ced3b4b3510a828fe (patch)
treeaa1984aef01c20b7b093527c28c37bd7d4d803d5
parentf2c9811fd8cbb205fad68952ebc1ba5d310f148d (diff)
downloadmal-f2544a9467ea032aff505b3ced3b4b3510a828fe.tar.gz
mal-f2544a9467ea032aff505b3ced3b4b3510a828fe.zip
go: add metadata and atoms. HashMap dedicated type.
HashMap needs a dedicated type now to be able to store the metadata.
-rw-r--r--go/src/core/core.go104
-rw-r--r--go/src/printer/printer.go9
-rw-r--r--go/src/reader/reader.go19
-rw-r--r--go/src/step2_eval/step2_eval.go14
-rw-r--r--go/src/step3_env/step3_env.go14
-rw-r--r--go/src/step4_if_fn_do/step4_if_fn_do.go16
-rw-r--r--go/src/step5_tco/step5_tco.go18
-rw-r--r--go/src/step6_file/step6_file.go20
-rw-r--r--go/src/step7_quote/step7_quote.go26
-rw-r--r--go/src/step8_macros/step8_macros.go26
-rw-r--r--go/src/stepA_more/stepA_more.go26
-rw-r--r--go/src/types/types.go73
12 files changed, 223 insertions, 142 deletions
diff --git a/go/src/core/core.go b/go/src/core/core.go
index cdb7d8f..f5d5842 100644
--- a/go/src/core/core.go
+++ b/go/src/core/core.go
@@ -47,18 +47,21 @@ func slurp(a []MalType) (MalType, error) {
// Hash Map functions
+func copy_hash_map(hm HashMap) (HashMap) {
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range hm.Val { new_hm.Val[k] = v }
+ return new_hm
+}
+
func assoc(a []MalType) (MalType, error) {
if len(a) <3 { return nil, errors.New("assoc requires at least 3 arguments") }
if (len(a) % 2 != 1) { return nil, errors.New("assoc requires odd number of arguments") }
if !HashMap_Q(a[0]) { return nil, errors.New("assoc called on non-hash map") }
- old_hm := a[0].(map[string]MalType)
- new_hm := map[string]MalType{}
- // copy
- for k, v := range old_hm { new_hm[k] = v }
+ new_hm := copy_hash_map(a[0].(HashMap))
for i := 1; i < len(a); i+=2 {
key := a[i]
if !String_Q(key) { return nil, errors.New("assoc called with non-string key") }
- new_hm[key.(string)] = a[i+1]
+ new_hm.Val[key.(string)] = a[i+1]
}
return new_hm, nil
}
@@ -66,14 +69,11 @@ func assoc(a []MalType) (MalType, error) {
func dissoc(a []MalType) (MalType, error) {
if len(a) <2 { return nil, errors.New("dissoc requires at least 3 arguments") }
if !HashMap_Q(a[0]) { return nil, errors.New("dissoc called on non-hash map") }
- old_hm := a[0].(map[string]MalType)
- new_hm := map[string]MalType{}
- // copy
- for k, v := range old_hm { new_hm[k] = v }
+ new_hm := copy_hash_map(a[0].(HashMap))
for i := 1; i < len(a); i+=1 {
key := a[i]
if !String_Q(key) { return nil, errors.New("dissoc called with non-string key") }
- delete(new_hm,key.(string))
+ delete(new_hm.Val,key.(string))
}
return new_hm, nil
}
@@ -83,32 +83,32 @@ func get(a []MalType) (MalType, error) {
if Nil_Q(a[0]) { return nil, nil }
if !HashMap_Q(a[0]) { return nil, errors.New("get called on non-hash map") }
if !String_Q(a[1]) { return nil, errors.New("get called with non-string key") }
- return a[0].(map[string]MalType)[a[1].(string)], nil
+ return a[0].(HashMap).Val[a[1].(string)], nil
}
func contains_Q(hm MalType, key MalType) (MalType, error) {
if Nil_Q(hm) { return nil, nil }
if !HashMap_Q(hm) { return nil, errors.New("get called on non-hash map") }
if !String_Q(key) { return nil, errors.New("get called with non-string key") }
- _, ok := hm.(map[string]MalType)[key.(string)]
+ _, ok := hm.(HashMap).Val[key.(string)]
return ok, nil
}
func keys(a []MalType) (MalType, error) {
if !HashMap_Q(a[0]) { return nil, errors.New("keys called on non-hash map") }
slc := []MalType{}
- for k, _ := range a[0].(map[string]MalType) {
+ for k, _ := range a[0].(HashMap).Val {
slc = append(slc, k)
}
- return List{slc}, nil
+ return List{slc,nil}, nil
}
func vals(a []MalType) (MalType, error) {
if !HashMap_Q(a[0]) { return nil, errors.New("keys called on non-hash map") }
slc := []MalType{}
- for _, v := range a[0].(map[string]MalType) {
+ for _, v := range a[0].(HashMap).Val {
slc = append(slc, v)
}
- return List{slc}, nil
+ return List{slc,nil}, nil
}
@@ -118,7 +118,7 @@ func cons(a []MalType) (MalType, error) {
val := a[0]
lst, e := GetSlice(a[1]); if e != nil { return nil, e }
- return List{append([]MalType{val}, lst...)}, nil
+ return List{append([]MalType{val}, lst...),nil}, nil
}
func concat(a []MalType) (MalType, error) {
@@ -128,7 +128,7 @@ func concat(a []MalType) (MalType, error) {
slc2, e := GetSlice(a[i]); if e != nil { return nil, e }
slc1 = append(slc1, slc2...)
}
- return List{slc1}, nil
+ return List{slc1,nil}, nil
}
func nth(a []MalType) (MalType, error) {
@@ -147,7 +147,7 @@ func first(a []MalType) (MalType, error) {
func rest(a []MalType) (MalType, error) {
slc, e := GetSlice(a[0]); if e != nil { return nil, e }
if len(slc) == 0 { return List{}, nil }
- return List{slc[1:]}, nil
+ return List{slc[1:],nil}, nil
}
@@ -192,10 +192,60 @@ func do_map(a []MalType) (MalType, error) {
results = append(results, res)
if e != nil { return nil, e }
}
- return List{results}, nil
+ return List{results,nil}, nil
}
+// Metadata functions
+func with_meta(a []MalType) (MalType, error) {
+ if len(a) != 2 { return nil, errors.New("with-meta requires 2 args") }
+ obj := a[0]; m := a[1]
+ switch tobj := obj.(type) {
+ case List: return List{tobj.Val,m}, nil
+ case Vector: return Vector{tobj.Val,m}, nil
+ case HashMap: return HashMap{tobj.Val,m}, nil
+ case MalFunc: fn := tobj; fn.Meta = m; return fn, nil
+ default: return nil, errors.New("with-meta not supported on type")
+ }
+}
+
+func meta(a []MalType) (MalType, error) {
+ obj := a[0]
+ switch tobj := obj.(type) {
+ case List: return tobj.Meta, nil
+ case Vector: return tobj.Meta, nil
+ case HashMap: return tobj.Meta, nil
+ case MalFunc: return tobj.Meta, nil
+ default: return nil, errors.New("meta not supported on type")
+ }
+}
+
+
+// Atom functions
+func deref(a []MalType) (MalType, error) {
+ if !Atom_Q(a[0]) { return nil, errors.New("deref called with non-atom") }
+ return a[0].(*Atom).Val, nil
+}
+
+func reset_BANG(a []MalType) (MalType, error) {
+ if !Atom_Q(a[0]) { return nil, errors.New("reset! called with non-atom") }
+ a[0].(*Atom).Set(a[1])
+ return a[1], nil
+}
+
+func swap_BANG(a []MalType) (MalType, error) {
+ if !Atom_Q(a[0]) { return nil, errors.New("swap! called with non-atom") }
+ if len(a) < 2 { return nil, errors.New("swap! requires at least 2 args") }
+ atm := a[0].(*Atom)
+ args := []MalType{atm.Val}
+ f := a[1]
+ args = append(args, a[2:]...)
+ res, e := Apply(f, args)
+ if e != nil { return nil, e }
+ atm.Set(res)
+ return res, nil
+}
+
// core namespace
var NS = map[string]MalType{
@@ -239,15 +289,15 @@ var NS = map[string]MalType{
return a[0].(int) / a[1].(int), nil },
"list": func(a []MalType) (MalType, error) {
- return List{a}, nil },
+ return List{a,nil}, nil },
"list?": func(a []MalType) (MalType, error) {
return List_Q(a[0]), nil },
"vector": func(a []MalType) (MalType, error) {
- return Vector{a}, nil },
+ return Vector{a,nil}, nil },
"vector?": func(a []MalType) (MalType, error) {
return Vector_Q(a[0]), nil },
"hash-map": func(a []MalType) (MalType, error) {
- return NewHashMap(List{a}) },
+ return NewHashMap(List{a,nil}) },
"map?": func(a []MalType) (MalType, error) {
return HashMap_Q(a[0]), nil },
"assoc": assoc,
@@ -269,4 +319,12 @@ var NS = map[string]MalType{
"count": count,
"apply": apply,
"map": do_map,
+
+ "with-meta": with_meta,
+ "meta": meta,
+ "atom": func(a []MalType) (MalType, error) {
+ return &Atom{a[0],nil}, nil },
+ "deref": deref,
+ "reset!": reset_BANG,
+ "swap!": swap_BANG,
}
diff --git a/go/src/printer/printer.go b/go/src/printer/printer.go
index 887c749..428958e 100644
--- a/go/src/printer/printer.go
+++ b/go/src/printer/printer.go
@@ -24,9 +24,9 @@ func Pr_str(obj types.MalType, print_readably bool) string {
return Pr_list(tobj.Val, print_readably, "(", ")", " ")
case types.Vector:
return Pr_list(tobj.Val, print_readably, "[", "]", " ")
- case map[string]types.MalType:
- str_list := make([]string, 0, len(tobj)*2)
- for k, v := range tobj {
+ case types.HashMap:
+ str_list := make([]string, 0, len(tobj.Val)*2)
+ for k, v := range tobj.Val {
str_list = append(str_list, Pr_str(k, print_readably))
str_list = append(str_list, Pr_str(v, print_readably))
}
@@ -51,6 +51,9 @@ func Pr_str(obj types.MalType, print_readably bool) string {
Pr_str(tobj.Exp, true) + ")"
case func([]types.MalType)(types.MalType, error):
return fmt.Sprintf("<function %v>", obj)
+ case *types.Atom:
+ return "(atom " +
+ Pr_str(tobj.Val, true) + ")"
default:
return fmt.Sprintf("%v", obj)
}
diff --git a/go/src/reader/reader.go b/go/src/reader/reader.go
index 2ac5a08..38f163c 100644
--- a/go/src/reader/reader.go
+++ b/go/src/reader/reader.go
@@ -93,13 +93,13 @@ func read_list(rdr Reader, start string, end string) (MalType, error) {
ast_list = append(ast_list, f)
}
rdr.next()
- return List{ast_list}, nil
+ return List{ast_list,nil}, nil
}
func read_vector(rdr Reader) (MalType, error) {
lst, e := read_list(rdr, "[", "]")
if e != nil { return nil, e }
- vec := Vector{lst.(List).Val}
+ vec := Vector{lst.(List).Val,nil}
return vec, nil
}
@@ -116,16 +116,23 @@ func read_form(rdr Reader) (MalType, error) {
case `'`: rdr.next();
form, e := read_form(rdr); if e != nil { return nil, e }
- return List{[]MalType{Symbol{"quote"}, form}}, nil
+ return List{[]MalType{Symbol{"quote"}, form},nil}, nil
case "`": rdr.next();
form, e := read_form(rdr); if e != nil { return nil, e }
- return List{[]MalType{Symbol{"quasiquote"}, form}}, nil
+ return List{[]MalType{Symbol{"quasiquote"}, form},nil}, nil
case `~`: rdr.next();
form, e := read_form(rdr); if e != nil { return nil, e }
- return List{[]MalType{Symbol{"unquote"}, form}}, nil
+ return List{[]MalType{Symbol{"unquote"}, form},nil}, nil
case `~@`: rdr.next();
form, e := read_form(rdr); if e != nil { return nil, e }
- return List{[]MalType{Symbol{"splice-unquote"}, form}}, nil
+ return List{[]MalType{Symbol{"splice-unquote"}, form},nil}, nil
+ case `^`: rdr.next();
+ meta, e := read_form(rdr); if e != nil { return nil, e }
+ form, e := read_form(rdr); if e != nil { return nil, e }
+ return List{[]MalType{Symbol{"with-meta"}, form,meta},nil}, nil
+ case `@`: rdr.next();
+ form, e := read_form(rdr); if e != nil { return nil, e }
+ return List{[]MalType{Symbol{"deref"}, form},nil}, nil
// list
case ")": return nil, errors.New("unexpected ')'")
diff --git a/go/src/step2_eval/step2_eval.go b/go/src/step2_eval/step2_eval.go
index d28de20..7a9a33f 100644
--- a/go/src/step2_eval/step2_eval.go
+++ b/go/src/step2_eval/step2_eval.go
@@ -33,7 +33,7 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -41,11 +41,11 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -53,7 +53,7 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -62,7 +62,7 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) {
}
func EVAL(ast MalType, env map[string]MalType) (MalType, error) {
- //fmt.Printf("EVAL: %#v\n", ast)
+ //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true))
switch ast.(type) {
case List: // continue
default: return eval_ast(ast, env)
diff --git a/go/src/step3_env/step3_env.go b/go/src/step3_env/step3_env.go
index eea250f..0d975ba 100644
--- a/go/src/step3_env/step3_env.go
+++ b/go/src/step3_env/step3_env.go
@@ -31,7 +31,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -39,11 +39,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -51,7 +51,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -60,7 +60,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
func EVAL(ast MalType, env EnvType) (MalType, error) {
- //fmt.Printf("EVAL: %#v\n", ast)
+ //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true))
switch ast.(type) {
case List: // continue
default: return eval_ast(ast, env)
diff --git a/go/src/step4_if_fn_do/step4_if_fn_do.go b/go/src/step4_if_fn_do/step4_if_fn_do.go
index 6a35b85..f63017b 100644
--- a/go/src/step4_if_fn_do/step4_if_fn_do.go
+++ b/go/src/step4_if_fn_do/step4_if_fn_do.go
@@ -32,7 +32,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -40,11 +40,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -52,7 +52,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -100,7 +100,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
}
return EVAL(a2, let_env)
case "do":
- el, e := eval_ast(List{ast.(List).Val[1:]}, env)
+ el, e := eval_ast(List{ast.(List).Val[1:],nil}, env)
if e != nil { return nil, e }
lst := el.(List).Val
if len(lst) == 0 { return nil, nil }
@@ -119,7 +119,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
}
case "fn*":
return func(arguments []MalType) (MalType, error) {
- new_env, e := NewEnv(env, a1, List{arguments})
+ new_env, e := NewEnv(env, a1, List{arguments,nil})
if e != nil { return nil, e }
return EVAL(a2, new_env)
}, nil
diff --git a/go/src/step5_tco/step5_tco.go b/go/src/step5_tco/step5_tco.go
index 75e1979..344a533 100644
--- a/go/src/step5_tco/step5_tco.go
+++ b/go/src/step5_tco/step5_tco.go
@@ -32,7 +32,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -40,11 +40,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -52,7 +52,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -104,7 +104,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
env = let_env
case "do":
lst := ast.(List).Val
- _, e := eval_ast(List{lst[1:len(lst)-1]}, env)
+ _, e := eval_ast(List{lst[1:len(lst)-1],nil}, env)
if e != nil { return nil, e }
if len(lst) == 1 { return nil, nil }
ast = lst[len(lst)-1]
@@ -121,7 +121,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = a2
}
case "fn*":
- fn := MalFunc{EVAL, a2, env, a1, false, NewEnv}
+ fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil}
return fn, nil
default:
el, e := eval_ast(ast, env)
@@ -130,7 +130,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
if MalFunc_Q(f) {
fn := f.(MalFunc)
ast = fn.Exp
- env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:]})
+ env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil})
if e != nil { return nil, e }
} else {
fn, ok := f.(func([]MalType)(MalType, error))
diff --git a/go/src/step6_file/step6_file.go b/go/src/step6_file/step6_file.go
index 912d932..51fe3cb 100644
--- a/go/src/step6_file/step6_file.go
+++ b/go/src/step6_file/step6_file.go
@@ -33,7 +33,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -41,11 +41,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -53,7 +53,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -105,7 +105,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
env = let_env
case "do":
lst := ast.(List).Val
- _, e := eval_ast(List{lst[1:len(lst)-1]}, env)
+ _, e := eval_ast(List{lst[1:len(lst)-1],nil}, env)
if e != nil { return nil, e }
if len(lst) == 1 { return nil, nil }
ast = lst[len(lst)-1]
@@ -122,7 +122,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = a2
}
case "fn*":
- fn := MalFunc{EVAL, a2, env, a1, false, NewEnv}
+ fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil}
return fn, nil
default:
el, e := eval_ast(ast, env)
@@ -131,7 +131,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
if MalFunc_Q(f) {
fn := f.(MalFunc)
ast = fn.Exp
- env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:]})
+ env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil})
if e != nil { return nil, e }
} else {
fn, ok := f.(func([]MalType)(MalType, error))
@@ -181,7 +181,7 @@ func main() {
for _,a := range os.Args[2:] {
args = append(args, a)
}
- repl_env.Set("*ARGV*", List{args})
+ repl_env.Set("*ARGV*", List{args,nil})
rep("(load-file \"" + os.Args[1] + "\")")
os.Exit(0)
}
diff --git a/go/src/step7_quote/step7_quote.go b/go/src/step7_quote/step7_quote.go
index 0877bbb..abf7b45 100644
--- a/go/src/step7_quote/step7_quote.go
+++ b/go/src/step7_quote/step7_quote.go
@@ -30,7 +30,7 @@ func is_pair(x MalType) bool {
func quasiquote(ast MalType) MalType {
if !is_pair(ast) {
- return List{[]MalType{Symbol{"quote"}, ast}}
+ return List{[]MalType{Symbol{"quote"}, ast},nil}
} else {
slc, _ := GetSlice(ast)
a0 := slc[0]
@@ -42,12 +42,12 @@ func quasiquote(ast MalType) MalType {
if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") {
return List{[]MalType{Symbol{"concat"},
slc0[1],
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
return List{[]MalType{Symbol{"cons"},
quasiquote(a0),
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
@@ -62,7 +62,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -70,11 +70,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -82,7 +82,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -138,7 +138,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = quasiquote(a1)
case "do":
lst := ast.(List).Val
- _, e := eval_ast(List{lst[1:len(lst)-1]}, env)
+ _, e := eval_ast(List{lst[1:len(lst)-1],nil}, env)
if e != nil { return nil, e }
if len(lst) == 1 { return nil, nil }
ast = lst[len(lst)-1]
@@ -155,7 +155,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = a2
}
case "fn*":
- fn := MalFunc{EVAL, a2, env, a1, false, NewEnv}
+ fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil}
return fn, nil
default:
el, e := eval_ast(ast, env)
@@ -164,7 +164,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
if MalFunc_Q(f) {
fn := f.(MalFunc)
ast = fn.Exp
- env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:]})
+ env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil})
if e != nil { return nil, e }
} else {
fn, ok := f.(func([]MalType)(MalType, error))
@@ -214,7 +214,7 @@ func main() {
for _,a := range os.Args[2:] {
args = append(args, a)
}
- repl_env.Set("*ARGV*", List{args})
+ repl_env.Set("*ARGV*", List{args,nil})
rep("(load-file \"" + os.Args[1] + "\")")
os.Exit(0)
}
diff --git a/go/src/step8_macros/step8_macros.go b/go/src/step8_macros/step8_macros.go
index 7a5c0e5..0feb739 100644
--- a/go/src/step8_macros/step8_macros.go
+++ b/go/src/step8_macros/step8_macros.go
@@ -30,7 +30,7 @@ func is_pair(x MalType) bool {
func quasiquote(ast MalType) MalType {
if !is_pair(ast) {
- return List{[]MalType{Symbol{"quote"}, ast}}
+ return List{[]MalType{Symbol{"quote"}, ast},nil}
} else {
slc, _ := GetSlice(ast)
a0 := slc[0]
@@ -42,12 +42,12 @@ func quasiquote(ast MalType) MalType {
if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") {
return List{[]MalType{Symbol{"concat"},
slc0[1],
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
return List{[]MalType{Symbol{"cons"},
quasiquote(a0),
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
@@ -90,7 +90,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -98,11 +98,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -110,7 +110,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -177,7 +177,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
return macroexpand(a1, env)
case "do":
lst := ast.(List).Val
- _, e := eval_ast(List{lst[1:len(lst)-1]}, env)
+ _, e := eval_ast(List{lst[1:len(lst)-1],nil}, env)
if e != nil { return nil, e }
if len(lst) == 1 { return nil, nil }
ast = lst[len(lst)-1]
@@ -194,7 +194,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = a2
}
case "fn*":
- fn := MalFunc{EVAL, a2, env, a1, false, NewEnv}
+ fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil}
return fn, nil
default:
el, e := eval_ast(ast, env)
@@ -203,7 +203,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
if MalFunc_Q(f) {
fn := f.(MalFunc)
ast = fn.Exp
- env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:]})
+ env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil})
if e != nil { return nil, e }
} else {
fn, ok := f.(func([]MalType)(MalType, error))
@@ -253,7 +253,7 @@ func main() {
for _,a := range os.Args[2:] {
args = append(args, a)
}
- repl_env.Set("*ARGV*", List{args})
+ repl_env.Set("*ARGV*", List{args,nil})
rep("(load-file \"" + os.Args[1] + "\")")
os.Exit(0)
}
diff --git a/go/src/stepA_more/stepA_more.go b/go/src/stepA_more/stepA_more.go
index 0194862..d573ad0 100644
--- a/go/src/stepA_more/stepA_more.go
+++ b/go/src/stepA_more/stepA_more.go
@@ -30,7 +30,7 @@ func is_pair(x MalType) bool {
func quasiquote(ast MalType) MalType {
if !is_pair(ast) {
- return List{[]MalType{Symbol{"quote"}, ast}}
+ return List{[]MalType{Symbol{"quote"}, ast},nil}
} else {
slc, _ := GetSlice(ast)
a0 := slc[0]
@@ -42,12 +42,12 @@ func quasiquote(ast MalType) MalType {
if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") {
return List{[]MalType{Symbol{"concat"},
slc0[1],
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
return List{[]MalType{Symbol{"cons"},
quasiquote(a0),
- quasiquote(List{slc[1:]})}}
+ quasiquote(List{slc[1:],nil})},nil}
}
}
@@ -90,7 +90,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return List{lst}, nil
+ return List{lst,nil}, nil
} else if Vector_Q(ast) {
lst := []MalType{}
for _, a := range ast.(Vector).Val {
@@ -98,11 +98,11 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
if e != nil { return nil, e }
lst = append(lst, exp)
}
- return Vector{lst}, nil
+ return Vector{lst,nil}, nil
} else if HashMap_Q(ast) {
- m := ast.(map[string]MalType)
- new_hm := map[string]MalType{}
- for k, v := range m {
+ m := ast.(HashMap)
+ new_hm := HashMap{map[string]MalType{},nil}
+ for k, v := range m.Val {
ke, e1 := EVAL(k, env)
if e1 != nil { return nil, e1 }
if _, ok := ke.(string); !ok {
@@ -110,7 +110,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
}
kv, e2 := EVAL(v, env)
if e2 != nil { return nil, e2 }
- new_hm[ke.(string)] = kv
+ new_hm.Val[ke.(string)] = kv
}
return new_hm, nil
} else {
@@ -199,7 +199,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
}
case "do":
lst := ast.(List).Val
- _, e := eval_ast(List{lst[1:len(lst)-1]}, env)
+ _, e := eval_ast(List{lst[1:len(lst)-1],nil}, env)
if e != nil { return nil, e }
if len(lst) == 1 { return nil, nil }
ast = lst[len(lst)-1]
@@ -216,7 +216,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
ast = a2
}
case "fn*":
- fn := MalFunc{EVAL, a2, env, a1, false, NewEnv}
+ fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil}
return fn, nil
default:
el, e := eval_ast(ast, env)
@@ -225,7 +225,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) {
if MalFunc_Q(f) {
fn := f.(MalFunc)
ast = fn.Exp
- env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:]})
+ env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil})
if e != nil { return nil, e }
} else {
fn, ok := f.(func([]MalType)(MalType, error))
@@ -275,7 +275,7 @@ func main() {
for _,a := range os.Args[2:] {
args = append(args, a)
}
- repl_env.Set("*ARGV*", List{args})
+ repl_env.Set("*ARGV*", List{args,nil})
rep("(load-file \"" + os.Args[1] + "\")")
os.Exit(0)
}
diff --git a/go/src/types/types.go b/go/src/types/types.go
index 03269f5..616c8c7 100644
--- a/go/src/types/types.go
+++ b/go/src/types/types.go
@@ -29,10 +29,7 @@ type EnvType interface {
// Scalars
func Nil_Q(obj MalType) bool {
- switch obj.(type) {
- case nil: return true
- default: return false
- }
+ if obj == nil { return true } else { return false }
}
func True_Q(obj MalType) bool {
@@ -55,19 +52,15 @@ type Symbol struct {
}
func Symbol_Q(obj MalType) bool {
- switch obj.(type) {
- case Symbol: return true
- default: return false
- }
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "Symbol"
}
// Strings
func String_Q(obj MalType) bool {
- switch obj.(type) {
- case string: return true
- default: return false
- }
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "string"
}
@@ -79,13 +72,12 @@ type MalFunc struct {
Params MalType
IsMacro bool
GenEnv func(EnvType, MalType, MalType) (EnvType, error)
+ Meta MalType
}
func MalFunc_Q(obj MalType) bool {
- switch obj.(type) {
- case MalFunc: return true
- default: return false
- }
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "MalFunc"
}
func (f MalFunc) SetMacro() MalType {
@@ -102,7 +94,7 @@ func (f MalFunc) GetMacro() bool {
func Apply(f_mt MalType, a []MalType) (MalType, error) {
switch f := f_mt.(type) {
case MalFunc:
- env, e := f.GenEnv(f.Env, f.Params, List{a})
+ env, e := f.GenEnv(f.Env, f.Params, List{a,nil})
if e != nil { return nil, e }
return f.Eval(f.Exp, env)
case func([]MalType)(MalType, error):
@@ -116,29 +108,27 @@ func Apply(f_mt MalType, a []MalType) (MalType, error) {
// Lists
type List struct {
Val []MalType
+ Meta MalType
}
func NewList(a ...MalType) MalType {
- return List{a}
+ return List{a,nil}
}
func List_Q(obj MalType) bool {
- switch obj.(type) {
- case List: return true
- default: return false
- }
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "List"
}
// Vectors
type Vector struct {
Val []MalType
+ Meta MalType
}
func Vector_Q(obj MalType) bool {
- switch obj.(type) {
- case Vector: return true
- default: return false
- }
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "Vector"
}
func GetSlice(seq MalType) ([]MalType, error) {
@@ -150,6 +140,11 @@ func GetSlice(seq MalType) ([]MalType, error) {
}
// Hash Maps
+type HashMap struct {
+ Val map[string]MalType
+ Meta MalType
+}
+
func NewHashMap(seq MalType) (MalType, error) {
lst, e := GetSlice(seq)
if e != nil { return nil, e }
@@ -164,19 +159,37 @@ func NewHashMap(seq MalType) (MalType, error) {
}
m[str] = lst[i+1]
}
- return m, nil
+ return HashMap{m,nil}, nil
}
func HashMap_Q(obj MalType) bool {
+ if obj == nil { return false }
+ return reflect.TypeOf(obj).Name() == "HashMap"
+}
+
+// Atoms
+type Atom struct {
+ Val MalType
+ Meta MalType
+}
+func (a *Atom) Set(val MalType) MalType {
+ a.Val= val
+ return a
+}
+
+func Atom_Q(obj MalType) bool {
switch obj.(type) {
- case map[string]MalType: return true
- default: return false
+ case *Atom: return true
+ default: return false
}
}
+
+
// General functions
func _obj_type(obj MalType) string {
+ if obj == nil { return "nil" }
return reflect.TypeOf(obj).Name()
}
@@ -204,7 +217,7 @@ func Equal_Q(a MalType, b MalType) bool {
if !Equal_Q(as[i], bs[i]) { return false }
}
return true
- case "map[string]MalType":
+ case "HashMap":
return false
default:
return a == b