microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
c8adde746a7aaa0185fd4eac69af19d259ce1faa

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_frontend/src/parse/expr.rs

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