syntax/ext/format -- rewrite conflicting closures into methods

This commit is contained in:
Niko Matsakis 2014-02-07 14:45:46 -05:00
parent b2b4c79b17
commit ca65c00ef2

View File

@ -21,6 +21,7 @@ use rsparse = parse;
use std::fmt::parse; use std::fmt::parse;
use std::hashmap::{HashMap, HashSet}; use std::hashmap::{HashMap, HashSet};
use std::vec; use std::vec;
use std::cell::RefCell;
#[deriving(Eq)] #[deriving(Eq)]
enum ArgumentType { enum ArgumentType {
@ -367,157 +368,167 @@ impl<'a> Context<'a> {
return ~[unnamed, allow_dead_code]; return ~[unnamed, allow_dead_code];
} }
/// Translate a `parse::Piece` to a static `rt::Piece` fn parsepath(&self, s: &str) -> ~[ast::Ident] {
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr { ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
let sp = self.fmtsp; self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
let parsepath = |s: &str| { }
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
self.ecx.ident_of("parse"), self.ecx.ident_of(s)] fn rtpath(&self, s: &str) -> ~[ast::Ident] {
}; ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
let rtpath = |s: &str| { self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), }
self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
}; fn ctpath(&self, s: &str) -> ~[ast::Ident] {
let ctpath = |s: &str| { ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
self.ecx.ident_of("parse"), self.ecx.ident_of(s)] }
};
let none = self.ecx.path_global(sp, ~[ fn none(&self) -> @ast::Expr {
let none = self.ecx.path_global(self.fmtsp, ~[
self.ecx.ident_of("std"), self.ecx.ident_of("std"),
self.ecx.ident_of("option"), self.ecx.ident_of("option"),
self.ecx.ident_of("None")]); self.ecx.ident_of("None")]);
let none = self.ecx.expr_path(none); self.ecx.expr_path(none)
let some = |e: @ast::Expr| { }
let p = self.ecx.path_global(sp, ~[
fn some(&self, e: @ast::Expr) -> @ast::Expr {
let p = self.ecx.path_global(self.fmtsp, ~[
self.ecx.ident_of("std"), self.ecx.ident_of("std"),
self.ecx.ident_of("option"), self.ecx.ident_of("option"),
self.ecx.ident_of("Some")]); self.ecx.ident_of("Some")]);
let p = self.ecx.expr_path(p); let p = self.ecx.expr_path(p);
self.ecx.expr_call(sp, p, ~[e]) self.ecx.expr_call(self.fmtsp, p, ~[e])
}; }
let trans_count = |c: parse::Count| {
match c { fn trans_count(&self, c: parse::Count) -> @ast::Expr {
parse::CountIs(i) => { let sp = self.fmtsp;
self.ecx.expr_call_global(sp, rtpath("CountIs"), match c {
~[self.ecx.expr_uint(sp, i)]) parse::CountIs(i) => {
} self.ecx.expr_call_global(sp, self.rtpath("CountIs"),
parse::CountIsParam(i) => { ~[self.ecx.expr_uint(sp, i)])
self.ecx.expr_call_global(sp, rtpath("CountIsParam"),
~[self.ecx.expr_uint(sp, i)])
}
parse::CountImplied => {
let path = self.ecx.path_global(sp, rtpath("CountImplied"));
self.ecx.expr_path(path)
}
parse::CountIsNextParam => {
let path = self.ecx.path_global(sp, rtpath("CountIsNextParam"));
self.ecx.expr_path(path)
}
parse::CountIsName(n) => {
let i = match self.name_positions.find_equiv(&n) {
Some(&i) => i,
None => 0, // error already emitted elsewhere
};
let i = i + self.args.len();
self.ecx.expr_call_global(sp, rtpath("CountIsParam"),
~[self.ecx.expr_uint(sp, i)])
}
} }
}; parse::CountIsParam(i) => {
let trans_method = |method: &parse::Method| { self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
let method = match *method { ~[self.ecx.expr_uint(sp, i)])
parse::Select(ref arms, ref default) => { }
let arms = arms.iter().map(|arm| { parse::CountImplied => {
let p = self.ecx.path_global(sp, rtpath("SelectArm")); let path = self.ecx.path_global(sp, self.rtpath("CountImplied"));
self.ecx.expr_path(path)
}
parse::CountIsNextParam => {
let path = self.ecx.path_global(sp, self.rtpath("CountIsNextParam"));
self.ecx.expr_path(path)
}
parse::CountIsName(n) => {
let i = match self.name_positions.find_equiv(&n) {
Some(&i) => i,
None => 0, // error already emitted elsewhere
};
let i = i + self.args.len();
self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
~[self.ecx.expr_uint(sp, i)])
}
}
}
fn trans_method(&mut self, method: &parse::Method) -> @ast::Expr {
let sp = self.fmtsp;
let method = match *method {
parse::Select(ref arms, ref default) => {
let arms = arms.iter().map(|arm| {
let p = self.ecx.path_global(sp, self.rtpath("SelectArm"));
let result = arm.result.iter().map(|p| { let result = arm.result.iter().map(|p| {
self.trans_piece(p) self.trans_piece(p)
}).collect(); }).collect();
let s = token::intern_and_get_ident(arm.selector); let s = token::intern_and_get_ident(arm.selector);
let selector = self.ecx.expr_str(sp, s); let selector = self.ecx.expr_str(sp, s);
self.ecx.expr_struct(sp, p, ~[ self.ecx.expr_struct(sp, p, ~[
self.ecx.field_imm(sp, self.ecx.field_imm(sp,
self.ecx.ident_of("selector"), self.ecx.ident_of("selector"),
selector), selector),
self.ecx.field_imm(sp, self.ecx.ident_of("result"), self.ecx.field_imm(sp, self.ecx.ident_of("result"),
self.ecx.expr_vec_slice(sp, result)), self.ecx.expr_vec_slice(sp, result)),
]) ])
}).collect(); }).collect();
let default = default.iter().map(|p| { let default = default.iter().map(|p| {
self.trans_piece(p) self.trans_piece(p)
}).collect(); }).collect();
self.ecx.expr_call_global(sp, rtpath("Select"), ~[ self.ecx.expr_call_global(sp, self.rtpath("Select"), ~[
self.ecx.expr_vec_slice(sp, arms), self.ecx.expr_vec_slice(sp, arms),
self.ecx.expr_vec_slice(sp, default), self.ecx.expr_vec_slice(sp, default),
]) ])
} }
parse::Plural(offset, ref arms, ref default) => { parse::Plural(offset, ref arms, ref default) => {
let offset = match offset { let offset = match offset {
Some(i) => { some(self.ecx.expr_uint(sp, i)) } Some(i) => { self.some(self.ecx.expr_uint(sp, i)) }
None => { none.clone() } None => { self.none() }
}; };
let arms = arms.iter().map(|arm| { let arms = arms.iter().map(|arm| {
let p = self.ecx.path_global(sp, rtpath("PluralArm")); let p = self.ecx.path_global(sp, self.rtpath("PluralArm"));
let result = arm.result.iter().map(|p| { let result = arm.result.iter().map(|p| {
self.trans_piece(p) self.trans_piece(p)
}).collect(); }).collect();
let (lr, selarg) = match arm.selector { let (lr, selarg) = match arm.selector {
parse::Keyword(t) => { parse::Keyword(t) => {
let p = ctpath(format!("{:?}", t)); let p = self.ctpath(format!("{:?}", t));
let p = self.ecx.path_global(sp, p); let p = self.ecx.path_global(sp, p);
(rtpath("Keyword"), self.ecx.expr_path(p)) (self.rtpath("Keyword"), self.ecx.expr_path(p))
} }
parse::Literal(i) => { parse::Literal(i) => {
(rtpath("Literal"), self.ecx.expr_uint(sp, i)) (self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
} }
}; };
let selector = self.ecx.expr_call_global(sp, let selector = self.ecx.expr_call_global(sp,
lr, ~[selarg]); lr, ~[selarg]);
self.ecx.expr_struct(sp, p, ~[ self.ecx.expr_struct(sp, p, ~[
self.ecx.field_imm(sp, self.ecx.field_imm(sp,
self.ecx.ident_of("selector"), self.ecx.ident_of("selector"),
selector), selector),
self.ecx.field_imm(sp, self.ecx.ident_of("result"), self.ecx.field_imm(sp, self.ecx.ident_of("result"),
self.ecx.expr_vec_slice(sp, result)), self.ecx.expr_vec_slice(sp, result)),
]) ])
}).collect(); }).collect();
let default = default.iter().map(|p| { let default = default.iter().map(|p| {
self.trans_piece(p) self.trans_piece(p)
}).collect(); }).collect();
self.ecx.expr_call_global(sp, rtpath("Plural"), ~[ self.ecx.expr_call_global(sp, self.rtpath("Plural"), ~[
offset, offset,
self.ecx.expr_vec_slice(sp, arms), self.ecx.expr_vec_slice(sp, arms),
self.ecx.expr_vec_slice(sp, default), self.ecx.expr_vec_slice(sp, default),
]) ])
} }
}; };
let life = self.ecx.lifetime(sp, self.ecx.ident_of("static")); let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
let ty = self.ecx.ty_path(self.ecx.path_all( let ty = self.ecx.ty_path(self.ecx.path_all(
sp, sp,
true, true,
rtpath("Method"), self.rtpath("Method"),
opt_vec::with(life), opt_vec::with(life),
~[] ~[]
), None); ), None);
let st = ast::ItemStatic(ty, ast::MutImmutable, method); let st = ast::ItemStatic(ty, ast::MutImmutable, method);
let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}", let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
self.method_statics.len())); self.method_statics.len()));
let item = self.ecx.item(sp, static_name, self.static_attrs(), st); let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
self.method_statics.push(item); self.method_statics.push(item);
self.ecx.expr_ident(sp, static_name) self.ecx.expr_ident(sp, static_name)
}; }
/// Translate a `parse::Piece` to a static `rt::Piece`
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
let sp = self.fmtsp;
match *piece { match *piece {
parse::String(s) => { parse::String(s) => {
let s = token::intern_and_get_ident(s); let s = token::intern_and_get_ident(s);
self.ecx.expr_call_global(sp, self.ecx.expr_call_global(sp,
rtpath("String"), self.rtpath("String"),
~[ ~[
self.ecx.expr_str(sp, s) self.ecx.expr_str(sp, s)
]) ])
} }
parse::CurrentArgument => { parse::CurrentArgument => {
let nil = self.ecx.expr_lit(sp, ast::LitNil); let nil = self.ecx.expr_lit(sp, ast::LitNil);
self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil]) self.ecx.expr_call_global(sp, self.rtpath("CurrentArgument"), ~[nil])
} }
parse::Argument(ref arg) => { parse::Argument(ref arg) => {
// Translate the position // Translate the position
@ -525,11 +536,11 @@ impl<'a> Context<'a> {
// These two have a direct mapping // These two have a direct mapping
parse::ArgumentNext => { parse::ArgumentNext => {
let path = self.ecx.path_global(sp, let path = self.ecx.path_global(sp,
rtpath("ArgumentNext")); self.rtpath("ArgumentNext"));
self.ecx.expr_path(path) self.ecx.expr_path(path)
} }
parse::ArgumentIs(i) => { parse::ArgumentIs(i) => {
self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
~[self.ecx.expr_uint(sp, i)]) ~[self.ecx.expr_uint(sp, i)])
} }
// Named arguments are converted to positional arguments at // Named arguments are converted to positional arguments at
@ -540,7 +551,7 @@ impl<'a> Context<'a> {
None => 0, // error already emitted elsewhere None => 0, // error already emitted elsewhere
}; };
let i = i + self.args.len(); let i = i + self.args.len();
self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
~[self.ecx.expr_uint(sp, i)]) ~[self.ecx.expr_uint(sp, i)])
} }
}; };
@ -550,20 +561,20 @@ impl<'a> Context<'a> {
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill as u32)); let fill = self.ecx.expr_lit(sp, ast::LitChar(fill as u32));
let align = match arg.format.align { let align = match arg.format.align {
parse::AlignLeft => { parse::AlignLeft => {
self.ecx.path_global(sp, parsepath("AlignLeft")) self.ecx.path_global(sp, self.parsepath("AlignLeft"))
} }
parse::AlignRight => { parse::AlignRight => {
self.ecx.path_global(sp, parsepath("AlignRight")) self.ecx.path_global(sp, self.parsepath("AlignRight"))
} }
parse::AlignUnknown => { parse::AlignUnknown => {
self.ecx.path_global(sp, parsepath("AlignUnknown")) self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
} }
}; };
let align = self.ecx.expr_path(align); let align = self.ecx.expr_path(align);
let flags = self.ecx.expr_uint(sp, arg.format.flags); let flags = self.ecx.expr_uint(sp, arg.format.flags);
let prec = trans_count(arg.format.precision); let prec = self.trans_count(arg.format.precision);
let width = trans_count(arg.format.width); let width = self.trans_count(arg.format.width);
let path = self.ecx.path_global(sp, rtpath("FormatSpec")); let path = self.ecx.path_global(sp, self.rtpath("FormatSpec"));
let fmt = self.ecx.expr_struct(sp, path, ~[ let fmt = self.ecx.expr_struct(sp, path, ~[
self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
self.ecx.field_imm(sp, self.ecx.ident_of("align"), align), self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
@ -574,19 +585,19 @@ impl<'a> Context<'a> {
// Translate the method (if any) // Translate the method (if any)
let method = match arg.method { let method = match arg.method {
None => { none.clone() } None => { self.none() }
Some(ref m) => { Some(ref m) => {
let m = trans_method(*m); let m = self.trans_method(*m);
some(self.ecx.expr_addr_of(sp, m)) self.some(self.ecx.expr_addr_of(sp, m))
} }
}; };
let path = self.ecx.path_global(sp, rtpath("Argument")); let path = self.ecx.path_global(sp, self.rtpath("Argument"));
let s = self.ecx.expr_struct(sp, path, ~[ let s = self.ecx.expr_struct(sp, path, ~[
self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt), self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
self.ecx.field_imm(sp, self.ecx.ident_of("method"), method), self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
]); ]);
self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s]) self.ecx.expr_call_global(sp, self.rtpath("Argument"), ~[s])
} }
} }
} }