Finally solves the missing panic on return issue for builtins, not pretty though. Refactor soon.

master
sloum 2 years ago
parent 17fcb17336
commit acd697ecc1

@ -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
}

Loading…
Cancel
Save