Example #1
0
static ast_result_t flatten_isect(pass_opt_t* opt, ast_t* ast)
{
  // Flatten intersections without testing subtyping. This is to preserve any
  // type guarantees that an element in the intersection might make.
  // If there are more than 2 children, this has already been flattened.
  if(ast_childcount(ast) > 2)
    return AST_OK;

  AST_EXTRACT_CHILDREN(ast, left, right);

  if((opt->check.frame->constraint == NULL) &&
    (opt->check.frame->iftype_constraint == NULL) &&
    (opt->check.frame->provides == NULL) &&
    !is_compat_type(left, right))
  {
    ast_add(ast, right);
    ast_add(ast, left);

    ast_error(opt->check.errors, ast,
      "intersection types cannot include reference capabilities that are not "
      "locally compatible");
    return AST_ERROR;
  }

  flatten_typeexpr_element(ast, left, TK_ISECTTYPE);
  flatten_typeexpr_element(ast, right, TK_ISECTTYPE);

  return AST_OK;
}
Example #2
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;
}
Example #3
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;
}
Example #4
0
static ast_result_t flatten_union(pass_opt_t* opt, ast_t* ast)
{
  (void)opt;
  // Flatten unions without testing subtyping. This will be tested after the
  // traits pass, when we have full subtyping information.
  // If there are more than 2 children, this has already been flattened.
  if(ast_childcount(ast) > 2)
    return AST_OK;

  AST_EXTRACT_CHILDREN(ast, left, right);

  flatten_typeexpr_element(ast, left, TK_UNIONTYPE);
  flatten_typeexpr_element(ast, right, TK_UNIONTYPE);

  return AST_OK;
}
Example #5
0
static ast_result_t sugar_for(typecheck_t* t, ast_t** astp)
{
  AST_EXTRACT_CHILDREN(*astp, for_idseq, for_iter, for_body, for_else);

  expand_none(for_else, true);
  const char* iter_name = package_hygienic_id(t);

  BUILD(try_next, for_iter,
    NODE(TK_TRY_NO_CHECK,
      NODE(TK_SEQ, AST_SCOPE
        NODE(TK_CALL,
          NONE
          NONE
          NODE(TK_DOT, NODE(TK_REFERENCE, ID(iter_name)) ID("next"))))
      NODE(TK_SEQ, AST_SCOPE
        NODE(TK_CONTINUE, NONE))
      NONE));

  sugar_try(try_next);

  REPLACE(astp,
    NODE(TK_SEQ,
      NODE(TK_ASSIGN, AST_NODEBUG
        TREE(for_iter)
        NODE(TK_LET, NICE_ID(iter_name, "for loop iterator") NONE))
      NODE(TK_WHILE, AST_SCOPE
        NODE(TK_SEQ,
          NODE_ERROR_AT(TK_CALL, for_iter,
            NONE
            NONE
            NODE(TK_DOT, NODE(TK_REFERENCE, ID(iter_name)) ID("has_next"))))
        NODE(TK_SEQ, AST_SCOPE
          NODE_ERROR_AT(TK_ASSIGN, for_idseq, AST_NODEBUG
            TREE(try_next)
            TREE(for_idseq))
          TREE(for_body))
        TREE(for_else))));

  return AST_OK;
}