rustdoc: Convert astsrv to pipes

This commit is contained in:
Brian Anderson 2013-01-31 20:24:03 -08:00
parent e343abd0ed
commit 63c16e9e79
20 changed files with 122 additions and 107 deletions

View File

@ -22,9 +22,10 @@ use core::prelude::*;
use parse;
use util;
use core::pipes::stream;
use core::pipes::{stream, Chan, SharedChan, Port};
use core::oldcomm;
use core::vec;
use core::ops::Drop;
use rustc::back::link;
use rustc::driver::driver;
use rustc::driver::session::Session;
@ -55,11 +56,15 @@ enum Msg {
}
pub struct Srv {
ch: oldcomm::Chan<Msg>
ch: SharedChan<Msg>
}
impl Srv: Clone {
fn clone(&self) -> Srv { copy *self }
fn clone(&self) -> Srv {
Srv {
ch: self.ch.clone()
}
}
}
pub fn from_str<T>(source: ~str, owner: SrvOwner<T>) -> T {
@ -72,18 +77,22 @@ pub fn from_file<T>(file: ~str, owner: SrvOwner<T>) -> T {
fn run<T>(owner: SrvOwner<T>, source: ~str, parse: Parser) -> T {
let (po, ch) = stream();
do task::spawn {
act(&po, copy source, copy parse);
}
let srv_ = Srv {
ch: do util::spawn_listener |copy source, move parse, po| {
act(po, copy source, copy parse);
}
ch: SharedChan(ch)
};
let res = owner(srv_);
oldcomm::send(srv_.ch, Exit);
let res = owner(srv_.clone());
srv_.ch.send(Exit);
move res
}
fn act(po: oldcomm::Port<Msg>, source: ~str, parse: Parser) {
fn act(po: &Port<Msg>, source: ~str, parse: Parser) {
let sess = build_session();
let ctxt = build_ctxt(
@ -93,7 +102,7 @@ fn act(po: oldcomm::Port<Msg>, source: ~str, parse: Parser) {
let mut keep_going = true;
while keep_going {
match oldcomm::recv(po) {
match po.recv() {
HandleRequest(f) => {
f(ctxt);
}
@ -112,7 +121,7 @@ pub fn exec<T:Owned>(
let msg = HandleRequest(fn~(move f, ctxt: Ctxt) {
ch.send(f(ctxt))
});
oldcomm::send(srv.ch, move msg);
srv.ch.send(move msg);
po.recv()
}

View File

@ -46,6 +46,7 @@ pub fn run(
doc: doc::Doc
) -> doc::Doc {
let fold = Fold {
ctxt: srv.clone(),
fold_crate: fold_crate,
fold_item: fold_item,
fold_enum: fold_enum,
@ -61,7 +62,7 @@ fn fold_crate(
doc: doc::CrateDoc
) -> doc::CrateDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let doc = fold::default_seq_fold_crate(fold, doc);
let attrs = do astsrv::exec(srv) |ctxt| {
@ -92,7 +93,7 @@ fn fold_item(
doc: doc::ItemDoc
) -> doc::ItemDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let doc = fold::default_seq_fold_item(fold, doc);
let desc = if doc.id == ast::crate_node_id {
@ -159,16 +160,16 @@ fn fold_enum(
doc: doc::EnumDoc
) -> doc::EnumDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let doc_id = doc.id();
let doc = fold::default_seq_fold_enum(fold, doc);
doc::EnumDoc {
variants: do par::map(doc.variants) |variant| {
variants: do vec::map(doc.variants) |variant| {
let variant = copy *variant;
let desc = {
let variant = copy variant;
do astsrv::exec(srv) |ctxt| {
do astsrv::exec(srv.clone()) |ctxt| {
match ctxt.ast_map.get(doc_id) {
ast_map::node_item(@ast::item {
node: ast::item_enum(ref enum_definition, _), _
@ -216,7 +217,7 @@ fn fold_trait(
fold: &fold::Fold<astsrv::Srv>,
doc: doc::TraitDoc
) -> doc::TraitDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let doc = fold::default_seq_fold_trait(fold, doc);
doc::TraitDoc {
@ -293,7 +294,7 @@ fn fold_impl(
fold: &fold::Fold<astsrv::Srv>,
doc: doc::ImplDoc
) -> doc::ImplDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let doc = fold::default_seq_fold_impl(fold, doc);
doc::ImplDoc {
@ -328,8 +329,8 @@ mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
run(srv.clone(), doc)
}
}
}

View File

@ -111,9 +111,9 @@ pub mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
run(srv.clone(), doc)
}
}
}

View File

@ -193,11 +193,10 @@ pub fn default_any_fold_mod<T:Owned Clone>(
fold: &Fold<T>,
doc: doc::ModDoc
) -> doc::ModDoc {
let fold_copy = fold.clone();
doc::ModDoc {
item: (fold.fold_item)(fold, copy doc.item),
items: par::map(doc.items, |ItemTag, move fold_copy| {
fold_ItemTag(&fold_copy, copy *ItemTag)
items: vec::map(doc.items, |ItemTag| {
fold_ItemTag(fold, copy *ItemTag)
}),
.. doc
}
@ -220,11 +219,10 @@ pub fn default_par_fold_mod<T:Owned Clone>(
fold: &Fold<T>,
doc: doc::ModDoc
) -> doc::ModDoc {
let fold_copy = fold.clone();
doc::ModDoc {
item: (fold.fold_item)(fold, copy doc.item),
items: par::map(doc.items, |ItemTag, move fold_copy| {
fold_ItemTag(&fold_copy, copy *ItemTag)
items: vec::map(doc.items, |ItemTag| {
fold_ItemTag(fold, copy *ItemTag)
}),
.. doc
}
@ -234,11 +232,10 @@ pub fn default_any_fold_nmod<T:Owned Clone>(
fold: &Fold<T>,
doc: doc::NmodDoc
) -> doc::NmodDoc {
let fold_copy = fold.clone();
doc::NmodDoc {
item: (fold.fold_item)(fold, copy doc.item),
fns: par::map(doc.fns, |FnDoc, move fold_copy| {
(fold_copy.fold_fn)(&fold_copy, copy *FnDoc)
fns: vec::map(doc.fns, |FnDoc| {
(fold.fold_fn)(fold, copy *FnDoc)
}),
.. doc
}
@ -261,11 +258,10 @@ pub fn default_par_fold_nmod<T:Owned Clone>(
fold: &Fold<T>,
doc: doc::NmodDoc
) -> doc::NmodDoc {
let fold_copy = fold.clone();
doc::NmodDoc {
item: (fold.fold_item)(fold, copy doc.item),
fns: par::map(doc.fns, |FnDoc, move fold_copy| {
(fold_copy.fold_fn)(&fold_copy, copy *FnDoc)
fns: vec::map(doc.fns, |FnDoc| {
(fold.fold_fn)(fold, copy *FnDoc)
}),
.. doc
}

View File

@ -274,11 +274,11 @@ mod test {
output_style: output_style,
.. config::default_config(&Path("whatever"))
};
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv, doc);
let doc = (path_pass::mk_pass().f)(srv, doc);
run(srv, doc, config)
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
run(srv.clone(), doc, config)
}
}
}

View File

@ -867,25 +867,25 @@ mod test {
.. config::default_config(&Path("whatever"))
};
let doc = extract::from_srv(srv, ~"");
let doc = extract::from_srv(srv.clone(), ~"");
debug!("doc (extract): %?", doc);
let doc = (tystr_pass::mk_pass().f)(srv, doc);
let doc = (tystr_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (tystr): %?", doc);
let doc = (path_pass::mk_pass().f)(srv, doc);
let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (path): %?", doc);
let doc = (attr_pass::mk_pass().f)(srv, doc);
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (attr): %?", doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv, doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (desc_to_brief): %?", doc);
let doc = (unindent_pass::mk_pass().f)(srv, doc);
let doc = (unindent_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (unindent): %?", doc);
let doc = (sectionalize_pass::mk_pass().f)(srv, doc);
let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (trim): %?", doc);
let doc = (trim_pass::mk_pass().f)(srv, doc);
let doc = (trim_pass::mk_pass().f)(srv.clone(), doc);
debug!("doc (sectionalize): %?", doc);
let doc = (markdown_index_pass::mk_pass(config).f)(srv, doc);
let doc = (markdown_index_pass::mk_pass(config).f)(srv.clone(), doc);
debug!("doc (index): %?", doc);
(srv, doc)
(srv.clone(), doc)
}
}

View File

@ -279,8 +279,8 @@ mod test {
pub fn mk_doc(name: ~str, source: ~str) -> doc::Doc {
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, copy name);
let doc = (path_pass::mk_pass().f)(srv, doc);
let doc = extract::from_srv(srv.clone(), copy name);
let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
doc
}
}

View File

@ -196,8 +196,8 @@ mod test {
source: ~str
) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
run(srv, doc, output_style)
let doc = extract::from_srv(srv.clone(), ~"");
run(srv.clone(), doc, output_style)
}
}

View File

@ -33,7 +33,7 @@ pub fn run_passes(
log(debug, fmt!("pass #%d", passno));
passno += 1;
do time(copy pass.name) {
(pass.f)(srv, copy doc)
(pass.f)(srv.clone(), copy doc)
}
}
}
@ -90,7 +90,7 @@ fn test_run_passes() {
f: pass2
}
];
let doc = extract::from_srv(srv, ~"one");
let doc = extract::from_srv(srv.clone(), ~"one");
let doc = run_passes(srv, doc, passes);
assert doc.cratemod().name() == ~"onetwothree";
}

View File

@ -35,7 +35,12 @@ struct Ctxt {
}
impl Ctxt: Clone {
fn clone(&self) -> Ctxt { copy *self }
fn clone(&self) -> Ctxt {
Ctxt {
srv: self.srv.clone(),
path: copy self.path
}
}
}
#[allow(non_implicitly_copyable_typarams)]
@ -45,6 +50,7 @@ fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
mut path: ~[]
};
let fold = Fold {
ctxt: ctxt.clone(),
fold_item: fold_item,
fold_mod: fold_mod,
fold_nmod: fold_nmod,
@ -89,8 +95,8 @@ fn fold_nmod(fold: &fold::Fold<Ctxt>, doc: doc::NmodDoc) -> doc::NmodDoc {
fn should_record_mod_paths() {
let source = ~"mod a { mod b { mod c { } } mod d { mod e { } } }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = run(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = run(srv.clone(), doc);
assert doc.cratemod().mods()[0].mods()[0].mods()[0].path()
== ~[~"a", ~"b"];
assert doc.cratemod().mods()[0].mods()[1].mods()[0].path()
@ -102,8 +108,8 @@ fn should_record_mod_paths() {
fn should_record_fn_paths() {
let source = ~"mod a { fn b() { } }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = run(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = run(srv.clone(), doc);
assert doc.cratemod().mods()[0].fns()[0].path() == ~[~"a"];
}
}
@ -112,8 +118,8 @@ fn should_record_fn_paths() {
fn should_record_foreign_mod_paths() {
let source = ~"mod a { extern mod b { } }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = run(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = run(srv.clone(), doc);
assert doc.cratemod().mods()[0].nmods()[0].path() == ~[~"a"];
}
}
@ -122,8 +128,8 @@ fn should_record_foreign_mod_paths() {
fn should_record_foreign_fn_paths() {
let source = ~"extern mod a { fn b(); }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = run(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = run(srv.clone(), doc);
assert doc.cratemod().nmods()[0].fns[0].path() == ~[~"a"];
}
}

View File

@ -30,6 +30,7 @@ pub fn mk_pass() -> Pass {
pub fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
let fold = Fold {
ctxt: srv.clone(),
fold_mod: fold_mod,
.. fold::default_any_fold(srv)
};
@ -44,7 +45,7 @@ fn fold_mod(
doc::ModDoc {
items: do doc.items.filtered |ItemTag| {
!is_hidden(fold.ctxt, ItemTag.item())
!is_hidden(fold.ctxt.clone(), ItemTag.item())
},
.. doc
}
@ -78,8 +79,8 @@ pub mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
run(srv.clone(), doc)
}
}
}

View File

@ -31,6 +31,7 @@ pub fn mk_pass() -> Pass {
pub fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
let fold = Fold {
ctxt: srv.clone(),
fold_mod: fold_mod,
.. fold::default_any_fold(srv)
};
@ -45,7 +46,7 @@ fn fold_mod(
doc::ModDoc {
items: doc.items.filtered(|ItemTag| {
is_visible(fold.ctxt, ItemTag.item())
is_visible(fold.ctxt.clone(), ItemTag.item())
}),
.. doc
}
@ -82,8 +83,8 @@ pub mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
run(srv.clone(), doc)
}
}
}

View File

@ -94,14 +94,14 @@ fn run(config: Config) {
// Just time how long it takes for the AST to become available
do time(~"wait_ast") {
do astsrv::exec(srv) |_ctxt| { }
do astsrv::exec(srv.clone()) |_ctxt| { }
};
// Extract the initial doc tree from the AST. This contains
// just names and node ids.
let doc = time(~"extract", || {
let default_name = copy source_file;
extract::from_srv(srv, default_name.to_str())
extract::from_srv(srv.clone(), default_name.to_str())
});
// Refine and publish the document

View File

@ -261,9 +261,9 @@ pub mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
run(srv.clone(), doc)
}
}
}

View File

@ -28,8 +28,8 @@ pub fn mk_pass() -> Pass {
fn test() {
let source = ~"mod z { } fn y() { }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (mk_pass().f)(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass().f)(srv.clone(), doc);
assert doc.cratemod().items[0].name() == ~"y";
assert doc.cratemod().items[1].name() == ~"z";
}

View File

@ -55,8 +55,8 @@ fn test() {
type itype = int; \
struct istruct { f: () }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (mk_pass().f)(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass().f)(srv.clone(), doc);
assert doc.cratemod().items[0].name() == ~"iconst";
assert doc.cratemod().items[1].name() == ~"itype";
assert doc.cratemod().items[2].name() == ~"ienum";

View File

@ -69,8 +69,8 @@ fn test() {
let source = ~"mod z { mod y { } fn x() { } } mod w { }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (mk_pass(~"", name_lteq).f)(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass(~"", name_lteq).f)(srv.clone(), doc);
assert doc.cratemod().mods()[0].name() == ~"w";
assert doc.cratemod().mods()[1].items[0].name() == ~"x";
assert doc.cratemod().mods()[1].items[1].name() == ~"y";
@ -86,11 +86,11 @@ fn should_be_stable() {
let source = ~"mod a { mod b { } } mod c { mod d { } }";
do astsrv::from_str(source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (mk_pass(~"", always_eq).f)(srv, doc);
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
assert doc.cratemod().mods()[0].items[0].name() == ~"b";
assert doc.cratemod().mods()[1].items[0].name() == ~"d";
let doc = (mk_pass(~"", always_eq).f)(srv, doc);
let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
assert doc.cratemod().mods()[0].items[0].name() == ~"b";
assert doc.cratemod().mods()[1].items[0].name() == ~"d";
}

View File

@ -306,11 +306,11 @@ mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv, doc);
let doc = (sectionalize_pass::mk_pass().f)(srv, doc);
(mk_pass(~"", |s| str::trim(s) ).f)(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc);
(mk_pass(~"", |s| str::trim(s) ).f)(srv.clone(), doc)
}
}
}

View File

@ -45,9 +45,9 @@ mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
(mk_pass().f)(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
(mk_pass().f)(srv.clone(), doc)
}
}
}

View File

@ -40,6 +40,7 @@ pub fn run(
doc: doc::Doc
) -> doc::Doc {
let fold = Fold {
ctxt: srv.clone(),
fold_fn: fold_fn,
fold_const: fold_const,
fold_enum: fold_enum,
@ -57,7 +58,7 @@ fn fold_fn(
doc: doc::FnDoc
) -> doc::FnDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
doc::SimpleItemDoc {
sig: get_fn_sig(srv, doc.id()),
@ -100,7 +101,7 @@ fn fold_const(
fold: &fold::Fold<astsrv::Srv>,
doc: doc::ConstDoc
) -> doc::ConstDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
doc::SimpleItemDoc {
sig: Some({
@ -130,13 +131,13 @@ fn fold_enum(
doc: doc::EnumDoc
) -> doc::EnumDoc {
let doc_id = doc.id();
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
doc::EnumDoc {
variants: do par::map(doc.variants) |variant| {
variants: do vec::map(doc.variants) |variant| {
let sig = {
let variant = copy *variant;
do astsrv::exec(srv) |copy variant, ctxt| {
do astsrv::exec(srv.clone()) |copy variant, ctxt| {
match ctxt.ast_map.get(doc_id) {
ast_map::node_item(@ast::item {
node: ast::item_enum(ref enum_definition, _), _
@ -174,7 +175,7 @@ fn fold_trait(
doc: doc::TraitDoc
) -> doc::TraitDoc {
doc::TraitDoc {
methods: merge_methods(fold.ctxt, doc.id(), copy doc.methods),
methods: merge_methods(fold.ctxt.clone(), doc.id(), copy doc.methods),
.. doc
}
}
@ -184,9 +185,9 @@ fn merge_methods(
item_id: doc::AstId,
docs: ~[doc::MethodDoc]
) -> ~[doc::MethodDoc] {
do par::map(docs) |doc| {
do vec::map(docs) |doc| {
doc::MethodDoc {
sig: get_method_sig(srv, item_id, copy doc.name),
sig: get_method_sig(srv.clone(), item_id, copy doc.name),
.. copy *doc
}
}
@ -265,7 +266,7 @@ fn fold_impl(
doc: doc::ImplDoc
) -> doc::ImplDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
let (trait_types, self_ty) = {
let doc = copy doc;
@ -289,7 +290,7 @@ fn fold_impl(
doc::ImplDoc {
trait_types: trait_types,
self_ty: self_ty,
methods: merge_methods(fold.ctxt, doc.id(), copy doc.methods),
methods: merge_methods(fold.ctxt.clone(), doc.id(), copy doc.methods),
.. doc
}
}
@ -324,7 +325,7 @@ fn fold_type(
doc: doc::TyDoc
) -> doc::TyDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
doc::SimpleItemDoc {
sig: {
@ -362,7 +363,7 @@ fn fold_struct(
fold: &fold::Fold<astsrv::Srv>,
doc: doc::StructDoc
) -> doc::StructDoc {
let srv = fold.ctxt;
let srv = fold.ctxt.clone();
doc::StructDoc {
sig: {
@ -434,8 +435,8 @@ pub mod test {
pub fn mk_doc(source: ~str) -> doc::Doc {
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
run(srv, doc)
let doc = extract::from_srv(srv.clone(), ~"");
run(srv.clone(), doc)
}
}
}