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