public Handle evalExpression(Handle node) throws TypeException, RecoverableException {
        Check.notNull(node, "node");

//#if defined( DEBUG) && DEBUG > 2
//  std::cerr << "SimpleEvaluator::evalExpression: ";
//  printList( node, std::cerr);
//  std::cerr << std::endl;
//#endif
//
        // The car cell of the first node either contains a lambda
        // expression or a symbol which refers to some executable node type.
        // In both cases the first node needs to be evaluated before application.
        Handle expr = eval(node.car());
        if (null == expr) {
            throw new RecoverableException("SimpleEvaluator::evalExpression: eval returned (null)");
        }

        if (expr.checkFlag(Handle.SPECIALFLAG)) {
            // Handle specials (don't evaluate arguments before call)

            if (expr.hasType(Handle.NodeType.CFUNC)) {
                // --- apply builtin special form
                final SpecialValue cmd = (SpecialValue) expr.typeImpl();
                assert null != cmd;
                return cmd.execute(ctx, envStack.peek(), node);
            }

        } else {
    // Handle standard s-expression: evaluate arguments before calling

            // step 1: collect arguments
            final List<Handle> argsTmp = new ArrayList<>();   //std::vector<Handle_ptr> args;

            if (eq(node.cdr(), ctx.NIL)) {
                LOG.debug("nil argument list");
            }

            for (Handle arg = node.cdr(); !eq(arg, ctx.NIL); arg = arg.cdr()) {
                argsTmp.add(eval(arg.car()));
            }

            final Handle[] args = argsTmp.toArray(new Handle[argsTmp.size()]);

            //}
//    #if defined( DEBUG) && DEBUG > 2
//        std::cerr << "collected " << args.size() << " arguments" << std::endl;
//    #endif
            LOG.debug("collected {} arguments", Integer.valueOf(argsTmp.size()));

            // step 2: execute function with the arguments collected before
            if (expr.hasType(Handle.NodeType.CFUNC)) {
                // --- apply builtin
                BuiltinValue cmd = (BuiltinValue) expr.typeImpl(); //dynamic_cast<BuiltinValue*>( expr->typeImpl());
                assert null != cmd;
                //return cmd->execute( m_ctx, m_envStack.top(), args);
                return cmd.execute(ctx, envStack.peek(), args);

            } else if (expr.hasType(Handle.NodeType.CLOSURE)) {
      // --- apply closure
                // a: push new binding environment and add arguments to it
                pushEnvironment(expr.bindArguments(args));

//#if defined( DEBUG) && DEBUG > 2
//      std::cerr << "closure body: ";
//      printList( expr->body(), std::cerr);
//      std::cerr << std::endl;
//#endif
                // b: call eval on the closure's body
                Handle retval = null;

                for (Handle pos = expr.body(); !eq(pos, ctx.NIL); pos = pos.cdr()) {
                    retval = eval(pos.car());
                }

                popEnvironment();

      //MCAssert( 0 != retval, "invalid lambda application");
                return retval;

            } else if (expr.hasType(Handle.NodeType.OBJECT)) {
      // --- message sending
                //MISSING: object implementation, need to create a good design first
                return ctx.NIL;

            } else {
                throw new RecoverableException("invalid expression type");
            }
        }

        throw new UnsupportedOperationException("undefined state in evaluator");
    }