libslide/parser/
expression_pattern_parser.rs1use super::{extra_tokens_diag, Parser};
2use crate::common::Span;
3use crate::diagnostics::Diagnostic;
4use crate::grammar::*;
5use crate::scanner::types::Token;
6use crate::utils::{hash, PeekIter};
7
8use std::collections::HashMap;
9use std::rc::Rc;
10
11pub fn parse(input: Vec<Token>) -> (Rc<ExprPat>, Vec<Diagnostic>) {
12 let mut parser = ExpressionPatternParser::new(input);
13 (parser.parse(), parser.diagnostics)
14}
15
16pub struct ExpressionPatternParser {
17 _input: PeekIter<Token>,
18 diagnostics: Vec<Diagnostic>,
19 seen: HashMap<u64, Rc<ExprPat>>,
23}
24
25impl Parser<Rc<ExprPat>> for ExpressionPatternParser {
26 type Expr = ExprPat;
27
28 fn new(input: Vec<Token>) -> Self {
29 Self {
30 _input: PeekIter::new(input.into_iter()),
31 diagnostics: vec![],
32 seen: HashMap::new(),
33 }
34 }
35
36 fn input(&mut self) -> &mut PeekIter<Token> {
37 &mut self._input
38 }
39
40 fn push_diag(&mut self, diagnostic: Diagnostic) {
41 self.diagnostics.push(diagnostic);
42 }
43
44 fn parse(&mut self) -> Rc<ExprPat> {
45 let parsed = self.expr();
46 if !self.done() {
47 let extra_tokens_diag = extra_tokens_diag(self.input());
48 self.push_diag(extra_tokens_diag);
49 }
50 parsed
51 }
52
53 fn parse_float(&mut self, f: f64, _span: Span) -> Self::Expr {
54 Self::Expr::Const(f)
55 }
56
57 fn parse_variable(&mut self, name: String, span: Span) -> Self::Expr {
58 self.push_diag(
59 Diagnostic::span_err(
60 span,
61 "Variables cannot be used in an expression pattern",
62 Some("unexpected variable".into()),
63 )
64 .with_help(format!(
65 r##"consider using "${name}", "#{name}", or "_{name}" as a pattern"##,
66 name = name,
67 )),
68 );
69 Self::Expr::VarPat(name)
70 }
71
72 fn parse_var_pattern(&mut self, name: String, _span: Span) -> Self::Expr {
73 Self::Expr::VarPat(name)
74 }
75
76 fn parse_const_pattern(&mut self, name: String, _span: Span) -> Self::Expr {
77 Self::Expr::ConstPat(name)
78 }
79
80 fn parse_any_pattern(&mut self, name: String, _span: Span) -> Self::Expr {
81 Self::Expr::AnyPat(name)
82 }
83
84 fn finish_expr(&mut self, expr: Self::Expr) -> Rc<Self::Expr> {
85 let p = self
86 .seen
87 .entry(hash(&expr))
88 .or_insert_with(|| Rc::new(expr));
89 Rc::clone(p)
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::scan;
97
98 parser_tests! {
99 parse_expression_pattern
100
101 pattern: "$a"
102 pattern_in_op_left: "$a + 1"
103 pattern_in_op_right: "1 + $a"
104 }
105
106 #[test]
107 fn common_subexpression_elimination() {
108 let program = "$v * #c + $v * #c";
109 let tokens = scan(program).tokens;
110 let (parsed, _) = parse(tokens);
111 let (l, r) = match (*parsed).clone() {
112 ExprPat::BinaryExpr(BinaryExpr { lhs, rhs, .. }) => (lhs, rhs),
113 _ => unreachable!(),
114 };
115 assert!(std::ptr::eq(l.as_ref(), r.as_ref())); let (ll, lr, rl, rr) = match (l.as_ref(), r.as_ref()) {
118 (
119 ExprPat::BinaryExpr(BinaryExpr {
120 lhs: ll, rhs: lr, ..
121 }),
122 ExprPat::BinaryExpr(BinaryExpr {
123 lhs: rl, rhs: rr, ..
124 }),
125 ) => (ll, lr, rl, rr),
126 _ => unreachable!(),
127 };
128 assert!(std::ptr::eq(ll.as_ref(), rl.as_ref())); assert!(std::ptr::eq(lr.as_ref(), rr.as_ref())); }
131}