about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2015-01-27 01:22:12 +0100
committerFelix S. Klock II <pnkfelix@pnkfx.org>2015-07-22 15:33:59 +0200
commit866250c6d4ca63fb56b7d58e55f8949337663998 (patch)
treec59ea396b51429ddaf14b0accf801c6ea009a36f /src/libsyntax/ext
parent1829fa5199bae5a192c771807c532badce14be37 (diff)
prototype Placer protocol for unstable overloaded-box and placement-in.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/expand.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b540e0adeea..3a72a50b5ca 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -33,6 +33,16 @@ use visit;
 use visit::Visitor;
 use std_inject;
 
+// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+fn mk_core_path(fld: &mut MacroExpander,
+                span: Span,
+                suffix: &[&'static str]) -> ast::Path {
+    let mut idents = vec![fld.cx.ident_of_std("core")];
+    for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); }
+    fld.cx.path_global(span, idents)
+}
+
 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) {
         fld.cx.bt_push(ExpnInfo {
@@ -47,6 +57,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     }
 
     e.and_then(|ast::Expr {id, node, span}| match node {
+
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
         ast::ExprMac(mac) => {
@@ -71,6 +82,109 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             })
         }
 
+        // Desugar ExprBox: `in (PLACE) EXPR`
+        ast::ExprBox(Some(placer), value_expr) => {
+            // to:
+            //
+            // let p = PLACE;
+            // let mut place = Placer::make_place(p);
+            // let raw_place = InPlace::pointer(&mut place);
+            // let value = EXPR;
+            // unsafe {
+            //     std::ptr::write(raw_place, value);
+            //     InPlace::finalize(place)
+            // }
+
+            let value_span = value_expr.span;
+            let placer_span = placer.span;
+
+            let placer_expr = fld.fold_expr(placer);
+            let value_expr = fld.fold_expr(value_expr);
+
+            let placer_ident = token::gensym_ident("placer");
+            let agent_ident = token::gensym_ident("place");
+            let value_ident = token::gensym_ident("value");
+            let p_ptr_ident = token::gensym_ident("p_ptr");
+
+            let placer = fld.cx.expr_ident(span, placer_ident);
+            let agent = fld.cx.expr_ident(span, agent_ident);
+            let value = fld.cx.expr_ident(span, value_ident);
+            let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);
+
+            let make_place = ["ops", "Placer", "make_place"];
+            let place_pointer = ["ops", "Place", "pointer"];
+            let ptr_write = ["ptr", "write"];
+            let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+            let make_call = |fld: &mut MacroExpander, p, args| {
+                let path = mk_core_path(fld, placer_span, p);
+                let path = fld.cx.expr_path(path);
+                fld.cx.expr_call(span, path, args)
+            };
+
+            let stmt_let = |fld: &mut MacroExpander, bind, expr| {
+                fld.cx.stmt_let(placer_span, false, bind, expr)
+            };
+            let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
+                fld.cx.stmt_let(placer_span, true, bind, expr)
+            };
+
+            // let placer = <placer_expr> ;
+            let s1 = stmt_let(fld, placer_ident, placer_expr);
+
+            // let mut place = Placer::make_place(placer);
+            let s2 = {
+                let call = make_call(fld, &make_place, vec![placer]);
+                stmt_let_mut(fld, agent_ident, call)
+            };
+
+            // let p_ptr = Place::pointer(&mut place);
+            let s3 = {
+                let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
+                let call = make_call(fld, &place_pointer, args);
+                stmt_let(fld, p_ptr_ident, call)
+            };
+
+            // let value = <value_expr>;
+            let s4 = fld.cx.stmt_let(value_span, false, value_ident, value_expr);
+
+            // unsafe { ptr::write(p_ptr, value); InPlace::finalize(place) }
+            let expr = {
+                let call_ptr_write = StmtSemi(make_call(
+                    fld, &ptr_write, vec![p_ptr, value]), ast::DUMMY_NODE_ID);
+                let call_ptr_write = codemap::respan(value_span, call_ptr_write);
+
+                let call = make_call(fld, &inplace_finalize, vec![agent]);
+                Some(fld.cx.expr_block(P(ast::Block {
+                    stmts: vec![P(call_ptr_write)],
+                    expr: Some(call),
+                    id: ast::DUMMY_NODE_ID,
+                    rules: ast::UnsafeBlock(ast::CompilerGenerated),
+                    span: span,
+                })))
+            };
+
+            let block = fld.cx.block_all(span, vec![s1, s2, s3, s4], expr);
+            fld.cx.expr_block(block)
+        }
+
+        // Issue #22181:
+        // Eventually a desugaring for `box EXPR`
+        // (similar to the desugaring above for `in PLACE BLOCK`)
+        // should go here, desugaring
+        //
+        // to:
+        //
+        // let mut place = BoxPlace::make_place();
+        // let raw_place = Place::pointer(&mut place);
+        // let value = $value;
+        // unsafe {
+        //     ::std::ptr::write(raw_place, value);
+        //     Boxed::finalize(place)
+        // }
+        //
+        // But for now there are type-inference issues doing that.
+
         ast::ExprWhile(cond, body, opt_ident) => {
             let cond = fld.fold_expr(cond);
             let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);