// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_escape]; use abi; use abi::AbiSet; use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil}; use ast::{CallSugar, NoSugar, DoSugar}; use ast::{TyBareFn, TyClosure}; use ast::{RegionTyParamBound, TraitTyParamBound}; use ast::{provided, public, purity}; use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, Block}; use ast::{BlockCheckMode, UnBox}; use ast::{Crate, CrateConfig, Decl, DeclItem}; use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, enum_def, explicit_self}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock}; use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody}; use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc, ExprRepeat}; use ast::{ExprRet, ExprSelf, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprVstore, ExprVstoreMutBox}; use ast::{ExprVstoreSlice, ExprVstoreBox}; use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, extern_fn, Field, fn_decl}; use ast::{ExprVstoreUniq, Onceness, Once, Many}; use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod}; use ast::{Ident, impure_fn, inherited, item, item_, item_static}; use ast::{item_enum, item_fn, item_foreign_mod, item_impl}; use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_}; use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int, lit_char}; use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local}; use ast::{MutImmutable, MutMutable, mac_, mac_invoc_tt, matcher, match_nonterminal}; use ast::{match_seq, match_tok, method, mt, BiMul, Mutability}; use ast::{named_field, UnNeg, noreturn, UnNot, P, Pat, PatBox, PatEnum}; use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatUniq, PatWild, PatWildMulti, private}; use ast::{BiRem, required}; use ast::{ret_style, return_val, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, struct_def, struct_field}; use ast::{struct_variant_kind, BiSub}; use ast::StrStyle; use ast::{sty_box, sty_region, sty_static, sty_uniq, sty_value}; use ast::{token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok}; use ast::{tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot, ty_box}; use ast::{TypeField, ty_fixed_length_vec, ty_closure, ty_bare_fn, ty_typeof}; use ast::{ty_infer, TypeMethod}; use ast::{ty_nil, TyParam, TyParamBound, ty_path, ty_ptr, ty_rptr}; use ast::{ty_tup, ty_u32, ty_uniq, ty_vec, UnUniq}; use ast::{unnamed_field, UnsafeBlock, unsafe_fn, view_item}; use ast::{view_item_, view_item_extern_mod, view_item_use}; use ast::{view_path, view_path_glob, view_path_list, view_path_simple}; use ast::visibility; use ast; use ast_util::{as_prec, operator_prec}; use ast_util; use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; use codemap; use parse::attr::parser_attr; use parse::classify; use parse::common::{SeqSep, seq_sep_none}; use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; use parse::lexer::reader; use parse::lexer::TokenAndSpan; use parse::obsolete::*; use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; use parse::token::{is_ident_or_path}; use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; use parse::token::{token_to_binop}; use parse::token; use parse::{new_sub_parser_from_file, ParseSess}; use opt_vec; use opt_vec::OptVec; use std::hashmap::HashSet; use std::util; use std::vec; #[deriving(Eq)] enum restriction { UNRESTRICTED, RESTRICT_STMT_EXPR, RESTRICT_NO_BAR_OP, RESTRICT_NO_BAR_OR_DOUBLEBAR_OP, } type item_info = (Ident, item_, Option<~[Attribute]>); /// How to parse a path. There are four different kinds of paths, all of which /// are parsed somewhat differently. #[deriving(Eq)] pub enum PathParsingMode { /// A path with no type parameters; e.g. `foo::bar::Baz` NoTypesAllowed, /// A path with a lifetime and type parameters, with no double colons /// before the type parameters; e.g. `foo::bar<'self>::Baz` LifetimeAndTypesWithoutColons, /// A path with a lifetime and type parameters with double colons before /// the type parameters; e.g. `foo::bar::<'self>::Baz::` LifetimeAndTypesWithColons, /// A path with a lifetime and type parameters with bounds before the last /// set of type parameters only; e.g. `foo::bar<'self>::Baz:X+Y` This /// form does not use extra double colons. LifetimeAndTypesAndBounds, } /// A pair of a path segment and group of type parameter bounds. (See `ast.rs` /// for the definition of a path segment.) struct PathSegmentAndBoundSet { segment: ast::PathSegment, bound_set: Option>, } /// A path paired with optional type bounds. struct PathAndBounds { path: ast::Path, bounds: Option>, } pub enum item_or_view_item { // Indicates a failure to parse any kind of item. The attributes are // returned. iovi_none(~[Attribute]), iovi_item(@item), iovi_foreign_item(@foreign_item), iovi_view_item(view_item) } #[deriving(Eq)] enum view_item_parse_mode { VIEW_ITEMS_AND_ITEMS_ALLOWED, FOREIGN_ITEMS_ALLOWED, IMPORTS_AND_ITEMS_ALLOWED } /* The expr situation is not as complex as I thought it would be. The important thing is to make sure that lookahead doesn't balk at INTERPOLATED tokens */ macro_rules! maybe_whole_expr ( ($p:expr) => ( { // This horrible convolution is brought to you by // @mut, have a terrible day let ret = match *($p).token { INTERPOLATED(token::nt_expr(e)) => { Some(e) } INTERPOLATED(token::nt_path(ref pt)) => { Some($p.mk_expr( ($p).span.lo, ($p).span.hi, ExprPath(/* bad */ (**pt).clone()))) } _ => None }; match ret { Some(e) => { $p.bump(); return e; } None => () } } ) ) macro_rules! maybe_whole ( ($p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return x.clone() } _ => {} } } ); (no_clone $p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return x } _ => {} } } ); (deref $p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return (*x).clone() } _ => {} } } ); (Some $p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return Some(x.clone()), } _ => {} } } ); (iovi $p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return iovi_item(x.clone()) } _ => {} } } ); (pair_empty $p:expr, $constructor:ident) => ( { let __found__ = match *($p).token { INTERPOLATED(token::$constructor(_)) => { Some(($p).bump_and_get()) } _ => None }; match __found__ { Some(INTERPOLATED(token::$constructor(x))) => { return (~[], x) } _ => {} } } ) ) fn maybe_append(lhs: ~[Attribute], rhs: Option<~[Attribute]>) -> ~[Attribute] { match rhs { None => lhs, Some(ref attrs) => vec::append(lhs, (*attrs)) } } struct ParsedItemsAndViewItems { attrs_remaining: ~[Attribute], view_items: ~[view_item], items: ~[@item], foreign_items: ~[@foreign_item] } /* ident is handled by common.rs */ pub fn Parser(sess: @mut ParseSess, cfg: ast::CrateConfig, rdr: @mut reader) -> Parser { let tok0 = rdr.next_token(); let interner = get_ident_interner(); let span = tok0.sp; let placeholder = TokenAndSpan { tok: token::UNDERSCORE, sp: span, }; Parser { reader: rdr, interner: interner, sess: sess, cfg: cfg, token: @mut tok0.tok, span: @mut span, last_span: @mut span, last_token: @mut None, buffer: @mut ([ placeholder.clone(), placeholder.clone(), placeholder.clone(), placeholder.clone(), ]), buffer_start: @mut 0, buffer_end: @mut 0, tokens_consumed: @mut 0, restriction: @mut UNRESTRICTED, quote_depth: @mut 0, obsolete_set: @mut HashSet::new(), mod_path_stack: @mut ~[], open_braces: @mut ~[], non_copyable: util::NonCopyable } } // ooh, nasty mutable fields everywhere.... pub struct Parser { sess: @mut ParseSess, cfg: CrateConfig, // the current token: token: @mut token::Token, // the span of the current token: span: @mut Span, // the span of the prior token: last_span: @mut Span, // the previous token or None (only stashed sometimes). last_token: @mut Option<~token::Token>, buffer: @mut [TokenAndSpan, ..4], buffer_start: @mut int, buffer_end: @mut int, tokens_consumed: @mut uint, restriction: @mut restriction, quote_depth: @mut uint, // not (yet) related to the quasiquoter reader: @mut reader, interner: @token::ident_interner, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice obsolete_set: @mut HashSet, /// Used to determine the path to externally loaded source files mod_path_stack: @mut ~[@str], /// Stack of spans of open delimiters. Used for error message. open_braces: @mut ~[Span], /* do not copy the parser; its state is tied to outside state */ priv non_copyable: util::NonCopyable } fn is_plain_ident_or_underscore(t: &token::Token) -> bool { is_plain_ident(t) || *t == token::UNDERSCORE } impl Parser { // convert a token to a string using self's reader pub fn token_to_str(&self, token: &token::Token) -> ~str { token::to_str(get_ident_interner(), token) } // convert the current token to a string using self's reader pub fn this_token_to_str(&self) -> ~str { self.token_to_str(self.token) } pub fn unexpected_last(&self, t: &token::Token) -> ! { self.span_fatal( *self.last_span, format!( "unexpected token: `{}`", self.token_to_str(t) ) ); } pub fn unexpected(&self) -> ! { self.fatal( format!( "unexpected token: `{}`", self.this_token_to_str() ) ); } // expect and consume the token t. Signal an error if // the next token is not t. pub fn expect(&self, t: &token::Token) { if *self.token == *t { self.bump(); } else { self.fatal( format!( "expected `{}` but found `{}`", self.token_to_str(t), self.this_token_to_str() ) ) } } // Expect next token to be edible or inedible token. If edible, // then consume it; if inedible, then return without consuming // anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of(&self, edible: &[token::Token], inedible: &[token::Token]) { fn tokens_to_str(p:&Parser, tokens: &[token::Token]) -> ~str { let mut i = tokens.iter(); // This might be a sign we need a connect method on Iterator. let b = i.next().map_default(~"", |t| p.token_to_str(t)); i.fold(b, |b,a| b + "`, `" + p.token_to_str(a)) } if edible.contains(self.token) { self.bump(); } else if inedible.contains(self.token) { // leave it in the input } else { let expected = vec::append(edible.to_owned(), inedible); let expect = tokens_to_str(self, expected); let actual = self.this_token_to_str(); self.fatal( if expected.len() != 1 { format!("expected one of `{}` but found `{}`", expect, actual) } else { format!("expected `{}` but found `{}`", expect, actual) } ) } } // Check for erroneous `ident { }`; if matches, signal error and // recover (without consuming any expected input token). Returns // true if and only if input was consumed for recovery. pub fn check_for_erroneous_unit_struct_expecting(&self, expected: &[token::Token]) -> bool { if *self.token == token::LBRACE && expected.iter().all(|t| *t != token::LBRACE) && self.look_ahead(1, |t| *t == token::RBRACE) { // matched; signal non-fatal error and recover. self.span_err(*self.span, "Unit-like struct construction is written with no trailing `{ }`"); self.eat(&token::LBRACE); self.eat(&token::RBRACE); true } else { false } } // Commit to parsing a complete expression `e` expected to be // followed by some token from the set edible + inedible. Recover // from anticipated input errors, discarding erroneous characters. pub fn commit_expr(&self, e: @Expr, edible: &[token::Token], inedible: &[token::Token]) { debug!("commit_expr {:?}", e); match e.node { ExprPath(..) => { // might be unit-struct construction; check for recoverableinput error. let expected = vec::append(edible.to_owned(), inedible); self.check_for_erroneous_unit_struct_expecting(expected); } _ => {} } self.expect_one_of(edible, inedible) } pub fn commit_expr_expecting(&self, e: @Expr, edible: token::Token) { self.commit_expr(e, &[edible], &[]) } // Commit to parsing a complete statement `s`, which expects to be // followed by some token from the set edible + inedible. Check // for recoverable input errors, discarding erroneous characters. pub fn commit_stmt(&self, s: @Stmt, edible: &[token::Token], inedible: &[token::Token]) { debug!("commit_stmt {:?}", s); let _s = s; // unused, but future checks might want to inspect `s`. if self.last_token.as_ref().map_default(false, |t| is_ident_or_path(*t)) { let expected = vec::append(edible.to_owned(), inedible); self.check_for_erroneous_unit_struct_expecting(expected); } self.expect_one_of(edible, inedible) } pub fn commit_stmt_expecting(&self, s: @Stmt, edible: token::Token) { self.commit_stmt(s, &[edible], &[]) } pub fn parse_ident(&self) -> ast::Ident { self.check_strict_keywords(); self.check_reserved_keywords(); match *self.token { token::IDENT(i, _) => { self.bump(); i } token::INTERPOLATED(token::nt_ident(..)) => { self.bug("ident interpolation not converted to real token"); } _ => { self.fatal( format!( "expected ident, found `{}`", self.this_token_to_str() ) ); } } } pub fn parse_path_list_ident(&self) -> ast::path_list_ident { let lo = self.span.lo; let ident = self.parse_ident(); let hi = self.last_span.hi; spanned(lo, hi, ast::path_list_ident_ { name: ident, id: ast::DUMMY_NODE_ID }) } // consume token 'tok' if it exists. Returns true if the given // token was present, false otherwise. pub fn eat(&self, tok: &token::Token) -> bool { let is_present = *self.token == *tok; if is_present { self.bump() } is_present } pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { token::is_keyword(kw, self.token) } // if the next token is the given keyword, eat it and return // true. Otherwise, return false. pub fn eat_keyword(&self, kw: keywords::Keyword) -> bool { let is_kw = match *self.token { token::IDENT(sid, false) => kw.to_ident().name == sid.name, _ => false }; if is_kw { self.bump() } is_kw } // if the given word is not a keyword, signal an error. // if the next token is not the given word, signal an error. // otherwise, eat it. pub fn expect_keyword(&self, kw: keywords::Keyword) { if !self.eat_keyword(kw) { self.fatal( format!( "expected `{}`, found `{}`", self.id_to_str(kw.to_ident()).to_str(), self.this_token_to_str() ) ); } } // signal an error if the given string is a strict keyword pub fn check_strict_keywords(&self) { if token::is_strict_keyword(self.token) { self.span_err(*self.span, format!("found `{}` in ident position", self.this_token_to_str())); } } // signal an error if the current token is a reserved keyword pub fn check_reserved_keywords(&self) { if token::is_reserved_keyword(self.token) { self.fatal(format!("`{}` is a reserved keyword", self.this_token_to_str())); } } // Expect and consume a `|`. If `||` is seen, replace it with a single // `|` and continue. If a `|` is not seen, signal an error. fn expect_or(&self) { match *self.token { token::BINOP(token::OR) => self.bump(), token::OROR => { self.replace_token(token::BINOP(token::OR), self.span.lo + BytePos(1), self.span.hi) } _ => { let found_token = self.token_to_str(&token::BINOP(token::OR)); self.fatal(format!("expected `{}`, found `{}`", found_token, self.this_token_to_str())) } } } // Parse a sequence bracketed by `|` and `|`, stopping before the `|`. fn parse_seq_to_before_or(&self, sep: &token::Token, f: |&Parser| -> T) -> ~[T] { let mut first = true; let mut vector = ~[]; while *self.token != token::BINOP(token::OR) && *self.token != token::OROR { if first { first = false } else { self.expect(sep) } vector.push(f(self)) } vector } // expect and consume a GT. if a >> is seen, replace it // with a single > and continue. If a GT is not seen, // signal an error. pub fn expect_gt(&self) { match *self.token { token::GT => self.bump(), token::BINOP(token::SHR) => self.replace_token( token::GT, self.span.lo + BytePos(1), self.span.hi ), _ => self.fatal(format!("expected `{}`, found `{}`", self.token_to_str(&token::GT), self.this_token_to_str())) } } // parse a sequence bracketed by '<' and '>', stopping // before the '>'. pub fn parse_seq_to_before_gt( &self, sep: Option, f: |&Parser| -> T) -> OptVec { let mut first = true; let mut v = opt_vec::Empty; while *self.token != token::GT && *self.token != token::BINOP(token::SHR) { match sep { Some(ref t) => { if first { first = false; } else { self.expect(t); } } _ => () } v.push(f(self)); } return v; } pub fn parse_seq_to_gt( &self, sep: Option, f: |&Parser| -> T) -> OptVec { let v = self.parse_seq_to_before_gt(sep, f); self.expect_gt(); return v; } // parse a sequence, including the closing delimiter. The function // f must consume tokens until reaching the next separator or // closing bracket. pub fn parse_seq_to_end( &self, ket: &token::Token, sep: SeqSep, f: |&Parser| -> T) -> ~[T] { let val = self.parse_seq_to_before_end(ket, sep, f); self.bump(); val } // parse a sequence, not including the closing delimiter. The function // f must consume tokens until reaching the next separator or // closing bracket. pub fn parse_seq_to_before_end( &self, ket: &token::Token, sep: SeqSep, f: |&Parser| -> T) -> ~[T] { let mut first: bool = true; let mut v: ~[T] = ~[]; while *self.token != *ket { match sep.sep { Some(ref t) => { if first { first = false; } else { self.expect(t); } } _ => () } if sep.trailing_sep_allowed && *self.token == *ket { break; } v.push(f(self)); } return v; } // parse a sequence, including the closing delimiter. The function // f must consume tokens until reaching the next separator or // closing bracket. pub fn parse_unspanned_seq( &self, bra: &token::Token, ket: &token::Token, sep: SeqSep, f: |&Parser| -> T) -> ~[T] { self.expect(bra); let result = self.parse_seq_to_before_end(ket, sep, f); self.bump(); result } // NB: Do not use this function unless you actually plan to place the // spanned list in the AST. pub fn parse_seq( &self, bra: &token::Token, ket: &token::Token, sep: SeqSep, f: |&Parser| -> T) -> Spanned<~[T]> { let lo = self.span.lo; self.expect(bra); let result = self.parse_seq_to_before_end(ket, sep, f); let hi = self.span.hi; self.bump(); spanned(lo, hi, result) } // advance the parser by one token pub fn bump(&self) { *self.last_span = *self.span; // Stash token for error recovery (sometimes; clone is not necessarily cheap). *self.last_token = if is_ident_or_path(self.token) { Some(~(*self.token).clone()) } else { None }; let next = if *self.buffer_start == *self.buffer_end { self.reader.next_token() } else { // Avoid token copies with `util::replace`. let buffer_start = *self.buffer_start as uint; let next_index = (buffer_start + 1) & 3 as uint; *self.buffer_start = next_index as int; let placeholder = TokenAndSpan { tok: token::UNDERSCORE, sp: *self.span, }; util::replace(&mut self.buffer[buffer_start], placeholder) }; *self.span = next.sp; *self.token = next.tok; *self.tokens_consumed += 1u; } // Advance the parser by one token and return the bumped token. pub fn bump_and_get(&self) -> token::Token { let old_token = util::replace(self.token, token::UNDERSCORE); self.bump(); old_token } // EFFECT: replace the current token and span with the given one pub fn replace_token(&self, next: token::Token, lo: BytePos, hi: BytePos) { *self.token = next; *self.span = mk_sp(lo, hi); } pub fn buffer_length(&self) -> int { if *self.buffer_start <= *self.buffer_end { return *self.buffer_end - *self.buffer_start; } return (4 - *self.buffer_start) + *self.buffer_end; } pub fn look_ahead(&self, distance: uint, f: |&token::Token| -> R) -> R { let dist = distance as int; while self.buffer_length() < dist { self.buffer[*self.buffer_end] = self.reader.next_token(); *self.buffer_end = (*self.buffer_end + 1) & 3; } f(&self.buffer[(*self.buffer_start + dist - 1) & 3].tok) } pub fn fatal(&self, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(*self.span, m) } pub fn span_fatal(&self, sp: Span, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(sp, m) } pub fn span_note(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_note(sp, m) } pub fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(*self.span, m) } pub fn warn(&self, m: &str) { self.sess.span_diagnostic.span_warn(*self.span, m) } pub fn span_err(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } pub fn abort_if_errors(&self) { self.sess.span_diagnostic.handler().abort_if_errors(); } pub fn id_to_str(&self, id: Ident) -> @str { get_ident_interner().get(id.name) } // Is the current token one of the keywords that signals a bare function // type? pub fn token_is_bare_fn_keyword(&self) -> bool { if token::is_keyword(keywords::Fn, self.token) { return true } if token::is_keyword(keywords::Unsafe, self.token) || token::is_keyword(keywords::Once, self.token) { return self.look_ahead(1, |t| token::is_keyword(keywords::Fn, t)) } false } // Is the current token one of the keywords that signals a closure type? pub fn token_is_closure_keyword(&self) -> bool { token::is_keyword(keywords::Unsafe, self.token) || token::is_keyword(keywords::Once, self.token) } // Is the current token one of the keywords that signals an old-style // closure type (with explicit sigil)? pub fn token_is_old_style_closure_keyword(&self) -> bool { token::is_keyword(keywords::Unsafe, self.token) || token::is_keyword(keywords::Once, self.token) || token::is_keyword(keywords::Fn, self.token) } pub fn token_is_lifetime(&self, tok: &token::Token) -> bool { match *tok { token::LIFETIME(..) => true, _ => false, } } pub fn get_lifetime(&self, tok: &token::Token) -> ast::Ident { match *tok { token::LIFETIME(ref ident) => *ident, _ => self.bug("not a lifetime"), } } // parse a ty_bare_fun type: pub fn parse_ty_bare_fn(&self) -> ty_ { /* [extern "ABI"] [unsafe] fn <'lt> (S) -> T ^~~~^ ^~~~~~~^ ^~~~^ ^~^ ^ | | | | | | | | | Return type | | | Argument types | | Lifetimes | | | Purity ABI */ let opt_abis = self.parse_opt_abis(); let abis = opt_abis.unwrap_or(AbiSet::Rust()); let purity = self.parse_unsafety(); self.expect_keyword(keywords::Fn); let (decl, lifetimes) = self.parse_ty_fn_decl(true); return ty_bare_fn(@TyBareFn { abis: abis, purity: purity, lifetimes: lifetimes, decl: decl }); } // Parses a procedure type (`proc`). The initial `proc` keyword must // already have been parsed. pub fn parse_proc_type(&self) -> ty_ { let (decl, lifetimes) = self.parse_ty_fn_decl(false); ty_closure(@TyClosure { sigil: OwnedSigil, region: None, purity: impure_fn, onceness: Once, bounds: None, decl: decl, lifetimes: lifetimes, }) } // parse a ty_closure type pub fn parse_ty_closure(&self, opt_sigil: Option, mut region: Option) -> ty_ { /* (&|~|@) ['r] [unsafe] [once] fn [:Bounds] <'lt> (S) -> T ^~~~~~^ ^~~^ ^~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^ | | | | | | | | | | | | | | | Return type | | | | | | Argument types | | | | | Lifetimes | | | | Closure bounds | | | Once-ness (a.k.a., affine) | | Purity | Lifetime bound Allocation type */ // At this point, the allocation type and lifetime bound have been // parsed. let purity = self.parse_unsafety(); let onceness = parse_onceness(self); let (sigil, decl, lifetimes, bounds) = match opt_sigil { Some(sigil) => { // Old-style closure syntax (`fn(A)->B`). self.expect_keyword(keywords::Fn); let bounds = self.parse_optional_ty_param_bounds(); let (decl, lifetimes) = self.parse_ty_fn_decl(false); (sigil, decl, lifetimes, bounds) } None => { // New-style closure syntax (`<'lt>|A|:K -> B`). let lifetimes = if self.eat(&token::LT) { let lifetimes = self.parse_lifetimes(); self.expect_gt(); // Re-parse the region here. What a hack. if region.is_some() { self.span_err(*self.last_span, "lifetime declarations must precede \ the lifetime associated with a \ closure"); } region = self.parse_opt_lifetime(); lifetimes } else { opt_vec::Empty }; let inputs = if self.eat(&token::OROR) { ~[] } else { self.expect_or(); let inputs = self.parse_seq_to_before_or( &token::COMMA, |p| p.parse_arg_general(false)); self.expect_or(); inputs }; let bounds = self.parse_optional_ty_param_bounds(); let (return_style, output) = self.parse_ret_ty(); let decl = P(ast::fn_decl { inputs: inputs, output: output, cf: return_style, variadic: false }); (BorrowedSigil, decl, lifetimes, bounds) } }; return ty_closure(@TyClosure { sigil: sigil, region: region, purity: purity, onceness: onceness, bounds: bounds, decl: decl, lifetimes: lifetimes, }); fn parse_onceness(this: &Parser) -> Onceness { if this.eat_keyword(keywords::Once) { Once } else { Many } } } pub fn parse_unsafety(&self) -> purity { if self.eat_keyword(keywords::Unsafe) { return unsafe_fn; } else { return impure_fn; } } // parse a function type (following the 'fn') pub fn parse_ty_fn_decl(&self, allow_variadic: bool) -> (P, OptVec) { /* (fn) <'lt> (S) -> T ^~~~^ ^~^ ^ | | | | | Return type | Argument types Lifetimes */ let lifetimes = if self.eat(&token::LT) { let lifetimes = self.parse_lifetimes(); self.expect_gt(); lifetimes } else { opt_vec::Empty }; let (inputs, variadic) = self.parse_fn_args(false, allow_variadic); let (ret_style, ret_ty) = self.parse_ret_ty(); let decl = P(ast::fn_decl { inputs: inputs, output: ret_ty, cf: ret_style, variadic: variadic }); (decl, lifetimes) } // parse the methods in a trait declaration pub fn parse_trait_methods(&self) -> ~[trait_method] { self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, seq_sep_none(), |p| { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; let vis_span = *self.span; let vis = p.parse_visibility(); let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. let ident = p.parse_ident(); let generics = p.parse_generics(); let (explicit_self, d) = self.parse_fn_decl_with_self(|p| { // This is somewhat dubious; We don't want to allow argument // names to be left off if there is a definition... p.parse_arg_general(false) }); let hi = p.last_span.hi; debug!("parse_trait_methods(): trait method signature ends in \ `{}`", self.this_token_to_str()); match *p.token { token::SEMI => { p.bump(); debug!("parse_trait_methods(): parsing required method"); // NB: at the moment, visibility annotations on required // methods are ignored; this could change. if vis != ast::inherited { self.obsolete(vis_span, ObsoleteTraitFuncVisibility); } required(TypeMethod { ident: ident, attrs: attrs, purity: pur, decl: d, generics: generics, explicit_self: explicit_self, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi) }) } token::LBRACE => { debug!("parse_trait_methods(): parsing provided method"); let (inner_attrs, body) = p.parse_inner_attrs_and_block(); let attrs = vec::append(attrs, inner_attrs); provided(@ast::method { ident: ident, attrs: attrs, generics: generics, explicit_self: explicit_self, purity: pur, decl: d, body: body, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), self_id: ast::DUMMY_NODE_ID, vis: vis, }) } _ => { p.fatal( format!( "expected `;` or `\\{` but found `{}`", self.this_token_to_str() ) ); } } }) } // parse a possibly mutable type pub fn parse_mt(&self) -> mt { let mutbl = self.parse_mutability(); let t = self.parse_ty(false); mt { ty: t, mutbl: mutbl } } // parse [mut/const/imm] ID : TY // now used only by obsolete record syntax parser... pub fn parse_ty_field(&self) -> TypeField { let lo = self.span.lo; let mutbl = self.parse_mutability(); let id = self.parse_ident(); self.expect(&token::COLON); let ty = self.parse_ty(false); let hi = ty.span.hi; ast::TypeField { ident: id, mt: ast::mt { ty: ty, mutbl: mutbl }, span: mk_sp(lo, hi), } } // parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&self) -> (ret_style, P) { return if self.eat(&token::RARROW) { let lo = self.span.lo; if self.eat(&token::NOT) { ( noreturn, P(Ty { id: ast::DUMMY_NODE_ID, node: ty_bot, span: mk_sp(lo, self.last_span.hi) }) ) } else { (return_val, self.parse_ty(false)) } } else { let pos = self.span.lo; ( return_val, P(Ty { id: ast::DUMMY_NODE_ID, node: ty_nil, span: mk_sp(pos, pos), }) ) } } // parse a type. // Useless second parameter for compatibility with quasiquote macros. // Bleh! pub fn parse_ty(&self, _: bool) -> P { maybe_whole!(no_clone self, nt_ty); let lo = self.span.lo; let t = if *self.token == token::LPAREN { self.bump(); if *self.token == token::RPAREN { self.bump(); ty_nil } else { // (t) is a parenthesized ty // (t,) is the type of a tuple with only one field, // of type t let mut ts = ~[self.parse_ty(false)]; let mut one_tuple = false; while *self.token == token::COMMA { self.bump(); if *self.token != token::RPAREN { ts.push(self.parse_ty(false)); } else { one_tuple = true; } } if ts.len() == 1 && !one_tuple { self.expect(&token::RPAREN); return ts[0] } let t = ty_tup(ts); self.expect(&token::RPAREN); t } } else if *self.token == token::AT { // MANAGED POINTER self.bump(); self.parse_box_or_uniq_pointee(ManagedSigil, ty_box) } else if *self.token == token::TILDE { // OWNED POINTER self.bump(); self.parse_box_or_uniq_pointee(OwnedSigil, ty_uniq) } else if *self.token == token::BINOP(token::STAR) { // STAR POINTER (bare pointer?) self.bump(); ty_ptr(self.parse_mt()) } else if *self.token == token::LBRACKET { // VECTOR self.expect(&token::LBRACKET); let mt = mt { ty: self.parse_ty(false), mutbl: MutImmutable }; // Parse the `, ..e` in `[ int, ..e ]` // where `e` is a const expression let t = match self.maybe_parse_fixed_vstore() { None => ty_vec(mt), Some(suffix) => ty_fixed_length_vec(mt, suffix) }; self.expect(&token::RBRACKET); t } else if *self.token == token::BINOP(token::AND) { // BORROWED POINTER self.bump(); self.parse_borrowed_pointee() } else if self.is_keyword(keywords::Extern) || self.token_is_bare_fn_keyword() { // BARE FUNCTION self.parse_ty_bare_fn() } else if self.token_is_closure_keyword() || *self.token == token::BINOP(token::OR) || *self.token == token::OROR || *self.token == token::LT || self.token_is_lifetime(self.token) { // CLOSURE // // XXX(pcwalton): Eventually `token::LT` will not unambiguously // introduce a closure, once procs can have lifetime bounds. We // will need to refactor the grammar a little bit at that point. let lifetime = self.parse_opt_lifetime(); let result = self.parse_ty_closure(None, lifetime); result } else if self.eat_keyword(keywords::Typeof) { // TYPEOF // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::LPAREN); let e = self.parse_expr(); self.expect(&token::RPAREN); ty_typeof(e) } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type() } else if *self.token == token::MOD_SEP || is_ident_or_path(self.token) { // NAMED TYPE let PathAndBounds { path, bounds } = self.parse_path(LifetimeAndTypesAndBounds); ty_path(path, bounds, ast::DUMMY_NODE_ID) } else { self.fatal(format!("expected type, found token {:?}", *self.token)); }; let sp = mk_sp(lo, self.last_span.hi); P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp}) } // parse the type following a @ or a ~ pub fn parse_box_or_uniq_pointee(&self, sigil: ast::Sigil, ctor: |v: mt| -> ty_) -> ty_ { // ~'foo fn() or ~fn() are parsed directly as obsolete fn types: match *self.token { token::LIFETIME(..) => { let lifetime = self.parse_lifetime(); self.obsolete(*self.last_span, ObsoleteBoxedClosure); return self.parse_ty_closure(Some(sigil), Some(lifetime)); } token::IDENT(..) => { if self.token_is_old_style_closure_keyword() { self.obsolete(*self.last_span, ObsoleteBoxedClosure); return self.parse_ty_closure(Some(sigil), None); } } _ => {} } // other things are parsed as @/~ + a type. Note that constructs like // @[] and @str will be resolved during typeck to slices and so forth, // rather than boxed ptrs. But the special casing of str/vec is not // reflected in the AST type. if sigil == OwnedSigil { ctor(mt { ty: self.parse_ty(false), mutbl: MutImmutable }) } else { ctor(self.parse_mt()) } } pub fn parse_borrowed_pointee(&self) -> ty_ { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: let opt_lifetime = self.parse_opt_lifetime(); if self.token_is_old_style_closure_keyword() { self.obsolete(*self.last_span, ObsoleteClosureType); return self.parse_ty_closure(Some(BorrowedSigil), opt_lifetime); } let mt = self.parse_mt(); return ty_rptr(opt_lifetime, mt); } pub fn is_named_argument(&self) -> bool { let offset = match *self.token { token::BINOP(token::AND) => 1, token::ANDAND => 1, _ if token::is_keyword(keywords::Mut, self.token) => 1, _ => 0 }; debug!("parser is_named_argument offset:{}", offset); if offset == 0 { is_plain_ident_or_underscore(&*self.token) && self.look_ahead(1, |t| *t == token::COLON) } else { self.look_ahead(offset, |t| is_plain_ident_or_underscore(t)) && self.look_ahead(offset + 1, |t| *t == token::COLON) } } // This version of parse arg doesn't necessarily require // identifier names. pub fn parse_arg_general(&self, require_name: bool) -> arg { let pat = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{:?})", require_name); let pat = self.parse_pat(); self.expect(&token::COLON); pat } else { debug!("parse_arg_general ident_to_pat"); ast_util::ident_to_pat(ast::DUMMY_NODE_ID, *self.last_span, special_idents::invalid) }; let t = self.parse_ty(false); ast::arg { ty: t, pat: pat, id: ast::DUMMY_NODE_ID, } } // parse a single function argument pub fn parse_arg(&self) -> arg { self.parse_arg_general(true) } // parse an argument in a lambda header e.g. |arg, arg| pub fn parse_fn_block_arg(&self) -> arg { let pat = self.parse_pat(); let t = if self.eat(&token::COLON) { self.parse_ty(false) } else { P(Ty { id: ast::DUMMY_NODE_ID, node: ty_infer, span: mk_sp(self.span.lo, self.span.hi), }) }; ast::arg { ty: t, pat: pat, id: ast::DUMMY_NODE_ID } } pub fn maybe_parse_fixed_vstore(&self) -> Option<@ast::Expr> { if *self.token == token::COMMA && self.look_ahead(1, |t| *t == token::DOTDOT) { self.bump(); self.bump(); Some(self.parse_expr()) } else { None } } // matches token_lit = LIT_INT | ... pub fn lit_from_token(&self, tok: &token::Token) -> lit_ { match *tok { token::LIT_CHAR(i) => lit_char(i), token::LIT_INT(i, it) => lit_int(i, it), token::LIT_UINT(u, ut) => lit_uint(u, ut), token::LIT_INT_UNSUFFIXED(i) => lit_int_unsuffixed(i), token::LIT_FLOAT(s, ft) => lit_float(self.id_to_str(s), ft), token::LIT_FLOAT_UNSUFFIXED(s) => lit_float_unsuffixed(self.id_to_str(s)), token::LIT_STR(s) => lit_str(self.id_to_str(s), ast::CookedStr), token::LIT_STR_RAW(s, n) => lit_str(self.id_to_str(s), ast::RawStr(n)), token::LPAREN => { self.expect(&token::RPAREN); lit_nil }, _ => { self.unexpected_last(tok); } } } // matches lit = true | false | token_lit pub fn parse_lit(&self) -> lit { let lo = self.span.lo; let lit = if self.eat_keyword(keywords::True) { lit_bool(true) } else if self.eat_keyword(keywords::False) { lit_bool(false) } else { let token = self.bump_and_get(); let lit = self.lit_from_token(&token); lit }; codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) } } // matches '-' lit | lit pub fn parse_literal_maybe_minus(&self) -> @Expr { let minus_lo = self.span.lo; let minus_present = self.eat(&token::BINOP(token::MINUS)); let lo = self.span.lo; let literal = @self.parse_lit(); let hi = self.span.hi; let expr = self.mk_expr(lo, hi, ExprLit(literal)); if minus_present { let minus_hi = self.span.hi; self.mk_expr(minus_lo, minus_hi, self.mk_unary(UnNeg, expr)) } else { expr } } /// Parses a path and optional type parameter bounds, depending on the /// mode. The `mode` parameter determines whether lifetimes, types, and/or /// bounds are permitted and whether `::` must precede type parameter /// groups. pub fn parse_path(&self, mode: PathParsingMode) -> PathAndBounds { // Check for a whole path... let found = match *self.token { INTERPOLATED(token::nt_path(_)) => Some(self.bump_and_get()), _ => None, }; match found { Some(INTERPOLATED(token::nt_path(~path))) => { return PathAndBounds { path: path, bounds: None, } } _ => {} } let lo = self.span.lo; let is_global = self.eat(&token::MOD_SEP); // Parse any number of segments and bound sets. A segment is an // identifier followed by an optional lifetime and a set of types. // A bound set is a set of type parameter bounds. let mut segments = ~[]; loop { // First, parse an identifier. let identifier = self.parse_ident(); // Next, parse a colon and bounded type parameters, if applicable. let bound_set = if mode == LifetimeAndTypesAndBounds { self.parse_optional_ty_param_bounds() } else { None }; // Parse the '::' before type parameters if it's required. If // it is required and wasn't present, then we're done. if mode == LifetimeAndTypesWithColons && !self.eat(&token::MOD_SEP) { segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, bound_set: bound_set }); break } // Parse the `<` before the lifetime and types, if applicable. let (any_lifetime_or_types, lifetimes, types) = { if mode != NoTypesAllowed && self.eat(&token::LT) { let (lifetimes, types) = self.parse_generic_values_after_lt(); (true, lifetimes, opt_vec::from(types)) } else { (false, opt_vec::Empty, opt_vec::Empty) } }; // Assemble and push the result. segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, lifetimes: lifetimes, types: types, }, bound_set: bound_set }); // We're done if we don't see a '::', unless the mode required // a double colon to get here in the first place. if !(mode == LifetimeAndTypesWithColons && !any_lifetime_or_types) { if !self.eat(&token::MOD_SEP) { break } } } // Assemble the span. let span = mk_sp(lo, self.last_span.hi); // Assemble the path segments. let mut path_segments = ~[]; let mut bounds = None; let last_segment_index = segments.len() - 1; for (i, segment_and_bounds) in segments.move_iter().enumerate() { let PathSegmentAndBoundSet { segment: segment, bound_set: bound_set } = segment_and_bounds; path_segments.push(segment); if bound_set.is_some() { if i != last_segment_index { self.span_err(span, "type parameter bounds are allowed only \ before the last segment in a path") } bounds = bound_set } } // Assemble the result. let path_and_bounds = PathAndBounds { path: ast::Path { span: span, global: is_global, segments: path_segments, }, bounds: bounds, }; path_and_bounds } /// parses 0 or 1 lifetime pub fn parse_opt_lifetime(&self) -> Option { match *self.token { token::LIFETIME(..) => { Some(self.parse_lifetime()) } _ => { None } } } /// Parses a single lifetime // matches lifetime = LIFETIME pub fn parse_lifetime(&self) -> ast::Lifetime { match *self.token { token::LIFETIME(i) => { let span = *self.span; self.bump(); return ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, ident: i }; } _ => { self.fatal(format!("Expected a lifetime name")); } } } // matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) // actually, it matches the empty one too, but putting that in there // messes up the grammar.... pub fn parse_lifetimes(&self) -> OptVec { /*! * * Parses zero or more comma separated lifetimes. * Expects each lifetime to be followed by either * a comma or `>`. Used when parsing type parameter * lists, where we expect something like `<'a, 'b, T>`. */ let mut res = opt_vec::Empty; loop { match *self.token { token::LIFETIME(_) => { res.push(self.parse_lifetime()); } _ => { return res; } } match *self.token { token::COMMA => { self.bump();} token::GT => { return res; } token::BINOP(token::SHR) => { return res; } _ => { self.fatal(format!("expected `,` or `>` after lifetime name, got: {:?}", *self.token)); } } } } pub fn token_is_mutability(&self, tok: &token::Token) -> bool { token::is_keyword(keywords::Mut, tok) || token::is_keyword(keywords::Const, tok) } // parse mutability declaration (mut/const/imm) pub fn parse_mutability(&self) -> Mutability { if self.eat_keyword(keywords::Mut) { MutMutable } else if self.eat_keyword(keywords::Const) { self.obsolete(*self.last_span, ObsoleteConstPointer); MutImmutable } else { MutImmutable } } // parse ident COLON expr pub fn parse_field(&self) -> Field { let lo = self.span.lo; let i = self.parse_ident(); let hi = self.last_span.hi; self.expect(&token::COLON); let e = self.parse_expr(); ast::Field { ident: spanned(lo, hi, i), expr: e, span: mk_sp(lo, e.span.hi), } } pub fn mk_expr(&self, lo: BytePos, hi: BytePos, node: Expr_) -> @Expr { @Expr { id: ast::DUMMY_NODE_ID, node: node, span: mk_sp(lo, hi), } } pub fn mk_unary(&self, unop: ast::UnOp, expr: @Expr) -> ast::Expr_ { ExprUnary(ast::DUMMY_NODE_ID, unop, expr) } pub fn mk_binary(&self, binop: ast::BinOp, lhs: @Expr, rhs: @Expr) -> ast::Expr_ { ExprBinary(ast::DUMMY_NODE_ID, binop, lhs, rhs) } pub fn mk_call(&self, f: @Expr, args: ~[@Expr], sugar: CallSugar) -> ast::Expr_ { ExprCall(f, args, sugar) } pub fn mk_method_call(&self, rcvr: @Expr, ident: Ident, tps: ~[P], args: ~[@Expr], sugar: CallSugar) -> ast::Expr_ { ExprMethodCall(ast::DUMMY_NODE_ID, rcvr, ident, tps, args, sugar) } pub fn mk_index(&self, expr: @Expr, idx: @Expr) -> ast::Expr_ { ExprIndex(ast::DUMMY_NODE_ID, expr, idx) } pub fn mk_field(&self, expr: @Expr, ident: Ident, tys: ~[P]) -> ast::Expr_ { ExprField(expr, ident, tys) } pub fn mk_assign_op(&self, binop: ast::BinOp, lhs: @Expr, rhs: @Expr) -> ast::Expr_ { ExprAssignOp(ast::DUMMY_NODE_ID, binop, lhs, rhs) } pub fn mk_mac_expr(&self, lo: BytePos, hi: BytePos, m: mac_) -> @Expr { @Expr { id: ast::DUMMY_NODE_ID, node: ExprMac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), span: mk_sp(lo, hi), } } pub fn mk_lit_u32(&self, i: u32) -> @Expr { let span = self.span; let lv_lit = @codemap::Spanned { node: lit_uint(i as u64, ty_u32), span: *span }; @Expr { id: ast::DUMMY_NODE_ID, node: ExprLit(lv_lit), span: *span, } } // at the bottom (top?) of the precedence hierarchy, // parse things like parenthesized exprs, // macros, return, etc. pub fn parse_bottom_expr(&self) -> @Expr { maybe_whole_expr!(self); let lo = self.span.lo; let mut hi = self.span.hi; let ex: Expr_; if *self.token == token::LPAREN { self.bump(); // (e) is parenthesized e // (e,) is a tuple with only one field, e let mut trailing_comma = false; if *self.token == token::RPAREN { hi = self.span.hi; self.bump(); let lit = @spanned(lo, hi, lit_nil); return self.mk_expr(lo, hi, ExprLit(lit)); } let mut es = ~[self.parse_expr()]; self.commit_expr(*es.last(), &[], &[token::COMMA, token::RPAREN]); while *self.token == token::COMMA { self.bump(); if *self.token != token::RPAREN { es.push(self.parse_expr()); self.commit_expr(*es.last(), &[], &[token::COMMA, token::RPAREN]); } else { trailing_comma = true; } } hi = self.span.hi; self.commit_expr_expecting(*es.last(), token::RPAREN); return if es.len() == 1 && !trailing_comma { self.mk_expr(lo, self.span.hi, ExprParen(es[0])) } else { self.mk_expr(lo, hi, ExprTup(es)) } } else if *self.token == token::LBRACE { self.bump(); let blk = self.parse_block_tail(lo, DefaultBlock); return self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); } else if token::is_bar(&*self.token) { return self.parse_lambda_expr(); } else if self.eat_keyword(keywords::Proc) { let decl = self.parse_proc_decl(); let body = self.parse_expr(); let fakeblock = P(ast::Block { view_items: ~[], stmts: ~[], expr: Some(body), id: ast::DUMMY_NODE_ID, rules: DefaultBlock, span: body.span, }); return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock)); } else if self.eat_keyword(keywords::Self) { ex = ExprSelf; hi = self.span.hi; } else if self.eat_keyword(keywords::If) { return self.parse_if_expr(); } else if self.eat_keyword(keywords::For) { return self.parse_for_expr(None); } else if self.eat_keyword(keywords::Do) { return self.parse_sugary_call_expr(lo, ~"do", DoSugar, ExprDoBody); } else if self.eat_keyword(keywords::While) { return self.parse_while_expr(); } else if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); self.bump(); self.expect(&token::COLON); if self.eat_keyword(keywords::For) { return self.parse_for_expr(Some(lifetime)) } else if self.eat_keyword(keywords::Loop) { return self.parse_loop_expr(Some(lifetime)) } else { self.fatal("expected `for` or `loop` after a label") } } else if self.eat_keyword(keywords::Loop) { return self.parse_loop_expr(None); } else if self.eat_keyword(keywords::Continue) { let lo = self.span.lo; let ex = if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); self.bump(); ExprAgain(Some(lifetime.name)) } else { ExprAgain(None) }; let hi = self.span.hi; return self.mk_expr(lo, hi, ex); } else if self.eat_keyword(keywords::Match) { return self.parse_match_expr(); } else if self.eat_keyword(keywords::Unsafe) { return self.parse_block_expr(lo, UnsafeBlock(ast::UserProvided)); } else if *self.token == token::LBRACKET { self.bump(); let mutbl = MutImmutable; if *self.token == token::RBRACKET { // Empty vector. self.bump(); ex = ExprVec(~[], mutbl); } else { // Nonempty vector. let first_expr = self.parse_expr(); if *self.token == token::COMMA && self.look_ahead(1, |t| *t == token::DOTDOT) { // Repeating vector syntax: [ 0, ..512 ] self.bump(); self.bump(); let count = self.parse_expr(); self.expect(&token::RBRACKET); ex = ExprRepeat(first_expr, count, mutbl); } else if *self.token == token::COMMA { // Vector with two or more elements. self.bump(); let remaining_exprs = self.parse_seq_to_end( &token::RBRACKET, seq_sep_trailing_allowed(token::COMMA), |p| p.parse_expr() ); ex = ExprVec(~[first_expr] + remaining_exprs, mutbl); } else { // Vector with one element. self.expect(&token::RBRACKET); ex = ExprVec(~[first_expr], mutbl); } } hi = self.last_span.hi; } else if self.eat_keyword(keywords::__LogLevel) { // LOG LEVEL expression self.expect(&token::LPAREN); ex = ExprLogLevel; hi = self.span.hi; self.expect(&token::RPAREN); } else if self.eat_keyword(keywords::Return) { // RETURN expression if can_begin_expr(&*self.token) { let e = self.parse_expr(); hi = e.span.hi; ex = ExprRet(Some(e)); } else { ex = ExprRet(None); } } else if self.eat_keyword(keywords::Break) { // BREAK expression if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); self.bump(); ex = ExprBreak(Some(lifetime.name)); } else { ex = ExprBreak(None); } hi = self.span.hi; } else if *self.token == token::MOD_SEP || is_ident(&*self.token) && !self.is_keyword(keywords::True) && !self.is_keyword(keywords::False) { let pth = self.parse_path(LifetimeAndTypesWithColons).path; // `!`, as an operator, is prefix, so we know this isn't that if *self.token == token::NOT { // MACRO INVOCATION expression self.bump(); match *self.token { token::LPAREN | token::LBRACE => {} _ => self.fatal("expected open delimiter") }; let ket = token::flip_delimiter(&*self.token); self.bump(); let tts = self.parse_seq_to_end(&ket, seq_sep_none(), |p| p.parse_token_tree()); let hi = self.span.hi; return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT)); } else if *self.token == token::LBRACE { // This might be a struct literal. if self.looking_at_struct_literal() { // It's a struct literal. self.bump(); let mut fields = ~[]; let mut base = None; fields.push(self.parse_field()); while *self.token != token::RBRACE { self.commit_expr(fields.last().expr, &[token::COMMA], &[token::RBRACE]); if self.eat(&token::DOTDOT) { base = Some(self.parse_expr()); break; } if *self.token == token::RBRACE { // Accept an optional trailing comma. break; } fields.push(self.parse_field()); } hi = pth.span.hi; self.commit_expr_expecting(fields.last().expr, token::RBRACE); ex = ExprStruct(pth, fields, base); return self.mk_expr(lo, hi, ex); } } hi = pth.span.hi; ex = ExprPath(pth); } else { // other literal expression let lit = self.parse_lit(); hi = lit.span.hi; ex = ExprLit(@lit); } return self.mk_expr(lo, hi, ex); } // parse a block or unsafe block pub fn parse_block_expr(&self, lo: BytePos, blk_mode: BlockCheckMode) -> @Expr { self.expect(&token::LBRACE); let blk = self.parse_block_tail(lo, blk_mode); return self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); } // parse a.b or a(13) or a[4] or just a pub fn parse_dot_or_call_expr(&self) -> @Expr { let b = self.parse_bottom_expr(); self.parse_dot_or_call_expr_with(b) } pub fn parse_dot_or_call_expr_with(&self, e0: @Expr) -> @Expr { let mut e = e0; let lo = e.span.lo; let mut hi; loop { // expr.f if self.eat(&token::DOT) { match *self.token { token::IDENT(i, _) => { hi = self.span.hi; self.bump(); let (_, tys) = if self.eat(&token::MOD_SEP) { self.expect(&token::LT); self.parse_generic_values_after_lt() } else { (opt_vec::Empty, ~[]) }; // expr.f() method call match *self.token { token::LPAREN => { let es = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_expr() ); hi = self.span.hi; let nd = self.mk_method_call(e, i, tys, es, NoSugar); e = self.mk_expr(lo, hi, nd); } _ => { e = self.mk_expr(lo, hi, self.mk_field(e, i, tys)); } } } _ => self.unexpected() } continue; } if self.expr_is_complete(e) { break; } match *self.token { // expr(...) token::LPAREN => { let es = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_expr() ); hi = self.span.hi; let nd = self.mk_call(e, es, NoSugar); e = self.mk_expr(lo, hi, nd); } // expr[...] token::LBRACKET => { self.bump(); let ix = self.parse_expr(); hi = ix.span.hi; self.commit_expr_expecting(ix, token::RBRACKET); e = self.mk_expr(lo, hi, self.mk_index(e, ix)); } _ => return e } } return e; } // parse an optional separator followed by a kleene-style // repetition token (+ or *). pub fn parse_sep_and_zerok(&self) -> (Option, bool) { fn parse_zerok(parser: &Parser) -> Option { match *parser.token { token::BINOP(token::STAR) | token::BINOP(token::PLUS) => { let zerok = *parser.token == token::BINOP(token::STAR); parser.bump(); Some(zerok) }, _ => None } }; match parse_zerok(self) { Some(zerok) => return (None, zerok), None => {} } let separator = self.bump_and_get(); match parse_zerok(self) { Some(zerok) => (Some(separator), zerok), None => self.fatal("expected `*` or `+`") } } // parse a single token tree from the input. pub fn parse_token_tree(&self) -> token_tree { // FIXME #6994: currently, this is too eager. It // parses token trees but also identifies tt_seq's // and tt_nonterminals; it's too early to know yet // whether something will be a nonterminal or a seq // yet. maybe_whole!(deref self, nt_tt); // this is the fall-through for the 'match' below. // invariants: the current token is not a left-delimiter, // not an EOF, and not the desired right-delimiter (if // it were, parse_seq_to_before_end would have prevented // reaching this point. fn parse_non_delim_tt_tok(p: &Parser) -> token_tree { maybe_whole!(deref p, nt_tt); match *p.token { token::RPAREN | token::RBRACE | token::RBRACKET => { // This is a conservative error: only report the last unclosed delimiter. The // previous unclosed delimiters could actually be closed! The parser just hasn't // gotten to them yet. p.open_braces.last_opt().map(|sp| p.span_note(*sp, "unclosed delimiter")); p.fatal(format!("incorrect close delimiter: `{}`", p.this_token_to_str())); }, /* we ought to allow different depths of unquotation */ token::DOLLAR if *p.quote_depth > 0u => { p.bump(); let sp = *p.span; if *p.token == token::LPAREN { let seq = p.parse_seq( &token::LPAREN, &token::RPAREN, seq_sep_none(), |p| p.parse_token_tree() ); let (s, z) = p.parse_sep_and_zerok(); let seq = match seq { Spanned { node, .. } => node, }; tt_seq( mk_sp(sp.lo, p.span.hi), @seq, s, z ) } else { tt_nonterminal(sp, p.parse_ident()) } } _ => { parse_any_tt_tok(p) } } } // turn the next token into a tt_tok: fn parse_any_tt_tok(p: &Parser) -> token_tree{ tt_tok(*p.span, p.bump_and_get()) } match *self.token { token::EOF => { for sp in self.open_braces.iter() { self.span_note(*sp, "Did you mean to close this delimiter?"); } // There shouldn't really be a span, but it's easier for the test runner // if we give it one self.fatal("This file contains an un-closed delimiter "); } token::LPAREN | token::LBRACE | token::LBRACKET => { let close_delim = token::flip_delimiter(&*self.token); // Parse the open delimiter. (*self.open_braces).push(*self.span); let mut result = ~[parse_any_tt_tok(self)]; let trees = self.parse_seq_to_before_end(&close_delim, seq_sep_none(), |p| p.parse_token_tree()); result.push_all_move(trees); // Parse the close delimiter. result.push(parse_any_tt_tok(self)); self.open_braces.pop(); tt_delim(@result) } _ => parse_non_delim_tt_tok(self) } } // parse a stream of tokens into a list of token_trees, // up to EOF. pub fn parse_all_token_trees(&self) -> ~[token_tree] { let mut tts = ~[]; while *self.token != token::EOF { tts.push(self.parse_token_tree()); } tts } pub fn parse_matchers(&self) -> ~[matcher] { // unification of matchers and token_trees would vastly improve // the interpolation of matchers maybe_whole!(self, nt_matchers); let name_idx = @mut 0u; match *self.token { token::LBRACE | token::LPAREN | token::LBRACKET => { let other_delimiter = token::flip_delimiter(self.token); self.bump(); self.parse_matcher_subseq_upto(name_idx, &other_delimiter) } _ => self.fatal("expected open delimiter") } } // This goofy function is necessary to correctly match parens in matchers. // Otherwise, `$( ( )` would be a valid matcher, and `$( () )` would be // invalid. It's similar to common::parse_seq. pub fn parse_matcher_subseq_upto(&self, name_idx: @mut uint, ket: &token::Token) -> ~[matcher] { let mut ret_val = ~[]; let mut lparens = 0u; while *self.token != *ket || lparens > 0u { if *self.token == token::LPAREN { lparens += 1u; } if *self.token == token::RPAREN { lparens -= 1u; } ret_val.push(self.parse_matcher(name_idx)); } self.bump(); return ret_val; } pub fn parse_matcher(&self, name_idx: @mut uint) -> matcher { let lo = self.span.lo; let m = if *self.token == token::DOLLAR { self.bump(); if *self.token == token::LPAREN { let name_idx_lo = *name_idx; self.bump(); let ms = self.parse_matcher_subseq_upto(name_idx, &token::RPAREN); if ms.len() == 0u { self.fatal("repetition body must be nonempty"); } let (sep, zerok) = self.parse_sep_and_zerok(); match_seq(ms, sep, zerok, name_idx_lo, *name_idx) } else { let bound_to = self.parse_ident(); self.expect(&token::COLON); let nt_name = self.parse_ident(); let m = match_nonterminal(bound_to, nt_name, *name_idx); *name_idx += 1u; m } } else { match_tok(self.bump_and_get()) }; return spanned(lo, self.span.hi, m); } // parse a prefix-operator expr pub fn parse_prefix_expr(&self) -> @Expr { let lo = self.span.lo; let hi; let ex; match *self.token { token::NOT => { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; ex = self.mk_unary(UnNot, e); } token::BINOP(b) => { match b { token::MINUS => { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; ex = self.mk_unary(UnNeg, e); } token::STAR => { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; ex = self.mk_unary(UnDeref, e); } token::AND => { self.bump(); let _lt = self.parse_opt_lifetime(); let m = self.parse_mutability(); let e = self.parse_prefix_expr(); hi = e.span.hi; // HACK: turn &[...] into a &-evec ex = match e.node { ExprVec(..) | ExprLit(@codemap::Spanned { node: lit_str(..), span: _ }) if m == MutImmutable => { ExprVstore(e, ExprVstoreSlice) } ExprVec(..) if m == MutMutable => { ExprVstore(e, ExprVstoreMutSlice) } _ => ExprAddrOf(m, e) }; } _ => return self.parse_dot_or_call_expr() } } token::AT => { self.bump(); let m = self.parse_mutability(); let e = self.parse_prefix_expr(); hi = e.span.hi; // HACK: turn @[...] into a @-evec ex = match e.node { ExprVec(..) | ExprRepeat(..) if m == MutMutable => ExprVstore(e, ExprVstoreMutBox), ExprVec(..) | ExprLit(@codemap::Spanned { node: lit_str(..), span: _}) | ExprRepeat(..) if m == MutImmutable => ExprVstore(e, ExprVstoreBox), _ => self.mk_unary(UnBox(m), e) }; } token::TILDE => { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; // HACK: turn ~[...] into a ~-evec ex = match e.node { ExprVec(..) | ExprLit(@codemap::Spanned { node: lit_str(..), span: _}) | ExprRepeat(..) => ExprVstore(e, ExprVstoreUniq), _ => self.mk_unary(UnUniq, e) }; } _ => return self.parse_dot_or_call_expr() } return self.mk_expr(lo, hi, ex); } // parse an expression of binops pub fn parse_binops(&self) -> @Expr { self.parse_more_binops(self.parse_prefix_expr(), 0) } // parse an expression of binops of at least min_prec precedence pub fn parse_more_binops(&self, lhs: @Expr, min_prec: uint) -> @Expr { if self.expr_is_complete(lhs) { return lhs; } // Prevent dynamic borrow errors later on by limiting the // scope of the borrows. { let token: &token::Token = self.token; let restriction: &restriction = self.restriction; match (token, restriction) { (&token::BINOP(token::OR), &RESTRICT_NO_BAR_OP) => return lhs, (&token::BINOP(token::OR), &RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs, (&token::OROR, &RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs, _ => { } } } let cur_opt = token_to_binop(self.token); match cur_opt { Some(cur_op) => { let cur_prec = operator_prec(cur_op); if cur_prec > min_prec { self.bump(); let expr = self.parse_prefix_expr(); let rhs = self.parse_more_binops(expr, cur_prec); let bin = self.mk_expr(lhs.span.lo, rhs.span.hi, self.mk_binary(cur_op, lhs, rhs)); self.parse_more_binops(bin, min_prec) } else { lhs } } None => { if as_prec > min_prec && self.eat_keyword(keywords::As) { let rhs = self.parse_ty(true); let _as = self.mk_expr(lhs.span.lo, rhs.span.hi, ExprCast(lhs, rhs)); self.parse_more_binops(_as, min_prec) } else { lhs } } } } // parse an assignment expression.... // actually, this seems to be the main entry point for // parsing an arbitrary expression. pub fn parse_assign_expr(&self) -> @Expr { let lo = self.span.lo; let lhs = self.parse_binops(); match *self.token { token::EQ => { self.bump(); let rhs = self.parse_expr(); self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs)) } token::BINOPEQ(op) => { self.bump(); let rhs = self.parse_expr(); let aop = match op { token::PLUS => BiAdd, token::MINUS => BiSub, token::STAR => BiMul, token::SLASH => BiDiv, token::PERCENT => BiRem, token::CARET => BiBitXor, token::AND => BiBitAnd, token::OR => BiBitOr, token::SHL => BiShl, token::SHR => BiShr }; self.mk_expr(lo, rhs.span.hi, self.mk_assign_op(aop, lhs, rhs)) } token::DARROW => { self.obsolete(*self.span, ObsoleteSwap); self.bump(); // Ignore what we get, this is an error anyway self.parse_expr(); self.mk_expr(lo, self.span.hi, ExprBreak(None)) } _ => { lhs } } } // parse an 'if' expression ('if' token already eaten) pub fn parse_if_expr(&self) -> @Expr { let lo = self.last_span.lo; let cond = self.parse_expr(); let thn = self.parse_block(); let mut els: Option<@Expr> = None; let mut hi = thn.span.hi; if self.eat_keyword(keywords::Else) { let elexpr = self.parse_else_expr(); els = Some(elexpr); hi = elexpr.span.hi; } self.mk_expr(lo, hi, ExprIf(cond, thn, els)) } // `|args| { ... }` or `{ ...}` like in `do` expressions pub fn parse_lambda_block_expr(&self) -> @Expr { self.parse_lambda_expr_( || { match *self.token { token::BINOP(token::OR) | token::OROR => { self.parse_fn_block_decl() } _ => { // No argument list - `do foo {` P(ast::fn_decl { inputs: ~[], output: P(Ty { id: ast::DUMMY_NODE_ID, node: ty_infer, span: *self.span }), cf: return_val, variadic: false }) } } }, || { let blk = self.parse_block(); self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)) }) } // `|args| expr` pub fn parse_lambda_expr(&self) -> @Expr { self.parse_lambda_expr_(|| self.parse_fn_block_decl(), || self.parse_expr()) } // parse something of the form |args| expr // this is used both in parsing a lambda expr // and in parsing a block expr as e.g. in for... pub fn parse_lambda_expr_(&self, parse_decl: || -> P, parse_body: || -> @Expr) -> @Expr { let lo = self.last_span.lo; let decl = parse_decl(); let body = parse_body(); let fakeblock = P(ast::Block { view_items: ~[], stmts: ~[], expr: Some(body), id: ast::DUMMY_NODE_ID, rules: DefaultBlock, span: body.span, }); return self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock)); } pub fn parse_else_expr(&self) -> @Expr { if self.eat_keyword(keywords::If) { return self.parse_if_expr(); } else { let blk = self.parse_block(); return self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); } } // parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&self, opt_ident: Option) -> @Expr { // Parse: `for in ` let lo = self.last_span.lo; let pat = self.parse_pat(); self.expect_keyword(keywords::In); let expr = self.parse_expr(); let loop_block = self.parse_block(); let hi = self.span.hi; self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)) } // parse a 'do'. // the 'do' expression parses as a call, but looks like // a function call followed by a closure expression. pub fn parse_sugary_call_expr(&self, lo: BytePos, keyword: ~str, sugar: CallSugar, ctor: |v: @Expr| -> Expr_) -> @Expr { // Parse the callee `foo` in // do foo || { // do foo.bar || { // etc, or the portion of the call expression before the lambda in // do foo() || { // or // do foo.bar(a) || { // Turn on the restriction to stop at | or || so we can parse // them as the lambda arguments let e = self.parse_expr_res(RESTRICT_NO_BAR_OR_DOUBLEBAR_OP); match e.node { ExprCall(f, ref args, NoSugar) => { let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); let args = vec::append((*args).clone(), [last_arg]); self.mk_expr(lo, block.span.hi, ExprCall(f, args, sugar)) } ExprMethodCall(_, f, i, ref tps, ref args, NoSugar) => { let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); let args = vec::append((*args).clone(), [last_arg]); self.mk_expr(lo, block.span.hi, self.mk_method_call(f, i, (*tps).clone(), args, sugar)) } ExprField(f, i, ref tps) => { let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); self.mk_expr(lo, block.span.hi, self.mk_method_call(f, i, (*tps).clone(), ~[last_arg], sugar)) } ExprPath(..) | ExprCall(..) | ExprMethodCall(..) | ExprParen(..) => { let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); self.mk_expr( lo, last_arg.span.hi, self.mk_call(e, ~[last_arg], sugar)) } _ => { // There may be other types of expressions that can // represent the callee in `do` expressions // but they aren't represented by tests debug!("sugary call on {:?}", e.node); self.span_fatal( e.span, format!("`{}` must be followed by a block call", keyword)); } } } pub fn parse_while_expr(&self) -> @Expr { let lo = self.last_span.lo; let cond = self.parse_expr(); let body = self.parse_block(); let hi = body.span.hi; return self.mk_expr(lo, hi, ExprWhile(cond, body)); } pub fn parse_loop_expr(&self, opt_ident: Option) -> @Expr { // loop headers look like 'loop {' or 'loop unsafe {' let is_loop_header = *self.token == token::LBRACE || (is_ident(&*self.token) && self.look_ahead(1, |t| *t == token::LBRACE)); if is_loop_header { // This is a loop body let lo = self.last_span.lo; let body = self.parse_block(); let hi = body.span.hi; return self.mk_expr(lo, hi, ExprLoop(body, opt_ident)); } else { // This is an obsolete 'continue' expression if opt_ident.is_some() { self.span_err(*self.last_span, "a label may not be used with a `loop` expression"); } self.obsolete(*self.last_span, ObsoleteLoopAsContinue); let lo = self.span.lo; let ex = if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); self.bump(); ExprAgain(Some(lifetime.name)) } else { ExprAgain(None) }; let hi = self.span.hi; return self.mk_expr(lo, hi, ex); } } // For distingishing between struct literals and blocks fn looking_at_struct_literal(&self) -> bool { *self.token == token::LBRACE && (self.look_ahead(1, |t| token::is_plain_ident(t)) && self.look_ahead(2, |t| *t == token::COLON)) } fn parse_match_expr(&self) -> @Expr { let lo = self.last_span.lo; let discriminant = self.parse_expr(); self.commit_expr_expecting(discriminant, token::LBRACE); let mut arms: ~[Arm] = ~[]; while *self.token != token::RBRACE { let pats = self.parse_pats(); let mut guard = None; if self.eat_keyword(keywords::If) { guard = Some(self.parse_expr()); } self.expect(&token::FAT_ARROW); let expr = self.parse_expr_res(RESTRICT_STMT_EXPR); let require_comma = !classify::expr_is_simple_block(expr) && *self.token != token::RBRACE; if require_comma { self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]); } else { self.eat(&token::COMMA); } let blk = P(ast::Block { view_items: ~[], stmts: ~[], expr: Some(expr), id: ast::DUMMY_NODE_ID, rules: DefaultBlock, span: expr.span, }); arms.push(ast::Arm { pats: pats, guard: guard, body: blk }); } let hi = self.span.hi; self.bump(); return self.mk_expr(lo, hi, ExprMatch(discriminant, arms)); } // parse an expression pub fn parse_expr(&self) -> @Expr { return self.parse_expr_res(UNRESTRICTED); } // parse an expression, subject to the given restriction fn parse_expr_res(&self, r: restriction) -> @Expr { let old = *self.restriction; *self.restriction = r; let e = self.parse_assign_expr(); *self.restriction = old; return e; } // parse the RHS of a local variable declaration (e.g. '= 14;') fn parse_initializer(&self) -> Option<@Expr> { if *self.token == token::EQ { self.bump(); Some(self.parse_expr()) } else { None } } // parse patterns, separated by '|' s fn parse_pats(&self) -> ~[@Pat] { let mut pats = ~[]; loop { pats.push(self.parse_pat()); if *self.token == token::BINOP(token::OR) { self.bump(); } else { return pats; } }; } fn parse_pat_vec_elements( &self, ) -> (~[@Pat], Option<@Pat>, ~[@Pat]) { let mut before = ~[]; let mut slice = None; let mut after = ~[]; let mut first = true; let mut before_slice = true; while *self.token != token::RBRACKET { if first { first = false; } else { self.expect(&token::COMMA); } let mut is_slice = false; if before_slice { if *self.token == token::DOTDOT { self.bump(); is_slice = true; before_slice = false; } } if is_slice { if *self.token == token::COMMA || *self.token == token::RBRACKET { slice = Some(@ast::Pat { id: ast::DUMMY_NODE_ID, node: PatWildMulti, span: *self.span, }) } else { let subpat = self.parse_pat(); match subpat { @ast::Pat { id, node: PatWild, span } => { self.obsolete(*self.span, ObsoleteVecDotDotWildcard); slice = Some(@ast::Pat { id: id, node: PatWildMulti, span: span }) }, @ast::Pat { node: PatIdent(_, _, _), .. } => { slice = Some(subpat); } @ast::Pat { span, .. } => self.span_fatal( span, "expected an identifier or nothing" ) } } } else { let subpat = self.parse_pat(); if before_slice { before.push(subpat); } else { after.push(subpat); } } } (before, slice, after) } // parse the fields of a struct-like pattern fn parse_pat_fields(&self) -> (~[ast::FieldPat], bool) { let mut fields = ~[]; let mut etc = false; let mut first = true; while *self.token != token::RBRACE { if first { first = false; } else { self.expect(&token::COMMA); } etc = *self.token == token::UNDERSCORE || *self.token == token::DOTDOT; if *self.token == token::UNDERSCORE { self.obsolete(*self.span, ObsoleteStructWildcard); } if etc { self.bump(); if *self.token != token::RBRACE { self.fatal( format!( "expected `\\}`, found `{}`", self.this_token_to_str() ) ); } etc = true; break; } let lo1 = self.last_span.lo; let fieldname = self.parse_ident(); let hi1 = self.last_span.lo; let fieldpath = ast_util::ident_to_path(mk_sp(lo1, hi1), fieldname); let subpat; if *self.token == token::COLON { self.bump(); subpat = self.parse_pat(); } else { subpat = @ast::Pat { id: ast::DUMMY_NODE_ID, node: PatIdent(BindByValue(MutImmutable), fieldpath, None), span: *self.last_span }; } fields.push(ast::FieldPat { ident: fieldname, pat: subpat }); } return (fields, etc); } // parse a pattern. pub fn parse_pat(&self) -> @Pat { maybe_whole!(self, nt_pat); let lo = self.span.lo; let mut hi; let pat; match *self.token { // parse _ token::UNDERSCORE => { self.bump(); pat = PatWild; hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } // parse @pat token::AT => { self.bump(); let sub = self.parse_pat(); hi = sub.span.hi; // HACK: parse @"..." as a literal of a vstore @str pat = match sub.node { PatLit(e@@Expr { node: ExprLit(@codemap::Spanned { node: lit_str(..), span: _}), .. }) => { let vst = @Expr { id: ast::DUMMY_NODE_ID, node: ExprVstore(e, ExprVstoreBox), span: mk_sp(lo, hi), }; PatLit(vst) } _ => PatBox(sub) }; hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } token::TILDE => { // parse ~pat self.bump(); let sub = self.parse_pat(); hi = sub.span.hi; // HACK: parse ~"..." as a literal of a vstore ~str pat = match sub.node { PatLit(e@@Expr { node: ExprLit(@codemap::Spanned { node: lit_str(..), span: _}), .. }) => { let vst = @Expr { id: ast::DUMMY_NODE_ID, node: ExprVstore(e, ExprVstoreUniq), span: mk_sp(lo, hi), }; PatLit(vst) } _ => PatUniq(sub) }; hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } token::BINOP(token::AND) => { // parse &pat let lo = self.span.lo; self.bump(); let sub = self.parse_pat(); hi = sub.span.hi; // HACK: parse &"..." as a literal of a borrowed str pat = match sub.node { PatLit(e@@Expr { node: ExprLit(@codemap::Spanned{ node: lit_str(..), .. }), .. }) => { let vst = @Expr { id: ast::DUMMY_NODE_ID, node: ExprVstore(e, ExprVstoreSlice), span: mk_sp(lo, hi) }; PatLit(vst) } _ => PatRegion(sub) }; hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } token::LPAREN => { // parse (pat,pat,pat,...) as tuple self.bump(); if *self.token == token::RPAREN { hi = self.span.hi; self.bump(); let lit = @codemap::Spanned { node: lit_nil, span: mk_sp(lo, hi)}; let expr = self.mk_expr(lo, hi, ExprLit(lit)); pat = PatLit(expr); } else { let mut fields = ~[self.parse_pat()]; if self.look_ahead(1, |t| *t != token::RPAREN) { while *self.token == token::COMMA { self.bump(); fields.push(self.parse_pat()); } } if fields.len() == 1 { self.expect(&token::COMMA); } self.expect(&token::RPAREN); pat = PatTup(fields); } hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } token::LBRACKET => { // parse [pat,pat,...] as vector pattern self.bump(); let (before, slice, after) = self.parse_pat_vec_elements(); self.expect(&token::RBRACKET); pat = ast::PatVec(before, slice, after); hi = self.last_span.hi; return @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi) } } _ => {} } let tok = self.token; if !is_ident_or_path(tok) || self.is_keyword(keywords::True) || self.is_keyword(keywords::False) { // Parse an expression pattern or exp .. exp. // // These expressions are limited to literals (possibly // preceded by unary-minus) or identifiers. let val = self.parse_literal_maybe_minus(); if self.eat(&token::DOTDOT) { let end = if is_ident_or_path(tok) { let path = self.parse_path(LifetimeAndTypesWithColons) .path; let hi = self.span.hi; self.mk_expr(lo, hi, ExprPath(path)) } else { self.parse_literal_maybe_minus() }; pat = PatRange(val, end); } else { pat = PatLit(val); } } else if self.eat_keyword(keywords::Mut) { pat = self.parse_pat_ident(BindByValue(MutMutable)); } else if self.eat_keyword(keywords::Ref) { // parse ref pat let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(BindByRef(mutbl)); } else { let can_be_enum_or_struct = self.look_ahead(1, |t| { match *t { token::LPAREN | token::LBRACKET | token::LT | token::LBRACE | token::MOD_SEP => true, _ => false, } }); if self.look_ahead(1, |t| *t == token::DOTDOT) { let start = self.parse_expr_res(RESTRICT_NO_BAR_OP); self.eat(&token::DOTDOT); let end = self.parse_expr_res(RESTRICT_NO_BAR_OP); pat = PatRange(start, end); } else if is_plain_ident(&*self.token) && !can_be_enum_or_struct { let name = self.parse_path(NoTypesAllowed).path; let sub; if self.eat(&token::AT) { // parse foo @ pat sub = Some(self.parse_pat()); } else { // or just foo sub = None; } pat = PatIdent(BindByValue(MutImmutable), name, sub); } else { // parse an enum pat let enum_path = self.parse_path(LifetimeAndTypesWithColons) .path; match *self.token { token::LBRACE => { self.bump(); let (fields, etc) = self.parse_pat_fields(); self.bump(); pat = PatStruct(enum_path, fields, etc); } _ => { let mut args: ~[@Pat] = ~[]; match *self.token { token::LPAREN => { let is_star = self.look_ahead(1, |t| { match *t { token::BINOP(token::STAR) => true, _ => false, } }); let is_dotdot = self.look_ahead(1, |t| { match *t { token::DOTDOT => true, _ => false, } }); if is_star | is_dotdot { // This is a "top constructor only" pat self.bump(); if is_star { self.obsolete(*self.span, ObsoleteEnumWildcard); } self.bump(); self.expect(&token::RPAREN); pat = PatEnum(enum_path, None); } else { args = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_pat() ); pat = PatEnum(enum_path, Some(args)); } }, _ => { if enum_path.segments.len() == 1 { // it could still be either an enum // or an identifier pattern, resolve // will sort it out: pat = PatIdent(BindByValue(MutImmutable), enum_path, None); } else { pat = PatEnum(enum_path, Some(args)); } } } } } } } hi = self.last_span.hi; @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi), } } // parse ident or ident @ pat // used by the copy foo and ref foo patterns to give a good // error message when parsing mistakes like ref foo(a,b) fn parse_pat_ident(&self, binding_mode: ast::BindingMode) -> ast::Pat_ { if !is_plain_ident(&*self.token) { self.span_fatal(*self.last_span, "expected identifier, found path"); } // why a path here, and not just an identifier? let name = self.parse_path(NoTypesAllowed).path; let sub = if self.eat(&token::AT) { Some(self.parse_pat()) } else { None }; // just to be friendly, if they write something like // ref Some(i) // we end up here with ( as the current token. This shortly // leads to a parse error. Note that if there is no explicit // binding mode then we do not end up here, because the lookahead // will direct us over to parse_enum_variant() if *self.token == token::LPAREN { self.span_fatal( *self.last_span, "expected identifier, found enum pattern"); } PatIdent(binding_mode, name, sub) } // parse a local variable declaration fn parse_local(&self) -> @Local { let lo = self.span.lo; let pat = self.parse_pat(); let mut ty = P(Ty { id: ast::DUMMY_NODE_ID, node: ty_infer, span: mk_sp(lo, lo), }); if self.eat(&token::COLON) { ty = self.parse_ty(false); } let init = self.parse_initializer(); @ast::Local { ty: ty, pat: pat, init: init, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, self.last_span.hi), } } // parse a "let" stmt fn parse_let(&self) -> @Decl { let lo = self.span.lo; let local = self.parse_local(); while self.eat(&token::COMMA) { let _ = self.parse_local(); self.obsolete(*self.span, ObsoleteMultipleLocalDecl); } return @spanned(lo, self.last_span.hi, DeclLocal(local)); } // parse a structure field fn parse_name_and_ty(&self, pr: visibility, attrs: ~[Attribute]) -> struct_field { let lo = self.span.lo; if !is_plain_ident(&*self.token) { self.fatal("expected ident"); } let name = self.parse_ident(); self.expect(&token::COLON); let ty = self.parse_ty(false); spanned(lo, self.last_span.hi, ast::struct_field_ { kind: named_field(name, pr), id: ast::DUMMY_NODE_ID, ty: ty, attrs: attrs, }) } // parse a statement. may include decl. // precondition: any attributes are parsed already pub fn parse_stmt(&self, item_attrs: ~[Attribute]) -> @Stmt { maybe_whole!(self, nt_stmt); fn check_expected_item(p: &Parser, found_attrs: bool) { // If we have attributes then we should have an item if found_attrs { p.span_err(*p.last_span, "expected item after attributes"); } } let lo = self.span.lo; if self.is_keyword(keywords::Let) { check_expected_item(self, !item_attrs.is_empty()); self.expect_keyword(keywords::Let); let decl = self.parse_let(); return @spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID)); } else if is_ident(&*self.token) && !token::is_any_keyword(self.token) && self.look_ahead(1, |t| *t == token::NOT) { // parse a macro invocation. Looks like there's serious // overlap here; if this clause doesn't catch it (and it // won't, for brace-delimited macros) it will fall through // to the macro clause of parse_item_or_view_item. This // could use some cleanup, it appears to me. // whoops! I now have a guess: I'm guessing the "parens-only" // rule here is deliberate, to allow macro users to use parens // for things that should be parsed as stmt_mac, and braces // for things that should expand into items. Tricky, and // somewhat awkward... and probably undocumented. Of course, // I could just be wrong. check_expected_item(self, !item_attrs.is_empty()); // Potential trouble: if we allow macros with paths instead of // idents, we'd need to look ahead past the whole path here... let pth = self.parse_path(NoTypesAllowed).path; self.bump(); let id = if *self.token == token::LPAREN { token::special_idents::invalid // no special identifier } else { self.parse_ident() }; let tts = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_none(), |p| p.parse_token_tree() ); let hi = self.span.hi; if id == token::special_idents::invalid { return @spanned(lo, hi, StmtMac( spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT)), false)); } else { // if it has a special ident, it's definitely an item return @spanned(lo, hi, StmtDecl( @spanned(lo, hi, DeclItem( self.mk_item( lo, hi, id /*id is good here*/, item_mac(spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT))), inherited, ~[/*no attrs*/]))), ast::DUMMY_NODE_ID)); } } else { let found_attrs = !item_attrs.is_empty(); match self.parse_item_or_view_item(item_attrs, false) { iovi_item(i) => { let hi = i.span.hi; let decl = @spanned(lo, hi, DeclItem(i)); return @spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID)); } iovi_view_item(vi) => { self.span_fatal(vi.span, "view items must be declared at the top of the block"); } iovi_foreign_item(_) => { self.fatal("foreign items are not allowed here"); } iovi_none(_) => { /* fallthrough */ } } check_expected_item(self, found_attrs); // Remainder are line-expr stmts. let e = self.parse_expr_res(RESTRICT_STMT_EXPR); return @spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)); } } // is this expression a successfully-parsed statement? fn expr_is_complete(&self, e: @Expr) -> bool { return *self.restriction == RESTRICT_STMT_EXPR && !classify::expr_requires_semi_to_be_stmt(e); } // parse a block. No inner attrs are allowed. pub fn parse_block(&self) -> P { maybe_whole!(no_clone self, nt_block); let lo = self.span.lo; if self.eat_keyword(keywords::Unsafe) { self.obsolete(*self.span, ObsoleteUnsafeBlock); } self.expect(&token::LBRACE); return self.parse_block_tail_(lo, DefaultBlock, ~[]); } // parse a block. Inner attrs are allowed. fn parse_inner_attrs_and_block(&self) -> (~[Attribute], P) { maybe_whole!(pair_empty self, nt_block); let lo = self.span.lo; if self.eat_keyword(keywords::Unsafe) { self.obsolete(*self.span, ObsoleteUnsafeBlock); } self.expect(&token::LBRACE); let (inner, next) = self.parse_inner_attrs_and_next(); (inner, self.parse_block_tail_(lo, DefaultBlock, next)) } // Precondition: already parsed the '{' or '#{' // I guess that also means "already parsed the 'impure'" if // necessary, and this should take a qualifier. // some blocks start with "#{"... fn parse_block_tail(&self, lo: BytePos, s: BlockCheckMode) -> P { self.parse_block_tail_(lo, s, ~[]) } // parse the rest of a block expression or function body fn parse_block_tail_(&self, lo: BytePos, s: BlockCheckMode, first_item_attrs: ~[Attribute]) -> P { let mut stmts = ~[]; let mut expr = None; // wouldn't it be more uniform to parse view items only, here? let ParsedItemsAndViewItems { attrs_remaining: attrs_remaining, view_items: view_items, items: items, .. } = self.parse_items_and_view_items(first_item_attrs, false, false); for item in items.iter() { let decl = @spanned(item.span.lo, item.span.hi, DeclItem(*item)); stmts.push(@spanned(item.span.lo, item.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID))); } let mut attributes_box = attrs_remaining; while (*self.token != token::RBRACE) { // parsing items even when they're not allowed lets us give // better error messages and recover more gracefully. attributes_box.push_all(self.parse_outer_attributes()); match *self.token { token::SEMI => { if !attributes_box.is_empty() { self.span_err(*self.last_span, "expected item after attributes"); attributes_box = ~[]; } self.bump(); // empty } token::RBRACE => { // fall through and out. } _ => { let stmt = self.parse_stmt(attributes_box); attributes_box = ~[]; match stmt.node { StmtExpr(e, stmt_id) => { // expression without semicolon if classify::stmt_ends_with_semi(stmt) { // Just check for errors and recover; do not eat semicolon yet. self.commit_stmt(stmt, &[], &[token::SEMI, token::RBRACE]); } match *self.token { token::SEMI => { self.bump(); stmts.push(@codemap::Spanned { node: StmtSemi(e, stmt_id), span: stmt.span, }); } token::RBRACE => { expr = Some(e); } _ => { stmts.push(stmt); } } } StmtMac(ref m, _) => { // statement macro; might be an expr let has_semi; match *self.token { token::SEMI => { has_semi = true; } token::RBRACE => { // if a block ends in `m!(arg)` without // a `;`, it must be an expr has_semi = false; expr = Some( self.mk_mac_expr(stmt.span.lo, stmt.span.hi, m.node.clone())); } _ => { has_semi = false; stmts.push(stmt); } } if has_semi { self.bump(); stmts.push(@codemap::Spanned { node: StmtMac((*m).clone(), true), span: stmt.span, }); } } _ => { // all other kinds of statements: stmts.push(stmt); if classify::stmt_ends_with_semi(stmt) { self.commit_stmt_expecting(stmt, token::SEMI); } } } } } } if !attributes_box.is_empty() { self.span_err(*self.last_span, "expected item after attributes"); } let hi = self.span.hi; self.bump(); P(ast::Block { view_items: view_items, stmts: stmts, expr: expr, id: ast::DUMMY_NODE_ID, rules: s, span: mk_sp(lo, hi), }) } fn parse_optional_purity(&self) -> ast::purity { if self.eat_keyword(keywords::Unsafe) { ast::unsafe_fn } else { ast::impure_fn } } fn parse_optional_onceness(&self) -> ast::Onceness { if self.eat_keyword(keywords::Once) { ast::Once } else { ast::Many } } // matches optbounds = ( ( : ( boundseq )? )? ) // where boundseq = ( bound + boundseq ) | bound // and bound = 'static | ty // Returns "None" if there's no colon (e.g. "T"); // Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:") // Returns "Some(stuff)" otherwise (e.g. "T:stuff"). // NB: The None/Some distinction is important for issue #7264. fn parse_optional_ty_param_bounds(&self) -> Option> { if !self.eat(&token::COLON) { return None; } let mut result = opt_vec::Empty; loop { match *self.token { token::LIFETIME(lifetime) => { if "static" == self.id_to_str(lifetime) { result.push(RegionTyParamBound); } else { self.span_err(*self.span, "`'static` is the only permissible region bound here"); } self.bump(); } token::MOD_SEP | token::IDENT(..) => { let tref = self.parse_trait_ref(); result.push(TraitTyParamBound(tref)); } _ => break, } if !self.eat(&token::BINOP(token::PLUS)) { break; } } return Some(result); } // matches typaram = IDENT optbounds fn parse_ty_param(&self) -> TyParam { let ident = self.parse_ident(); let opt_bounds = self.parse_optional_ty_param_bounds(); // For typarams we don't care about the difference b/w "" and "". let bounds = opt_bounds.unwrap_or_default(); ast::TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds } } // parse a set of optional generic type parameter declarations // matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) // | ( < lifetimes , typaramseq ( , )? > ) // where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&self) -> ast::Generics { if self.eat(&token::LT) { let lifetimes = self.parse_lifetimes(); let ty_params = self.parse_seq_to_gt( Some(token::COMMA), |p| p.parse_ty_param()); ast::Generics { lifetimes: lifetimes, ty_params: ty_params } } else { ast_util::empty_generics() } } // parse a generic use site fn parse_generic_values(&self) -> (OptVec, ~[P]) { if !self.eat(&token::LT) { (opt_vec::Empty, ~[]) } else { self.parse_generic_values_after_lt() } } fn parse_generic_values_after_lt(&self) -> (OptVec, ~[P]) { let lifetimes = self.parse_lifetimes(); let result = self.parse_seq_to_gt( Some(token::COMMA), |p| p.parse_ty(false)); (lifetimes, opt_vec::take_vec(result)) } fn parse_fn_args(&self, named_args: bool, allow_variadic: bool) -> (~[arg], bool) { let sp = *self.span; let mut args: ~[Option] = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), |p| { if *p.token == token::DOTDOTDOT { p.bump(); if allow_variadic { if *p.token != token::RPAREN { p.span_fatal(*p.span, "`...` must be last in argument list for variadic function"); } } else { p.span_fatal(*p.span, "only foreign functions are allowed to be variadic"); } None } else { Some(p.parse_arg_general(named_args)) } } ); let variadic = match args.pop_opt() { Some(None) => true, Some(x) => { // Need to put back that last arg args.push(x); false } None => false }; if variadic && args.is_empty() { self.span_err(sp, "variadic function must be declared with at least one named argument"); } let args = args.move_iter().map(|x| x.unwrap()).collect(); (args, variadic) } // parse the argument list and result type of a function declaration pub fn parse_fn_decl(&self, allow_variadic: bool) -> P { let (args, variadic) = self.parse_fn_args(true, allow_variadic); let (ret_style, ret_ty) = self.parse_ret_ty(); P(ast::fn_decl { inputs: args, output: ret_ty, cf: ret_style, variadic: variadic }) } fn is_self_ident(&self) -> bool { match *self.token { token::IDENT(id, false) => id.name == special_idents::self_.name, _ => false } } fn expect_self_ident(&self) { if !self.is_self_ident() { self.fatal( format!( "expected `self` but found `{}`", self.this_token_to_str() ) ); } self.bump(); } // parse the argument list and result type of a function // that may have a self type. fn parse_fn_decl_with_self(&self, parse_arg_fn: |&Parser| -> arg) -> (explicit_self, P) { fn maybe_parse_explicit_self(cnstr: |v: Mutability| -> ast::explicit_self_, p: &Parser) -> ast::explicit_self_ { // We need to make sure it isn't a type if p.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) || ((p.look_ahead(1, |t| token::is_keyword(keywords::Const, t)) || p.look_ahead(1, |t| token::is_keyword(keywords::Mut, t))) && p.look_ahead(2, |t| token::is_keyword(keywords::Self, t))) { p.bump(); let mutability = p.parse_mutability(); p.expect_self_ident(); cnstr(mutability) } else { sty_static } } fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ { // The following things are possible to see here: // // fn(&self) // fn(&mut self) // fn(&'lt self) // fn(&'lt mut self) // // We already know that the current token is `&`. if this.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) { this.bump(); this.expect_self_ident(); sty_region(None, MutImmutable) } else if this.look_ahead(1, |t| this.token_is_mutability(t)) && this.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) { this.bump(); let mutability = this.parse_mutability(); this.expect_self_ident(); sty_region(None, mutability) } else if this.look_ahead(1, |t| this.token_is_lifetime(t)) && this.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) { this.bump(); let lifetime = this.parse_lifetime(); this.expect_self_ident(); sty_region(Some(lifetime), MutImmutable) } else if this.look_ahead(1, |t| this.token_is_lifetime(t)) && this.look_ahead(2, |t| this.token_is_mutability(t)) && this.look_ahead(3, |t| token::is_keyword(keywords::Self, t)) { this.bump(); let lifetime = this.parse_lifetime(); let mutability = this.parse_mutability(); this.expect_self_ident(); sty_region(Some(lifetime), mutability) } else { sty_static } } self.expect(&token::LPAREN); // A bit of complexity and lookahead is needed here in order to be // backwards compatible. let lo = self.span.lo; let explicit_self = match *self.token { token::BINOP(token::AND) => { maybe_parse_borrowed_explicit_self(self) } token::AT => { maybe_parse_explicit_self(sty_box, self) } token::TILDE => { maybe_parse_explicit_self(|mutability| { if mutability != MutImmutable { self.span_err(*self.last_span, "mutability declaration not allowed here"); } sty_uniq(MutImmutable) }, self) } token::IDENT(..) if self.is_self_ident() => { self.bump(); sty_value(MutImmutable) } token::BINOP(token::STAR) => { // Possibly "*self" or "*mut self" -- not supported. Try to avoid // emitting cryptic "unexpected token" errors. self.bump(); let mutability = if self.token_is_mutability(self.token) { self.parse_mutability() } else { MutImmutable }; if self.is_self_ident() { self.span_err(*self.span, "cannot pass self by unsafe pointer"); self.bump(); } sty_value(mutability) } _ if self.token_is_mutability(self.token) && self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => { let mutability = self.parse_mutability(); self.expect_self_ident(); sty_value(mutability) } _ if self.token_is_mutability(self.token) && self.look_ahead(1, |t| *t == token::TILDE) && self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => { let mutability = self.parse_mutability(); self.bump(); self.expect_self_ident(); sty_uniq(mutability) } _ => { sty_static } }; // If we parsed a self type, expect a comma before the argument list. let fn_inputs; if explicit_self != sty_static { match *self.token { token::COMMA => { self.bump(); let sep = seq_sep_trailing_disallowed(token::COMMA); fn_inputs = self.parse_seq_to_before_end( &token::RPAREN, sep, parse_arg_fn ); } token::RPAREN => { fn_inputs = ~[]; } _ => { self.fatal( format!( "expected `,` or `)`, found `{}`", self.this_token_to_str() ) ); } } } else { let sep = seq_sep_trailing_disallowed(token::COMMA); fn_inputs = self.parse_seq_to_before_end( &token::RPAREN, sep, parse_arg_fn ); } self.expect(&token::RPAREN); let hi = self.span.hi; let (ret_style, ret_ty) = self.parse_ret_ty(); let fn_decl = P(ast::fn_decl { inputs: fn_inputs, output: ret_ty, cf: ret_style, variadic: false }); (spanned(lo, hi, explicit_self), fn_decl) } // parse the |arg, arg| header on a lambda fn parse_fn_block_decl(&self) -> P { let inputs_captures = { if self.eat(&token::OROR) { ~[] } else { self.parse_unspanned_seq( &token::BINOP(token::OR), &token::BINOP(token::OR), seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_fn_block_arg() ) } }; let output = if self.eat(&token::RARROW) { self.parse_ty(false) } else { P(Ty { id: ast::DUMMY_NODE_ID, node: ty_infer, span: *self.span }) }; P(ast::fn_decl { inputs: inputs_captures, output: output, cf: return_val, variadic: false }) } // Parses the `(arg, arg) -> return_type` header on a procedure. fn parse_proc_decl(&self) -> P { let inputs = self.parse_unspanned_seq(&token::LPAREN, &token::RPAREN, seq_sep_trailing_allowed(token::COMMA), |p| p.parse_fn_block_arg()); let output = if self.eat(&token::RARROW) { self.parse_ty(false) } else { P(Ty { id: ast::DUMMY_NODE_ID, node: ty_infer, span: *self.span, }) }; P(ast::fn_decl { inputs: inputs, output: output, cf: return_val, variadic: false }) } // parse the name and optional generic types of a function header. fn parse_fn_header(&self) -> (Ident, ast::Generics) { let id = self.parse_ident(); let generics = self.parse_generics(); (id, generics) } fn mk_item(&self, lo: BytePos, hi: BytePos, ident: Ident, node: item_, vis: visibility, attrs: ~[Attribute]) -> @item { @ast::item { ident: ident, attrs: attrs, id: ast::DUMMY_NODE_ID, node: node, vis: vis, span: mk_sp(lo, hi) } } // parse an item-position function declaration. fn parse_item_fn(&self, purity: purity, abis: AbiSet) -> item_info { let (ident, generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(false); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); (ident, item_fn(decl, purity, abis, generics, body), Some(inner_attrs)) } // parse a method in a trait impl, starting with `attrs` attributes. fn parse_method(&self, already_parsed_attrs: Option<~[Attribute]>) -> @method { let next_attrs = self.parse_outer_attributes(); let attrs = match already_parsed_attrs { Some(mut a) => { a.push_all_move(next_attrs); a } None => next_attrs }; let lo = self.span.lo; let visa = self.parse_visibility(); let pur = self.parse_fn_purity(); let ident = self.parse_ident(); let generics = self.parse_generics(); let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { p.parse_arg() }); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); let hi = body.span.hi; let attrs = vec::append(attrs, inner_attrs); @ast::method { ident: ident, attrs: attrs, generics: generics, explicit_self: explicit_self, purity: pur, decl: decl, body: body, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), self_id: ast::DUMMY_NODE_ID, vis: visa, } } // parse trait Foo { ... } fn parse_item_trait(&self) -> item_info { let ident = self.parse_ident(); let tps = self.parse_generics(); // Parse traits, if necessary. let traits; if *self.token == token::COLON { self.bump(); traits = self.parse_trait_ref_list(&token::LBRACE); } else { traits = ~[]; } let meths = self.parse_trait_methods(); (ident, item_trait(tps, traits, meths), None) } // Parses two variants (with the region/type params always optional): // impl Foo { ... } // impl ToStr for ~[T] { ... } fn parse_item_impl(&self) -> item_info { // First, parse type parameters if necessary. let generics = self.parse_generics(); // This is a new-style impl declaration. // XXX: clownshoes let ident = special_idents::clownshoes_extensions; // Special case: if the next identifier that follows is '(', don't // allow this to be parsed as a trait. let could_be_trait = *self.token != token::LPAREN; // Parse the trait. let mut ty = self.parse_ty(false); // Parse traits, if necessary. let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. let opt_trait_ref = match ty.node { ty_path(ref path, None, node_id) => { Some(trait_ref { path: /* bad */ (*path).clone(), ref_id: node_id }) } ty_path(..) => { self.span_err(ty.span, "bounded traits are only valid in type position"); None } _ => { self.span_err(ty.span, "not a trait"); None } }; ty = self.parse_ty(false); opt_trait_ref } else { None }; let mut meths = ~[]; let inner_attrs = if self.eat(&token::SEMI) { self.obsolete(*self.last_span, ObsoleteEmptyImpl); None } else { self.expect(&token::LBRACE); let (inner_attrs, next) = self.parse_inner_attrs_and_next(); let mut method_attrs = Some(next); while !self.eat(&token::RBRACE) { meths.push(self.parse_method(method_attrs)); method_attrs = None; } Some(inner_attrs) }; (ident, item_impl(generics, opt_trait, ty, meths), inner_attrs) } // parse a::B<~str,int> fn parse_trait_ref(&self) -> trait_ref { ast::trait_ref { path: self.parse_path(LifetimeAndTypesWithoutColons).path, ref_id: ast::DUMMY_NODE_ID, } } // parse B + C<~str,int> + D fn parse_trait_ref_list(&self, ket: &token::Token) -> ~[trait_ref] { self.parse_seq_to_before_end( ket, seq_sep_trailing_disallowed(token::BINOP(token::PLUS)), |p| p.parse_trait_ref() ) } // parse struct Foo { ... } fn parse_item_struct(&self) -> item_info { let class_name = self.parse_ident(); let generics = self.parse_generics(); let mut fields: ~[struct_field]; let is_tuple_like; if self.eat(&token::LBRACE) { // It's a record-like struct. is_tuple_like = false; fields = ~[]; while *self.token != token::RBRACE { fields.push(self.parse_struct_decl_field()); } if fields.len() == 0 { self.fatal(format!("Unit-like struct definition should be written as `struct {};`", get_ident_interner().get(class_name.name))); } self.bump(); } else if *self.token == token::LPAREN { // It's a tuple-like struct. is_tuple_like = true; fields = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_allowed(token::COMMA), |p| { let attrs = self.parse_outer_attributes(); let lo = p.span.lo; let struct_field_ = ast::struct_field_ { kind: unnamed_field, id: ast::DUMMY_NODE_ID, ty: p.parse_ty(false), attrs: attrs, }; spanned(lo, p.span.hi, struct_field_) }); self.expect(&token::SEMI); } else if self.eat(&token::SEMI) { // It's a unit-like struct. is_tuple_like = true; fields = ~[]; } else { self.fatal( format!( "expected `\\{`, `(`, or `;` after struct name \ but found `{}`", self.this_token_to_str() ) ); } let _ = ast::DUMMY_NODE_ID; // XXX: Workaround for crazy bug. let new_id = ast::DUMMY_NODE_ID; (class_name, item_struct(@ast::struct_def { fields: fields, ctor_id: if is_tuple_like { Some(new_id) } else { None } }, generics), None) } fn token_is_pound_or_doc_comment(&self, tok: token::Token) -> bool { match tok { token::POUND | token::DOC_COMMENT(_) => true, _ => false } } // parse a structure field declaration pub fn parse_single_struct_field(&self, vis: visibility, attrs: ~[Attribute]) -> struct_field { let a_var = self.parse_name_and_ty(vis, attrs); match *self.token { token::COMMA => { self.bump(); } token::RBRACE => {} _ => { self.span_fatal(*self.span, format!("expected `,`, or `\\}` but found `{}`", self.this_token_to_str())); } } a_var } // parse an element of a struct definition fn parse_struct_decl_field(&self) -> struct_field { let attrs = self.parse_outer_attributes(); if self.eat_keyword(keywords::Priv) { return self.parse_single_struct_field(private, attrs); } if self.eat_keyword(keywords::Pub) { return self.parse_single_struct_field(public, attrs); } return self.parse_single_struct_field(inherited, attrs); } // parse visiility: PUB, PRIV, or nothing fn parse_visibility(&self) -> visibility { if self.eat_keyword(keywords::Pub) { public } else if self.eat_keyword(keywords::Priv) { private } else { inherited } } // given a termination token and a vector of already-parsed // attributes (of length 0 or 1), parse all of the items in a module fn parse_mod_items(&self, term: token::Token, first_item_attrs: ~[Attribute]) -> _mod { // parse all of the items up to closing or an attribute. // view items are legal here. let ParsedItemsAndViewItems { attrs_remaining: attrs_remaining, view_items: view_items, items: starting_items, .. } = self.parse_items_and_view_items(first_item_attrs, true, true); let mut items: ~[@item] = starting_items; let attrs_remaining_len = attrs_remaining.len(); // don't think this other loop is even necessary.... let mut first = true; while *self.token != term { let mut attrs = self.parse_outer_attributes(); if first { attrs = attrs_remaining + attrs; first = false; } debug!("parse_mod_items: parse_item_or_view_item(attrs={:?})", attrs); match self.parse_item_or_view_item(attrs, true /* macros allowed */) { iovi_item(item) => items.push(item), iovi_view_item(view_item) => { self.span_fatal(view_item.span, "view items must be declared at the top of \ the module"); } _ => { self.fatal(format!("expected item but found `{}`", self.this_token_to_str())); } } } if first && attrs_remaining_len > 0u { // We parsed attributes for the first item but didn't find it self.span_err(*self.last_span, "expected item after attributes"); } ast::_mod { view_items: view_items, items: items } } fn parse_item_const(&self) -> item_info { let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable}; let id = self.parse_ident(); self.expect(&token::COLON); let ty = self.parse_ty(false); self.expect(&token::EQ); let e = self.parse_expr(); self.commit_expr_expecting(e, token::SEMI); (id, item_static(ty, m, e), None) } // parse a `mod { ... }` or `mod ;` item fn parse_item_mod(&self, outer_attrs: &[Attribute]) -> item_info { let id_span = *self.span; let id = self.parse_ident(); if *self.token == token::SEMI { self.bump(); // This mod is in an external file. Let's go get it! let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span); (id, m, Some(attrs)) } else { self.push_mod_path(id, outer_attrs); self.expect(&token::LBRACE); let (inner, next) = self.parse_inner_attrs_and_next(); let m = self.parse_mod_items(token::RBRACE, next); self.expect(&token::RBRACE); self.pop_mod_path(); (id, item_mod(m), Some(inner)) } } fn push_mod_path(&self, id: Ident, attrs: &[Attribute]) { let default_path = token::interner_get(id.name); let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") { Some(d) => d, None => default_path }; self.mod_path_stack.push(file_path) } fn pop_mod_path(&self) { self.mod_path_stack.pop(); } // read a module from a source file. fn eval_src_mod(&self, id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) -> (ast::item_, ~[ast::Attribute]) { let mut prefix = Path::init(self.sess.cm.span_to_filename(*self.span)); prefix.pop(); let mod_path_stack = &*self.mod_path_stack; let mod_path = Path::init(".").join_many(*mod_path_stack); let dir_path = prefix.join(&mod_path); let file_path = match ::attr::first_attr_value_str_by_name( outer_attrs, "path") { Some(d) => dir_path.join(d), None => { let mod_name = token::interner_get(id.name).to_owned(); let default_path_str = mod_name + ".rs"; let secondary_path_str = mod_name + "/mod.rs"; let default_path = dir_path.join(default_path_str.as_slice()); let secondary_path = dir_path.join(secondary_path_str.as_slice()); let default_exists = default_path.exists(); let secondary_exists = secondary_path.exists(); match (default_exists, secondary_exists) { (true, false) => default_path, (false, true) => secondary_path, (false, false) => { self.span_fatal(id_sp, format!("file not found for module `{}`", mod_name)); } (true, true) => { self.span_fatal(id_sp, format!("file for module `{}` found at both {} and {}", mod_name, default_path_str, secondary_path_str)); } } } }; self.eval_src_mod_from_path(file_path, outer_attrs.to_owned(), id_sp) } fn eval_src_mod_from_path(&self, path: Path, outer_attrs: ~[ast::Attribute], id_sp: Span) -> (ast::item_, ~[ast::Attribute]) { let maybe_i = self.sess.included_mod_stack.iter().position(|p| *p == path); match maybe_i { Some(i) => { let stack = &self.sess.included_mod_stack; let mut err = ~"circular modules: "; for p in stack.slice(i, stack.len()).iter() { p.display().with_str(|s| err.push_str(s)); err.push_str(" -> "); } path.display().with_str(|s| err.push_str(s)); self.span_fatal(id_sp, err); } None => () } self.sess.included_mod_stack.push(path.clone()); let p0 = new_sub_parser_from_file(self.sess, self.cfg.clone(), &path, id_sp); let (inner, next) = p0.parse_inner_attrs_and_next(); let mod_attrs = vec::append(outer_attrs, inner); let first_item_outer_attrs = next; let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); self.sess.included_mod_stack.pop(); return (ast::item_mod(m0), mod_attrs); } // parse a function declaration from a foreign module fn parse_item_foreign_fn(&self, vis: ast::visibility, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; // Parse obsolete purity. let purity = self.parse_fn_purity(); if purity != impure_fn { self.obsolete(*self.last_span, ObsoleteUnsafeExternFn); } let (ident, generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(true); let hi = self.span.hi; self.expect(&token::SEMI); @ast::foreign_item { ident: ident, attrs: attrs, node: foreign_item_fn(decl, generics), id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), vis: vis } } // parse a static item from a foreign module fn parse_item_foreign_static(&self, vis: ast::visibility, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; self.expect_keyword(keywords::Static); let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident(); self.expect(&token::COLON); let ty = self.parse_ty(false); let hi = self.span.hi; self.expect(&token::SEMI); @ast::foreign_item { ident: ident, attrs: attrs, node: foreign_item_static(ty, mutbl), id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), vis: vis } } // parse safe/unsafe and fn fn parse_fn_purity(&self) -> purity { if self.eat_keyword(keywords::Fn) { impure_fn } else if self.eat_keyword(keywords::Unsafe) { self.expect_keyword(keywords::Fn); unsafe_fn } else { self.unexpected(); } } // at this point, this is essentially a wrapper for // parse_foreign_items. fn parse_foreign_mod_items(&self, abis: AbiSet, first_item_attrs: ~[Attribute]) -> foreign_mod { let ParsedItemsAndViewItems { attrs_remaining: attrs_remaining, view_items: view_items, items: _, foreign_items: foreign_items } = self.parse_foreign_items(first_item_attrs, true); if (! attrs_remaining.is_empty()) { self.span_err(*self.last_span, "expected item after attributes"); } assert!(*self.token == token::RBRACE); ast::foreign_mod { abis: abis, view_items: view_items, items: foreign_items } } // parse extern foo; or extern mod foo { ... } or extern { ... } fn parse_item_foreign_mod(&self, lo: BytePos, opt_abis: Option, visibility: visibility, attrs: ~[Attribute], items_allowed: bool) -> item_or_view_item { let mut must_be_named_mod = false; if self.is_keyword(keywords::Mod) { must_be_named_mod = true; self.expect_keyword(keywords::Mod); } else if *self.token != token::LBRACE { self.span_fatal(*self.span, format!("expected `\\{` or `mod` but found `{}`", self.this_token_to_str())); } let (named, maybe_path, ident) = match *self.token { token::IDENT(..) => { let the_ident = self.parse_ident(); let path = if *self.token == token::EQ { self.bump(); Some(self.parse_str()) } else { None }; (true, path, the_ident) } _ => { if must_be_named_mod { self.span_fatal(*self.span, format!("expected foreign module name but \ found `{}`", self.this_token_to_str())); } (false, None, special_idents::clownshoes_foreign_mod) } }; // extern mod foo { ... } or extern { ... } if items_allowed && self.eat(&token::LBRACE) { // `extern mod foo { ... }` is obsolete. if named { self.obsolete(*self.last_span, ObsoleteNamedExternModule); } let abis = opt_abis.unwrap_or(AbiSet::C()); let (inner, next) = self.parse_inner_attrs_and_next(); let m = self.parse_foreign_mod_items(abis, next); self.expect(&token::RBRACE); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_foreign_mod(m), visibility, maybe_append(attrs, Some(inner)))); } if opt_abis.is_some() { self.span_err(*self.span, "an ABI may not be specified here"); } // extern mod foo; let metadata = self.parse_optional_meta(); self.expect(&token::SEMI); iovi_view_item(ast::view_item { node: view_item_extern_mod(ident, maybe_path, metadata, ast::DUMMY_NODE_ID), attrs: attrs, vis: visibility, span: mk_sp(lo, self.last_span.hi) }) } // parse type Foo = Bar; fn parse_item_type(&self) -> item_info { let ident = self.parse_ident(); let tps = self.parse_generics(); self.expect(&token::EQ); let ty = self.parse_ty(false); self.expect(&token::SEMI); (ident, item_ty(ty, tps), None) } // parse a structure-like enum variant definition // this should probably be renamed or refactored... fn parse_struct_def(&self) -> @struct_def { let mut fields: ~[struct_field] = ~[]; while *self.token != token::RBRACE { fields.push(self.parse_struct_decl_field()); } self.bump(); return @ast::struct_def { fields: fields, ctor_id: None }; } // parse the part of an "enum" decl following the '{' fn parse_enum_def(&self, _generics: &ast::Generics) -> enum_def { let mut variants = ~[]; let mut all_nullary = true; let mut have_disr = false; while *self.token != token::RBRACE { let variant_attrs = self.parse_outer_attributes(); let vlo = self.span.lo; let vis = self.parse_visibility(); let ident; let kind; let mut args = ~[]; let mut disr_expr = None; ident = self.parse_ident(); if self.eat(&token::LBRACE) { // Parse a struct variant. all_nullary = false; kind = struct_variant_kind(self.parse_struct_def()); } else if *self.token == token::LPAREN { all_nullary = false; let arg_tys = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_ty(false) ); for ty in arg_tys.move_iter() { args.push(ast::variant_arg { ty: ty, id: ast::DUMMY_NODE_ID, }); } kind = tuple_variant_kind(args); } else if self.eat(&token::EQ) { have_disr = true; disr_expr = Some(self.parse_expr()); kind = tuple_variant_kind(args); } else { kind = tuple_variant_kind(~[]); } let vr = ast::variant_ { name: ident, attrs: variant_attrs, kind: kind, id: ast::DUMMY_NODE_ID, disr_expr: disr_expr, vis: vis, }; variants.push(P(spanned(vlo, self.last_span.hi, vr))); if !self.eat(&token::COMMA) { break; } } self.expect(&token::RBRACE); if (have_disr && !all_nullary) { self.fatal("discriminator values can only be used with a c-like \ enum"); } ast::enum_def { variants: variants } } // parse an "enum" declaration fn parse_item_enum(&self) -> item_info { let id = self.parse_ident(); let generics = self.parse_generics(); self.expect(&token::LBRACE); let enum_definition = self.parse_enum_def(&generics); (id, item_enum(enum_definition, generics), None) } fn parse_fn_ty_sigil(&self) -> Option { match *self.token { token::AT => { self.bump(); Some(ManagedSigil) } token::TILDE => { self.bump(); Some(OwnedSigil) } token::BINOP(token::AND) => { self.bump(); Some(BorrowedSigil) } _ => { None } } } fn fn_expr_lookahead(&self, tok: &token::Token) -> bool { match *tok { token::LPAREN | token::AT | token::TILDE | token::BINOP(_) => true, _ => false } } // Parses a string as an ABI spec on an extern type or module. Consumes // the `extern` keyword, if one is found. fn parse_opt_abis(&self) -> Option { if !self.eat_keyword(keywords::Extern) { return None } match *self.token { token::LIT_STR(s) | token::LIT_STR_RAW(s, _) => { self.bump(); let the_string = ident_to_str(&s); let mut abis = AbiSet::empty(); for word in the_string.words() { match abi::lookup(word) { Some(abi) => { if abis.contains(abi) { self.span_err( *self.span, format!("ABI `{}` appears twice", word)); } else { abis.add(abi); } } None => { self.span_err( *self.span, format!("illegal ABI: \ expected one of [{}], \ found `{}`", abi::all_names().connect(", "), word)); } } } Some(abis) } _ => { None } } } // parse one of the items or view items allowed by the // flags; on failure, return iovi_none. // NB: this function no longer parses the items inside an // extern mod. fn parse_item_or_view_item(&self, attrs: ~[Attribute], macros_allowed: bool) -> item_or_view_item { match *self.token { INTERPOLATED(token::nt_item(item)) => { self.bump(); let new_attrs = vec::append(attrs, item.attrs); return iovi_item(@ast::item { attrs: new_attrs, ..(*item).clone()}); } _ => {} } let lo = self.span.lo; let visibility = self.parse_visibility(); // must be a view item: if self.eat_keyword(keywords::Use) { // USE ITEM (iovi_view_item) let view_item = self.parse_use(); self.expect(&token::SEMI); return iovi_view_item(ast::view_item { node: view_item, attrs: attrs, vis: visibility, span: mk_sp(lo, self.last_span.hi) }); } // either a view item or an item: if self.is_keyword(keywords::Extern) { let opt_abis = self.parse_opt_abis(); if self.eat_keyword(keywords::Fn) { // EXTERN FUNCTION ITEM let abis = opt_abis.unwrap_or(AbiSet::C()); let (ident, item_, extra_attrs) = self.parse_item_fn(extern_fn, abis); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } else { // EXTERN MODULE ITEM (iovi_view_item) return self.parse_item_foreign_mod(lo, opt_abis, visibility, attrs, true); } } // the rest are all guaranteed to be items: if self.is_keyword(keywords::Static) { // STATIC ITEM self.bump(); let (ident, item_, extra_attrs) = self.parse_item_const(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.is_keyword(keywords::Fn) && self.look_ahead(1, |f| !self.fn_expr_lookahead(f)) { // FUNCTION ITEM self.bump(); let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn, AbiSet::Rust()); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.is_keyword(keywords::Unsafe) && self.look_ahead(1u, |t| *t != token::LBRACE) { // UNSAFE FUNCTION ITEM self.bump(); self.expect_keyword(keywords::Fn); let (ident, item_, extra_attrs) = self.parse_item_fn(unsafe_fn, AbiSet::Rust()); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Mod) { // MODULE ITEM let (ident, item_, extra_attrs) = self.parse_item_mod(attrs); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Type) { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Enum) { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Trait) { // TRAIT ITEM let (ident, item_, extra_attrs) = self.parse_item_trait(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Impl) { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } if self.eat_keyword(keywords::Struct) { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility) } // parse a foreign item; on failure, return iovi_none. fn parse_foreign_item(&self, attrs: ~[Attribute], macros_allowed: bool) -> item_or_view_item { maybe_whole!(iovi self, nt_item); let lo = self.span.lo; let visibility = self.parse_visibility(); if self.is_keyword(keywords::Static) { // FOREIGN STATIC ITEM let item = self.parse_item_foreign_static(visibility, attrs); return iovi_foreign_item(item); } if self.is_keyword(keywords::Fn) || self.is_keyword(keywords::Unsafe) { // FOREIGN FUNCTION ITEM let item = self.parse_item_foreign_fn(visibility, attrs); return iovi_foreign_item(item); } self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility) } // this is the fall-through for parsing items. fn parse_macro_use_or_failure( &self, attrs: ~[Attribute], macros_allowed: bool, lo : BytePos, visibility : visibility ) -> item_or_view_item { if macros_allowed && !token::is_any_keyword(self.token) && self.look_ahead(1, |t| *t == token::NOT) && (self.look_ahead(2, |t| is_plain_ident(t)) || self.look_ahead(2, |t| *t == token::LPAREN) || self.look_ahead(2, |t| *t == token::LBRACE)) { // MACRO INVOCATION ITEM // item macro. let pth = self.parse_path(NoTypesAllowed).path; self.expect(&token::NOT); // a 'special' identifier (like what `macro_rules!` uses) // is optional. We should eventually unify invoc syntax // and remove this. let id = if is_plain_ident(&*self.token) { self.parse_ident() } else { token::special_idents::invalid // no special identifier }; // eat a matched-delimiter token tree: let tts = match *self.token { token::LPAREN | token::LBRACE => { let ket = token::flip_delimiter(&*self.token); self.bump(); self.parse_seq_to_end(&ket, seq_sep_none(), |p| p.parse_token_tree()) } _ => self.fatal("expected open delimiter") }; // single-variant-enum... : let m = ast::mac_invoc_tt(pth, tts, EMPTY_CTXT); let m: ast::mac = codemap::Spanned { node: m, span: mk_sp(self.span.lo, self.span.hi) }; let item_ = item_mac(m); return iovi_item(self.mk_item(lo, self.last_span.hi, id, item_, visibility, attrs)); } // FAILURE TO PARSE ITEM if visibility != inherited { let mut s = ~"unmatched visibility `"; if visibility == public { s.push_str("pub") } else { s.push_str("priv") } s.push_char('`'); self.span_fatal(*self.last_span, s); } return iovi_none(attrs); } pub fn parse_item(&self, attrs: ~[Attribute]) -> Option<@ast::item> { match self.parse_item_or_view_item(attrs, true) { iovi_none(_) => None, iovi_view_item(_) => self.fatal("view items are not allowed here"), iovi_foreign_item(_) => self.fatal("foreign items are not allowed here"), iovi_item(item) => Some(item) } } // parse, e.g., "use a::b::{z,y}" fn parse_use(&self) -> view_item_ { return view_item_use(self.parse_view_paths()); } // matches view_path : MOD? IDENT EQ non_global_path // | MOD? non_global_path MOD_SEP LBRACE RBRACE // | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE // | MOD? non_global_path MOD_SEP STAR // | MOD? non_global_path fn parse_view_path(&self) -> @view_path { let lo = self.span.lo; let first_ident = self.parse_ident(); let mut path = ~[first_ident]; debug!("parsed view_path: {}", self.id_to_str(first_ident)); match *self.token { token::EQ => { // x = foo::bar self.bump(); path = ~[self.parse_ident()]; while *self.token == token::MOD_SEP { self.bump(); let id = self.parse_ident(); path.push(id); } let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() }; return @spanned(lo, self.span.hi, view_path_simple(first_ident, path, ast::DUMMY_NODE_ID)); } token::MOD_SEP => { // foo::bar or foo::{a,b,c} or foo::* while *self.token == token::MOD_SEP { self.bump(); match *self.token { token::IDENT(i, _) => { self.bump(); path.push(i); } // foo::bar::{a,b,c} token::LBRACE => { let idents = self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, seq_sep_trailing_allowed(token::COMMA), |p| p.parse_path_list_ident() ); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() }; return @spanned(lo, self.span.hi, view_path_list(path, idents, ast::DUMMY_NODE_ID)); } // foo::bar::* token::BINOP(token::STAR) => { self.bump(); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() }; return @spanned(lo, self.span.hi, view_path_glob(path, ast::DUMMY_NODE_ID)); } _ => break } } } _ => () } let last = path[path.len() - 1u]; let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() }; return @spanned(lo, self.last_span.hi, view_path_simple(last, path, ast::DUMMY_NODE_ID)); } // matches view_paths = view_path | view_path , view_paths fn parse_view_paths(&self) -> ~[@view_path] { let mut vp = ~[self.parse_view_path()]; while *self.token == token::COMMA { self.bump(); vp.push(self.parse_view_path()); } return vp; } fn is_view_item(&self) -> bool { if !self.is_keyword(keywords::Pub) && !self.is_keyword(keywords::Priv) { token::is_keyword(keywords::Use, self.token) || (token::is_keyword(keywords::Extern, self.token) && self.look_ahead(1, |t| token::is_keyword(keywords::Mod, t))) } else { self.look_ahead(1, |t| token::is_keyword(keywords::Use, t)) || (self.look_ahead(1, |t| token::is_keyword(keywords::Extern, t)) && self.look_ahead(2, |t| token::is_keyword(keywords::Mod, t))) } } // parse a view item. fn parse_view_item( &self, attrs: ~[Attribute], vis: visibility ) -> view_item { let lo = self.span.lo; let node = if self.eat_keyword(keywords::Use) { self.parse_use() } else if self.eat_keyword(keywords::Extern) { self.expect_keyword(keywords::Mod); let ident = self.parse_ident(); let path = if *self.token == token::EQ { self.bump(); Some(self.parse_str()) } else { None }; let metadata = self.parse_optional_meta(); view_item_extern_mod(ident, path, metadata, ast::DUMMY_NODE_ID) } else { self.bug("expected view item"); }; self.expect(&token::SEMI); ast::view_item { node: node, attrs: attrs, vis: vis, span: mk_sp(lo, self.last_span.hi) } } // Parses a sequence of items. Stops when it finds program // text that can't be parsed as an item // - mod_items uses extern_mod_allowed = true // - block_tail_ uses extern_mod_allowed = false fn parse_items_and_view_items(&self, first_item_attrs: ~[Attribute], mut extern_mod_allowed: bool, macros_allowed: bool) -> ParsedItemsAndViewItems { let mut attrs = vec::append(first_item_attrs, self.parse_outer_attributes()); // First, parse view items. let mut view_items : ~[ast::view_item] = ~[]; let mut items = ~[]; // I think this code would probably read better as a single // loop with a mutable three-state-variable (for extern mods, // view items, and regular items) ... except that because // of macros, I'd like to delay that entire check until later. loop { match self.parse_item_or_view_item(attrs, macros_allowed) { iovi_none(attrs) => { return ParsedItemsAndViewItems { attrs_remaining: attrs, view_items: view_items, items: items, foreign_items: ~[] } } iovi_view_item(view_item) => { match view_item.node { view_item_use(..) => { // `extern mod` must precede `use`. extern_mod_allowed = false; } view_item_extern_mod(..) if !extern_mod_allowed => { self.span_err(view_item.span, "\"extern mod\" declarations are not allowed here"); } view_item_extern_mod(..) => {} } view_items.push(view_item); } iovi_item(item) => { items.push(item); attrs = self.parse_outer_attributes(); break; } iovi_foreign_item(_) => { fail!(); } } attrs = self.parse_outer_attributes(); } // Next, parse items. loop { match self.parse_item_or_view_item(attrs, macros_allowed) { iovi_none(returned_attrs) => { attrs = returned_attrs; break } iovi_view_item(view_item) => { attrs = self.parse_outer_attributes(); self.span_err(view_item.span, "`use` and `extern mod` declarations must precede items"); } iovi_item(item) => { attrs = self.parse_outer_attributes(); items.push(item) } iovi_foreign_item(_) => { fail!(); } } } ParsedItemsAndViewItems { attrs_remaining: attrs, view_items: view_items, items: items, foreign_items: ~[] } } // Parses a sequence of foreign items. Stops when it finds program // text that can't be parsed as an item fn parse_foreign_items(&self, first_item_attrs: ~[Attribute], macros_allowed: bool) -> ParsedItemsAndViewItems { let mut attrs = vec::append(first_item_attrs, self.parse_outer_attributes()); let mut foreign_items = ~[]; loop { match self.parse_foreign_item(attrs, macros_allowed) { iovi_none(returned_attrs) => { if *self.token == token::RBRACE { attrs = returned_attrs; break } self.unexpected(); }, iovi_view_item(view_item) => { // I think this can't occur: self.span_err(view_item.span, "`use` and `extern mod` declarations must precede items"); } iovi_item(item) => { // FIXME #5668: this will occur for a macro invocation: self.span_fatal(item.span, "macros cannot expand to foreign items"); } iovi_foreign_item(foreign_item) => { foreign_items.push(foreign_item); } } attrs = self.parse_outer_attributes(); } ParsedItemsAndViewItems { attrs_remaining: attrs, view_items: ~[], items: ~[], foreign_items: foreign_items } } // Parses a source module as a crate. This is the main // entry point for the parser. pub fn parse_crate_mod(&self) -> Crate { let lo = self.span.lo; // parse the crate's inner attrs, maybe (oops) one // of the attrs of an item: let (inner, next) = self.parse_inner_attrs_and_next(); let first_item_outer_attrs = next; // parse the items inside the crate: let m = self.parse_mod_items(token::EOF, first_item_outer_attrs); ast::Crate { module: m, attrs: inner, config: self.cfg.clone(), span: mk_sp(lo, self.span.lo) } } pub fn parse_optional_str(&self) -> Option<(@str, ast::StrStyle)> { let (s, style) = match *self.token { token::LIT_STR(s) => (s, ast::CookedStr), token::LIT_STR_RAW(s, n) => (s, ast::RawStr(n)), _ => return None }; self.bump(); Some((ident_to_str(&s), style)) } pub fn parse_str(&self) -> (@str, StrStyle) { match self.parse_optional_str() { Some(s) => { s } _ => self.fatal("expected string literal") } } }