aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <[email protected]>2010-12-15 09:38:23 -0800
committerPatrick Walton <[email protected]>2010-12-15 09:38:40 -0800
commite17806e1c887f35aea4edde785378b9b29f7433e (patch)
tree7bb335696d4b62a80c2a0dfe21333cc080fb43f9 /src
parentTeach typeck.ty, typeck.collect_item_types and typeck.check_expr about obj it... (diff)
downloadrust-e17806e1c887f35aea4edde785378b9b29f7433e.tar.xz
rust-e17806e1c887f35aea4edde785378b9b29f7433e.zip
rustc: Translate pattern matching
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans.rs156
1 files changed, 155 insertions, 1 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 82a5d3fb..6f2145b6 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -15,6 +15,8 @@ import middle.typeck;
import back.x86;
import back.abi;
+import middle.typeck.pat_ty;
+
import util.common;
import util.common.istr;
import util.common.new_def_hash;
@@ -950,6 +952,7 @@ fn build_memcpy(@block_ctxt cx,
// lib.llvm.llvm.LLVMAlignOf(llty);
// but this makes it upset because it's not a constant.
+ log "building memcpy";
auto volatile = C_integral(0, T_i1());
ret res(cx, cx.build.Call(memcpy,
vec(dst_ptr, src_ptr,
@@ -1320,6 +1323,150 @@ impure fn trans_do_while(@block_ctxt cx, &ast.block body,
ret res(next_cx, body_res.val);
}
+// Pattern matching translation
+
+// Returns a pointer to the union part of the LLVM representation of a tag
+// type, cast to the appropriate type.
+fn get_pat_union_ptr(@block_ctxt cx, vec[@ast.pat] subpats, ValueRef llval)
+ -> ValueRef {
+ auto llblobptr = cx.build.GEP(llval, vec(C_int(0), C_int(1)));
+
+ // Generate the union type.
+ let vec[TypeRef] llsubpattys = vec();
+ for (@ast.pat subpat in subpats) {
+ llsubpattys += vec(type_of(cx.fcx.ccx, pat_ty(subpat)));
+ }
+
+ // Recursively check subpatterns.
+ auto llunionty = T_struct(llsubpattys);
+ ret cx.build.TruncOrBitCast(llblobptr, T_ptr(llunionty));
+}
+
+impure fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
+ @block_ctxt next_cx) -> result {
+ alt (pat.node) {
+ case (ast.pat_wild(_)) { ret res(cx, llval); }
+ case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
+ case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
+ auto lltagptr = cx.build.GEP(llval, vec(C_int(0), C_int(0)));
+ auto lltag = cx.build.Load(lltagptr);
+
+ auto vdef = option.get[ast.variant_def](vdef_opt);
+ auto variant_id = vdef._1;
+ auto tinfo = cx.fcx.ccx.tags.get(vdef._0);
+ auto variant_tag = 0;
+ auto i = 0;
+ for (tup(ast.def_id,arity) vinfo in tinfo.variants) {
+ auto this_variant_id = vinfo._0;
+ if (variant_id._0 == this_variant_id._0 &&
+ variant_id._1 == this_variant_id._1) {
+ variant_tag = i;
+ }
+ i += 1;
+ }
+
+ auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
+
+ auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lltag,
+ C_int(variant_tag));
+ cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
+
+ if (_vec.len[@ast.pat](subpats) > 0u) {
+ auto llunionptr = get_pat_union_ptr(matched_cx, subpats,
+ llval);
+ auto i = 0;
+ for (@ast.pat subpat in subpats) {
+ auto llsubvalptr = matched_cx.build.GEP(llunionptr,
+ vec(C_int(0),
+ C_int(i)));
+ auto llsubval = load_non_structural(matched_cx,
+ llsubvalptr,
+ pat_ty(subpat));
+ auto subpat_res = trans_pat_match(matched_cx, subpat,
+ llsubval, next_cx);
+ matched_cx = subpat_res.bcx;
+ }
+ }
+
+ ret res(matched_cx, llval);
+ }
+ }
+
+ fail;
+}
+
+impure fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
+ -> result {
+ alt (pat.node) {
+ case (ast.pat_wild(_)) { ret res(cx, llval); }
+ case (ast.pat_bind(?id, ?def_id, ?ann)) {
+ auto ty = node_ann_type(cx.fcx.ccx, ann);
+ auto llty = type_of(cx.fcx.ccx, ty);
+
+ auto dst = cx.build.Alloca(llty);
+ llvm.LLVMSetValueName(dst, _str.buf(id));
+ cx.fcx.lllocals.insert(def_id, dst);
+ cx.cleanups += clean(bind drop_slot(_, dst, ty));
+
+ ret copy_ty(cx, true, dst, llval, ty);
+ }
+ case (ast.pat_tag(_, ?subpats, _, _)) {
+ if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }
+
+ auto llunionptr = get_pat_union_ptr(cx, subpats, llval);
+
+ auto this_cx = cx;
+ auto i = 0;
+ for (@ast.pat subpat in subpats) {
+ auto llsubvalptr = this_cx.build.GEP(llunionptr,
+ vec(C_int(0), C_int(i)));
+ auto llsubval = load_non_structural(this_cx, llsubvalptr,
+ pat_ty(subpat));
+ auto subpat_res = trans_pat_binding(this_cx, subpat,
+ llsubval);
+ this_cx = subpat_res.bcx;
+ }
+
+ ret res(this_cx, llval);
+ }
+ }
+}
+
+impure fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
+ -> result {
+ auto expr_res = trans_expr(cx, expr);
+
+ auto last_cx = new_sub_block_ctxt(expr_res.bcx, "last");
+
+ auto this_cx = expr_res.bcx;
+ for (ast.arm arm in arms) {
+ auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
+ auto match_res = trans_pat_match(this_cx, arm.pat, expr_res.val,
+ next_cx);
+
+ auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
+ match_res.bcx.build.Br(binding_cx.llbb);
+
+ auto binding_res = trans_pat_binding(binding_cx, arm.pat,
+ expr_res.val);
+
+ auto block_res = trans_block(binding_res.bcx, arm.block);
+ if (!is_terminated(block_res.bcx)) {
+ block_res.bcx.build.Br(last_cx.llbb);
+ }
+
+ this_cx = next_cx;
+ }
+
+ // FIXME: This is executed when none of the patterns match; it should fail
+ // instead!
+ this_cx.build.Br(last_cx.llbb);
+
+ // FIXME: This is very wrong; we should phi together all the arm blocks,
+ // since this is an expression.
+ ret res(last_cx, C_nil());
+}
+
// The additional bool returned indicates whether it's mem (that is
// represented as an alloca or heap, hence needs a 'load' to be used as an
// immediate).
@@ -1339,6 +1486,10 @@ fn trans_name(@block_ctxt cx, &ast.name n, &option.t[ast.def] dopt)
ret tup(res(cx, cx.fcx.lllocals.get(did)),
true);
}
+ case (ast.def_binding(?did)) {
+ check (cx.fcx.lllocals.contains_key(did));
+ ret tup(res(cx, cx.fcx.lllocals.get(did)), true);
+ }
case (ast.def_fn(?did)) {
check (cx.fcx.ccx.item_ids.contains_key(did));
ret tup(res(cx, cx.fcx.ccx.item_ids.get(did)),
@@ -1666,6 +1817,10 @@ impure fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
ret trans_do_while(cx, body, cond);
}
+ case (ast.expr_alt(?expr, ?arms, _)) {
+ ret trans_alt(cx, expr, arms);
+ }
+
case (ast.expr_block(?blk, _)) {
auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
auto next_cx = new_sub_block_ctxt(cx, "next");
@@ -2461,7 +2616,6 @@ fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv);
b.Ret(b.Call(llrust_start, start_args));
-
}
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {