// Copyright (C) 2020 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// .
#ifndef RUST_COMPILE_EXPR
#define RUST_COMPILE_EXPR
#include "rust-compile-base.h"
#include "rust-compile-tyty.h"
#include "rust-compile-resolve-path.h"
#include "rust-compile-block.h"
#include "rust-compile-struct-field-expr.h"
namespace Rust {
namespace Compile {
class CompileExpr : public HIRCompileBase
{
public:
static Bexpression *Compile (HIR::Expr *expr, Context *ctx)
{
CompileExpr compiler (ctx);
expr->accept_vis (compiler);
return compiler.translated;
}
void visit (HIR::TupleIndexExpr &expr)
{
HIR::Expr *tuple_expr = expr.get_tuple_expr ().get ();
TupleIndex index = expr.get_tuple_index ();
Bexpression *receiver_ref = CompileExpr::Compile (tuple_expr, ctx);
translated
= ctx->get_backend ()->struct_field_expression (receiver_ref, index,
expr.get_locus ());
}
void visit (HIR::TupleExpr &expr)
{
if (expr.is_unit ())
{
translated = ctx->get_backend ()->unit_expression ();
return;
}
TyTy::TyBase *tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&tyty))
{
rust_fatal_error (expr.get_locus (),
"did not resolve type for this TupleExpr");
return;
}
Btype *tuple_type = TyTyResolveCompile::compile (ctx, tyty);
rust_assert (tuple_type != nullptr);
// this assumes all fields are in order from type resolution
std::vector vals;
for (auto &elem : expr.get_tuple_elems ())
{
auto e = CompileExpr::Compile (elem.get (), ctx);
vals.push_back (e);
}
translated
= ctx->get_backend ()->constructor_expression (tuple_type, vals,
expr.get_locus ());
}
void visit (HIR::ReturnExpr &expr)
{
Bexpression *compiled_expr
= CompileExpr::Compile (expr.return_expr.get (), ctx);
rust_assert (compiled_expr != nullptr);
auto fncontext = ctx->peek_fn ();
std::vector retstmts;
retstmts.push_back (compiled_expr);
auto s = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts,
expr.get_locus ());
ctx->add_statement (s);
}
void visit (HIR::CallExpr &expr);
void visit (HIR::MethodCallExpr &expr);
void visit (HIR::IdentifierExpr &expr)
{
// need to look up the reference for this identifier
NodeId ref_node_id;
if (!ctx->get_resolver ()->lookup_resolved_name (
expr.get_mappings ().get_nodeid (), &ref_node_id))
{
rust_fatal_error (expr.get_locus (), "failed to look up resolved name");
return;
}
// these ref_node_ids will resolve to a pattern declaration but we are
// interested in the definition that this refers to get the parent id
Resolver::Definition def;
if (!ctx->get_resolver ()->lookup_definition (ref_node_id, &def))
{
rust_error_at (expr.get_locus (), "unknown reference");
return;
}
HirId ref;
if (!ctx->get_mappings ()->lookup_node_to_hir (
expr.get_mappings ().get_crate_num (), def.parent, &ref))
{
rust_fatal_error (expr.get_locus (), "reverse lookup failure");
return;
}
Bfunction *fn = nullptr;
Bvariable *var = nullptr;
if (ctx->lookup_const_decl (ref, &translated))
{
return;
}
else if (ctx->lookup_function_decl (ref, &fn))
{
translated
= ctx->get_backend ()->function_code_expression (fn,
expr.get_locus ());
}
else if (ctx->lookup_var_decl (ref, &var))
{
translated
= ctx->get_backend ()->var_expression (var, expr.get_locus ());
}
else
{
rust_fatal_error (expr.get_locus (),
"failed to lookup compiled reference");
}
}
void visit (HIR::LiteralExpr &expr)
{
auto literal_value = expr.get_literal ();
switch (expr.get_lit_type ())
{
case HIR::Literal::BOOL: {
bool bval = literal_value->as_string ().compare ("true") == 0;
translated = ctx->get_backend ()->boolean_constant_expression (bval);
}
return;
case HIR::Literal::INT: {
mpz_t ival;
if (mpz_init_set_str (ival, literal_value->as_string ().c_str (), 10)
!= 0)
{
rust_fatal_error (expr.get_locus (), "bad number in literal");
return;
}
TyTy::TyBase *tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (
expr.get_mappings ().get_hirid (), &tyty))
{
rust_fatal_error (expr.get_locus (),
"did not resolve type for this literal expr");
return;
}
Btype *type = TyTyResolveCompile::compile (ctx, tyty);
translated
= ctx->get_backend ()->integer_constant_expression (type, ival);
}
return;
case HIR::Literal::FLOAT: {
mpfr_t fval;
if (mpfr_init_set_str (fval, literal_value->as_string ().c_str (), 10,
MPFR_RNDN)
!= 0)
{
rust_fatal_error (expr.get_locus (),
"bad float number in literal");
return;
}
TyTy::TyBase *tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (
expr.get_mappings ().get_hirid (), &tyty))
{
rust_fatal_error (expr.get_locus (),
"did not resolve type for this literal expr");
return;
}
Btype *type = TyTyResolveCompile::compile (ctx, tyty);
translated
= ctx->get_backend ()->float_constant_expression (type, fval);
}
return;
default:
rust_fatal_error (expr.get_locus (), "unknown literal");
return;
}
gcc_unreachable ();
}
void visit (HIR::AssignmentExpr &expr)
{
fncontext fn = ctx->peek_fn ();
auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
Bstatement *assignment
= ctx->get_backend ()->assignment_statement (fn.fndecl, lhs, rhs,
expr.get_locus ());
ctx->add_statement (assignment);
}
void visit (HIR::ArrayIndexExpr &expr)
{
Bexpression *array = CompileExpr::Compile (expr.get_array_expr (), ctx);
Bexpression *index = CompileExpr::Compile (expr.get_index_expr (), ctx);
translated
= ctx->get_backend ()->array_index_expression (array, index,
expr.get_locus ());
}
void visit (HIR::ArrayExpr &expr)
{
TyTy::TyBase *tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&tyty))
{
rust_fatal_error (expr.get_locus (),
"did not resolve type for this array expr");
return;
}
Btype *array_type = TyTyResolveCompile::compile (ctx, tyty);
expr.get_internal_elements ()->accept_vis (*this);
std::vector indexes;
for (size_t i = 0; i < constructor.size (); i++)
indexes.push_back (i);
translated
= ctx->get_backend ()->array_constructor_expression (array_type, indexes,
constructor,
expr.get_locus ());
}
void visit (HIR::ArrayElemsValues &elems)
{
elems.iterate ([&] (HIR::Expr *e) mutable -> bool {
Bexpression *translated_expr = CompileExpr::Compile (e, ctx);
constructor.push_back (translated_expr);
return true;
});
}
void visit (HIR::ArrayElemsCopied &elems)
{
Bexpression *translated_expr
= CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
for (size_t i = 0; i < elems.get_num_elements (); ++i)
constructor.push_back (translated_expr);
}
void visit (HIR::ArithmeticOrLogicalExpr &expr)
{
Operator op;
switch (expr.get_expr_type ())
{
case HIR::ArithmeticOrLogicalExpr::ADD:
op = OPERATOR_PLUS;
break;
case HIR::ArithmeticOrLogicalExpr::SUBTRACT:
op = OPERATOR_MINUS;
break;
case HIR::ArithmeticOrLogicalExpr::MULTIPLY:
op = OPERATOR_MULT;
break;
case HIR::ArithmeticOrLogicalExpr::DIVIDE:
op = OPERATOR_DIV;
break;
case HIR::ArithmeticOrLogicalExpr::MODULUS:
op = OPERATOR_MOD;
break;
case HIR::ArithmeticOrLogicalExpr::BITWISE_AND:
op = OPERATOR_AND;
break;
case HIR::ArithmeticOrLogicalExpr::BITWISE_OR:
op = OPERATOR_OR;
break;
case HIR::ArithmeticOrLogicalExpr::BITWISE_XOR:
op = OPERATOR_XOR;
break;
case HIR::ArithmeticOrLogicalExpr::LEFT_SHIFT:
op = OPERATOR_LSHIFT;
break;
case HIR::ArithmeticOrLogicalExpr::RIGHT_SHIFT:
op = OPERATOR_RSHIFT;
break;
default:
rust_fatal_error (expr.get_locus (), "failed to compile operator");
return;
}
auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
translated = ctx->get_backend ()->binary_expression (op, lhs, rhs,
expr.get_locus ());
}
void visit (HIR::ComparisonExpr &expr)
{
Operator op;
switch (expr.get_expr_type ())
{
case HIR::ComparisonExpr::EQUAL:
op = OPERATOR_EQEQ;
break;
case HIR::ComparisonExpr::NOT_EQUAL:
op = OPERATOR_NOTEQ;
break;
case HIR::ComparisonExpr::GREATER_THAN:
op = OPERATOR_GT;
break;
case HIR::ComparisonExpr::LESS_THAN:
op = OPERATOR_LT;
break;
case HIR::ComparisonExpr::GREATER_OR_EQUAL:
op = OPERATOR_GE;
break;
case HIR::ComparisonExpr::LESS_OR_EQUAL:
op = OPERATOR_LE;
break;
default:
rust_fatal_error (expr.get_locus (), "failed to compile operator");
return;
}
auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
translated = ctx->get_backend ()->binary_expression (op, lhs, rhs,
expr.get_locus ());
}
void visit (HIR::LazyBooleanExpr &expr)
{
Operator op;
switch (expr.get_expr_type ())
{
case HIR::LazyBooleanExpr::LOGICAL_OR:
op = OPERATOR_OROR;
break;
case HIR::LazyBooleanExpr::LOGICAL_AND:
op = OPERATOR_ANDAND;
break;
default:
rust_fatal_error (expr.get_locus (), "failed to compile operator");
return;
}
auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
translated = ctx->get_backend ()->binary_expression (op, lhs, rhs,
expr.get_locus ());
}
void visit (HIR::NegationExpr &expr)
{
Operator op (OPERATOR_INVALID);
switch (expr.get_negation_type ())
{
case HIR::NegationExpr::NegationType::NEGATE:
op = OPERATOR_MINUS;
break;
case HIR::NegationExpr::NegationType::NOT:
op = OPERATOR_NOT;
break;
}
Bexpression *negated_expr = CompileExpr::Compile (expr.get_expr (), ctx);
translated = ctx->get_backend ()->unary_expression (op, negated_expr,
expr.get_locus ());
}
void visit (HIR::IfExpr &expr)
{
auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr);
ctx->add_statement (stmt);
}
void visit (HIR::IfExprConseqElse &expr)
{
TyTy::TyBase *if_type = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&if_type))
{
rust_error_at (expr.get_locus (),
"failed to lookup type of IfExprConseqElse");
return;
}
Bvariable *tmp = NULL;
bool needs_temp = if_type->get_kind () != TyTy::TypeKind::UNIT;
if (needs_temp)
{
fncontext fnctx = ctx->peek_fn ();
Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
Btype *block_type = TyTyResolveCompile::compile (ctx, if_type);
bool is_address_taken = false;
Bstatement *ret_var_stmt = nullptr;
tmp = ctx->get_backend ()->temporary_variable (
fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
expr.get_locus (), &ret_var_stmt);
ctx->add_statement (ret_var_stmt);
}
auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
ctx->add_statement (stmt);
if (tmp != NULL)
{
translated
= ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
}
}
void visit (HIR::IfExprConseqIf &expr)
{
TyTy::TyBase *if_type = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&if_type))
{
rust_error_at (expr.get_locus (),
"failed to lookup type of IfExprConseqElse");
return;
}
Bvariable *tmp = NULL;
bool needs_temp = if_type->get_kind () != TyTy::TypeKind::UNIT;
if (needs_temp)
{
fncontext fnctx = ctx->peek_fn ();
Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
Btype *block_type = TyTyResolveCompile::compile (ctx, if_type);
bool is_address_taken = false;
Bstatement *ret_var_stmt = nullptr;
tmp = ctx->get_backend ()->temporary_variable (
fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
expr.get_locus (), &ret_var_stmt);
ctx->add_statement (ret_var_stmt);
}
auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
ctx->add_statement (stmt);
if (tmp != NULL)
{
translated
= ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
}
}
void visit (HIR::BlockExpr &expr)
{
TyTy::TyBase *block_tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&block_tyty))
{
rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
return;
}
Bvariable *tmp = NULL;
bool needs_temp = block_tyty->get_kind () != TyTy::TypeKind::UNIT;
if (needs_temp)
{
fncontext fnctx = ctx->peek_fn ();
Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty);
bool is_address_taken = false;
Bstatement *ret_var_stmt = nullptr;
tmp = ctx->get_backend ()->temporary_variable (
fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
expr.get_locus (), &ret_var_stmt);
ctx->add_statement (ret_var_stmt);
}
auto code_block = CompileBlock::compile (&expr, ctx, tmp);
auto block_stmt = ctx->get_backend ()->block_statement (code_block);
ctx->add_statement (block_stmt);
if (tmp != NULL)
{
translated
= ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
}
}
void visit (HIR::StructExprStructFields &struct_expr)
{
Btype *type
= ResolvePathType::Compile (&struct_expr.get_struct_name (), ctx);
// this assumes all fields are in order from type resolution and if a base
// struct was specified those fields are filed via accesors
std::vector vals;
struct_expr.iterate ([&] (HIR::StructExprField *field) mutable -> bool {
Bexpression *expr = CompileStructExprField::Compile (field, ctx);
vals.push_back (expr);
return true;
});
translated
= ctx->get_backend ()->constructor_expression (type, vals,
struct_expr.get_locus ());
}
void visit (HIR::GroupedExpr &expr)
{
translated = CompileExpr::Compile (expr.get_expr_in_parens ().get (), ctx);
}
void visit (HIR::FieldAccessExpr &expr)
{
// resolve the receiver back to ADT type
TyTy::TyBase *receiver = nullptr;
if (!ctx->get_tyctx ()->lookup_type (
expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver))
{
rust_error_at (expr.get_receiver_expr ()->get_locus_slow (),
"unresolved type for receiver");
return;
}
rust_assert (receiver->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = (TyTy::ADTType *) receiver;
size_t index = 0;
adt->get_field (expr.get_field_name (), &index);
Bexpression *struct_ref
= CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx);
translated
= ctx->get_backend ()->struct_field_expression (struct_ref, index,
expr.get_locus ());
}
void visit (HIR::PathInExpression &expr)
{
translated = ResolvePathRef::Compile (&expr, ctx);
}
private:
CompileExpr (Context *ctx) : HIRCompileBase (ctx), translated (nullptr) {}
Bexpression *translated;
std::vector constructor;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_EXPR