maybe overthinking, but i cant shake the feeling that w bytecode macros you can write a lisp with very few 'special forms' here's a fairly complete sketch of an implementation of if. i think the only special forms would be anything that does name binding (e.g. let, fn, def) #jn
given an expression's arguments you need to answer two questions: what is its type, and what bytecode does it expand to? this gets particularly tricky when implementing 'operators'. bytecode is e.g. mul for primitives, but method invocation for other value types.