Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 8 additions & 13 deletions docs/step_notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Step Notes:
- add <lang>_STEP_TO_PROG entry
- add <lang>_RUNSTEP entry
- for a compiled language, add <lang>/Makefile
- targets: all, step*, stats, stats-lisp,
- targets: all, step*, stats, stats-lisp,

- use native eval in EVAL if available

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -409,4 +405,3 @@ Step Notes:
- convert returned data to mal data
- recursive, similar to pr_str
- Details:

2 changes: 0 additions & 2 deletions impls/chuck/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`?
Expand Down
24 changes: 8 additions & 16 deletions impls/go/src/env/env.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package env

import (
"errors"
//"fmt"
)

Expand Down Expand Up @@ -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
}
95 changes: 46 additions & 49 deletions impls/go/src/step2_eval/step2_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand Down
Loading
Loading