}
void eval_call_expr(so_interpreter *interp, so_expr_call *call, so_expr *expr) {
+ void *function_handle = NULL;
+
+ for (int i = 0; i < interp->loaded_libraries; i++) {
+ function_handle = dlsym(interp->library_handles[i], call->name);
+ if (function_handle)
+ break;
+ }
+
+ if (!function_handle) {
+ fprintf(stderr, "error: could not find the function: %s\n", call->name);
+ free_ast(expr);
+ so_interpreter_deinit(interp);
+ exit(EXIT_FAILURE);
+ }
+
+ ffi_cif cif;
+
+ ffi_type **argument_types = malloc(sizeof(ffi_type *) * call->nargs);
+ void **argument_values = malloc(sizeof(void *) * call->nargs);
+
+ for (int i = 0; i < call->nargs; i++) {
+ if (call->args[i]->tag == SO_EXPR_INT) {
+ argument_types[i] = &ffi_type_sint;
+ argument_values[i] = &call->args[i]->as.number;
+ }
+
+ if (call->args[i]->tag == SO_EXPR_STRING) {
+ argument_types[i] = &ffi_type_pointer;
+ argument_values[i] = &call->args[i]->as.string;
+ }
+ }
+
+ ffi_status status = ffi_prep_cif(
+ &cif,
+ FFI_DEFAULT_ABI,
+ call->nargs,
+ &ffi_type_void,
+ argument_types);
+
+ if (status != FFI_OK) {
+ fprintf(stderr, "error: failed to prepare ffi call: %s\n", call->name);
+ free_ast(expr);
+ so_interpreter_deinit(interp);
+ free(argument_types);
+ free(argument_values);
+ exit(EXIT_FAILURE);
+ }
+
+ // At this point is to the caller to have provided the right arguments
+ ffi_call(&cif, function_handle, NULL, argument_values);
+
+ free(argument_types);
+ free(argument_values);
}