Пример #1
0
static void names_applycap_index(ast_t* ast, ast_t* cap, ast_t* ephemeral,
  int index)
{
  ast_t* a_cap = ast_childidx(ast, index);
  ast_t* a_ephemeral = ast_sibling(a_cap);

  if(ast_id(cap) != TK_NONE)
    ast_replace(&a_cap, cap);

  if(ast_id(ephemeral) != TK_NONE)
    ast_replace(&a_ephemeral, ephemeral);
}
Пример #2
0
static bool reify_typeparamref(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  assert(ast_id(ast) == TK_TYPEPARAMREF);
  ast_t* ref_name = ast_child(ast);
  ast_t* param_name = ast_child(typeparam);

  if(ast_name(ref_name) != ast_name(param_name))
    return false;

  // Keep ephemerality.
  switch(ast_id(ast_childidx(ast, 2)))
  {
    case TK_EPHEMERAL:
      typearg = consume_type(typearg, TK_NONE);
      break;

    case TK_NONE:
      break;

    case TK_BORROWED:
      typearg = alias(typearg);
      break;

    default:
      assert(0);
      return false;
  }

  ast_replace(astp, typearg);
  return true;
}
Пример #3
0
static ast_result_t sugar_new(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result);

  // Return type default to ref^ for classes, val^ for primitives, and
  // tag^ for actors.
  if(ast_id(result) == TK_NONE)
  {
    token_id tcap = ast_id(cap);

    if(tcap == TK_NONE)
    {
      switch(ast_id(t->frame->type))
      {
        case TK_PRIMITIVE: tcap = TK_VAL; break;
        case TK_ACTOR: tcap = TK_TAG; break;
        default: tcap = TK_REF; break;
      }

      ast_setid(cap, tcap);
    }

    ast_replace(&result, type_for_this(opt, ast, tcap, TK_EPHEMERAL, false));
  }

  sugar_docstring(ast);
  return check_method(ast);
}
Пример #4
0
static void reify_typeparamref(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  assert(ast_id(ast) == TK_TYPEPARAMREF);

  ast_t* ref_def = (ast_t*)ast_data(ast);
  ast_t* param_def = (ast_t*)ast_data(typeparam);

  assert(ref_def != NULL);
  assert(param_def != NULL);

  if(ref_def != param_def)
    return;

  // Keep ephemerality.
  switch(ast_id(ast_childidx(ast, 2)))
  {
    case TK_EPHEMERAL:
      typearg = consume_type(typearg, TK_NONE);
      break;

    case TK_NONE:
      break;

    case TK_BORROWED:
      typearg = alias(typearg);
      break;

    default:
      assert(0);
  }

  ast_replace(astp, typearg);
}
Пример #5
0
static ast_result_t sugar_ffi(ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, typeargs, args, named_args);

  const char* name = ast_name(id);
  size_t len = ast_name_len(id);

  // Check for \0 in ffi name (it may be a string literal)
  if(memchr(name, '\0', len) != NULL)
  {
    ast_error(ast, "FFI function names cannot include nul characters");
    return AST_ERROR;
  }

  // Prefix '@' to the name
  char* new_name = (char*)pool_alloc_size(len + 2);
  new_name[0] = '@';
  memcpy(new_name + 1, name, len);
  new_name[len + 1] = '\0';

  ast_t* new_id = ast_from_string(id, stringtab_consume(new_name, len + 2));
  ast_replace(&id, new_id);

  if(ast_id(ast) == TK_FFIDECL)
    return check_params(args);

  return AST_OK;
}
Пример #6
0
static bool check_type_params(ast_t** astp)
{
  ast_t* lhs = *astp;
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  ast_t* typeparams = ast_childidx(type, 1);
  assert(ast_id(type) == TK_FUNTYPE);

  if(ast_id(typeparams) == TK_NONE)
    return true;

  BUILD(typeargs, typeparams, NODE(TK_TYPEARGS));

  if(!check_constraints(typeparams, typeargs, true))
  {
    ast_free_unattached(typeargs);
    return false;
  }

  type = reify(type, typeparams, typeargs);
  typeparams = ast_childidx(type, 1);
  ast_replace(&typeparams, ast_from(typeparams, TK_NONE));

  REPLACE(astp, NODE(ast_id(lhs), TREE(lhs) TREE(typeargs)));
  ast_settype(*astp, type);

  return true;
}
Пример #7
0
static bool names_type(typecheck_t* t, ast_t** astp, ast_t* def)
{
  ast_t* ast = *astp;
  AST_GET_CHILDREN(ast, package, id, typeparams, cap, eph);
  token_id tcap = ast_id(cap);

  if((tcap == TK_NONE) && (ast_id(def) == TK_PRIMITIVE))
  {
    // A primitive without a capability is a val, even if it is a constraint.
    tcap = TK_VAL;
  } else if(t->frame->constraint != NULL) {
    // A constraint is modified to a generic capability.
    switch(tcap)
    {
      case TK_NONE: tcap = TK_ANY_GENERIC; break;
      case TK_BOX: tcap = TK_BOX_GENERIC; break;
      case TK_TAG: tcap = TK_TAG_GENERIC; break;
      default: {}
    }
  } else if(tcap == TK_NONE) {
    // Otherwise, we use the default capability.
    tcap = ast_id(ast_childidx(def, 2));
  }

  ast_setid(cap, tcap);

  // Keep the actual package id.
  ast_append(ast, package);
  ast_replace(&package, package_id(def));

  // Store our definition for later use.
  ast_setdata(ast, def);
  return true;
}
Пример #8
0
static ast_result_t flatten_arrow(pass_opt_t* opt, ast_t** astp)
{
  AST_GET_CHILDREN(*astp, left, right);

  switch(ast_id(left))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_REF:
    case TK_VAL:
    case TK_BOX:
    case TK_TAG:
    case TK_THISTYPE:
    case TK_TYPEPARAMREF:
    {
      ast_t* r_ast = viewpoint_type(left, right);
      ast_replace(astp, r_ast);
      return AST_OK;
    }

    default: {}
  }

  ast_error(opt->check.errors, left,
    "only 'this', refcaps, and type parameters can be viewpoints");
  return AST_ERROR;
}
Пример #9
0
    void AST_t::replace_with(AST_t ast)
    {
        if (ast._ast == NULL)
        {
            internal_error("Trying to replace a tree with an empty tree.", 0);
        }

        if (this->_ast == NULL)
        {
            internal_error("Trying to replace an empty tree with another tree", 0);
        }

        AST previous_parent = ASTParent(this->_ast);
        ast_replace(this->_ast, ast._ast);
        ast_set_parent(this->_ast, previous_parent);

        // Relink sons
        for (int i = 0; i < ASTNumChildren(this->_ast); i++)
        {
            if (ASTChild(this->_ast, i) != NULL)
            {
                ast_set_parent(ASTChild(this->_ast, i), this->_ast);
            }
        }
    }
Пример #10
0
static ast_t* make_single_arrow(ast_t* left, ast_t* right)
{
  switch(ast_id(left))
  {
    case TK_ARROW:
    {
      ast_t* arrow = ast_dup(left);
      ast_t* child = ast_childidx(arrow, 1);

      // Arrow is right associative.
      while(ast_id(child) == TK_ARROW)
        child = ast_childidx(child, 1);

      ast_t* view = viewpoint_type(child, right);

      if(view == NULL)
      {
        ast_free_unattached(arrow);
        return NULL;
      }

      ast_replace(&child, view);
      return arrow;
    }

    default: {}
  }

  ast_t* arrow = ast_from(left, TK_ARROW);
  ast_add(arrow, right);
  ast_add(arrow, left);
  return arrow;
}
Пример #11
0
static bool names_typealias(pass_opt_t* opt, ast_t** astp, ast_t* def)
{
  ast_t* ast = *astp;
  AST_GET_CHILDREN(ast, pkg, id, typeargs, cap, eph);

  // Make sure the alias is resolved,
  AST_GET_CHILDREN(def, alias_id, typeparams, def_cap, provides);
  ast_t* alias = ast_child(provides);

  if(!names_resolvealias(opt, def, &alias))
    return false;

  // Reify the alias.
  ast_t* r_alias = reify(typeparams, alias, typeparams, typeargs);

  if(r_alias == NULL)
    return false;

  // Apply our cap and ephemeral to the result.
  if(!names_applycap(r_alias, cap, eph))
  {
    ast_free_unattached(r_alias);
    return false;
  }

  // Maintain the position info of the original reference to aid error
  // reporting.
  ast_setpos(r_alias, ast_line(ast), ast_pos(ast));

  // Replace this with the alias.
  ast_replace(astp, r_alias);
  return true;
}
Пример #12
0
// Attach the appropriate body (if any) from the given method list to the given
// entity method
static void attach_body_from_list(ast_t* list, ast_t* entity_method)
{
  assert(list != NULL);
  assert(entity_method != NULL);

  void* data = ast_data(entity_method);

  for(ast_t* p = ast_child(list); p != NULL; p = ast_sibling(p))
  {
    void* p_data = ast_data(p);

    if(p_data != NULL && p_data != data && is_eqtype(entity_method, p))
    {
      // p has a valid (and different) body

      if(data != NULL || p_data == BODY_AMBIGUOUS)
      {
        // Multiple possible bodies
        ast_setdata(entity_method, BODY_AMBIGUOUS);
        return;
      }

      // This is the first valid body, use it
      ast_t* old_body = ast_childidx(entity_method, 6);
      assert(ast_id(old_body) == TK_NONE);
      ast_replace(&old_body, ast_childidx(p, 6));
      ast_setdata(entity_method, p_data);
      data = p_data;
    }
  }
}
Пример #13
0
static void add_field_to_object(pass_opt_t* opt, ast_t* field,
  ast_t* class_members, ast_t* create_params, ast_t* create_body,
  ast_t* call_args)
{
  AST_GET_CHILDREN(field, id, type, init);
  ast_t* p_id = ast_from_string(id, package_hygienic_id(&opt->check));

  // The param is: $0: type
  BUILD(param, field,
    NODE(TK_PARAM,
      TREE(p_id)
      TREE(type)
      NONE));

  // The arg is: $seq init
  BUILD(arg, init,
    NODE(TK_SEQ,
      TREE(init)));

  // The body of create contains: id = consume $0
  BUILD(assign, init,
    NODE(TK_ASSIGN,
      NODE(TK_CONSUME, NODE(TK_NONE) NODE(TK_REFERENCE, TREE(p_id)))
      NODE(TK_REFERENCE, TREE(id))));

  // Remove the initialiser from the field
  ast_replace(&init, ast_from(init, TK_NONE));

  ast_add(class_members, field);
  ast_append(create_params, param);
  ast_append(create_body, assign);
  ast_append(call_args, arg);
}
Пример #14
0
void fun_defaults(ast_t* ast)
{
  assert(ast != NULL);
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body,
    docstring);

  // If the receiver cap is not specified, set it to box.
  if(ast_id(cap) == TK_NONE)
    ast_setid(cap, TK_BOX);

  // If the return value is not specified, set it to None.
  if(ast_id(result) == TK_NONE)
  {
    ast_t* type = type_sugar(ast, NULL, "None");
    ast_replace(&result, type);
  }

  // If the return type is None, add a None at the end of the body, unless it
  // already ends with an error or return statement
  if(is_none(result) && (ast_id(body) != TK_NONE))
  {
    ast_t* last_cmd = ast_childlast(body);

    if(ast_id(last_cmd) != TK_ERROR && ast_id(last_cmd) != TK_RETURN)
    {
      BUILD_NO_DEBUG(ref, body, NODE(TK_REFERENCE, ID("None")));
      ast_append(body, ref);
    }
  }
}
Пример #15
0
static bool apply_named_args(pass_opt_t* opt, ast_t* params, ast_t* positional,
  ast_t* namedargs)
{
  ast_t* namedarg = ast_pop(namedargs);

  while(namedarg != NULL)
  {
    AST_GET_CHILDREN(namedarg, arg_id, arg);

    ast_t* param = ast_child(params);
    size_t param_index = 0;

    while(param != NULL)
    {
      AST_GET_CHILDREN(param, param_id);

      if(ast_name(arg_id) == ast_name(param_id))
        break;

      param = ast_sibling(param);
      param_index++;
    }

    if(param == NULL)
    {
      if(ast_id(namedarg) == TK_UPDATEARG)
      {
        ast_error(opt->check.errors, arg_id,
          "cannot use sugar, update() has no parameter named \"value\"");
        return false;
      }

      ast_error(opt->check.errors, arg_id, "not a parameter name");
      return false;
    }

    ast_t* arg_replace = ast_childidx(positional, param_index);

    if(ast_id(arg_replace) != TK_NONE)
    {
      ast_error(opt->check.errors, arg_id,
        "named argument is already supplied");
      ast_error_continue(opt->check.errors, arg_replace,
        "supplied argument is here");
      return false;
    }

    // Extract named argument expression to avoid copying it
    ast_free(ast_pop(namedarg));  // ID
    arg = ast_pop(namedarg);  // Expression

    ast_replace(&arg_replace, arg);
    namedarg = ast_pop(namedargs);
  }

  ast_setid(namedargs, TK_NONE);
  return true;
}
Пример #16
0
// Sugar any case methods in the given entity.
ast_result_t sugar_case_methods(typecheck_t* t, ast_t* entity)
{
  assert(entity != NULL);

  ast_result_t result = AST_OK;
  ast_t* members = ast_childidx(entity, 4);
  bool cases_found = false;

  // Check each method to see if its name is repeated, which indicates a case
  // method.
  for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p))
  {
    if(ast_id(p) == TK_FUN || ast_id(p) == TK_BE)
    {
      const char* p_name = ast_name(ast_childidx(p, 1));

      // Check if any subsequent methods share p's name.
      for(ast_t* q = ast_sibling(p); q != NULL; q = ast_sibling(q))
      {
        if(ast_id(q) == TK_FUN || ast_id(q) == TK_BE)
        {
          const char* q_name = ast_name(ast_childidx(q, 1));

          if(q_name == p_name)
          {
            // p's name is repeated, it's a case method, get a match method.
            if(!sugar_case_method(p, members, p_name, t))
              result = AST_ERROR;

            cases_found = true;
            break;
          }
        }
      }
    }
  }

  if(cases_found)
  {
    // Remove nodes marked during processing.
    ast_t* filtered_members = ast_from(members, TK_MEMBERS);
    ast_t* list = NULL;
    ast_t* member;

    while((member = ast_pop(members)) != NULL)
    {
      if(ast_id(member) == TK_NONE) // Marked for removal.
        ast_free(member);
      else  // Put back in filtered list.
        ast_list_append(filtered_members, &list, member);
    }

    ast_replace(&members, filtered_members);
  }

  return result;
}
Пример #17
0
// Process the given provided method for the given entity.
// The method passed should be reified already and will be freed by this
// function.
static bool provided_method(pass_opt_t* opt, ast_t* entity,
  ast_t* reified_method, ast_t* raw_method, ast_t** last_method)
{
  assert(entity != NULL);
  assert(reified_method != NULL);
  assert(last_method != NULL);

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

  if(ast_id(reified_method) == TK_BE || ast_id(reified_method) == TK_NEW)
  {
    // Modify return type to the inheriting type
    ast_t* this_type = type_for_this(opt, entity, ast_id(cap),
      TK_EPHEMERAL, true);

    ast_replace(&result, this_type);
  }

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

  // Check for existing method of the same name
  const char* name = ast_name(id);
  assert(name != NULL);

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

  if(existing != NULL && is_field(existing))
  {
    ast_error(existing, "field '%s' clashes with provided method", name);
    ast_error(raw_method, "method is defined here");
    ast_free_unattached(reified_method);
    return false;
  }

  existing = add_method(entity, existing, reified_method, last_method);

  if(existing == NULL)
  {
    ast_free_unattached(reified_method);
    return false;
  }

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

  if(!record_default_body(reified_method, raw_method, info))
    ast_free_unattached(reified_method);

  return true;
}
Пример #18
0
// Convert the given method into a delegation indirection to the specified
// field.
static void make_delegation(ast_t* method, ast_t* field, ast_t* delegate_ref,
  ast_t* body_donor)
{
  assert(method != NULL);
  assert(field != NULL);
  assert(delegate_ref != NULL);

  // Make a redirection method body.
  ast_t* args = ast_from(delegate_ref, TK_NONE);
  ast_t* last_arg = NULL;

  AST_GET_CHILDREN(method, cap, id, t_params, params, result, error, old_body);

  for(ast_t* p = ast_child(params); p != NULL; p = ast_sibling(p))
  {
    const char* param_name = ast_name(ast_child(p));

    BUILD(arg, delegate_ref,
      NODE(TK_SEQ,
        NODE(TK_CONSUME,
          NONE
          NODE(TK_REFERENCE, ID(param_name)))));

    ast_list_append(args, &last_arg, arg);
    ast_setid(args, TK_POSITIONALARGS);
  }

  BUILD(body, delegate_ref,
    NODE(TK_SEQ,
      NODE(TK_CALL,
        TREE(args)    // Positional args.
        NODE(TK_NONE) // Named args.
        NODE(TK_DOT,  // Receiver.
          NODE(TK_REFERENCE, ID(ast_name(ast_child(field))))
          ID(ast_name(ast_childidx(method, 1)))))));

  if(is_none(result))
  {
    // Add None to end of body. Whilst the call generated above will return
    // None anyway in this case, without this extra None testing is very hard
    // since a directly written version of this body will have the None.
    BUILD(none, delegate_ref, NODE(TK_REFERENCE, ID("None")));
    ast_append(body, none);
  }

  ast_replace(&old_body, body);

  // Setup method info.
  method_t* info = (method_t*)ast_data(method);
  assert(info != NULL);
  info->body_donor = body_donor;
  info->delegated_field = field;
}
Пример #19
0
static ast_result_t sugar_with(typecheck_t* t, ast_t** astp)
{
  AST_EXTRACT_CHILDREN(*astp, withexpr, body, else_clause);
  token_id try_token;

  if(ast_id(else_clause) == TK_NONE)
    try_token = TK_TRY_NO_CHECK;
  else
    try_token = TK_TRY;

  expand_none(else_clause, false);

  // First build a skeleton try block without the "with" variables
  BUILD(replace, *astp,
    NODE(TK_SEQ,
      NODE(try_token,
        NODE(TK_SEQ, AST_SCOPE
          TREE(body))
        NODE(TK_SEQ, AST_SCOPE
          TREE(else_clause))
        NODE(TK_SEQ, AST_SCOPE))));

  ast_t* tryexpr = ast_child(replace);
  AST_GET_CHILDREN(tryexpr, try_body, try_else, try_then);

  // Add the "with" variables from each with element
  for(ast_t* p = ast_child(withexpr); p != NULL; p = ast_sibling(p))
  {
    assert(ast_id(p) == TK_SEQ);
    AST_GET_CHILDREN(p, idseq, init);
    const char* init_name = package_hygienic_id(t);

    BUILD(assign, idseq,
      NODE(TK_ASSIGN, AST_NODEBUG
        TREE(init)
        NODE(TK_LET, ID(init_name) NONE)));

    BUILD(local, idseq,
      NODE(TK_ASSIGN, AST_NODEBUG
        NODE(TK_REFERENCE, ID(init_name))
        TREE(idseq)));

    ast_add(replace, assign);
    ast_add(try_body, local);
    ast_add(try_else, local);
    build_with_dispose(try_then, idseq);
    ast_add(try_then, local);
  }

  ast_replace(astp, replace);
  return AST_OK;
}
Пример #20
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;
}
Пример #21
0
static ast_result_t sugar_be(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body);
  ast_setid(cap, TK_TAG);

  if(ast_id(result) == TK_NONE)
  {
    // Return type is This tag
    ast_replace(&result, type_for_this(opt, ast, TK_TAG, TK_NONE, false));
  }

  sugar_docstring(ast);
  return check_method(ast);
}
Пример #22
0
bool flatten_arrows(ast_t** astp, bool errors)
{
  ast_t* ast = *astp;
  ast_t* node_type = ast_type(ast);

  if(node_type != NULL)
  {
    if(!flatten_arrows(&node_type, errors))
      return false;
  }

  if(ast_id(ast) == TK_ARROW)
  {
    AST_GET_CHILDREN(ast, left, right);
    ast_t* flat;

    if(!flatten_arrows(&right, errors))
      return false;

    if((ast_id(left) == TK_BOXTYPE) && (ast_id(right) != TK_ARROW))
      flat = viewpoint_cap(TK_BOX, TK_NONE, right);
    else
      flat = viewpoint_type(left, right);

    if(flat == NULL)
    {
      if(errors)
        ast_error(ast, "can't flatten arrow type");

      return false;
    }

    ast_replace(astp, flat);
    return true;
  }

  ast_t* child = ast_child(ast);

  while(child != NULL)
  {
    if(!flatten_arrows(&child, errors))
      return false;

    child = ast_sibling(child);
  }

  return true;
}
Пример #23
0
static bool reify_one(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  ast_t* type = ast_type(ast);

  if(type != NULL)
    reify_one(&type, typeparam, typearg);

  if(ast_id(ast) == TK_TYPEPARAMREF)
    return reify_typeparamref(astp, typeparam, typearg);

  ast_t* child = ast_child(ast);
  bool flatten = false;

  while(child != NULL)
  {
    flatten |= reify_one(&child, typeparam, typearg);
    child = ast_sibling(child);
  }

  // Flatten type expressions after reifying them.
  if(flatten)
  {
    switch(ast_id(ast))
    {
      case TK_ARROW:
      {
        AST_GET_CHILDREN(ast, left, right);
        ast = viewpoint_type(left, right);

        if(ast == NULL)
          return false;

        if(ast == right)
          ast = ast_dup(ast);

        ast_replace(astp, ast);
        return true;
      }

      default: {}
    }
  }

  return false;
}
Пример #24
0
// Flatten a provides type into a list, checking all types are traits or
// interfaces
static ast_result_t flatten_provides_list(ast_t* provider, int index)
{
  assert(provider != NULL);

  ast_t* provides = ast_childidx(provider, index);
  ast_t* list = ast_from(provides, TK_PROVIDES);
  ast_t* list_end = NULL;

  if(ast_id(provides) != TK_NONE &&
    !flatten_provided_type(provides, provider, list, &list_end))
  {
    ast_free(list);
    return AST_ERROR;
  }

  ast_replace(&provides, list);
  return AST_OK;
}
Пример #25
0
static void reify_arrow(ast_t** astp)
{
  ast_t* ast = *astp;
  assert(ast_id(ast) == TK_ARROW);
  AST_GET_CHILDREN(ast, left, right);

  ast_t* r_left = left;
  ast_t* r_right = right;

  if(ast_id(left) == TK_ARROW)
  {
    AST_GET_CHILDREN(left, l_left, l_right);
    r_left = l_left;
    r_right = viewpoint_type(l_right, right);
  }

  ast_t* r_type = viewpoint_type(r_left, r_right);
  ast_replace(astp, r_type);
}
Пример #26
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;
}
Пример #27
0
static void reify_typeparamref(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  pony_assert(ast_id(ast) == TK_TYPEPARAMREF);
  pony_assert(ast_id(typeparam) == TK_TYPEPARAM);

  ast_t* ref_def = (ast_t*)ast_data(ast);

  // We can't compare ref_def and typeparam, as they could be a copy or
  // a iftype shadowing. However, their data points back to the original
  // typeparam definition, which can be compared.
  ref_def = (ast_t*)ast_data(ref_def);
  typeparam = (ast_t*)ast_data(typeparam);

  pony_assert(ref_def != NULL);
  pony_assert(typeparam != NULL);

  if(ref_def != typeparam)
    return;

  // Keep ephemerality.
  switch(ast_id(ast_childidx(ast, 2)))
  {
    case TK_EPHEMERAL:
      typearg = consume_type(typearg, TK_NONE);
      break;

    case TK_NONE:
      break;

    case TK_ALIASED:
      typearg = alias(typearg);
      break;

    default:
      pony_assert(0);
  }

  ast_replace(astp, typearg);
}
Пример #28
0
static void sugar_docstring(ast_t* ast)
{
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, cap, id, type_params, params, return_type,
    error, body, docstring);

  if(ast_id(docstring) == TK_NONE)
  {
    ast_t* first = ast_child(body);

    // First expression in body is a docstring if it is a string literal and
    // there are any other expressions in the body sequence
    if((first != NULL) &&
      (ast_id(first) == TK_STRING) &&
      (ast_sibling(first) != NULL))
    {
      ast_pop(body);
      ast_replace(&docstring, first);
    }
  }
}
Пример #29
0
static ast_result_t sugar_case(ast_t* ast)
{
  ast_t* body = ast_childidx(ast, 2);

  if(ast_id(body) != TK_NONE)
    return AST_OK;

  // We have no body, take a copy of the next case with a body
  ast_t* next = ast;
  ast_t* next_body = body;

  while(ast_id(next_body) == TK_NONE)
  {
    next = ast_sibling(next);
    assert(next != NULL);
    assert(ast_id(next) == TK_CASE);
    next_body = ast_childidx(next, 2);
  }

  ast_replace(&body, next_body);
  return AST_OK;
}
Пример #30
0
void replace_thistype(ast_t** astp, ast_t* type)
{
  ast_t* ast = *astp;

  if(ast_id(ast) == TK_THISTYPE)
  {
    ast_replace(astp, type);
    return;
  }

  ast_t* node_type = ast_type(ast);

  if(node_type != NULL)
    replace_thistype(&node_type, type);

  ast_t* child = ast_child(ast);

  while(child != NULL)
  {
    replace_thistype(&child, type);
    child = ast_sibling(child);
  }
}