/home/noah/src/ruchy/src/frontend/parser/actors.rs
Line | Count | Source |
1 | | //! Actor system parsing |
2 | | |
3 | | use super::{ParserState, *}; |
4 | | use crate::frontend::ast::{ActorHandler, StructField}; |
5 | | |
6 | | /// # Errors |
7 | | /// |
8 | | /// Returns an error if the operation fails |
9 | | /// # Errors |
10 | | /// |
11 | | /// Returns an error if the operation fails |
12 | 0 | pub fn parse_actor(state: &mut ParserState) -> Result<Expr> { |
13 | 0 | let start_span = state.tokens.advance().expect("checked by parser logic").1; // consume actor |
14 | 0 | let name = parse_actor_name(state)?; |
15 | 0 | state.tokens.expect(&Token::LeftBrace)?; |
16 | | |
17 | 0 | let (state_fields, handlers) = parse_actor_body(state)?; |
18 | 0 | state.tokens.expect(&Token::RightBrace)?; |
19 | | |
20 | 0 | Ok(Expr::new( |
21 | 0 | ExprKind::Actor { |
22 | 0 | name, |
23 | 0 | state: state_fields, |
24 | 0 | handlers, |
25 | 0 | }, |
26 | 0 | start_span, |
27 | 0 | )) |
28 | 0 | } |
29 | | |
30 | | // Helper: Parse actor name (complexity: 2) |
31 | 0 | fn parse_actor_name(state: &mut ParserState) -> Result<String> { |
32 | 0 | if let Some((Token::Identifier(n), _)) = state.tokens.peek() { |
33 | 0 | let name = n.clone(); |
34 | 0 | state.tokens.advance(); |
35 | 0 | Ok(name) |
36 | | } else { |
37 | 0 | bail!("Expected actor name"); |
38 | | } |
39 | 0 | } |
40 | | |
41 | | // Helper: Parse actor body (complexity: 4) |
42 | 0 | fn parse_actor_body(state: &mut ParserState) -> Result<(Vec<StructField>, Vec<ActorHandler>)> { |
43 | 0 | let mut state_fields = Vec::new(); |
44 | 0 | let mut handlers = Vec::new(); |
45 | | |
46 | 0 | while !matches!(state.tokens.peek(), Some((Token::RightBrace, _))) { |
47 | 0 | if matches!(state.tokens.peek(), Some((Token::State, _))) { |
48 | 0 | parse_state_block(state, &mut state_fields)?; |
49 | 0 | } else if matches!(state.tokens.peek(), Some((Token::Receive, _))) { |
50 | 0 | parse_receive_handler(state, &mut handlers)?; |
51 | | } else { |
52 | 0 | parse_inline_state_field(state, &mut state_fields)?; |
53 | | } |
54 | | } |
55 | | |
56 | 0 | Ok((state_fields, handlers)) |
57 | 0 | } |
58 | | |
59 | | // Helper: Parse state block (complexity: 5) |
60 | 0 | fn parse_state_block(state: &mut ParserState, state_fields: &mut Vec<StructField>) -> Result<()> { |
61 | 0 | state.tokens.advance(); // consume 'state' |
62 | 0 | state.tokens.expect(&Token::LeftBrace)?; |
63 | | |
64 | 0 | while !matches!(state.tokens.peek(), Some((Token::RightBrace, _))) { |
65 | 0 | let field_name = parse_field_name(state, "Expected field name in state block")?; |
66 | 0 | state.tokens.expect(&Token::Colon)?; |
67 | 0 | let ty = utils::parse_type(state)?; |
68 | | |
69 | 0 | state_fields.push(StructField { |
70 | 0 | name: field_name, |
71 | 0 | ty, |
72 | 0 | is_pub: false, |
73 | 0 | }); |
74 | | |
75 | 0 | consume_optional_separator(state); |
76 | | } |
77 | | |
78 | 0 | state.tokens.expect(&Token::RightBrace)?; |
79 | 0 | Ok(()) |
80 | 0 | } |
81 | | |
82 | | // Helper: Parse receive handler (complexity: 3) |
83 | 0 | fn parse_receive_handler(state: &mut ParserState, handlers: &mut Vec<ActorHandler>) -> Result<()> { |
84 | 0 | state.tokens.advance(); // consume 'receive' |
85 | | |
86 | 0 | if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) { |
87 | 0 | parse_receive_block(state, handlers) |
88 | | } else { |
89 | 0 | parse_individual_handler(state, handlers) |
90 | | } |
91 | 0 | } |
92 | | |
93 | | // Helper: Parse receive block with multiple handlers (complexity: 6) |
94 | 0 | fn parse_receive_block(state: &mut ParserState, handlers: &mut Vec<ActorHandler>) -> Result<()> { |
95 | 0 | state.tokens.advance(); // consume { |
96 | | |
97 | 0 | while !matches!(state.tokens.peek(), Some((Token::RightBrace, _))) { |
98 | 0 | let message_type = parse_field_name(state, "Expected message type in receive block")?; |
99 | 0 | let params = parse_optional_params(state)?; |
100 | 0 | state.tokens.expect(&Token::FatArrow)?; |
101 | 0 | let body = parse_handler_body(state)?; |
102 | | |
103 | 0 | handlers.push(ActorHandler { |
104 | 0 | message_type, |
105 | 0 | params, |
106 | 0 | body, |
107 | 0 | }); |
108 | | |
109 | 0 | if matches!(state.tokens.peek(), Some((Token::Comma, _))) { |
110 | 0 | state.tokens.advance(); |
111 | 0 | } |
112 | | } |
113 | | |
114 | 0 | state.tokens.expect(&Token::RightBrace)?; |
115 | 0 | Ok(()) |
116 | 0 | } |
117 | | |
118 | | // Helper: Parse individual handler (complexity: 4) |
119 | 0 | fn parse_individual_handler(state: &mut ParserState, handlers: &mut Vec<ActorHandler>) -> Result<()> { |
120 | 0 | let message_type = parse_field_name(state, "Expected message type after receive")?; |
121 | 0 | let params = parse_optional_params(state)?; |
122 | | |
123 | | // Parse optional return type |
124 | 0 | if matches!(state.tokens.peek(), Some((Token::Arrow, _))) { |
125 | 0 | state.tokens.advance(); // consume -> |
126 | 0 | let _return_type = utils::parse_type(state)?; |
127 | 0 | } |
128 | | |
129 | 0 | let body = Box::new(collections::parse_block(state)?); |
130 | | |
131 | 0 | handlers.push(ActorHandler { |
132 | 0 | message_type, |
133 | 0 | params, |
134 | 0 | body, |
135 | 0 | }); |
136 | | |
137 | 0 | Ok(()) |
138 | 0 | } |
139 | | |
140 | | // Helper: Parse inline state field (complexity: 4) |
141 | 0 | fn parse_inline_state_field(state: &mut ParserState, state_fields: &mut Vec<StructField>) -> Result<()> { |
142 | 0 | let field_name = parse_field_name(state, "Expected field name")?; |
143 | 0 | state.tokens.expect(&Token::Colon)?; |
144 | 0 | let ty = utils::parse_type(state)?; |
145 | | |
146 | | // Parse optional default value |
147 | 0 | if matches!(state.tokens.peek(), Some((Token::Equal, _))) { |
148 | 0 | state.tokens.advance(); // consume = |
149 | 0 | let _default_value = super::parse_expr_recursive(state)?; |
150 | 0 | } |
151 | | |
152 | 0 | state_fields.push(StructField { |
153 | 0 | name: field_name, |
154 | 0 | ty, |
155 | 0 | is_pub: false, |
156 | 0 | }); |
157 | | |
158 | 0 | consume_optional_separator(state); |
159 | 0 | Ok(()) |
160 | 0 | } |
161 | | |
162 | | // Helper: Parse field name (complexity: 2) |
163 | 0 | fn parse_field_name(state: &mut ParserState, error_msg: &str) -> Result<String> { |
164 | 0 | if let Some((Token::Identifier(name), _)) = state.tokens.peek() { |
165 | 0 | let name = name.clone(); |
166 | 0 | state.tokens.advance(); |
167 | 0 | Ok(name) |
168 | | } else { |
169 | 0 | bail!("{}", error_msg); |
170 | | } |
171 | 0 | } |
172 | | |
173 | | // Helper: Parse optional parameters (complexity: 2) |
174 | 0 | fn parse_optional_params(state: &mut ParserState) -> Result<Vec<Param>> { |
175 | 0 | if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) { |
176 | 0 | utils::parse_params(state) |
177 | | } else { |
178 | 0 | Ok(Vec::new()) |
179 | | } |
180 | 0 | } |
181 | | |
182 | | // Helper: Parse handler body (complexity: 2) |
183 | 0 | fn parse_handler_body(state: &mut ParserState) -> Result<Box<Expr>> { |
184 | 0 | if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) { |
185 | 0 | Ok(Box::new(collections::parse_block(state)?)) |
186 | | } else { |
187 | 0 | Ok(Box::new(super::parse_expr_recursive(state)?)) |
188 | | } |
189 | 0 | } |
190 | | |
191 | | // Helper: Consume optional separator (complexity: 2) |
192 | 0 | fn consume_optional_separator(state: &mut ParserState) { |
193 | 0 | if matches!( |
194 | 0 | state.tokens.peek(), |
195 | | Some((Token::Comma | Token::Semicolon, _)) |
196 | 0 | ) { |
197 | 0 | state.tokens.advance(); |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | #[cfg(test)] |
202 | | mod tests { |
203 | | use super::*; |
204 | | |
205 | | #[test] |
206 | | fn test_parse_actor_function_signature() { |
207 | | // This test just verifies the function signature compiles and exists |
208 | | // Actual functionality testing is done via integration tests due to |
209 | | // complex parser infrastructure requirements |
210 | | |
211 | | // Verify function exists with correct signature |
212 | | // This is a compile-time check - if it compiles, the test passes |
213 | | let f: fn(&mut ParserState) -> Result<Expr> = parse_actor; |
214 | | |
215 | | // Use the variable to avoid unused warning |
216 | | assert!(!format!("{f:p}").is_empty(), "Function exists"); |
217 | | } |
218 | | } |