diff --git a/docs/FAQ.md b/docs/FAQ.md index 4cfd83029c..945ac8abef 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -150,7 +150,7 @@ accepted into the main repository: * Your implementation should follow the existing mal steps and structure: Lisp-centric code (eval, eval_ast, quasiquote, - macroexpand) in the step files, other code in reader, printer, env, + macros) in the step files, other code in reader, printer, env, and core files. See [code layout rationale](#code_split) above. I encourage you to create implementations that take mal in new directions for your own learning and experimentation, but for it to diff --git a/docs/step_notes.txt b/docs/step_notes.txt index df6a74e6ad..27b732f151 100644 --- a/docs/step_notes.txt +++ b/docs/step_notes.txt @@ -16,7 +16,7 @@ Step Notes: - add _STEP_TO_PROG entry - add _RUNSTEP entry - for a compiled language, add /Makefile - - targets: all, step*, stats, stats-lisp, + - targets: all, step*, stats, stats-lisp, - use native eval in EVAL if available @@ -79,7 +79,7 @@ Step Notes: - run `make test^EXT^step1`. Much of the basics should pass up to vectors - implement read_hash_map (can refactor read_list) - - import read_vector + - import read_vector - probably want to define types for List and Vector in types.EXT that extend or wrap native arrays - run `make test^EXT^step1`. All mandatory should pass @@ -319,22 +319,18 @@ Step Notes: - capability to store ismacro property in function - core module: - add first, rest, nth functions - - add is_macro_call and macroexpand - - recursively macroexpand lists - - if applying a macro function, run it on the ast first before - continuing - - call macroexpand apply in EVAL before apply - EVAL: - - add 'defmacro!' and 'macroexpand' + - add 'defmacro!' - set ismacro property on function + - apply macros and perform TCO. - Details: - cp step7_quote.EXT to step8_macros.EXT - if compiled update Makefile - add isMacro property to Mal Function type - may need to go back and adjust step5-7 - - implement is_macro_call and macroexpand - - call macroexpand on ast before apply in EVAL - - add defmacro! and macroexpand to EVAL switch + - before apply in EVAL, if the function is a macro, apply it + to raw arguments and EVAL again (TCO). + - add defmacro! to EVAL switch - make test^go^step8 should pass some basic macros - add nth, first, and rest to core.ns - make test^go^step8 should now pass @@ -345,7 +341,7 @@ Step Notes: - apply, map functions: should not directly call EVAL, which requires the function object to be runnable - readline - - nil?, true?, false? + - nil?, true?, false? - EVAL: - try*/catch*: for normal exceptions, extracts string otherwise extracts full value @@ -409,4 +405,3 @@ Step Notes: - convert returned data to mal data - recursive, similar to pr_str - Details: - diff --git a/impls/chuck/notes.md b/impls/chuck/notes.md index c467d15bc9..33a77fec66 100644 --- a/impls/chuck/notes.md +++ b/impls/chuck/notes.md @@ -101,8 +101,6 @@ - "In the previous step, quoting enabled some simple manipulation [of] data structures" -- The macroexpand function step refers to call/apply, it's unclear how - to proceed if you don't have such a thing - How should the exception for invalid `nth` access look like? Also, why is it an exception and not an error like with the reader? - How can `first` take a list (or vector), but work on `nil`? diff --git a/impls/go/src/env/env.go b/impls/go/src/env/env.go index 0c3ed5b8b2..18303b33ac 100644 --- a/impls/go/src/env/env.go +++ b/impls/go/src/env/env.go @@ -1,7 +1,6 @@ package env import ( - "errors" //"fmt" ) @@ -41,25 +40,18 @@ func NewEnv(outer EnvType, binds_mt MalType, exprs_mt MalType) (EnvType, error) return env, nil } -func (e Env) Find(key Symbol) EnvType { - if _, ok := e.data[key.Val]; ok { - return e +func (e Env) Get(key string) (MalType, bool) { + result, ok := e.data[key] + if ok { + return result, ok } else if e.outer != nil { - return e.outer.Find(key) + return e.outer.Get(key) } else { - return nil + return nil, false } } -func (e Env) Set(key Symbol, value MalType) MalType { - e.data[key.Val] = value +func (e Env) Set(key string, value MalType) MalType { + e.data[key] = 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 -} diff --git a/impls/go/src/step2_eval/step2_eval.go b/impls/go/src/step2_eval/step2_eval.go index b24f858831..135861cc93 100644 --- a/impls/go/src/step2_eval/step2_eval.go +++ b/impls/go/src/step2_eval/step2_eval.go @@ -19,33 +19,33 @@ func READ(str string) (MalType, error) { } // 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") +func map_eval(xs []MalType, env map[string]MalType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e } - 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) + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env map[string]MalType) (MalType, error) { + + // fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + + if Symbol_Q(ast) { + env_val, env_found := env[ast.(Symbol).Val] + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -59,33 +59,30 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { 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) - } - - if len(ast.(List).Val) == 0 { - return ast, nil - } + } else { + // apply list + if len(ast.(List).Val) == 0 { + return ast, nil + } - // 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:]) + a0 := ast.(List).Val[0] + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, env) + if e != nil { + return nil, e + } + fn, ok := f.(func([]MalType) (MalType, error)) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn(args) + } } // print diff --git a/impls/go/src/step3_env/step3_env.go b/impls/go/src/step3_env/step3_env.go index 0f199e1a5f..e63b518ab7 100644 --- a/impls/go/src/step3_env/step3_env.go +++ b/impls/go/src/step3_env/step3_env.go @@ -20,28 +20,36 @@ func READ(str string) (MalType, error) { } // eval -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env EnvType) (MalType, error) { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -55,79 +63,75 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { 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) - } - - if len(ast.(List).Val) == 0 { - return ast, nil - } - - // 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 + } else { + // apply list + if len(ast.(List).Val) == 0 { + return ast, nil } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { - return nil, e + + 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] } - arr1, e := GetSlice(a1) - if e != nil { - return nil, e + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val } - for i := 0; i < len(arr1); i += 2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e } - exp, e := EVAL(arr1[i+1], let_env) + return env.Set(a1.(Symbol).Val, res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) 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") + 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: + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, env) + if e != nil { + return nil, e + } + fn, ok := f.(func([]MalType) (MalType, error)) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn(args) } - return f(el.(List).Val[1:]) } } @@ -156,25 +160,25 @@ func rep(str string) (MalType, error) { } func main() { - repl_env.Set(Symbol{"+"}, func(a []MalType) (MalType, error) { + repl_env.Set("+", func(a []MalType) (MalType, error) { if e := assertArgNum(a, 2); e != nil { return nil, e } return a[0].(int) + a[1].(int), nil }) - repl_env.Set(Symbol{"-"}, func(a []MalType) (MalType, error) { + repl_env.Set("-", func(a []MalType) (MalType, error) { if e := assertArgNum(a, 2); e != nil { return nil, e } return a[0].(int) - a[1].(int), nil }) - repl_env.Set(Symbol{"*"}, func(a []MalType) (MalType, error) { + repl_env.Set("*", func(a []MalType) (MalType, error) { if e := assertArgNum(a, 2); e != nil { return nil, e } return a[0].(int) * a[1].(int), nil }) - repl_env.Set(Symbol{"/"}, func(a []MalType) (MalType, error) { + repl_env.Set("/", func(a []MalType) (MalType, error) { if e := assertArgNum(a, 2); e != nil { return nil, e } diff --git a/impls/go/src/step4_if_fn_do/step4_if_fn_do.go b/impls/go/src/step4_if_fn_do/step4_if_fn_do.go index 9de8d00a30..5b366a3333 100644 --- a/impls/go/src/step4_if_fn_do/step4_if_fn_do.go +++ b/impls/go/src/step4_if_fn_do/step4_if_fn_do.go @@ -21,28 +21,36 @@ func READ(str string) (MalType, error) { } // eval -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env EnvType) (MalType, error) { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -56,111 +64,111 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = 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) - } - - if len(ast.(List).Val) == 0 { + } else if !List_Q(ast) { return ast, nil - } - - // 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 + } else { + // apply list + if len(ast.(List).Val) == 0 { + return ast, nil } - return env.Set(a1.(Symbol), res), nil - case "let*": - let_env, e := NewEnv(env, nil, nil) - if e != nil { - return nil, e + + 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] } - arr1, e := GetSlice(a1) - if e != nil { - return nil, e + a0sym := "__<*fn*>__" + if Symbol_Q(a0) { + a0sym = a0.(Symbol).Val } - for i := 0; i < len(arr1); i += 2 { - if !Symbol_Q(arr1[i]) { - return nil, errors.New("non-symbol bind value") + switch a0sym { + case "def!": + res, e := EVAL(a2, env) + if e != nil { + return nil, e } - exp, e := EVAL(arr1[i+1], let_env) + return env.Set(a1.(Symbol).Val, res), nil + case "let*": + let_env, e := NewEnv(env, nil, nil) 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 { + 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) + case "do": + lst := ast.(List).Val + _, e := map_eval(lst[1 : len(lst)-1], env) + if e != nil { + return nil, e + } + if len(lst) == 1 { 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}) + return EVAL(lst[len(lst)-1], env) + case "if": + cond, e := EVAL(a1, env) 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") + 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*": + fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} + return fn, nil + default: + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, env) + if e != nil { + return nil, e + } + if MalFunc_Q(f) { + fn := f.(MalFunc) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) + if e != nil { + return nil, e + } + return EVAL(fn.Exp, env) + } else { + fn, ok := f.(Func) + if !ok { + return nil, errors.New("attempt to call non-function") + } + return fn.Fn(args) + } } - return f(el.(List).Val[1:]) } } @@ -191,7 +199,7 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(Symbol{k}, v) + repl_env.Set(k, Func{v.(func([]MalType) (MalType, error)), nil}) } // core.mal: defined using the language itself diff --git a/impls/go/src/step5_tco/step5_tco.go b/impls/go/src/step5_tco/step5_tco.go index 7205fc805d..e601abb01c 100644 --- a/impls/go/src/step5_tco/step5_tco.go +++ b/impls/go/src/step5_tco/step5_tco.go @@ -21,28 +21,37 @@ func READ(str string) (MalType, error) { } // eval -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env EnvType) (MalType, error) { + for { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -56,26 +65,14 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { 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) - } - + } else { + // apply list if len(ast.(List).Val) == 0 { return ast, nil } - // apply list a0 := ast.(List).Val[0] var a1 MalType = nil var a2 MalType = nil @@ -100,7 +97,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -118,13 +115,13 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env case "do": lst := ast.(List).Val - _, e := eval_ast(List{lst[1 : len(lst)-1], nil}, env) + _, e := map_eval(lst[1 : len(lst)-1], env) if e != nil { return nil, e } @@ -150,15 +147,19 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} return fn, nil default: - el, e := eval_ast(ast, env) + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, 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}) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) if e != nil { return nil, e } @@ -167,10 +168,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) + return fn.Fn(args) } } - + } } // TCO loop } @@ -201,7 +202,7 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } // core.mal: defined using the language itself diff --git a/impls/go/src/step6_file/step6_file.go b/impls/go/src/step6_file/step6_file.go index 88128d30f1..8cb7ab00e4 100644 --- a/impls/go/src/step6_file/step6_file.go +++ b/impls/go/src/step6_file/step6_file.go @@ -22,28 +22,37 @@ func READ(str string) (MalType, error) { } // eval -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env EnvType) (MalType, error) { + for { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -57,26 +66,14 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { 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) - } - + } else { + // apply list if len(ast.(List).Val) == 0 { return ast, nil } - // apply list a0 := ast.(List).Val[0] var a1 MalType = nil var a2 MalType = nil @@ -101,7 +98,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -119,13 +116,13 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env case "do": lst := ast.(List).Val - _, e := eval_ast(List{lst[1 : len(lst)-1], nil}, env) + _, e := map_eval(lst[1 : len(lst)-1], env) if e != nil { return nil, e } @@ -151,15 +148,19 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} return fn, nil default: - el, e := eval_ast(ast, env) + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, 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}) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) if e != nil { return nil, e } @@ -168,10 +169,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) + return fn.Fn(args) } } - + } } // TCO loop } @@ -202,12 +203,11 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + repl_env.Set("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)))") @@ -219,13 +219,14 @@ func main() { for _, a := range os.Args[2:] { args = append(args, a) } - repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + repl_env.Set("*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_env.Set("*ARGV*", List{}) // repl loop for { diff --git a/impls/go/src/step7_quote/step7_quote.go b/impls/go/src/step7_quote/step7_quote.go index 11832eb622..75c5bb0f21 100644 --- a/impls/go/src/step7_quote/step7_quote.go +++ b/impls/go/src/step7_quote/step7_quote.go @@ -67,28 +67,37 @@ func quasiquote(ast MalType) MalType { } } -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) + if e != nil { + return nil, e + } + lst = append(lst, exp) + } + return lst, nil +} + +func EVAL(ast MalType, env EnvType) (MalType, error) { + for { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -102,26 +111,14 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { 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) - } - + } else { + // apply list if len(ast.(List).Val) == 0 { return ast, nil } - // apply list a0 := ast.(List).Val[0] var a1 MalType = nil var a2 MalType = nil @@ -146,7 +143,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -164,19 +161,17 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env case "quote": return a1, nil - case "quasiquoteexpand": - return quasiquote(a1), nil case "quasiquote": ast = quasiquote(a1) case "do": lst := ast.(List).Val - _, e := eval_ast(List{lst[1 : len(lst)-1], nil}, env) + _, e := map_eval(lst[1 : len(lst)-1], env) if e != nil { return nil, e } @@ -202,15 +197,19 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} return fn, nil default: - el, e := eval_ast(ast, env) + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + args, e = map_eval(args, 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}) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) if e != nil { return nil, e } @@ -219,10 +218,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) + return fn.Fn(args) } } - + } } // TCO loop } @@ -253,12 +252,11 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + repl_env.Set("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)))") @@ -270,13 +268,14 @@ func main() { for _, a := range os.Args[2:] { args = append(args, a) } - repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + repl_env.Set("*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_env.Set("*ARGV*", List{}) // repl loop for { diff --git a/impls/go/src/step8_macros/step8_macros.go b/impls/go/src/step8_macros/step8_macros.go index 762dcaf374..4d4fa19d45 100644 --- a/impls/go/src/step8_macros/step8_macros.go +++ b/impls/go/src/step8_macros/step8_macros.go @@ -67,67 +67,37 @@ func quasiquote(ast MalType) MalType { } } -func is_macro_call(ast MalType, env EnvType) bool { - if List_Q(ast) { - slc, _ := GetSlice(ast) - if len(slc) == 0 { - return false - } - 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:]) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) if e != nil { return nil, e } + lst = append(lst, exp) } - return ast, nil + return lst, nil } -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func EVAL(ast MalType, env EnvType) (MalType, error) { + for { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -141,30 +111,10 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { return ast, nil - } -} - -func EVAL(ast MalType, env EnvType) (MalType, error) { - 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) - } - + } else { // apply list - ast, e = macroexpand(ast, env) - if e != nil { - return nil, e - } - if !List_Q(ast) { - return eval_ast(ast, env) - } if len(ast.(List).Val) == 0 { return ast, nil } @@ -193,7 +143,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -211,14 +161,12 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env case "quote": return a1, nil - case "quasiquoteexpand": - return quasiquote(a1), nil case "quasiquote": ast = quasiquote(a1) case "defmacro!": @@ -227,12 +175,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil - case "macroexpand": - return macroexpand(a1, env) + return env.Set(a1.(Symbol).Val, fn), nil case "do": lst := ast.(List).Val - _, e := eval_ast(List{lst[1 : len(lst)-1], nil}, env) + _, e := map_eval(lst[1 : len(lst)-1], env) if e != nil { return nil, e } @@ -258,15 +204,27 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} return fn, nil default: - el, e := eval_ast(ast, env) + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + if MalFunc_Q(f) && f.(MalFunc).GetMacro() { + new_ast, e := Apply(f.(MalFunc), args) + if e != nil { + return nil, e + } + ast = new_ast + continue + } + args, e = map_eval(args, 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}) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) if e != nil { return nil, e } @@ -275,10 +233,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) + return fn.Fn(args) } } - + } } // TCO loop } @@ -309,12 +267,11 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + repl_env.Set("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)))") @@ -327,13 +284,14 @@ func main() { for _, a := range os.Args[2:] { args = append(args, a) } - repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + repl_env.Set("*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_env.Set("*ARGV*", List{}) // repl loop for { diff --git a/impls/go/src/step9_try/step9_try.go b/impls/go/src/step9_try/step9_try.go index ddc8a77435..8651364d00 100644 --- a/impls/go/src/step9_try/step9_try.go +++ b/impls/go/src/step9_try/step9_try.go @@ -67,67 +67,37 @@ func quasiquote(ast MalType) MalType { } } -func is_macro_call(ast MalType, env EnvType) bool { - if List_Q(ast) { - slc, _ := GetSlice(ast) - if len(slc) == 0 { - return false - } - 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:]) +func map_eval(xs []MalType, env EnvType) ([]MalType, error) { + lst := []MalType{} + for _, a := range xs { + exp, e := EVAL(a, env) if e != nil { return nil, e } + lst = append(lst, exp) } - return ast, nil + return lst, nil } -func eval_ast(ast MalType, env EnvType) (MalType, error) { - //fmt.Printf("eval_ast: %#v\n", ast) +func EVAL(ast MalType, env EnvType) (MalType, error) { + for { + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } + 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) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") } - 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) + lst, e := map_eval(ast.(Vector).Val, env) + if e != nil { + return nil, e } return Vector{lst, nil}, nil } else if HashMap_Q(ast) { @@ -141,30 +111,10 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) { new_hm.Val[k] = kv } return new_hm, nil - } else { + } else if !List_Q(ast) { return ast, nil - } -} - -func EVAL(ast MalType, env EnvType) (MalType, error) { - 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) - } - + } else { // apply list - ast, e = macroexpand(ast, env) - if e != nil { - return nil, e - } - if !List_Q(ast) { - return eval_ast(ast, env) - } if len(ast.(List).Val) == 0 { return ast, nil } @@ -193,7 +143,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -211,14 +161,12 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env case "quote": return a1, nil - case "quasiquoteexpand": - return quasiquote(a1), nil case "quasiquote": ast = quasiquote(a1) case "defmacro!": @@ -227,9 +175,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil - case "macroexpand": - return macroexpand(a1, env) + return env.Set(a1.(Symbol).Val, fn), nil case "try*": var exc MalType exp, e := EVAL(a1, env) @@ -260,7 +206,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { } case "do": lst := ast.(List).Val - _, e := eval_ast(List{lst[1 : len(lst)-1], nil}, env) + _, e := map_eval(lst[1 : len(lst)-1], env) if e != nil { return nil, e } @@ -286,15 +232,27 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { fn := MalFunc{EVAL, a2, env, a1, false, NewEnv, nil} return fn, nil default: - el, e := eval_ast(ast, env) + f, e := EVAL(a0, env) + if e != nil { + return nil, e + } + args := ast.(List).Val[1:] + if MalFunc_Q(f) && f.(MalFunc).GetMacro() { + new_ast, e := Apply(f.(MalFunc), args) + if e != nil { + return nil, e + } + ast = new_ast + continue + } + args, e = map_eval(args, 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}) + env, e = NewEnv(fn.Env, fn.Params, List{args, nil}) if e != nil { return nil, e } @@ -303,10 +261,10 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if !ok { return nil, errors.New("attempt to call non-function") } - return fn.Fn(el.(List).Val[1:]) + return fn.Fn(args) } } - + } } // TCO loop } @@ -337,12 +295,11 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + repl_env.Set("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)))") @@ -355,13 +312,14 @@ func main() { for _, a := range os.Args[2:] { args = append(args, a) } - repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + repl_env.Set("*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_env.Set("*ARGV*", List{}) // repl loop for { diff --git a/impls/go/src/stepA_mal/stepA_mal.go b/impls/go/src/stepA_mal/stepA_mal.go index 2ff77563c9..72484c1d7d 100644 --- a/impls/go/src/stepA_mal/stepA_mal.go +++ b/impls/go/src/stepA_mal/stepA_mal.go @@ -81,10 +81,19 @@ func map_eval(xs []MalType, env EnvType) ([]MalType, error) { func EVAL(ast MalType, env EnvType) (MalType, error) { for { - //fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + + env_val, env_found := env.Get("DEBUG-EVAL") + if env_found && env_val != nil && env_val != false { + fmt.Printf("EVAL: %v\n", printer.Pr_str(ast, true)) + } if Symbol_Q(ast) { - return env.Get(ast.(Symbol)) + env_val, env_found := env.Get(ast.(Symbol).Val) + if env_found { + return env_val, nil + } else { + return nil, errors.New("'" + ast.(Symbol).Val + "' not found") + } } else if Vector_Q(ast) { lst, e := map_eval(ast.(Vector).Val, env) if e != nil { @@ -134,7 +143,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), res), nil + return env.Set(a1.(Symbol).Val, res), nil case "let*": let_env, e := NewEnv(env, nil, nil) if e != nil { @@ -152,7 +161,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - let_env.Set(arr1[i].(Symbol), exp) + let_env.Set(arr1[i].(Symbol).Val, exp) } ast = a2 env = let_env @@ -166,7 +175,7 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { if e != nil { return nil, e } - return env.Set(a1.(Symbol), fn), nil + return env.Set(a1.(Symbol).Val, fn), nil case "try*": var exc MalType exp, e := EVAL(a1, env) @@ -286,12 +295,11 @@ func rep(str string) (MalType, error) { 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(k, Func{v.(func([]MalType) (MalType, error)), nil}) } - repl_env.Set(Symbol{"eval"}, Func{func(a []MalType) (MalType, error) { + repl_env.Set("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\")") @@ -305,13 +313,14 @@ func main() { for _, a := range os.Args[2:] { args = append(args, a) } - repl_env.Set(Symbol{"*ARGV*"}, List{args, nil}) + repl_env.Set("*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_env.Set("*ARGV*", List{}) // repl loop rep("(println (str \"Mal [\" *host-language* \"]\"))") diff --git a/impls/go/src/types/types.go b/impls/go/src/types/types.go index 9d4cb10b5f..1296531729 100644 --- a/impls/go/src/types/types.go +++ b/impls/go/src/types/types.go @@ -21,9 +21,8 @@ type MalType interface { } type EnvType interface { - Find(key Symbol) EnvType - Set(key Symbol, value MalType) MalType - Get(key Symbol) (MalType, error) + Set(key string, value MalType) MalType + Get(key string) (MalType, bool) } // Scalars diff --git a/impls/latex3/env.sty b/impls/latex3/env.sty index f1a5f42adc..9bb52355b0 100644 --- a/impls/latex3/env.sty +++ b/impls/latex3/env.sty @@ -54,8 +54,6 @@ { #4 } } } -% This one is useful for macroexpand, but may disappear once it is removed. -\cs_generate_variant:Nn \mal_env_get:NnTF { NxTF } \cs_new:Nn \mal_env_get:NnT { \mal_env_get:NnTF #1 { #2 } { #3 } { } } \cs_new:Nn \mal_env_get:NnF { \mal_env_get:NnTF #1 { #2 } { } { #3 } } \cs_generate_variant:Nn \mal_env_get:NnT { NVT }