about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-02-17 12:20:55 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-02-17 12:20:55 -0800
commit79d3ceaac0b4a6ca83f0ff7b8b533649fc5165a1 (patch)
treecb102047edb55b39921373dae7bbce2c2e8ea72e
parente867d8ea993945803d96396bcba9c07d61d7c95d (diff)
downloadrust-79d3ceaac0b4a6ca83f0ff7b8b533649fc5165a1.tar.gz
rust-79d3ceaac0b4a6ca83f0ff7b8b533649fc5165a1.zip
Steps toward implementing iterators.
-rw-r--r--src/comp/middle/trans.rs123
1 files changed, 116 insertions, 7 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index e3e68d4b3e9..62b5a41510c 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -88,6 +88,7 @@ state type fn_ctxt = rec(ValueRef llfn,
                          ValueRef llenv,
                          ValueRef llretptr,
                          mutable option.t[ValueRef] llself,
+                         mutable option.t[ValueRef] lliterbody,
                          hashmap[ast.def_id, ValueRef] llargs,
                          hashmap[ast.def_id, ValueRef] llobjfields,
                          hashmap[ast.def_id, ValueRef] lllocals,
@@ -399,6 +400,8 @@ fn type_of_explicit_args(@crate_ctxt cx,
 //  - trans_args
 
 fn type_of_fn_full(@crate_ctxt cx,
+                   // FIXME: change bool flag to tag
+                   bool is_iter,
                    option.t[TypeRef] obj_self,
                    vec[ty.arg] inputs,
                    @ty.t output) -> TypeRef {
@@ -436,14 +439,26 @@ fn type_of_fn_full(@crate_ctxt cx,
         }
     }
 
+    if (is_iter) {
+        // If it's an iter, the 'output' type of the iter is actually the
+        // *input* type of the function we're given as our iter-block
+        // argument.
+        atys += T_fn_pair(type_of_fn_full(cx, false, none[TypeRef],
+                                          vec(rec(mode=ast.val, ty=output)),
+                                          plain_ty(ty.ty_nil)));
+    }
+
     // ... then explicit args.
     atys += type_of_explicit_args(cx, inputs);
 
     ret T_fn(atys, llvm.LLVMVoidType());
 }
 
-fn type_of_fn(@crate_ctxt cx, vec[ty.arg] inputs, @ty.t output) -> TypeRef {
-    ret type_of_fn_full(cx, none[TypeRef], inputs, output);
+fn type_of_fn(@crate_ctxt cx,
+              // FIXME: change bool flag to tag
+              bool is_iter,
+              vec[ty.arg] inputs, @ty.t output) -> TypeRef {
+    ret type_of_fn_full(cx, is_iter, none[TypeRef], inputs, output);
 }
 
 fn type_of_native_fn(@crate_ctxt cx, vec[ty.arg] inputs,
@@ -499,7 +514,8 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
             ret T_struct(tys);
         }
         case (ty.ty_fn(?args, ?out)) {
-            ret T_fn_pair(type_of_fn(cx, args, out));
+            // FIXME: put iter in ty_fn.
+            ret T_fn_pair(type_of_fn(cx, false, args, out));
         }
         case (ty.ty_native_fn(?args, ?out)) {
             ret T_fn_pair(type_of_native_fn(cx, args, out));
@@ -512,6 +528,8 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
             for (ty.method m in meths) {
                 let TypeRef mty =
                     type_of_fn_full(cx,
+                                    // FIXME: support method iters
+                                    false,
                                     some[TypeRef](self_ty),
                                     m.inputs, m.output);
                 mtys += T_ptr(mty);
@@ -2141,7 +2159,83 @@ fn trans_for_each(@block_ctxt cx,
                   @ast.decl decl,
                   @ast.expr seq,
                   &ast.block body) -> result {
-    cx.fcx.ccx.sess.unimpl("for each loop");
+
+    /*
+     * The translation is a little .. complex here. Code like:
+     *
+     *    let ty1 p = ...;
+     *
+     *    let ty1 q = ...;
+     *
+     *    foreach (ty v in foo(a,b)) { body(p,q,v) }
+     *
+     *
+     * Turns into a something like so (C/Rust mishmash):
+     *
+     *    type env = { *ty1 p, *ty2 q, ... };
+     *
+     *    let env e = { &p, &q, ... };
+     *
+     *    fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
+     *
+     *    foo([foreach123_body, env*], a, b);
+     *
+     */
+
+    // Step 1: walk body and figure out which references it makes
+    // escape. This could be determined upstream, and probably ought
+    // to be so, eventualy. For first cut, skip this. Null env.
+
+    auto env_ty = T_struct(vec(T_ptr(T_i8())));
+
+
+    // Step 2: Declare foreach body function.
+
+    // FIXME: possibly support alias-mode here?
+    auto decl_ty = plain_ty(ty.ty_nil);
+    alt (decl.node) {
+        case (ast.decl_local(?local)) {
+            decl_ty = node_ann_type(cx.fcx.ccx, local.ann);
+        }
+    }
+
+    let str s =
+        cx.fcx.ccx.names.next("_rust_foreach")
+        + sep() + cx.fcx.ccx.path;
+
+    // The 'env' arg entering the body function is a fake env member (as in
+    // the env-part of the normal rust calling convention) that actually
+    // points to a stack allocated env in this frame. We bundle that env
+    // pointer along with the foreach-body-fn pointer into a 'normal' fn pair
+    // and pass it in as a first class fn-arg to the iterator.
+
+    auto foreach_llty = type_of_fn_full(cx.fcx.ccx, false, none[TypeRef],
+                                        vec(rec(mode=ast.val, ty=decl_ty)),
+                                        plain_ty(ty.ty_nil));
+
+    let ValueRef llforeach = decl_fastcall_fn(cx.fcx.ccx.llmod,
+                                              s, foreach_llty);
+
+    // FIXME: handle ty params properly.
+    let vec[ast.ty_param] ty_params = vec();
+
+    auto fcx = new_fn_ctxt(cx.fcx.ccx, s, llforeach);
+    auto bcx = new_top_block_ctxt(fcx);
+
+    // FIXME: populate lllocals from llenv here.
+    auto res = trans_block(bcx, body);
+    res.bcx.build.RetVoid();
+
+
+    // Step 3: Call iter passing [llforeach, llenv], plus other args.
+
+    alt (seq.node) {
+        case (ast.expr_call(?f, ?args, ?ann)) {
+            // FIXME_ finish here by transferring to trans_call,
+            // suitably refactored.
+            cx.fcx.ccx.sess.unimpl("for each loop in trans");
+        }
+    }
     fail;
 }
 
@@ -3538,6 +3632,7 @@ fn new_fn_ctxt(@crate_ctxt cx,
              llenv=llenv,
              llretptr=llretptr,
              mutable llself=none[ValueRef],
+             mutable lliterbody=none[ValueRef],
              llargs=llargs,
              llobjfields=llobjfields,
              lllocals=lllocals,
@@ -3553,6 +3648,8 @@ fn new_fn_ctxt(@crate_ctxt cx,
 //  - trans_args
 
 fn create_llargs_for_fn_args(&@fn_ctxt cx,
+                             // FIXME: change bool flag to tag
+                             bool is_iter,
                              option.t[TypeRef] ty_self,
                              @ty.t ret_ty,
                              &vec[ast.arg] args,
@@ -3577,6 +3674,12 @@ fn create_llargs_for_fn_args(&@fn_ctxt cx,
         }
     }
 
+    if (is_iter) {
+        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
+        check (llarg as int != 0);
+        cx.lliterbody = some[ValueRef](llarg);
+        arg_n += 1u;
+    }
 
     for (ast.arg arg in args) {
         auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
@@ -3713,7 +3816,8 @@ fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
     cx.item_names.insert(cx.path, llfndecl);
 
     auto fcx = new_fn_ctxt(cx, cx.path, llfndecl);
-    create_llargs_for_fn_args(fcx, ty_self, ret_ty_of_fn(ann),
+    create_llargs_for_fn_args(fcx, f.is_iter,
+                              ty_self, ret_ty_of_fn(ann),
                               f.decl.inputs, ty_params);
     auto bcx = new_top_block_ctxt(fcx);
 
@@ -3754,6 +3858,8 @@ fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
         alt (node_ann_type(cx, m.node.ann).struct) {
             case (ty.ty_fn(?inputs, ?output)) {
                 llfnty = type_of_fn_full(cx,
+                                         // FIXME: support method iters.
+                                         false,
                                          some[TypeRef](self_ty),
                                          inputs, output);
             }
@@ -3797,7 +3903,8 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
     }
 
     auto fcx = new_fn_ctxt(cx, cx.path, llctor_decl);
-    create_llargs_for_fn_args(fcx, none[TypeRef], ret_ty_of_fn(ann),
+    create_llargs_for_fn_args(fcx, false,
+                              none[TypeRef], ret_ty_of_fn(ann),
                               fn_args, ty_params);
 
     auto bcx = new_top_block_ctxt(fcx);
@@ -3925,7 +4032,8 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
     let ValueRef llfndecl = cx.item_ids.get(variant.id);
 
     auto fcx = new_fn_ctxt(cx, cx.path, llfndecl);
-    create_llargs_for_fn_args(fcx, none[TypeRef], ret_ty_of_fn(variant.ann),
+    create_llargs_for_fn_args(fcx, false,
+                              none[TypeRef], ret_ty_of_fn(variant.ann),
                               fn_args, ty_params);
 
     auto bcx = new_top_block_ctxt(fcx);
@@ -4331,6 +4439,7 @@ fn trans_exit_task_glue(@crate_ctxt cx) {
                     llenv=C_null(T_opaque_closure_ptr()),
                     llretptr=C_null(T_ptr(T_nil())),
                     mutable llself=none[ValueRef],
+                    mutable lliterbody=none[ValueRef],
                     llargs=new_def_hash[ValueRef](),
                     llobjfields=new_def_hash[ValueRef](),
                     lllocals=new_def_hash[ValueRef](),