LValue *l_eval_var_node(LNode *node, LClosure *closure) { LValue *value = l_closure_get(closure, node->val); if(value != NULL) { return value; } else { value = l_value_new(L_ERR_TYPE, closure); value->core.str = make_stringbuf(node->val); buffer_concat(value->core.str, " not found"); l_handle_error(value, node, closure); return value; } }
LValue *l_eval_call_node(LNode *node, LValue *func, LClosure *closure) { if(func == NULL) func = l_eval_var_node(node, closure); char *name = (node != NULL) ? node->val : ""; LValue *value, *args_val; LNode *expr; int i; // create a running scope to hold arguments // and a reference to self (for recursion) // TODO this may not be necessary (can't we just do `cl=func->core.func.closure`?) LClosure *cl = l_closure_clone(func->core.func.closure, node); tail_loop: l_debug(L_DEBUG_CALL) { if(node) printf(">>> entering %s on line %d in %s\n", name, node->line_no, node->source_file); else printf(">>> entering %s\n", name); } if(strcmp(name, "") != 0) l_closure_set(cl, name, func, true); args_val = l_eval_call_args(node, func, closure, cl); if(func->core.func.ptr != NULL) { // native C code if(!setjmp(cl->jmp)) { value = func->core.func.ptr(args_val, cl); } else { // function called longjmp to initiate a tail call l_debug(L_DEBUG_CALL) printf("^^^ reached end of %s (longjmp tail call)\n", name); node = NULL; func = l_closure_get(cl, "--tail-call--"); closure = cl; l_closure_backfill(func->core.func.closure, cl, node); name = ""; goto tail_loop; } } else { // Lydia code int exprc = func->core.func.exprc; if(exprc > 0) { // eval all but the last expression for(i=0; i<exprc-1; i++) { expr = func->core.func.exprs[i]; value = l_eval_node(expr, cl); } expr = func->core.func.exprs[exprc-1]; if(expr->type == L_CALL_TYPE) { // tail call l_debug(L_DEBUG_CALL) printf("^^^ reached end of %s (tail call)\n", name); node = expr; func = l_eval_var_node(node, cl); closure = cl; l_closure_backfill(func->core.func.closure, cl, node); name = node->val; goto tail_loop; } else { value = l_eval_node(expr, cl); } } else { value = l_value_new(L_NIL_TYPE, cl); } } l_closure_free(cl); l_debug(L_DEBUG_CALL) printf("<<< returning from %s\n", name); return value; }