Beispiel #1
0
static bool void_star_param(ast_t* param_type, ast_t* arg_type)
{
  assert(param_type != NULL);
  assert(arg_type != NULL);

  if(!is_pointer(param_type))
    return false;

  ast_t* type_args = ast_childidx(param_type, 2);

  if(ast_childcount(type_args) != 1 || !is_none(ast_child(type_args)))
    return false;

  // Parameter type is Pointer[None]
  // If the argument is Pointer[A], MaybePointer[A] or USize, allow it
  while(ast_id(arg_type) == TK_ARROW)
    arg_type = ast_childidx(arg_type, 1);

  if(is_pointer(arg_type) ||
    is_maybe(arg_type) ||
    is_literal(arg_type, "USize"))
    return true;

  return false;
}
Beispiel #2
0
static void print_types(compile_t* c, FILE* fp, printbuf_t* buf)
{
  size_t i = HASHMAP_BEGIN;
  reachable_type_t* t;

  while((t = reachable_types_next(c->reachable, &i)) != NULL)
  {
    // Print the docstring if we have one.
    ast_t* def = (ast_t*)ast_data(t->ast);
    ast_t* docstring = ast_childidx(def, 6);

    if(ast_id(docstring) == TK_STRING)
      fprintf(fp, "/*\n%s*/\n", ast_name(docstring));

    if(!is_pointer(t->ast) && !is_maybe(t->ast) && !is_machine_word(t->ast))
    {
      // Forward declare an opaque type.
      fprintf(fp, "typedef struct %s %s;\n\n", t->name, t->name);

      // Function signature for the allocator.
      printbuf(buf,
        "/* Allocate a %s without initialising it. */\n%s* %s_Alloc();\n\n",
        t->name,
        t->name,
        t->name
        );
    }

    print_methods(c, t, buf);
  }
}
Beispiel #3
0
static int print_pointer_type(compile_t* c, printbuf_t* buf, ast_t* type)
{
  ast_t* typeargs = ast_childidx(type, 2);
  ast_t* elem = ast_child(typeargs);

  if(is_pointer(elem) || is_maybe(elem))
    return print_pointer_type(c, buf, elem) + 1;

  print_base_type(c, buf, elem);
  return 1;
}
Beispiel #4
0
static trace_t trace_type_nominal(ast_t* type)
{
  switch(ast_id((ast_t*)ast_data(type)))
  {
    case TK_INTERFACE:
    case TK_TRAIT:
      switch(cap_single(type))
      {
        case TK_VAL:
          return TRACE_VAL_UNKNOWN;

        case TK_TAG:
          return TRACE_TAG_UNKNOWN;

        default: {}
      }

      return TRACE_MUT_UNKNOWN;

    case TK_PRIMITIVE:
    {
      if(is_machine_word(type))
        return TRACE_MACHINE_WORD;

      return TRACE_PRIMITIVE;
    }

    case TK_STRUCT:
    case TK_CLASS:
      if(is_maybe(type))
        return TRACE_MAYBE;

      switch(cap_single(type))
      {
        case TK_VAL:
          return TRACE_VAL_KNOWN;

        case TK_TAG:
          return TRACE_TAG_KNOWN;

        default: {}
      }

      return TRACE_MUT_KNOWN;

    case TK_ACTOR:
      return TRACE_TAG_KNOWN;

    default: {}
  }

  pony_assert(0);
  return TRACE_NONE;
}
Beispiel #5
0
static void print_type_name(compile_t* c, printbuf_t* buf, ast_t* type)
{
  if(is_pointer(type) || is_maybe(type))
  {
    int depth = print_pointer_type(c, buf, type);

    for(int i = 0; i < depth; i++)
      printbuf(buf, "*");
  } else {
    print_base_type(c, buf, type);
  }
}
Beispiel #6
0
static trace_t trace_type_nominal(ast_t* type)
{
  switch(ast_id((ast_t*)ast_data(type)))
  {
    case TK_INTERFACE:
    case TK_TRAIT:
      switch(cap_single(type))
      {
        case TK_VAL:
          return TRACE_UNKNOWN_VAL;

        case TK_TAG:
          return TRACE_TAG_OR_ACTOR;

        default: {}
      }

      return TRACE_UNKNOWN;

    case TK_PRIMITIVE:
      return TRACE_PRIMITIVE;

    case TK_STRUCT:
    case TK_CLASS:
      if(is_maybe(type))
        return TRACE_MAYBE;

      switch(cap_single(type))
      {
        case TK_VAL:
          return TRACE_KNOWN_VAL;

        case TK_TAG:
          return TRACE_TAG;

        default: {}
      }

      return TRACE_KNOWN;

    case TK_ACTOR:
      return TRACE_ACTOR;

    default: {}
  }

  assert(0);
  return TRACE_NONE;
}
Beispiel #7
0
static bool genfun_allocator(compile_t* c, reachable_type_t* t)
{
  switch(t->underlying)
  {
    case TK_PRIMITIVE:
    case TK_STRUCT:
    case TK_CLASS:
    case TK_ACTOR:
      break;

    default:
      return true;
  }

  // No allocator for machine word types or pointers.
  if((t->primitive != NULL) || is_pointer(t->ast) || is_maybe(t->ast))
    return true;

  const char* funname = genname_fun(t->name, "Alloc", NULL);
  LLVMTypeRef ftype = LLVMFunctionType(t->use_type, NULL, 0, false);
  LLVMValueRef fun = codegen_addfun(c, funname, ftype);
  codegen_startfun(c, fun, NULL, NULL);

  LLVMValueRef result;

  switch(t->underlying)
  {
    case TK_PRIMITIVE:
    case TK_STRUCT:
    case TK_CLASS:
      // Allocate the object or return the global instance.
      result = gencall_alloc(c, t);
      break;

    case TK_ACTOR:
      // Allocate the actor.
      result = gencall_create(c, t);
      break;

    default:
      assert(0);
      return false;
  }

  LLVMBuildRet(c->builder, result);
  codegen_finishfun(c);
  return true;
}
Beispiel #8
0
static void setup_dwarf(dwarf_t* dwarf, dwarf_meta_t* meta, gentype_t* g,
  bool opaque, bool field)
{
  memset(meta, 0, sizeof(dwarf_meta_t));

  ast_t* ast = g->ast;
  LLVMTypeRef type = g->primitive;

  if(is_machine_word(ast))
  {
    if(is_float(ast))
      meta->flags |= DWARF_FLOAT;
    else if(is_signed(dwarf->opt, ast))
      meta->flags |= DWARF_SIGNED;
    else if(is_bool(ast))
      meta->flags |= DWARF_BOOLEAN;
  }
  else if(is_pointer(ast) || is_maybe(ast) || !is_concrete(ast) ||
    (is_constructable(ast) && field))
  {
    type = g->use_type;
  }
  else if(is_constructable(ast))
  {
    type = g->structure;
  }

  bool defined_type = g->underlying != TK_TUPLETYPE &&
    g->underlying != TK_UNIONTYPE && g->underlying != TK_ISECTTYPE;

  source_t* source;

  if(defined_type)
    ast = (ast_t*)ast_data(ast);

  source = ast_source(ast);
  meta->file = source->file;
  meta->name = g->type_name;
  meta->line = ast_line(ast);
  meta->pos = ast_pos(ast);

  if(!opaque)
  {
    meta->size = LLVMABISizeOfType(dwarf->target_data, type) << 3;
    meta->align = LLVMABIAlignmentOfType(dwarf->target_data, type) << 3;
  }
}
Beispiel #9
0
LLVMValueRef gencall_alloc(compile_t* c, reach_type_t* t)
{
  // Do nothing for primitives.
  if(t->primitive != NULL)
    return NULL;

  // Do nothing for Pointer and Maybe.
  if(is_pointer(t->ast) || is_maybe(t->ast))
    return NULL;

  // Use the global instance if we have one.
  if(t->instance != NULL)
    return t->instance;

  if(t->underlying == TK_ACTOR)
    return gencall_create(c, t);

  return gencall_allocstruct(c, t);
}
Beispiel #10
0
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t)
{
  switch(ast_id(postfix))
  {
    case TK_NEWREF:
    case TK_NEWBEREF:
      break;

    default:
      return true;
  }

  // No receiver if a new primitive.
  if(t->primitive != NULL)
    return false;

  // No receiver if a new Pointer or Maybe.
  if(is_pointer(t->ast) || is_maybe(t->ast))
    return false;

  return true;
}
Beispiel #11
0
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t)
{
  switch(ast_id(postfix))
  {
    case TK_NEWREF:
    case TK_NEWBEREF:
      // No receiver if a new primitive.
      if(((compile_type_t*)t->c_type)->primitive != NULL)
        return false;

      // No receiver if a new Pointer or Maybe.
      if(is_pointer(t->ast) || is_maybe(t->ast))
        return false;

      return true;

    // Always generate the receiver, even for bare function calls. This ensures
    // that side-effects always happen.
    default:
      return true;
  }
}
Beispiel #12
0
bool expr_nominal(pass_opt_t* opt, ast_t** astp)
{
  // Resolve type aliases and typeparam references.
  if(!names_nominal(opt, *astp, astp, true))
    return false;

  ast_t* ast = *astp;

  switch(ast_id(ast))
  {
    case TK_TYPEPARAMREF:
      return flatten_typeparamref(opt, ast) == AST_OK;

    case TK_NOMINAL:
      break;

    default:
      return true;
  }

  // If still nominal, check constraints.
  ast_t* def = (ast_t*)ast_data(ast);

  // Special case: don't check the constraint of a Pointer or an Array. These
  // builtin types have no contraint on their type parameter, and it is safe
  // to bind a struct as a type argument (which is not safe on any user defined
  // type, as that type might then be used for pattern matching).
  if(is_pointer(ast) || is_literal(ast, "Array"))
    return true;

  ast_t* typeparams = ast_childidx(def, 1);
  ast_t* typeargs = ast_childidx(ast, 2);

  if(!reify_defaults(typeparams, typeargs, true, opt))
    return false;

  if(is_maybe(ast))
  {
    // MaybePointer[A] must be bound to a struct.
    assert(ast_childcount(typeargs) == 1);
    ast_t* typeparam = ast_child(typeparams);
    ast_t* typearg = ast_child(typeargs);
    bool ok = false;

    switch(ast_id(typearg))
    {
      case TK_NOMINAL:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = ast_id(def) == TK_STRUCT;
        break;
      }

      case TK_TYPEPARAMREF:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = def == typeparam;
        break;
      }

      default: {}
    }

    if(!ok)
    {
      ast_error(opt->check.errors, ast,
        "%s is not allowed: "
        "the type argument to MaybePointer must be a struct",
        ast_print_type(ast));

      return false;
    }

    return true;
  }

  return check_constraints(typeargs, typeparams, typeargs, true, opt);
}
Beispiel #13
0
bool gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type)
{
  bool tag = trace_as_tag(c, value, type);

  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
    case TK_ISECTTYPE:
    {
      if(tag)
        trace_tag_or_actor(c, ctx, value);
      else
        trace_unknown(c, ctx, value);

      return true;
    }

    case TK_TUPLETYPE:
      return trace_tuple(c, ctx, value, type);

    case TK_NOMINAL:
    {
      switch(ast_id((ast_t*)ast_data(type)))
      {
        case TK_INTERFACE:
        case TK_TRAIT:
          if(tag)
            trace_tag_or_actor(c, ctx, value);
          else
            trace_unknown(c, ctx, value);

          return true;

        case TK_PRIMITIVE:
          // Do nothing.
          return false;

        case TK_STRUCT:
        case TK_CLASS:
          if(tag)
          {
            if(is_maybe(type))
              trace_maybe(c, ctx, value, type, true);
            else
              trace_tag(c, ctx, value);

            return true;
          }

          if(is_maybe(type))
          {
            trace_maybe(c, ctx, value, type, false);
            return true;
          }

          return trace_known(c, ctx, value, type);

        case TK_ACTOR:
          trace_actor(c, ctx, value);
          return true;

        default: {}
      }
      break;
    }

    default: {}
  }

  assert(0);
  return false;
}