示例#1
0
文件: traits.c 项目: abingham/ponyc
// Sort out symbol table for copied method body
static ast_result_t rescope(ast_t** astp, pass_opt_t* options)
{
  (void)options;
  ast_t* ast = *astp;

  if(ast_has_scope(ast))
    ast_clear_local(ast);

  switch(ast_id(ast))
  {
    case TK_FVAR:
    case TK_FLET:
    case TK_PARAM:
    case TK_TYPEPARAM:
      assert(ast_child(ast) != NULL);
      ast_set(ast, ast_name(ast_child(ast)), ast, SYM_DEFINED);
      break;

    case TK_LET:
    case TK_VAR:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_DEFINED);
      break;
    }

    default: {}
  }

  return AST_OK;
}
示例#2
0
文件: traits.c 项目: awaidmann/ponyc
// Sort out symbol table for copied method body.
static ast_result_t rescope(ast_t** astp, pass_opt_t* options)
{
  (void)options;
  ast_t* ast = *astp;

  if(ast_has_scope(ast))
    ast_clear_local(ast);

  switch(ast_id(ast))
  {
    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
    case TK_PARAM:
    case TK_TYPEPARAM:
    {
      assert(ast_child(ast) != NULL);
      ast_set(ast, ast_name(ast_child(ast)), ast, SYM_DEFINED, true);
      break;
    }

    case TK_LET:
    case TK_VAR:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_UNDEFINED, true);
      break;
    }

    case TK_MATCH_CAPTURE:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_DEFINED, true);
      break;
    }

    case TK_TYPEPARAMREF:
    {
      assert(ast_child(ast) != NULL);
      ast_t* def = ast_get(ast, ast_name(ast_child(ast)), NULL);
      ast_setdata(ast, def);
      break;
    }

    default: {}
  }

  return AST_OK;
}
示例#3
0
文件: package.c 项目: dipinhora/ponyc
// Create a package AST, set up its state and add it to the given program
ast_t* create_package(ast_t* program, const char* name,
  const char* qualified_name, pass_opt_t* opt)
{
  ast_t* package = ast_blank(TK_PACKAGE);
  uint32_t pkg_id = program_assign_pkg_id(program);

  package_t* pkg = POOL_ALLOC(package_t);
  pkg->path = name;
  pkg->qualified_name = qualified_name;
  pkg->id = id_to_string(NULL, pkg_id);

  const char* p = strrchr(pkg->path, PATH_SLASH);

  if(p == NULL)
    p = pkg->path;
  else
    p = p + 1;

  pkg->filename = stringtab(p);

  if(pkg_id > 1)
    pkg->symbol = create_package_symbol(program, pkg->filename);
  else
    pkg->symbol = NULL;

  pkg->ast = package;
  package_set_init(&pkg->dependencies, 1);
  pkg->group = NULL;
  pkg->group_index = -1;
  pkg->next_hygienic_id = 0;
  pkg->low_index = -1;
  ast_setdata(package, pkg);

  ast_scope(package);
  ast_append(program, package);
  ast_set(program, pkg->path, package, SYM_NONE, false);
  ast_set(program, pkg->id, package, SYM_NONE, false);

  strlist_t* safe = opt->safe_packages;

  if((safe != NULL) && (strlist_find(safe, pkg->path) == NULL))
    pkg->allow_ffi = false;
  else
    pkg->allow_ffi = true;

  pkg->on_stack = false;

  return package;
}
示例#4
0
文件: traits.c 项目: abingham/ponyc
// Process the given list of provided methods (all of the same name) for the
// given entity
static bool process_method_name(ast_t* list, ast_t* entity)
{
  assert(list != NULL);
  assert(entity != NULL);

  const char* name = ast_name(list);
  assert(name != NULL);

  ast_t* existing = ast_get(entity, name, NULL);

  if(existing != NULL)
  {
    // Method is explicitly defined in entity
    if(!methods_compatible(list, existing, name, entity))
      return false;
  } else {
    // Method is not defined in entity
    existing = most_general_method(list, entity, name);

    if(existing == NULL)
      return false;

    // Add the most general method from the list to the entity
    existing = ast_dup(existing);
    ast_append(ast_childidx(entity, 4), existing);
    ast_set(entity, name, existing, SYM_NONE);
  }

  // Current body (if any) is not provided by this entity, get one from the
  // trait methods
  if(ast_data(existing) != (void*)entity)
    attach_body_from_list(list, existing);

  return true;
}
示例#5
0
文件: traits.c 项目: lzpfmh/ponyc
// Check that the given method is compatible with the existing definition.
// Return the method that ends up being in the entity or NULL on error.
// Stages 2A, 2B and 2C.
static ast_t* add_method(ast_t* entity, ast_t* existing_method,
  ast_t* new_method, ast_t** last_method)
{
  assert(entity != NULL);
  assert(new_method != NULL);
  assert(last_method != NULL);

  const char* name = ast_name(ast_childidx(new_method, 1));
  const char* entity_name = ast_name(ast_child(entity));

  if(existing_method == NULL)
  {
    // This method is new to the entity.
    // Stage 2C.
    ast_t* case_clash = ast_get_case(entity, name, NULL);

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

    attach_method_t(new_method, NULL, false);
    ast_list_append(ast_childidx(entity, 4), last_method, new_method);
    ast_set(entity, name, new_method, SYM_DEFINED);
    return *last_method;
  }

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

  if(info->local_def)
  {
    // Existing method is a local definition, new method must be a subtype
    // Stage 2A
    if(is_subtype(existing_method, new_method, true))
      return existing_method;

    ast_error(existing_method,
      "local method %s is not compatible with provided version", name);
    ast_error(new_method, "clashing method is here");

    return NULL;
  }

  // Both method versions came from the provides list, their signatures must
  // match exactly
  // Stage 2B
  if(compare_signatures(existing_method, new_method))
    return existing_method;

  ast_error(entity, "clashing definitions of method %s provided, local "
    "disambiguation required", name);
  ast_error(existing_method, "provided here");
  ast_error(new_method, "and here");

  return NULL;
}
示例#6
0
文件: package.c 项目: dleonard0/ponyc
// Create a package AST, set up its state and add it to the given program
static ast_t* create_package(ast_t* program, const char* name)
{
  ast_t* package = ast_blank(TK_PACKAGE);
  uint32_t pkg_id = program_assign_pkg_id(program);

  package_t* pkg = POOL_ALLOC(package_t);
  pkg->path = name;
  pkg->id = id_to_string(NULL, pkg_id);

  const char* p = strrchr(pkg->path, PATH_SLASH);

  if(p == NULL)
    p = pkg->path;
  else
    p = p + 1;

  pkg->filename = stringtab(p);

  if(pkg_id > 1)
    pkg->symbol = create_package_symbol(program, pkg->filename);
  else
    pkg->symbol = NULL;

  pkg->next_hygienic_id = 0;
  ast_setdata(package, pkg);

  ast_scope(package);
  ast_append(program, package);
  ast_set(program, pkg->path, package, SYM_NONE);
  ast_set(program, pkg->id, package, SYM_NONE);

  if((safe != NULL) && (strlist_find(safe, pkg->path) == NULL))
    pkg->allow_ffi = false;
  else
    pkg->allow_ffi = true;

  return package;
}
示例#7
0
文件: scope.c 项目: jonas-l/ponyc
/**
 * Insert a name->AST mapping into the specified scope.
 */
