diff options
Diffstat (limited to 'gcc/rust/backend/rust-compile-pattern.cc')
-rw-r--r-- | gcc/rust/backend/rust-compile-pattern.cc | 331 |
1 files changed, 290 insertions, 41 deletions
diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 93a5f7c..9e13480 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -26,7 +26,7 @@ namespace Rust { namespace Compile { void -CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern) +CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern) { // lookup the type TyTy::BaseType *lookup = nullptr; @@ -36,6 +36,7 @@ CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern) rust_assert (ok); // this must be an enum + // TODO: might not be rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT); TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup); rust_assert (adt->is_enum ()); @@ -50,38 +51,28 @@ CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern) ok = adt->lookup_variant_by_id (variant_id, &variant); rust_assert (ok); - HIR::Expr *discrim_expr = variant->get_discriminant (); - tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); - tree folded_discrim_expr = fold_expr (discrim_expr_node); - tree case_low = folded_discrim_expr; + // find discriminant field of scrutinee + tree scrutinee_record_expr + = Backend::struct_field_expression (match_scrutinee_expr, 0, + pattern.get_locus ()); + tree scrutinee_expr_qualifier_expr + = Backend::struct_field_expression (scrutinee_record_expr, 0, + pattern.get_locus ()); - case_label_expr - = build_case_label (case_low, NULL_TREE, associated_case_label); -} - -void -CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern) -{ - CompilePatternCaseLabelExpr::visit (pattern.get_path ()); -} + // must be enum + match_scrutinee_expr = scrutinee_expr_qualifier_expr; -void -CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern) -{ - CompilePatternCaseLabelExpr::visit (pattern.get_path ()); -} + HIR::Expr *discrim_expr = variant->get_discriminant (); + tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); -void -CompilePatternCaseLabelExpr::visit (HIR::WildcardPattern &pattern) -{ - // operand 0 being NULL_TREE signifies this is the default case label see: - // tree.def for documentation for CASE_LABEL_EXPR - case_label_expr - = build_case_label (NULL_TREE, NULL_TREE, associated_case_label); + check_expr + = Backend::comparison_expression (ComparisonOperator::EQUAL, + match_scrutinee_expr, discrim_expr_node, + pattern.get_locus ()); } void -CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern) +CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern) { // Compile the literal HIR::LiteralExpr *litexpr @@ -101,18 +92,9 @@ CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern) tree lit = CompileExpr::Compile (litexpr, ctx); - case_label_expr = build_case_label (lit, NULL_TREE, associated_case_label); -} - -void -CompilePatternCaseLabelExpr::visit (HIR::AltPattern &pattern) -{ - const auto &alts = pattern.get_alts (); - for (auto &alt_pattern : alts) - { - CompilePatternCaseLabelExpr::Compile (alt_pattern.get (), - associated_case_label, ctx); - } + check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL, + match_scrutinee_expr, lit, + pattern.get_locus ()); } static tree @@ -161,7 +143,7 @@ compile_range_pattern_bound (HIR::RangePatternBound *bound, } void -CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern) +CompilePatternCheckExpr::visit (HIR::RangePattern &pattern) { tree upper = compile_range_pattern_bound (pattern.get_upper_bound ().get (), pattern.get_mappings (), @@ -170,7 +152,274 @@ CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern) pattern.get_mappings (), pattern.get_locus (), ctx); - case_label_expr = build_case_label (lower, upper, associated_case_label); + tree check_lower + = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL, + match_scrutinee_expr, lower, + pattern.get_locus ()); + tree check_upper + = Backend::comparison_expression (ComparisonOperator::LESS_OR_EQUAL, + match_scrutinee_expr, upper, + pattern.get_locus ()); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper, + pattern.get_locus ()); +} + +void +CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern) +{ + match_scrutinee_expr + = indirect_expression (match_scrutinee_expr, pattern.get_locus ()); + pattern.get_referenced_pattern ()->accept_vis (*this); +} + +void +CompilePatternCheckExpr::visit (HIR::AltPattern &pattern) +{ + auto &alts = pattern.get_alts (); + + check_expr = CompilePatternCheckExpr::Compile (alts.at (0).get (), + match_scrutinee_expr, ctx); + auto end = alts.end (); + for (auto i = alts.begin () + 1; i != end; i++) + { + tree next_expr + = CompilePatternCheckExpr::Compile (i->get (), match_scrutinee_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr, + (*i)->get_locus ()); + } +} + +void +CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) +{ + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + pattern.get_path ().get_mappings ().get_hirid (), &lookup); + rust_assert (ok); + + // this might be an enum + rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup); + + rust_assert (adt->number_of_variants () > 0); + TyTy::VariantDef *variant = nullptr; + if (adt->is_enum ()) + { + // lookup the variant + HirId variant_id; + ok = ctx->get_tyctx ()->lookup_variant_definition ( + pattern.get_path ().get_mappings ().get_hirid (), &variant_id); + rust_assert (ok); + + int variant_index = 0; + ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index); + rust_assert (ok); + + // find expected discriminant + // // need to access qualifier the field, if we use QUAL_UNION_TYPE this + // // would be DECL_QUALIFIER i think. For now this will just access the + // // first record field and its respective qualifier because it will + // // always be set because this is all a big special union + HIR::Expr *discrim_expr = variant->get_discriminant (); + tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); + + // find discriminant field of scrutinee + tree scrutinee_record_expr + = Backend::struct_field_expression (match_scrutinee_expr, variant_index, + pattern.get_path ().get_locus ()); + tree scrutinee_expr_qualifier_expr + = Backend::struct_field_expression (scrutinee_record_expr, 0, + pattern.get_path ().get_locus ()); + + check_expr + = Backend::comparison_expression (ComparisonOperator::EQUAL, + scrutinee_expr_qualifier_expr, + discrim_expr_node, + pattern.get_path ().get_locus ()); + + match_scrutinee_expr = scrutinee_record_expr; + } + else + { + variant = adt->get_variants ().at (0); + check_expr = boolean_true_node; + } + + auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); + for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) + { + switch (field->get_item_type ()) + { + case HIR::StructPatternField::ItemType::TUPLE_PAT: { + // TODO + rust_unreachable (); + } + break; + + case HIR::StructPatternField::ItemType::IDENT_PAT: { + HIR::StructPatternFieldIdentPat &ident + = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ()); + + size_t offs = 0; + ok = variant->lookup_field (ident.get_identifier ().as_string (), + nullptr, &offs); + rust_assert (ok); + + // we may be offsetting by + 1 here since the first field in the + // record is always the discriminator + offs += adt->is_enum (); + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, offs, + ident.get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (ident.get_pattern ().get (), + field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, ident.get_pattern ()->get_locus ()); + } + break; + + case HIR::StructPatternField::ItemType::IDENT: { + // ident pattern always matches - do nothing + } + break; + } + } +} + +void +CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) +{ + size_t tuple_field_index; + + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + pattern.get_path ().get_mappings ().get_hirid (), &lookup); + rust_assert (ok); + + // this might be an enum + rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup); + + rust_assert (adt->number_of_variants () > 0); + TyTy::VariantDef *variant = nullptr; + if (adt->is_enum ()) + { + // lookup the variant + HirId variant_id; + ok = ctx->get_tyctx ()->lookup_variant_definition ( + pattern.get_path ().get_mappings ().get_hirid (), &variant_id); + rust_assert (ok); + + int variant_index = 0; + ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index); + rust_assert (ok); + + // find expected discriminant + HIR::Expr *discrim_expr = variant->get_discriminant (); + tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); + + // find discriminant field of scrutinee + tree scrutinee_record_expr + = Backend::struct_field_expression (match_scrutinee_expr, variant_index, + pattern.get_path ().get_locus ()); + tree scrutinee_expr_qualifier_expr + = Backend::struct_field_expression (scrutinee_record_expr, 0, + pattern.get_path ().get_locus ()); + + check_expr + = Backend::comparison_expression (ComparisonOperator::EQUAL, + scrutinee_expr_qualifier_expr, + discrim_expr_node, + pattern.get_path ().get_locus ()); + + match_scrutinee_expr = scrutinee_record_expr; + // we are offsetting by + 1 here since the first field in the record + // is always the discriminator + tuple_field_index = 1; + } + else + { + variant = adt->get_variants ().at (0); + check_expr = boolean_true_node; + tuple_field_index = 0; + } + + std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items (); + switch (items->get_item_type ()) + { + case HIR::TupleStructItems::RANGE: { + // TODO + rust_unreachable (); + } + break; + + case HIR::TupleStructItems::NO_RANGE: { + HIR::TupleStructItemsNoRange &items_no_range + = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ()); + + rust_assert (items_no_range.get_patterns ().size () + == variant->num_fields ()); + + for (auto &pattern : items_no_range.get_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pattern->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (pattern.get (), field_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern->get_locus ()); + } + } + break; + } +} + +void +CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) +{ + check_expr = boolean_true_node; + + switch (pattern.get_items ()->get_item_type ()) + { + case HIR::TuplePatternItems::RANGED: { + // TODO + gcc_unreachable (); + } + break; + + case HIR::TuplePatternItems::MULTIPLE: { + auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( + *pattern.get_items ()); + size_t tuple_field_index = 0; + + for (auto &pat : items.get_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pat->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (pat.get (), field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pat->get_locus ()); + } + } + } } // setup the bindings |