void call_lambda_from_ffi(ffi_cif *cif, void *ret, void* args[], LambdaAndItsType *lambda_and_its_type) { //printf("Calling lambda %s from ffi function!\n", obj_to_string(lambda_and_its_type->lambda)->s); int arg_count = cif->nargs; //printf("arg count: %d\n", arg_count); Obj **obj_args = malloc(sizeof(Obj*) * arg_count); //Obj *obj_args[arg_count]; Obj *lambda_type_signature = lambda_and_its_type->signature; // TODO: shadow stack?! Obj *lambda_return_type = lambda_type_signature->cdr->cdr->car; Obj *lambda_arg_type_list_p = lambda_type_signature->cdr->car; //printf("Lambda signature: %s\n", obj_to_string(lambda_type_signature)->s); Process *process = lambda_and_its_type->process; for(int i = 0; i < arg_count; i++) { Obj *lambda_arg_type_p = lambda_arg_type_list_p->car; if(!lambda_arg_type_p) { printf("Too many arguments (%d) sent to lambda with signature: %s\n", arg_count, obj_to_string(process, lambda_type_signature)->s); eval_error = obj_new_string("Too many args."); return; } // Unwrap ref args if(lambda_arg_type_p->tag == 'C' && lambda_arg_type_p->car && lambda_arg_type_p->cdr && lambda_arg_type_p->cdr->car && obj_eq(process, lambda_arg_type_p->car, obj_new_keyword("ref"))) { lambda_arg_type_p = lambda_arg_type_p->cdr->car; // the second element of the list } //printf("Lambda arg p: %s\n", obj_to_string(lambda_arg_type_p)->s); if(cif->arg_types[i] == &ffi_type_sint) { int *x = args[i]; obj_args[i] = obj_new_int(*x); } else if(cif->arg_types[i] == &ffi_type_float) { float *x = args[i]; obj_args[i] = obj_new_float(*x); } else if(cif->arg_types[i] == &ffi_type_double) { double *x = args[i]; obj_args[i] = obj_new_double(*x); } else if(cif->arg_types[i] == &ffi_type_schar) { char *x = args[i]; obj_args[i] = obj_new_char(*x); } else { if(obj_eq(process, lambda_arg_type_p, type_string)) { char **x = args[i]; assert(*x); char *new_s = strdup(*x); //printf("new_s: %s\n", new_s); obj_args[i] = obj_new_string(new_s); } else { //printf("Lambda called from ffi with arg %d of type %s\n", i, obj_to_string(lambda_arg_type_p)->s); /* printf("Can't handle arg type %p when calling ffi function.\n", cif->arg_types[i]); */ /* set_error("FFI function failed to call lambda: ", lambda_and_its_type->lambda); */ /* return; */ void **ptr = args[i]; obj_args[i] = obj_new_ptr(*ptr); } } //printf("arg %d: %s\n", i, obj_to_string(obj_args[i])->s); lambda_arg_type_list_p = lambda_arg_type_list_p->cdr; //shadow_stack_push(obj_args[i]); } apply(process, lambda_and_its_type->lambda, obj_args, cif->nargs); Obj *result = stack_pop(process); free(obj_args); // unwrap ref if(lambda_return_type->tag == 'C' && lambda_return_type->car && lambda_return_type->cdr && lambda_return_type->cdr->car && obj_eq(process, lambda_return_type->car, obj_new_keyword("ref"))) { lambda_return_type = lambda_return_type->cdr->car; // the second element of the list } // TODO: extract this and refactor to common helper function if(obj_eq(process, lambda_return_type, type_int)) { assert_or_set_error(result->tag == 'I', "Invalid type of return value: ", result); int *integer = ret; *integer = result->i; } else if(obj_eq(process, lambda_return_type, type_bool)) { assert_or_set_error(result->tag == 'Y', "Invalid type of return value ", result); bool b = is_true(result); bool *boolean = ret; *boolean = b; } else if(obj_eq(process, lambda_return_type, type_char)) { assert_or_set_error(result->tag == 'T', "Invalid type of return value ", result); char c = result->character; char *character = ret; *character = c; } else if(obj_eq(process, lambda_return_type, type_float)) { assert_or_set_error(result->tag == 'V', "Invalid type of return value ", result); float *x = ret; *x = result->f32; } else if(obj_eq(process, lambda_return_type, type_double)) { assert_or_set_error(result->tag == 'W', "Invalid type of return value ", result); double *x = ret; *x = result->f64; } else if(obj_eq(process, lambda_return_type, type_string)) { assert_or_set_error(result->tag == 'S', "Invalid type of return value ", result); char **s = ret; *s = result->s; } else if(obj_eq(process, lambda_return_type, type_void)) { } else { //set_error("Calling lambda from FFI can't handle return type ", lambda_return_type); assert_or_set_error(result->tag == 'Q', "Invalid type of return value ", result); void **p = ret; *p = result->void_ptr; } /* for(int i = 0; i < arg_count; i++) { */ /* shadow_stack_pop(process); */ /* } */ }
void call_struct_constructor(Process *process, Obj *function, Obj **args, int arg_count) { // Evaluation of a struct-definition (a dictionary) in function position (which means that it is used as a constructor) Obj *name_obj = env_lookup(process, function, obj_new_keyword("name")); assert_or_set_error(name_obj, "no key 'name' on struct definition: ", function); char *name = name_obj->s; Obj *struct_size_obj = env_lookup(process, function, obj_new_keyword("size")); assert_or_set_error(struct_size_obj, "no key 'size' on struct definition: ", function); int struct_size = struct_size_obj->i; Obj *struct_member_count_obj = env_lookup(process, function, obj_new_keyword("member-count")); assert_or_set_error(struct_member_count_obj, "no key 'member-count' on struct definition: ", function); int member_count = struct_member_count_obj->i; Obj *offsets_obj = env_lookup(process, function, obj_new_keyword("member-offsets")); assert_or_set_error(offsets_obj, "no key 'member-offsets' on struct definition: ", function); assert_or_set_error(offsets_obj->tag == 'A', "offsets must be an array: ", function); Obj **offsets = offsets_obj->array; Obj *member_types_obj = env_lookup(process, function, obj_new_keyword("member-types")); assert_or_set_error(member_types_obj, "no key 'member-types' on struct definition: ", function); assert_or_set_error(member_types_obj->tag == 'A', "member-types must be an array: ", function); Obj **member_types = member_types_obj->array; //printf("Will create a %s of size %d and member count %d.\n", name, size, member_count); void *p = malloc(struct_size); Obj *new_struct = obj_new_ptr(p); shadow_stack_push(process, new_struct); if(!new_struct->meta) { new_struct->meta = obj_new_environment(NULL); } env_assoc(process, new_struct->meta, obj_new_keyword("type"), obj_new_keyword(name)); assert_or_set_error(!(arg_count < member_count), "Too few args to struct constructor: ", obj_new_string(name)); assert_or_set_error(!(arg_count > member_count), "Too many args to struct constructor: ", obj_new_string(name)); for(int i = 0; i < arg_count; i++) { Obj *member_type = member_types[i]; int offset = offsets[i]->i; if(args[i]->tag == 'V') { assert_or_set_error(obj_eq(process, member_type, type_float), "Can't assign float to a member of type ", obj_to_string(process, member_type)); float *fp = (float *)(((char *)new_struct->void_ptr) + offset); float f = args[i]->f32; //printf("Setting member %d at offset %d to %f.\n", i, offset, f); *fp = f; } else if(args[i]->tag == 'I') { assert_or_set_error(obj_eq(process, member_type, type_int), "Can't assign int to a member of type ", obj_to_string(process, member_type)); int *xp = (int *)(((char *)new_struct->void_ptr) + offset); int x = args[i]->i; *xp = x; } else if(args[i]->tag == 'B') { assert_or_set_error(obj_eq(process, member_type, type_bool), "Can't assign bool to a member of type ", obj_to_string(process, member_type)); bool *xp = (bool *)(((char *)new_struct->void_ptr) + offset); bool x = args[i]->boolean; *xp = x; } else if(args[i]->tag == 'Q') { assert_or_set_error(!obj_eq(process, member_type, type_char), "Can't assign char to a member of type ", obj_to_string(process, member_type)); assert_or_set_error(!obj_eq(process, member_type, type_int), "Can't assign int to a member of type ", obj_to_string(process, member_type)); assert_or_set_error(!obj_eq(process, member_type, type_float), "Can't assign float to a member of type ", obj_to_string(process, member_type)); assert_or_set_error(!obj_eq(process, member_type, type_string), "Can't assign string to a member of type ", obj_to_string(process, member_type)); void **vp = (void **)(((char *)new_struct->void_ptr) + offset); *vp = args[i]->void_ptr; } else if(args[i]->tag == 'S') { assert_or_set_error(obj_eq(process, member_type, type_string), "Can't assign int to a member of type ", obj_to_string(process, member_type)); char **sp = (char **)(((char *)new_struct->void_ptr) + offset); *sp = strdup(args[i]->s); // must strdup or the struct will ref Obj's on the stack that will get gc:ed } else if(args[i]->tag == 'T') { assert_or_set_error(obj_eq(process, member_type, type_char), "Can't assign char to a member of type ", obj_to_string(process, member_type)); char *cp = (char *)(((char *)new_struct->void_ptr) + offset); *cp = args[i]->character; } else if(args[i]->tag == 'A') { //assert_or_set_error(obj_eq(member_type, type_array), "Can't assign array to a member of type ", obj_to_string(member_type)); // TODO: use this code for sending arrays to normal FFI functions too!!! // TODO: use the SAME code for sending data to FFI and struct constructors. // TODO: check that we send the expected type to the constructor Array *a = obj_array_to_carp_array(process, args[i]); if(!a) { return; } void **ap = (void **)(((char *)new_struct->void_ptr) + offset); *ap = a; } else { eval_error = obj_new_string("Can't set member "); char buffer[32]; sprintf(buffer, "%d", i); obj_string_mut_append(eval_error, buffer); obj_string_mut_append(eval_error, " of struct "); obj_string_mut_append(eval_error, name); obj_string_mut_append(eval_error, " to "); obj_string_mut_append(eval_error, obj_to_string(process, args[i])->s); obj_string_mut_append(eval_error, " (handled type)."); return; } } shadow_stack_pop(process); // pop new_struct stack_push(process, new_struct); }
Process *process_new() { Process *process = malloc(sizeof(Process)); process->dead = false; process->final_result = NULL; #if BYTECODE_EVAL process->frame = 0; #else process->frame = -1; #endif process->bytecodeObj = NULL; pop_stacks_to_zero(process); process->global_env = obj_new_environment(NULL); nil = obj_new_cons(NULL, NULL); define("nil", nil); lisp_false = obj_new_bool(false); define("false", lisp_false); lisp_true = obj_new_bool(true); define("true", lisp_true); lisp_quote = obj_new_symbol("quote"); define("quote", lisp_quote); ampersand = obj_new_symbol("&"); define("&", ampersand); dotdotdot = obj_new_symbol("dotdotdot"); define("dotdotdot", dotdotdot); hash = obj_new_keyword("hash"); define("hash", hash); lisp_NULL = obj_new_ptr(NULL); define("NULL", lisp_NULL); type_ref = obj_new_keyword("ref"); define("type_ref", type_ref); type_int = obj_new_keyword("int"); define("type-int", type_int); // without this it will get GC'd! type_bool = obj_new_keyword("bool"); define("type-bool", type_bool); type_float = obj_new_keyword("float"); define("type-float", type_float); type_double = obj_new_keyword("double"); define("type-double", type_double); type_string = obj_new_keyword("string"); define("type-string", type_string); type_symbol = obj_new_keyword("symbol"); define("type-symbol", type_symbol); type_keyword = obj_new_keyword("keyword"); define("type-keyword", type_keyword); type_foreign = obj_new_keyword("foreign"); define("type-foreign", type_foreign); type_primop = obj_new_keyword("primop"); define("type-primop", type_primop); type_env = obj_new_keyword("env"); define("type-env", type_env); type_macro = obj_new_keyword("macro"); define("type-macro", type_macro); type_lambda = obj_new_keyword("lambda"); define("type-lambda", type_lambda); type_list = obj_new_keyword("list"); define("type-list", type_list); type_void = obj_new_keyword("void"); define("type-void", type_void); type_ptr = obj_new_keyword("ptr"); define("type-ptr", type_ptr); type_char = obj_new_keyword("char"); define("type-char", type_char); type_array = obj_new_keyword("array"); define("type-array", type_array); type_ptr_to_global = obj_new_keyword("ptr-to-global"); define("type-ptr-to-global", type_ptr_to_global); prompt = define("prompt", obj_new_string(PROMPT)); prompt_unfinished_form = define("prompt-unfinished-form", obj_new_string(PROMPT_UNFINISHED_FORM)); register_primop(process, "open", p_open_file); register_primop(process, "save", p_save_file); register_primop(process, "+", p_add); register_primop(process, "-", p_sub); register_primop(process, "*", p_mul); register_primop(process, "/", p_div); //register_primop(process, "mod", p_mod); register_primop(process, "=", p_eq); register_primop(process, "list", p_list); register_primop(process, "array", p_array); register_primop(process, "dictionary", p_dictionary); register_primop(process, "str", p_str); register_primop(process, "str-append!", p_str_append_bang); register_primop(process, "str-replace", p_str_replace); register_primop(process, "join", p_join); register_primop(process, "register", p_register); register_primop(process, "register-variable", p_register_variable); register_primop(process, "register-builtin", p_register_builtin); register_primop(process, "print", p_print); register_primop(process, "println", p_println); register_primop(process, "prn", p_prn); register_primop(process, "def?", p_def_QMARK); //register_primop(process, "system", p_system); register_primop(process, "get", p_get); register_primop(process, "get-maybe", p_get_maybe); register_primop(process, "dict-set!", p_dict_set_bang); register_primop(process, "dict-remove!", p_dict_remove_bang); register_primop(process, "first", p_first); register_primop(process, "rest", p_rest); register_primop(process, "cons", p_cons); register_primop(process, "cons-last", p_cons_last); register_primop(process, "concat", p_concat); register_primop(process, "nth", p_nth); register_primop(process, "count", p_count); register_primop(process, "map", p_map); register_primop(process, "map-copy", p_map); // only matters when compiling to C register_primop(process, "map2", p_map2); register_primop(process, "filter", p_filter); register_primop(process, "reduce", p_reduce); register_primop(process, "apply", p_apply); register_primop(process, "type", p_type); register_primop(process, "<", p_lt); register_primop(process, "env", p_env); register_primop(process, "load-lisp", p_load_lisp); register_primop(process, "load-dylib", p_load_dylib); register_primop(process, "unload-dylib", p_unload_dylib); register_primop(process, "read", p_read); register_primop(process, "read-many", p_read_many); register_primop(process, "code", p_code); register_primop(process, "copy", p_copy); register_primop(process, "now", p_now); register_primop(process, "name", p_name); register_primop(process, "symbol", p_symbol); register_primop(process, "keyword", p_keyword); register_primop(process, "error", p_error); register_primop(process, "keys", p_keys); register_primop(process, "values", p_values); register_primop(process, "signature", p_signature); register_primop(process, "eval", p_eval); register_primop(process, "meta-set!", p_meta_set_BANG); register_primop(process, "meta-get", p_meta_get); register_primop(process, "meta-get-all", p_meta_get_all); register_primop(process, "array-to-list", p_array_to_list); register_primop(process, "array-of-size", p_array_of_size); register_primop(process, "array-set!", p_array_set_BANG); register_primop(process, "array-set", p_array_set); register_primop(process, "gc", p_gc); register_primop(process, "hash", p_hash); register_primop(process, "delete", p_delete); register_primop(process, "stop", p_stop); register_primop(process, "parallell", p_parallell); register_primop(process, "bytecode", p_bytecode); register_primop(process, "eval-bytecode", p_bytecode_eval); register_primop(process, "lookup-in-substs-fast", p_lookup_in_substs_fast); register_primop(process, "replace-subst-from-right-fast", p_replace_subst_from_right_fast); register_primop(process, "types-exactly-eq?", p_types_exactly_eq); register_primop(process, "extend-substitutions-fast", p_extend_substitutions_fast); register_primop(process, "sort-by-fast", p_sort_by); Obj *abs_args = obj_list(type_int); register_ffi_internal(process, "abs", (VoidFn)abs, abs_args, type_int, true); Obj *exit_args = obj_list(type_int); register_ffi_internal(process, "exit", (VoidFn)exit, exit_args, type_void, true); Obj *getenv_args = obj_list(type_string); register_ffi_internal(process, "getenv", (VoidFn)getenv, getenv_args, type_string, true); //printf("Global env: %s\n", obj_to_string(env)->s); return process; }