use core::option;
use core::vec;
- use std::oldmap::HashMap;
+ use core::hashmap::LinearMap;
- pub fn expand_expr(exts: SyntaxExtensions, cx: ext_ctxt,
+ pub fn expand_expr(extsbox: @mut SyntaxEnv, cx: ext_ctxt,
- e: expr_, s: span, fld: ast_fold,
- orig: fn@(expr_, span, ast_fold) -> (expr_, span))
+ e: &expr_, s: span, fld: ast_fold,
+ orig: fn@(&expr_, span, ast_fold) -> (expr_, span))
-> (expr_, span) {
- return match e {
- // expr_mac should really be expr_ext or something; it's the
- // entry-point for all syntax extensions.
- expr_mac(ref mac) => {
-
+ match *e {
+ // expr_mac should really be expr_ext or something; it's the
+ // entry-point for all syntax extensions.
+ expr_mac(ref mac) => {
match (*mac).node {
-
- // Token-tree macros, these will be the only case when we're
- // finished transitioning.
- mac_invoc_tt(pth, ref tts) => {
- assert (vec::len(pth.idents) == 1u);
- /* using idents and token::special_idents would make the
- the macro names be hygienic */
- let extname = cx.parse_sess().interner.get(pth.idents[0]);
- // leaving explicit deref here to highlight unbox op:
- match (*extsbox).find(&extname) {
- None => {
- cx.span_fatal(pth.span,
- fmt!("macro undefined: '%s'", *extname))
- }
- Some(@SE(NormalTT(SyntaxExpanderTT{expander: exp,
- span: exp_sp}))) => {
- cx.bt_push(ExpandedFrom(CallInfo{
- call_site: s,
- callee: NameAndSpan {
- name: *extname, span: exp_sp
+ // Token-tree macros, these will be the only case when we're
+ // finished transitioning.
+ mac_invoc_tt(pth, ref tts) => {
+ assert (vec::len(pth.idents) == 1u);
+ /* using idents and token::special_idents would make the
+ the macro names be hygienic */
+ let extname = cx.parse_sess().interner.get(pth.idents[0]);
- match exts.find(&extname) {
++ // leaving explicit deref here to highlight unbox op:
++ match (*extsbox).find(&extname) {
+ None => {
+ cx.span_fatal(
+ pth.span,
+ fmt!("macro undefined: '%s'", *extname))
}
- Some(NormalTT(SyntaxExpanderTT{
- }));
-
- let expanded = match exp(cx, (*mac).span, (*tts)) {
- MRExpr(e) => e,
- MRAny(expr_maker,_,_) => expr_maker(),
- _ => cx.span_fatal(
- pth.span, fmt!("non-expr macro in expr pos: %s",
- *extname))
- };
-
- //keep going, outside-in
- let fully_expanded = fld.fold_expr(expanded).node;
- cx.bt_pop();
-
- (fully_expanded, s)
- }
- _ => {
- cx.span_fatal(pth.span,
- fmt!("'%s' is not a tt-style macro",
- *extname))
- }
-
++ Some(@SE(NormalTT(SyntaxExpanderTT{
+ expander: exp,
+ span: exp_sp
- })) => {
++ }))) => {
+ cx.bt_push(ExpandedFrom(CallInfo {
+ call_site: s,
+ callee: NameAndSpan {
+ name: copy *extname,
+ span: exp_sp,
+ },
+ }));
+
+ let expanded = match exp(cx, mac.span, *tts) {
+ MRExpr(e) => e,
+ MRAny(expr_maker,_,_) => expr_maker(),
+ _ => {
+ cx.span_fatal(
+ pth.span,
+ fmt!(
+ "non-expr macro in expr pos: %s",
+ *extname
+ )
+ )
+ }
+ };
+
+ //keep going, outside-in
+ let fully_expanded =
+ copy fld.fold_expr(expanded).node;
+ cx.bt_pop();
+
+ (fully_expanded, s)
+ }
+ _ => {
+ cx.span_fatal(
+ pth.span,
+ fmt!("'%s' is not a tt-style macro", *extname)
+ )
+ }
+ }
}
- }
}
- }
- _ => orig(e, s, fld)
- };
+ }
+ _ => orig(e, s, fld)
+ }
}
// This is a secondary mechanism for invoking syntax extensions on items:
//
// NB: there is some redundancy between this and expand_item, below, and
// they might benefit from some amount of semantic and language-UI merger.
- pub fn expand_mod_items(exts: SyntaxExtensions, cx: ext_ctxt,
+ pub fn expand_mod_items(extsbox: @mut SyntaxEnv, cx: ext_ctxt,
- module_: ast::_mod, fld: ast_fold,
- orig: fn@(ast::_mod, ast_fold) -> ast::_mod)
+ module_: &ast::_mod, fld: ast_fold,
+ orig: fn@(&ast::_mod, ast_fold) -> ast::_mod)
-> ast::_mod {
// Fold the contents first:
let module_ = orig(module_, fld);
}
+ // eval $e with a new exts frame:
+ macro_rules! with_exts_frame (
+ ($extsboxexpr:expr,$e:expr) =>
+ ({let extsbox = $extsboxexpr;
+ let oldexts = *extsbox;
+ *extsbox = oldexts.push_frame();
+ let result = $e;
+ *extsbox = oldexts;
+ result
+ })
+ )
+
// When we enter a module, record it, for the sake of `module!`
- pub fn expand_item(exts: SyntaxExtensions,
+ pub fn expand_item(extsbox: @mut SyntaxEnv,
- cx: ext_ctxt, &&it: @ast::item, fld: ast_fold,
- orig: fn@(&&v: @ast::item, ast_fold) -> Option<@ast::item>)
+ cx: ext_ctxt, it: @ast::item, fld: ast_fold,
+ orig: fn@(@ast::item, ast_fold) -> Option<@ast::item>)
-> Option<@ast::item> {
- let is_mod = match it.node {
- ast::item_mod(_) | ast::item_foreign_mod(_) => true,
- _ => false
- };
+ // need to do expansion first... it might turn out to be a module.
let maybe_it = match it.node {
- ast::item_mac(*) => expand_item_mac(exts, cx, it, fld),
+ ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
_ => Some(it)
};
-
match maybe_it {
Some(it) => {
- if is_mod { cx.mod_push(it.ident); }
- let ret_val = orig(it, fld);
- if is_mod { cx.mod_pop(); }
- return ret_val;
+ match it.node {
+ ast::item_mod(_) | ast::item_foreign_mod(_) => {
+ cx.mod_push(it.ident);
+ let result =
+ // don't push a macro scope for macro_escape:
+ if contains_macro_escape(it.attrs) {
+ orig(it,fld)
+ } else {
+ // otherwise, push a scope:
+ with_exts_frame!(extsbox,orig(it,fld))
+ };
+ cx.mod_pop();
+ result
+ }
+ _ => orig(it,fld)
+ }
}
- None => return None
+ None => None
}
}
return maybe_it;
}
- pub fn expand_stmt(exts: SyntaxExtensions, cx: ext_ctxt,
+ // expand a stmt
+ pub fn expand_stmt(extsbox: @mut SyntaxEnv, cx: ext_ctxt,
- && s: stmt_, sp: span, fld: ast_fold,
- orig: fn@(&&s: stmt_, span, ast_fold) -> (stmt_, span))
+ s: &stmt_, sp: span, fld: ast_fold,
+ orig: fn@(s: &stmt_, span, ast_fold) -> (stmt_, span))
-> (stmt_, span) {
- let (mac, pth, tts, semi) = match s {
+ let (mac, pth, tts, semi) = match *s {
stmt_mac(ref mac, semi) => {
- match (*mac).node {
- mac_invoc_tt(pth, ref tts) => ((*mac), pth, (*tts), semi)
+ match mac.node {
+ mac_invoc_tt(pth, ref tts) => {
+ (copy *mac, pth, copy *tts, semi)
+ }
}
}
_ => return orig(s, sp, fld)
None =>
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", *extname)),
- Some(NormalTT(
- SyntaxExpanderTT{expander: exp, span: exp_sp})) => {
+ Some(@SE(NormalTT(
+ SyntaxExpanderTT{expander: exp, span: exp_sp}))) => {
cx.bt_push(ExpandedFrom(CallInfo {
call_site: sp,
- callee: NameAndSpan { name: *extname, span: exp_sp }
+ callee: NameAndSpan { name: copy *extname, span: exp_sp }
}));
let expanded = match exp(cx, mac.span, tts) {
MRExpr(e) =>
}
- && blk: blk_, sp: span, fld: ast_fold,
- orig: fn@(&&s: blk_, span, ast_fold) -> (blk_, span))
+
+ pub fn expand_block(extsbox: @mut SyntaxEnv, cx: ext_ctxt,
++ blk: &blk_, sp: span, fld: ast_fold,
++ orig: fn@(&blk_, span, ast_fold) -> (blk_, span))
+ -> (blk_, span) {
+ match (*extsbox).find(&@~" block") {
+ // no scope limit on macros in this block, no need
+ // to push an exts frame:
+ Some(@ScopeMacros(false)) => {
+ orig (blk,sp,fld)
+ },
+ // this block should limit the scope of its macros:
+ Some(@ScopeMacros(true)) => {
+ // see note below about treatment of exts table
+ with_exts_frame!(extsbox,orig(blk,sp,fld))
+ },
+ _ => cx.span_bug(sp,
+ ~"expected ScopeMacros binding for \" block\"")
+ }
+ }
+
pub fn new_span(cx: ext_ctxt, sp: span) -> span {
/* this discards information in the case of macro-defining macros */
return span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
cfg: ast::crate_cfg, c: @crate) -> @crate {
- let exts = syntax_expander_table();
+ // adding *another* layer of indirection here so that the block
+ // visitor can swap out one exts table for another for the duration
+ // of the block. The cleaner alternative would be to thread the
+ // exts table through the fold, but that would require updating
+ // every method/element of AstFoldFns in fold.rs.
+ let extsbox = @mut syntax_expander_table();
let afp = default_ast_fold();
- let cx: ext_ctxt = mk_ctxt(parse_sess, cfg);
+ let cx: ext_ctxt = mk_ctxt(parse_sess, copy cfg);
let f_pre = @AstFoldFns {
- fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
- fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod),
- fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item),
- fold_stmt: |a,b,c| expand_stmt(exts, cx, a, b, c, afp.fold_stmt),
+ fold_expr: |expr,span,recur|
+ expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr),
+ fold_mod: |modd,recur|
+ expand_mod_items(extsbox, cx, modd, recur, afp.fold_mod),
+ fold_item: |item,recur|
+ expand_item(extsbox, cx, item, recur, afp.fold_item),
+ fold_stmt: |stmt,span,recur|
+ expand_stmt(extsbox, cx, stmt, span, recur, afp.fold_stmt),
+ fold_block: |blk,span,recur|
- expand_block (extsbox, cx, blk, span, recur, afp.fold_block),
++ expand_block(extsbox, cx, blk, span, recur, afp.fold_block),
new_span: |a| new_span(cx, a),
.. *afp};
let f = make_fold(f_pre);
- let cm = parse_expr_from_source_str(~"<core-macros>",
- @core_macros(),
- copy cfg,
- parse_sess);
-
+ // add a bunch of macros as though they were placed at the
+ // head of the program (ick).
- let attrs = ~[spanned {span:codemap::dummy_sp(),
- node: attribute_
- {style:attr_outer,
- value:spanned
- {node:meta_word(@~"macro_escape"),
- span:codemap::dummy_sp()},
- is_sugared_doc:false}}];
++ let attrs = ~[
++ spanned {
++ span: codemap::dummy_sp(),
++ node: attribute_ {
++ style: attr_outer,
++ value: @spanned {
++ node: meta_word(@~"macro_escape"),
++ span: codemap::dummy_sp(),
++ },
++ is_sugared_doc: false,
++ }
++ }
++ ];
+
+ let cm = match parse_item_from_source_str(~"<core-macros>",
+ @core_macros(),
- cfg,attrs,
++ copy cfg,
++ attrs,
+ parse_sess) {
+ Some(item) => item,
+ None => cx.bug(~"expected core macros to parse correctly")
+ };
// This is run for its side-effects on the expander env,
// as it registers all the core macros as expanders.
- f.fold_expr(cm);
+ f.fold_item(cm);
- let res = @f.fold_crate(*c);
- return res;
+ @f.fold_crate(&*c)
}
+
+ #[cfg(test)]
+ mod test {
+ use super::*;
+ use util::testing::check_equal;
+
+ // make sure that fail! is present
+ #[test] fn fail_exists_test () {
+ let src = ~"fn main() { fail!(~\"something appropriately gloomy\");}";
+ let sess = parse::new_parse_sess(None);
+ let cfg = ~[];
+ let crate_ast = parse::parse_crate_from_source_str(
+ ~"<test>",
+ @src,
+ cfg,sess);
+ expand_crate(sess,cfg,crate_ast);
+ }
+
+ // these following tests are quite fragile, in that they don't test what
+ // *kind* of failure occurs.
+
+ // make sure that macros can leave scope
+ #[should_fail]
+ #[test] fn macros_cant_escape_fns_test () {
+ let src = ~"fn bogus() {macro_rules! z (() => (3+4))}\
+ fn inty() -> int { z!() }";
+ let sess = parse::new_parse_sess(None);
+ let cfg = ~[];
+ let crate_ast = parse::parse_crate_from_source_str(
+ ~"<test>",
+ @src,
+ cfg,sess);
+ // should fail:
+ expand_crate(sess,cfg,crate_ast);
+ }
+
+ // make sure that macros can leave scope for modules
+ #[should_fail]
+ #[test] fn macros_cant_escape_mods_test () {
+ let src = ~"mod foo {macro_rules! z (() => (3+4))}\
+ fn inty() -> int { z!() }";
+ let sess = parse::new_parse_sess(None);
+ let cfg = ~[];
+ let crate_ast = parse::parse_crate_from_source_str(
+ ~"<test>",
+ @src,
+ cfg,sess);
+ // should fail:
+ expand_crate(sess,cfg,crate_ast);
+ }
+
+ // macro_escape modules shouldn't cause macros to leave scope
+ #[test] fn macros_can_escape_flattened_mods_test () {
+ let src = ~"#[macro_escape] mod foo {macro_rules! z (() => (3+4))}\
+ fn inty() -> int { z!() }";
+ let sess = parse::new_parse_sess(None);
+ let cfg = ~[];
+ let crate_ast = parse::parse_crate_from_source_str(
+ ~"<test>",
+ @src,
+ cfg,sess);
+ // should fail:
+ expand_crate(sess,cfg,crate_ast);
+ }
+
+ #[test] fn core_macros_must_parse () {
+ let src = ~"
+ pub mod macros {
+ macro_rules! ignore (($($x:tt)*) => (()))
+
+ macro_rules! error ( ($( $arg:expr ),+) => (
+ log(::core::error, fmt!( $($arg),+ )) ))
+ }";
+ let sess = parse::new_parse_sess(None);
+ let cfg = ~[];
+ let item_ast = parse::parse_item_from_source_str(
+ ~"<test>",
+ @src,
+ cfg,~[make_dummy_attr (@~"macro_escape")],sess);
+ match item_ast {
+ Some(_) => (), // success
+ None => fail!(~"expected this to parse")
+ }
+ }
+
+ #[test] fn test_contains_flatten (){
+ let attr1 = make_dummy_attr (@~"foo");
+ let attr2 = make_dummy_attr (@~"bar");
+ let escape_attr = make_dummy_attr (@~"macro_escape");
+ let attrs1 = ~[attr1, escape_attr, attr2];
+ check_equal (contains_macro_escape (attrs1),true);
+ let attrs2 = ~[attr1,attr2];
+ check_equal (contains_macro_escape (attrs2),false);
+ }
+
+ // make a "meta_word" outer attribute with the given name
+ fn make_dummy_attr(s: @~str) -> ast::attribute {
+ spanned {span:codemap::dummy_sp(),
+ node: attribute_
+ {style:attr_outer,
+ value:spanned
+ {node:meta_word(s),
+ span:codemap::dummy_sp()},
+ is_sugared_doc:false}}
+ }
+
+ }
+
// Local Variables:
// mode: rust
// fill-column: 78;
}
pub trait append_types {
- fn add_ty(ty: @ast::Ty) -> @ast::path;
- fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path;
+ fn add_ty(&self, ty: @ast::Ty) -> @ast::path;
+ fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::path;
}
- pub impl append_types for @ast::path {
+ impl append_types for @ast::path {
- fn add_ty(ty: @ast::Ty) -> @ast::path {
- @ast::path { types: vec::append_one(self.types, ty),
- .. *self}
+ fn add_ty(&self, ty: @ast::Ty) -> @ast::path {
+ @ast::path {
+ types: vec::append_one(copy self.types, ty),
+ .. copy **self
+ }
}
- fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path {
- @ast::path { types: vec::append(self.types, tys),
- .. *self}
+ fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::path {
+ @ast::path {
+ types: vec::append(copy self.types, tys),
+ .. copy **self
+ }
}
}
fn parse_message(&self, state: state);
}
- pub impl proto_parser for parser::Parser {
+ impl proto_parser for parser::Parser {
- fn parse_proto(&self, id: ~str) -> protocol {
+ fn parse_proto(&self, +id: ~str) -> protocol {
let proto = protocol(id, *self.span);
- self.parse_seq_to_before_end(token::EOF, SeqSep {
- sep: None,
- trailing_sep_allowed: false
- }, |self| self.parse_state(proto));
+ self.parse_seq_to_before_end(
+ &token::EOF,
+ SeqSep {
+ sep: None,
+ trailing_sep_allowed: false,
+ },
+ |self| self.parse_state(proto)
+ );
return proto;
}
use core::str;
use core::vec;
- fn topmost_expn_info(expn_info: @codemap::ExpnInfo) -> @codemap::ExpnInfo {
- // FIXME(#3874): this would be better written as:
- // let @ExpandedFrom(CallInfo {
- // call_site: ref call_site,
- // _
- // }) = expn_info;
- match *expn_info {
- ExpandedFrom(CallInfo { call_site: ref call_site, _}) => {
- match call_site.expn_info {
- Some(next_expn_info) => {
- // Don't recurse into file using "include!"
- match *next_expn_info {
- ExpandedFrom(
- CallInfo { callee: NameAndSpan {
- name: ref name,
- _
- },
- _
- }) => {
- if *name == ~"include" { return expn_info; }
- }
- }
-
- topmost_expn_info(next_expn_info)
- },
- None => expn_info
- }
- }
- }
- }
+ // These macros all relate to the file system; they either return
+ // the column/row/filename of the expression, or they include
+ // a given file into the current one.
/* line!(): expands to the current line number */
-pub fn expand_line(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
+pub fn expand_line(cx: ext_ctxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
base::check_zero_tts(cx, sp, tts, "line!");
|x| cx.str_of(*x)), ~"::")))
}
-pub fn expand_include(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
+ // include! : parse the given file as an expr
+ // This is generally a bad idea because it's going to behave
+ // unhygienically.
+pub fn expand_include(cx: ext_ctxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let file = get_single_str_from_tts(cx, sp, tts, "include!");
let p = parse::new_sub_parser_from_file(
base::MRExpr(p.parse_expr())
}
-pub fn expand_include_str(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
+ // include_str! : read the given file, insert it as a literal string expr
+pub fn expand_include_str(cx: ext_ctxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let file = get_single_str_from_tts(cx, sp, tts, "include_str!");
let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file)));
fn noop_span(sp: span) -> span { return sp; }
pub fn default_ast_fold() -> ast_fold_fns {
- return @AstFoldFns {fold_crate: wrap(noop_fold_crate),
- fold_view_item: noop_fold_view_item,
- fold_foreign_item: noop_fold_foreign_item,
- fold_item: noop_fold_item,
- fold_struct_field: noop_fold_struct_field,
- fold_item_underscore: noop_fold_item_underscore,
- fold_method: noop_fold_method,
- fold_block: wrap(noop_fold_block),
- fold_stmt: wrap(noop_fold_stmt),
- fold_arm: noop_fold_arm,
- fold_pat: wrap(noop_fold_pat),
- fold_decl: wrap(noop_fold_decl),
- fold_expr: wrap(noop_fold_expr),
- fold_ty: wrap(noop_fold_ty),
- fold_mod: noop_fold_mod,
- fold_foreign_mod: noop_fold_foreign_mod,
- fold_variant: wrap(noop_fold_variant),
- fold_ident: noop_fold_ident,
- fold_path: noop_fold_path,
- fold_local: wrap(noop_fold_local),
- map_exprs: noop_map_exprs,
- new_id: noop_id,
- new_span: noop_span};
+ @AstFoldFns {
+ fold_crate: wrap(noop_fold_crate),
+ fold_view_item: noop_fold_view_item,
+ fold_foreign_item: noop_fold_foreign_item,
+ fold_item: noop_fold_item,
+ fold_struct_field: noop_fold_struct_field,
+ fold_item_underscore: noop_fold_item_underscore,
+ fold_method: noop_fold_method,
+ fold_block: wrap(noop_fold_block),
+ fold_stmt: wrap(noop_fold_stmt),
+ fold_arm: noop_fold_arm,
+ fold_pat: wrap(noop_fold_pat),
+ fold_decl: wrap(noop_fold_decl),
+ fold_expr: wrap(noop_fold_expr),
+ fold_ty: wrap(noop_fold_ty),
+ fold_mod: noop_fold_mod,
+ fold_foreign_mod: noop_fold_foreign_mod,
+ fold_variant: wrap(noop_fold_variant),
+ fold_ident: noop_fold_ident,
+ fold_path: noop_fold_path,
+ fold_local: wrap(noop_fold_local),
+ map_exprs: noop_map_exprs,
+ new_id: noop_id,
+ new_span: noop_span
+ }
}
- pub impl ast_fold for ast_fold_fns {
+ impl ast_fold for ast_fold_fns {
/* naturally, a macro to write these would be nice */
- fn fold_crate(c: crate) -> crate {
- let (n, s) = (self.fold_crate)(c.node, c.span, self as ast_fold);
+ fn fold_crate(c: &crate) -> crate {
+ let (n, s) = (self.fold_crate)(&c.node, c.span, self as ast_fold);
spanned { node: n, span: (self.new_span)(s) }
}
- fn fold_view_item(&&x: @view_item) ->
+ fn fold_view_item(x: @view_item) ->
@view_item {
@ast::view_item {
node: (self.fold_view_item)(x.node, self as ast_fold),
// why is there no p.abort_if_errors here?
}
-pub fn parse_crate_from_source_str(name: ~str,
- source: @~str,
- cfg: ast::crate_cfg,
- sess: @mut ParseSess) -> @ast::crate {
- let p = new_parser_from_source_str(sess, cfg, name,
- codemap::FssNone, source);
- maybe_aborted(p.parse_crate_mod(cfg),p)
+pub fn parse_crate_from_source_str(
+ name: ~str,
+ source: @~str,
+ cfg: ast::crate_cfg,
+ sess: @mut ParseSess
+) -> @ast::crate {
+ let p = new_parser_from_source_str(
+ sess,
+ /*bad*/ copy cfg,
+ /*bad*/ copy name,
+ codemap::FssNone,
+ source
+ );
- let r = p.parse_crate_mod(/*bad*/ copy cfg);
- p.abort_if_errors();
- r
++ maybe_aborted(p.parse_crate_mod(/*bad*/ copy cfg),p)
}
-pub fn parse_expr_from_source_str(name: ~str,
- source: @~str,
- cfg: ast::crate_cfg,
- sess: @mut ParseSess) -> @ast::expr {
- let p = new_parser_from_source_str(sess, cfg, name,
- codemap::FssNone, source);
+pub fn parse_expr_from_source_str(
+ name: ~str,
+ source: @~str,
+ +cfg: ast::crate_cfg,
+ sess: @mut ParseSess
+) -> @ast::expr {
+ let p = new_parser_from_source_str(
+ sess,
+ cfg,
+ /*bad*/ copy name,
+ codemap::FssNone,
+ source
+ );
- let r = p.parse_expr();
- p.abort_if_errors();
- r
+ maybe_aborted(p.parse_expr(), p)
}
-pub fn parse_item_from_source_str(name: ~str,
- source: @~str,
- cfg: ast::crate_cfg,
- +attrs: ~[ast::attribute],
- sess: @mut ParseSess)
- -> Option<@ast::item> {
- let p = new_parser_from_source_str(sess, cfg, name,
- codemap::FssNone, source);
+pub fn parse_item_from_source_str(
+ name: ~str,
+ source: @~str,
+ +cfg: ast::crate_cfg,
+ +attrs: ~[ast::attribute],
+ sess: @mut ParseSess
+) -> Option<@ast::item> {
+ let p = new_parser_from_source_str(
+ sess,
+ cfg,
+ /*bad*/ copy name,
+ codemap::FssNone,
+ source
+ );
- let r = p.parse_item(attrs);
- p.abort_if_errors();
- r
+ maybe_aborted(p.parse_item(attrs),p)
}
-pub fn parse_stmt_from_source_str(name: ~str,
- source: @~str,
- cfg: ast::crate_cfg,
- +attrs: ~[ast::attribute],
- sess: @mut ParseSess) -> @ast::stmt {
- let p = new_parser_from_source_str(sess, cfg, name,
- codemap::FssNone, source);
+pub fn parse_stmt_from_source_str(
+ name: ~str,
+ source: @~str,
+ +cfg: ast::crate_cfg,
+ +attrs: ~[ast::attribute],
+ sess: @mut ParseSess
+) -> @ast::stmt {
+ let p = new_parser_from_source_str(
+ sess,
+ cfg,
+ /*bad*/ copy name,
+ codemap::FssNone,
+ source
+ );
- let r = p.parse_stmt(attrs);
- p.abort_if_errors();
- r
+ maybe_aborted(p.parse_stmt(attrs),p)
}
-pub fn parse_tts_from_source_str(name: ~str,
- source: @~str,
- cfg: ast::crate_cfg,
- sess: @mut ParseSess) -> ~[ast::token_tree] {
- let p = new_parser_from_source_str(sess, cfg, name,
- codemap::FssNone, source);
+pub fn parse_tts_from_source_str(
+ name: ~str,
+ source: @~str,
+ +cfg: ast::crate_cfg,
+ sess: @mut ParseSess
+) -> ~[ast::token_tree] {
+ let p = new_parser_from_source_str(
+ sess,
+ cfg,
+ /*bad*/ copy name,
+ codemap::FssNone,
+ source
+ );
*p.quote_depth += 1u;
- let r = p.parse_all_token_trees();
- p.abort_if_errors();
- r
+ maybe_aborted(p.parse_all_token_trees(),p)
}
-pub fn parse_from_source_str<T>(f: fn (p: Parser) -> T,
- name: ~str, ss: codemap::FileSubstr,
- source: @~str, cfg: ast::crate_cfg,
- sess: @mut ParseSess)
- -> T
-{
- let p = new_parser_from_source_str(sess, cfg, name, ss,
- source);
+pub fn parse_from_source_str<T>(
+ f: fn (Parser) -> T,
+ name: ~str, ss: codemap::FileSubstr,
+ source: @~str,
+ +cfg: ast::crate_cfg,
+ sess: @mut ParseSess
+) -> T {
+ let p = new_parser_from_source_str(
+ sess,
+ cfg,
+ /*bad*/ copy name,
+ /*bad*/ copy ss,
+ source
+ );
let r = f(p);
if !p.reader.is_eof() {
p.reader.fatal(~"expected end-of-string");
return rv;
}
-pub fn new_parser_from_source_str(sess: @mut ParseSess, cfg: ast::crate_cfg,
- +name: ~str, +ss: codemap::FileSubstr,
- source: @~str) -> Parser {
+pub fn new_parser_from_source_str(
+ sess: @mut ParseSess,
+ +cfg: ast::crate_cfg,
+ +name: ~str,
+ +ss: codemap::FileSubstr,
+ source: @~str
+) -> Parser {
let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
- let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
- filemap,
- sess.interner);
- return Parser(sess, cfg, srdr as reader);
+ let srdr = lexer::new_string_reader(
+ copy sess.span_diagnostic,
+ filemap,
+ sess.interner
+ );
+ Parser(sess, cfg, srdr as reader)
}
- // Read the entire source file, return a parser
- // that draws from that string
+ /// Read the entire source file, return a parser
+ /// that draws from that string
-pub fn new_parser_result_from_file(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
- path: &Path)
- -> Result<Parser, ~str> {
+pub fn new_parser_result_from_file(
+ sess: @mut ParseSess,
+ +cfg: ast::crate_cfg,
+ path: &Path
+) -> Result<Parser, ~str> {
match io::read_whole_file_str(path) {
- result::Ok(src) => {
+ Ok(src) => {
+ let filemap = sess.cm.new_filemap(path.to_str(), @src);
+ let srdr = lexer::new_string_reader(
+ copy sess.span_diagnostic,
+ filemap,
+ sess.interner
+ );
+ Ok(Parser(sess, cfg, srdr as reader))
- let filemap = sess.cm.new_filemap(path.to_str(), @src);
- let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
- filemap,
- sess.interner);
- Ok(Parser(sess, cfg, srdr as reader))
-
- }
- result::Err(e) => Err(e)
+ }
+ Err(e) => Err(e)
}
}
- /// Create a new parser for an entire crate, handling errors as appropriate
+ /// Create a new parser, handling errors as appropriate
/// if the file doesn't exist
-pub fn new_parser_from_file(sess: @mut ParseSess, cfg: ast::crate_cfg,
- path: &Path) -> Parser {
+pub fn new_parser_from_file(
+ sess: @mut ParseSess,
+ +cfg: ast::crate_cfg,
+ path: &Path
+) -> Parser {
match new_parser_result_from_file(sess, cfg, path) {
Ok(parser) => parser,
Err(e) => {
}
}
-pub fn new_parser_from_tts(sess: @mut ParseSess, cfg: ast::crate_cfg,
- tts: ~[ast::token_tree]) -> Parser {
- let trdr = lexer::new_tt_reader(copy sess.span_diagnostic, sess.interner,
- None, tts);
- return Parser(sess, cfg, trdr as reader)
+pub fn new_parser_from_tts(
+ sess: @mut ParseSess,
+ +cfg: ast::crate_cfg,
+ +tts: ~[ast::token_tree]
+) -> Parser {
+ let trdr = lexer::new_tt_reader(
+ copy sess.span_diagnostic,
+ sess.interner,
+ None,
+ tts
+ );
+ Parser(sess, cfg, trdr as reader)
}
+ // abort if necessary
+ pub fn maybe_aborted<T>(+result : T, p: Parser) -> T {
+ p.abort_if_errors();
+ result
+ }
+
+
#[cfg(test)]
mod test {
}
ty_rec(elems)
} else if *self.token == token::LBRACKET {
- self.expect(token::LBRACKET);
+ self.expect(&token::LBRACKET);
let mt = self.parse_mt();
+ if mt.mutbl == m_mutbl { // `m_const` too after snapshot
+ self.obsolete(*self.last_span, ObsoleteMutVector);
+ }
// Parse the `* 3` in `[ int * 3 ]`
let t = match self.maybe_parse_fixed_vstore_with_star() {
either::Left(self.parse_arg_general(true))
}
- fn parse_arg_or_capture_item() -> arg_or_capture_item {
- self.parse_capture_item_or(|p| p.parse_arg())
- }
-
fn parse_fn_block_arg() -> arg_or_capture_item {
- do self.parse_capture_item_or |p| {
- let m = p.parse_arg_mode();
- let is_mutbl = self.eat_keyword(&~"mut");
- let pat = p.parse_pat(false);
- let t = if p.eat(&token::COLON) {
- p.parse_ty(false)
- } else {
- @Ty {
- id: p.get_id(),
- node: ty_infer,
- span: mk_sp(p.span.lo, p.span.hi),
- }
- };
- either::Left(ast::arg {
- mode: m,
- is_mutbl: is_mutbl,
- ty: t,
- pat: pat,
- id: p.get_id()
- })
- }
+ let m = self.parse_arg_mode();
- let is_mutbl = self.eat_keyword(~"mut");
++ let is_mutbl = self.eat_keyword(&~"mut");
+ let pat = self.parse_pat(false);
- let t = if self.eat(token::COLON) {
++ let t = if self.eat(&token::COLON) {
+ self.parse_ty(false)
+ } else {
+ @Ty {
+ id: self.get_id(),
+ node: ty_infer,
+ span: mk_sp(self.span.lo, self.span.hi),
+ }
+ };
+ either::Left(ast::arg {
+ mode: m,
+ is_mutbl: is_mutbl,
+ ty: t,
+ pat: pat,
+ id: self.get_id()
+ })
}
fn maybe_parse_fixed_vstore_with_star() -> Option<uint> {
}
// Parses two variants (with the region/type params always optional):
- // impl<T> ~[T] : to_str { ... }
- // impl<T> to_str for ~[T] { ... }
- fn parse_item_impl() -> item_info {
+ // impl<T> Foo { ... }
+ // impl<T> ToStr for ~[T] { ... }
+ fn parse_item_impl(visibility: ast::visibility) -> item_info {
- fn wrap_path(p: Parser, pt: @path) -> @Ty {
+ fn wrap_path(p: &Parser, pt: @path) -> @Ty {
@Ty {
id: p.get_id(),
node: ty_path(pt, p.get_id()),
None
};
+ // Do not allow visibility to be specified in `impl...for...`. It is
+ // meaningless.
+ if opt_trait.is_some() && visibility != ast::inherited {
+ self.obsolete(*self.span, ObsoleteTraitImplVisibility);
+ }
+
let mut meths = ~[];
- if !self.eat(token::SEMI) {
- self.expect(token::LBRACE);
- while !self.eat(token::RBRACE) {
+ if !self.eat(&token::SEMI) {
+ self.expect(&token::LBRACE);
+ while !self.eat(&token::RBRACE) {
meths.push(self.parse_method());
}
}
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
visibility,
maybe_append(attrs, extra_attrs)));
- } else if items_allowed && self.eat_keyword(~"impl") {
+ } else if items_allowed && self.eat_keyword(&~"impl") {
// IMPL ITEM
- let (ident, item_, extra_attrs) = self.parse_item_impl();
+ let (ident, item_, extra_attrs) =
+ self.parse_item_impl(visibility);
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
visibility,
maybe_append(attrs, extra_attrs)));