Example #1
0
bool expr_consume(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, term);
  ast_t* type = ast_type(term);

  if(is_typecheck_error(type))
    return false;

  const char* name = NULL;

  switch(ast_id(term))
  {
    case TK_VARREF:
    case TK_LETREF:
    case TK_PARAMREF:
    {
      ast_t* id = ast_child(term);
      name = ast_name(id);
      break;
    }

    case TK_THIS:
    {
      name = stringtab("this");
      break;
    }

    default:
      ast_error(opt->check.errors, ast,
        "consume must take 'this', a local, or a parameter");
      return false;
  }

  // Can't consume from an outer scope while in a loop condition.
  if((opt->check.frame->loop_cond != NULL) &&
    !ast_within_scope(opt->check.frame->loop_cond, ast, name))
  {
    ast_error(opt->check.errors, ast,
      "can't consume from an outer scope in a loop condition");
    return false;
  }

  ast_setstatus(ast, name, SYM_CONSUMED);

  token_id tcap = ast_id(cap);
  ast_t* c_type = consume_type(type, tcap);

  if(c_type == NULL)
  {
    ast_error(opt->check.errors, ast, "can't consume to this capability");
    ast_error_continue(opt->check.errors, term, "expression type is %s",
      ast_print_type(type));
    return false;
  }

  ast_settype(ast, c_type);
  return true;
}
Example #2
0
bool ast_all_consumes_in_scope(ast_t* outer, ast_t* inner, errorframe_t* errorf)
{
  ast_t* from = inner;
  bool ok = true;

  do
  {
    if(inner->symtab != NULL)
    {
      size_t i = HASHMAP_BEGIN;
      symbol_t* sym;

      while((sym = symtab_next(inner->symtab, &i)) != NULL)
      {
        // If it's consumed, and has a null value, it's from outside of this
        // scope. We need to know if it's outside the loop scope.
        if((sym->status == SYM_CONSUMED) && (sym->def == NULL))
        {
          if(!ast_within_scope(outer, inner, sym->name))
          {
            ast_t* def = ast_get(inner, sym->name, NULL);
            if(errorf != NULL)
            {
              ast_error_frame(errorf, from,
                "identifier '%s' is consumed when the loop exits", sym->name);
              ast_error_frame(errorf, def,
                "consumed identifier is defined here");
            }
            ok = false;
          }
        }
      }
    }

    if(inner == outer)
      break;

    inner = inner->parent;
  } while((inner != NULL) && (token_get_id(inner->t) != TK_PROGRAM));

  return ok;
}