static bool set_scope(typecheck_t* t, ast_t* scope, ast_t* name, ast_t* value)
{
  assert(ast_id(name) == TK_ID);
  const char* s = ast_name(name);

  sym_status_t status = SYM_NONE;

  switch(ast_id(value))
  {
    case TK_ID:
    {
      if((t != NULL) && (t->frame->pattern != NULL))
        status = SYM_DEFINED;
      else
        status = SYM_UNDEFINED;

      break;
    }

    case TK_FFIDECL:
    case TK_TYPE:
    case TK_INTERFACE:
    case TK_TRAIT:
    case TK_PRIMITIVE:
    case TK_CLASS:
    case TK_ACTOR:
    case TK_TYPEPARAM:
    case TK_PACKAGE:
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
      status = SYM_DEFINED;
      break;

    case TK_PARAM:
      status = SYM_DEFINED;
      break;

    default:
      assert(0);
      return false;
  }

  if(!ast_set(scope, s, value, status))
  {
    ast_t* prev = ast_get(scope, s, NULL);
    ast_t* prev_nocase = ast_get_case(scope, s, NULL);

    ast_error(name, "can't reuse name '%s'", s);
    ast_error(prev_nocase, "previous use of '%s'%s",
      s, (prev == NULL) ? " differs only by case" : "");

    return false;
  }

  return true;
}
示例#8
0
文件: traits.c 项目: lzpfmh/ponyc
// Add eq() and ne() functions to the given entity.
static bool add_comparable(ast_t* ast, pass_opt_t* options)
{
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, id, typeparams, defcap, traits, members);
  ast_t* typeargs = ast_from(typeparams, TK_NONE);
  bool r = true;

  for(ast_t* p = ast_child(typeparams); p != NULL; p = ast_sibling(p))
  {
    ast_t* p_id = ast_child(p);

    BUILD_NO_DEBUG(type, p_id,
      NODE(TK_NOMINAL, NONE TREE(p_id) NONE NONE NONE));

    ast_append(typeargs, type);
    ast_setid(typeargs, TK_TYPEARGS);
  }

  if(!has_member(members, "eq"))
  {
    BUILD_NO_DEBUG(eq, members,
      NODE(TK_FUN, AST_SCOPE
        NODE(TK_BOX)
        ID("eq")
        NONE
        NODE(TK_PARAMS,
          NODE(TK_PARAM,
            ID("that")
            NODE(TK_NOMINAL, NONE TREE(id) TREE(typeargs) NONE NONE)
            NONE))
        NODE(TK_NOMINAL, NONE ID("Bool") NONE NONE NONE)
        NONE
        NODE(TK_SEQ,
          NODE(TK_IS,
            NODE(TK_THIS)
            NODE(TK_REFERENCE, ID("that"))))
        NONE
        NONE));

    // Need to set function data field to point to originating type, ie ast.
    // This won't be done when we catch up the passes since we've already
    // processed that type.
    ast_setdata(eq, ast);
    ast_append(members, eq);
    ast_set(ast, stringtab("eq"), eq, SYM_DEFINED);

    if(!ast_passes_subtree(&eq, options, PASS_TRAITS))
      r = false;
  }

  if(!has_member(members, "ne"))
  {
    BUILD_NO_DEBUG(ne, members,
      NODE(TK_FUN, AST_SCOPE
        NODE(TK_BOX)
        ID("ne")
        NONE
        NODE(TK_PARAMS,
          NODE(TK_PARAM,
            ID("that")
            NODE(TK_NOMINAL, NONE TREE(id) TREE(typeargs) NONE NONE)
            NONE))
        NODE(TK_NOMINAL, NONE ID("Bool") NONE NONE NONE)
        NONE
        NODE(TK_SEQ,
          NODE(TK_ISNT,
            NODE(TK_THIS)
            NODE(TK_REFERENCE, ID("that"))))
        NONE
        NONE));

    // Need to set function data field to point to originating type, ie ast.
    // This won't be done when we catch up the passes since we've already
    // processed that type.
    ast_setdata(ne, ast);
    ast_append(members, ne);
    ast_set(ast, stringtab("ne"), ne, SYM_DEFINED);

    if(!ast_passes_subtree(&ne, options, PASS_TRAITS))
      r = false;
  }

  ast_free_unattached(typeargs);
  return r;
}
示例#9
0
文件: traits.c 项目: awaidmann/ponyc
// Add a new method to the given entity, based on the specified method from
// the specified type.
// The trait_ref is the entry in the provides / delegates list that causes this
// method inclusion. Needed for error reporting.
// The basis_method is the reified method in the trait to add.
// The adjective parameter is used for error reporting and should be "provided"
// or similar.
// Return the newly added method or NULL on error.
static ast_t* add_method(ast_t* entity, ast_t* trait_ref, ast_t* basis_method,
  const char* adjective, pass_opt_t* opt)
{
  assert(entity != NULL);
  assert(trait_ref != NULL);
  assert(basis_method != NULL);
  assert(adjective != NULL);

  const char* name = ast_name(ast_childidx(basis_method, 1));

  // Check behaviour compatability.
  if(ast_id(basis_method) == TK_BE)
  {
    switch(ast_id(entity))
    {
      case TK_PRIMITIVE:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a primitive", name);
        return NULL;

      case TK_STRUCT:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a struct", name);
        return NULL;

      case TK_CLASS:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a class", name);
        return NULL;

      default:
        break;
    }
  }

  // Check for existing method of the same name.
  ast_t* existing = ast_get(entity, name, NULL);

  if(existing != NULL)
  {
    assert(is_field(existing)); // Should already have checked for methods.

    ast_error(opt->check.errors, trait_ref,
      "%s method '%s' clashes with field", adjective, name);
    ast_error_continue(opt->check.errors, basis_method,
      "method is defined here");
    return NULL;
  }

  // Check for clash with existing method.
  ast_t* case_clash = ast_get_case(entity, name, NULL);

  if(case_clash != NULL)
  {
    const char* clash_name = "";

    switch(ast_id(case_clash))
    {
      case TK_FUN:
      case TK_BE:
      case TK_NEW:
        clash_name = ast_name(ast_childidx(case_clash, 1));
        break;

      case TK_LET:
      case TK_VAR:
      case TK_EMBED:
        clash_name = ast_name(ast_child(case_clash));
        break;

      default:
        assert(0);
        break;
    }

    ast_error(opt->check.errors, trait_ref,
      "%s method '%s' differs only in case from '%s'",
      adjective, name, clash_name);
    ast_error_continue(opt->check.errors, basis_method,
      "clashing method is defined here");
    return NULL;
  }

  AST_GET_CHILDREN(basis_method, cap, id, typeparams, params, result,
    can_error, body, doc);

  // Ignore docstring.
  if(ast_id(doc) == TK_STRING)
  {
    ast_set_name(doc, "");
    ast_setid(doc, TK_NONE);
  }

  ast_t* local = ast_append(ast_childidx(entity, 4), basis_method);
  ast_set(entity, name, local, SYM_DEFINED, false);
  ast_t* body_donor = (ast_t*)ast_data(basis_method);
  method_t* info = attach_method_t(local);
  info->trait_ref = trait_ref;

  if(ast_id(body) != TK_NONE)
    info->body_donor = body_donor;

  return local;
}