libsyntax: remove quasiquoter from auto_serialize2

This commit is contained in:
Erick Tryzelaar 2012-09-19 07:41:39 -07:00 committed by Graydon Hoare
parent d2506a1787
commit 99d84bacc8

View File

@ -114,12 +114,46 @@ fn expand(cx: ext_ctxt,
} }
} }
priv impl ext_ctxt {
fn expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr {
self.expr(span, ast::expr_path(self.path(span, strs)))
}
fn expr_var(span: span, var: ~str) -> @ast::expr {
self.expr_path(span, ~[self.ident_of(var)])
}
fn expr_field(
span: span,
expr: @ast::expr,
ident: ast::ident
) -> @ast::expr {
self.expr(span, ast::expr_field(expr, ident, ~[]))
}
fn expr_call(
span: span,
expr: @ast::expr,
args: ~[@ast::expr]
) -> @ast::expr {
self.expr(span, ast::expr_call(expr, args, false))
}
fn lambda_expr(expr: @ast::expr) -> @ast::expr {
self.lambda(self.expr_blk(expr))
}
fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr {
self.lambda(self.blk(span, stmts))
}
}
fn mk_impl( fn mk_impl(
cx: ext_ctxt, cx: ext_ctxt,
span: span, span: span,
ident: ast::ident, ident: ast::ident,
tps: ~[ast::ty_param], tps: ~[ast::ty_param],
ser_body: @ast::stmt, ser_body: @ast::expr,
deser_body: @ast::expr deser_body: @ast::expr
) -> @ast::item { ) -> @ast::item {
// Make a path to the std::serialization2::Serializable trait. // Make a path to the std::serialization2::Serializable trait.
@ -161,7 +195,7 @@ fn mk_impl(
); );
let methods = ~[ let methods = ~[
mk_ser_method(cx, span, cx.blk(span, ~[ser_body])), mk_ser_method(cx, span, cx.expr_blk(ser_body)),
mk_deser_method(cx, span, ty, cx.expr_blk(deser_body)), mk_deser_method(cx, span, ty, cx.expr_blk(deser_body)),
]; ];
@ -302,7 +336,7 @@ fn mk_rec_impl(
let ser_body = mk_ser_fields(cx, span, fields); let ser_body = mk_ser_fields(cx, span, fields);
let deser_body = do mk_deser_fields(cx, span, fields) |fields| { let deser_body = do mk_deser_fields(cx, span, fields) |fields| {
ast::expr_rec(fields, None) cx.expr(span, ast::expr_rec(fields, None))
}; };
mk_impl(cx, span, ident, tps, ser_body, deser_body) mk_impl(cx, span, ident, tps, ser_body, deser_body)
@ -337,7 +371,7 @@ fn mk_struct_impl(
let ser_body = mk_ser_fields(cx, span, fields); let ser_body = mk_ser_fields(cx, span, fields);
let deser_body = do mk_deser_fields(cx, span, fields) |fields| { let deser_body = do mk_deser_fields(cx, span, fields) |fields| {
ast::expr_struct(cx.path(span, ~[ident]), fields, None) cx.expr(span, ast::expr_struct(cx.path(span, ~[ident]), fields, None))
}; };
mk_impl(cx, span, ident, tps, ser_body, deser_body) mk_impl(cx, span, ident, tps, ser_body, deser_body)
@ -347,80 +381,104 @@ fn mk_ser_fields(
cx: ext_ctxt, cx: ext_ctxt,
span: span, span: span,
fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }] fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }]
) -> @ast::stmt { ) -> @ast::expr {
let ext_cx = cx; // required for #ast{}
let stmts = do fields.mapi |idx, field| { let stmts = do fields.mapi |idx, field| {
let name = cx.lit_str(field.span, @cx.str_of(field.ident)); // ast for `|| self.$(name).serialize(__s)`
let idx = cx.lit_uint(field.span, idx); let expr_lambda = cx.lambda_expr(
cx.expr_call(
// XXX: The next couple stanzas are just to write span,
// `self.$(name).serialize(s)`. It'd be nice if the #ast macro could cx.expr_field(
// write this for us, but it doesn't appear to support quaziquoting a span,
// value inside a field chain. cx.expr_field(
let expr_self = cx.expr( span,
span, cx.expr_var(span, ~"self"),
ast::expr_path( field.ident
cx.path(span, ~[cx.ident_of(~"self")]) ),
cx.ident_of(~"serialize")
),
~[cx.expr_var(span, ~"__s")]
) )
); );
let expr_name = cx.expr( // ast for `__s.emit_rec_field($(name), $(idx), $(expr_lambda))`
span, cx.stmt(
ast::expr_field(expr_self, field.ident, ~[]) cx.expr_call(
); span,
cx.expr_field(
let expr_serialize = cx.expr( span,
span, cx.expr_var(span, ~"__s"),
ast::expr_field(expr_name, cx.ident_of(~"serialize"), ~[]) cx.ident_of(~"emit_rec_field")
); ),
~[
let expr_arg = cx.expr( cx.lit_str(span, @cx.str_of(field.ident)),
span, cx.lit_uint(span, idx),
ast::expr_path( expr_lambda,
cx.path(span, ~[cx.ident_of(~"__s")]) ]
) )
); )
let expr = cx.expr(
span,
ast::expr_call(expr_serialize, ~[expr_arg], false)
);
#ast[stmt]{ __s.emit_rec_field($(name), $(idx), || $(expr))) }
}; };
let fields_lambda = cx.lambda(cx.blk(span, stmts)); // ast for `__s.emit_rec(|| $(stmts))`
#ast[stmt]{ __s.emit_rec($(fields_lambda)) } cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_var(span, ~"__s"),
cx.ident_of(~"emit_rec")
),
~[cx.lambda_stmts(span, stmts)]
)
} }
fn mk_deser_fields( fn mk_deser_fields(
cx: ext_ctxt, cx: ext_ctxt,
span: span, span: span,
fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }], fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }],
f: fn(~[ast::field]) -> ast::expr_ f: fn(~[ast::field]) -> @ast::expr
) -> @ast::expr { ) -> @ast::expr {
let ext_cx = cx; // required for #ast{}
let fields = do fields.mapi |idx, field| { let fields = do fields.mapi |idx, field| {
let name = cx.lit_str( // ast for `|| deserialize(__d)`
field.span, let expr_lambda = cx.lambda(
@cx.str_of(field.ident) cx.expr_blk(
cx.expr_call(
span,
cx.expr_var(span, ~"deserialize"),
~[cx.expr_var(span, ~"__d")]
)
)
);
// ast for `__d.read_rec_field($(name), $(idx), $(expr_lambda))`
let expr: @ast::expr = cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_rec_field")
),
~[
cx.lit_str(span, @cx.str_of(field.ident)),
cx.lit_uint(span, idx),
expr_lambda,
]
); );
let idx = cx.lit_uint(field.span, idx);
let expr = #ast{
__d.read_rec_field($(name), $(idx), || deserialize(__d))
};
{ {
node: { mutbl: field.mutbl, ident: field.ident, expr: expr }, node: { mutbl: field.mutbl, ident: field.ident, expr: expr },
span: field.span, span: span,
} }
}; };
let fields_expr = cx.expr(span, f(fields)); // ast for `__d.read_rec(|| $(fields_expr))`
let fields_lambda = cx.lambda(cx.expr_blk(fields_expr)); cx.expr_call(
#ast{ __d.read_rec($(fields_lambda)) } span,
cx.expr_field(
span,
cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_rec")
),
~[cx.lambda_expr(f(fields))]
)
} }
fn mk_enum_impl( fn mk_enum_impl(
@ -432,15 +490,15 @@ fn mk_enum_impl(
) -> @ast::item { ) -> @ast::item {
let ser_body = mk_enum_ser_body( let ser_body = mk_enum_ser_body(
cx, cx,
ident,
span, span,
ident,
enum_def.variants enum_def.variants
); );
let deser_body = mk_enum_deser_body( let deser_body = mk_enum_deser_body(
cx, cx,
ident,
span, span,
ident,
enum_def.variants enum_def.variants
); );
@ -449,13 +507,11 @@ fn mk_enum_impl(
fn ser_variant( fn ser_variant(
cx: ext_ctxt, cx: ext_ctxt,
v_span: span, span: span,
v_name: ast::ident, v_name: ast::ident,
v_idx: @ast::expr, v_idx: uint,
args: ~[ast::variant_arg] args: ~[ast::variant_arg]
) -> ast::arm { ) -> ast::arm {
let ext_cx = cx; // required for #ast{}
// Name the variant arguments. // Name the variant arguments.
let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i))); let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i)));
@ -465,12 +521,12 @@ fn ser_variant(
let pat_node = if pats.is_empty() { let pat_node = if pats.is_empty() {
ast::pat_ident( ast::pat_ident(
ast::bind_by_implicit_ref, ast::bind_by_implicit_ref,
cx.path(v_span, ~[v_name]), cx.path(span, ~[v_name]),
None None
) )
} else { } else {
ast::pat_enum( ast::pat_enum(
cx.path(v_span, ~[v_name]), cx.path(span, ~[v_name]),
Some(pats) Some(pats)
) )
}; };
@ -478,45 +534,69 @@ fn ser_variant(
let pat = @{ let pat = @{
id: cx.next_id(), id: cx.next_id(),
node: pat_node, node: pat_node,
span: v_span, span: span,
}; };
// Create the s.emit_variant_arg statements.
let stmts = do args.mapi |a_idx, _arg| { let stmts = do args.mapi |a_idx, _arg| {
let v = cx.var_ref(v_span, names[a_idx]); // ast for `__s.emit_enum_variant_arg`
let a_idx = cx.lit_uint(v_span, a_idx); let expr_emit = cx.expr_field(
span,
cx.expr_var(span, ~"__s"),
cx.ident_of(~"emit_enum_variant_arg")
);
#ast[stmt]{ // ast for `|| $(v).serialize(__s)`
__s.emit_enum_variant_arg($(a_idx), || $(v).serialize(__s)); let expr_serialize = cx.lambda_expr(
} cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_path(span, ~[names[a_idx]]),
cx.ident_of(~"serialize")
),
~[cx.expr_var(span, ~"__s")]
)
);
// ast for `$(expr_emit)($(a_idx), $(expr_serialize))`
cx.stmt(
cx.expr_call(
span,
expr_emit,
~[cx.lit_uint(span, a_idx), expr_serialize]
)
)
}; };
let v_name = cx.lit_str(v_span, @cx.str_of(v_name)); // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))`
let v_sz = cx.lit_uint(v_span, stmts.len()); let body = cx.expr_call(
let lambda = cx.lambda(cx.blk(v_span, stmts)); span,
let body = #ast{ cx.expr_field(
__s.emit_enum_variant($(v_name), $(v_idx), $(v_sz), $(lambda)) span,
}; cx.expr_var(span, ~"__s"),
cx.ident_of(~"emit_enum_variant")
),
~[
cx.lit_str(span, @cx.str_of(v_name)),
cx.lit_uint(span, v_idx),
cx.lit_uint(span, stmts.len()),
cx.lambda_stmts(span, stmts),
]
);
{ pats: ~[pat], guard: None, body: cx.expr_blk(body) } { pats: ~[pat], guard: None, body: cx.expr_blk(body) }
} }
fn mk_enum_ser_body( fn mk_enum_ser_body(
cx: ext_ctxt, cx: ext_ctxt,
e_name: ast::ident, span: span,
e_span: span, name: ast::ident,
variants: ~[ast::variant] variants: ~[ast::variant]
) -> @ast::stmt { ) -> @ast::expr {
let ext_cx = cx; // required for #ast{}
let arms = do variants.mapi |v_idx, variant| { let arms = do variants.mapi |v_idx, variant| {
let v_span = variant.span;
let v_name = variant.node.name;
let v_idx = cx.lit_uint(v_span, v_idx);
match variant.node.kind { match variant.node.kind {
ast::tuple_variant_kind(args) => ast::tuple_variant_kind(args) =>
ser_variant(cx, v_span, v_name, v_idx, args), ser_variant(cx, span, variant.node.name, v_idx, args),
ast::struct_variant_kind(*) => ast::struct_variant_kind(*) =>
fail ~"struct variants unimplemented", fail ~"struct variants unimplemented",
ast::enum_variant_kind(*) => ast::enum_variant_kind(*) =>
@ -524,53 +604,81 @@ fn mk_enum_ser_body(
} }
}; };
// ast for `match self { $(arms) }`
let match_expr = cx.expr( let match_expr = cx.expr(
e_span, span,
ast::expr_match(#ast{ self }, arms) ast::expr_match(
cx.expr_var(span, ~"self"),
arms
)
); );
let e_name = cx.lit_str(e_span, @cx.str_of(e_name));
#ast[stmt]{ __s.emit_enum($(e_name), || $(match_expr)) } // ast for `__s.emit_enum($(name), || $(match_expr))`
cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_var(span, ~"__s"),
cx.ident_of(~"emit_enum")
),
~[
cx.lit_str(span, @cx.str_of(name)),
cx.lambda_expr(match_expr),
]
)
}
fn mk_enum_deser_variant_nary(
cx: ext_ctxt,
span: span,
name: ast::ident,
args: ~[ast::variant_arg]
) -> @ast::expr {
let args = do args.mapi |idx, _arg| {
// ast for `|| deserialize(__d)`
let expr_lambda = cx.lambda_expr(
cx.expr_call(
span,
cx.expr_var(span, ~"deserialize"),
~[cx.expr_var(span, ~"__d")]
)
);
// ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))`
cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_enum_variant_arg")
),
~[cx.lit_uint(span, idx), expr_lambda]
)
};
// ast for `$(name)($(args))`
cx.expr_call(span, cx.expr_path(span, ~[name]), args)
} }
fn mk_enum_deser_body( fn mk_enum_deser_body(
cx: ext_ctxt, cx: ext_ctxt,
e_name: ast::ident, span: span,
e_span: span, name: ast::ident,
variants: ~[ast::variant] variants: ~[ast::variant]
) -> @ast::expr { ) -> @ast::expr {
let ext_cx = cx; // required for #ast{}
let mut arms = do variants.mapi |v_idx, variant| { let mut arms = do variants.mapi |v_idx, variant| {
let v_span = variant.span;
let v_name = variant.node.name;
let body = match variant.node.kind { let body = match variant.node.kind {
ast::tuple_variant_kind(args) => { ast::tuple_variant_kind(args) => {
let tys = args.map(|a| a.ty); if args.is_empty() {
if tys.is_empty() {
// for a nullary variant v, do "v" // for a nullary variant v, do "v"
cx.var_ref(v_span, v_name) cx.expr_path(span, ~[variant.node.name])
} else { } else {
// for an n-ary variant v, do "v(a_1, ..., a_n)" // for an n-ary variant v, do "v(a_1, ..., a_n)"
mk_enum_deser_variant_nary(
let arg_exprs = do tys.mapi |a_idx, _ty| { cx,
let a_idx = cx.lit_uint(v_span, a_idx); span,
#ast{ variant.node.name,
__d.read_enum_variant_arg($(a_idx), || { args
deserialize(__d)
})
}
};
cx.expr(
v_span,
ast::expr_call(
cx.var_ref(v_span, v_name),
arg_exprs,
false
)
) )
} }
}, },
@ -582,8 +690,8 @@ fn mk_enum_deser_body(
let pat = @{ let pat = @{
id: cx.next_id(), id: cx.next_id(),
node: ast::pat_lit(cx.lit_uint(v_span, v_idx)), node: ast::pat_lit(cx.lit_uint(span, v_idx)),
span: v_span, span: span,
}; };
{ {
@ -594,23 +702,71 @@ fn mk_enum_deser_body(
}; };
let impossible_case = { let impossible_case = {
pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: e_span}], pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: span}],
guard: None, guard: None,
// FIXME(#3198): proper error message // FIXME(#3198): proper error message
body: cx.expr_blk(cx.expr(e_span, ast::expr_fail(None))), body: cx.expr_blk(cx.expr(span, ast::expr_fail(None))),
}; };
vec::push(arms, impossible_case); vec::push(arms, impossible_case);
let e_name = cx.lit_str(e_span, @cx.str_of(e_name)); // ast for `|i| { match i { $(arms) } }`
let alt_expr = cx.expr(e_span, ast::expr_match(#ast{ i }, arms)); let expr_lambda = cx.expr(
span,
ast::expr_fn_block(
{
inputs: ~[{
mode: ast::infer(cx.next_id()),
ty: @{
id: cx.next_id(),
node: ast::ty_infer,
span: span
},
ident: cx.ident_of(~"i"),
id: cx.next_id(),
}],
output: @{
id: cx.next_id(),
node: ast::ty_infer,
span: span,
},
cf: ast::return_val,
},
cx.expr_blk(
cx.expr(
span,
ast::expr_match(cx.expr_var(span, ~"i"), arms)
)
),
@~[]
)
);
#ast{ // ast for `__d.read_enum_variant($(expr_lambda))`
__d.read_enum($(e_name), || { let expr_lambda = cx.lambda_expr(
__d.read_enum_variant(|i| { cx.expr_call(
$(alt_expr) span,
}) cx.expr_field(
}) span,
} cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_enum_variant")
),
~[expr_lambda]
)
);
// ast for `__d.read_enum($(e_name), $(expr_lambda))`
cx.expr_call(
span,
cx.expr_field(
span,
cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_enum")
),
~[
cx.lit_str(span, @cx.str_of(name)),
expr_lambda
]
)
} }