1use crate::ast::SNode;
2use crate::operators::{Associativity, BinaryOperator, Precedence, UnaryOperator};
3use harn_lexer::{Span, TokenKind};
4
5use super::error::ParserError;
6use super::expression_nodes::{self as nodes, Expression};
7use super::state::Parser;
8
9enum RangeSpelling {
10 Exclusive,
12 Inclusive,
14 LegacyTo,
16}
17
18fn binary_operator_token(op: BinaryOperator) -> TokenKind {
20 match op {
21 BinaryOperator::Pipe => TokenKind::Pipe,
22 BinaryOperator::Or => TokenKind::Or,
23 BinaryOperator::And => TokenKind::And,
24 BinaryOperator::Eq => TokenKind::Eq,
25 BinaryOperator::Neq => TokenKind::Neq,
26 BinaryOperator::Lt => TokenKind::Lt,
27 BinaryOperator::Gt => TokenKind::Gt,
28 BinaryOperator::Lte => TokenKind::Lte,
29 BinaryOperator::Gte => TokenKind::Gte,
30 BinaryOperator::In | BinaryOperator::NotIn => TokenKind::In,
31 BinaryOperator::NilCoalesce => TokenKind::NilCoal,
32 BinaryOperator::Add => TokenKind::Plus,
33 BinaryOperator::Sub => TokenKind::Minus,
34 BinaryOperator::Mul => TokenKind::Star,
35 BinaryOperator::Div => TokenKind::Slash,
36 BinaryOperator::Mod => TokenKind::Percent,
37 BinaryOperator::Pow => TokenKind::Pow,
38 }
39}
40
41impl Parser {
42 pub fn parse_single_expression(&mut self) -> Result<SNode, ParserError> {
44 self.check_token_nesting_limit()?;
45 self.skip_newlines();
46 let expr = self.parse_expression()?;
47 self.skip_newlines();
48 if !self.is_at_end() {
49 return Err(self.error("end of interpolated expression"));
50 }
51 Ok(expr)
52 }
53
54 pub(super) fn parse_nested_expression(
55 &mut self,
56 context: &'static str,
57 ) -> Result<SNode, ParserError> {
58 self.with_nesting(context, |parser| parser.parse_expression())
59 }
60
61 pub(super) fn parse_expression(&mut self) -> Result<SNode, ParserError> {
62 self.skip_newlines();
63 self.parse_precedence(self.grammar.loosest())
64 .map(|expr| *expr)
65 }
66
67 fn parse_precedence(&mut self, group: Precedence) -> Result<Expression, ParserError> {
70 match group {
71 Precedence::Ternary => self.parse_ternary(),
72 Precedence::Range => self.parse_range(),
73 Precedence::Prefix => self.parse_unary_expression(),
74 Precedence::Exponent => self.parse_exponent(),
75 Precedence::Postfix => self.parse_postfix(),
76 binary => self.parse_binary_group(binary),
77 }
78 }
79
80 fn parse_binary_group(&mut self, group: Precedence) -> Result<Expression, ParserError> {
82 debug_assert_eq!(group.associativity(), Associativity::Left);
83 let operand = self.grammar.tighter(group);
84 let mut left = self.parse_precedence(operand)?;
85 while let Some(op) = self.check_binary_operator(group) {
86 let start = left.span;
87 self.advance();
88 if op == BinaryOperator::NotIn {
89 self.advance();
90 }
91 self.skip_newlines();
92 let right = self.parse_precedence(operand)?;
93 left = nodes::binary(op, left, right, Span::merge(start, self.prev_span()));
94 }
95 Ok(left)
96 }
97
98 fn check_binary_operator(&mut self, group: Precedence) -> Option<BinaryOperator> {
101 for op in BinaryOperator::ALL {
102 if op.precedence() != group {
103 continue;
104 }
105 let found = match op {
106 BinaryOperator::In => self.check(&TokenKind::In),
107 BinaryOperator::NotIn => {
108 self.check_identifier("not") && matches!(self.peek_kind(), Some(TokenKind::In))
109 }
110 _ => {
111 let kind = binary_operator_token(op);
112 if op.continues_across_newline() {
113 self.check_skip_newlines(&kind)
114 } else {
115 self.check(&kind)
116 }
117 }
118 };
119 if found {
120 return Some(op);
121 }
122 }
123 None
124 }
125
126 fn parse_range(&mut self) -> Result<Expression, ParserError> {
128 let operand = self.grammar.tighter(Precedence::Range);
129 let left = self.parse_precedence(operand)?;
130 let Some(spelling) = self.check_range_operator()? else {
131 return Ok(left);
132 };
133 let start = left.span;
134 self.advance();
135 self.skip_newlines();
136 let right = self.parse_precedence(operand)?;
137 let inclusive = match spelling {
138 RangeSpelling::Exclusive => false,
139 RangeSpelling::Inclusive => true,
140 RangeSpelling::LegacyTo => {
141 let exclusive = self.check_identifier("exclusive");
142 if exclusive {
143 self.advance();
144 }
145 !exclusive
146 }
147 };
148 if self.check(&TokenKind::DotDot) || self.check(&TokenKind::DotDotEq) {
149 return Err(self.error("end of range; parenthesize a range used as a range bound"));
150 }
151 Ok(nodes::range(
152 left,
153 right,
154 inclusive,
155 Span::merge(start, self.prev_span()),
156 ))
157 }
158
159 fn check_range_operator(&mut self) -> Result<Option<RangeSpelling>, ParserError> {
162 if self.check_skip_newlines(&TokenKind::DotDot) {
163 return Ok(Some(RangeSpelling::Exclusive));
164 }
165 if self.check_skip_newlines(&TokenKind::DotDotEq) {
166 return Ok(Some(RangeSpelling::Inclusive));
167 }
168 if self.check_identifier("to") {
169 if self.grammar.legacy_ranges() {
170 return Ok(Some(RangeSpelling::LegacyTo));
171 }
172 return Err(ParserError::RemovedRangeSyntax {
173 span: self.current_span(),
174 });
175 }
176 Ok(None)
177 }
178
179 fn parse_ternary(&mut self) -> Result<Expression, ParserError> {
180 let condition = self.parse_precedence(self.grammar.tighter(Precedence::Ternary))?;
181 if !self.check_skip_newlines(&TokenKind::Question) {
184 return Ok(condition);
185 }
186 let start = condition.span;
187 self.advance();
188 self.skip_newlines();
189 let true_expr = self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
190 self.consume(&TokenKind::Colon, ":")?;
191 self.skip_newlines();
192 let false_expr =
193 self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
194 Ok(nodes::ternary(
195 condition,
196 true_expr,
197 false_expr,
198 Span::merge(start, self.prev_span()),
199 ))
200 }
201
202 fn parse_exponent(&mut self) -> Result<Expression, ParserError> {
205 let left = self.parse_postfix()?;
206 if !self.check_skip_newlines(&TokenKind::Pow) {
207 return Ok(left);
208 }
209 let start = left.span;
210 self.advance();
211 self.skip_newlines();
212 let right = self.with_nesting("exponent expression", |parser| {
213 parser.parse_unary_expression()
214 })?;
215 Ok(nodes::binary(
216 BinaryOperator::Pow,
217 left,
218 right,
219 Span::merge(start, self.prev_span()),
220 ))
221 }
222
223 pub(super) fn parse_unary(&mut self) -> Result<SNode, ParserError> {
224 self.parse_unary_expression().map(|expr| *expr)
225 }
226
227 fn parse_unary_expression(&mut self) -> Result<Expression, ParserError> {
228 let op = if self.check(&TokenKind::Not) {
229 UnaryOperator::Not
230 } else if self.check(&TokenKind::Minus) {
231 UnaryOperator::Neg
232 } else {
233 return self.parse_exponent();
234 };
235 let start = self.current_span();
236 self.advance();
237 let operand =
238 self.with_nesting("unary expression", |parser| parser.parse_unary_expression())?;
239 Ok(nodes::unary(
240 op,
241 operand,
242 Span::merge(start, self.prev_span()),
243 ))
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250 use crate::ast::Node;
251 use harn_lexer::Lexer;
252
253 #[test]
254 fn additive_newlines_preserve_statement_boundaries() {
255 let tokens = Lexer::new("1\n-2").tokenize().unwrap();
256 let program = Parser::new(tokens).parse().unwrap();
257 assert_eq!(program.len(), 2);
258 assert!(matches!(program[0].node, Node::IntLiteral(1)));
259 assert!(matches!(&program[1].node, Node::UnaryOp { op, operand }
260 if *op == UnaryOperator::Neg && matches!(operand.node, Node::IntLiteral(2))));
261
262 for (source, expected_op) in [
263 ("1\n+2", BinaryOperator::Add),
264 ("1-\n2", BinaryOperator::Sub),
265 ] {
266 let tokens = Lexer::new(source).tokenize().unwrap();
267 let expression = Parser::new(tokens).parse_single_expression().unwrap();
268 assert!(
269 matches!(&expression.node, Node::BinaryOp { op, left, right }
270 if *op == expected_op
271 && matches!(left.node, Node::IntLiteral(1))
272 && matches!(right.node, Node::IntLiteral(2)))
273 );
274 }
275 }
276}