diff options
| author | Simonas Kazlauskas <git@kazlauskas.me> | 2015-10-15 15:51:30 +0300 |
|---|---|---|
| committer | Simonas Kazlauskas <git@kazlauskas.me> | 2015-10-27 21:55:04 +0200 |
| commit | 471f5a1f9a8bf24eff35183031ad38b9e11eeb0a (patch) | |
| tree | 01d9a1c7f23e05e0181ad624ab012d0f63143c22 | |
| parent | 540fd3aa715c8af7efb4b06b7f9ab6da398deb62 (diff) | |
| download | rust-471f5a1f9a8bf24eff35183031ad38b9e11eeb0a.tar.gz rust-471f5a1f9a8bf24eff35183031ad38b9e11eeb0a.zip | |
Generalise associative operator parsing
This commit generalises parsing of associative operators from left-associative only (with some ugly hacks to support right-associative assignment) to properly left/right-associative operators. Parsing still is not general enough to handle non-associative, non-highest-precedence prefix or non-highest-precedence postfix operators (e.g. `..` range syntax), though. That should be fixed in the future. Lastly, this commit adds support for parsing right-associative `<-` (left arrow) operator with precedence higher than assignment as the operator for placement-in feature.
| -rw-r--r-- | src/libsyntax/ast_util.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 263 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 14 | ||||
| -rw-r--r-- | src/libsyntax/util/parser.rs | 191 | ||||
| -rw-r--r-- | src/test/compile-fail/feature-gate-placement-expr.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-14084.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/removed-syntax-larrow-init.rs | 17 | ||||
| -rw-r--r-- | src/test/parse-fail/removed-syntax-larrow-move.rs | 18 |
9 files changed, 334 insertions, 194 deletions
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 8c3360512d5..f1c88232fc4 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -242,26 +242,6 @@ pub fn struct_field_visibility(field: ast::StructField) -> Visibility { } } -/// Maps a binary operator to its precedence -pub fn operator_prec(op: ast::BinOp_) -> usize { - match op { - // 'as' sits here with 12 - BiMul | BiDiv | BiRem => 11, - BiAdd | BiSub => 10, - BiShl | BiShr => 9, - BiBitAnd => 8, - BiBitXor => 7, - BiBitOr => 6, - BiLt | BiLe | BiGe | BiGt | BiEq | BiNe => 3, - BiAnd => 2, - BiOr => 1 - } -} - -/// Precedence of the `as` operator, which is a binary operator -/// not appearing in the prior table. -pub const AS_PREC: usize = 12; - pub fn empty_generics() -> Generics { Generics { lifetimes: Vec::new(), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9adef08771d..406b763ca46 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -66,6 +66,7 @@ pub mod util { #[cfg(test)] pub mod parser_testing; pub mod small_vector; + pub mod parser; } pub mod diagnostics { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e153f1665e3..f4e14a6ee36 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,7 +15,7 @@ use ast::BareFnTy; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; -use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block}; +use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; use ast::{Constness, ConstImplItem, ConstTraitItem, Crate, CrateConfig}; use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn}; @@ -60,7 +60,7 @@ use ast::{UnnamedField, UnsafeBlock}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast; -use ast_util::{self, AS_PREC, ident_to_path, operator_prec}; +use ast_util::{self, ident_to_path}; use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; use diagnostic; use ext::tt::macro_parser; @@ -73,6 +73,7 @@ use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax}; use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString}; use parse::token::{keywords, special_idents, SpecialMacroVar}; use parse::{new_sub_parser_from_file, ParseSess}; +use util::parser::{AssocOp, Fixity}; use print::pprust; use ptr::P; use owned_slice::OwnedSlice; @@ -2597,7 +2598,7 @@ impl<'a> Parser<'a> { Ok(tts) } - /// Parse a prefix-operator expr + /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> { let lo = self.span.lo; let hi; @@ -2634,8 +2635,10 @@ impl<'a> Parser<'a> { try!(self.bump()); let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let blk = try!(self.parse_block()); - hi = blk.span.hi; - let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); + let span = blk.span; + hi = span.hi; + let blk_expr = self.mk_expr(span.lo, span.hi, ExprBlock(blk)); + self.span_warn(span, "in PLACE BLOCK syntax is deprecated and will be removed soon"); ex = ExprInPlace(place, blk_expr); } token::Ident(..) if self.token.is_keyword(keywords::Box) => { @@ -2649,65 +2652,146 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo, hi, ex)); } - /// Parse an expression of binops - pub fn parse_binops(&mut self) -> PResult<P<Expr>> { - let prefix_expr = try!(self.parse_prefix_expr()); - self.parse_more_binops(prefix_expr, 0) + /// Parse an associative expression + /// + /// This parses an expression accounting for associativity and precedence of the operators in + /// the expression. + pub fn parse_assoc_expr(&mut self) -> PResult<P<Expr>> { + if self.token == token::DotDot { + // prefix-form of range notation `..expr` and `..` + // This has the precedence just higher than assignment expressions (much lower than + // other prefix expressions) to be consistent with the postfix-form `expr..` + // If it isn’t clear yet, this is a hack of the worst kind (one that also probably + // can’t be fixed anymore because stability guarantees). + let lo = self.span.lo; + let mut hi = self.span.hi; + try!(self.bump()); + let opt_end = if self.is_at_start_of_range_notation_rhs() { + // RHS must be parsed with more associativity than DotDot. + let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1; + let end = try!(self.parse_assoc_expr_with(next_prec, None)); + hi = end.span.hi; + Some(end) + } else { + None + }; + let r = self.mk_range(None, opt_end); + Ok(self.mk_expr(lo, hi, r)) + } else { + self.parse_assoc_expr_with(0, None) + } } - /// Parse an expression of binops of at least min_prec precedence - pub fn parse_more_binops(&mut self, lhs: P<Expr>, min_prec: usize) -> PResult<P<Expr>> { - if self.expr_is_complete(&*lhs) { return Ok(lhs); } - + /// Parse an associative expression with operators of at least `min_prec` precedence + pub fn parse_assoc_expr_with(&mut self, min_prec: usize, lhs: Option<P<Expr>>) -> PResult<P<Expr>> { + let mut lhs = if lhs.is_some() { + lhs.unwrap() + } else { + try!(self.parse_prefix_expr()) + }; + if self.expr_is_complete(&*lhs) && min_prec == 0 { + // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 + return Ok(lhs); + } + let cur_op_span = self.span; self.expected_tokens.push(TokenType::Operator); + while let Some(op) = AssocOp::from_token(&self.token) { + if op.precedence() < min_prec { + break; + } + try!(self.bump()); + if op.is_comparison() { + self.check_no_chained_comparison(&*lhs, &op); + } + // Special cases: + if op == AssocOp::As { + let rhs = try!(self.parse_ty_nopanic()); + lhs = self.mk_expr(lhs.span.lo, rhs.span.hi, ExprCast(lhs, rhs)); + continue + } else if op == AssocOp::DotDot { + // If we didn’t have to handle `x..`, it would be pretty easy to generalise + // here by simply doing something along the lines of + // + // break_from_this_loop_after_setting_lhs = true; + // rhs = self.parse_assoc_expr_with(op.precedence() + 1, None); + // + // We have 2 alternatives here: `x..y` and `x..` The other two variants are + // handled in `parse_assoc_expr` + let rhs = if self.is_at_start_of_range_notation_rhs() { + self.parse_assoc_expr_with(op.precedence() + 1, None).ok() + } else { + None + }; + let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs { + x.span + } else { + cur_op_span + }); + let r = self.mk_range(Some(lhs), rhs); + lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r); + break + } - let cur_op_span = self.span; - let cur_opt = self.token.to_binop(); - match cur_opt { - Some(cur_op) => { - if ast_util::is_comparison_binop(cur_op) { - self.check_no_chained_comparison(&*lhs, cur_op) - } - let cur_prec = operator_prec(cur_op); - if cur_prec >= min_prec { - try!(self.bump()); - let expr = try!(self.parse_prefix_expr()); - let rhs = try!(self.parse_more_binops(expr, cur_prec + 1)); - let lhs_span = lhs.span; - let rhs_span = rhs.span; - let binary = self.mk_binary(codemap::respan(cur_op_span, cur_op), lhs, rhs); - let bin = self.mk_expr(lhs_span.lo, rhs_span.hi, binary); - self.parse_more_binops(bin, min_prec) - } else { - Ok(lhs) + let rhs = try!(match op.fixity() { + Fixity::Right => self.parse_assoc_expr_with(op.precedence(), None), + Fixity::Left => self.parse_assoc_expr_with(op.precedence() + 1, None), + // We currently have no non-associative operators that are not handled above by + // the special cases. The code is here only for future convenience. + Fixity::None => self.parse_assoc_expr_with(op.precedence() + 1, None), + }); + + lhs = match op { + AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | + AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | + AssocOp::BitAnd | AssocOp::BitOr | AssocOp::ShiftLeft | AssocOp::ShiftRight | + AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual | + AssocOp::Greater | AssocOp::GreaterEqual => { + let ast_op = op.to_ast_binop().unwrap(); + let (lhs_span, rhs_span) = (lhs.span, rhs.span); + let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); + self.mk_expr(lhs_span.lo, rhs_span.hi, binary) } - } - None => { - if AS_PREC >= min_prec && try!(self.eat_keyword_noexpect(keywords::As) ){ - let rhs = try!(self.parse_ty_nopanic()); - let _as = self.mk_expr(lhs.span.lo, - rhs.span.hi, - ExprCast(lhs, rhs)); - self.parse_more_binops(_as, min_prec) - } else { - Ok(lhs) + AssocOp::Assign => + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)), + AssocOp::Inplace => + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprInPlace(lhs, rhs)), + AssocOp::AssignOp(k) => { + let aop = match k { + 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 + }; + let (lhs_span, rhs_span) = (lhs.span, rhs.span); + let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); + self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr) } - } + AssocOp::As | AssocOp::DotDot => self.bug("As or DotDot branch reached") + }; + + if op.fixity() == Fixity::None { break } } + Ok(lhs) } /// Produce an error if comparison operators are chained (RFC #558). /// We only need to check lhs, not rhs, because all comparison ops /// have same precedence and are left-associative - fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: ast::BinOp_) { - debug_assert!(ast_util::is_comparison_binop(outer_op)); + fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { + debug_assert!(outer_op.is_comparison()); match lhs.node { ExprBinary(op, _, _) if ast_util::is_comparison_binop(op.node) => { // respan to include both operators let op_span = mk_sp(op.span.lo, self.span.hi); self.span_err(op_span, "chained comparison operators require parentheses"); - if op.node == BiLt && outer_op == BiGt { + if op.node == BiLt && *outer_op == AssocOp::Greater { self.fileline_help(op_span, "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } @@ -2716,88 +2800,6 @@ impl<'a> Parser<'a> { } } - /// Parse an assignment expression.... - /// actually, this seems to be the main entry point for - /// parsing an arbitrary expression. - pub fn parse_assign_expr(&mut self) -> PResult<P<Expr>> { - match self.token { - token::DotDot => { - // prefix-form of range notation '..expr' - // This has the same precedence as assignment expressions - // (much lower than other prefix expressions) to be consistent - // with the postfix-form 'expr..' - let lo = self.span.lo; - let mut hi = self.span.hi; - try!(self.bump()); - let opt_end = if self.is_at_start_of_range_notation_rhs() { - let end = try!(self.parse_binops()); - hi = end.span.hi; - Some(end) - } else { - None - }; - let ex = self.mk_range(None, opt_end); - Ok(self.mk_expr(lo, hi, ex)) - } - _ => { - let lhs = try!(self.parse_binops()); - self.parse_assign_expr_with(lhs) - } - } - } - - pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> { - let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL; - let op_span = self.span; - match self.token { - token::Eq => { - try!(self.bump()); - let rhs = try!(self.parse_expr_res(restrictions)); - Ok(self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs))) - } - token::BinOpEq(op) => { - try!(self.bump()); - let rhs = try!(self.parse_expr_res(restrictions)); - 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 - }; - let rhs_span = rhs.span; - let span = lhs.span; - let assign_op = self.mk_assign_op(codemap::respan(op_span, aop), lhs, rhs); - Ok(self.mk_expr(span.lo, rhs_span.hi, assign_op)) - } - // A range expression, either `expr..expr` or `expr..`. - token::DotDot => { - let lo = lhs.span.lo; - let mut hi = self.span.hi; - try!(self.bump()); - - let opt_end = if self.is_at_start_of_range_notation_rhs() { - let end = try!(self.parse_binops()); - hi = end.span.hi; - Some(end) - } else { - None - }; - let range = self.mk_range(Some(lhs), opt_end); - return Ok(self.mk_expr(lo, hi, range)); - } - - _ => { - Ok(lhs) - } - } - } - fn is_at_start_of_range_notation_rhs(&self) -> bool { if self.token.can_begin_expr() { // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. @@ -2982,7 +2984,7 @@ impl<'a> Parser<'a> { pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult<P<Expr>> { let old = self.restrictions; self.restrictions = r; - let e = try!(self.parse_assign_expr()); + let e = try!(self.parse_assoc_expr()); self.restrictions = old; return Ok(e); } @@ -3624,8 +3626,7 @@ impl<'a> Parser<'a> { let e = self.mk_mac_expr(span.lo, span.hi, mac.and_then(|m| m.node)); let e = try!(self.parse_dot_or_call_expr_with(e)); - let e = try!(self.parse_more_binops(e, 0)); - let e = try!(self.parse_assign_expr_with(e)); + let e = try!(self.parse_assoc_expr_with(0, Some(e))); try!(self.handle_expression_like_statement( e, span, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 87cecdba28e..0bdbf132cb8 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -14,6 +14,7 @@ use abi; use ast; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast_util; +use util::parser::AssocOp; use attr; use owned_slice::OwnedSlice; use attr::{AttrMetaMethods, AttributeMethods}; @@ -445,7 +446,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { match expr.node { ast::ExprAssign(..) | ast::ExprBinary(..) | ast::ExprClosure(..) | - ast::ExprAssignOp(..) | ast::ExprCast(..) => true, + ast::ExprAssignOp(..) | ast::ExprCast(..) | + ast::ExprInPlace(..) => true, _ => false, } } @@ -1776,8 +1778,8 @@ impl<'a> State<'a> { binop: ast::BinOp) -> bool { match sub_expr.node { ast::ExprBinary(ref sub_op, _, _) => { - if ast_util::operator_prec(sub_op.node) < - ast_util::operator_prec(binop.node) { + if AssocOp::from_ast_binop(sub_op.node).precedence() < + AssocOp::from_ast_binop(binop.node).precedence() { true } else { false @@ -1802,10 +1804,10 @@ impl<'a> State<'a> { fn print_expr_in_place(&mut self, place: &ast::Expr, expr: &ast::Expr) -> io::Result<()> { - try!(self.word_space("in")); - try!(self.print_expr(place)); + try!(self.print_expr_maybe_paren(place)); try!(space(&mut self.s)); - self.print_expr(expr) + try!(self.word_space("<-")); + self.print_expr_maybe_paren(expr) } fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> io::Result<()> { diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs new file mode 100644 index 00000000000..c12cd8e89db --- /dev/null +++ b/src/libsyntax/util/parser.rs @@ -0,0 +1,191 @@ +use parse::token::{Token, BinOpToken, keywords}; +use ast; + +/// Associative operator with precedence. +/// +/// This is the enum which specifies operator precedence and fixity to the parser. +#[derive(Debug, PartialEq, Eq)] +pub enum AssocOp { + /// `+` + Add, + /// `-` + Subtract, + /// `*` + Multiply, + /// `/` + Divide, + /// `%` + Modulus, + /// `&&` + LAnd, + /// `||` + LOr, + /// `^` + BitXor, + /// `&` + BitAnd, + /// `|` + BitOr, + /// `<<` + ShiftLeft, + /// `>>` + ShiftRight, + /// `==` + Equal, + /// `<` + Less, + /// `<=` + LessEqual, + /// `!=` + NotEqual, + /// `>` + Greater, + /// `>=` + GreaterEqual, + /// `=` + Assign, + /// `<-` + Inplace, + /// `?=` where ? is one of the BinOpToken + AssignOp(BinOpToken), + /// `as` + As, + /// `..` range + DotDot +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Fixity { + /// The operator is left-associative + Left, + /// The operator is right-associative + Right, + /// The operator is not associative + None +} + +impl AssocOp { + /// Create a new AssocOP from a token + pub fn from_token(t: &Token) -> Option<AssocOp> { + use self::AssocOp::*; + match *t { + Token::BinOpEq(k) => Some(AssignOp(k)), + Token::LArrow => Some(Inplace), + Token::Eq => Some(Assign), + Token::BinOp(BinOpToken::Star) => Some(Multiply), + Token::BinOp(BinOpToken::Slash) => Some(Divide), + Token::BinOp(BinOpToken::Percent) => Some(Modulus), + Token::BinOp(BinOpToken::Plus) => Some(Add), + Token::BinOp(BinOpToken::Minus) => Some(Subtract), + Token::BinOp(BinOpToken::Shl) => Some(ShiftLeft), + Token::BinOp(BinOpToken::Shr) => Some(ShiftRight), + Token::BinOp(BinOpToken::And) => Some(BitAnd), + Token::BinOp(BinOpToken::Caret) => Some(BitXor), + Token::BinOp(BinOpToken::Or) => Some(BitOr), + Token::Lt => Some(Less), + Token::Le => Some(LessEqual), + Token::Ge => Some(GreaterEqual), + Token::Gt => Some(Greater), + Token::EqEq => Some(Equal), + Token::Ne => Some(NotEqual), + Token::AndAnd => Some(LAnd), + Token::OrOr => Some(LOr), + Token::DotDot => Some(DotDot), + _ if t.is_keyword(keywords::As) => Some(As), + _ => None + } + } + + /// Create a new AssocOp from ast::BinOp_. + pub fn from_ast_binop(op: ast::BinOp_) -> Self { + use self::AssocOp::*; + match op { + ast::BiLt => Less, + ast::BiGt => Greater, + ast::BiLe => LessEqual, + ast::BiGe => GreaterEqual, + ast::BiEq => Equal, + ast::BiNe => NotEqual, + ast::BiMul => Multiply, + ast::BiDiv => Divide, + ast::BiRem => Modulus, + ast::BiAdd => Add, + ast::BiSub => Subtract, + ast::BiShl => ShiftLeft, + ast::BiShr => ShiftRight, + ast::BiBitAnd => BitAnd, + ast::BiBitXor => BitXor, + ast::BiBitOr => BitOr, + ast::BiAnd => LAnd, + ast::BiOr => LOr + } + } + + /// Gets the precedence of this operator + pub fn precedence(&self) -> usize { + use self::AssocOp::*; + match *self { + As => 14, + Multiply | Divide | Modulus => 13, + Add | Subtract => 12, + ShiftLeft | ShiftRight => 11, + BitAnd => 10, + BitXor => 9, + BitOr => 8, + Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, + LAnd => 6, + LOr => 5, + DotDot => 4, + Inplace => 3, + Assign | AssignOp(_) => 2, + } + } + + /// Gets the fixity of this operator + pub fn fixity(&self) -> Fixity { + use self::AssocOp::*; + // NOTE: it is a bug to have an operators that has same precedence but different fixities! + match *self { + Inplace | Assign | AssignOp(_) => Fixity::Right, + As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | + BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | + LAnd | LOr => Fixity::Left, + DotDot => Fixity::None + } + } + + pub fn is_comparison(&self) -> bool { + use self::AssocOp::*; + match *self { + Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, + Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | + ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot => false + } + } + + pub fn to_ast_binop(&self) -> Option<ast::BinOp_> { + use self::AssocOp::*; + match *self { + Less => Some(ast::BiLt), + Greater => Some(ast::BiGt), + LessEqual => Some(ast::BiLe), + GreaterEqual => Some(ast::BiGe), + Equal => Some(ast::BiEq), + NotEqual => Some(ast::BiNe), + Multiply => Some(ast::BiMul), + Divide => Some(ast::BiDiv), + Modulus => Some(ast::BiRem), + Add => Some(ast::BiAdd), + Subtract => Some(ast::BiSub), + ShiftLeft => Some(ast::BiShl), + ShiftRight => Some(ast::BiShr), + BitAnd => Some(ast::BiBitAnd), + BitXor => Some(ast::BiBitXor), + BitOr => Some(ast::BiBitOr), + LAnd => Some(ast::BiAnd), + LOr => Some(ast::BiOr), + Inplace | Assign | AssignOp(_) | As | DotDot => None + } + } + +} diff --git a/src/test/compile-fail/feature-gate-placement-expr.rs b/src/test/compile-fail/feature-gate-placement-expr.rs index 47a25bf637c..080364c0855 100644 --- a/src/test/compile-fail/feature-gate-placement-expr.rs +++ b/src/test/compile-fail/feature-gate-placement-expr.rs @@ -19,6 +19,6 @@ fn main() { use std::boxed::HEAP; - let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental + let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental println!("x: {}", x); } diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index 6b19cb0b68f..8cbec549dda 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -12,6 +12,6 @@ #![feature(placement_in_syntax)] fn main() { - in () { 0 }; + () <- 0; //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented } diff --git a/src/test/parse-fail/removed-syntax-larrow-init.rs b/src/test/parse-fail/removed-syntax-larrow-init.rs deleted file mode 100644 index 1388f8745df..00000000000 --- a/src/test/parse-fail/removed-syntax-larrow-init.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -fn removed_moves() { - let mut x = 0; - let y <- x; - //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `<-` -} diff --git a/src/test/parse-fail/removed-syntax-larrow-move.rs b/src/test/parse-fail/removed-syntax-larrow-move.rs deleted file mode 100644 index 0736e483a49..00000000000 --- a/src/test/parse-fail/removed-syntax-larrow-move.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -fn removed_moves() { - let mut x = 0; - let y = 0; - y <- x; - //~^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `<-` -} |
