// File: /workspace/github_c_makefile_star2_O3/qpfiffer[P]lair/src/eval.c
// Function: lair_call_function
static const struct _lair_type *_lair_call_function(struct _lair_runtime *r, const struct _lair_ast *ast_node, struct _lair_env *env) {
	if (!_is_callable(ast_node)) {
		char buf[512] = {0};
		snprintf(buf, sizeof(buf), "Cannot call a non-function: %s", _friendly_enum(ast_node->atom.type));
		throw_exception(r, ERR_RUNTIME, buf);
	}
	/* Determine if the thing we're trying to call is a function
	 * or not. It might be an atom, in which case we need to check
	 * or function/c_function maps to see if it's in there.
	 */
	const char *func_name = ast_node->atom.value.str;
	const size_t func_len = strlen(ast_node->atom.value.str);

	struct _lair_env *cur_env = env;
	while (cur_env != NULL) {
		const struct _lair_function *builtin_function = _tst_map_get(cur_env->c_functions, func_name, func_len);
		if (builtin_function != NULL)
			return _lair_call_builtin(r, ast_node, env, builtin_function);

		/* Well if we're at this point this is a program-defined function. */
		const struct _lair_ast *defined_function_ast = _tst_map_get(cur_env->functions, func_name, func_len);
		if (defined_function_ast != NULL) {
			/* Don't call it a stack frame. */
			const struct _lair_ast *last_func = env->current_function;
			env->current_function = defined_function_ast;
			const struct _lair_type *value = _lair_call_runtime_function(r, ast_node, defined_function_ast, env);
			env->current_function = last_func;
			return value;
		}

		const struct _lair_ast *not_variable_ast = _tst_map_get(cur_env->not_variables, func_name, func_len);
		if (not_variable_ast != NULL) {
			const struct _lair_ast *last_func = env->current_function;
			env->current_function = defined_function_ast;
			const struct _lair_type *value = _lair_call_function(r, not_variable_ast, env);
			env->current_function = last_func;
			return value;
		}

		cur_env = (struct _lair_env *)cur_env->parent;
	}

	char buf[512] = {0};
	snprintf(buf, sizeof(buf), "No such function: %s", func_name);
	throw_exception(r, ERR_RUNTIME, buf);
	return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x228, %rsp            # imm = 0x228
movq %rdx, %rbp
movq %rsi, %r15
movq %rdi, %r14
movl 0x28(%rsi), %ebx
cmpl $0xe, %ebx
ja 0x23e9
movl $0x500e, %eax           # imm = 0x500E
btl %ebx, %eax
jae 0x23e9
movq %r14, (%rsp)
movq 0x30(%r15), %r12
movq %r12, %rdi
callq 0x1080
testq %rbp, %rbp
je 0x23a4
movq %rax, %rbx
movq %rbp, %r14
movq 0x8(%r14), %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x2a16
testq %rax, %rax
jne 0x2432
movq 0x10(%r14), %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x2a16
testq %rax, %rax
jne 0x245f
movq 0x18(%r14), %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x2a16
testq %rax, %rax
jne 0x2591
movq (%r14), %r14
testq %r14, %r14
jne 0x2354
leaq 0x20(%rsp), %r14
xorl %ebx, %ebx
movl $0x200, %edx            # imm = 0x200
movq %r14, %rdi
xorl %esi, %esi
callq 0x10d0
leaq 0x213b(%rip), %rdx      # 0x44fc
movl $0x200, %esi            # imm = 0x200
movq %r14, %rdi
movq %r12, %rcx
xorl %eax, %eax
callq 0x10b0
movq (%rsp), %rdi
movl $0x2, %esi
movq %r14, %rdx
callq 0x1630
jmp 0x25c4
leaq 0x20(%rsp), %r12
movl $0x200, %edx            # imm = 0x200
movq %r12, %rdi
xorl %esi, %esi
callq 0x10d0
movl %ebx, %edi
callq 0x2b4c
leaq 0x20d2(%rip), %rdx      # 0x44dd
movl $0x200, %esi            # imm = 0x200
movq %r12, %rdi
movq %rax, %rcx
xorl %eax, %eax
callq 0x10b0
movq %r14, %rdi
movl $0x2, %esi
movq %r12, %rdx
callq 0x1630
jmp 0x2339
movq %rax, %r13
movl (%rax), %esi
movq (%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rdx
movq %rbp, %rcx
callq 0x26dc
movl (%r13), %esi
movq %rbx, %rdi
movq %rax, %rdx
callq *0x10(%r13)
movq %rax, %rbx
jmp 0x25c4
movq 0x20(%rbp), %r14
movq %rax, 0x20(%rbp)
movq 0x8(%rax), %r12
cmpl $0x5, 0x28(%r12)
jne 0x25ae
movq %r14, 0x18(%rsp)
movq %rbp, 0x8(%rsp)
xorl %ebp, %ebp
movq %r12, %r13
movq (%rsp), %r14
movq 0x8(%r13), %r13
incq %rbp
cmpl $0x5, 0x28(%r13)
je 0x248a
movq %r14, %rdi
movl %ebp, %esi
movq %r15, %rdx
movq 0x8(%rsp), %rbx
movq %rbx, %rcx
callq 0x26dc
movq %rax, %r15
xorl %esi, %esi
testq %rax, %rax
setne %sil
leaq 0x20b8(%rip), %rcx      # 0x4578
movq %r14, %rdi
movl $0x2, %edx
callq 0x1608
movl $0x1, %edi
movl $0x30, %esi
callq 0x1130
movq %rbx, (%rax)
movq %rax, 0x10(%rsp)
movq %rax, %rbx
addq $0x18, %rbx
xorl %esi, %esi
cmpl $0x5, 0x28(%r12)
sete %sil
movq %r14, %rdi
movl $0x1, %edx
leaq 0x2080(%rip), %rcx      # 0x4586
callq 0x1608
movq 0x30(%r12), %r14
movq (%r15), %rax
movl (%rax), %ecx
movq 0x8(%rax), %rax
xorps %xmm0, %xmm0
movaps %xmm0, 0x40(%rsp)
movaps %xmm0, 0x30(%rsp)
movaps %xmm0, 0x20(%rsp)
movl %ecx, 0x48(%rsp)
movq %rax, 0x50(%rsp)
movq %r14, %rdi
callq 0x1080
movl $0x38, %r8d
movq %rbx, %rdi
movq %r14, %rsi
movq (%rsp), %r14
movq %rax, %rdx
leaq 0x20(%rsp), %rcx
callq 0x2910
movq 0x8(%r12), %r12
addq $0x8, %r15
decq %rbp
jne 0x24eb
movq %r14, %rdi
movq %r13, %rsi
movq 0x10(%rsp), %r14
movq %r14, %rdx
callq 0x1f71
movq %rax, %rbx
movq %r14, %rdi
callq 0x26ab
movq 0x8(%rsp), %rbp
movq 0x18(%rsp), %r14
jmp 0x25c0
movq 0x20(%rbp), %r14
movq $0x0, 0x20(%rbp)
movq (%rsp), %rdi
movq %rax, %rsi
movq %rbp, %rdx
callq 0x2305
jmp 0x25bd
movq (%rsp), %rdi
movq %r12, %rsi
movq %rbp, %rdx
callq 0x1f71
movq %rax, %rbx
movq %r14, 0x20(%rbp)
movq %rbx, %rax
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq