Ejemplo n.º 1
0
static ast_t* viewpoint_for_type(token_id view, token_id eph, ast_t* type,
  int cap_index)
{
  ast_t* cap = ast_childidx(type, cap_index);
  token_id tcap = ast_id(cap);
  token_id rcap = cap_viewpoint(view, tcap);

  if(rcap == TK_NONE)
    return NULL;

  if((tcap != rcap) || (eph == TK_EPHEMERAL))
  {
    type = ast_dup(type);
    cap = ast_childidx(type, cap_index);
    ast_setid(cap, rcap);

    if(eph == TK_EPHEMERAL && ((view == TK_ISO) || (view == TK_TRN)))
    {
      // If we're adapting from an ephemeral type, make this type ephemeral.
      // iso^->iso = iso^, previous views were iso, alias(iso^) ~ alias(iso)
      // iso^->trn = trn^, previous views were tag, alias(trn^) ~ alias(tag)
      // trn^->iso = iso^, previous views were iso, alias(iso^) ~ alias(iso)
      // trn^->trn = trn^, previous views were trn, alias(trn^) ~ alias(trn)
      // alias(iso)->x isn't alllowed
      // alias(trn)->x = box->x
      // alias(iso^) ~ alias(box->iso)
      // alias(trn^) ~ alias(box->trn)
      // Doesn't work for ref, isn't needed for val, box or tag.
      ast_t* ephemeral = ast_sibling(cap);
      ast_setid(ephemeral, eph);
    }
  }

  return type;
}
Ejemplo n.º 2
0
ast_t* set_cap_and_ephemeral(ast_t* type, token_id cap, token_id ephemeral)
{
  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
    case TK_ISECTTYPE:
    case TK_TUPLETYPE:
    {
      ast_t* child = ast_child(type);
      type = ast_from(type, ast_id(type));

      while(child != NULL)
      {
        ast_append(type, set_cap_and_ephemeral(child, cap, ephemeral));
        child = ast_sibling(child);
      }

      return type;
    }

    case TK_NOMINAL:
    {
      type = ast_dup(type);
      AST_GET_CHILDREN(type, package, id, typeargs, tcap, eph);

      if(cap != TK_NONE)
        ast_setid(tcap, cap);

      ast_setid(eph, ephemeral);
      return type;
    }

    case TK_TYPEPARAMREF:
    {
      type = ast_dup(type);
      AST_GET_CHILDREN(type, id, tcap, eph);

      if(cap != TK_NONE)
        ast_setid(tcap, cap);

      ast_setid(eph, ephemeral);
      return type;
    }

    case TK_ARROW:
      // Just use the lhs of the viewpoint type.
      return set_cap_and_ephemeral(ast_childidx(type, 1), cap, ephemeral);

    default: {}
  }

  assert(0);
  return NULL;
}
Ejemplo n.º 3
0
bool expr_tilde(pass_opt_t* opt, ast_t** astp)
{
  if(!dot_or_tilde(opt, astp, true))
    return false;

  ast_t* ast = *astp;

  if(ast_id(ast) == TK_TILDE && ast_type(ast) != NULL &&
    ast_id(ast_type(ast)) == TK_OPERATORLITERAL)
  {
    ast_error(opt->check.errors, ast,
      "can't do partial application on a literal number");
    return false;
  }

  switch(ast_id(ast))
  {
    case TK_NEWREF:
    case TK_NEWBEREF:
      ast_setid(ast, TK_NEWAPP);
      return true;

    case TK_BEREF:
      ast_setid(ast, TK_BEAPP);
      return true;

    case TK_FUNREF:
      ast_setid(ast, TK_FUNAPP);
      return true;

    case TK_TYPEREF:
      ast_error(opt->check.errors, ast,
        "can't do partial application on a package");
      return false;

    case TK_FVARREF:
    case TK_FLETREF:
    case TK_EMBEDREF:
      ast_error(opt->check.errors, ast,
        "can't do partial application of a field");
      return false;

    default: {}
  }

  assert(0);
  return false;
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
0
static bool tuple_access(ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  // Change the lookup name to an integer index.
  if(!make_tuple_index(&right))
  {
    ast_error(right,
      "lookup on a tuple must take the form _X, where X is an integer");
    return false;
  }

  // Make sure our index is in bounds.
  type = ast_childidx(type, (size_t)ast_int(right));

  if(type == NULL)
  {
    ast_error(right, "tuple index is out of bounds");
    return false;
  }

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Ejemplo n.º 6
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);
    }
  }
}
Ejemplo n.º 7
0
static bool apply_default_arg(pass_opt_t* opt, ast_t* param, ast_t* arg)
{
  // Pick up a default argument.
  ast_t* def_arg = ast_childidx(param, 2);

  if(ast_id(def_arg) == TK_NONE)
  {
    ast_error(arg, "not enough arguments");
    return false;
  }

  ast_setid(arg, TK_SEQ);
  ast_add(arg, def_arg);

  // Type check the arg.
  if(ast_type(def_arg) == NULL)
  {
    if(ast_visit(&arg, NULL, pass_expr, opt) != AST_OK)
      return false;

    ast_visit(&arg, NULL, pass_nodebug, opt);
  } else {
    if(!expr_seq(arg))
      return false;
  }

  return true;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
static bool apply_default_arg(pass_opt_t* opt, ast_t* param, ast_t* arg)
{
  // Pick up a default argument.
  AST_GET_CHILDREN(param, id, type, def_arg);

  if(ast_id(def_arg) == TK_NONE)
  {
    ast_error(opt->check.errors, arg, "not enough arguments");
    return false;
  }

  if(ast_id(def_arg) == TK_LOCATION)
  {
    // Default argument is __loc. Expand call location.
    ast_t* location = expand_location(arg);
    ast_add(arg, location);

    if(!ast_passes_subtree(&location, opt, PASS_EXPR))
      return false;
  }
  else
  {
    // Just use default argument.
    ast_add(arg, def_arg);
  }

  ast_setid(arg, TK_SEQ);

  if(!expr_seq(opt, arg))
    return false;

  return true;
}
Ejemplo n.º 10
0
static ast_result_t sugar_update(ast_t** astp)
{
  ast_t* ast = *astp;
  assert(ast_id(ast) == TK_ASSIGN);

  AST_GET_CHILDREN(ast, value, call);

  if(ast_id(call) != TK_CALL)
    return AST_OK;

  // We are of the form:  x(y) = z
  // Replace us with:     x.update(y where value = z)
  AST_EXTRACT_CHILDREN(call, positional, named, expr);

  // If there are no named arguments yet, named will be a TK_NONE.
  ast_setid(named, TK_NAMEDARGS);

  // Build a new namedarg.
  BUILD_NO_DEBUG(namedarg, ast,
    NODE(TK_UPDATEARG,
      ID("value")
      NODE(TK_SEQ, TREE(value))));

  // Append the named arg to our existing list.
  ast_append(named, namedarg);

  // Replace with the update call.
  REPLACE(astp,
    NODE(TK_CALL,
      TREE(positional)
      TREE(named)
      NODE(TK_DOT, TREE(expr) ID("update"))));

  return AST_OK;
}
Ejemplo n.º 11
0
/* Load an ID node.
 * IDs are indicated by the keyword id followed by the ID name, all contained
 * within parentheses. For example:
 *    (id foo)
 *
 * The ( and id keyword must have been parsed before this is called.
 */
static ast_t* get_id(build_parser_t* builder, ast_t* existing_ast)
{
  assert(builder != NULL);

  if(existing_ast != NULL)
  {
    ast_free(existing_ast);
    build_error(builder, "Seen ID not first in node");
    return NULL;
  }

  ast_token_id id = get_token(builder);

  if(id != AT_ID && id != AT_STRING)
  {
    build_error(builder, "ID name expected");
    return NULL;
  }

  ast_t* ast = ast_token(builder->token);
  ast_setid(ast, TK_ID);
  save_token(builder);

  if(get_token(builder) != AT_RPAREN)
  {
    build_error(builder, "Close paren expected for ID");
    ast_free(ast);
    return NULL;
  }

  return ast;
}
Ejemplo n.º 12
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(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);

  const char* entity_name = ast_name(ast_child(entity));

  if(ast_id(reified_method) == TK_BE || ast_id(reified_method) == TK_NEW)
  {
    // Modify return type to the inheritting type
    ast_t* ret_type = ast_childidx(reified_method, 4);
    assert(ast_id(ret_type) == TK_NOMINAL);

    const char* pkg_name = package_name(ast_nearest(entity, TK_PACKAGE));
    ast_set_name(ast_childidx(ret_type, 0), pkg_name);
    ast_set_name(ast_childidx(ret_type, 1), entity_name);
  }

  // Ignore docstring
  ast_t* doc = ast_childidx(reified_method, 7);

  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(ast_childidx(reified_method, 1));
  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;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,
  pass_opt_t* opt)
{
  assert(
    (ast_id(typeparams) == TK_TYPEPARAMS) ||
    (ast_id(typeparams) == TK_NONE)
    );
  assert(
    (ast_id(typeargs) == TK_TYPEARGS) ||
    (ast_id(typeargs) == TK_NONE)
    );

  size_t param_count = ast_childcount(typeparams);
  size_t arg_count = ast_childcount(typeargs);

  if(param_count == arg_count)
    return true;

  if(param_count < arg_count)
  {
    if(errors)
    {
      ast_error(opt->check.errors, typeargs, "too many type arguments");
      ast_error_continue(opt->check.errors, typeparams, "definition is here");
    }

    return false;
  }

  // Pick up default type arguments if they exist.
  ast_setid(typeargs, TK_TYPEARGS);
  ast_t* typeparam = ast_childidx(typeparams, arg_count);

  while(typeparam != NULL)
  {
    ast_t* defarg = ast_childidx(typeparam, 2);

    if(ast_id(defarg) == TK_NONE)
      break;

    ast_append(typeargs, defarg);
    typeparam = ast_sibling(typeparam);
  }

  if(typeparam != NULL)
  {
    if(errors)
    {
      ast_error(opt->check.errors, typeargs, "not enough type arguments");
      ast_error_continue(opt->check.errors, typeparams, "definition is here");
    }

    return false;
  }

  return true;
}
Ejemplo n.º 15
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;
}
Ejemplo n.º 16
0
// Determine the UIF types that satisfy the given "simple" type.
// Here a simple type is defined as a non-tuple type that does not depend on
// any formal parameters.
static int uifset_simple_type(pass_opt_t* opt, ast_t* type)
{
  assert(type != NULL);

  int set = 0;

  for(int i = 0; i < UIF_COUNT; i++)
  {
    ast_t* uif = type_builtin(opt, type, _str_uif_types[i].name);
    ast_setid(ast_childidx(uif, 3), TK_VAL);
    ast_setid(ast_childidx(uif, 4), TK_EPHEMERAL);

    if(is_subtype(uif, type))
      set |= (1 << i);

    ast_free(uif);
  }

  return set;
}
Ejemplo n.º 17
0
bool expr_chain(pass_opt_t* opt, ast_t** astp)
{
  if(!entity_access(opt, astp))
    return false;

  ast_t* ast = *astp;

  switch(ast_id(ast))
  {
    case TK_BEREF:
      ast_setid(ast, TK_BECHAIN);
      return true;

    case TK_FUNREF:
      ast_setid(ast, TK_FUNCHAIN);
      return true;

    case TK_NEWREF:
    case TK_NEWBEREF:
      ast_error(opt->check.errors, ast,
        "can't do method chaining on a constructor");
      return false;

    case TK_TYPEREF:
      ast_error(opt->check.errors, ast,
        "can't do method chaining on a package");
      return false;

    case TK_FVARREF:
    case TK_FLETREF:
    case TK_EMBEDREF:
      ast_error(opt->check.errors, ast,
        "can't do method chaining on a field");
      return false;

    default: {}
  }

  assert(0);
  return false;
}
Ejemplo n.º 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;
}
Ejemplo n.º 19
0
// If the given tree is a TK_NONE expand it to a source None
static void expand_none(ast_t* ast, bool is_scope)
{
  if(ast_id(ast) != TK_NONE)
    return;

  if(is_scope)
    ast_scope(ast);

  ast_setid(ast, TK_SEQ);
  BUILD_NO_DEBUG(ref, ast, NODE(TK_REFERENCE, ID("None")));
  ast_add(ast, ref);
}
Ejemplo n.º 20
0
static bool method_access(pass_opt_t* opt, ast_t* ast, ast_t* method)
{
  AST_GET_CHILDREN(method, cap, id, typeparams, params, result, can_error,
    body);

  switch(ast_id(method))
  {
    case TK_NEW:
    {
      AST_GET_CHILDREN(ast, left, right);
      ast_t* type = ast_type(left);

      if(is_typecheck_error(type))
        return false;

      if(!constructor_type(opt, ast, ast_id(cap), type, &result))
        return false;
      break;
    }

    case TK_BE:
      ast_setid(ast, TK_BEREF);
      break;

    case TK_FUN:
      ast_setid(ast, TK_FUNREF);
      break;

    default:
      assert(0);
      return false;
  }

  ast_settype(ast, type_for_fun(method));

  if(ast_id(can_error) == TK_QUESTION)
    ast_seterror(ast);

  return is_method_called(opt, ast);
}
Ejemplo n.º 21
0
static ast_result_t sugar_try(ast_t* ast)
{
  AST_GET_CHILDREN(ast, ignore, else_clause, then_clause);

  if(ast_id(else_clause) == TK_NONE && ast_id(then_clause) != TK_NONE)
    // Then without else means we don't require a throwable in the try block
    ast_setid(ast, TK_TRY_NO_CHECK);

  expand_none(else_clause, true);
  expand_none(then_clause, true);

  return AST_OK;
}
Ejemplo n.º 22
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);
  }
}
Ejemplo n.º 23
0
static ast_result_t sugar_let(typecheck_t* t, ast_t* ast)
{
  ast_t* id = ast_child(ast);

  if(ast_id(id) == TK_DONTCARE)
  {
    // Replace "_" with "$1" in with and for variable lists
    ast_setid(id, TK_ID);
    ast_set_name(id, package_hygienic_id(t));
  }

  return AST_OK;
}
Ejemplo n.º 24
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);
}
Ejemplo n.º 25
0
static ast_t* viewpoint_lower_for_type(ast_t* type, int cap_index)
{
  ast_t* cap = ast_childidx(type, cap_index);
  token_id tcap = ast_id(cap);

  // For any chain of arrows, return a capability that is a subtype of the
  // resulting capability.
  // ref->iso = iso, val->iso = val, box->iso = tag => iso
  // ref->trn = trn, val->trn = val, box->trn = box => trn
  // ref->ref = ref, val->ref = val, box->ref = box => trn
  // ref->val = val, val->val = val, box->val = val => val
  // ref->box = box, val->box = val, box->box = box => val
  // ref->tag = tag, val->tag = tag, box->tag = tag => tag
  // #read: ref = trn, val = val, box = val => trn
  // #send: iso = iso, val = val, tag = tag => iso
  // #share: val = val, tag = tag => val
  // #any: iso = iso => iso
  switch(tcap)
  {
    case TK_ISO:
    case TK_TRN:
    case TK_VAL:
    case TK_TAG:
      return type;

    case TK_REF:
    case TK_CAP_READ:
      tcap = TK_TRN;
      break;

    case TK_BOX:
    case TK_CAP_SHARE:
      tcap = TK_VAL;
      break;

    case TK_CAP_SEND:
    case TK_CAP_ANY:
      tcap = TK_ISO;
      break;

    default:
      assert(0);
      return NULL;
  }

  type = ast_dup(type);
  cap = ast_childidx(type, cap_index);
  ast_setid(cap, tcap);
  return type;
}
Ejemplo n.º 26
0
static ast_result_t sugar_return(typecheck_t* t, ast_t* ast)
{
  ast_t* return_value = ast_child(ast);

  if((ast_id(ast) == TK_RETURN) && (ast_id(t->frame->method) == TK_NEW))
  {
    assert(ast_id(return_value) == TK_NONE);
    ast_setid(return_value, TK_THIS);
  } else {
    expand_none(return_value, false);
  }

  return AST_OK;
}
Ejemplo n.º 27
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);
  assert(params != NULL);
  assert(args != 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)
  BUILD(new_param, orig_param,
    NODE(TK_TYPEPARAM,
      ID(name)
      TREE(constraint)
      NONE));

  ast_append(params, new_param);

  // New type arguments binds to old type parameter
  BUILD(new_arg, orig_param,
    NODE(TK_TYPEPARAMREF, DATA(orig_param)  
      ID(name)
      NONE  // cap
      NONE)); // ephemeral

  ast_append(args, new_arg);

  // Since we have a type parameter the params and args node should not be
  // TK_NONE
  ast_setid(params, TK_TYPEPARAMS);
  ast_setid(args, TK_TYPEARGS);
}
Ejemplo n.º 28
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;
}
Ejemplo n.º 29
0
// Check type parameters and build the all type parameter structures for a
// complete set of case methods with the given name.
// Generate type parameter list for worker call.
static void build_t_params(ast_t* match_t_params,
  ast_t* worker_t_params)
{
  assert(match_t_params != NULL);
  assert(worker_t_params != NULL);

  for(ast_t* p = ast_child(match_t_params); p != NULL; p = ast_sibling(p))
  {
    AST_GET_CHILDREN(p, id, constraint, def_type);
    assert(ast_id(id) == TK_ID);

    // Add type parameter name to worker call list.
    BUILD(type, p, NODE(TK_NOMINAL, NONE TREE(id) NONE NONE NONE));
    ast_append(worker_t_params, type);
    ast_setid(worker_t_params, TK_TYPEARGS);
  }
}
Ejemplo n.º 30
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;
}