aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-04 23:40:43 -0500
committerJoel Martin <github@martintribe.org>2014-10-04 23:40:43 -0500
commit9feb2c9527294d82592bf35b97f8039f61bbec45 (patch)
treead98f49352e56fe439b43385c4612aa337c1c095 /go
parent8b8afefc458810da516272d679b5a9de1f0daa17 (diff)
downloadmal-9feb2c9527294d82592bf35b97f8039f61bbec45.tar.gz
mal-9feb2c9527294d82592bf35b97f8039f61bbec45.zip
go: add step3_env
Diffstat (limited to 'go')
-rw-r--r--go/Makefile6
-rw-r--r--go/src/step2_eval/step2_eval.go1
-rw-r--r--go/src/step3_env/step3_env.go152
-rw-r--r--go/src/types/types.go12
4 files changed, 168 insertions, 3 deletions
diff --git a/go/Makefile b/go/Makefile
index de72c44..695627e 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -2,13 +2,13 @@ export GOPATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
#####################
-SOURCES_BASE = src/types/types.go src/reader/reader.go src/printer/printer.go
-SOURCES_LISP = src/step2_eval/step2_eval.go
+SOURCES_BASE = src/types/types.go src/reader/reader.go src/printer/printer.go src/env/env.go
+SOURCES_LISP = src/step3_env/step3_env.go
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
#####################
-SRCS = step0_repl.go step1_read_print.go step2_eval.go
+SRCS = step0_repl.go step1_read_print.go step2_eval.go step3_env.go
BINS = $(SRCS:%.go=%)
#####################
diff --git a/go/src/step2_eval/step2_eval.go b/go/src/step2_eval/step2_eval.go
index e82c360..31d6f64 100644
--- a/go/src/step2_eval/step2_eval.go
+++ b/go/src/step2_eval/step2_eval.go
@@ -70,6 +70,7 @@ func EVAL(ast MalType, env map[string]MalType) (MalType, error) {
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))
diff --git a/go/src/step3_env/step3_env.go b/go/src/step3_env/step3_env.go
new file mode 100644
index 0000000..6241eff
--- /dev/null
+++ b/go/src/step3_env/step3_env.go
@@ -0,0 +1,152 @@
+package main
+
+import (
+ "bufio"
+ //"io"
+ "fmt"
+ "os"
+ "strings"
+ "errors"
+)
+
+import (
+ . "types"
+ "reader"
+ "printer"
+ . "env"
+)
+
+// read
+func READ(str string) (MalType, error) {
+ return reader.Read_str(str)
+}
+
+// eval
+func eval_ast(ast MalType, env Env) (MalType, error) {
+ //fmt.Printf("eval_ast: %#v\n", ast)
+ if Symbol_Q(ast) {
+ return env.Get(ast.(Symbol).Val)
+ } 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
+ } 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
+ } else if Hash_Map_Q(ast) {
+ m := ast.(map[string]MalType)
+ new_hm := map[string]MalType{}
+ for k, v := range m {
+ 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[ke.(string)] = kv
+ }
+ return new_hm, nil
+ } else {
+ return ast, nil
+ }
+}
+
+func EVAL(ast MalType, env Env) (MalType, error) {
+ //fmt.Printf("EVAL: %#v\n", ast)
+ switch ast.(type) {
+ case List: // continue
+ default: return eval_ast(ast, env)
+ }
+
+ // apply list
+ a0 := ast.(List).Val[0]
+ if !Symbol_Q(a0) {
+ return nil, errors.New("attempt to apply on non-symbol '" +
+ printer.Pr_str(a0, true) + "'")
+ }
+ switch a0.(Symbol).Val {
+ case "def!":
+ a1 := ast.(List).Val[1]; a2 := ast.(List).Val[2]
+ res, e := EVAL(a2, env)
+ if e != nil { return nil, e }
+ return env.Set(a1.(Symbol).Val, res), nil
+ case "let*":
+ a1 := ast.(List).Val[1]; a2 := ast.(List).Val[2]
+ let_env := NewEnv(&env, nil, nil)
+ 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).Val, 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) (MalType, error) {
+ 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 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 exp, e = PRINT(exp); e != nil { return nil, e }
+ return exp, nil
+}
+
+func main() {
+ repl_env.Set("+", func(a []MalType) (MalType, error) {
+ return a[0].(int) + a[1].(int), nil })
+ repl_env.Set("-", func(a []MalType) (MalType, error) {
+ return a[0].(int) - a[1].(int), nil })
+ repl_env.Set("*", func(a []MalType) (MalType, error) {
+ return a[0].(int) * a[1].(int), nil })
+ repl_env.Set("/", func(a []MalType) (MalType, error) {
+ return a[0].(int) / a[1].(int), nil })
+
+ rdr := bufio.NewReader(os.Stdin);
+ // repl loop
+ for {
+ fmt.Print("user> ");
+ text, err := rdr.ReadString('\n');
+ 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 9fcc78c..2eacaaf 100644
--- a/go/src/types/types.go
+++ b/go/src/types/types.go
@@ -1,5 +1,9 @@
package types
+import (
+ "errors"
+)
+
//type Error interface {
// error
//}
@@ -43,6 +47,14 @@ func Vector_Q(obj MalType) bool {
}
}
+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")
+ }
+}
+
// Hash Maps
func Hash_Map_Q(obj MalType) bool {
switch obj.(type) {