Exemplo n.º 1
0
void dwarf_field(dwarf_t* dwarf, gentype_t* composite, gentype_t* field,
  int index)
{
  char buf[32];
  memset(buf, 0, sizeof(buf));

  dwarf_meta_t meta;
  setup_dwarf(dwarf, &meta, field, false, true);

  meta.typearg = field->type_name;

  if(composite->underlying == TK_TUPLETYPE)
  {
    meta.flags |= DWARF_CONSTANT;
    snprintf(buf, sizeof(buf), "_%d", index + 1);
    meta.name = buf;
  }
  else
  {
    ast_t* def = (ast_t*)ast_data(composite->ast);
    ast_t* members = ast_childidx(def, 4);
    ast_t* fld = ast_childidx(members, index);
    meta.name = ast_name(ast_child(fld));

    if(ast_id(fld) == TK_FLET)
      meta.flags |= DWARF_CONSTANT;
  }

  if(meta.name[0] == '_')
    meta.flags |= DWARF_PRIVATE;

  LLVMTypeRef structure = composite->primitive;
  int offset = 0;

  if(composite->underlying != TK_TUPLETYPE)
  {
    structure = composite->structure;

    if(composite->underlying != TK_STRUCT)
      offset++;

    if(composite->underlying == TK_ACTOR)
      offset++;
  }

  meta.offset = 8 * LLVMOffsetOfElement(dwarf->target_data, structure,
    offset + index);

  symbols_field(dwarf->symbols, &meta);
}
Exemplo n.º 2
0
// Determine which body to use for the given method
static bool resolve_body(ast_t* entity, ast_t* method, pass_opt_t* options)
{
  assert(entity != NULL);
  assert(method != NULL);

  method_t* info = (method_t*)ast_data(method);
  assert(info != NULL);

  if(info->local_def) // Local defs just use their own body
    return true;

  token_id e_id = ast_id(entity);
  bool concrete =
    (e_id == TK_PRIMITIVE) || (e_id == TK_STRUCT) ||
    (e_id == TK_CLASS) || (e_id == TK_ACTOR);

  const char* name = ast_name(ast_childidx(method, 1));
  assert(name != NULL);

  // NExt try a delegate body
  ast_t* r = resolve_delegate_body(entity, method, info, name);

  if(r == BODY_ERROR)
    return false;

  if(r == NULL) // And finally a default body
    r = resolve_default_body(entity, method, info, name, concrete);

  if(r == BODY_ERROR)
    return false;

  if(r != NULL)
  {
    // We have a body, use it and patch up symbol tables
    ast_t* old_body = ast_childidx(method, 6);
    ast_replace(&old_body, r);
    ast_visit(&method, rescope, NULL, options, PASS_ALL);
    return true;
  }

  // Nowhere left to get a body from
  if(concrete)
  {
    ast_error(entity, "no body found for method %s", name);
    ast_error(method, "provided from here");
    return false;
  }

  return true;
}
Exemplo n.º 3
0
static bool generate_actor(compile_t* c, ast_t* ast)
{
  ast_t* id = ast_child(ast);
  ast_t* type = type_builtin(c->opt, ast, ast_name(id));

  if(type == NULL)
    return false;

  gentype_t g;
  bool ok = gentype(c, type, &g);
  ast_free_unattached(type);

  return ok;
}
Exemplo n.º 4
0
static int check_call_send(ast_t* ast, bool in_final)
{
  AST_GET_CHILDREN(ast, positional, named, question, lhs);
  AST_GET_CHILDREN(lhs, receiver, method);

  switch(ast_id(receiver))
  {
    case TK_NEWREF:
    case TK_FUNREF:
    case TK_FUNCHAIN:
      // Qualified. Get the real receiver.
      receiver = ast_child(receiver);
      method = ast_sibling(receiver);
      break;

    default: {}
  }

  ast_t* type = ast_type(receiver);

  // If we don't know the final type, we can't be certain of what all
  // implementations of the method do. Leave it as might send.
  if(!is_known(type))
    return FINAL_CAN_SEND;

  ast_t* def = receiver_def(type);
  pony_assert(def != NULL);

  const char* method_name = ast_name(method);
  ast_t* fun = ast_get(def, method_name, NULL);
  pony_assert(fun != NULL);

  AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body);
  int r = check_body_send(body, false);

  if(r == FINAL_NO_SEND)
  {
    // Mark the call as no send.
    ast_clearmightsend(ast);
  } else if(in_final && (r == FINAL_RECURSE)) {
    // If we're in the finaliser, which can't recurse, we treat a recurse as
    // a no send.
    ast_clearmightsend(ast);
  } else if((r & FINAL_CAN_SEND) != 0) {
    // Mark the call as can send.
    ast_setsend(ast);
  }

  return r;
}
Exemplo n.º 5
0
static LLVMValueRef special_case_platform(compile_t* c, ast_t* ast)
{
  AST_GET_CHILDREN(ast, positional, named, postfix);
  AST_GET_CHILDREN(postfix, receiver, method);

  const char* method_name = ast_name(method);
  bool is_target;

  if(os_is_target(method_name, c->opt->release, &is_target, c->opt))
    return LLVMConstInt(c->ibool, is_target ? 1 : 0, false);

  ast_error(c->opt->check.errors, ast, "unknown Platform setting");
  return NULL;
}
Exemplo n.º 6
0
static bool package_access(pass_opt_t* opt, ast_t** astp)
{
  ast_t* ast = *astp;

  // Left is a packageref, right is an id.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);

  assert(ast_id(left) == TK_PACKAGEREF);
  assert(ast_id(right) == TK_ID);

  // Must be a type in a package.
  const char* package_name = ast_name(ast_child(left));
  ast_t* package = ast_get(left, package_name, NULL);

  if(package == NULL)
  {
    ast_error(right, "can't access package '%s'", package_name);
    return false;
  }

  assert(ast_id(package) == TK_PACKAGE);
  const char* type_name = ast_name(right);
  ast_t* type = ast_get(package, type_name, NULL);

  if(type == NULL)
  {
    ast_error(right, "can't find type '%s' in package '%s'",
      type_name, package_name);
    return false;
  }

  ast_settype(ast, type_sugar(ast, package_name, type_name));
  ast_setid(ast, TK_TYPEREF);

  return expr_typeref(opt, astp);
}
Exemplo n.º 7
0
static bool is_nominal_sub_interface(ast_t* sub, ast_t* super)
{
  ast_t* sub_def = (ast_t*)ast_data(sub);
  ast_t* super_def = (ast_t*)ast_data(super);

  ast_t* sub_typeargs = ast_childidx(sub, 2);
  ast_t* super_typeargs = ast_childidx(super, 2);

  ast_t* sub_typeparams = ast_childidx(sub_def, 1);
  ast_t* super_typeparams = ast_childidx(super_def, 1);

  ast_t* super_members = ast_childidx(super_def, 4);
  ast_t* super_member = ast_child(super_members);

  while(super_member != NULL)
  {
    ast_t* super_member_id = ast_childidx(super_member, 1);
    ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL);

    if(sub_member == NULL)
      return false;

    ast_t* r_sub_member = reify(sub_typeargs, sub_member, sub_typeparams,
      sub_typeargs);

    if(r_sub_member== NULL)
      return false;

    ast_t* r_super_member = reify(super_typeargs, super_member,
      super_typeparams, super_typeargs);

    if(r_super_member == NULL)
    {
      ast_free_unattached(r_sub_member);
      return false;
    }

    bool ok = is_fun_sub_fun(r_sub_member, r_super_member, sub, super);
    ast_free_unattached(r_sub_member);
    ast_free_unattached(r_super_member);

    if(!ok)
      return false;

    super_member = ast_sibling(super_member);
  }

  return true;
}
Exemplo n.º 8
0
bool expr_fieldref(pass_opt_t* opt, ast_t* ast, ast_t* find, token_id tid)
{
  AST_GET_CHILDREN(ast, left, right);
  ast_t* l_type = ast_type(left);

  if(is_typecheck_error(l_type))
    return false;

  AST_GET_CHILDREN(find, id, f_type, init);

  // Viewpoint adapted type of the field.
  ast_t* type = viewpoint_type(l_type, f_type);

  if(ast_id(type) == TK_ARROW)
  {
    ast_t* upper = viewpoint_upper(type);

    if(upper == NULL)
    {
      ast_error(ast, "can't read a field through %s", ast_print_type(l_type));
      return false;
    }

    ast_free_unattached(upper);
  }

  // Set the unadapted field type.
  ast_settype(right, f_type);

  // Set the type so that it isn't free'd as unattached.
  ast_setid(ast, tid);
  ast_settype(ast, type);

  if(ast_id(left) == TK_THIS)
  {
    // Handle symbol status if the left side is 'this'.
    ast_t* id = ast_child(find);
    const char* name = ast_name(id);

    sym_status_t status;
    ast_get(ast, name, &status);

    if(!valid_reference(opt, ast, type, status))
      return false;
  }

  return true;
}
Exemplo n.º 9
0
// Find the declaration for the given FFI call that is valid for the given
// build config, within the specified ifdef condition (NULL for none).
// Returns: true on success, false on failure.
static bool find_ffi_decl(ast_t* ast, ast_t* package, ast_t* ifdef_cond,
  ast_t** out_decl, pass_opt_t* opt)
{
  pony_assert(ast != NULL);
  pony_assert(package != NULL);
  pony_assert(out_decl != NULL);

  const char* ffi_name = ast_name(ast_child(ast));
  buildflagset_t* config = buildflagset_create();

  // Find all the relevant build flags.
  if(ifdef_cond != NULL)
    find_flags_in_cond(ifdef_cond, config);

  if(!find_decl_flags(package, ffi_name, config))
  {
    // There are no declarations for this FFI.
    buildflagset_free(config);
    *out_decl = NULL;
    return true;
  }

  check_config_count(config, ast);
  ffi_decl_t decl_info = { NULL, NULL };
  buildflagset_startenum(config);

  while(buildflagset_next(config))
  {
    if(ifdef_cond == NULL || cond_eval(ifdef_cond, config, false, opt))
    {
      // ifdef condition true, or not in an ifdef.
      // Look for valid FFI declaration.
      if(!find_decl_for_config(ast, package, ffi_name, config, &decl_info, opt))
      {
        // Config has failed.
        buildflagset_free(config);
        return false;
      }

      pony_assert(decl_info.decl != NULL);
    }
  }

  buildflagset_free(config);
  pony_assert(decl_info.decl != NULL);
  *out_decl = decl_info.decl;
  return true;
}
Exemplo n.º 10
0
Arquivo: use.c Projeto: Sendence/ponyc
// Find the index of the handler for the given URI
static int find_handler(pass_opt_t* opt, ast_t* uri, const char** out_locator)
{
  assert(uri != NULL);
  assert(out_locator != NULL);
  assert(ast_id(uri) == TK_STRING);

  const char* text = ast_name(uri);
  const char* colon = strchr(text, ':');

  if(colon == NULL)
  {
    // No scheme specified, use default
    *out_locator = stringtab(text);
    return 0;
  }

  size_t scheme_len = colon - text + 1;  // +1 for colon

  // Search for matching handler
  for(int i = 0; handlers[i].scheme != NULL; i++)
  {
    if(handlers[i].scheme_len == scheme_len &&
      strncmp(handlers[i].scheme, text, scheme_len) == 0)
    {
      if(handlers[i].handler == NULL) // No handler provided (probably test:)
        break;

      // Matching scheme found
      *out_locator = stringtab(colon + 1);
      return i;
    }
  }

  // No match found
#ifdef PLATFORM_IS_WINDOWS
  if(colon == text + 1)
  {
    // Special case error message
    ast_error(opt->check.errors, uri, "Use scheme %c: not found. "
      "If this is an absolute path use prefix \"package:\"", text[0]);
    return -1;
  }
#endif

  ast_error(opt->check.errors, uri, "Use scheme %.*s not found",
    (int)scheme_len, text);
  return -1;
}
Exemplo n.º 11
0
static void name_params(compile_t* c, reachable_type_t* t,
  reachable_method_t* m, ast_t* params, LLVMValueRef func)
{
  // Name the receiver 'this'.
  name_param(c, t, m, func, c->str_this, 0, ast_line(params), ast_pos(params));

  // Name each parameter.
  ast_t* param = ast_child(params);

  for(size_t i = 0; i < m->param_count; i++)
  {
    name_param(c, m->params[i], m, func, ast_name(ast_child(param)),
      (unsigned)i + 1, ast_line(param), ast_pos(param));
    param = ast_sibling(param);
  }
}
Exemplo n.º 12
0
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast)
{
  ast_t* id = ast_child(ast);
  ast_t* type = ast_type(id);
  const char* name = ast_name(id);

  // If this local has already been generated, don't create another copy. This
  // can happen when the same ast node is generated more than once, such as
  // the condition block of a while expression.
  LLVMValueRef value = codegen_getlocal(c, name);

  if(value != NULL)
    return GEN_NOVALUE;

  reach_type_t* t = reach_type(c->reach, type);

  // All alloca should happen in the entry block of a function.
  LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder);
  LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(codegen_fun(c));
  LLVMValueRef inst = LLVMGetFirstInstruction(entry_block);

  if(inst != NULL)
    LLVMPositionBuilderBefore(c->builder, inst);
  else
    LLVMPositionBuilderAtEnd(c->builder, entry_block);

  LLVMValueRef alloc = LLVMBuildAlloca(c->builder, t->use_type, name);

  // Store the alloca to use when we reference this local.
  codegen_setlocal(c, name, alloc);

  LLVMMetadataRef file = codegen_difile(c);
  LLVMMetadataRef scope = codegen_discope(c);

  LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name,
    file, (unsigned)ast_line(ast), t->di_type);

  LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0);

  LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr,
    (unsigned)ast_line(ast), (unsigned)ast_pos(ast), scope,
    LLVMGetInsertBlock(c->builder));

  // Put the builder back where it was.
  LLVMPositionBuilderAtEnd(c->builder, this_block);
  return GEN_NOVALUE;
}
Exemplo n.º 13
0
static bool check_finaliser(ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body);

  if(strcmp(ast_name(id), "_final"))
    return true;

  bool ok = true;

  if(ast_id(ast) != TK_FUN)
  {
    ast_error(ast, "_final must be a function");
    ok = false;
  }

  if(ast_id(cap) != TK_BOX)
  {
    ast_error(cap, "_final must be box");
    ok = false;
  }

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(typeparams, "_final must not be polymorphic");
    ok = false;
  }

  if(ast_childcount(params) != 0)
  {
    ast_error(params, "_final must not have parameters");
    ok = false;
  }

  if(!is_none(result))
  {
    ast_error(result, "_final must return None");
    ok = false;
  }

  if(ast_id(can_error) != TK_NONE)
  {
    ast_error(can_error, "_final cannot raise an error");
    ok = false;
  }

  return ok;
}
Exemplo n.º 14
0
// Write the given package home page to its own file
static void doc_package_home(docgen_t* docgen, ast_t* package,
  ast_t* doc_string)
{
  assert(docgen != NULL);
  assert(docgen->index_file != NULL);
  assert(docgen->home_file != NULL);
  assert(docgen->type_file == NULL);
  assert(package != NULL);
  assert(ast_id(package) == TK_PACKAGE);

  // First open a file
  size_t tqfn_len;
  char* tqfn = write_tqfn(package, "-index", &tqfn_len);

  // Package group
  fprintf(docgen->index_file, "- package %s:\n",
    package_qualified_name(package));

  docgen->type_file = doc_open_file(docgen, true, tqfn, ".md");

  if(docgen->type_file == NULL)
    return;

  // Add reference to new file to index file
  fprintf(docgen->index_file, "  - Package: \"%s.md\"\n", tqfn);

  // Add reference to package to home file
  fprintf(docgen->home_file, "* [%s](%s)\n", package_qualified_name(package),
    tqfn);

  // Now we can write the actual documentation for the package
  if(doc_string != NULL)
  {
    assert(ast_id(doc_string) == TK_STRING);
    fprintf(docgen->type_file, "%s", ast_name(doc_string));
  }
  else
  {
    fprintf(docgen->type_file, "No package doc string provided for %s.",
      package_qualified_name(package));
  }

  pool_free_size(tqfn_len, tqfn);

  fclose(docgen->type_file);
  docgen->type_file = NULL;
}
Exemplo n.º 15
0
static const char* suggest_alt_name(ast_t* ast, const char* name)
{
  assert(ast != NULL);
  assert(name != NULL);

  size_t name_len = strlen(name);

  if(is_name_private(name))
  {
    // Try without leading underscore
    const char* try_name = stringtab(name + 1);

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }
  else
  {
    // Try with a leading underscore
    char* buf = (char*)ponyint_pool_alloc_size(name_len + 2);
    buf[0] = '_';
    strncpy(buf + 1, name, name_len + 1);
    const char* try_name = stringtab_consume(buf, name_len + 2);

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }

  // Try with a different case (without crossing type/value boundary)
  ast_t* case_ast = ast_get_case(ast, name, NULL);
  if(case_ast != NULL)
  {
    ast_t* id = case_ast;

    if(ast_id(id) != TK_ID)
      id = ast_child(id);

    assert(ast_id(id) == TK_ID);
    const char* try_name = ast_name(id);

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }

  // Give up
  return NULL;
}
Exemplo n.º 16
0
ast_t* type_for_this(typecheck_t* t, ast_t* ast, token_id cap,
  token_id ephemeral)
{
  bool make_arrow = false;

  if(cap == TK_BOX)
  {
    cap = TK_REF;
    make_arrow = true;
  }

  AST_GET_CHILDREN(t->frame->type, id, typeparams);

  BUILD(typeargs, ast, NODE(TK_NONE));

  BUILD(type, ast,
    NODE(TK_NOMINAL,
      NODE(TK_NONE)
      TREE(id)
      TREE(typeargs)
      NODE(cap)
      NODE(ephemeral)));

  if(ast_id(typeparams) == TK_TYPEPARAMS)
  {
    ast_setid(typeargs, TK_TYPEARGS);
    ast_t* typeparam = ast_child(typeparams);

    while(typeparam != NULL)
    {
      ast_t* typeparam_id = ast_child(typeparam);
      ast_t* typearg = type_sugar(ast, NULL, ast_name(typeparam_id));
      ast_append(typeargs, typearg);

      typeparam = ast_sibling(typeparam);
    }
  }

  if(make_arrow)
  {
    BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type)));
    return arrow;
  }

  return type;
}
Exemplo n.º 17
0
static bool is_constructed_from(pass_opt_t* opt, ast_t* ast, ast_t* type)
{
  ast_t* parent = ast_parent(ast);

  if(ast_id(parent) != TK_DOT)
    return false;

  AST_GET_CHILDREN(parent, left, right);
  ast_t* find = lookup_try(opt, parent, type, ast_name(right));

  if(find == NULL)
    return false;

  bool ok = ast_id(find) == TK_NEW;
  ast_free_unattached(find);
  return ok;
}
Exemplo n.º 18
0
// Check that the given entity, if concrete, has bodies for all methods.
static bool check_concrete_bodies(ast_t* entity, pass_opt_t* opt)
{
  assert(entity != NULL);

  token_id variety = ast_id(entity);
  if((variety != TK_PRIMITIVE) && (variety != TK_STRUCT) &&
    (variety != TK_CLASS) && (variety != TK_ACTOR))
    return true;

  bool r = true;
  ast_t* members = ast_childidx(entity, 4);
  assert(members != NULL);

  for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p))
  {
    if(is_method(p))
    {
      method_t* info = (method_t*)ast_data(p);
      assert(info != NULL);

      if(!info->failed)
      {
        const char* name = ast_name(ast_childidx(p, 1));

        if(ast_checkflag(p, AST_FLAG_AMBIGUOUS))
        {
          // Concrete types must not have ambiguous bodies.
          ast_error(opt->check.errors, entity, "multiple possible bodies for "
            "method %s, local disambiguation required", name);
          r = false;
        }
        else if(info->body_donor == NULL)
        {
          // Concrete types must have method bodies.
          assert(info->trait_ref != NULL);
          ast_error(opt->check.errors, info->trait_ref,
            "no body found for method %s", name);
          r = false;
        }
      }
    }
  }

  return r;
}
Exemplo n.º 19
0
Arquivo: genfun.c Projeto: fydot/ponyc
static void name_params(compile_t* c, ast_t* type, ast_t* params,
  LLVMValueRef func)
{
  int count = 0;

  // Name the receiver 'this'.
  name_param(c, func, stringtab("this"), type, count++);

  // Name each parameter.
  ast_t* param = ast_child(params);

  while(param != NULL)
  {
    AST_GET_CHILDREN(param, id, type);
    name_param(c, func, ast_name(id), type, count++);
    param = ast_sibling(param);
  }
}
Exemplo n.º 20
0
// Add the given method to the relevant name list in the given symbol table
static bool add_method_to_list(ast_t* method, methods_t* method_info,
  const char *entity_name)
{
  assert(method != NULL);
  assert(method_info != NULL);
  assert(entity_name != NULL);

  const char* name = ast_name(ast_childidx(method, 1));
  assert(name != NULL);

  symtab_t* symtab = method_info->symtab;
  assert(symtab != NULL);

  // Entity doesn't yet have method, add it to our list for later
  ast_t* list = (ast_t*)symtab_find(symtab, name, NULL);

  if(list == NULL)
  {
    ast_t* case_clash = (ast_t*)symtab_find_case(symtab, name, NULL);

    if(case_clash != NULL)
    {
      ast_error(case_clash, "in %s method name differs only in case",
        entity_name);
      ast_error(method, "previous definition is here");
      return false;
    }

    // First instance of this name
    list = ast_blank(TK_ID);
    ast_set_name(list, name);
    symtab_add(symtab, name, (void*)list, SYM_NONE);

    if(method_info->last_list == NULL)
      ast_add(method_info->name_lists, list);
    else
      ast_add_sibling(method_info->last_list, list);

    method_info->last_list = list;
  }

  ast_add(list, method);
  return true;
}
Exemplo n.º 21
0
// Write the given list of type parameters to the current type file, with
// surrounding []. If the given list is empty nothing is written.
static void doc_type_params(docgen_t* docgen, ast_t* t_params,
  bool generate_links)
{
  assert(docgen != NULL);
  assert(docgen->type_file != NULL);
  assert(t_params != NULL);

  if(ast_id(t_params) == TK_NONE)
    return;

  assert(ast_id(t_params) == TK_TYPEPARAMS);

  if(generate_links)
    fprintf(docgen->type_file, "\\[");
  else
    fprintf(docgen->type_file, "[");
  ast_t* first = ast_child(t_params);

  for(ast_t* t_param = first; t_param != NULL; t_param = ast_sibling(t_param))
  {
    if(t_param != first)
      fprintf(docgen->type_file, ", ");

    AST_GET_CHILDREN(t_param, id, constraint, default_type);
    const char* name = ast_name(id);
    assert(name != NULL);

    if(ast_id(default_type) != TK_NONE)
      fprintf(docgen->type_file, "optional ");

    fprintf(docgen->type_file, "%s: ", name);

    if(ast_id(constraint) != TK_NONE)
      doc_type(docgen, constraint, generate_links);
    else
      fprintf(docgen->type_file, "no constraint");
  }

  if(generate_links)
    fprintf(docgen->type_file, "\\]");
  else
    fprintf(docgen->type_file, "]");
}
Exemplo n.º 22
0
static bool check_fields_defined(pass_opt_t* opt, ast_t* ast)
{
  assert(ast_id(ast) == TK_NEW);

  ast_t* members = ast_parent(ast);
  ast_t* member = ast_child(members);
  bool result = true;

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FVAR:
      case TK_FLET:
      case TK_EMBED:
      {
        sym_status_t status;
        ast_t* id = ast_child(member);
        ast_t* def = ast_get(ast, ast_name(id), &status);

        if((def != member) || (status != SYM_DEFINED))
        {
          ast_error(opt->check.errors, def,
            "field left undefined in constructor");
          result = false;
        }

        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  if(!result)
    ast_error(opt->check.errors, ast,
      "constructor with undefined fields is here");

  return result;
}
Exemplo n.º 23
0
static void list_doc_params(docgen_t* docgen, ast_t* params)
{
  assert(docgen != NULL);
  assert(docgen->type_file != NULL);
  assert(params != NULL);

  ast_t* first = ast_child(params);

  for(ast_t* param = first; param != NULL; param = ast_sibling(param))
  {
    if(param == first)
      fprintf(docgen->type_file, "#### Parameters\n\n");

    fprintf(docgen->type_file, "* ");

    AST_GET_CHILDREN(param, id, type, def_val);
    const char* name = ast_name(id);
    assert(name != NULL);

    fprintf(docgen->type_file, "  %s: ", name);
    doc_type(docgen, type, true);

    // if we have a default value, add it to the documentation
    if(ast_id(def_val) != TK_NONE)
    {
      switch(ast_id(def_val))
      {
        case TK_STRING:
          fprintf(docgen->type_file, "= \"%s\"", ast_get_print(def_val));
          break;

        default:
          fprintf(docgen->type_file, " = %s", ast_get_print(def_val));
          break;
      }
    }

    fprintf(docgen->type_file, "\n");
  }

  fprintf(docgen->type_file, "\n");
}
Exemplo n.º 24
0
static bool make_tuple_index(ast_t** astp)
{
  ast_t* ast = *astp;
  const char* name = ast_name(ast);

  if(!is_name_private(name))
    return false;

  for(size_t i = 1; name[i] != '\0'; i++)
  {
    if((name[i] < '0') || (name[i] > '9'))
      return false;
  }

  size_t index = strtol(&name[1], NULL, 10) - 1;
  ast_t* node = ast_from_int(ast, index);
  ast_replace(astp, node);

  return true;
}
Exemplo n.º 25
0
static const char* suggest_alt_name(ast_t* ast, const char* name)
{
  assert(ast != NULL);
  assert(name != NULL);

  size_t name_len = strlen(name);
  VLA(char, buf, name_len + 2);

  if(name[0] == '_')
  {
    // Try without leading underscore
    const char* try_name = stringtab(name + 1);

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }
  else
  {
    // Try with a leading underscore
    buf[0] = '_';
    strncpy(buf + 1, name, name_len + 1);
    const char* try_name = stringtab(buf);

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }

  // Try with a different case (without crossing type/value boundary)
  ast_t* case_ast = ast_get_case(ast, name, NULL);
  if(case_ast != NULL)
  {
    assert(ast_child(case_ast) != NULL);
    const char* try_name = ast_name(ast_child(case_ast));

    if(ast_get(ast, try_name, NULL) != NULL)
      return try_name;
  }

  // Give up
  return NULL;
}
Exemplo n.º 26
0
bool ffi_get_decl(typecheck_t* t, ast_t* ast, ast_t** out_decl,
  pass_opt_t* opt)
{
  pony_assert(t != NULL);
  pony_assert(ast != NULL);
  pony_assert(out_decl != NULL);

  const char* ffi_name = ast_name(ast_child(ast));

  // Get the symbol table for our containing ifdef (if any) directly. We can't
  // just search up through scopes as normal since FFI declarations in outer
  // scopes may not be valid within our ifdef.
  ast_t* ifdef = t->frame->ifdef_clause;
  pony_assert(ifdef != NULL);

  symtab_t* symtab = ast_get_symtab(ifdef);
  sym_status_t status;
  ast_t* decl = symtab_find(symtab, ffi_name, &status);

  if(status == SYM_ERROR)
    // We've already found an error with that FFI name in this context.
    return false;

  if(status == SYM_NONE)
  {
    // We've not looked that up yet.
    pony_assert(decl == NULL);
    if(!find_ffi_decl(ast, t->frame->package, t->frame->ifdef_cond, &decl, opt))
    {
      // That went wrong. Record that so we don't try again.
      symtab_add(symtab, ffi_name, NULL, SYM_ERROR);
      return false;
    }

    // Store declaration found for next time, including if we found nothing.
    symtab_add(symtab, ffi_name, decl, SYM_FFIDECL);
  }

  *out_decl = decl;
  return true;
}
Exemplo n.º 27
0
bool is_this_incomplete(typecheck_t* t, ast_t* ast)
{
  // If we're in a default argument, we're incomplete by definition.
  if(t->frame->method == NULL)
    return true;

  // If we're not in a constructor, we're complete by definition.
  if(ast_id(t->frame->method) != TK_NEW)
    return false;

  // Check if all fields have been marked as defined.
  ast_t* members = ast_childidx(t->frame->type, 4);
  ast_t* member = ast_child(members);

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FLET:
      case TK_FVAR:
      case TK_EMBED:
      {
        sym_status_t status;
        ast_t* id = ast_child(member);
        ast_get(ast, ast_name(id), &status);

        if(status != SYM_DEFINED)
          return true;

        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  return false;
}
Exemplo n.º 28
0
LLVMValueRef gen_string(compile_t* c, ast_t* ast)
{
  const char* name = ast_name(ast);

  genned_string_t k;
  k.string = name;
  size_t index = HASHMAP_UNKNOWN;
  genned_string_t* string = genned_strings_get(&c->strings, &k, &index);

  if(string != NULL)
    return string->global;

  ast_t* type = ast_type(ast);
  pony_assert(is_literal(type, "String"));
  reach_type_t* t = reach_type(c->reach, type);
  compile_type_t* c_t = (compile_type_t*)t->c_type;

  size_t len = ast_name_len(ast);

  LLVMValueRef args[4];
  args[0] = c_t->desc;
  args[1] = LLVMConstInt(c->intptr, len, false);
  args[2] = LLVMConstInt(c->intptr, len + 1, false);
  args[3] = codegen_string(c, name, len);

  LLVMValueRef inst = LLVMConstNamedStruct(c_t->structure, args, 4);
  LLVMValueRef g_inst = LLVMAddGlobal(c->module, c_t->structure, "");
  LLVMSetInitializer(g_inst, inst);
  LLVMSetGlobalConstant(g_inst, true);
  LLVMSetLinkage(g_inst, LLVMPrivateLinkage);
  LLVMSetUnnamedAddr(g_inst, true);

  string = POOL_ALLOC(genned_string_t);
  string->string = name;
  string->global = g_inst;
  genned_strings_putindex(&c->strings, string, index);

  return g_inst;
}
Exemplo n.º 29
0
// Collect the given type parameter
static void collect_type_param(ast_t* orig_param, ast_t* params, ast_t* args)
{
  assert(orig_param != NULL);

  // Get original type parameter info
  AST_GET_CHILDREN(orig_param, id, constraint, deflt);
  const char* name = ast_name(id);

  constraint = sanitise_type(constraint);
  assert(constraint != NULL);

  // New type parameter has the same constraint as the old one (sanitised)
  if(params != NULL)
  {
    BUILD(new_param, orig_param,
      NODE(TK_TYPEPARAM,
        ID(name)
        TREE(constraint)
        NONE));

    ast_append(params, new_param);
    ast_setid(params, TK_TYPEPARAMS);
  }

  // New type arguments binds to old type parameter
  if(args != NULL)
  {
    BUILD(new_arg, orig_param,
      NODE(TK_NOMINAL,
        NONE  // Package
        ID(name)
        NONE  // Type args
        NONE  // cap
        NONE)); // ephemeral

    ast_append(args, new_arg);
    ast_setid(args, TK_TYPEARGS);
  }
}
Exemplo n.º 30
0
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value,
  ast_t* l_type, ast_t* right)
{
  switch(ast_id(l_type))
  {
    case TK_NOMINAL:
    {
      assert(ast_id(right) == TK_ID);

      ast_t* def = (ast_t*)ast_data(l_type);
      ast_t* field = ast_get(def, ast_name(right), NULL);
      int index = (int)ast_index(field);

      if(ast_id(def) != TK_STRUCT)
        index++;

      if(ast_id(def) == TK_ACTOR)
        index++;

      return LLVMBuildStructGEP(c->builder, l_value, index, "");
    }

    case TK_TUPLETYPE:
    {
      assert(ast_id(right) == TK_INT);
      int index = (int)ast_int(right)->low;

      return LLVMBuildExtractValue(c->builder, l_value, index, "");
    }

    case TK_ARROW:
      return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right);

    default: {}
  }

  assert(0);
  return NULL;
}