Exemplo n.º 1
0
Arquivo: control.c Projeto: ozra/ponyc
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
Arquivo: control.c Projeto: ozra/ponyc
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;
}
Exemplo n.º 4
0
bool expr_break(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->loop_body == NULL)
  {
    ast_error(opt->check.errors, ast, "must be in a loop");
    return false;
  }

  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

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

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

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

  if(ast_id(body) != TK_NONE)
  {
    if(is_control_type(ast_type(body)))
    {
      ast_error(opt->check.errors, body,
        "break value cannot be a control statement");
      return false;
    }

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

    // If there is no body the break will jump to the else branch, whose type
    // has already been added to the loop type.
    loop_type = control_type_add_branch(opt, loop_type, body);
    ast_settype(t->frame->loop, loop_type);
  }

  return true;
}
Exemplo n.º 5
0
bool expr_continue(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->loop_body == NULL)
  {
    ast_error(opt->check.errors, ast, "must be in a loop");
    return false;
  }

  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    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;
}