func apply(fn, x, a Addr) Addr {
if atom(fn) == T {
switch fn {
case CAR:
return caar(x)
case CDR:
return cdar(x)
case CONS:
return cons(car(x), cadr(x))
case ATOM:
return atom(car(x))
case EQ:
return eq(car(x), cadr(x))
default:
return apply(eval(fn, a), x, a)
}
}
switch car(fn) {
case LAMBDA:
return eval(caddr(fn), pairlis(cadr(fn), x, a))
case LABEL:
return apply(caddr(fn), x, cons(cons(cadr(fn), caddr(fn)), a))
}
panic(errint("bad node: " + car(fn).String()))
}
On the perf side: I'm curious to know where Go sits now relative to C assuming you elide away all heap allocations in your inner loops. In the early days Go's codegen was based on plan9's simple and simplistic C compiler's back end. Things have gotten much better since then and to my knowledge it's within striking distance of C. But I could be wrong.