microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.0.33

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_parse/src/expr.rs

730lines · 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, mut overflow), c| {
435 let (increment, over) = i64::from(c.to_digit(radix)?).overflowing_mul(place);
436 overflow |= over;
437
438 let (new_value, over) = value.overflowing_add(increment);
439 overflow |= over;
440
441 // Only treat as overflow if the value is not i64::MIN, since we need to allow once special
442 // case of overflow to allow for minimum value literals.
443 if overflow && new_value != i64::MIN {
444 return None;
445 }
446
447 let (new_place, over) = place.overflowing_mul(multiplier);
448 overflow |= over;
449
450 // If the place overflows, we can still accept the value as long as it's the last digit.
451 // Pass the overflow forward so that it fails if there are more digits.
452 Some((new_value, new_place, overflow))
453 })
454 .map(|(value, _, _)| value)
455}
456
457fn prefix_op(name: OpName) -> Option<PrefixOp> {
458 match name {
459 OpName::Keyword(Keyword::Not) => Some(PrefixOp {
460 kind: UnOp::NotL,
461 precedence: 11,
462 }),
463 OpName::Token(TokenKind::TildeTildeTilde) => Some(PrefixOp {
464 kind: UnOp::NotB,
465 precedence: 11,
466 }),
467 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Plus)) => Some(PrefixOp {
468 kind: UnOp::Pos,
469 precedence: 11,
470 }),
471 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Minus)) => Some(PrefixOp {
472 kind: UnOp::Neg,
473 precedence: 11,
474 }),
475 OpName::Keyword(Keyword::AdjointUpper) => Some(PrefixOp {
476 kind: UnOp::Functor(Functor::Adj),
477 precedence: 14,
478 }),
479 OpName::Keyword(Keyword::ControlledUpper) => Some(PrefixOp {
480 kind: UnOp::Functor(Functor::Ctl),
481 precedence: 14,
482 }),
483 _ => None,
484 }
485}
486
487#[allow(clippy::too_many_lines)]
488fn mixfix_op(name: OpName) -> Option<MixfixOp> {
489 match name {
490 OpName::Token(TokenKind::RArrow) => Some(MixfixOp {
491 kind: OpKind::Rich(|s, input| lambda_op(s, *input, CallableKind::Function)),
492 precedence: LAMBDA_PRECEDENCE,
493 }),
494 OpName::Token(TokenKind::FatArrow) => Some(MixfixOp {
495 kind: OpKind::Rich(|s, input| lambda_op(s, *input, CallableKind::Operation)),
496 precedence: LAMBDA_PRECEDENCE,
497 }),
498 OpName::Token(TokenKind::DotDot) => Some(MixfixOp {
499 kind: OpKind::Rich(range_op),
500 precedence: RANGE_PRECEDENCE,
501 }),
502 OpName::Token(TokenKind::DotDotDot) => Some(MixfixOp {
503 kind: OpKind::Rich(|_, start| Ok(Box::new(ExprKind::Range(Some(start), None, None)))),
504 precedence: RANGE_PRECEDENCE,
505 }),
506 OpName::Token(TokenKind::WSlash) => Some(MixfixOp {
507 kind: OpKind::Ternary(TernOp::Update, TokenKind::LArrow, Assoc::Left),
508 precedence: 1,
509 }),
510 OpName::Token(TokenKind::Question) => Some(MixfixOp {
511 kind: OpKind::Ternary(TernOp::Cond, TokenKind::Bar, Assoc::Right),
512 precedence: 1,
513 }),
514 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Or)) => Some(MixfixOp {
515 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Or), Assoc::Left),
516 precedence: 2,
517 }),
518 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::And)) => Some(MixfixOp {
519 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::And), Assoc::Left),
520 precedence: 3,
521 }),
522 OpName::Token(TokenKind::EqEq) => Some(MixfixOp {
523 kind: OpKind::Binary(BinOp::Eq, Assoc::Left),
524 precedence: 4,
525 }),
526 OpName::Token(TokenKind::Ne) => Some(MixfixOp {
527 kind: OpKind::Binary(BinOp::Neq, Assoc::Left),
528 precedence: 4,
529 }),
530 OpName::Token(TokenKind::Gt) => Some(MixfixOp {
531 kind: OpKind::Binary(BinOp::Gt, Assoc::Left),
532 precedence: 4,
533 }),
534 OpName::Token(TokenKind::Gte) => Some(MixfixOp {
535 kind: OpKind::Binary(BinOp::Gte, Assoc::Left),
536 precedence: 4,
537 }),
538 OpName::Token(TokenKind::Lt) => Some(MixfixOp {
539 kind: OpKind::Binary(BinOp::Lt, Assoc::Left),
540 precedence: 4,
541 }),
542 OpName::Token(TokenKind::Lte) => Some(MixfixOp {
543 kind: OpKind::Binary(BinOp::Lte, Assoc::Left),
544 precedence: 4,
545 }),
546 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::BarBarBar)) => Some(MixfixOp {
547 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::BarBarBar), Assoc::Left),
548 precedence: 5,
549 }),
550 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::CaretCaretCaret)) => Some(MixfixOp {
551 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::CaretCaretCaret), Assoc::Left),
552 precedence: 6,
553 }),
554 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::AmpAmpAmp)) => Some(MixfixOp {
555 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::AmpAmpAmp), Assoc::Left),
556 precedence: 7,
557 }),
558 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::LtLtLt)) => Some(MixfixOp {
559 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::LtLtLt), Assoc::Left),
560 precedence: 8,
561 }),
562 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::GtGtGt)) => Some(MixfixOp {
563 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::GtGtGt), Assoc::Left),
564 precedence: 8,
565 }),
566 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Plus)) => Some(MixfixOp {
567 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Plus), Assoc::Left),
568 precedence: 9,
569 }),
570 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Minus)) => Some(MixfixOp {
571 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Minus), Assoc::Left),
572 precedence: 9,
573 }),
574 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Star)) => Some(MixfixOp {
575 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Star), Assoc::Left),
576 precedence: 10,
577 }),
578 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Slash)) => Some(MixfixOp {
579 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Slash), Assoc::Left),
580 precedence: 10,
581 }),
582 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Percent)) => Some(MixfixOp {
583 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Percent), Assoc::Left),
584 precedence: 10,
585 }),
586 OpName::Token(TokenKind::ClosedBinOp(ClosedBinOp::Caret)) => Some(MixfixOp {
587 kind: OpKind::Binary(closed_bin_op(ClosedBinOp::Caret), Assoc::Right),
588 precedence: 12,
589 }),
590 OpName::Token(TokenKind::Open(Delim::Paren)) => Some(MixfixOp {
591 kind: OpKind::Rich(call_op),
592 precedence: 13,
593 }),
594 OpName::Token(TokenKind::Bang) => Some(MixfixOp {
595 kind: OpKind::Postfix(UnOp::Unwrap),
596 precedence: 15,
597 }),
598 OpName::Token(TokenKind::ColonColon) => Some(MixfixOp {
599 kind: OpKind::Rich(field_op),
600 precedence: 15,
601 }),
602 OpName::Token(TokenKind::Open(Delim::Bracket)) => Some(MixfixOp {
603 kind: OpKind::Rich(index_op),
604 precedence: 15,
605 }),
606 _ => None,
607 }
608}
609
610fn closed_bin_op(op: ClosedBinOp) -> BinOp {
611 match op {
612 ClosedBinOp::AmpAmpAmp => BinOp::AndB,
613 ClosedBinOp::And => BinOp::AndL,
614 ClosedBinOp::BarBarBar => BinOp::OrB,
615 ClosedBinOp::Caret => BinOp::Exp,
616 ClosedBinOp::CaretCaretCaret => BinOp::XorB,
617 ClosedBinOp::GtGtGt => BinOp::Shr,
618 ClosedBinOp::LtLtLt => BinOp::Shl,
619 ClosedBinOp::Minus => BinOp::Sub,
620 ClosedBinOp::Or => BinOp::OrL,
621 ClosedBinOp::Percent => BinOp::Mod,
622 ClosedBinOp::Plus => BinOp::Add,
623 ClosedBinOp::Slash => BinOp::Div,
624 ClosedBinOp::Star => BinOp::Mul,
625 }
626}
627
628fn lambda_op(s: &mut Scanner, input: Expr, kind: CallableKind) -> Result<Box<ExprKind>> {
629 let input = expr_as_pat(input)?;
630 let output = expr_op(s, OpContext::Precedence(LAMBDA_PRECEDENCE))?;
631 Ok(Box::new(ExprKind::Lambda(kind, input, output)))
632}
633
634fn field_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
635 Ok(Box::new(ExprKind::Field(lhs, ident(s)?)))
636}
637
638fn index_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
639 let index = expr(s)?;
640 token(s, TokenKind::Close(Delim::Bracket))?;
641 Ok(Box::new(ExprKind::Index(lhs, index)))
642}
643
644fn call_op(s: &mut Scanner, lhs: Box<Expr>) -> Result<Box<ExprKind>> {
645 let lo = s.span(0).hi - 1;
646 let (args, final_sep) = seq(s, expr)?;
647 token(s, TokenKind::Close(Delim::Paren))?;
648 let rhs = Box::new(Expr {
649 id: NodeId::default(),
650 span: s.span(lo),
651 kind: Box::new(final_sep.reify(args, ExprKind::Paren, ExprKind::Tuple)),
652 });
653 Ok(Box::new(ExprKind::Call(lhs, rhs)))
654}
655
656fn range_op(s: &mut Scanner, start: Box<Expr>) -> Result<Box<ExprKind>> {
657 let rhs = expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))?;
658 Ok(Box::new(if token(s, TokenKind::DotDot).is_ok() {
659 let end = expr_op(s, OpContext::Precedence(RANGE_PRECEDENCE + 1))?;
660 ExprKind::Range(Some(start), Some(rhs), Some(end))
661 } else if token(s, TokenKind::DotDotDot).is_ok() {
662 ExprKind::Range(Some(start), Some(rhs), None)
663 } else {
664 ExprKind::Range(Some(start), None, Some(rhs))
665 }))
666}
667
668fn op_name(s: &Scanner) -> OpName {
669 match Keyword::from_str(s.read()) {
670 Ok(Keyword::And | Keyword::Or) | Err(_) => OpName::Token(s.peek().kind),
671 Ok(keyword) => OpName::Keyword(keyword),
672 }
673}
674
675fn next_precedence(precedence: u8, assoc: Assoc) -> u8 {
676 match assoc {
677 Assoc::Left => precedence + 1,
678 Assoc::Right => precedence,
679 }
680}
681
682fn expr_as_pat(expr: Expr) -> Result<Box<Pat>> {
683 let kind = Box::new(match *expr.kind {
684 ExprKind::Path(path) if path.namespace.is_none() => Ok(PatKind::Bind(path.name, None)),
685 ExprKind::Hole => Ok(PatKind::Discard(None)),
686 ExprKind::Range(None, None, None) => Ok(PatKind::Elided),
687 ExprKind::Paren(expr) => Ok(PatKind::Paren(expr_as_pat(*expr)?)),
688 ExprKind::Tuple(exprs) => {
689 let pats = exprs
690 .into_vec()
691 .into_iter()
692 .map(|e| expr_as_pat(*e))
693 .collect::<Result<_>>()?;
694 Ok(PatKind::Tuple(pats))
695 }
696 _ => Err(Error(ErrorKind::Convert(
697 "pattern",
698 "expression",
699 expr.span,
700 ))),
701 }?);
702
703 Ok(Box::new(Pat {
704 id: NodeId::default(),
705 span: expr.span,
706 kind,
707 }))
708}
709
710fn unescape(s: &str) -> result::Result<String, usize> {
711 let mut chars = s.char_indices();
712 let mut buf = String::with_capacity(s.len());
713 while let Some((index, ch)) = chars.next() {
714 buf.push(if ch == '\\' {
715 let escape = chars.next().expect("escape should not be empty").1;
716 match escape {
717 '\\' => '\\',
718 '"' => '"',
719 'n' => '\n',
720 'r' => '\r',
721 't' => '\t',
722 _ => return Err(index),
723 }
724 } else {
725 ch
726 });
727 }
728
729 Ok(buf)
730}
731