// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x480, %rsp            # imm = 0x480
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x3040
cmpl $0x0, %eax
jne 0x2ac4
leaq -0x220(%rbp), %rdi
xorl %esi, %esi
movl $0x200, %edx            # imm = 0x200
callq 0x10b0
leaq -0x220(%rbp), %rax
movq %rax, -0x478(%rbp)
movq -0x18(%rbp), %rax
movl 0x28(%rax), %edi
callq 0x3d10
movq -0x478(%rbp), %rdi
movq %rax, %rcx
movl $0x200, %esi            # imm = 0x200
leaq 0x39df(%rip), %rdx      # 0x6487
movb $0x0, %al
callq 0x1090
movq -0x10(%rbp), %rdi
leaq -0x220(%rbp), %rdx
movl $0x2, %esi
callq 0x1870
movq -0x18(%rbp), %rax
movq 0x30(%rax), %rax
movq %rax, -0x228(%rbp)
movq -0x18(%rbp), %rax
movq 0x30(%rax), %rdi
callq 0x1060
movq %rax, -0x230(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x238(%rbp)
cmpq $0x0, -0x238(%rbp)
je 0x2c75
movq -0x238(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x228(%rbp), %rsi
movq -0x230(%rbp), %rdx
callq 0x3a90
movq %rax, -0x240(%rbp)
cmpq $0x0, -0x240(%rbp)
je 0x2b50
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq -0x240(%rbp), %rcx
callq 0x3260
movq %rax, -0x8(%rbp)
jmp 0x2cc6
movq -0x238(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x228(%rbp), %rsi
movq -0x230(%rbp), %rdx
callq 0x3a90
movq %rax, -0x248(%rbp)
cmpq $0x0, -0x248(%rbp)
je 0x2bdb
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x250(%rbp)
movq -0x248(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x248(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x32c0
movq %rax, -0x258(%rbp)
movq -0x250(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x258(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x2cc6
movq -0x238(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x228(%rbp), %rsi
movq -0x230(%rbp), %rdx
callq 0x3a90
movq %rax, -0x260(%rbp)
cmpq $0x0, -0x260(%rbp)
je 0x2c5f
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x268(%rbp)
movq -0x248(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x10(%rbp), %rdi
movq -0x260(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x2a40
movq %rax, -0x270(%rbp)
movq -0x268(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x270(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x2cc6
movq -0x238(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x238(%rbp)
jmp 0x2af2
leaq -0x470(%rbp), %rdi
xorl %esi, %esi
movl $0x200, %edx            # imm = 0x200
callq 0x10b0
leaq -0x470(%rbp), %rdi
movq -0x228(%rbp), %rcx
movl $0x200, %esi            # imm = 0x200
leaq 0x3804(%rip), %rdx      # 0x64a6
movb $0x0, %al
callq 0x1090
movq -0x10(%rbp), %rdi
leaq -0x470(%rbp), %rdx
movl $0x2, %esi
callq 0x1870
movq $0x0, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x480, %rsp            # imm = 0x480
popq %rbp
retq
nopw %cs:(%rax,%rax)