microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
8e8577d2e6e8e35efc136f45208fea8889b769b4

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_parse/src/expr.rs

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