diff options
| author | Joel Martin <github@martintribe.org> | 2015-03-04 10:29:46 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-03-04 10:29:46 -0600 |
| commit | 6cee207674783a1707c3e3c4dcec575112ba1c81 (patch) | |
| tree | 87048f918631dc42828c928b1f87a78e9fbf2b52 | |
| parent | c67c27e6c295200accf3c95c33e9ca5821268e74 (diff) | |
| parent | 9fb199e2cb2cf44cd61c2a226193a70f6013aadc (diff) | |
| download | mal-6cee207674783a1707c3e3c4dcec575112ba1c81.tar.gz mal-6cee207674783a1707c3e3c4dcec575112ba1c81.zip | |
Merge pull request #12 from tebeka/master
Works when ~/.mal-history does not exist
| -rw-r--r-- | go/src/core/core.go | 686 | ||||
| -rw-r--r-- | go/src/env/env.go | 80 | ||||
| -rw-r--r-- | go/src/printer/printer.go | 98 | ||||
| -rw-r--r-- | go/src/reader/reader.go | 298 | ||||
| -rw-r--r-- | go/src/readline/readline.go | 87 | ||||
| -rw-r--r-- | go/src/step0_repl/step0_repl.go | 32 | ||||
| -rw-r--r-- | go/src/step1_read_print/step1_read_print.go | 72 | ||||
| -rw-r--r-- | go/src/step2_eval/step2_eval.go | 211 | ||||
| -rw-r--r-- | go/src/step3_env/step3_env.go | 282 | ||||
| -rw-r--r-- | go/src/step4_if_fn_do/step4_if_fn_do.go | 332 | ||||
| -rw-r--r-- | go/src/step5_tco/step5_tco.go | 348 | ||||
| -rw-r--r-- | go/src/step6_file/step6_file.go | 397 | ||||
| -rw-r--r-- | go/src/step7_quote/step7_quote.go | 453 | ||||
| -rw-r--r-- | go/src/step8_macros/step8_macros.go | 526 | ||||
| -rw-r--r-- | go/src/step9_try/step9_try.go | 576 | ||||
| -rw-r--r-- | go/src/stepA_mal/stepA_mal.go | 580 | ||||
| -rw-r--r-- | go/src/types/types.go | 320 |
17 files changed, 3030 insertions, 2348 deletions
diff --git a/go/src/core/core.go b/go/src/core/core.go index 2acca69..159acc7 100644 --- a/go/src/core/core.go +++ b/go/src/core/core.go @@ -1,380 +1,516 @@ package core import ( - "errors" - "io/ioutil" - "fmt" - "time" + "errors" + "fmt" + "io/ioutil" + "time" ) import ( - . "types" - "reader" - "printer" - "readline" + "printer" + "reader" + "readline" + . "types" ) // Errors/Exceptions func throw(a []MalType) (MalType, error) { - return nil, MalError{a[0]} + return nil, MalError{a[0]} } - // String functions func pr_str(a []MalType) (MalType, error) { - return printer.Pr_list(a, true, "", "", " "), nil + return printer.Pr_list(a, true, "", "", " "), nil } func str(a []MalType) (MalType, error) { - return printer.Pr_list(a, false, "", "", ""), nil + return printer.Pr_list(a, false, "", "", ""), nil } func prn(a []MalType) (MalType, error) { - fmt.Println(printer.Pr_list(a, true, "", "", " ")) - return nil, nil + fmt.Println(printer.Pr_list(a, true, "", "", " ")) + return nil, nil } func println(a []MalType) (MalType, error) { - fmt.Println(printer.Pr_list(a, false, "", "", " ")) - return nil, nil + fmt.Println(printer.Pr_list(a, false, "", "", " ")) + return nil, nil } func slurp(a []MalType) (MalType, error) { - b, e := ioutil.ReadFile(a[0].(string)) - if e != nil { return nil, e } - return string(b), nil + b, e := ioutil.ReadFile(a[0].(string)) + if e != nil { + return nil, e + } + return string(b), nil } // Number functions func time_ms(a []MalType) (MalType, error) { - return int(time.Now().UnixNano() / int64(time.Millisecond)), nil + return int(time.Now().UnixNano() / int64(time.Millisecond)), nil } - // 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 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") } - 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.Val[key.(string)] = a[i+1] - } - return new_hm, nil + 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") + } + 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.Val[key.(string)] = a[i+1] + } + return new_hm, nil } 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") } - 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.Val,key.(string)) - } - return new_hm, nil + 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") + } + 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.Val, key.(string)) + } + return new_hm, nil } func get(a []MalType) (MalType, error) { - if len(a) != 2 { return nil, errors.New("get requires 2 arguments") } - 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].(HashMap).Val[a[1].(string)], nil + if len(a) != 2 { + return nil, errors.New("get requires 2 arguments") + } + 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].(HashMap).Val[a[1].(string)], nil } func contains_Q(hm MalType, key MalType) (MalType, error) { - if Nil_Q(hm) { return false, 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.(HashMap).Val[key.(string)] - return ok, nil + if Nil_Q(hm) { + return false, 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.(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].(HashMap).Val { - slc = append(slc, k) - } - return List{slc,nil}, nil + if !HashMap_Q(a[0]) { + return nil, errors.New("keys called on non-hash map") + } + slc := []MalType{} + for k, _ := range a[0].(HashMap).Val { + slc = append(slc, k) + } + 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].(HashMap).Val { - slc = append(slc, v) - } - return List{slc,nil}, nil + if !HashMap_Q(a[0]) { + return nil, errors.New("keys called on non-hash map") + } + slc := []MalType{} + for _, v := range a[0].(HashMap).Val { + slc = append(slc, v) + } + return List{slc, nil}, nil } - // Sequence functions func cons(a []MalType) (MalType, error) { - val := a[0] - lst, e := GetSlice(a[1]); if e != nil { return nil, e } + val := a[0] + lst, e := GetSlice(a[1]) + if e != nil { + return nil, e + } - return List{append([]MalType{val}, lst...),nil}, nil + return List{append([]MalType{val}, lst...), nil}, nil } func concat(a []MalType) (MalType, error) { - if len(a) == 0 { return List{}, nil } - slc1, e := GetSlice(a[0]); if e != nil { return nil, e } - for i := 1; i < len(a); i+=1 { - slc2, e := GetSlice(a[i]); if e != nil { return nil, e } - slc1 = append(slc1, slc2...) - } - return List{slc1,nil}, nil + if len(a) == 0 { + return List{}, nil + } + slc1, e := GetSlice(a[0]) + if e != nil { + return nil, e + } + for i := 1; i < len(a); i += 1 { + slc2, e := GetSlice(a[i]) + if e != nil { + return nil, e + } + slc1 = append(slc1, slc2...) + } + return List{slc1, nil}, nil } func nth(a []MalType) (MalType, error) { - slc, e := GetSlice(a[0]); if e != nil { return nil, e } - idx := a[1].(int) - if idx < len(slc) { - return slc[idx], nil - } else { - return nil, errors.New("nth: index out of range") - } + slc, e := GetSlice(a[0]) + if e != nil { + return nil, e + } + idx := a[1].(int) + if idx < len(slc) { + return slc[idx], nil + } else { + return nil, errors.New("nth: index out of range") + } } func first(a []MalType) (MalType, error) { - if len(a) == 0 { return nil, nil } - slc, e := GetSlice(a[0]); if e != nil { return nil, e } - if len(slc) == 0 { return nil, nil } - return slc[0], nil + if len(a) == 0 { + return nil, nil + } + slc, e := GetSlice(a[0]) + if e != nil { + return nil, e + } + if len(slc) == 0 { + return nil, nil + } + return slc[0], nil } 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}, nil + slc, e := GetSlice(a[0]) + if e != nil { + return nil, e + } + if len(slc) == 0 { + return List{}, nil + } + return List{slc[1:], nil}, nil } - func empty_Q(a []MalType) (MalType, error) { - switch obj := a[0].(type) { - case List: return len(obj.Val) == 0, nil - case Vector: return len(obj.Val) == 0, nil - case nil: return true, nil - default: return nil, errors.New("Count called on non-sequence") - } + switch obj := a[0].(type) { + case List: + return len(obj.Val) == 0, nil + case Vector: + return len(obj.Val) == 0, nil + case nil: + return true, nil + default: + return nil, errors.New("Count called on non-sequence") + } } func count(a []MalType) (MalType, error) { - switch obj := a[0].(type) { - case List: return len(obj.Val), nil - case Vector: return len(obj.Val), nil - case map[string]MalType: return len(obj), nil - case nil: return 0, nil - default: return nil, errors.New("Count called on non-sequence") - } + switch obj := a[0].(type) { + case List: + return len(obj.Val), nil + case Vector: + return len(obj.Val), nil + case map[string]MalType: + return len(obj), nil + case nil: + return 0, nil + default: + return nil, errors.New("Count called on non-sequence") + } } func apply(a []MalType) (MalType, error) { - if len(a) < 2 { return nil, errors.New("apply requires at least 2 args") } - f := a[0] - args := []MalType{} - for _, b := range a[1:len(a)-1] { - args = append(args, b) - } - last, e := GetSlice(a[len(a)-1]); if e != nil { return nil, e } - args = append(args, last...) - return Apply(f, args) + if len(a) < 2 { + return nil, errors.New("apply requires at least 2 args") + } + f := a[0] + args := []MalType{} + for _, b := range a[1 : len(a)-1] { + args = append(args, b) + } + last, e := GetSlice(a[len(a)-1]) + if e != nil { + return nil, e + } + args = append(args, last...) + return Apply(f, args) } func do_map(a []MalType) (MalType, error) { - if len(a) != 2 { return nil, errors.New("map requires 2 args") } - f := a[0] - results := []MalType{} - args, e := GetSlice(a[1]); if e != nil { return nil, e } - for _, arg := range args { - res, e := Apply(f, []MalType{arg}) - results = append(results, res) - if e != nil { return nil, e } - } - return List{results,nil}, nil + if len(a) != 2 { + return nil, errors.New("map requires 2 args") + } + f := a[0] + results := []MalType{} + args, e := GetSlice(a[1]) + if e != nil { + return nil, e + } + for _, arg := range args { + res, e := Apply(f, []MalType{arg}) + results = append(results, res) + if e != nil { + return nil, e + } + } + return List{results, nil}, nil } func conj(a []MalType) (MalType, error) { - if len(a) <2 { return nil, errors.New("conj requires at least 2 arguments") } - switch seq := a[0].(type) { - case List: - new_slc := []MalType{} - for i := len(a)-1 ; i > 0 ; i-=1 { - new_slc = append(new_slc, a[i]) - } - return List{append(new_slc, seq.Val...),nil}, nil - case Vector: - new_slc := seq.Val - for _, x := range a[1:] { - new_slc = append(new_slc, x) - } - return Vector{new_slc,nil}, nil - } - - if !HashMap_Q(a[0]) { return nil, errors.New("dissoc called on non-hash map") } - 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.Val,key.(string)) - } - return new_hm, nil + if len(a) < 2 { + return nil, errors.New("conj requires at least 2 arguments") + } + switch seq := a[0].(type) { + case List: + new_slc := []MalType{} + for i := len(a) - 1; i > 0; i -= 1 { + new_slc = append(new_slc, a[i]) + } + return List{append(new_slc, seq.Val...), nil}, nil + case Vector: + new_slc := seq.Val + for _, x := range a[1:] { + new_slc = append(new_slc, x) + } + return Vector{new_slc, nil}, nil + } + + if !HashMap_Q(a[0]) { + return nil, errors.New("dissoc called on non-hash map") + } + 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.Val, key.(string)) + } + return new_hm, 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 Func: return Func{tobj.Fn,m}, nil - case MalFunc: fn := tobj; fn.Meta = m; return fn, nil - default: return nil, errors.New("with-meta not supported on type") - } + 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 Func: + return Func{tobj.Fn, 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 Func: return tobj.Meta, nil - case MalFunc: return tobj.Meta, nil - default: return nil, errors.New("meta not supported on type") - } + 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 Func: + 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 + 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 + 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 + 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{ - "=": func(a []MalType) (MalType, error) { - return Equal_Q(a[0], a[1]), nil }, - "throw": throw, - "nil?": func(a []MalType) (MalType, error) { - return Nil_Q(a[0]), nil }, - "true?": func(a []MalType) (MalType, error) { - return True_Q(a[0]), nil }, - "false?": func(a []MalType) (MalType, error) { - return False_Q(a[0]), nil }, - "symbol": func(a []MalType) (MalType, error) { - return Symbol{a[0].(string)}, nil }, - "symbol?": func(a []MalType) (MalType, error) { - return Symbol_Q(a[0]), nil }, - "keyword": func(a []MalType) (MalType, error) { - return NewKeyword(a[0].(string)) }, - "keyword?": func(a []MalType) (MalType, error) { - return Keyword_Q(a[0]), nil }, - - "pr-str": func(a []MalType) (MalType, error) { return pr_str(a) }, - "str": func(a []MalType) (MalType, error) { return str(a) }, - "prn": func(a []MalType) (MalType, error) { return prn(a) }, - "println": func(a []MalType) (MalType, error) { return println(a) }, - "read-string": func(a []MalType) (MalType, error) { - return reader.Read_str(a[0].(string)) }, - "slurp": slurp, - "readline": func(a []MalType) (MalType, error) { - return readline.Readline(a[0].(string)) }, - - "<": func(a []MalType) (MalType, error) { - return a[0].(int) < a[1].(int), nil }, - "<=": func(a []MalType) (MalType, error) { - return a[0].(int) <= a[1].(int), nil }, - ">": func(a []MalType) (MalType, error) { - return a[0].(int) > a[1].(int), nil }, - ">=": func(a []MalType) (MalType, error) { - return a[0].(int) >= a[1].(int), nil }, - "+": func(a []MalType) (MalType, error) { - return a[0].(int) + a[1].(int), nil }, - "-": func(a []MalType) (MalType, error) { - return a[0].(int) - a[1].(int), nil }, - "*": func(a []MalType) (MalType, error) { - return a[0].(int) * a[1].(int), nil }, - "/": func(a []MalType) (MalType, error) { - return a[0].(int) / a[1].(int), nil }, - "time-ms": time_ms, - - "list": func(a []MalType) (MalType, error) { - 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}, nil }, - "vector?": func(a []MalType) (MalType, error) { - return Vector_Q(a[0]), nil }, - "hash-map": func(a []MalType) (MalType, error) { - return NewHashMap(List{a,nil}) }, - "map?": func(a []MalType) (MalType, error) { - return HashMap_Q(a[0]), nil }, - "assoc": assoc, - "dissoc": dissoc, - "get": get, - "contains?": func(a []MalType) (MalType, error) { - return contains_Q(a[0], a[1]) }, - "keys": keys, - "vals": vals, - - "sequential?": func(a []MalType) (MalType, error) { - return Sequential_Q(a[0]), nil }, - "cons": cons, - "concat": concat, - "nth": nth, - "first": first, - "rest": rest, - "empty?": empty_Q, - "count": count, - "apply": apply, - "map": do_map, - "conj": conj, - - "with-meta": with_meta, - "meta": meta, - "atom": func(a []MalType) (MalType, error) { - return &Atom{a[0],nil}, nil }, - "atom?": func(a []MalType) (MalType, error) { - return Atom_Q(a[0]), nil }, - "deref": deref, - "reset!": reset_BANG, - "swap!": swap_BANG, - } + "=": func(a []MalType) (MalType, error) { + return Equal_Q(a[0], a[1]), nil + }, + "throw": throw, + "nil?": func(a []MalType) (MalType, error) { + return Nil_Q(a[0]), nil + }, + "true?": func(a []MalType) (MalType, error) { + return True_Q(a[0]), nil + }, + "false?": func(a []MalType) (MalType, error) { + return False_Q(a[0]), nil + }, + "symbol": func(a []MalType) (MalType, error) { + return Symbol{a[0].(string)}, nil + }, + "symbol?": func(a []MalType) (MalType, error) { + return Symbol_Q(a[0]), nil + }, + "keyword": func(a []MalType) (MalType, error) { + return NewKeyword(a[0].(string)) + }, + "keyword?": func(a []MalType) (MalType, error) { + return Keyword_Q(a[0]), nil + }, + + "pr-str": func(a []MalType) (MalType, error) { return pr_str(a) }, + "str": func(a []MalType) (MalType, error) { return str(a) }, + "prn": func(a []MalType) (MalType, error) { return prn(a) }, + "println": func(a []MalType) (MalType, error) { return println(a) }, + "read-string": func(a []MalType) (MalType, error) { + return reader.Read_str(a[0].(string)) + }, + "slurp": slurp, + "readline": func(a []MalType) (MalType, error) { + return readline.Readline(a[0].(string)) + }, + + "<": func(a []MalType) (MalType, error) { + return a[0].(int) < a[1].(int), nil + }, + "<=": func(a []MalType) (MalType, error) { + return a[0].(int) <= a[1].(int), nil + }, + ">": func(a []MalType) (MalType, error) { + return a[0].(int) > a[1].(int), nil + }, + ">=": func(a []MalType) (MalType, error) { + return a[0].(int) >= a[1].(int), nil + }, + "+": func(a []MalType) (MalType, error) { + return a[0].(int) + a[1].(int), nil + }, + "-": func(a []MalType) (MalType, error) { + return a[0].(int) - a[1].(int), nil + }, + "*": func(a []MalType) (MalType, error) { + return a[0].(int) * a[1].(int), nil + }, + "/": func(a []MalType) (MalType, error) { + return a[0].(int) / a[1].(int), nil + }, + "time-ms": time_ms, + + "list": func(a []MalType) (MalType, error) { + 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}, nil + }, + "vector?": func(a []MalType) (MalType, error) { + return Vector_Q(a[0]), nil + }, + "hash-map": func(a []MalType) (MalType, error) { + return NewHashMap(List{a, nil}) + }, + "map?": func(a []MalType) (MalType, error) { + return HashMap_Q(a[0]), nil + }, + "assoc": assoc, + "dissoc": dissoc, + "get": get, + "contains?": func(a []MalType) (MalType, error) { + return contains_Q(a[0], a[1]) + }, + "keys": keys, + "vals": vals, + + "sequential?": func(a []MalType) (MalType, error) { + return Sequential_Q(a[0]), nil + }, + "cons": cons, + "concat": concat, + "nth": nth, + "first": first, + "rest": rest, + "empty?": empty_Q, + "count": count, + "apply": apply, + "map": do_map, + "conj": conj, + + "with-meta": with_meta, + "meta": meta, + "atom": func(a []MalType) (MalType, error) { + return &Atom{a[0], nil}, nil + }, + "atom?": func(a []MalType) (MalType, error) { + return Atom_Q(a[0]), nil + }, + "deref": deref, + "reset!": reset_BANG, + "swap!": swap_BANG, +} diff --git a/go/src/env/env.go b/go/src/env/env.go index 584c9a7..88098fc 100644 --- a/go/src/env/env.go +++ b/go/src/env/env.go @@ -1,59 +1,65 @@ package env import ( - "errors" - //"fmt" + "errors" + //"fmt" ) import ( - . "types" + . "types" ) type Env struct { - data map[string]MalType - outer EnvType + data map[string]MalType + outer EnvType } func NewEnv(outer EnvType, binds_mt MalType, exprs_mt MalType) (EnvType, error) { - env := Env{map[string]MalType{}, outer} - - if binds_mt != nil && exprs_mt != nil { - binds, e := GetSlice(binds_mt); if e != nil { return nil, e } - exprs, e := GetSlice(exprs_mt); if e != nil { return nil, e } - // Return a new Env with symbols in binds boudn to - // corresponding values in exprs - for i := 0; i < len(binds); i+=1 { - if (Symbol_Q(binds[i]) && binds[i].(Symbol).Val == "&") { - env.data[binds[i+1].(Symbol).Val] = List{exprs[i:],nil} - break - } else { - env.data[binds[i].(Symbol).Val] = exprs[i] - } - } - } - //return &et, nil - return env, nil + env := Env{map[string]MalType{}, outer} + + if binds_mt != nil && exprs_mt != nil { + binds, e := GetSlice(binds_mt) + if e != nil { + return nil, e + } + exprs, e := GetSlice(exprs_mt) + if e != nil { + return nil, e + } + // Return a new Env with symbols in binds boudn to + // corresponding values in exprs + for i := 0; i < len(binds); i += 1 { + if Symbol_Q(binds[i]) && binds[i].(Symbol).Val == "&" { + env.data[binds[i+1].(Symbol).Val] = List{exprs[i:], nil} + break + } else { + env.data[binds[i].(Symbol).Val] = exprs[i] + } + } + } + //return &et, nil + return env, nil } func (e Env) Find(key Symbol) EnvType { - if _, ok := e.data[key.Val]; ok { - return e - } else if (e.outer != nil) { - return e.outer.Find(key) - } else { - return nil - } + if _, ok := e.data[key.Val]; ok { + return e + } else if e.outer != nil { + return e.outer.Find(key) + } else { + return nil + } } func (e Env) Set(key Symbol, value MalType) MalType { - e.data[key.Val] = value - return value + e.data[key.Val] = value + return value } func (e Env) Get(key Symbol) (MalType, error) { - env := e.Find(key) - if env == nil { - return nil, errors.New("'" + key.Val + "' not found") - } - return env.(Env).data[key.Val], nil + env := e.Find(key) + if env == nil { + return nil, errors.New("'" + key.Val + "' not found") + } + return env.(Env).data[key.Val], nil } diff --git a/go/src/printer/printer.go b/go/src/printer/printer.go index 1b8e9fe..016e65f 100644 --- a/go/src/printer/printer.go +++ b/go/src/printer/printer.go @@ -1,62 +1,62 @@ package printer import ( - "fmt" - "strings" + "fmt" + "strings" ) import ( - "types" + "types" ) func Pr_list(lst []types.MalType, pr bool, - start string, end string, join string) string { - str_list := make([]string, 0, len(lst)) - for _, e := range lst { - str_list = append(str_list, Pr_str(e, pr)) - } - return start + strings.Join(str_list, join) + end + start string, end string, join string) string { + str_list := make([]string, 0, len(lst)) + for _, e := range lst { + str_list = append(str_list, Pr_str(e, pr)) + } + return start + strings.Join(str_list, join) + end } func Pr_str(obj types.MalType, print_readably bool) string { - switch tobj := obj.(type) { - case types.List: - return Pr_list(tobj.Val, print_readably, "(", ")", " ") - case types.Vector: - return Pr_list(tobj.Val, print_readably, "[", "]", " ") - 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)) - } - return "{" + strings.Join(str_list, " ") + "}" - case string: - if strings.HasPrefix(tobj, "\u029e") { - return ":" + tobj[2:len(tobj)] - } else if print_readably { - return `"` + strings.Replace( - strings.Replace( - strings.Replace(tobj,`\`,`\\`, -1), - `"`, `\"`, -1), - "\n", `\n`, -1) + `"` - } else { - return tobj - } - case types.Symbol: - return tobj.Val - case nil: - return "nil" - case types.MalFunc: - return "(fn* " + - Pr_str(tobj.Params, true) + " " + - 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) - } + switch tobj := obj.(type) { + case types.List: + return Pr_list(tobj.Val, print_readably, "(", ")", " ") + case types.Vector: + return Pr_list(tobj.Val, print_readably, "[", "]", " ") + 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)) + } + return "{" + strings.Join(str_list, " ") + "}" + case string: + if strings.HasPrefix(tobj, "\u029e") { + return ":" + tobj[2:len(tobj)] + } else if print_readably { + return `"` + strings.Replace( + strings.Replace( + strings.Replace(tobj, `\`, `\\`, -1), + `"`, `\"`, -1), + "\n", `\n`, -1) + `"` + } else { + return tobj + } + case types.Symbol: + return tobj.Val + case nil: + return "nil" + case types.MalFunc: + return "(fn* " + + Pr_str(tobj.Params, true) + " " + + 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 9cacb8b..ee64f56 100644 --- a/go/src/reader/reader.go +++ b/go/src/reader/reader.go @@ -1,162 +1,216 @@ package reader import ( - "errors" - "regexp" - "strconv" - "strings" - //"fmt" + "errors" + "regexp" + "strconv" + "strings" + //"fmt" ) import ( - . "types" + . "types" ) type Reader interface { - next() *string - peek() *string + next() *string + peek() *string } type TokenReader struct { - tokens []string - position int + tokens []string + position int } func (tr *TokenReader) next() *string { - if tr.position >= len(tr.tokens) { return nil } - token := tr.tokens[tr.position] - tr.position = tr.position + 1 - return &token + if tr.position >= len(tr.tokens) { + return nil + } + token := tr.tokens[tr.position] + tr.position = tr.position + 1 + return &token } func (tr *TokenReader) peek() *string { - if tr.position >= len(tr.tokens) { return nil } - return &tr.tokens[tr.position] + if tr.position >= len(tr.tokens) { + return nil + } + return &tr.tokens[tr.position] } - - -func tokenize (str string) []string { - results := make([]string, 0, 1) - // Work around lack of quoting in backtick - re := regexp.MustCompile(`[\s,]*(~@|[\[\]{}()'` + "`" + - `~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"` + "`" + - `,;)]*)`) - for _, group := range re.FindAllStringSubmatch(str, -1) { - if (group[1] == "") || (group[1][0] == ';') { continue } - results = append(results, group[1]) - } - return results +func tokenize(str string) []string { + results := make([]string, 0, 1) + // Work around lack of quoting in backtick + re := regexp.MustCompile(`[\s,]*(~@|[\[\]{}()'` + "`" + + `~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"` + "`" + + `,;)]*)`) + for _, group := range re.FindAllStringSubmatch(str, -1) { + if (group[1] == "") || (group[1][0] == ';') { + continue + } + results = append(results, group[1]) + } + return results } func read_atom(rdr Reader) (MalType, error) { - token := rdr.next() - if token == nil { return nil, errors.New("read_atom underflow") } - if match, _ := regexp.MatchString(`^-?[0-9]+$`, *token); match { - var i int - var e error - if i, e = strconv.Atoi(*token); e != nil { - return nil, errors.New("number parse error") - } - return i, nil - } else if (*token)[0] == '"' { - str := (*token)[1:len(*token)-1] - return strings.Replace( - strings.Replace(str, `\"`, `"`, -1), - `\n`, "\n", -1), nil - } else if (*token)[0] == ':' { - return NewKeyword((*token)[1:len(*token)]) - } else if *token == "nil" { - return nil, nil - } else if *token == "true" { - return true, nil - } else if *token == "false" { - return false, nil - } else { - return Symbol{*token}, nil - } - return token, nil + token := rdr.next() + if token == nil { + return nil, errors.New("read_atom underflow") + } + if match, _ := regexp.MatchString(`^-?[0-9]+$`, *token); match { + var i int + var e error + if i, e = strconv.Atoi(*token); e != nil { + return nil, errors.New("number parse error") + } + return i, nil + } else if (*token)[0] == '"' { + str := (*token)[1 : len(*token)-1] + return strings.Replace( + strings.Replace(str, `\"`, `"`, -1), + `\n`, "\n", -1), nil + } else if (*token)[0] == ':' { + return NewKeyword((*token)[1:len(*token)]) + } else if *token == "nil" { + return nil, nil + } else if *token == "true" { + return true, nil + } else if *token == "false" { + return false, nil + } else { + return Symbol{*token}, nil + } + return token, nil } func read_list(rdr Reader, start string, end string) (MalType, error) { - token := rdr.next() - if token == nil { return nil, errors.New("read_list underflow") } - if *token != start { - return nil, errors.New("expected '" + start + "'") - } - - ast_list := []MalType{} - token = rdr.peek() - for ; true ; token = rdr.peek() { - if token == nil { return nil, errors.New("exepected '" + end + "', got EOF") } - if *token == end { break } - f, e := read_form(rdr) - if e != nil { return nil, e } - ast_list = append(ast_list, f) - } - rdr.next() - return List{ast_list,nil}, nil + token := rdr.next() + if token == nil { + return nil, errors.New("read_list underflow") + } + if *token != start { + return nil, errors.New("expected '" + start + "'") + } + + ast_list := []MalType{} + token = rdr.peek() + for ; true; token = rdr.peek() { + if token == nil { + return nil, errors.New("exepected '" + end + "', got EOF") + } + if *token == end { + break + } + f, e := read_form(rdr) + if e != nil { + return nil, e + } + ast_list = append(ast_list, f) + } + rdr.next() + 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,nil} - return vec, nil + lst, e := read_list(rdr, "[", "]") + if e != nil { + return nil, e + } + vec := Vector{lst.(List).Val, nil} + return vec, nil } func read_hash_map(rdr Reader) (MalType, error) { - mal_lst, e := read_list(rdr, "{", "}") - if e != nil { return nil, e } - return NewHashMap(mal_lst) + mal_lst, e := read_list(rdr, "{", "}") + if e != nil { + return nil, e + } + return NewHashMap(mal_lst) } func read_form(rdr Reader) (MalType, error) { - token := rdr.peek() - if token == nil { return nil, errors.New("read_form underflow") } - switch (*token) { - - case `'`: rdr.next(); - form, e := read_form(rdr); if e != nil { return nil, e } - 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}, nil - case `~`: rdr.next(); - form, e := read_form(rdr); if e != nil { return nil, e } - 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}, 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 ')'") - case "(": return read_list(rdr, "(", ")") - - // vector - case "]": return nil, errors.New("unexpected ']'") - case "[": return read_vector(rdr) - - // hash-map - case "}": return nil, errors.New("unexpected '}'") - case "{": return read_hash_map(rdr) - default: return read_atom(rdr) - } - return read_atom(rdr) + token := rdr.peek() + if token == nil { + return nil, errors.New("read_form underflow") + } + switch *token { + + case `'`: + rdr.next() + form, e := read_form(rdr) + if e != nil { + return nil, e + } + 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}, nil + case `~`: + rdr.next() + form, e := read_form(rdr) + if e != nil { + return nil, e + } + 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}, 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 ')'") + case "(": + return read_list(rdr, "(", ")") + + // vector + case "]": + return nil, errors.New("unexpected ']'") + case "[": + return read_vector(rdr) + + // hash-map + case "}": + return nil, errors.New("unexpected '}'") + case "{": + return read_hash_map(rdr) + default: + return read_atom(rdr) + } + return read_atom(rdr) } func Read_str(str string) (MalType, error) { - var tokens = tokenize(str); - if len(tokens) == 0 { - return nil, errors.New("<empty line>") - } + var tokens = tokenize(str) + if len(tokens) == 0 { + return nil, errors.New("<empty line>") + } - return read_form(&TokenReader{tokens: tokens, position: 0}) + return read_form(&TokenReader{tokens: tokens, position: 0}) } diff --git a/go/src/readline/readline.go b/go/src/readline/readline.go index 2777cb4..31c1fbb 100644 --- a/go/src/readline/readline.go +++ b/go/src/readline/readline.go @@ -8,6 +8,7 @@ package readline // free() #include <stdlib.h> // readline() +#include <stdio.h> // FILE * #include <readline/readline.h> // add_history() #include <readline/history.h> @@ -15,56 +16,64 @@ package readline import "C" import ( - "errors" - "unsafe" - "strings" - "io/ioutil" - "os" - "path/filepath" - "fmt" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "unsafe" ) var HISTORY_FILE = ".mal-history" +var history_path string -var rl_history_loaded = false +func loadHistory(filename string) error { + content, err := ioutil.ReadFile(history_path) + if err != nil { + return err + } -func Readline(prompt string) (string, error) { - history_path := filepath.Join(os.Getenv("HOME"), "/", HISTORY_FILE) - - if !rl_history_loaded { - rl_history_loaded = true - content, e := ioutil.ReadFile(history_path) - if e != nil { return "", e } + for _, add_line := range strings.Split(string(content), "\n") { + if add_line == "" { + continue + } + c_add_line := C.CString(add_line) + C.add_history(c_add_line) + C.free(unsafe.Pointer(c_add_line)) + } - for _, add_line := range strings.Split(string(content), "\n") { - if add_line == "" { continue } - c_add_line := C.CString(add_line) - C.add_history(c_add_line) - C.free(unsafe.Pointer(c_add_line)) - } - } + return nil +} +func init() { + history_path = filepath.Join(os.Getenv("HOME"), HISTORY_FILE) + loadHistory(history_path) +} - c_prompt := C.CString(prompt) - defer C.free(unsafe.Pointer(c_prompt)) +func Readline(prompt string) (string, error) { + c_prompt := C.CString(prompt) + defer C.free(unsafe.Pointer(c_prompt)) - c_line := C.readline(c_prompt) - defer C.free(unsafe.Pointer(c_line)) - line := C.GoString(c_line) + c_line := C.readline(c_prompt) + defer C.free(unsafe.Pointer(c_line)) + line := C.GoString(c_line) - if c_line == nil { - return "", errors.New("C.readline call failed") - } - C.add_history(c_line) + if c_line == nil { + return "", errors.New("C.readline call failed") + } + C.add_history(c_line) - // append to file - f, e := os.OpenFile(history_path, os.O_APPEND|os.O_WRONLY, 0600) - if e == nil { - defer f.Close() + // append to file + f, e := os.OpenFile(history_path, os.O_APPEND|os.O_WRONLY, 0600) + if e == nil { + defer f.Close() - _, e = f.WriteString(line+"\n") - if e != nil { fmt.Printf("error writing to history") } - } + _, e = f.WriteString(line + "\n") + if e != nil { + fmt.Printf("error writing to history") + } + } - return line, nil + return line, nil } diff --git a/go/src/step0_repl/step0_repl.go b/go/src/step0_repl/step0_repl.go index 2e4c47c..644a087 100644 --- a/go/src/step0_repl/step0_repl.go +++ b/go/src/step0_repl/step0_repl.go @@ -1,42 +1,42 @@ package main import ( - "fmt" - "strings" + "fmt" + "strings" ) import ( - "readline" + "readline" ) // read func READ(str string) string { - return str + return str } // eval func EVAL(ast string, env string) string { - return ast + return ast } // print func PRINT(exp string) string { - return exp + return exp } // repl func rep(str string) string { - return PRINT(EVAL(READ(str), "")) + return PRINT(EVAL(READ(str), "")) } func main() { - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - fmt.Println(rep(text)) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + fmt.Println(rep(text)) + } } diff --git a/go/src/step1_read_print/step1_read_print.go b/go/src/step1_read_print/step1_read_print.go index e008ed5..f4c4115 100644 --- a/go/src/step1_read_print/step1_read_print.go +++ b/go/src/step1_read_print/step1_read_print.go @@ -1,58 +1,66 @@ package main import ( - "fmt" - "strings" + "fmt" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func EVAL(ast MalType, env string) (MalType, error) { - return ast, nil + return ast, nil } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, ""); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, ""); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step2_eval/step2_eval.go b/go/src/step2_eval/step2_eval.go index 7a9a33f..246c4cf 100644 --- a/go/src/step2_eval/step2_eval.go +++ b/go/src/step2_eval/step2_eval.go @@ -1,127 +1,150 @@ package main import ( - "fmt" - "strings" - "errors" + "errors" + "fmt" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func eval_ast(ast MalType, env map[string]MalType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - k := ast.(Symbol).Val - exp, ok := env[k] - if !ok { return nil, errors.New("'" + k + "' not found") } - return exp, nil - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + k := ast.(Symbol).Val + exp, ok := env[k] + if !ok { + return nil, errors.New("'" + k + "' not found") + } + return exp, nil + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env map[string]MalType) (MalType, error) { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f, ok := el.(List).Val[0].(func([]MalType)(MalType, error)) - if !ok { return nil, errors.New("attempt to call non-function") } - return f(el.(List).Val[1:]) + // apply list + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f, ok := el.(List).Val[0].(func([]MalType) (MalType, error)) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return f(el.(List).Val[1:]) } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } var repl_env = map[string]MalType{ - "+": func(a []MalType) (MalType, error) { - return a[0].(int) + a[1].(int), nil - }, - "-": func(a []MalType) (MalType, error) { - return a[0].(int) - a[1].(int), nil - }, - "*": func(a []MalType) (MalType, error) { - return a[0].(int) * a[1].(int), nil - }, - "/": func(a []MalType) (MalType, error) { - return a[0].(int) / a[1].(int), nil - }, + "+": func(a []MalType) (MalType, error) { + return a[0].(int) + a[1].(int), nil + }, + "-": func(a []MalType) (MalType, error) { + return a[0].(int) - a[1].(int), nil + }, + "*": func(a []MalType) (MalType, error) { + return a[0].(int) * a[1].(int), nil + }, + "/": func(a []MalType) (MalType, error) { + return a[0].(int) / a[1].(int), nil + }, } // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step3_env/step3_env.go b/go/src/step3_env/step3_env.go index 0c45bf2..6a91701 100644 --- a/go/src/step3_env/step3_env.go +++ b/go/src/step3_env/step3_env.go @@ -1,155 +1,193 @@ package main import ( - "fmt" - "strings" - "errors" + "errors" + "fmt" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - return EVAL(a2, let_env) - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f, ok := el.(List).Val[0].(func([]MalType)(MalType, error)) - if !ok { return nil, errors.New("attempt to call non-function") } - return f(el.(List).Val[1:]) - } + // apply list + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + return EVAL(a2, let_env) + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f, ok := el.(List).Val[0].(func([]MalType) (MalType, error)) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return f(el.(List).Val[1:]) + } } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - repl_env.Set(Symbol{"+"}, func(a []MalType) (MalType, error) { - return a[0].(int) + a[1].(int), nil }) - repl_env.Set(Symbol{"-"}, func(a []MalType) (MalType, error) { - return a[0].(int) - a[1].(int), nil }) - repl_env.Set(Symbol{"*"}, func(a []MalType) (MalType, error) { - return a[0].(int) * a[1].(int), nil }) - repl_env.Set(Symbol{"/"}, func(a []MalType) (MalType, error) { - return a[0].(int) / a[1].(int), nil }) + repl_env.Set(Symbol{"+"}, func(a []MalType) (MalType, error) { + return a[0].(int) + a[1].(int), nil + }) + repl_env.Set(Symbol{"-"}, func(a []MalType) (MalType, error) { + return a[0].(int) - a[1].(int), nil + }) + repl_env.Set(Symbol{"*"}, func(a []MalType) (MalType, error) { + return a[0].(int) * a[1].(int), nil + }) + repl_env.Set(Symbol{"/"}, func(a []MalType) (MalType, error) { + return a[0].(int) / a[1].(int), nil + }) - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } 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 d90a720..2e6d60d 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 @@ -1,179 +1,221 @@ package main import ( - "fmt" - "strings" - "errors" + "errors" + "fmt" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - return EVAL(a2, let_env) - case "do": - 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 } - return lst[len(lst)-1], nil - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - return EVAL(ast.(List).Val[3], env) - } else { - return nil, nil - } - } else { - return EVAL(a2, env) - } - case "fn*": - return func(arguments []MalType) (MalType, error) { - new_env, e := NewEnv(env, a1, List{arguments,nil}) - if e != nil { return nil, e } - return EVAL(a2, new_env) - }, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f, ok := el.(List).Val[0].(func([]MalType)(MalType, error)) - if !ok { return nil, errors.New("attempt to call non-function") } - return f(el.(List).Val[1:]) - } + // apply list + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + return EVAL(a2, let_env) + case "do": + 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 + } + return lst[len(lst)-1], nil + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + return EVAL(ast.(List).Val[3], env) + } else { + return nil, nil + } + } else { + return EVAL(a2, env) + } + case "fn*": + return func(arguments []MalType) (MalType, error) { + new_env, e := NewEnv(env, a1, List{arguments, nil}) + if e != nil { + return nil, e + } + return EVAL(a2, new_env) + }, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f, ok := el.(List).Val[0].(func([]MalType) (MalType, error)) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return f(el.(List).Val[1:]) + } } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, v) - } + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, v) + } - // core.mal: defined using the language itself - rep("(def! not (fn* (a) (if a false true)))") + // core.mal: defined using the language itself + rep("(def! not (fn* (a) (if a false true)))") - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step5_tco/step5_tco.go b/go/src/step5_tco/step5_tco.go index 8c6ff37..81b7ebd 100644 --- a/go/src/step5_tco/step5_tco.go +++ b/go/src/step5_tco/step5_tco.go @@ -1,189 +1,231 @@ package main import ( - "fmt" - "strings" - "errors" + "errors" + "fmt" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - for { + for { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } + // apply list + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } - } // TCO loop + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } - // core.mal: defined using the language itself - rep("(def! not (fn* (a) (if a false true)))") + // core.mal: defined using the language itself + rep("(def! not (fn* (a) (if a false true)))") - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step6_file/step6_file.go b/go/src/step6_file/step6_file.go index 701ac47..d0624d0 100644 --- a/go/src/step6_file/step6_file.go +++ b/go/src/step6_file/step6_file.go @@ -1,208 +1,251 @@ package main import ( - "fmt" - "strings" - "errors" - "os" + "errors" + "fmt" + "os" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - for { - - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } - - // apply list - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } - - } // TCO loop + for { + + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } + + // apply list + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } + + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) },nil}) - repl_env.Set(Symbol{"*ARGV*"}, List{}) - - // core.mal: defined using the language itself - rep("(def! not (fn* (a) (if a false true)))") - rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") - - // called with mal script to load and eval - if len(os.Args) > 1 { - args := make([]MalType, 0, len(os.Args)-2) - for _,a := range os.Args[2:] { - args = append(args, a) - } - repl_env.Set(Symbol{"*ARGV*"}, List{args,nil}) - if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { - fmt.Printf("Error: %v\n", e) - os.Exit(1) - } - os.Exit(0) - } - - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } + repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) + }, nil}) + repl_env.Set(Symbol{"*ARGV*"}, List{}) + + // core.mal: defined using the language itself + rep("(def! not (fn* (a) (if a false true)))") + rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") + + // called with mal script to load and eval + if len(os.Args) > 1 { + args := make([]MalType, 0, len(os.Args)-2) + for _, a := range os.Args[2:] { + args = append(args, a) + } + repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + if _, e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } + os.Exit(0) + } + + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step7_quote/step7_quote.go b/go/src/step7_quote/step7_quote.go index d93f620..5260eb5 100644 --- a/go/src/step7_quote/step7_quote.go +++ b/go/src/step7_quote/step7_quote.go @@ -1,241 +1,286 @@ package main import ( - "fmt" - "strings" - "errors" - "os" + "errors" + "fmt" + "os" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func is_pair(x MalType) bool { - slc, e := GetSlice(x) - if e != nil { return false } - return len(slc) > 0 + slc, e := GetSlice(x) + if e != nil { + return false + } + return len(slc) > 0 } func quasiquote(ast MalType) MalType { - if !is_pair(ast) { - return List{[]MalType{Symbol{"quote"}, ast},nil} - } else { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { - return slc[1] - } else if is_pair(a0) { - slc0, _ := GetSlice(a0) - a00 := slc0[0] - if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { - return List{[]MalType{Symbol{"concat"}, - slc0[1], - quasiquote(List{slc[1:],nil})},nil} - } - } - return List{[]MalType{Symbol{"cons"}, - quasiquote(a0), - quasiquote(List{slc[1:],nil})},nil} - } + if !is_pair(ast) { + return List{[]MalType{Symbol{"quote"}, ast}, nil} + } else { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { + return slc[1] + } else if is_pair(a0) { + slc0, _ := GetSlice(a0) + a00 := slc0[0] + if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { + return List{[]MalType{Symbol{"concat"}, + slc0[1], + quasiquote(List{slc[1:], nil})}, nil} + } + } + return List{[]MalType{Symbol{"cons"}, + quasiquote(a0), + quasiquote(List{slc[1:], nil})}, nil} + } } func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - for { - - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } - - // apply list - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "quote": - return a1, nil - case "quasiquote": - ast = quasiquote(a1) - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } - - } // TCO loop + for { + + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } + + // apply list + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "quote": + return a1, nil + case "quasiquote": + ast = quasiquote(a1) + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } + + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) },nil}) - repl_env.Set(Symbol{"*ARGV*"}, List{}) - - // core.mal: defined using the language itself - rep("(def! not (fn* (a) (if a false true)))") - rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") - - // called with mal script to load and eval - if len(os.Args) > 1 { - args := make([]MalType, 0, len(os.Args)-2) - for _,a := range os.Args[2:] { - args = append(args, a) - } - repl_env.Set(Symbol{"*ARGV*"}, List{args,nil}) - if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { - fmt.Printf("Error: %v\n", e) - os.Exit(1) - } - os.Exit(0) - } - - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } + repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) + }, nil}) + repl_env.Set(Symbol{"*ARGV*"}, List{}) + + // core.mal: defined using the language itself + rep("(def! not (fn* (a) (if a false true)))") + rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") + + // called with mal script to load and eval + if len(os.Args) > 1 { + args := make([]MalType, 0, len(os.Args)-2) + for _, a := range os.Args[2:] { + args = append(args, a) + } + repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + if _, e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } + os.Exit(0) + } + + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step8_macros/step8_macros.go b/go/src/step8_macros/step8_macros.go index 86db33b..cbada3b 100644 --- a/go/src/step8_macros/step8_macros.go +++ b/go/src/step8_macros/step8_macros.go @@ -1,282 +1,342 @@ package main import ( - "fmt" - "strings" - "errors" - "os" + "errors" + "fmt" + "os" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func is_pair(x MalType) bool { - slc, e := GetSlice(x) - if e != nil { return false } - return len(slc) > 0 + slc, e := GetSlice(x) + if e != nil { + return false + } + return len(slc) > 0 } func quasiquote(ast MalType) MalType { - if !is_pair(ast) { - return List{[]MalType{Symbol{"quote"}, ast},nil} - } else { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { - return slc[1] - } else if is_pair(a0) { - slc0, _ := GetSlice(a0) - a00 := slc0[0] - if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { - return List{[]MalType{Symbol{"concat"}, - slc0[1], - quasiquote(List{slc[1:],nil})},nil} - } - } - return List{[]MalType{Symbol{"cons"}, - quasiquote(a0), - quasiquote(List{slc[1:],nil})},nil} - } + if !is_pair(ast) { + return List{[]MalType{Symbol{"quote"}, ast}, nil} + } else { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { + return slc[1] + } else if is_pair(a0) { + slc0, _ := GetSlice(a0) + a00 := slc0[0] + if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { + return List{[]MalType{Symbol{"concat"}, + slc0[1], + quasiquote(List{slc[1:], nil})}, nil} + } + } + return List{[]MalType{Symbol{"cons"}, + quasiquote(a0), + quasiquote(List{slc[1:], nil})}, nil} + } } func is_macro_call(ast MalType, env EnvType) bool { - if List_Q(ast) { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { - mac, e := env.Get(a0.(Symbol)) - if e != nil { return false } - if MalFunc_Q(mac) { - return mac.(MalFunc).GetMacro() - } - } - } - return false + if List_Q(ast) { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { + mac, e := env.Get(a0.(Symbol)) + if e != nil { + return false + } + if MalFunc_Q(mac) { + return mac.(MalFunc).GetMacro() + } + } + } + return false } -func macroexpand(ast MalType, env EnvType) (MalType, error) { - var mac MalType - var e error - for ; is_macro_call(ast, env) ; { - slc, _ := GetSlice(ast) - a0 := slc[0] - mac, e = env.Get(a0.(Symbol)); if e != nil { return nil, e } - fn := mac.(MalFunc) - ast, e = Apply(fn, slc[1:]); if e != nil { return nil, e } - } - return ast, nil +func macroexpand(ast MalType, env EnvType) (MalType, error) { + var mac MalType + var e error + for is_macro_call(ast, env) { + slc, _ := GetSlice(ast) + a0 := slc[0] + mac, e = env.Get(a0.(Symbol)) + if e != nil { + return nil, e + } + fn := mac.(MalFunc) + ast, e = Apply(fn, slc[1:]) + if e != nil { + return nil, e + } + } + return ast, nil } func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - var e error - for { + var e error + for { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - ast, e = macroexpand(ast, env); if e != nil { return nil, e } - if (!List_Q(ast)) { return ast, nil } + // apply list + ast, e = macroexpand(ast, env) + if e != nil { + return nil, e + } + if !List_Q(ast) { + return ast, nil + } - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "quote": - return a1, nil - case "quasiquote": - ast = quasiquote(a1) - case "defmacro!": - fn, e := EVAL(a2, env) - fn = fn.(MalFunc).SetMacro() - if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil - case "macroexpand": - return macroexpand(a1, env) - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "quote": + return a1, nil + case "quasiquote": + ast = quasiquote(a1) + case "defmacro!": + fn, e := EVAL(a2, env) + fn = fn.(MalFunc).SetMacro() + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), fn), nil + case "macroexpand": + return macroexpand(a1, env) + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } - } // TCO loop + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) },nil}) - repl_env.Set(Symbol{"*ARGV*"}, List{}) + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } + repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) + }, nil}) + repl_env.Set(Symbol{"*ARGV*"}, List{}) - // core.mal: defined using the language itself - 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))))))))") + // core.mal: defined using the language itself + 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))))))))") - // called with mal script to load and eval - if len(os.Args) > 1 { - args := make([]MalType, 0, len(os.Args)-2) - for _,a := range os.Args[2:] { - args = append(args, a) - } - repl_env.Set(Symbol{"*ARGV*"}, List{args,nil}) - if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { - fmt.Printf("Error: %v\n", e) - os.Exit(1) - } - os.Exit(0) - } + // called with mal script to load and eval + if len(os.Args) > 1 { + args := make([]MalType, 0, len(os.Args)-2) + for _, a := range os.Args[2:] { + args = append(args, a) + } + repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + if _, e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } + os.Exit(0) + } - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/step9_try/step9_try.go b/go/src/step9_try/step9_try.go index 18f3c9c..34b380a 100644 --- a/go/src/step9_try/step9_try.go +++ b/go/src/step9_try/step9_try.go @@ -1,304 +1,370 @@ package main import ( - "fmt" - "strings" - "errors" - "os" + "errors" + "fmt" + "os" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func is_pair(x MalType) bool { - slc, e := GetSlice(x) - if e != nil { return false } - return len(slc) > 0 + slc, e := GetSlice(x) + if e != nil { + return false + } + return len(slc) > 0 } func quasiquote(ast MalType) MalType { - if !is_pair(ast) { - return List{[]MalType{Symbol{"quote"}, ast},nil} - } else { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { - return slc[1] - } else if is_pair(a0) { - slc0, _ := GetSlice(a0) - a00 := slc0[0] - if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { - return List{[]MalType{Symbol{"concat"}, - slc0[1], - quasiquote(List{slc[1:],nil})},nil} - } - } - return List{[]MalType{Symbol{"cons"}, - quasiquote(a0), - quasiquote(List{slc[1:],nil})},nil} - } + if !is_pair(ast) { + return List{[]MalType{Symbol{"quote"}, ast}, nil} + } else { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { + return slc[1] + } else if is_pair(a0) { + slc0, _ := GetSlice(a0) + a00 := slc0[0] + if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { + return List{[]MalType{Symbol{"concat"}, + slc0[1], + quasiquote(List{slc[1:], nil})}, nil} + } + } + return List{[]MalType{Symbol{"cons"}, + quasiquote(a0), + quasiquote(List{slc[1:], nil})}, nil} + } } func is_macro_call(ast MalType, env EnvType) bool { - if List_Q(ast) { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { - mac, e := env.Get(a0.(Symbol)) - if e != nil { return false } - if MalFunc_Q(mac) { - return mac.(MalFunc).GetMacro() - } - } - } - return false + if List_Q(ast) { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { + mac, e := env.Get(a0.(Symbol)) + if e != nil { + return false + } + if MalFunc_Q(mac) { + return mac.(MalFunc).GetMacro() + } + } + } + return false } -func macroexpand(ast MalType, env EnvType) (MalType, error) { - var mac MalType - var e error - for ; is_macro_call(ast, env) ; { - slc, _ := GetSlice(ast) - a0 := slc[0] - mac, e = env.Get(a0.(Symbol)); if e != nil { return nil, e } - fn := mac.(MalFunc) - ast, e = Apply(fn, slc[1:]); if e != nil { return nil, e } - } - return ast, nil +func macroexpand(ast MalType, env EnvType) (MalType, error) { + var mac MalType + var e error + for is_macro_call(ast, env) { + slc, _ := GetSlice(ast) + a0 := slc[0] + mac, e = env.Get(a0.(Symbol)) + if e != nil { + return nil, e + } + fn := mac.(MalFunc) + ast, e = Apply(fn, slc[1:]) + if e != nil { + return nil, e + } + } + return ast, nil } func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - var e error - for { + var e error + for { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - ast, e = macroexpand(ast, env); if e != nil { return nil, e } - if (!List_Q(ast)) { return ast, nil } + // apply list + ast, e = macroexpand(ast, env) + if e != nil { + return nil, e + } + if !List_Q(ast) { + return ast, nil + } - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "quote": - return a1, nil - case "quasiquote": - ast = quasiquote(a1) - case "defmacro!": - fn, e := EVAL(a2, env) - fn = fn.(MalFunc).SetMacro() - if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil - case "macroexpand": - return macroexpand(a1, env) - case "try*": - var exc MalType - exp, e := EVAL(a1, env) - if e == nil { - return exp, nil - } else { - if a2 != nil && List_Q(a2) { - a2s, _ := GetSlice(a2) - if Symbol_Q(a2s[0]) && (a2s[0].(Symbol).Val == "catch*") { - switch e.(type) { - case MalError: exc = e.(MalError).Obj - default: exc = e.Error() - } - binds := NewList(a2s[1]) - new_env, e := NewEnv(env, binds, NewList(exc)) - if e != nil { return nil, e } - exp, e = EVAL(a2s[2], new_env) - if e == nil { return exp, nil } - } - } - return nil, e - } - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "quote": + return a1, nil + case "quasiquote": + ast = quasiquote(a1) + case "defmacro!": + fn, e := EVAL(a2, env) + fn = fn.(MalFunc).SetMacro() + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), fn), nil + case "macroexpand": + return macroexpand(a1, env) + case "try*": + var exc MalType + exp, e := EVAL(a1, env) + if e == nil { + return exp, nil + } else { + if a2 != nil && List_Q(a2) { + a2s, _ := GetSlice(a2) + if Symbol_Q(a2s[0]) && (a2s[0].(Symbol).Val == "catch*") { + switch e.(type) { + case MalError: + exc = e.(MalError).Obj + default: + exc = e.Error() + } + binds := NewList(a2s[1]) + new_env, e := NewEnv(env, binds, NewList(exc)) + if e != nil { + return nil, e + } + exp, e = EVAL(a2s[2], new_env) + if e == nil { + return exp, nil + } + } + } + return nil, e + } + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } - } // TCO loop + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) },nil}) - repl_env.Set(Symbol{"*ARGV*"}, List{}) + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } + repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) + }, nil}) + repl_env.Set(Symbol{"*ARGV*"}, List{}) - // core.mal: defined using the language itself - 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))))))))") + // core.mal: defined using the language itself + 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))))))))") - // called with mal script to load and eval - if len(os.Args) > 1 { - args := make([]MalType, 0, len(os.Args)-2) - for _,a := range os.Args[2:] { - args = append(args, a) - } - repl_env.Set(Symbol{"*ARGV*"}, List{args,nil}) - if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { - fmt.Printf("Error: %v\n", e) - os.Exit(1) - } - os.Exit(0) - } + // called with mal script to load and eval + if len(os.Args) > 1 { + args := make([]MalType, 0, len(os.Args)-2) + for _, a := range os.Args[2:] { + args = append(args, a) + } + repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + if _, e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } + os.Exit(0) + } - // repl loop - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/stepA_mal/stepA_mal.go b/go/src/stepA_mal/stepA_mal.go index 808022a..548d72b 100644 --- a/go/src/stepA_mal/stepA_mal.go +++ b/go/src/stepA_mal/stepA_mal.go @@ -1,306 +1,372 @@ package main import ( - "fmt" - "strings" - "errors" - "os" + "errors" + "fmt" + "os" + "strings" ) import ( - "readline" - . "types" - "reader" - "printer" - . "env" - "core" + "core" + . "env" + "printer" + "reader" + "readline" + . "types" ) // read func READ(str string) (MalType, error) { - return reader.Read_str(str) + return reader.Read_str(str) } // eval func is_pair(x MalType) bool { - slc, e := GetSlice(x) - if e != nil { return false } - return len(slc) > 0 + slc, e := GetSlice(x) + if e != nil { + return false + } + return len(slc) > 0 } func quasiquote(ast MalType) MalType { - if !is_pair(ast) { - return List{[]MalType{Symbol{"quote"}, ast},nil} - } else { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { - return slc[1] - } else if is_pair(a0) { - slc0, _ := GetSlice(a0) - a00 := slc0[0] - if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { - return List{[]MalType{Symbol{"concat"}, - slc0[1], - quasiquote(List{slc[1:],nil})},nil} - } - } - return List{[]MalType{Symbol{"cons"}, - quasiquote(a0), - quasiquote(List{slc[1:],nil})},nil} - } + if !is_pair(ast) { + return List{[]MalType{Symbol{"quote"}, ast}, nil} + } else { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && (a0.(Symbol).Val == "unquote") { + return slc[1] + } else if is_pair(a0) { + slc0, _ := GetSlice(a0) + a00 := slc0[0] + if Symbol_Q(a00) && (a00.(Symbol).Val == "splice-unquote") { + return List{[]MalType{Symbol{"concat"}, + slc0[1], + quasiquote(List{slc[1:], nil})}, nil} + } + } + return List{[]MalType{Symbol{"cons"}, + quasiquote(a0), + quasiquote(List{slc[1:], nil})}, nil} + } } func is_macro_call(ast MalType, env EnvType) bool { - if List_Q(ast) { - slc, _ := GetSlice(ast) - a0 := slc[0] - if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { - mac, e := env.Get(a0.(Symbol)) - if e != nil { return false } - if MalFunc_Q(mac) { - return mac.(MalFunc).GetMacro() - } - } - } - return false + if List_Q(ast) { + slc, _ := GetSlice(ast) + a0 := slc[0] + if Symbol_Q(a0) && env.Find(a0.(Symbol)) != nil { + mac, e := env.Get(a0.(Symbol)) + if e != nil { + return false + } + if MalFunc_Q(mac) { + return mac.(MalFunc).GetMacro() + } + } + } + return false } -func macroexpand(ast MalType, env EnvType) (MalType, error) { - var mac MalType - var e error - for ; is_macro_call(ast, env) ; { - slc, _ := GetSlice(ast) - a0 := slc[0] - mac, e = env.Get(a0.(Symbol)); if e != nil { return nil, e } - fn := mac.(MalFunc) - ast, e = Apply(fn, slc[1:]); if e != nil { return nil, e } - } - return ast, nil +func macroexpand(ast MalType, env EnvType) (MalType, error) { + var mac MalType + var e error + for is_macro_call(ast, env) { + slc, _ := GetSlice(ast) + a0 := slc[0] + mac, e = env.Get(a0.(Symbol)) + if e != nil { + return nil, e + } + fn := mac.(MalFunc) + ast, e = Apply(fn, slc[1:]) + if e != nil { + return nil, e + } + } + return ast, nil } func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) - if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) - } else if List_Q(ast) { - lst := []MalType{} - for _, a := range ast.(List).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return List{lst,nil}, nil - } else if Vector_Q(ast) { - lst := []MalType{} - for _, a := range ast.(Vector).Val { - exp, e := EVAL(a, env) - if e != nil { return nil, e } - lst = append(lst, exp) - } - return Vector{lst,nil}, nil - } else if HashMap_Q(ast) { - 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 { - return nil, errors.New("non string hash-map key") - } - kv, e2 := EVAL(v, env) - if e2 != nil { return nil, e2 } - new_hm.Val[ke.(string)] = kv - } - return new_hm, nil - } else { - return ast, nil - } + //fmt.Printf("eval_ast: %#v\n", ast) + if Symbol_Q(ast) { + return env.Get(ast.(Symbol)) + } else if List_Q(ast) { + lst := []MalType{} + for _, a := range ast.(List).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return List{lst, nil}, nil + } else if Vector_Q(ast) { + lst := []MalType{} + for _, a := range ast.(Vector).Val { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return Vector{lst, nil}, nil + } else if HashMap_Q(ast) { + 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 { + return nil, errors.New("non string hash-map key") + } + kv, e2 := EVAL(v, env) + if e2 != nil { + return nil, e2 + } + new_hm.Val[ke.(string)] = kv + } + return new_hm, nil + } else { + return ast, nil + } } func EVAL(ast MalType, env EnvType) (MalType, error) { - var e error - for { + var e error + for { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) - switch ast.(type) { - case List: // continue - default: return eval_ast(ast, env) - } + //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + switch ast.(type) { + case List: // continue + default: + return eval_ast(ast, env) + } - // apply list - ast, e = macroexpand(ast, env); if e != nil { return nil, e } - if (!List_Q(ast)) { return ast, nil } + // apply list + ast, e = macroexpand(ast, env) + if e != nil { + return nil, e + } + if !List_Q(ast) { + return ast, nil + } - a0 := ast.(List).Val[0] - var a1 MalType = nil; var a2 MalType = nil - switch len(ast.(List).Val) { - case 1: - a1 = nil; a2 = nil - case 2: - a1 = ast.(List).Val[1]; a2 = nil - default: - a1 = ast.(List).Val[1]; a2 = ast.(List).Val[2] - } - a0sym := "__<*fn*>__" - if Symbol_Q(a0) { a0sym = a0.(Symbol).Val } - switch a0sym { - case "def!": - res, e := EVAL(a2, env) - if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { return nil, e } - arr1, e := GetSlice(a1) - if e != nil { return nil, e } - for i := 0; i < len(arr1); i+=2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") - } - exp, e := EVAL(arr1[i+1], let_env) - if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) - } - ast = a2 - env = let_env - case "quote": - return a1, nil - case "quasiquote": - ast = quasiquote(a1) - case "defmacro!": - fn, e := EVAL(a2, env) - fn = fn.(MalFunc).SetMacro() - if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil - case "macroexpand": - return macroexpand(a1, env) - case "try*": - var exc MalType - exp, e := EVAL(a1, env) - if e == nil { - return exp, nil - } else { - if a2 != nil && List_Q(a2) { - a2s, _ := GetSlice(a2) - if Symbol_Q(a2s[0]) && (a2s[0].(Symbol).Val == "catch*") { - switch e.(type) { - case MalError: exc = e.(MalError).Obj - default: exc = e.Error() - } - binds := NewList(a2s[1]) - new_env, e := NewEnv(env, binds, NewList(exc)) - if e != nil { return nil, e } - exp, e = EVAL(a2s[2], new_env) - if e == nil { return exp, nil } - } - } - return nil, e - } - case "do": - lst := ast.(List).Val - _, 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] - case "if": - cond, e := EVAL(a1, env) - if e != nil { return nil, e } - if cond == nil || cond == false { - if len(ast.(List).Val) >= 4 { - ast = ast.(List).Val[3] - } else { - return nil, nil - } - } else { - ast = a2 - } - case "fn*": - fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} - return fn, nil - default: - el, e := eval_ast(ast, env) - if e != nil { return nil, e } - f := el.(List).Val[0] - if MalFunc_Q(f) { - fn := f.(MalFunc) - ast = fn.Exp - env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) - if e != nil { return nil, e } - } else { - fn, ok := f.(Func) - if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) - } - } + a0 := ast.(List).Val[0] + var a1 MalType = nil + var a2 MalType = nil + switch len(ast.(List).Val) { + case 1: + a1 = nil + a2 = nil + case 2: + a1 = ast.(List).Val[1] + a2 = nil + default: + a1 = ast.(List).Val[1] + a2 = ast.(List).Val[2] + } + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val + } + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) + if e != nil { + return nil, e + } + arr1, e := GetSlice(a1) + if e != nil { + return nil, e + } + for i := 0; i < len(arr1); i += 2 { + if !Symbol_Q(arr1[i]) { + return nil, errors.New("non-symbol bind value") + } + exp, e := EVAL(arr1[i+1], let_env) + if e != nil { + return nil, e + } + let_env.Set(arr1[i].(Symbol), exp) + } + ast = a2 + env = let_env + case "quote": + return a1, nil + case "quasiquote": + ast = quasiquote(a1) + case "defmacro!": + fn, e := EVAL(a2, env) + fn = fn.(MalFunc).SetMacro() + if e != nil { + return nil, e + } + return env.Set(a1.(Symbol), fn), nil + case "macroexpand": + return macroexpand(a1, env) + case "try*": + var exc MalType + exp, e := EVAL(a1, env) + if e == nil { + return exp, nil + } else { + if a2 != nil && List_Q(a2) { + a2s, _ := GetSlice(a2) + if Symbol_Q(a2s[0]) && (a2s[0].(Symbol).Val == "catch*") { + switch e.(type) { + case MalError: + exc = e.(MalError).Obj + default: + exc = e.Error() + } + binds := NewList(a2s[1]) + new_env, e := NewEnv(env, binds, NewList(exc)) + if e != nil { + return nil, e + } + exp, e = EVAL(a2s[2], new_env) + if e == nil { + return exp, nil + } + } + } + return nil, e + } + case "do": + lst := ast.(List).Val + _, 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] + case "if": + cond, e := EVAL(a1, env) + if e != nil { + return nil, e + } + if cond == nil || cond == false { + if len(ast.(List).Val) >= 4 { + ast = ast.(List).Val[3] + } else { + return nil, nil + } + } else { + ast = a2 + } + case "fn*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + el, e := eval_ast(ast, env) + if e != nil { + return nil, e + } + f := el.(List).Val[0] + if MalFunc_Q(f) { + fn := f.(MalFunc) + ast = fn.Exp + env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:], nil}) + if e != nil { + return nil, e + } + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(el.(List).Val[1:]) + } + } - } // TCO loop + } // TCO loop } // print func PRINT(exp MalType) (string, error) { - return printer.Pr_str(exp, true), nil + return printer.Pr_str(exp, true), nil } - var repl_env, _ = NewEnv(nil, nil, nil) // repl func rep(str string) (MalType, error) { - var exp MalType - var res string - var e error - if exp, e = READ(str); e != nil { return nil, e } - if exp, e = EVAL(exp, repl_env); e != nil { return nil, e } - if res, e = PRINT(exp); e != nil { return nil, e } - return res, nil + var exp MalType + var res string + var e error + if exp, e = READ(str); e != nil { + return nil, e + } + if exp, e = EVAL(exp, repl_env); e != nil { + return nil, e + } + if res, e = PRINT(exp); e != nil { + return nil, e + } + return res, nil } func main() { - // core.go: defined using go - for k, v := range core.NS { - repl_env.Set(Symbol{k}, Func{v.(func([]MalType)(MalType,error)),nil}) - } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) },nil}) - repl_env.Set(Symbol{"*ARGV*"}, List{}) + // core.go: defined using go + for k, v := range core.NS { + repl_env.Set(Symbol{k}, Func{v.(func([]MalType) (MalType, error)), nil}) + } + repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) + }, nil}) + repl_env.Set(Symbol{"*ARGV*"}, List{}) - // core.mal: defined using the language itself - rep("(def! *host-language* \"go\")") - 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))))))))") + // core.mal: defined using the language itself + rep("(def! *host-language* \"go\")") + 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))))))))") - // called with mal script to load and eval - if len(os.Args) > 1 { - args := make([]MalType, 0, len(os.Args)-2) - for _,a := range os.Args[2:] { - args = append(args, a) - } - repl_env.Set(Symbol{"*ARGV*"}, List{args,nil}) - if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { - fmt.Printf("Error: %v\n", e) - os.Exit(1) - } - os.Exit(0) - } + // called with mal script to load and eval + if len(os.Args) > 1 { + args := make([]MalType, 0, len(os.Args)-2) + for _, a := range os.Args[2:] { + args = append(args, a) + } + repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + if _, e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } + os.Exit(0) + } - // repl loop - rep("(println (str \"Mal [\" *host-language* \"]\"))") - for { - text, err := readline.Readline("user> ") - text = strings.TrimRight(text, "\n"); - if (err != nil) { - return - } - var out MalType - var e error - if out, e = rep(text); e != nil { - if e.Error() == "<empty line>" { continue } - fmt.Printf("Error: %v\n", e) - continue - } - fmt.Printf("%v\n", out) - } + // repl loop + rep("(println (str \"Mal [\" *host-language* \"]\"))") + for { + text, err := readline.Readline("user> ") + text = strings.TrimRight(text, "\n") + if err != nil { + return + } + var out MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { + continue + } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%v\n", out) + } } diff --git a/go/src/types/types.go b/go/src/types/types.go index 54e4176..3fac06d 100644 --- a/go/src/types/types.go +++ b/go/src/types/types.go @@ -1,258 +1,302 @@ package types import ( - "reflect" - "errors" - "fmt" - "strings" + "errors" + "fmt" + "reflect" + "strings" ) // Errors/Exceptions type MalError struct { - Obj MalType + Obj MalType } func (e MalError) Error() string { - return fmt.Sprintf("%#v", e.Obj) + return fmt.Sprintf("%#v", e.Obj) } - // General types type MalType interface { } type EnvType interface { - Find(key Symbol) EnvType - Set(key Symbol, value MalType) MalType - Get(key Symbol) (MalType, error) + Find(key Symbol) EnvType + Set(key Symbol, value MalType) MalType + Get(key Symbol) (MalType, error) } // Scalars func Nil_Q(obj MalType) bool { - if obj == nil { return true } else { return false } + if obj == nil { + return true + } else { + return false + } } func True_Q(obj MalType) bool { - switch tobj := obj.(type) { - case bool: return tobj == true - default: return false - } + switch tobj := obj.(type) { + case bool: + return tobj == true + default: + return false + } } func False_Q(obj MalType) bool { - switch tobj := obj.(type) { - case bool: return tobj == false - default: return false - } + switch tobj := obj.(type) { + case bool: + return tobj == false + default: + return false + } } // Symbols type Symbol struct { - Val string + Val string } func Symbol_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "Symbol" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "Symbol" } - // Keywords func NewKeyword(s string) (MalType, error) { - return "\u029e" + s, nil; + return "\u029e" + s, nil } func Keyword_Q(obj MalType) bool { - if obj == nil { return false } - switch s := obj.(type) { - case string: return strings.HasPrefix(s, "\u029e") - default: return false - } + if obj == nil { + return false + } + switch s := obj.(type) { + case string: + return strings.HasPrefix(s, "\u029e") + default: + return false + } } - // Strings func String_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "string" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "string" } - // Functions type Func struct { - Fn func([]MalType) (MalType, error) - Meta MalType + Fn func([]MalType) (MalType, error) + Meta MalType } func Func_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "Func" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "Func" } type MalFunc struct { - Eval func(MalType, EnvType) (MalType, error) - Exp MalType - Env EnvType - Params MalType - IsMacro bool - GenEnv func(EnvType, MalType, MalType) (EnvType, error) - Meta MalType + Eval func(MalType, EnvType) (MalType, error) + Exp MalType + Env EnvType + Params MalType + IsMacro bool + GenEnv func(EnvType, MalType, MalType) (EnvType, error) + Meta MalType } func MalFunc_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "MalFunc" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "MalFunc" } func (f MalFunc) SetMacro() MalType { - f.IsMacro = true - return f + f.IsMacro = true + return f } func (f MalFunc) GetMacro() bool { - return f.IsMacro + return f.IsMacro } // Take either a MalFunc or regular function and apply it to the // arguments 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,nil}) - if e != nil { return nil, e } - return f.Eval(f.Exp, env) - case Func: - return f.Fn(a) - case func([]MalType)(MalType, error): - return f(a) - default: - return nil, errors.New("Invalid function to Apply") - } + switch f := f_mt.(type) { + case MalFunc: + 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: + return f.Fn(a) + case func([]MalType) (MalType, error): + return f(a) + default: + return nil, errors.New("Invalid function to Apply") + } } - // Lists type List struct { - Val []MalType - Meta MalType + Val []MalType + Meta MalType } func NewList(a ...MalType) MalType { - return List{a,nil} + return List{a, nil} } func List_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "List" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "List" } // Vectors type Vector struct { - Val []MalType - Meta MalType + Val []MalType + Meta MalType } func Vector_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "Vector" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "Vector" } func GetSlice(seq MalType) ([]MalType, error) { - switch obj := seq.(type) { - case List: return obj.Val, nil - case Vector: return obj.Val, nil - default: return nil, errors.New("GetSlice called on non-sequence") - } + switch obj := seq.(type) { + case List: + return obj.Val, nil + case Vector: + return obj.Val, nil + default: + return nil, errors.New("GetSlice called on non-sequence") + } } // Hash Maps type HashMap struct { - Val map[string]MalType - Meta MalType + Val map[string]MalType + Meta MalType } func NewHashMap(seq MalType) (MalType, error) { - lst, e := GetSlice(seq) - if e != nil { return nil, e } - if len(lst) % 2 == 1 { - return nil, errors.New("Odd number of arguments to NewHashMap") - } - m := map[string]MalType{} - for i := 0; i < len(lst); i+=2 { - str, ok := lst[i].(string) - if !ok { - return nil, errors.New("expected hash-map key string") - } - m[str] = lst[i+1] - } - return HashMap{m,nil}, nil + lst, e := GetSlice(seq) + if e != nil { + return nil, e + } + if len(lst)%2 == 1 { + return nil, errors.New("Odd number of arguments to NewHashMap") + } + m := map[string]MalType{} + for i := 0; i < len(lst); i += 2 { + str, ok := lst[i].(string) + if !ok { + return nil, errors.New("expected hash-map key string") + } + m[str] = lst[i+1] + } + return HashMap{m, nil}, nil } func HashMap_Q(obj MalType) bool { - if obj == nil { return false } - return reflect.TypeOf(obj).Name() == "HashMap" + if obj == nil { + return false + } + return reflect.TypeOf(obj).Name() == "HashMap" } // Atoms type Atom struct { - Val MalType - Meta MalType + Val MalType + Meta MalType } + func (a *Atom) Set(val MalType) MalType { - a.Val= val - return a + a.Val = val + return a } func Atom_Q(obj MalType) bool { - switch obj.(type) { - case *Atom: return true - default: return false - } + switch obj.(type) { + 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() + if obj == nil { + return "nil" + } + return reflect.TypeOf(obj).Name() } func Sequential_Q(seq MalType) bool { - if seq == nil { return false } - return (reflect.TypeOf(seq).Name() == "List") || - (reflect.TypeOf(seq).Name() == "Vector") + if seq == nil { + return false + } + return (reflect.TypeOf(seq).Name() == "List") || + (reflect.TypeOf(seq).Name() == "Vector") } func Equal_Q(a MalType, b MalType) bool { - ota := reflect.TypeOf(a); otb := reflect.TypeOf(b) - if !((ota == otb) || (Sequential_Q(a) && Sequential_Q(b))) { - return false - } - //av := reflect.ValueOf(a); bv := reflect.ValueOf(b) - //fmt.Printf("here2: %#v\n", reflect.TypeOf(a).Name()) - //switch reflect.TypeOf(a).Name() { - switch a.(type) { - case Symbol: - return a.(Symbol).Val == b.(Symbol).Val - case List: - as,_ := GetSlice(a); bs,_ := GetSlice(b) - if len(as) != len(bs) { return false } - for i := 0; i < len(as); i+=1 { - if !Equal_Q(as[i], bs[i]) { return false } - } - return true - case Vector: - as,_ := GetSlice(a); bs,_ := GetSlice(b) - if len(as) != len(bs) { return false } - for i := 0; i < len(as); i+=1 { - if !Equal_Q(as[i], bs[i]) { return false } - } - return true - case HashMap: - return false - default: - return a == b - } + ota := reflect.TypeOf(a) + otb := reflect.TypeOf(b) + if !((ota == otb) || (Sequential_Q(a) && Sequential_Q(b))) { + return false + } + //av := reflect.ValueOf(a); bv := reflect.ValueOf(b) + //fmt.Printf("here2: %#v\n", reflect.TypeOf(a).Name()) + //switch reflect.TypeOf(a).Name() { + switch a.(type) { + case Symbol: + return a.(Symbol).Val == b.(Symbol).Val + case List: + as, _ := GetSlice(a) + bs, _ := GetSlice(b) + if len(as) != len(bs) { + return false + } + for i := 0; i < len(as); i += 1 { + if !Equal_Q(as[i], bs[i]) { + return false + } + } + return true + case Vector: + as, _ := GetSlice(a) + bs, _ := GetSlice(b) + if len(as) != len(bs) { + return false + } + for i := 0; i < len(as); i += 1 { + if !Equal_Q(as[i], bs[i]) { + return false + } + } + return true + case HashMap: + return false + default: + return a == b + } } |
