|
24 | 24 | #include "rust-hir-path-probe.h"
|
25 | 25 | #include "rust-hir-type-bounds.h"
|
26 | 26 | #include "rust-hir-dot-operator.h"
|
| 27 | +#include "rust-compile-pattern.h" |
| 28 | + |
| 29 | +#include "fold-const.h" |
27 | 30 |
|
28 | 31 | namespace Rust {
|
29 | 32 | namespace Compile {
|
@@ -154,6 +157,175 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
|
154 | 157 | known_valid, expr.get_locus ());
|
155 | 158 | }
|
156 | 159 |
|
| 160 | +void |
| 161 | +CompileExpr::visit (HIR::MatchExpr &expr) |
| 162 | +{ |
| 163 | + // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements |
| 164 | + // TODO |
| 165 | + // SWITCH_ALL_CASES_P is true if the switch includes a default label or the |
| 166 | + // case label ranges cover all possible values of the condition expression |
| 167 | + |
| 168 | + /* Switch expression. |
| 169 | +
|
| 170 | + TREE_TYPE is the original type of the condition, before any |
| 171 | + language required type conversions. It may be NULL, in which case |
| 172 | + the original type and final types are assumed to be the same. |
| 173 | +
|
| 174 | + Operand 0 is the expression used to perform the branch, |
| 175 | + Operand 1 is the body of the switch, which probably contains |
| 176 | + CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2 |
| 177 | + must not be NULL. */ |
| 178 | + // DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2) |
| 179 | + |
| 180 | + /* Used to represent a case label. |
| 181 | +
|
| 182 | + Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the label |
| 183 | + is a 'default' label. |
| 184 | + Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple |
| 185 | + (one-value) case label. If it is non-NULL_TREE, the case is a range. |
| 186 | + Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL. |
| 187 | + Operand 3 is CASE_CHAIN. This operand is only used in tree-cfg.c to |
| 188 | + speed up the lookup of case labels which use a particular edge in |
| 189 | + the control flow graph. */ |
| 190 | + // DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4) |
| 191 | + |
| 192 | + TyTy::BaseType *scrutinee_expr_tyty = nullptr; |
| 193 | + if (!ctx->get_tyctx ()->lookup_type ( |
| 194 | + expr.get_scrutinee_expr ()->get_mappings ().get_hirid (), |
| 195 | + &scrutinee_expr_tyty)) |
| 196 | + { |
| 197 | + translated = ctx->get_backend ()->error_expression (); |
| 198 | + return; |
| 199 | + } |
| 200 | + |
| 201 | + rust_assert (scrutinee_expr_tyty->get_kind () == TyTy::TypeKind::ADT); |
| 202 | + |
| 203 | + // this will need to change but for now the first pass implementation, lets |
| 204 | + // assert this is the case |
| 205 | + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty); |
| 206 | + rust_assert (adt->is_enum ()); |
| 207 | + rust_assert (adt->number_of_variants () > 0); |
| 208 | + |
| 209 | + TyTy::BaseType *expr_tyty = nullptr; |
| 210 | + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), |
| 211 | + &expr_tyty)) |
| 212 | + { |
| 213 | + translated = ctx->get_backend ()->error_expression (); |
| 214 | + return; |
| 215 | + } |
| 216 | + |
| 217 | + fncontext fnctx = ctx->peek_fn (); |
| 218 | + Bvariable *tmp = NULL; |
| 219 | + bool needs_temp = !expr_tyty->is_unit (); |
| 220 | + if (needs_temp) |
| 221 | + { |
| 222 | + tree enclosing_scope = ctx->peek_enclosing_scope (); |
| 223 | + tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty); |
| 224 | + |
| 225 | + bool is_address_taken = false; |
| 226 | + tree ret_var_stmt = nullptr; |
| 227 | + tmp = ctx->get_backend ()->temporary_variable ( |
| 228 | + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, |
| 229 | + expr.get_locus (), &ret_var_stmt); |
| 230 | + ctx->add_statement (ret_var_stmt); |
| 231 | + } |
| 232 | + |
| 233 | + // lets compile the scrutinee expression |
| 234 | + tree match_scrutinee_expr |
| 235 | + = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx); |
| 236 | + |
| 237 | + // need to access the qualifier field, if we use QUAL_UNION_TYPE this would be |
| 238 | + // DECL_QUALIFIER i think. For now this will just access the first record |
| 239 | + // field and its respective qualifier because it will always be set because |
| 240 | + // this is all a big special union |
| 241 | + tree scrutinee_first_record_expr |
| 242 | + = ctx->get_backend ()->struct_field_expression ( |
| 243 | + match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ()); |
| 244 | + tree match_scrutinee_expr_qualifier_expr |
| 245 | + = ctx->get_backend ()->struct_field_expression ( |
| 246 | + scrutinee_first_record_expr, 0, expr.get_scrutinee_expr ()->get_locus ()); |
| 247 | + |
| 248 | + // setup the end label so the cases can exit properly |
| 249 | + tree fndecl = fnctx.fndecl; |
| 250 | + Location end_label_locus = expr.get_locus (); // FIXME |
| 251 | + tree end_label |
| 252 | + = ctx->get_backend ()->label (fndecl, |
| 253 | + "" /* empty creates an artificial label */, |
| 254 | + end_label_locus); |
| 255 | + tree end_label_decl_statement |
| 256 | + = ctx->get_backend ()->label_definition_statement (end_label); |
| 257 | + |
| 258 | + // setup the switch-body-block |
| 259 | + Location start_location; // FIXME |
| 260 | + Location end_location; // FIXME |
| 261 | + tree enclosing_scope = ctx->peek_enclosing_scope (); |
| 262 | + tree switch_body_block |
| 263 | + = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_location, |
| 264 | + end_location); |
| 265 | + ctx->push_block (switch_body_block); |
| 266 | + |
| 267 | + for (auto &kase : expr.get_match_cases ()) |
| 268 | + { |
| 269 | + // for now lets just get single pattern's working |
| 270 | + HIR::MatchArm &kase_arm = kase.get_arm (); |
| 271 | + rust_assert (kase_arm.get_patterns ().size () > 0); |
| 272 | + |
| 273 | + // generate implicit label |
| 274 | + Location arm_locus = kase_arm.get_patterns ().at (0)->get_locus (); |
| 275 | + tree case_label = ctx->get_backend ()->label ( |
| 276 | + fndecl, "" /* empty creates an artificial label */, arm_locus); |
| 277 | + |
| 278 | + // not sure if we need to add this to the block or if the CASE_LABEL_EXPR |
| 279 | + // does this implicitly |
| 280 | + // |
| 281 | + // tree case_label_decl_statement |
| 282 | + // = ctx->get_backend ()->label_definition_statement (case_label); |
| 283 | + |
| 284 | + // setup the bindings for the block |
| 285 | + for (auto &kase_pattern : kase_arm.get_patterns ()) |
| 286 | + { |
| 287 | + tree switch_kase_expr |
| 288 | + = CompilePatternCaseLabelExpr::Compile (kase_pattern.get (), |
| 289 | + case_label, ctx); |
| 290 | + // ctx->add_statement (case_label_decl_statement); |
| 291 | + ctx->add_statement (switch_kase_expr); |
| 292 | + |
| 293 | + CompilePatternBindings::Compile (kase_pattern.get (), |
| 294 | + match_scrutinee_expr, ctx); |
| 295 | + } |
| 296 | + |
| 297 | + // compile the expr and setup the assignment if required when tmp != NULL |
| 298 | + tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), ctx); |
| 299 | + if (tmp != NULL) |
| 300 | + { |
| 301 | + tree result_reference |
| 302 | + = ctx->get_backend ()->var_expression (tmp, arm_locus); |
| 303 | + tree assignment = ctx->get_backend ()->assignment_statement ( |
| 304 | + fnctx.fndecl, result_reference, kase_expr_tree, arm_locus); |
| 305 | + ctx->add_statement (assignment); |
| 306 | + } |
| 307 | + |
| 308 | + // go to end label |
| 309 | + tree goto_end_label = build1_loc (arm_locus.gcc_location (), GOTO_EXPR, |
| 310 | + void_type_node, end_label); |
| 311 | + ctx->add_statement (goto_end_label); |
| 312 | + } |
| 313 | + |
| 314 | + // setup the switch expression |
| 315 | + tree match_body = ctx->pop_block (); |
| 316 | + tree match_expr_stmt |
| 317 | + = build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR, |
| 318 | + TREE_TYPE (match_scrutinee_expr_qualifier_expr), |
| 319 | + match_scrutinee_expr_qualifier_expr, match_body); |
| 320 | + ctx->add_statement (match_expr_stmt); |
| 321 | + ctx->add_statement (end_label_decl_statement); |
| 322 | + |
| 323 | + if (tmp != NULL) |
| 324 | + { |
| 325 | + translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); |
| 326 | + } |
| 327 | +} |
| 328 | + |
157 | 329 | void
|
158 | 330 | CompileExpr::visit (HIR::CallExpr &expr)
|
159 | 331 | {
|
|
0 commit comments