예제 #1
0
void obj_to_string_internal(Process *process, Obj *total, const Obj *o, bool prn, int indent) {
    assert(o);
    int x = indent;
    if(o->tag == 'C') {
        obj_string_mut_append(total, "(");
        x++;
        int save_x = x;
        const Obj *p = o;
        while(p && p->car) {
            obj_to_string_internal(process, total, p->car, true, x);
            if(p->cdr && p->cdr->tag != 'C') {
                obj_string_mut_append(total, " . ");
                obj_to_string_internal(process, total, o->cdr, true, x);
                break;
            }
            else if(p->cdr && p->cdr->car) {
                if(/* p->car->tag == 'C' ||  */ p->car->tag == 'E') {
                    obj_string_mut_append(total, "\n");
                    x = save_x;
                    add_indentation(total, x);
                }
                else {
                    obj_string_mut_append(total, " ");
                    x++;
                }
            }
            p = p->cdr;
        }
        obj_string_mut_append(total, ")");
        x++;
    }
    else if(o->tag == 'A') {
        //printf("Will print Obj Array with count %d\n", o->count);
        shadow_stack_push(process, (struct Obj *)o);
        x++;
        //int save_x = x;
        obj_string_mut_append(total, "[");
        for(int i = 0; i < o->count; i++) {
            obj_to_string_internal(process, total, o->array[i], true, x);
            if(i < o->count - 1) {
                /* if(o->array[i]->car->tag == 'Q' || o->array[i]->car->tag == 'E') { */
                /*   obj_string_mut_append(total, "\n"); */
                /*   x = save_x; */
                /*   add_indentation(total, x); */
                /* } */
                /* else { */
                /*   obj_string_mut_append(total, " "); */
                /*   x++; */
                /* } */
                obj_string_mut_append(total, " ");
            }
        }
        obj_string_mut_append(total, "]");
        shadow_stack_pop(process);
        x++;
    }
    else if(o->tag == 'E') {
        shadow_stack_push(process, (struct Obj *)o);

        if(o == process->global_env) {
            obj_string_mut_append(total, "{ GLOBAL ENVIRONMENT }");
            return;
        }

        obj_string_mut_append(total, "{");
        x++;
        Obj *p = o->bindings;
        while(p && p->car) {
            char *key_s = obj_to_string(process, p->car->car)->s;
            obj_string_mut_append(total, key_s);
            obj_string_mut_append(total, " ");
            obj_to_string_internal(process, total, p->car->cdr, true, x + (int)strlen(key_s) + 1);
            p = p->cdr;
            if(p && p->car && p->car->car) {
                obj_string_mut_append(total, ", \n");
                add_indentation(total, x);
            }
        }
        obj_string_mut_append(total, "}");
        if(o->parent) {
            obj_string_mut_append(total, " -> \n");
            Obj *parent_printout = obj_to_string(process, o->parent);
            obj_string_mut_append(total, parent_printout->s);
        }
        shadow_stack_pop(process);
    }
    else if(o->tag == 'I') {
        static char temp[64];
        snprintf(temp, 64, "%d", o->i);
        obj_string_mut_append(total, temp);
    }
    else if(o->tag == 'V') {
        static char temp[64];
        snprintf(temp, 64, "%f", o->f32);
        obj_string_mut_append(total, temp);
        obj_string_mut_append(total, "f");
    }
    else if(o->tag == 'W') {
        static char temp[64];
        snprintf(temp, 64, "%f", o->f64);
        obj_string_mut_append(total, temp);
    }
    else if(o->tag == 'S') {
        if(prn) {
            obj_string_mut_append(total, "\"");
        }
        obj_string_mut_append(total, o->s);
        if(prn) {
            obj_string_mut_append(total, "\"");
        }
    }
    else if(o->tag == 'Y') {
        obj_string_mut_append(total, o->s);
    }
    else if(o->tag == 'K') {
        obj_string_mut_append(total, ":");
        obj_string_mut_append(total, o->s);
    }
    else if(o->tag == 'P') {
        obj_string_mut_append(total, "<primop:");
        static char temp[256];
        snprintf(temp, 256, "%p", o->primop);
        obj_string_mut_append(total, temp);
        if(o->meta) {
            Obj *name = env_lookup(process, o->meta, obj_new_keyword("name"));
            if(name) {
                obj_string_mut_append(total, ":");
                obj_string_mut_append(total, obj_to_string_not_prn(process, name)->s);
            }
        }
        obj_string_mut_append(total, ">");
    }
    else if(o->tag == 'D') {
        obj_string_mut_append(total, "<dylib:");
        static char temp[256];
        snprintf(temp, 256, "%p", o->primop);
        obj_string_mut_append(total, temp);
        obj_string_mut_append(total, ">");
    }
    else if(o->tag == 'Q') {
        shadow_stack_push(process, (struct Obj *)o);
        Obj *type_lookup;
        if(o->meta && (type_lookup = env_lookup(process, o->meta, obj_new_keyword("type")))) {
            if(type_lookup->tag == 'C' && type_lookup->cdr->car && obj_eq(process, type_lookup->car, obj_new_keyword("Array"))) {
                print_generic_array_or_struct(process, total, type_lookup, (struct Obj *)o);
            }
            else {
                print_generic_array_or_struct(process, total, type_lookup, (struct Obj *)o);
                /* obj_string_mut_append(total, "<ptr"); */
                /* obj_string_mut_append(total, obj_to_string(type_lookup)->s); */
                /* obj_string_mut_append(total, ">"); */
            }
        }
        else {
            obj_string_mut_append(total, "<ptr:");
            static char temp[256];
            snprintf(temp, 256, "%p", o->primop);
            obj_string_mut_append(total, temp);
            obj_string_mut_append(total, " of unknown type");
            obj_string_mut_append(total, ">");
        }
        shadow_stack_pop(process);
    }
    else if(o->tag == 'R') {
        shadow_stack_push(process, (struct Obj *)o);

        if(!o->void_ptr) {
            eval_error = obj_new_string("Pointer to global is NULL.\n");
            return;
        }

        Obj *type_lookup;
        //printf("o %p %p\n", o, o->void_ptr);

        if(o->void_ptr == NULL) {
            obj_string_mut_append(total, "NULL");
        }
        else if(o->meta && (type_lookup = env_lookup(process, o->meta, obj_new_keyword("type")))) {
            //printf("type %s\n", obj_to_string(type_lookup)->s);
            if(type_lookup->tag == 'C' && type_lookup->cdr->car && obj_eq(process, type_lookup->car, obj_new_keyword("Array"))) {
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_lookup);
                shadow_stack_push(process, x);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
                shadow_stack_pop(process); // x
            }
            else if(obj_eq(process, type_lookup, type_int)) {
                //int i = 123;
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_int);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
            }
            else if(obj_eq(process, type_lookup, type_float)) {
                //int i = 123;
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_float);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
            }
            else if(obj_eq(process, type_lookup, type_double)) {
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_double);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
            }
            else if(obj_eq(process, type_lookup, type_bool)) {
                void *dereffed = *(void **)o->void_ptr;
                // can't assert since false == NULL
                Obj *x = primitive_to_obj(process, dereffed, type_bool);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
            }
            else if(obj_eq(process, type_lookup, type_string)) {
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_string);
                obj_string_mut_append(total, x->s);
            }
            else if(obj_eq(process, type_lookup, type_char)) {
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_char);
                obj_string_mut_append(total, obj_to_string(process, x)->s);
            }
            else {
                void *dereffed = *(void **)o->void_ptr;
                assert(dereffed);
                Obj *x = primitive_to_obj(process, dereffed, type_lookup);
                print_generic_array_or_struct(process, total, type_lookup, (struct Obj *)x);
                /* obj_string_mut_append(total, "<ptr"); */
                /* obj_string_mut_append(total, obj_to_string(type_lookup)->s); */
                /* obj_string_mut_append(total, ">"); */
            }
        }

        obj_string_mut_append(total, " ; ptr-to-global");

        shadow_stack_pop(process);
    }
    else if(o->tag == 'F') {
        obj_string_mut_append(total, "<ffi:");
        static char temp[256];
        snprintf(temp, 256, "%p", o->funptr);
        obj_string_mut_append(total, temp);
        if(o->meta) {
            Obj *name = env_lookup(process, o->meta, obj_new_keyword("name"));
            if(name) {
                obj_string_mut_append(total, ":");
                obj_string_mut_append(total, obj_to_string_not_prn(process, name)->s);
            }
        }
        else {
        }
        obj_string_mut_append(total, ">");
    }
    else if(o->tag == 'L') {
        if(setting_print_lambda_body) {
            obj_string_mut_append(total, "(fn");
            obj_string_mut_append(total, " ");
            obj_string_mut_append(total, obj_to_string(process, o->params)->s);
            obj_string_mut_append(total, " ");
            obj_string_mut_append(total, obj_to_string(process, o->body)->s);
            obj_string_mut_append(total, ")");
        }
        else {
            obj_string_mut_append(total, "<lambda>");
        }
    }
    else if(o->tag == 'M') {
        if(setting_print_lambda_body) {
            obj_string_mut_append(total, "(macro");
            obj_string_mut_append(total, " ");
            obj_string_mut_append(total, obj_to_string(process, o->params)->s);
            obj_string_mut_append(total, " ");
            obj_string_mut_append(total, obj_to_string(process, o->body)->s);
            obj_string_mut_append(total, ")");
        }
        else {
            obj_string_mut_append(total, "<macro>");
        }
    }
    else if(o->tag == 'T') {
        char s[2] = {o->character, '\0'};
        if(prn) {
            obj_string_mut_append(total, "\\");
        }
        obj_string_mut_append(total, s);
    }
    else if(o->tag == 'B') {
        if(o->boolean) {
            obj_string_mut_append(total, "true");
        }
        else {
            obj_string_mut_append(total, "false");
        }
    }
    else if(o->tag == 'X') {
        obj_string_mut_append(total, "(\n");

        for(char *p = o->bytecode; *p != '\0';) {
            const int buffer_size = 128;
            char buffer[buffer_size];

            snprintf(buffer, buffer_size, "%4d  ", (int)(p - o->bytecode));
            obj_string_mut_append(total, buffer);

            char c = *p;
            p++;

            if(c == 'l') {
                snprintf(buffer, buffer_size, "LOAD LIT %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'a') {
                snprintf(buffer, buffer_size, "LOAD λ %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'c') {
                snprintf(buffer, buffer_size, "CALL %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'd') {
                snprintf(buffer, buffer_size, "DEFINE %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'y') {
                snprintf(buffer, buffer_size, "LOOKUP %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'i') {
                snprintf(buffer, buffer_size, "JUMP IF NOT %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'j') {
                snprintf(buffer, buffer_size, "JUMP %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'r') {
                snprintf(buffer, buffer_size, "RESET %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 't') {
                snprintf(buffer, buffer_size, "LET %d", *((int*)p));
                p += sizeof(int);
            }
            else if(c == 'e') {
                snprintf(buffer, buffer_size, "DISCARD");
            }
            else if(c == 'g') {
                snprintf(buffer, buffer_size, "CATCH");
            }
            else if(c == 'n') {
                snprintf(buffer, buffer_size, "NOT");
            }
            else if(c == 'p') {
                snprintf(buffer, buffer_size, "PUSH NIL");
            }
            else if(c == 'v') {
                snprintf(buffer, buffer_size, "POP LET-SCOPE");
            }
            else if(c == 'x') {
                snprintf(buffer, buffer_size, "DIRECT LOOKUP");
            }
            else if(c == 'q') {
                snprintf(buffer, buffer_size, "END");
            }
            else {
                snprintf(buffer, buffer_size, "UNHANDLED OP (%c)", *p);
                p++;
            }

            obj_string_mut_append(total, buffer);
            obj_string_mut_append(total, "\n");
        }

        obj_string_mut_append(total, "Literals: ");
        obj_string_mut_append(total, obj_to_string(process, o->bytecode_literals)->s);
        obj_string_mut_append(total, "\n");
        obj_string_mut_append(total, ")");
    }
    else {
        printf("obj_to_string() can't handle type tag %c (%d).\n", o->tag, o->tag);
        assert(false);
    }
}
예제 #2
0
파일: call_ffi.c 프로젝트: jl2/Carp
void call_foreign_function(Process *process, Obj *function, Obj **args, int arg_count) {
  assert(function);

  if(!function->funptr) {
    eval_error = obj_new_string("Can't call foregin function, it's funptr is NULL. May be a stub function with just a signature?");
    return;
  }
    
  assert(function->cif);
  assert(function->arg_types);
  assert(function->return_type);

  // TODO: change name to 'arg_values' or something like that
  void **values = calloc(sizeof(void*), arg_count);
  assert(values);

#define assert_or_free_values_and_set_error(assertion, message, object) \
  if(!(assertion)) {                                                    \
    free(values);                                                       \
  }                                                                     \
  assert_or_set_error((assertion), (message), (object));

  Obj *p = function->arg_types;
  for(int i = 0; i < arg_count; i++) {      
    if(p && p->cdr) {
      assert(p->car);
      Obj *type_obj = p->car;

      // Handle ref types by unwrapping them: (:ref x) -> x
      if(type_obj->tag == 'C' && type_obj->car && type_obj->cdr && type_obj->cdr->car && obj_eq(process, type_obj->car, type_ref)) {
        type_obj = type_obj->cdr->car; // the second element of the list
      }
        
      args[i]->given_to_ffi = true; // This makes the GC ignore this value when deleting internal C-data, like inside a string

      if(obj_eq(process, type_obj, type_int)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'I', "Invalid (expected int) type of arg: ", args[i]);
        values[i] = &args[i]->i;
      }
      else if(obj_eq(process, type_obj, type_bool)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'B', "Invalid (expected bool) type of arg: ", args[i]);
        bool b = args[i]->boolean;
        values[i] = &b;
      }
      else if(obj_eq(process, type_obj, type_char)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'T', "Invalid (expected char) type of arg: ", args[i]);
        char c = args[i]->character;
        values[i] = &c;
      }
      else if(obj_eq(process, type_obj, type_float)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'V', "Invalid (expected float) type of arg: ", args[i]);
        values[i] = &args[i]->f32;
      }
      else if(obj_eq(process, type_obj, type_double)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'W', "Invalid (expected double) type of arg: ", args[i]);
        values[i] = &args[i]->f64;
      }
      else if(obj_eq(process, type_obj, type_string)) {
        assert_or_free_values_and_set_error(args[i]->tag == 'S', "Invalid (expected string) type of arg: ", args[i]);
        //args[i]->s = strdup(args[i]->s); // OBS! Duplicating string here. TODO: Think about if this is the correct thing to do!
        values[i] = &args[i]->s;
      }
      else {
        //printf("Calling function with expected parameter of type %s. Argument is of type %c.\n", obj_to_string(process, p->car)->s, args[i]->tag);         
          
        if(args[i]->tag == 'Q' /* || args[i]->tag == 'R' */) {

#ifdef CHECKING
          if(args[i]->void_ptr == NULL || obj_eq(type_obj, obj_new_keyword("any"))) {
            goto hack;
          }

          assert_or_free_values_and_set_error(args[i]->meta, "Argument is missing meta data: ", args[i]);
          Obj *meta_type_tag = env_lookup(args[i]->meta, obj_new_keyword("type")); // TODO: make this keyword to a "singleton"
          assert_or_free_values_and_set_error(meta_type_tag, "Argument is missing meta 'type' tag: ", args[i]);

          bool eq = obj_eq(meta_type_tag, type_obj);
          if(!eq) {
            eval_error = obj_new_string("Invalid type of argument sent to function expecting '");
            obj_string_mut_append(eval_error, obj_to_string(type_obj)->s);
            obj_string_mut_append(eval_error, "' type: ");
            obj_string_mut_append(eval_error, obj_to_string(meta_type_tag)->s);
            return;
          }

        hack:;
#endif
            
          values[i] = &args[i]->void_ptr;
        }
        else if(args[i]->tag == 'A') {
          // TODO: Do some type checking here!!!
          Array *a = obj_array_to_carp_array(process, args[i]);
          if(eval_error) {
            return;
          }
          assert(a);
          values[i] = &a;            
        }
        else if(args[i]->tag == 'F') {
          values[i] = &args[i]->funptr;
        }
        else if(args[i]->tag == 'L') {
          if(ALLOW_SENDING_LAMBDA_TO_FFI) {
            //printf("Will call unbaked lambda from ffi function. Lambda should have types: %s\n", obj_to_string(type_obj)->s);
	    
            ffi_type *closure_args[1];
            ffi_closure *closure;  
            void (*closure_fun_ptr)();
            closure = ffi_closure_alloc(sizeof(ffi_closure), (void**)&closure_fun_ptr);
     
            if (closure) {
              /* Initialize the argument info vectors */
              closure_args[0] = &ffi_type_pointer;

              /* ffi_cif cif_static; */
              /* ffi_cif *cif = &cif_static; */
              /* ffi_prep_cif(cif, FFI_DEFAULT_ABI, 0, &ffi_type_void, closure_args); */

              //printf("Type obj: %s\n", obj_to_string(type_obj)->s);

              Obj *lambda_arg_types = type_obj->cdr->car;
              Obj *lambda_return_type = type_obj->cdr->cdr->car;
              int lambda_arg_count = 0;
              Obj *p = lambda_arg_types;
              while(p && p->car) {
                p = p->cdr;
                lambda_arg_count++;
              }
		
              ffi_cif *cif = create_cif(process, lambda_arg_types, lambda_arg_count, lambda_return_type, "TODO:proper-name");

              Obj *lambda_arg = args[i];
              LambdaAndItsType *lambda_and_its_type = malloc(sizeof(LambdaAndItsType)); // TODO: free!
              lambda_and_its_type->lambda = lambda_arg; // the uncompiled lambda that was passed to the ffi function
              lambda_and_its_type->signature = type_obj;
              lambda_and_its_type->process = process;
                
              typedef void (*LambdaCallback)(ffi_cif *, void *, void **, void *);
	      
              if (ffi_prep_closure_loc(closure, cif, (LambdaCallback)call_lambda_from_ffi, lambda_and_its_type, closure_fun_ptr) == FFI_OK) {
                //printf("Closure preparation done.\n");
                values[i] = &closure_fun_ptr;
              }
              else {
                set_error("Closure prep failed. ", nil);
              }
            }
            else {
              set_error("Failed to allocate closure. ", nil);
            }
          } else {
            free(values);
            set_error("Can't send argument of lambda type (tag 'L') to ffi function, you need to compile it to a C function using (bake ...) first:\n", args[i]);
          }
        }
        else {
          free(values);
          printf("INVALID ARG TYPE: %c\n", args[i]->tag);
          printf("ARG: %s\n", obj_to_string(process, args[i])->s);
          set_error("Can't send argument of invalid type to foreign function taking parameter of type ", p->car);
        }
      }
      p = p->cdr;
    }
    else {
      free(values);
      set_error("Too many arguments to ", function);
    } 
  }

  if(p && p->car) {
    free(values);
    set_error("Too few arguments to ", function);
  }


  // Handle refs:
  Obj *return_type = function->return_type;
  if(return_type->tag == 'C' && return_type->car && return_type->cdr &&
     return_type->cdr->car && obj_eq(process, return_type->car, type_ref)) {
    return_type = return_type->cdr->car; // the second element of the list
  }

  void *result;
  ffi_call(function->cif, function->funptr, &result, values);

  Obj *obj_result = primitive_to_obj(process, result, return_type); 

  free(values);
    
  if(!obj_result) {
    printf("obj_result == NULL, return_type = %s\n", obj_to_string(process, return_type)->s);
    return; // something went wrong
  }

  stack_push(process, obj_result);    
}