bool is_lvalue(const exprt &expr)
{
  if(expr.id()==ID_index)
    return is_lvalue(to_index_expr(expr).op0());
  else if(expr.id()==ID_member)
    return is_lvalue(to_member_expr(expr).op0());
  else if(expr.id()==ID_dereference)
    return true;
  else if(expr.id()==ID_symbol)
    return true;
  else
    return false;
}
exprt make_va_list(const exprt &expr)
{
  // we first strip any typecast
  if(expr.id()==ID_typecast)
    return make_va_list(to_typecast_expr(expr).op());

  // if it's an address of an lvalue, we take that
  if(expr.id()==ID_address_of &&
     expr.operands().size()==1 &&
     is_lvalue(expr.op0()))
    return expr.op0();

  return expr;
}
示例#3
0
文件: main.cpp 项目: CCJY/coliru
 bool is_xvalue() const noexcept
 { return !is_lvalue(); }
示例#4
0
文件: main.cpp 项目: CCJY/coliru
 T copy_or_move() const
 {
     if(is_lvalue()) return *lvalue;
     else return std::move(*xvalue);
 }
示例#5
0
文件: operator.c 项目: jonas-l/ponyc
static bool is_lvalue(typecheck_t* t, ast_t* ast, bool need_value)
{
  switch(ast_id(ast))
  {
    case TK_DONTCARE:
      // Can only assign to it if we don't need the value.
      return !need_value;

    case TK_VAR:
    case TK_LET:
      return assign_id(t, ast_child(ast), ast_id(ast) == TK_LET, need_value);

    case TK_VARREF:
    {
      ast_t* id = ast_child(ast);
      return assign_id(t, id, false, need_value);
    }

    case TK_LETREF:
    {
      ast_error(ast, "can't assign to a let local");
      return false;
    }

    case TK_FVARREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) == TK_THIS)
        return assign_id(t, right, false, need_value);

      return true;
    }

    case TK_FLETREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) != TK_THIS)
      {
        ast_error(ast, "can't assign to a let field");
        return false;
      }

      if(t->frame->loop_body != NULL)
      {
        ast_error(ast, "can't assign to a let field in a loop");
        return false;
      }

      return assign_id(t, right, true, need_value);
    }

    case TK_EMBEDREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) != TK_THIS)
      {
        ast_error(ast, "can't assign to an embed field");
        return false;
      }

      if(t->frame->loop_body != NULL)
      {
        ast_error(ast, "can't assign to an embed field in a loop");
        return false;
      }

      return assign_id(t, right, true, need_value);
    }

    case TK_TUPLE:
    {
      // A tuple is an lvalue if every component expression is an lvalue.
      ast_t* child = ast_child(ast);

      while(child != NULL)
      {
        if(!is_lvalue(t, child, need_value))
          return false;

        child = ast_sibling(child);
      }

      return true;
    }

    case TK_SEQ:
    {
      // A sequence is an lvalue if it has a single child that is an lvalue.
      // This is used because the components of a tuple are sequences.
      ast_t* child = ast_child(ast);

      if(ast_sibling(child) != NULL)
        return false;

      return is_lvalue(t, child, need_value);
    }

    default: {}
  }

  return false;
}
示例#6
0
文件: operator.c 项目: jonas-l/ponyc
bool expr_assign(pass_opt_t* opt, ast_t* ast)
{
  // Left and right are swapped in the AST to make sure we type check the
  // right side before the left. Fetch them in the opposite order.
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, right, left);
  ast_t* l_type = ast_type(left);

  if(!is_lvalue(&opt->check, left, is_result_needed(ast)))
  {
    ast_error(ast, "left side must be something that can be assigned to");
    return false;
  }

  assert(l_type != NULL);

  if(!coerce_literals(&right, l_type, opt))
    return false;

  ast_t* r_type = ast_type(right);

  if(is_typecheck_error(r_type))
    return false;

  if(!infer_locals(left, r_type))
    return false;

  // Inferring locals may have changed the left type.
  l_type = ast_type(left);

  // Assignment is based on the alias of the right hand side.
  ast_t* a_type = alias(r_type);

  if(!is_subtype(a_type, l_type))
  {
    ast_error(ast, "right side must be a subtype of left side");
    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_error(l_type, "left side type: %s", ast_print_type(l_type));
    ast_free_unattached(a_type);
    return false;
  }

  if((ast_id(left) == TK_TUPLE) && (ast_id(a_type) != TK_TUPLETYPE))
  {
    switch(ast_id(a_type))
    {
      case TK_UNIONTYPE:
        ast_error(ast,
          "can't destructure a union using assignment, use pattern matching "
          "instead");
        break;

      case TK_ISECTTYPE:
        ast_error(ast,
          "can't destructure an intersection using assignment, use pattern "
          "matching instead");
        break;

      default:
        assert(0);
        break;
    }

    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  bool ok_safe = safe_to_write(left, a_type);

  if(!ok_safe)
  {
    if(ast_id(left) == TK_FVARREF && ast_child(left) != NULL &&
      ast_id(ast_child(left)) == TK_THIS)
    {
      // We are writing to a field in this
      ast_t* fn = ast_nearest(left, TK_FUN);

      if(fn != NULL)
      {
        ast_t* iso = ast_child(fn);
        assert(iso != NULL);
        token_id iso_id = ast_id(iso);

        if(iso_id == TK_BOX || iso_id == TK_VAL || iso_id == TK_TAG)
        {
          ast_error(ast, "cannot write to a field in a %s function",
            lexer_print(iso_id));
          ast_free_unattached(a_type);
          return false;
        }
      }
    }

    ast_error(ast, "not safe to write right side to left side");
    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  ast_free_unattached(a_type);

  // If it's an embedded field, check for a constructor result.
  if(ast_id(left) == TK_EMBEDREF)
  {
    if((ast_id(right) != TK_CALL) ||
      (ast_id(ast_childidx(right, 2)) != TK_NEWREF))
    {
      ast_error(ast, "an embedded field must be assigned using a constructor");
      return false;
    }
  }

  ast_settype(ast, consume_type(l_type, TK_NONE));
  ast_inheritflags(ast);
  return true;
}
示例#7
0
文件: operator.c 项目: Sendence/ponyc
bool expr_assign(pass_opt_t* opt, ast_t* ast)
{
  // Left and right are swapped in the AST to make sure we type check the
  // right side before the left. Fetch them in the opposite order.
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, right, left);
  ast_t* l_type = ast_type(left);

  if(l_type == NULL || !is_lvalue(opt, left, is_result_needed(ast)))
  {
    ast_error(opt->check.errors, ast,
      "left side must be something that can be assigned to");
    return false;
  }

  if(!coerce_literals(&right, l_type, opt))
    return false;

  ast_t* r_type = ast_type(right);

  if(is_typecheck_error(r_type))
    return false;

  if(is_control_type(r_type))
  {
    ast_error(opt->check.errors, ast,
      "the right hand side does not return a value");
    return false;
  }

  if(!infer_locals(opt, left, r_type))
    return false;

  // Inferring locals may have changed the left type.
  l_type = ast_type(left);

  // Assignment is based on the alias of the right hand side.
  ast_t* a_type = alias(r_type);

  errorframe_t info = NULL;
  if(!is_subtype(a_type, l_type, &info, opt))
  {
    errorframe_t frame = NULL;
    ast_error_frame(&frame, ast, "right side must be a subtype of left side");
    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
    ast_free_unattached(a_type);
    return false;
  }

  if((ast_id(left) == TK_TUPLE) && (ast_id(a_type) != TK_TUPLETYPE))
  {
    switch(ast_id(a_type))
    {
      case TK_UNIONTYPE:
        ast_error(opt->check.errors, ast,
          "can't destructure a union using assignment, use pattern matching "
          "instead");
        break;

      case TK_ISECTTYPE:
        ast_error(opt->check.errors, ast,
          "can't destructure an intersection using assignment, use pattern "
          "matching instead");
        break;

      default:
        assert(0);
        break;
    }

    ast_free_unattached(a_type);
    return false;
  }

  bool ok_safe = safe_to_write(left, a_type);

  if(!ok_safe)
  {
    if(ast_id(left) == TK_FVARREF && ast_child(left) != NULL &&
      ast_id(ast_child(left)) == TK_THIS)
    {
      // We are writing to a field in this
      ast_t* fn = ast_nearest(left, TK_FUN);

      if(fn != NULL)
      {
        ast_t* iso = ast_child(fn);
        assert(iso != NULL);
        token_id iso_id = ast_id(iso);

        if(iso_id == TK_BOX || iso_id == TK_VAL || iso_id == TK_TAG)
        {
          ast_error(opt->check.errors, ast,
            "cannot write to a field in a %s function. If you are trying to "
            "change state in a function use fun ref",
            lexer_print(iso_id));
          ast_free_unattached(a_type);
          return false;
        }
      }
    }

    ast_error(opt->check.errors, ast,
      "not safe to write right side to left side");
    ast_error_continue(opt->check.errors, a_type, "right side type: %s",
      ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  ast_free_unattached(a_type);

  if(!check_embed_construction(opt, left, right))
    return false;

  ast_settype(ast, consume_type(l_type, TK_NONE));
  return true;
}
示例#8
0
文件: q.c 项目: TheProjecter/qvm
static void emit_expr(struct q *q, const struct node *node)
{
    switch (node->tok) {

    case '.':
        if (node->left->tok == TOK_IDENT)
            emit_byte(q, OP_PUSHNS);
        emit_expr(q, node->left);
        emit_expr(q, node->right);
        emit_byte(q, OP_GET);
        break;

    case '%':
    case '*':
    case '/':
    case '+':
    case '-':
        emit_expr(q, node->left);
        emit_expr(q, node->right);
        emit_byte(q, OP_MATH);
        emit_byte(q, node->tok);
        break;

    case '=':
        emit_expr(q, node->right);
        emit_expr(q, node->left);
        if (node->left->tok != TOK_IDENT &&
                node->left->tok != '.' && node->left->tok != '=')
            die(q, "%s: %d: %s", serr,
                node->line_no, "invalid assignment");
        emit_byte(q, OP_SET);
        break;

    case ',':
        emit_expr(q, node->left);
        emit_expr(q, node->right);
        die(q, "%s: %d: %s", serr, node->line_no, "use ';', not ','");
        break;

    case '(':
        emit_function_call(q, node);
        break;

    case TOK_NIL:
        emit_byte(q, OP_PUSH);
        emit_byte(q, TYPE_NIL);
        break;

    case TOK_IDENT:
        /*
         * Identifier could be either rvalue or lvalue:
         * "foo.bar = baz = x.y;"
         * Lvalues: bar, baz
         * Rvalues: foo, x, y
         * Lvalue is a key, for namespace insert.
         * Rvalue is always a key for namespace lookup.
         */
        if (node->parent == NULL || node->parent->tok != '.')
            emit_byte(q, OP_PUSHNS);
        emit_ident(q, node);
        if (!is_lvalue(node) && !(node->parent != NULL &&
                                  node->parent->tok == '.' && is_lvalue(node->parent)))
            emit_byte(q, OP_GET);
        break;

    case TOK_STR:
        emit_string_constant(q, node);
        break;

    case TOK_NUM:
        emit_num(q, strtod(node->vec.ptr, NULL));
        break;

    case '[':
        emit_byte(q, OP_NEWMAP);
        assert(node->right != NULL);
        if (node->right->tok != TOK_NIL) {
            emit_hash_definition(q, node->right, 0);
            emit_byte(q, OP_POP);
        }
        break;

    default:
        die(q, "%s: %d: %s [%d]", serr, node->line_no,
            "internal parser error", node->tok);
        break;
    }
}