Skip to main content

voltaic_parser/
support.rs

1use crate::parse;
2
3use voltaic_ast::BinaryOp;
4
5use voltaic_ast::Program;
6
7use voltaic_diag::Code;
8
9use voltaic_diag::Span;
10
11use voltaic_lexer::Keyword;
12
13use voltaic_lexer::LexError;
14
15use voltaic_lexer::Token;
16
17use voltaic_lexer::TokenKind;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct ParseError {
21  pub code: Code,
22  pub message: String,
23  pub span: Span,
24  pub help: Option<String>,
25}
26
27impl ParseError {
28  pub(crate) fn expected(message: impl Into<String>, span: Span) -> Self {
29    ParseError {
30      code: Code::ExpectedToken,
31      message: message.into(),
32      span,
33      help: None,
34    }
35  }
36
37  pub(crate) fn r#with(code: Code, message: impl Into<String>, span: Span) -> Self {
38    ParseError {
39      code,
40      message: message.into(),
41      span,
42      help: None,
43    }
44  }
45
46  pub(crate) fn with_help(
47    code: Code,
48    message: impl Into<String>,
49    help: impl Into<String>,
50    span: Span,
51  ) -> Self {
52    ParseError {
53      code,
54      message: message.into(),
55      span,
56      help: Some(help.into()),
57    }
58  }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub enum ParseFailure {
63  Lex(LexError),
64  Parse(Vec<ParseError>),
65}
66#[allow(unused_imports)]
67use ParseFailure::*;
68
69pub const MAX_NESTING: usize = 16;
70
71pub(crate) fn nesting_depth(toks: &[Token]) -> usize {
72  let mut depth: usize = 0;
73  let mut deepest: usize = 0;
74  for token in toks {
75    match token.kind {
76      TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => {
77        depth += 1;
78        deepest = deepest.max(depth);
79      }
80      TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
81        depth = depth.saturating_sub(1);
82      }
83      _ => (),
84    };
85  }
86  deepest
87}
88
89pub(crate) fn above_bitor() -> u8 {
90  let found = binary_power(&TokenKind::Or).expect("`|` is in the precedence table");
91  found.1 + 1
92}
93
94pub(crate) fn binary_power(kind: &TokenKind) -> Option<(BinaryOp, u8, u8)> {
95  let op = match kind {
96    TokenKind::Pipe => BinaryOp::Pipeline,
97    TokenKind::Coalesce => BinaryOp::Coalesce,
98    TokenKind::Kw(Keyword::Catch) => BinaryOp::Catch,
99    TokenKind::DotDot => BinaryOp::Range,
100    TokenKind::DotDotEq => BinaryOp::RangeInclusive,
101    TokenKind::OrOr => BinaryOp::Or,
102    TokenKind::AndAnd => BinaryOp::And,
103    TokenKind::EqEq => BinaryOp::Eq,
104    TokenKind::Ne => BinaryOp::Ne,
105    TokenKind::Lt => BinaryOp::Lt,
106    TokenKind::Gt => BinaryOp::Gt,
107    TokenKind::Le => BinaryOp::Le,
108    TokenKind::Ge => BinaryOp::Ge,
109    TokenKind::Or => BinaryOp::BitOr,
110    TokenKind::Caret => BinaryOp::BitXor,
111    TokenKind::Amp => BinaryOp::BitAnd,
112    TokenKind::Shl => BinaryOp::Shl,
113    TokenKind::Shr => BinaryOp::Shr,
114    TokenKind::Plus => BinaryOp::Add,
115    TokenKind::Minus => BinaryOp::Sub,
116    TokenKind::Star => BinaryOp::Mul,
117    TokenKind::Slash => BinaryOp::Div,
118    TokenKind::Percent => BinaryOp::Rem,
119    TokenKind::Compose => BinaryOp::Compose,
120    TokenKind::ComposeBack => BinaryOp::ComposeBack,
121    _ => {
122      return None;
123    }
124  };
125  let left = op.power();
126  Some((op, left, left + 1))
127}
128
129#[cfg(test)]
130fn power(kind: TokenKind) -> u8 {
131  binary_power(&kind).expect("should have a precedence").1
132}
133
134pub(crate) const PREFIX_POWER: u8 = 25;
135
136pub fn parse_source(src: &str) -> Result<Program, ParseFailure> {
137  let toks = voltaic_lexer::lex(src).map_err(ParseFailure::Lex)?;
138  parse(&toks, src.len()).map_err(ParseFailure::Parse)
139}
140
141#[cfg(test)]
142mod __rdx_tests {
143  use super::*;
144
145  #[test]
146  fn precedence_follows_rust() {
147    assert!(power(TokenKind::Star) > power(TokenKind::Plus));
148    assert!(power(TokenKind::Plus) > power(TokenKind::Shl));
149    assert!(power(TokenKind::Shl) > power(TokenKind::Amp));
150    assert!(power(TokenKind::Amp) > power(TokenKind::Caret));
151    assert!(power(TokenKind::Caret) > power(TokenKind::Or));
152    assert!(power(TokenKind::Or) > power(TokenKind::EqEq));
153    assert!(power(TokenKind::EqEq) > power(TokenKind::AndAnd));
154    assert!(power(TokenKind::AndAnd) > power(TokenKind::OrOr));
155  }
156
157  #[test]
158  fn the_new_operators_sit_where_doc_03_places_them() {
159    assert!(power(TokenKind::Coalesce) < power(TokenKind::OrOr));
160    assert!(power(TokenKind::Pipe) < power(TokenKind::Coalesce));
161  }
162
163  #[test]
164  fn unary_and_postfix_bind_tighter_than_any_binary() {
165    assert!(crate::support::PREFIX_POWER > power(TokenKind::Star));
166  }
167
168  #[test]
169  fn binary_operators_are_left_associative() {
170    for kind in [TokenKind::Plus, TokenKind::Star, TokenKind::Pipe] {
171      let rung = binary_power(&kind).expect("should have a precedence");
172      assert_eq!(rung.2, rung.1 + 1, "{:?} should be left-associative", kind);
173    }
174  }
175
176  #[test]
177  fn a_non_operator_has_no_precedence() {
178    assert!(binary_power(&TokenKind::Ident("x".into())).is_none());
179    assert!(binary_power(&TokenKind::Newline).is_none());
180  }
181
182  #[test]
183  fn the_powers_come_from_the_operator() {
184    for kind in [
185      TokenKind::Pipe,
186      TokenKind::Coalesce,
187      TokenKind::OrOr,
188      TokenKind::EqEq,
189      TokenKind::Plus,
190      TokenKind::Percent,
191    ] {
192      let rung = binary_power(&kind).expect("should have a precedence");
193      assert_eq!(
194        rung.1,
195        rung.0.power(),
196        "{:?} reports a power of its own",
197        kind
198      );
199      assert_eq!(rung.2, rung.0.power() + 1);
200    }
201  }
202
203  #[test]
204  fn maps_tokens_to_their_operators() {
205    assert_eq!(
206      binary_power(&TokenKind::Plus).map(|pair| pair.0),
207      Some(BinaryOp::Add)
208    );
209    assert_eq!(
210      binary_power(&TokenKind::DotDot).map(|pair| pair.0),
211      Some(BinaryOp::Range),
212      "`..` is exclusive (doc 03 ยง4.2)"
213    );
214  }
215}