1use crate::ast::SNode;
2use harn_lexer::{Span, TokenKind};
3
4use super::error::ParserError;
5use super::expression_nodes::{self as nodes, Expression};
6use super::state::Parser;
7
8impl Parser {
9 pub fn parse_single_expression(&mut self) -> Result<SNode, ParserError> {
11 self.check_token_nesting_limit()?;
12 self.skip_newlines();
13 let expr = self.parse_expression()?;
14 self.skip_newlines();
15 if !self.is_at_end() {
16 return Err(self.error("end of interpolated expression"));
17 }
18 Ok(expr)
19 }
20
21 pub(super) fn parse_nested_expression(
22 &mut self,
23 context: &'static str,
24 ) -> Result<SNode, ParserError> {
25 self.with_nesting(context, |parser| parser.parse_expression())
26 }
27
28 pub(super) fn parse_expression(&mut self) -> Result<SNode, ParserError> {
29 self.skip_newlines();
30 self.parse_pipe().map(|expr| *expr)
31 }
32
33 fn parse_pipe(&mut self) -> Result<Expression, ParserError> {
34 self.parse_binary_level(Self::parse_range, &[(TokenKind::Pipe, "|>")])
35 }
36
37 fn parse_range(&mut self) -> Result<Expression, ParserError> {
38 let left = self.parse_ternary()?;
39 if !self.check(&TokenKind::To) {
40 return Ok(left);
41 }
42 let start = left.span;
43 self.advance();
44 let right = self.parse_ternary()?;
45 let inclusive = if self.check(&TokenKind::Exclusive) {
46 self.advance();
47 false
48 } else {
49 true
50 };
51 Ok(nodes::range(
52 left,
53 right,
54 inclusive,
55 Span::merge(start, self.prev_span()),
56 ))
57 }
58
59 fn parse_ternary(&mut self) -> Result<Expression, ParserError> {
60 let condition = self.parse_logical_or()?;
61 if !self.check_skip_newlines(&TokenKind::Question) {
64 return Ok(condition);
65 }
66 let start = condition.span;
67 self.advance();
68 self.skip_newlines();
69 let true_expr = self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
70 self.consume(&TokenKind::Colon, ":")?;
71 self.skip_newlines();
72 let false_expr =
73 self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
74 Ok(nodes::ternary(
75 condition,
76 true_expr,
77 false_expr,
78 Span::merge(start, self.prev_span()),
79 ))
80 }
81
82 fn parse_logical_or(&mut self) -> Result<Expression, ParserError> {
83 self.parse_binary_level(Self::parse_logical_and, &[(TokenKind::Or, "||")])
84 }
85
86 fn parse_logical_and(&mut self) -> Result<Expression, ParserError> {
87 self.parse_binary_level(Self::parse_equality, &[(TokenKind::And, "&&")])
88 }
89
90 fn parse_equality(&mut self) -> Result<Expression, ParserError> {
91 self.parse_binary_level(
92 Self::parse_comparison,
93 &[(TokenKind::Eq, "=="), (TokenKind::Neq, "!=")],
94 )
95 }
96
97 fn parse_comparison(&mut self) -> Result<Expression, ParserError> {
98 let mut left = self.parse_additive()?;
99 loop {
100 let op = if self.check_skip_newlines(&TokenKind::Lt) {
101 "<"
102 } else if self.check_skip_newlines(&TokenKind::Gt) {
103 ">"
104 } else if self.check_skip_newlines(&TokenKind::Lte) {
105 "<="
106 } else if self.check_skip_newlines(&TokenKind::Gte) {
107 ">="
108 } else if self.check(&TokenKind::In) {
109 "in"
110 } else if self.check_identifier("not") {
111 let saved = self.pos;
112 self.advance();
113 if !self.check(&TokenKind::In) {
114 self.pos = saved;
115 break;
116 }
117 "not_in"
118 } else {
119 break;
120 };
121 let start = left.span;
122 self.advance();
123 self.skip_newlines();
124 let right = self.parse_additive()?;
125 left = nodes::binary(op, left, right, Span::merge(start, self.prev_span()));
126 }
127 Ok(left)
128 }
129
130 fn parse_additive(&mut self) -> Result<Expression, ParserError> {
131 let mut left = self.parse_nil_coalescing()?;
132 while self.check_skip_newlines(&TokenKind::Plus) || self.check(&TokenKind::Minus) {
134 let op = if self.check(&TokenKind::Plus) {
135 "+"
136 } else {
137 "-"
138 };
139 let start = left.span;
140 self.advance();
141 self.skip_newlines();
142 let right = self.parse_nil_coalescing()?;
143 left = nodes::binary(op, left, right, Span::merge(start, self.prev_span()));
144 }
145 Ok(left)
146 }
147
148 fn parse_nil_coalescing(&mut self) -> Result<Expression, ParserError> {
150 self.parse_binary_level(Self::parse_multiplicative, &[(TokenKind::NilCoal, "??")])
151 }
152
153 fn parse_multiplicative(&mut self) -> Result<Expression, ParserError> {
154 self.parse_binary_level(
155 Self::parse_unary_expression,
156 &[
157 (TokenKind::Star, "*"),
158 (TokenKind::Slash, "/"),
159 (TokenKind::Percent, "%"),
160 ],
161 )
162 }
163
164 fn parse_binary_level(
165 &mut self,
166 operand: fn(&mut Self) -> Result<Expression, ParserError>,
167 operators: &[(TokenKind, &str)],
168 ) -> Result<Expression, ParserError> {
169 let mut left = operand(self)?;
170 while let Some((_, op)) = operators
171 .iter()
172 .find(|(kind, _)| self.check_skip_newlines(kind))
173 {
174 let start = left.span;
175 self.advance();
176 self.skip_newlines();
177 let right = operand(self)?;
178 left = nodes::binary(op, left, right, Span::merge(start, self.prev_span()));
179 }
180 Ok(left)
181 }
182
183 fn parse_exponent(&mut self) -> Result<Expression, ParserError> {
186 let left = self.parse_postfix()?;
187 if !self.check_skip_newlines(&TokenKind::Pow) {
188 return Ok(left);
189 }
190 let start = left.span;
191 self.advance();
192 self.skip_newlines();
193 let right = self.with_nesting("exponent expression", |parser| {
194 parser.parse_unary_expression()
195 })?;
196 Ok(nodes::binary(
197 "**",
198 left,
199 right,
200 Span::merge(start, self.prev_span()),
201 ))
202 }
203
204 pub(super) fn parse_unary(&mut self) -> Result<SNode, ParserError> {
205 self.parse_unary_expression().map(|expr| *expr)
206 }
207
208 fn parse_unary_expression(&mut self) -> Result<Expression, ParserError> {
209 let op = if self.check(&TokenKind::Not) {
210 "!"
211 } else if self.check(&TokenKind::Minus) {
212 "-"
213 } else {
214 return self.parse_exponent();
215 };
216 let start = self.current_span();
217 self.advance();
218 let operand =
219 self.with_nesting("unary expression", |parser| parser.parse_unary_expression())?;
220 Ok(nodes::unary(
221 op,
222 operand,
223 Span::merge(start, self.prev_span()),
224 ))
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::ast::Node;
232 use harn_lexer::Lexer;
233
234 #[test]
235 fn additive_newlines_preserve_statement_boundaries() {
236 let tokens = Lexer::new("1\n-2").tokenize().unwrap();
237 let program = Parser::new(tokens).parse().unwrap();
238 assert_eq!(program.len(), 2);
239 assert!(matches!(program[0].node, Node::IntLiteral(1)));
240 assert!(matches!(&program[1].node, Node::UnaryOp { op, operand }
241 if op == "-" && matches!(operand.node, Node::IntLiteral(2))));
242
243 for (source, expected_op) in [("1\n+2", "+"), ("1-\n2", "-")] {
244 let tokens = Lexer::new(source).tokenize().unwrap();
245 let expression = Parser::new(tokens).parse_single_expression().unwrap();
246 assert!(
247 matches!(&expression.node, Node::BinaryOp { op, left, right }
248 if op == expected_op
249 && matches!(left.node, Node::IntLiteral(1))
250 && matches!(right.node, Node::IntLiteral(2)))
251 );
252 }
253 }
254}