diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-09 21:37:00 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-10-09 21:37:00 -0500 |
| commit | f2544a9467ea032aff505b3ced3b4b3510a828fe (patch) | |
| tree | aa1984aef01c20b7b093527c28c37bd7d4d803d5 | |
| parent | f2c9811fd8cbb205fad68952ebc1ba5d310f148d (diff) | |
| download | mal-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.go | 104 | ||||
| -rw-r--r-- | go/src/printer/printer.go | 9 | ||||
| -rw-r--r-- | go/src/reader/reader.go | 19 | ||||
| -rw-r--r-- | go/src/step2_eval/step2_eval.go | 14 | ||||
| -rw-r--r-- | go/src/step3_env/step3_env.go | 14 | ||||
| -rw-r--r-- | go/src/step4_if_fn_do/step4_if_fn_do.go | 16 | ||||
| -rw-r--r-- | go/src/step5_tco/step5_tco.go | 18 | ||||
| -rw-r--r-- | go/src/step6_file/step6_file.go | 20 | ||||
| -rw-r--r-- | go/src/step7_quote/step7_quote.go | 26 | ||||
| -rw-r--r-- | go/src/step8_macros/step8_macros.go | 26 | ||||
| -rw-r--r-- | go/src/stepA_more/stepA_more.go | 26 | ||||
| -rw-r--r-- | go/src/types/types.go | 73 |
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 |
