// File: /workspace/github_c_makefile_star2_O2/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, 0x8(%rsp)
movl 0x28(%rsi), %ebx
cmpl $0xe, %ebx
ja 0x23e0
movl $0x500e, %eax           # imm = 0x500E
btl %ebx, %eax
jae 0x23e0
movq 0x30(%r15), %r12
movq %r12, %rdi
callq 0x1080
movq %rax, %r13
movq %rbp, %r14
testq %r14, %r14
je 0x2290
movq 0x8(%r14), %rdi
movq %r12, %rsi
movq %r13, %rdx
callq 0x293c
testq %rax, %rax
jne 0x22d5
movq 0x10(%r14), %rdi
movq %r12, %rsi
movq %r13, %rdx
callq 0x293c
testq %rax, %rax
jne 0x2300
movq 0x18(%r14), %rdi
movq %r12, %rsi
movq %r13, %rdx
callq 0x293c
testq %rax, %rax
jne 0x23bb
movq (%r14), %r14
jmp 0x2242
leaq 0x20(%rsp), %rbx
xorl %r15d, %r15d
movl $0x200, %edx            # imm = 0x200
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10d0
leaq 0x224e(%rip), %rdx      # 0x44fc
movl $0x200, %esi            # imm = 0x200
movq %rbx, %rdi
movq %r12, %rcx
xorl %eax, %eax
callq 0x10b0
pushq $0x2
popq %rsi
movq 0x8(%rsp), %rdi
movq %rbx, %rdx
callq 0x15d8
jmp 0x2467
movq %rax, %rbx
movl (%rax), %esi
movq 0x8(%rsp), %r14
movq %r14, %rdi
movq %r15, %rdx
movq %rbp, %rcx
callq 0x25f4
movl (%rbx), %esi
movq %r14, %rdi
movq %rax, %rdx
callq *0x10(%rbx)
movq %rax, %r15
jmp 0x2467
movq 0x20(%rbp), %r14
movq %rax, 0x20(%rbp)
movq 0x8(%rax), %rbx
xorl %r13d, %r13d
movq %rbx, %r12
cmpl $0x5, 0x28(%r12)
jne 0x2324
movq 0x8(%r12), %r12
incq %r13
jmp 0x2312
testl %r13d, %r13d
je 0x2450
movq %r14, 0x10(%rsp)
movq 0x8(%rsp), %r14
movq %r14, %rdi
movl %r13d, %esi
movq %r15, %rdx
movq %rbp, %rcx
callq 0x25f4
movq %rax, %r15
xorl %esi, %esi
testq %rax, %rax
setne %sil
leaq 0x221d(%rip), %rcx      # 0x4578
pushq $0x2
popq %rdx
movq %r14, %rdi
callq 0x15c8
movq %rbp, 0x18(%rsp)
movq %rbp, %rdi
callq 0x1ea5
movq %rax, %rbp
pushq $0x1
popq %r14
subq $0x1, %r13
jb 0x2429
xorl %esi, %esi
cmpl $0x5, 0x28(%rbx)
sete %sil
movq 0x8(%rsp), %rdi
movl %r14d, %edx
leaq 0x21e9(%rip), %rcx      # 0x4586
callq 0x15c8
movq 0x30(%rbx), %rsi
movq (%r15), %rdx
movq %rbp, %rdi
callq 0x247c
movq 0x8(%rbx), %rbx
addq $0x8, %r15
jmp 0x237a
movq 0x20(%rbp), %rbx
andq $0x0, 0x20(%rbp)
movq 0x8(%rsp), %rdi
movq %rax, %rsi
movq %rbp, %rdx
callq 0x21fa
movq %rax, %r15
movq %rbx, 0x20(%rbp)
jmp 0x2467
leaq 0x20(%rsp), %r14
movl $0x200, %edx            # imm = 0x200
movq %r14, %rdi
xorl %esi, %esi
callq 0x10d0
movl %ebx, %edi
callq 0x2a50
leaq 0x20db(%rip), %rdx      # 0x44dd
movl $0x200, %esi            # imm = 0x200
movq %r14, %rdi
movq %rax, %rcx
xorl %eax, %eax
callq 0x10b0
pushq $0x2
popq %rsi
movq 0x8(%rsp), %rdi
movq %r14, %rdx
callq 0x15d8
jmp 0x2230
movq 0x8(%rsp), %rdi
movq %r12, %rsi
movq %rbp, %rdx
callq 0x1eb9
movq %rax, %r15
movq %rbp, %rdi
callq 0x25c3
movq 0x18(%rsp), %rbp
movq 0x10(%rsp), %r14
jmp 0x2463
movq 0x8(%rsp), %rdi
movq %r12, %rsi
movq %rbp, %rdx
callq 0x1eb9
movq %rax, %r15
movq %r14, 0x20(%rbp)
movq %r15, %rax
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq