|
|
|
@ -29,12 +29,14 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
switch car, _ := e[0].(symbol); car {
|
|
|
|
|
case "quote":
|
|
|
|
|
if len(e) < 2 {
|
|
|
|
|
return exception("Invalid 'quote' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'quote' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
value = e[1]
|
|
|
|
|
case "if":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return exception("Invalid 'if' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'if' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if AnythingToBool(eval(e[1], en)).(bool) {
|
|
|
|
|
value = eval(e[2], en)
|
|
|
|
@ -45,7 +47,8 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
}
|
|
|
|
|
case "and":
|
|
|
|
|
if len(e) < 2 {
|
|
|
|
|
return exception("Invalid 'and' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'and' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
OuterAnd:
|
|
|
|
|
for i := range e[1:] {
|
|
|
|
@ -64,7 +67,8 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
}
|
|
|
|
|
case "or":
|
|
|
|
|
if len(e) < 2 {
|
|
|
|
|
return exception("Invalid 'or' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'or' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
OuterOr:
|
|
|
|
|
for i := range e[1:] {
|
|
|
|
@ -83,50 +87,60 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
}
|
|
|
|
|
case "cond":
|
|
|
|
|
if len(e) < 2 {
|
|
|
|
|
return exception("Invalid 'cond' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'cond' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
// CondLoop:
|
|
|
|
|
for _, exp := range e[1:] {
|
|
|
|
|
switch i := exp.(type) {
|
|
|
|
|
case []expression:
|
|
|
|
|
if len(i) < 2 {
|
|
|
|
|
return exception("Invalid 'cond' case, cases must take the form: `(<test> <expression>)")
|
|
|
|
|
value = exception("Invalid 'cond' case, cases must take the form: `(<test> <expression>)")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if i[0] == "else" || i[0] == symbol("else") {
|
|
|
|
|
return eval(i[1], en)
|
|
|
|
|
value = eval(i[1], en)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if AnythingToBool(eval(i[0], en)).(bool) {
|
|
|
|
|
return eval(i[1], en)
|
|
|
|
|
value = eval(i[1], en)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return exception("Invalid 'cond' case, cases must take the form: `(<test> <expression>)")
|
|
|
|
|
value = exception("Invalid 'cond' case, cases must take the form: `(<test> <expression>)")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
value = make([]expression, 0)
|
|
|
|
|
}
|
|
|
|
|
case "set!":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return exception("Invalid 'set!' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'set!' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
v, ok := e[1].(symbol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return exception("'set!' expected a symbol as its first argument, a non-symbol was provided")
|
|
|
|
|
value = exception("'set!' expected a symbol as its first argument, a non-symbol was provided")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
val := eval(e[2], en)
|
|
|
|
|
en.Find(v).vars[v] = val
|
|
|
|
|
value = val
|
|
|
|
|
case "define":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return exception("Invalid 'define' syntax - too few arguments")
|
|
|
|
|
value = exception("Invalid 'define' syntax - too few arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if _, ok := e[1].(symbol); !ok {
|
|
|
|
|
return exception("'define' expects a symbol as its first argument")
|
|
|
|
|
value = exception("'define' expects a symbol as its first argument")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
val := eval(e[2], en)
|
|
|
|
|
en.vars[e[1].(symbol)] = val
|
|
|
|
|
value = val
|
|
|
|
|
case "lambda", "λ":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return exception("'lambda' expects at least three arguments")
|
|
|
|
|
value = exception("'lambda' expects at least three arguments")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
b := []expression{symbol("begin")}
|
|
|
|
|
b = append(b, e[2:]...)
|
|
|
|
@ -159,13 +173,14 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Println(out.String())
|
|
|
|
|
return make([]expression, 0)
|
|
|
|
|
value = make([]expression, 0)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
proc, ok := e[1].(string)
|
|
|
|
|
if !ok {
|
|
|
|
|
p, ok2 := e[1].(symbol)
|
|
|
|
|
if !ok2 {
|
|
|
|
|
return exception("'usage' expected a string or symbol as its first argument, a non-string non-symbol value was given")
|
|
|
|
|
value = exception("'usage' expected a string or symbol as its first argument, a non-string non-symbol value was given")
|
|
|
|
|
}
|
|
|
|
|
proc = string(p)
|
|
|
|
|
}
|
|
|
|
@ -178,11 +193,13 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
value = make([]expression, 0)
|
|
|
|
|
case "load":
|
|
|
|
|
if en.outer != nil {
|
|
|
|
|
return expression("'load' is only callable from the global/top-level")
|
|
|
|
|
value = expression("'load' is only callable from the global/top-level")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
for _, fp := range e[1:] {
|
|
|
|
|
if _, ok := fp.(string); !ok {
|
|
|
|
|
return expression("'load' expects filepaths as a string, a non-string value was encountered")
|
|
|
|
|
value = expression("'load' expects filepaths as a string, a non-string value was encountered")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
loadFiles(e[1:])
|
|
|
|
@ -227,12 +244,14 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
value = symbol("ok")
|
|
|
|
|
case "filter":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return expression("'filter' expects two arguments: a procedure and an argument list, too few arguments were given")
|
|
|
|
|
value = expression("'filter' expects two arguments: a procedure and an argument list, too few arguments were given")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
proc := eval(e[1], en)
|
|
|
|
|
list, ok := eval(e[2], en).([]expression)
|
|
|
|
|
if !ok {
|
|
|
|
|
return expression("'filter' expects a list as its second argument, a non-list value was given")
|
|
|
|
|
value = expression("'filter' expects a list as its second argument, a non-list value was given")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
val := make([]expression, 0)
|
|
|
|
|
for i := range list {
|
|
|
|
@ -245,14 +264,15 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
value = val
|
|
|
|
|
case "apply":
|
|
|
|
|
if len(e) < 3 {
|
|
|
|
|
return expression("'apply' expects two arguments: a procedure and an argument list, too few arguments were given")
|
|
|
|
|
value = expression("'apply' expects two arguments: a procedure and an argument list, too few arguments were given")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
args := eval(e[2], en)
|
|
|
|
|
switch item := args.(type) {
|
|
|
|
|
case []expression:
|
|
|
|
|
return apply(eval(e[1], en), item)
|
|
|
|
|
value = apply(eval(e[1], en), item)
|
|
|
|
|
default:
|
|
|
|
|
return apply(eval(e[1], en), []expression{item})
|
|
|
|
|
value = apply(eval(e[1], en), []expression{item})
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
operands := e[1:]
|
|
|
|
@ -265,6 +285,10 @@ func eval(exp expression, en *env) (value expression) {
|
|
|
|
|
default:
|
|
|
|
|
panic("Unknown expression type encountered during EVAL")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if e, ok := value.(exception); panicOnException && ok {
|
|
|
|
|
panic(string(e))
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|