Beispiel #1
0
ast_t* control_type_add_branch(ast_t* control_type, ast_t* branch)
{
  assert(branch != NULL);

  ast_t* branch_type = ast_type(branch);

  if(is_typecheck_error(branch_type))
    return branch_type;

  if(is_type_literal(branch_type))
  {
    // The new branch is a literal
    if(control_type == NULL)
      control_type = ast_from(branch, TK_LITERAL);

    if(ast_id(control_type) != TK_LITERAL)
    {
      // The current control type is not a literal, fix that
      ast_t* old_control = control_type;
      control_type = ast_from(branch, TK_LITERAL);
      ast_settype(control_type, old_control);
    }

    assert(ast_id(control_type) == TK_LITERAL);

    // Add a literal branch reference to the new branch
    ast_t* member = ast_from(branch, TK_LITERALBRANCH);
    ast_setdata(member, (void*)branch);
    ast_append(control_type, member);

    ast_t* branch_non_lit = ast_type(branch_type);

    if(branch_non_lit != NULL)
    {
      // The branch's literal type has a non-literal component
      ast_t* non_literal_type = ast_type(control_type);
      ast_settype(control_type, type_union(non_literal_type, branch_non_lit));
    }

    return control_type;
  }

  if(control_type != NULL && ast_id(control_type) == TK_LITERAL)
  {
    // New branch is not literal, but the control structure is
    // Add new branch type to the control structure's non-literal aspect
    ast_t* non_literal_type = ast_type(control_type);
    non_literal_type = type_union(non_literal_type, branch_type);
    ast_settype(control_type, non_literal_type);
    return control_type;
  }

  // No literals here, just union the types
  return type_union(control_type, branch_type);
}
Beispiel #2
0
void collect_type_params(ast_t* ast, ast_t** out_params, ast_t** out_args)
{
  assert(ast != NULL);

  // Create params and args as TK_NONE, we'll change them if we find any type
  // params
  ast_t* params = out_params ? ast_from(ast, TK_NONE) : NULL;
  ast_t* args = out_args ? ast_from(ast, TK_NONE) : NULL;

  // Find enclosing entity, or NULL if not within an entity
  ast_t* entity = ast;

  while(entity != NULL && ast_id(entity) != TK_INTERFACE &&
    ast_id(entity) != TK_TRAIT && ast_id(entity) != TK_PRIMITIVE &&
    ast_id(entity) != TK_STRUCT && ast_id(entity) != TK_CLASS &&
    ast_id(entity) != TK_ACTOR)
  {
    entity = ast_parent(entity);
  }

  // Find enclosing method, or NULL if not within a method
  ast_t* method = ast;

  while(method != NULL && ast_id(method) != TK_FUN &&
    ast_id(method) != TK_NEW && ast_id(method) != TK_BE)
  {
    method = ast_parent(method);
  }

  // Collect type parameters defined on the entity (if within an entity)
  if(entity != NULL)
  {
    ast_t* entity_t_params = ast_childidx(entity, 1);

    for(ast_t* p = ast_child(entity_t_params); p != NULL; p = ast_sibling(p))
      collect_type_param(p, params, args);
  }

  // Collect type parameters defined on the method (if within a method)
  if(method != NULL)
  {
    ast_t* method_t_params = ast_childidx(method, 2);

    for(ast_t* p = ast_child(method_t_params); p != NULL; p = ast_sibling(p))
      collect_type_param(p, params, args);
  }

  if(out_params != NULL)
    *out_params = params;

  if(out_args != NULL)
    *out_args = args;
}
Beispiel #3
0
ast_t* viewpoint_replacethis(ast_t* ast, ast_t* with)
{
  ast_t* thistype = ast_from(ast, TK_THISTYPE);
  ast_t* r_ast = viewpoint_replace(ast, thistype, with);
  ast_free_unattached(thistype);
  return r_ast;
}
Beispiel #4
0
bool expr_compiler_intrinsic(typecheck_t* t, ast_t* ast)
{
  if(t->frame->method_body == NULL)
  {
    ast_error(ast, "a compiler intrinsic must be a method body");
    return false;
  }

  ast_t* child = ast_child(t->frame->method_body);

  // Allow a docstring before the compiler_instrinsic.
  if(ast_id(child) == TK_STRING)
    child = ast_sibling(child);

  if((child != ast) || (ast_sibling(child) != NULL))
  {
    ast_error(ast, "a compiler intrinsic must be the entire body");
    return false;
  }

  // Disable debuglocs on calls to this method.
  ast_setdebug(t->frame->method, false);

  ast_settype(ast, ast_from(ast, TK_COMPILER_INTRINSIC));
  return true;
}
Beispiel #5
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;
}
Beispiel #6
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);
}
Beispiel #7
0
bool expr_break(typecheck_t* t, ast_t* ast)
{
    if(t->frame->loop_body == NULL)
    {
        ast_error(ast, "must be in a loop");
        return false;
    }

    if(!ast_all_consumes_in_scope(t->frame->loop_body, ast))
        return false;

    // break is always the last expression in a sequence
    assert(ast_sibling(ast) == NULL);

    ast_settype(ast, ast_from(ast, TK_BREAK));
    ast_inheritflags(ast);

    // Add type to loop.
    ast_t* body = ast_child(ast);

    if(is_control_type(ast_type(body)))
    {
        ast_error(body, "break value cannot be a control statement");
        return false;
    }

    ast_t* loop_type = ast_type(t->frame->loop);

    loop_type = control_type_add_branch(loop_type, body);
    ast_settype(t->frame->loop, loop_type);

    return true;
}
Beispiel #8
0
static bool push_assume(ast_t* sub, ast_t* super)
{
  // Returns true if we have already assumed sub is a subtype of super.
  if(subtype_assume != NULL)
  {
    ast_t* assumption = ast_child(subtype_assume);

    while(assumption != NULL)
    {
      AST_GET_CHILDREN(assumption, assume_sub, assume_super);

      if(exact_nominal(sub, assume_sub) &&
        exact_nominal(super, assume_super))
        return true;

      assumption = ast_sibling(assumption);
    }
  } else {
    subtype_assume = ast_from(sub, TK_NONE);
  }

  BUILD(assume, sub, NODE(TK_NONE, TREE(ast_dup(sub)) TREE(ast_dup(super))));
  ast_add(subtype_assume, assume);
  return false;
}
Beispiel #9
0
static ast_result_t sugar_binop(ast_t** astp, const char* fn_name)
{
  AST_GET_CHILDREN(*astp, left, right);

  ast_t* positional = ast_from(right, TK_POSITIONALARGS);

  if(ast_id(right) == TK_TUPLE)
  {
    ast_t* value = ast_child(right);

    while(value != NULL)
    {
      BUILD(arg, right, NODE(TK_SEQ, TREE(value)));
      ast_append(positional, arg);
      value = ast_sibling(value);
    }
  } else {
    BUILD(arg, right, NODE(TK_SEQ, TREE(right)));
    ast_add(positional, arg);
  }

  REPLACE(astp,
    NODE(TK_CALL,
      TREE(positional)
      NONE
      NODE(TK_DOT, TREE(left) ID(fn_name))
      ));

  return AST_OK;
}
Beispiel #10
0
bool expr_lambda(pass_opt_t* opt, ast_t** astp)
{
  assert(astp != NULL);
  ast_t* ast = *astp;
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, cap, t_params, params, captures, ret_type, raises,
    body);

  ast_t* members = ast_from(ast, TK_MEMBERS);
  ast_t* last_member = NULL;
  bool failed = false;

  // Process captures
  for(ast_t* p = ast_child(captures); p != NULL; p = ast_sibling(p))
  {
    ast_t* field = make_capture_field(p);

    if(field != NULL)
      ast_list_append(members, &last_member, field);
    else  // An error occurred, just keep going to potentially find more errors
      failed = true;
  }

  if(failed)
  {
    ast_free(members);
    return false;
  }

  // Stop the various elements being marked as preserve
  ast_clearflag(t_params, AST_FLAG_PRESERVE);
  ast_clearflag(params, AST_FLAG_PRESERVE);
  ast_clearflag(ret_type, AST_FLAG_PRESERVE);
  ast_clearflag(body, AST_FLAG_PRESERVE);

  // Make the apply function
  BUILD(apply, ast,
    NODE(TK_FUN, AST_SCOPE
      NONE  // Capability
      ID("apply")
      TREE(t_params)
      TREE(params)
      TREE(ret_type)
      TREE(raises)
      TREE(body)
      NONE));  // Doc string

  ast_list_append(members, &last_member, apply);

  // Replace lambda with object literal
  REPLACE(astp,
    NODE(TK_OBJECT,
      TREE(cap);
      NONE  // Provides list
      TREE(members)));

  // Catch up passes
  return ast_passes_subtree(astp, opt, PASS_EXPR);
}
Beispiel #11
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;
}
Beispiel #12
0
bool expr_compile_error(ast_t* ast)
{
  // compile_error is always the last expression in a sequence
  assert(ast_sibling(ast) == NULL);

  ast_settype(ast, ast_from(ast, TK_COMPILE_ERROR));
  return true;
}
Beispiel #13
0
bool expr_error(pass_opt_t* opt, ast_t* ast)
{
  (void)opt;
  // error is always the last expression in a sequence
  assert(ast_sibling(ast) == NULL);

  ast_settype(ast, ast_from(ast, TK_ERROR));
  return true;
}
Beispiel #14
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;
}
Beispiel #15
0
// Handle the given case method parameter list.
// Combine and check the case parameters against the existing match parameters
// and generate the match pattern to go in the worker method.
// Returns: match pattern, NULL on error.
static ast_t* process_params(ast_t* match_params, ast_t* case_params)
{
  assert(match_params != NULL);
  assert(case_params != NULL);

  bool ok = true;
  size_t count = 0;
  ast_t* pattern = ast_from(case_params, TK_TUPLE);
  ast_t* case_param = ast_child(case_params);
  ast_t* match_param = ast_child(match_params);

  while(case_param != NULL && match_param != NULL)
  {
    AST_GET_CHILDREN(case_param, id, type, def_arg);

    if(ast_id(type) != TK_NONE)
    {
      // We have a parameter.
      if(!param_with_type(case_param, match_param, pattern))
        ok = false;
    }
    else
    {
      // We have a value to match.
      if(!param_without_type(case_param, pattern))
        ok = false;
    }

    case_param = ast_sibling(case_param);
    match_param = ast_sibling(match_param);
    count++;
  }

  if(case_param != NULL || match_param != NULL)
  {
    ast_error(case_params, "differing number of parameters to case methods");
    ast_error(match_params, "clashing parameter count here");
    ok = false;
  }

  if(!ok)
  {
    ast_free(pattern);
    return NULL;
  }

  assert(count > 0);
  if(count == 1)
  {
    // Only one parameter, don't need a tuple pattern.
    ast_t* tmp = ast_pop(ast_child(pattern));
    ast_free(pattern);
    pattern = tmp;
  }

  return pattern;
}
Beispiel #16
0
ast_t* viewpoint_reifythis(ast_t* type)
{
  ast_t* tuple = ast_from(type, TK_TUPLETYPE);

  ast_t* this_ref = ast_from(type, TK_REF);
  ast_append(tuple, viewpoint_replacethis(type, this_ref));
  ast_free_unattached(this_ref);

  ast_t* this_val = ast_from(type, TK_VAL);
  ast_append(tuple, viewpoint_replacethis(type, this_val));
  ast_free_unattached(this_val);

  ast_t* this_box = ast_from(type, TK_BOX);
  ast_append(tuple, viewpoint_replacethis(type, this_box));
  ast_free_unattached(this_box);

  return tuple;
}
Beispiel #17
0
static token_id partial_application_cap(pass_opt_t* opt, ast_t* ftype,
  ast_t* receiver, ast_t* positional)
{
  // Check if the apply method in the generated object literal can accept a box
  // receiver. If not, it must be a ref receiver. It can accept a box receiver
  // if box->receiver <: lhs->receiver and box->arg <: lhs->param.
  AST_GET_CHILDREN(ftype, cap, typeparams, params, result);

  ast_t* type = ast_type(receiver);
  ast_t* view_type = viewpoint_type(ast_from(type, TK_BOX), type);
  ast_t* need_type = set_cap_and_ephemeral(type, ast_id(cap), TK_NONE);

  bool ok = is_subtype(view_type, need_type, NULL, opt);
  ast_free_unattached(view_type);
  ast_free_unattached(need_type);

  if(!ok)
    return TK_REF;

  ast_t* param = ast_child(params);
  ast_t* arg = ast_child(positional);

  while(arg != NULL)
  {
    if(ast_id(arg) != TK_NONE)
    {
      type = ast_type(arg);
      view_type = viewpoint_type(ast_from(type, TK_BOX), type);
      need_type = ast_childidx(param, 1);

      ok = is_subtype(view_type, need_type, NULL, opt);
      ast_free_unattached(view_type);
      ast_free_unattached(need_type);

      if(!ok)
        return TK_REF;
    }

    arg = ast_sibling(arg);
    param = ast_sibling(param);
  }

  return TK_BOX;
}
Beispiel #18
0
bool expr_repeat(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, body, cond, else_clause);

  ast_t* body_type = ast_type(body);
  ast_t* cond_type = ast_type(cond);
  ast_t* else_type = ast_type(else_clause);

  if(is_typecheck_error(cond_type))
    return false;

  if(!is_bool(cond_type))
  {
    ast_error(opt->check.errors, cond, "condition must be a Bool");
    return false;
  }

  if(is_typecheck_error(body_type) || is_typecheck_error(else_type))
    return false;

  // All consumes have to be in scope when the loop body finishes.
  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(body, body, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

  // Union with any existing type due to a break expression.
  ast_t* type = ast_type(ast);

  // No symbol status is inherited from the loop body or condition. Nothing
  // from outside can be consumed, and definitions inside may not occur.
  if(!is_control_type(body_type))
    type = control_type_add_branch(opt, type, body);

  if(!is_control_type(else_type))
  {
    type = control_type_add_branch(opt, type, else_clause);
    ast_inheritbranch(ast, else_clause);

    // Use a branch count of two instead of one. This means we will pick up any
    // consumes, but not any definitions, since definitions may not occur.
    ast_consolidate_branches(ast, 2);
  }

  if(type == NULL)
    type = ast_from(ast, TK_REPEAT);

  ast_settype(ast, type);
  literal_unify_control(ast, opt);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), ast);
  return true;
}
Beispiel #19
0
bool expr_if(pass_opt_t* opt, ast_t* ast)
{
    ast_t* cond = ast_child(ast);
    ast_t* left = ast_sibling(cond);
    ast_t* right = ast_sibling(left);
    ast_t* cond_type = ast_type(cond);

    if(is_typecheck_error(cond_type))
        return false;

    if(!is_bool(cond_type))
    {
        ast_error(cond, "condition must be a Bool");
        return false;
    }

    ast_t* l_type = ast_type(left);
    ast_t* r_type = ast_type(right);

    ast_t* type = NULL;
    size_t branch_count = 0;

    if(!is_control_type(l_type))
    {
        type = control_type_add_branch(type, left);
        ast_inheritbranch(ast, left);
        branch_count++;
    }

    if(!is_control_type(r_type))
    {
        type = control_type_add_branch(type, right);
        ast_inheritbranch(ast, right);
        branch_count++;
    }

    if(type == NULL)
    {
        if(ast_sibling(ast) != NULL)
        {
            ast_error(ast_sibling(ast), "unreachable code");
            return false;
        }

        type = ast_from(ast, TK_IF);
    }

    ast_settype(ast, type);
    ast_inheritflags(ast);
    ast_consolidate_branches(ast, branch_count);
    literal_unify_control(ast, opt);

    // Push our symbol status to our parent scope.
    ast_inheritstatus(ast_parent(ast), ast);
    return true;
}
Beispiel #20
0
bool expr_try(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, body, else_clause, then_clause);

  ast_t* body_type = ast_type(body);
  ast_t* else_type = ast_type(else_clause);
  ast_t* then_type = ast_type(then_clause);

  if(is_typecheck_error(body_type) ||
    is_typecheck_error(else_type) ||
    is_typecheck_error(then_type))
    return false;

  ast_t* type = NULL;

  if(!is_control_type(body_type))
    type = control_type_add_branch(opt, type, body);

  if(!is_control_type(else_type))
    type = control_type_add_branch(opt, type, else_clause);

  if(type == NULL)
  {
    if(ast_sibling(ast) != NULL)
    {
      ast_error(opt->check.errors, ast_sibling(ast), "unreachable code");
      return false;
    }

    type = ast_from(ast, TK_TRY);
  }

  // The then clause does not affect the type of the expression.
  if(is_control_type(then_type))
  {
    ast_error(opt->check.errors, then_clause,
      "then clause always terminates the function");
    return false;
  }

  if(is_type_literal(then_type))
  {
    ast_error(opt->check.errors, then_clause,
      "Cannot infer type of unused literal");
    return false;
  }

  ast_settype(ast, type);

  literal_unify_control(ast, opt);

  // Push the symbol status from the then clause to our parent scope.
  ast_inheritstatus(ast_parent(ast), then_clause);
  return true;
}
Beispiel #21
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;
}
Beispiel #22
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;
}
Beispiel #23
0
ast_t* ast_from_string(ast_t* ast, const char* name)
{
  if(name == NULL)
    return ast_from(ast, TK_NONE);

  token_t* t = token_dup(ast->t);
  token_set_id(t, TK_ID);
  token_set_string(t, name, 0);

  ast_t* new_ast = ast_token(t);
  set_scope_no_parent(new_ast, ast->parent);
  return new_ast;
}
Beispiel #24
0
void collect_type_params(ast_t* ast, ast_t** out_params, ast_t** out_args)
{
  assert(ast != NULL);
  assert(out_params != NULL);
  assert(out_args != NULL);

  // Create params and args as TK_NONE, we'll change them if we find any type
  // params
  ast_t* params = ast_from(ast, TK_NONE);
  ast_t* args = ast_from(ast, TK_NONE);

  ast_t* method = ast;

  // Find enclosing method
  while(ast_id(method) != TK_FUN && ast_id(method) != TK_NEW &&
    ast_id(method) != TK_BE)
  {
    method = ast_parent(method);
    assert(method != NULL);
  }

  // Find enclosing entity
  ast_t* entity = ast_parent(ast_parent(method));
  ast_t* entity_t_params = ast_childidx(entity, 1);

  // Collect type parameters defined on the entity
  for(ast_t* p = ast_child(entity_t_params); p != NULL; p = ast_sibling(p))
    collect_type_param(p, params, args);

  ast_t* method_t_params = ast_childidx(method, 1);

  // Collect type parameters defined on the method
  for(ast_t* p = ast_child(method_t_params); p != NULL; p = ast_sibling(p))
    collect_type_param(p, params, args);

  *out_params = params;
  *out_args = args;
}
Beispiel #25
0
static ast_result_t sugar_as(pass_opt_t* opt, ast_t** astp)
{
  typecheck_t* t = &opt->check;
  ast_t* ast = *astp;
  AST_GET_CHILDREN(ast, expr, type);

  ast_t* pattern_root = ast_from(type, TK_LEX_ERROR);
  ast_t* body_root = ast_from(type, TK_LEX_ERROR);
  add_as_type(t, type, pattern_root, body_root);

  ast_t* body = ast_pop(body_root);
  ast_free(body_root);

  if(body == NULL)
  {
    // No body implies all types are "don't care"
    ast_error(ast, "Cannot treat value as \"don't care\"");
    ast_free(pattern_root);
    return AST_ERROR;
  }

  // Don't need top sequence in pattern
  assert(ast_id(ast_child(pattern_root)) == TK_SEQ);
  ast_t* pattern = ast_pop(ast_child(pattern_root));
  ast_free(pattern_root);

  REPLACE(astp,
    NODE(TK_MATCH, AST_SCOPE
      NODE(TK_SEQ, TREE(expr))
      NODE(TK_CASES, AST_SCOPE
        NODE(TK_CASE, AST_SCOPE
          TREE(pattern)
          NONE
          TREE(body)))
      NODE(TK_SEQ, AST_SCOPE NODE(TK_ERROR, NONE))));

  return ast_visit(astp, pass_sugar, NULL, opt, PASS_SUGAR);
}
Beispiel #26
0
// Setup the type, or lack thereof, for local variable declarations.
// This is not really anything to do with traits, but must be done before the
// expr pass (to allow initialisation references to the variable type) but
// after the name pass (to get temporal capabilities).
static void local_types(ast_t* ast)
{
  assert(ast != NULL);

  // Setup type or mark as inferred now to allow calling create on a
  // non-inferred local to initialise itself
  AST_GET_CHILDREN(ast, id, type);
  assert(type != NULL);

  if(ast_id(type) == TK_NONE)
    type = ast_from(id, TK_INFERTYPE);

  ast_settype(id, type);
  ast_settype(ast, type);
}
Beispiel #27
0
static void reify_reference(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  pony_assert(ast_id(ast) == TK_REFERENCE);

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

  sym_status_t status;
  ast_t* ref_def = ast_get(ast, name, &status);

  if(ref_def == NULL)
    return;

  ast_t* param_def = (ast_t*)ast_data(typeparam);
  pony_assert(param_def != NULL);

  if(ref_def != param_def)
    return;

  ast_setid(ast, TK_TYPEREF);
  ast_add(ast, ast_from(ast, TK_NONE));    // 1st child: package reference
  ast_append(ast, ast_from(ast, TK_NONE)); // 3rd child: type args
  ast_settype(ast, typearg);
}
Beispiel #28
0
ast_t* viewpoint_cap(token_id cap, token_id eph, ast_t* type)
{
  if(cap == TK_TAG)
    return NULL;

  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
    case TK_ISECTTYPE:
    case TK_TUPLETYPE:
    {
      // Adapt all elements.
      ast_t* r_type = ast_from(type, ast_id(type));
      ast_t* child = ast_child(type);

      while(child != NULL)
      {
        ast_append(r_type, viewpoint_cap(cap, eph, child));
        child = ast_sibling(child);
      }

      return r_type;
    }

    case TK_NOMINAL:
      return viewpoint_for_type(cap, eph, type, 3);

    case TK_TYPEPARAMREF:
      return viewpoint_for_type(cap, eph, type, 1);

    case TK_ARROW:
    {
      // Adapt the lower bounds.
      ast_t* lower = viewpoint_lower(type);
      ast_t* r_type = viewpoint_cap(cap, eph, lower);

      if(r_type != lower)
        ast_free_unattached(lower);

      return r_type;
    }

    default: {}
  }

  assert(0);
  return NULL;
}
Beispiel #29
0
static bool insert_apply(pass_opt_t* opt, ast_t** astp)
{
  // Sugar .apply()
  ast_t* ast = *astp;
  AST_GET_CHILDREN(ast, positional, namedargs, lhs);

  ast_t* dot = ast_from(ast, TK_DOT);
  ast_add(dot, ast_from_string(ast, "apply"));
  ast_swap(lhs, dot);
  ast_add(dot, lhs);

  if(!expr_dot(opt, &dot))
    return false;

  return expr_call(opt, astp);
}
Beispiel #30
0
bool expr_continue(typecheck_t* t, ast_t* ast)
{
    if(t->frame->loop_body == NULL)
    {
        ast_error(ast, "must be in a loop");
        return false;
    }

    if(!ast_all_consumes_in_scope(t->frame->loop_body, ast))
        return false;

    // continue is always the last expression in a sequence
    assert(ast_sibling(ast) == NULL);

    ast_settype(ast, ast_from(ast, TK_CONTINUE));
    return true;
}