microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
eb3781450bbbcf238227980dfb7206fa40de10f0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_parse/src/expr.rs

729lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Expression parsing makes use of Pratt parsing (or “top-down operator-precedence parsing”) to handle
5//! relative precedence of operators.
6
7#[cfg(test)]
8mod tests;
9
10use crate::{
11 keyword::Keyword,
12 lex::{
13 ClosedBinOp, Delim, InterpolatedEnding, InterpolatedStart, Radix, StringToken, Token,
14 TokenKind,
15 },
16 prim::{ident, opt, pat, path, seq, shorten, token},
17 scan::Scanner,
18 stmt, Error, ErrorKind, Result,
19};
20use num_bigint::BigInt;
21use num_traits::Num;
22use qsc_ast::ast::{
23 self, BinOp, CallableKind, Expr, ExprKind, Functor, Lit, NodeId, Pat, PatKind, Pauli,
24 StringComponent, TernOp, UnOp,
25};
26use qsc_data_structures::span::Span;
27use std::{result, str::FromStr};
28
29struct PrefixOp {
30 kind: UnOp,
31 precedence: u8,
32}
33
34struct MixfixOp {
35 kind: OpKind,
36 precedence: u8,
37}
38
39enum OpKind {
40 Postfix(UnOp),
41 Binary(BinOp, Assoc),
42 Ternary(TernOp, TokenKind, Assoc),
43 Rich(fn(&mut Scanner, Box<Expr>) -> Result<Box<ExprKind>>),
44}
45
46#[derive(Clone, Copy)]
47enum OpName {
48 Token(TokenKind),
49 Keyword(Keyword),
50}
51
52#[derive(Clone, Copy)]
53enum OpContext {
54 Precedence(u8),
55 Stmt,
56}
57
58#[derive(Clone, Copy)]
59enum Assoc {
60 Left,
61 Right,
62}
63
64const LAMBDA_PRECEDENCE: u8 = 1;
65
66const RANGE_PRECEDENCE: u8 = 1;
67
68pub(super) fn expr(s: &mut Scanner) -> Result<Box<Expr>> {
69 expr_op(s, OpContext::Precedence(0))
70}
71
72pub(super) fn expr_eof(s: &mut Scanner) -> Result<Box<Expr>> {
73 let expr = expr(s)?;
74 token(s, TokenKind::Eof)?;
75 Ok(expr)
76}
77
78pub(super) fn expr_stmt(s: &mut Scanner) -> Result<Box<Expr>> {
79 expr_op(s, OpContext::Stmt)
80}
81
82/// Returns true if the expression kind is statement-final. When a statement-final expression occurs
83/// at the top level of an expression statement, it indicates the end of the statement, and any
84/// operators following it will not be parsed as part of the expression. Statement-final expressions
85/// in a top level position also do not require a semicolon when they are followed by another
86/// statement.
87pub(super) fn is_stmt_final(kind: &ExprKind) -> bool {
88 matches!(
89 kind,
90 ExprKind::Block(..)
91 | ExprKind::Conjugate(..)
92 | ExprKind::For(..)
93 | ExprKind::If(..)
94 | ExprKind::Repeat(..)
95 | ExprKind::While(..)
96 )
97}
98
99fn expr_op(s: &mut Scanner, context: OpContext) -> Result<Box<Expr>> {
100 let lo = s.peek().span.lo;
101 let mut lhs = if let Some(op) = prefix_op(op_name(s)) {
102 s.advance();
103 let rhs = expr_op(s, OpContext::Precedence(op.precedence))?;
104 Box::new(Expr {
105 id: NodeId::default(),
106 span: s.span(lo),
107 kind: Box::new(ExprKind::UnOp(op.kind, rhs)),
108 })
109 } else {
110 expr_base(s)?
111 };
112
113 let min_precedence = match context {
114 OpContext::Precedence(p) => p,
115 OpContext::Stmt if is_stmt_final(&lhs.kind) => return Ok(lhs),
116 OpContext::Stmt => 0,
117 };
118
119 while let Some(op) = mixfix_op(op_name(s)) {
120 if op.precedence < min_precedence {
121 break;
122 }
123
124 s.advance();
125 let kind = match op.kind {
126 OpKind::Postfix(kind) => Box::new(ExprKind::UnOp(kind, lhs)),
127 OpKind::Binary(kind, assoc) => {
128 let precedence = next_precedence(op.precedence, assoc);
129 let rhs = expr_op(s, OpContext::Precedence(precedence))?;
130 Box::new(ExprKind::BinOp(kind, lhs, rhs))
131 }
132 OpKind::Ternary(kind, delim, assoc) => {
133 let mid = expr(s)?;
134 token(s, delim)?;
135 let precedence = next_precedence(op.precedence, assoc);
136 let rhs = expr_op(s, OpContext::Precedence(precedence))?;
137 Box::new(ExprKind::TernOp(kind, lhs, mid, rhs))
138 }
139 OpKind::Rich(f) => f(s, lhs)?,
140 };
141
142 lhs = Box::new(Expr {
143 id: NodeId::default(),
144 span: s.span(lo),
145 kind,
146 });
147 }
148
149 Ok(lhs)
150}
151
152fn expr_base(s: &mut Scanner) -> Result<Box<Expr>> {
153 let lo = s.peek().span.lo;
154 let kind = if token(s, TokenKind::Open(Delim::Paren)).is_ok() {
155 let (exprs, final_sep) = seq(s, expr)?;
156 token(s, TokenKind::Close(Delim::Paren))?;
157 Ok(Box::new(final_sep.reify(
158 exprs,
159 ExprKind::Paren,
160 ExprKind::Tuple,
161 )))
162 } else if token(s, TokenKind::DotDotDot).is_ok() {
163 expr_range_prefix(s)
164 } else if token(s, TokenKind::Keyword(Keyword::Underscore)).is_ok() {
165 Ok(Box::new(ExprKind::Hole))
166 } else if token(s, TokenKind::Keyword(Keyword::Fail)).is_ok() {
167 Ok(Box::new(ExprKind::Fail(expr(s)?)))
168 } else if token(s, TokenKind::Keyword(Keyword::For)).is_ok() {
169 let vars = pat(s)?;
170 token(s, TokenKind::Keyword(Keyword::In))?;
171 let iter = expr(s)?;
172 let body = stmt::parse_block(s)?;
173 Ok(Box::new(ExprKind::For(vars, iter, body)))
174 } else if token(s, TokenKind::Keyword(Keyword::If)).is_ok() {
175 expr_if(s)
176 } else if let Some(components) = opt(s, expr_interpolate)? {
177 Ok(Box::new(ExprKind::Interpolate(
178 components.into_boxed_slice(),
179 )))
180 } else if token(s, TokenKind::Keyword(Keyword::Repeat)).is_ok() {
181 let body = stmt::parse_block(s)?;
182 token(s, TokenKind::Keyword(Keyword::Until))?;
183 let cond = expr(s)?;
184 let fixup = if token(s, TokenKind::Keyword(Keyword::Fixup)).is_ok() {
185 Some(stmt::parse_block(s)?)
186 } else {
187 None
188 };
189 Ok(Box::new(ExprKind::Repeat(body, cond, fixup)))
190 } else if token(s, TokenKind::Keyword(Keyword::Return)).is_ok() {
191 Ok(Box::new(ExprKind::Return(expr(s)?)))
192 } else if token(s, TokenKind::Keyword(Keyword::Set)).is_ok() {
193 expr_set(s)
194 } else if token(s, TokenKind::Keyword(Keyword::While)).is_ok() {
195 Ok(Box::new(ExprKind::While(expr(s)?, stmt::parse_block(s)?)))
196 } else if token(s, TokenKind::Keyword(Keyword::Within)).is_ok() {
197 let outer = stmt::parse_block(s)?;
198 token(s, TokenKind::Keyword(Keyword::Apply))?;
199 let inner = stmt::parse_block(s)?;
200 Ok(Box::new(ExprKind::Conjugate(outer, inner)))
201 } else if let Some(a) = opt(s, expr_array)? {
202 Ok(a)
203 } else if let Some(b) = opt(s, stmt::parse_block)? {
204 Ok(Box::new(ExprKind::Block(b)))
205 } else if let Some(l) = lit(s)? {
206 Ok(Box::new(ExprKind::Lit(Box::new(l))))
207 } else if let Some(p) = opt(s, path)? {
208 Ok(Box::new(ExprKind::Path(p)))
209 } else {
210 Err(Error(ErrorKind::Rule(
211 "expression",
212 s.peek().kind,
213 s.peek().span,
214 )))
215 }?;
216
217 Ok(Box::new(Expr {
218 id: NodeId::default(),
219 span: s.span(lo),
220 kind,
221 }))
222}
223
224fn expr_if(s: &mut Scanner) -> Result<Box<ExprKind>> {
225 let cond = expr(s)?;
226 let body = stmt::parse_block(s)?;
227 let lo = s.peek().span.lo;
228
229 let otherwise = if token(s, TokenKind::Keyword(Keyword::Elif)).is_ok() {
230 Some(expr_if(s)?)
231 } else if token(s, TokenKind::Keyword(Keyword::Else)).is_ok() {
232 Some(Box::new(ExprKind::Block(stmt::parse_block(s)?)))
233 } else {
234 None
235 }
236 .map(|kind| {
237 Box::new(Expr {
238 id: NodeId::default(),
239 span: s.span(lo),
240 kind,
241 })
242 });
243
244 Ok(Box::new(ExprKind::If(cond, body, otherwise)))
245}
246
247fn expr_set(s: &mut Scanner) -> Result<Box<ExprKind>> {
248 let lhs = expr(s)?;
249 if token(s, TokenKind::Eq).is_ok() {
250 let rhs = expr(s)?;
251 Ok(Box::new(ExprKind::Assign(lhs, rhs)))
252 } else if token(s, TokenKind::WSlashEq).is_ok() {
253 let index = expr(s)?;
254 token(s, TokenKind::LArrow)?;
255 let rhs = expr(s)?;
256 Ok(Box::new(ExprKind::AssignUpdate(lhs, index, rhs)))
257 } else if let TokenKind::BinOpEq(op) = s.peek().kind {
258 s.advance();
259 let rhs = expr(s)?;
260 Ok(Box::new(ExprKind::AssignOp(closed_bin_op(op), lhs, rhs)))
261 } else {
262 Err(Error(ErrorKind::Rule(
263 "assignment operator",
264 s.peek().kind,
265 s.peek().span,
266 )))
267 }
268}
269
270fn expr_array(s: &mut Scanner) -> Result<Box<ExprKind>> {
271 token(s, TokenKind::Open(Delim::Bracket))?;
272 let kind = expr_array_core(s)?;
273 token(s, TokenKind::Close(Delim::Bracket))?;
274 Ok(kind)
275}
276
277fn expr_array_core(s: &mut Scanner) -> Result<Box<ExprKind>> {
278 let Some(first) = opt(s, expr)? else {
279 return Ok(Box::new(ExprKind::Array(Vec::new().into_boxed_slice())));
280 };
281
282 if token(s, TokenKind::Comma).is_err() {
283 return Ok(Box::new(ExprKind::Array(vec![first].into_boxed_slice())));
284 }
285
286 let second = expr(s)?;
287 if is_ident("size", &second.kind) && token(s, TokenKind::Eq).is_ok() {
288 let size = expr(s)?;
289 return Ok(Box::new(ExprKind::ArrayRepeat(first, size)));
290 }
291
292 let mut items = vec![first, second];
293 if token(s, TokenKind::Comma).is_ok() {
294 items.append(&mut seq(s, expr)?.0);
295 }
296 Ok(Box::new(ExprKind::Array(items.into_boxed_slice())))
297}
298
299fn is_ident(name: &str, kind: &ExprKind) -> bool {
300 matches!(kind, ExprKind::Path(path) if path.namespace.is_none() && path.name.name.as_ref() == name)
301}
302
303fn expr_range_prefix(s: &mut Scanner) -> Result<Box<ExprKind>> {
304 let e = opt(s, |s| {
305 expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))
306 })?;
307
308 Ok(Box::new(if token(s, TokenKind::DotDotDot).is_ok() {
309 ExprKind::Range(None, e, None)
310 } else if token(s, TokenKind::DotDot).is_ok() {
311 let end = expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))?;
312 ExprKind::Range(None, e, Some(end))
313 } else {
314 ExprKind::Range(None, None, e)
315 }))
316}
317
318fn expr_interpolate(s: &mut Scanner) -> Result<Vec<StringComponent>> {
319 let token = s.peek();
320 let TokenKind::String(StringToken::Interpolated(InterpolatedStart::DollarQuote, mut end)) =
321 token.kind
322 else {
323 return Err(Error(ErrorKind::Rule(
324 "interpolated string",
325 token.kind,
326 token.span,
327 )));
328 };
329
330 let mut components = Vec::new();
331 let lit = shorten(2, 1, s.read());
332 if !lit.is_empty() {
333 components.push(StringComponent::Lit(lit.into()));
334 }
335
336 s.advance();
337 while end == InterpolatedEnding::LBrace {
338 components.push(StringComponent::Expr(expr(s)?));
339
340 let token = s.peek();
341 let TokenKind::String(StringToken::Interpolated(InterpolatedStart::RBrace, next_end)) =
342 token.kind
343 else {
344 return Err(Error(ErrorKind::Rule(
345 "interpolated string",
346 token.kind,
347 token.span,
348 )));
349 };
350
351 let lit = shorten(1, 1, s.read());
352 if !lit.is_empty() {
353 components.push(StringComponent::Lit(lit.into()));
354 }
355
356 s.advance();
357 end = next_end;
358 }
359
360 Ok(components)
361}
362
363fn lit(s: &mut Scanner) -> Result<Option<Lit>> {
364 let lexeme = s.read();
365 let token = s.peek();
366 match lit_token(lexeme, token) {
367 Ok(Some(lit)) => {
368 s.advance();
369 Ok(Some(lit))
370 }
371 Ok(None) => Ok(None),
372 Err(err) => {
373 s.advance();
374 Err(err)
375 }
376 }
377}
378
379#[allow(clippy::inline_always)]
380#[inline(always)]
381fn lit_token(lexeme: &str, token: Token) -> Result<Option<Lit>> {
382 match token.kind {
383 TokenKind::BigInt(radix) => {
384 let offset = if radix == Radix::Decimal { 0 } else { 2 };
385 let lexeme = &lexeme[offset..lexeme.len() - 1]; // Slice off prefix and suffix.
386 let value = BigInt::from_str_radix(lexeme, radix.into())
387 .map_err(|_| Error(ErrorKind::Lit("big-integer", token.span)))?;
388 Ok(Some(Lit::BigInt(Box::new(value))))
389 }
390 TokenKind::Float => {
391 let lexeme = lexeme.replace('_', "");
392 let value = lexeme
393 .parse()
394 .map_err(|_| Error(ErrorKind::Lit("floating-point", token.span)))?;
395 Ok(Some(Lit::Double(value)))
396 }
397 TokenKind::Int(radix) => {
398 let offset = if radix == Radix::Decimal { 0 } else { 2 };
399 let value = lit_int(&lexeme[offset..], radix.into())
400 .ok_or(Error(ErrorKind::Lit("integer", token.span)))?;
401 Ok(Some(Lit::Int(value)))
402 }
403 TokenKind::String(StringToken::Normal) => {
404 let lexeme = shorten(1, 1, lexeme);
405 let string = unescape(lexeme).map_err(|index| {
406 let ch = lexeme[index + 1..]
407 .chars()
408 .next()
409 .expect("character should be found at index");
410 let index: u32 = index.try_into().expect("index should fit into u32");
411 let lo = token.span.lo + index + 2;
412 let span = Span { lo, hi: lo + 1 };
413 Error(ErrorKind::Escape(ch, span))
414 })?;
415 Ok(Some(Lit::String(string.into())))
416 }
417 TokenKind::Keyword(Keyword::True) => Ok(Some(Lit::Bool(true))),
418 TokenKind::Keyword(Keyword::Zero) => Ok(Some(Lit::Result(ast::Result::Zero))),
419 TokenKind::Keyword(Keyword::One) => Ok(Some(Lit::Result(ast::Result::One))),
420 TokenKind::Keyword(Keyword::PauliZ) => Ok(Some(Lit::Pauli(Pauli::Z))),
421 TokenKind::Keyword(Keyword::False) => Ok(Some(Lit::Bool(false))),
422 TokenKind::Keyword(Keyword::PauliX) => Ok(Some(Lit::Pauli(Pauli::X))),
423 TokenKind::Keyword(Keyword::PauliI) => Ok(Some(Lit::Pauli(Pauli::I))),
424 TokenKind::Keyword(Keyword::PauliY) => Ok(Some(Lit::Pauli(Pauli::Y))),
425 _ => Ok(None),
426 }
427}
428
429fn lit_int(lexeme: &str, radix: u32) -> Option<i64> {
430 let multiplier = i64::from(radix);
431 lexeme
432 .chars()
433 .filter(|&c| c != '_')
434 .try_rfold((0i64, 1i64, false), |(value, place, overflow), c| {
435 if overflow {
436 return None;
437 }
438 let (increment, false) = i64::from(c.to_digit(radix)?).overflowing_mul(place) else {
439 return None;
440 };
441 let (new_value, overflow) = value.overflowing_add(increment);
442 // Only treat as overflow if the value is not i64::MIN, since we need to allow once special
443 // case of overflow to allow for minimum value literals.
444 if overflow && new_value != i64::MIN {
445 return None;
446 }
447 let (new_place, overflow) = place.overflowing_mul(multiplier);
448
449 // If the place overflows, we can still accept the value as long as it's the last digit.
450 // Pass the overflow forward so that it fails if there are more digits.
451 Some((new_value, new_place, overflow))
452 })
453 .map(|(value, _, _)| value)
454}
455
456fn prefix_op(name: OpName) -> Option<PrefixOp> {
457 match name {
458 OpName::Keyword(Keyword::Not) => Some(PrefixOp {
459 kind: UnOp::NotL,
460 precedence: 11,
461 }),
462 OpName::Token(TokenKind::TildeTildeTilde) => Some(PrefixOp {
463 kind: UnOp::NotB,
464 precedence: 11,
465 }),
466 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Plus)) => Some(PrefixOp {
467 kind: UnOp::Pos,
468 precedence: 11,
469 }),
470 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Minus)) => Some(PrefixOp {
471 kind: UnOp::Neg,
472 precedence: 11,
473 }),
474 OpName::Keyword(Keyword::AdjointUpper) => Some(PrefixOp {
475 kind: UnOp::Functor(Functor::Adj),
476 precedence: 14,
477 }),
478 OpName::Keyword(Keyword::ControlledUpper) => Some(PrefixOp {
479 kind: UnOp::Functor(Functor::Ctl),
480 precedence: 14,
481 }),
482 _ => None,
483 }
484}
485
486#[allow(clippy::too_many_lines)]
487fn mixfix_op(name: OpName) -> Option<MixfixOp> {
488 match name {
489 OpName::Token(TokenKind::RArrow) => Some(MixfixOp {
490 kind: OpKind::Rich(|s, input| lambda_op(s, *input, CallableKind::Function)),
491 precedence: LAMBDA_PRECEDENCE,
492 }),
493 OpName::Token(TokenKind::FatArrow) => Some(MixfixOp {
494 kind: OpKind::Rich(|s, input| lambda_op(s, *input, CallableKind::Operation)),
495 precedence: LAMBDA_PRECEDENCE,
496 }),
497 OpName::Token(TokenKind::DotDot) => Some(MixfixOp {
498 kind: OpKind::Rich(range_op),
499 precedence: RANGE_PRECEDENCE,
500 }),
501 OpName::Token(TokenKind::DotDotDot) => Some(MixfixOp {
502 kind: OpKind::Rich(|_, start| Ok(Box::new(ExprKind::Range(Some(start), None, None)))),
503 precedence: RANGE_PRECEDENCE,
504 }),
505 OpName::Token(TokenKind::WSlash) => Some(MixfixOp {
506 kind: OpKind::Ternary(TernOp::Update, TokenKind::LArrow, Assoc::Left),
507 precedence: 1,
508 }),
509 OpName::Token(TokenKind::Question) => Some(MixfixOp {
510 kind: OpKind::Ternary(TernOp::Cond, TokenKind::Bar, Assoc::Right),
511 precedence: 1,
512 }),
513 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Or)) => Some(MixfixOp {
514 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Or), Assoc::Left),
515 precedence: 2,
516 }),
517 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::And)) => Some(MixfixOp {
518 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::And), Assoc::Left),
519 precedence: 3,
520 }),
521 OpName::Token(TokenKind::EqEq) => Some(MixfixOp {
522 kind: OpKind::Binary(BinOp::Eq, Assoc::Left),
523 precedence: 4,
524 }),
525 OpName::Token(TokenKind::Ne) => Some(MixfixOp {
526 kind: OpKind::Binary(BinOp::Neq, Assoc::Left),
527 precedence: 4,
528 }),
529 OpName::Token(TokenKind::Gt) => Some(MixfixOp {
530 kind: OpKind::Binary(BinOp::Gt, Assoc::Left),
531 precedence: 4,
532 }),
533 OpName::Token(TokenKind::Gte) => Some(MixfixOp {
534 kind: OpKind::Binary(BinOp::Gte, Assoc::Left),
535 precedence: 4,
536 }),
537 OpName::Token(TokenKind::Lt) => Some(MixfixOp {
538 kind: OpKind::Binary(BinOp::Lt, Assoc::Left),
539 precedence: 4,
540 }),
541 OpName::Token(TokenKind::Lte) => Some(MixfixOp {
542 kind: OpKind::Binary(BinOp::Lte, Assoc::Left),
543 precedence: 4,
544 }),
545 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::BarBarBar)) => Some(MixfixOp {
546 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::BarBarBar), Assoc::Left),
547 precedence: 5,
548 }),
549 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::CaretCaretCaret)) => Some(MixfixOp {
550 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::CaretCaretCaret), Assoc::Left),
551 precedence: 6,
552 }),
553 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::AmpAmpAmp)) => Some(MixfixOp {
554 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::AmpAmpAmp), Assoc::Left),
555 precedence: 7,
556 }),
557 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::LtLtLt)) => Some(MixfixOp {
558 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::LtLtLt), Assoc::Left),
559 precedence: 8,
560 }),
561 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::GtGtGt)) => Some(MixfixOp {
562 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::GtGtGt), Assoc::Left),
563 precedence: 8,
564 }),
565 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Plus)) => Some(MixfixOp {
566 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Plus), Assoc::Left),
567 precedence: 9,
568 }),
569 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Minus)) => Some(MixfixOp {
570 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Minus), Assoc::Left),
571 precedence: 9,
572 }),
573 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Star)) => Some(MixfixOp {
574 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Star), Assoc::Left),
575 precedence: 10,
576 }),
577 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Slash)) => Some(MixfixOp {
578 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Slash), Assoc::Left),
579 precedence: 10,
580 }),
581 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Percent)) => Some(MixfixOp {
582 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Percent), Assoc::Left),
583 precedence: 10,
584 }),
585 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Caret)) => Some(MixfixOp {
586 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Caret), Assoc::Right),
587 precedence: 12,
588 }),
589 OpName::Token(TokenKind::Open(Delim::Paren)) => Some(MixfixOp {
590 kind: OpKind::Rich(call_op),
591 precedence: 13,
592 }),
593 OpName::Token(TokenKind::Bang) => Some(MixfixOp {
594 kind: OpKind::Postfix(UnOp::Unwrap),
595 precedence: 15,
596 }),
597 OpName::Token(TokenKind::ColonColon) => Some(MixfixOp {
598 kind: OpKind::Rich(field_op),
599 precedence: 15,
600 }),
601 OpName::Token(TokenKind::Open(Delim::Bracket)) => Some(MixfixOp {
602 kind: OpKind::Rich(index_op),
603 precedence: 15,
604 }),
605 _ => None,
606 }
607}
608
609fn closed_bin_op(op: ClosedBinOp) -> BinOp {
610 match op {
611 ClosedBinOp::AmpAmpAmp => BinOp::AndB,
612 ClosedBinOp::And => BinOp::AndL,
613 ClosedBinOp::BarBarBar => BinOp::OrB,
614 ClosedBinOp::Caret => BinOp::Exp,
615 ClosedBinOp::CaretCaretCaret => BinOp::XorB,
616 ClosedBinOp::GtGtGt => BinOp::Shr,
617 ClosedBinOp::LtLtLt => BinOp::Shl,
618 ClosedBinOp::Minus => BinOp::Sub,
619 ClosedBinOp::Or => BinOp::OrL,
620 ClosedBinOp::Percent => BinOp::Mod,
621 ClosedBinOp::Plus => BinOp::Add,
622 ClosedBinOp::Slash => BinOp::Div,
623 ClosedBinOp::Star => BinOp::Mul,
624 }
625}
626
627fn lambda_op(s: &mut Scanner, input: Expr, kind: CallableKind) -> Result<Box<ExprKind>> {
628 let input = expr_as_pat(input)?;
629 let output = expr_op(s, OpContext::Precedence(LAMBDA_PRECEDENCE))?;
630 Ok(Box::new(ExprKind::Lambda(kind, input, output)))
631}
632
633fn field_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
634 Ok(Box::new(ExprKind::Field(lhs, ident(s)?)))
635}
636
637fn index_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
638 let index = expr(s)?;
639 token(s, TokenKind::Close(Delim::Bracket))?;
640 Ok(Box::new(ExprKind::Index(lhs, index)))
641}
642
643fn call_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
644 let lo = s.span(0).hi - 1;
645 let (args, final_sep) = seq(s, expr)?;
646 token(s, TokenKind::Close(Delim::Paren))?;
647 let rhs = Box::new(Expr {
648 id: NodeId::default(),
649 span: s.span(lo),
650 kind: Box::new(final_sep.reify(args, ExprKind::Paren, ExprKind::Tuple)),
651 });
652 Ok(Box::new(ExprKind::Call(lhs, rhs)))
653}
654
655fn range_op(s: &mut Scanner, start: Box<Expr>) -> Result<Box<ExprKind>> {
656 let rhs = expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))?;
657 Ok(Box::new(if token(s, TokenKind::DotDot).is_ok() {
658 let end = expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))?;
659 ExprKind::Range(Some(start), Some(rhs), Some(end))
660 } else if token(s, TokenKind::DotDotDot).is_ok() {
661 ExprKind::Range(Some(start), Some(rhs), None)
662 } else {
663 ExprKind::Range(Some(start), None, Some(rhs))
664 }))
665}
666
667fn op_name(s: &Scanner) -> OpName {
668 match Keyword::from_str(s.read()) {
669 Ok(Keyword::And | Keyword::Or) | Err(_) => OpName::Token(s.peek().kind),
670 Ok(keyword) => OpName::Keyword(keyword),
671 }
672}
673
674fn next_precedence(precedence: u8, assoc: Assoc) -> u8 {
675 match assoc {
676 Assoc::Left => precedence + 1,
677 Assoc::Right => precedence,
678 }
679}
680
681fn expr_as_pat(expr: Expr) -> Result<Box<Pat>> {
682 let kind = Box::new(match *expr.kind {
683 ExprKind::Path(path) if path.namespace.is_none() => Ok(PatKind::Bind(path.name, None)),
684 ExprKind::Hole => Ok(PatKind::Discard(None)),
685 ExprKind::Range(None, None, None) => Ok(PatKind::Elided),
686 ExprKind::Paren(expr) => Ok(PatKind::Paren(expr_as_pat(*expr)?)),
687 ExprKind::Tuple(exprs) => {
688 let pats = exprs
689 .into_vec()
690 .into_iter()
691 .map(|e| expr_as_pat(*e))
692 .collect::<Result<_>>()?;
693 Ok(PatKind::Tuple(pats))
694 }
695 _ => Err(Error(ErrorKind::Convert(
696 "pattern",
697 "expression",
698 expr.span,
699 ))),
700 }?);
701
702 Ok(Box::new(Pat {
703 id: NodeId::default(),
704 span: expr.span,
705 kind,
706 }))
707}
708
709fn unescape(s: &str) -> result::Result<String, usize> {
710 let mut chars = s.char_indices();
711 let mut buf = String::with_capacity(s.len());
712 while let Some((index, ch)) = chars.next() {
713 buf.push(if ch == '\\' {
714 let escape = chars.next().expect("escape should not be empty").1;
715 match escape {
716 '\\' => '\\',
717 '"' => '"',
718 'n' => '\n',
719 'r' => '\r',
720 't' => '\t',
721 _ => return Err(index),
722 }
723 } else {
724 ch
725 });
726 }
727
728 Ok(buf)
729}
730