Skip to content

Commit 17d9b43

Browse files
lantos1618claude
andcommitted
refactor(parser): audit-driven cleanup — dead code, DRY helpers, decompose primary.rs
Delete ~360 lines of dead code (parse_method, parse_impl_function, parse_binding_pattern, parse_variable_assignment, entire comptime.rs). Add core helpers: try_split_right_angle (consolidate >> splitting), parse_dotted_path, parse_identifier_list, AstType::self_type(). Rewrite external.rs with core helpers (85→59 lines), replace manual save/restore with save_state()/restore_state(), consolidate method-chain parsing into calls.rs, decompose 800-line parse_primary_expression into thin dispatch + helpers, replace boolean-tuple DeclKind with enum. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9981ba1 commit 17d9b43

File tree

16 files changed

+705
-1389
lines changed

16 files changed

+705
-1389
lines changed

src/ast/types.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ pub struct TraitConstraint {
133133
// ============================================================================
134134

135135
impl AstType {
136+
/// Create a Self-type placeholder for implicit `self` parameters.
137+
/// This is resolved during type checking based on the implementing type.
138+
pub fn self_type() -> AstType {
139+
AstType::Generic {
140+
name: "Self".to_string(),
141+
type_args: Vec::new(),
142+
}
143+
}
144+
136145
/// Returns the variant name of this type as a static string.
137146
pub fn variant_name(&self) -> &'static str {
138147
match self {

src/parser/behaviors.rs

Lines changed: 2 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ impl<'a> Parser<'a> {
7070
let type_ = if name == "self" && self.current_token != Token::Symbol(':') {
7171
// For 'self' without explicit type, use a placeholder type
7272
// This will be resolved during type checking based on the implementing type
73-
Type::Generic {
74-
name: "Self".to_string(),
75-
type_args: Vec::new(),
76-
}
73+
Type::self_type()
7774
} else {
7875
// Expect ':' for type annotation
7976
self.expect_symbol(':')?;
@@ -263,94 +260,7 @@ impl<'a> Parser<'a> {
263260
let param_type = if param_name == "self" && self.current_token != Token::Symbol(':')
264261
{
265262
// For 'self' without explicit type, use a placeholder type
266-
Type::Generic {
267-
name: "Self".to_string(),
268-
type_args: Vec::new(),
269-
}
270-
} else {
271-
self.expect_symbol(':')?;
272-
self.parse_type()?
273-
};
274-
args.push((param_name, param_type));
275-
276-
if self.current_token == Token::Symbol(')') {
277-
break;
278-
}
279-
if !self.try_consume_symbol(',') {
280-
return Err(self.syntax_error("Expected ',' or ')' in parameter list"));
281-
}
282-
}
283-
}
284-
self.next_token(); // consume ')'
285-
286-
// Check for return type (it should be present for impl functions)
287-
let return_type = if self.current_token != Token::Symbol('{') {
288-
// If it's not '{', then we have a return type
289-
self.parse_type()?
290-
} else {
291-
// Default to void/unit type if no return type specified
292-
crate::ast::AstType::Void
293-
};
294-
295-
// Function body
296-
self.expect_symbol('{')?;
297-
298-
let mut body = vec![];
299-
while self.current_token != Token::Symbol('}') && self.current_token != Token::Eof {
300-
body.push(self.parse_statement()?);
301-
}
302-
303-
if self.current_token != Token::Symbol('}') {
304-
return Err(self.syntax_error("Expected '}' to close function body"));
305-
}
306-
self.next_token();
307-
308-
// Check visibility before moving name
309-
let is_public = !name.starts_with("__");
310-
311-
Ok(Function {
312-
name,
313-
type_params,
314-
args,
315-
return_type,
316-
body,
317-
is_varargs: false,
318-
is_public,
319-
})
320-
}
321-
322-
/// Parse a function within an impl block context
323-
/// This is different from parse_function() because the function name and '=' have already been consumed
324-
#[allow(dead_code)]
325-
pub fn parse_impl_function(&mut self) -> Result<crate::ast::Function> {
326-
use crate::ast::Function;
327-
328-
// Function name
329-
let name = self.expect_identifier("function name")?;
330-
331-
// Parse generic type parameters if present: <T: Constraint, U, ...>
332-
let type_params = self.parse_type_parameters()?;
333-
334-
// Expect '=' (function signature separator)
335-
self.expect_operator("=")?;
336-
337-
// Parameters
338-
self.expect_symbol('(')?;
339-
340-
let mut args = vec![];
341-
if self.current_token != Token::Symbol(')') {
342-
loop {
343-
// Parameter name
344-
let param_name = self.expect_identifier("parameter name")?;
345-
346-
// Parameter type - special handling for 'self'
347-
let param_type = if param_name == "self" && self.current_token != Token::Symbol(':')
348-
{
349-
// For 'self' without explicit type, use a placeholder type
350-
Type::Generic {
351-
name: "Self".to_string(),
352-
type_args: Vec::new(),
353-
}
263+
Type::self_type()
354264
} else {
355265
self.expect_symbol(':')?;
356266
self.parse_type()?

src/parser/comptime.rs

Lines changed: 0 additions & 125 deletions
This file was deleted.

src/parser/core.rs

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,29 @@ impl<'a> Parser<'a> {
6969
}
7070
}
7171

72+
/// Try to split a `>>` or `>>=` token by consuming one `>`.
73+
/// Returns true if successfully consumed a `>` (either standalone or by splitting).
74+
/// Does NOT advance past a standalone `>` — that's done by the caller.
75+
fn try_split_right_angle(&mut self) -> bool {
76+
if self.current_token == Token::Operator(">>".to_string()) {
77+
self.current_token = Token::Operator(">".to_string());
78+
true
79+
} else if self.current_token == Token::Operator(">>=".to_string()) {
80+
self.current_token = Token::Operator(">=".to_string());
81+
true
82+
} else {
83+
false
84+
}
85+
}
86+
7287
/// Expect current token to be a specific operator, return error if not
7388
/// Special handling for `>` when current token is `>>` or `>>=` (needed for nested generics)
7489
pub fn expect_operator(&mut self, expected: &str) -> crate::error::Result<()> {
7590
if self.current_token == Token::Operator(expected.to_string()) {
7691
self.next_token();
7792
Ok(())
78-
} else if expected == ">" {
79-
// Handle nested generics: when expecting `>`, split `>>` into two `>` tokens
80-
if self.current_token == Token::Operator(">>".to_string()) {
81-
// Replace `>>` with single `>` (the remaining part after consuming one `>`)
82-
self.current_token = Token::Operator(">".to_string());
83-
Ok(())
84-
} else if self.current_token == Token::Operator(">>=".to_string()) {
85-
// Replace `>>=` with `>=` (the remaining part after consuming one `>`)
86-
self.current_token = Token::Operator(">=".to_string());
87-
Ok(())
88-
} else {
89-
Err(self.syntax_error(format!(
90-
"Expected '{}', got {:?}",
91-
expected, self.current_token
92-
)))
93-
}
93+
} else if expected == ">" && self.try_split_right_angle() {
94+
Ok(())
9495
} else {
9596
Err(self.syntax_error(format!(
9697
"Expected '{}', got {:?}",
@@ -115,21 +116,8 @@ impl<'a> Parser<'a> {
115116
if self.current_token == Token::Operator(op.to_string()) {
116117
self.next_token();
117118
true
118-
} else if op == ">" {
119-
// Handle nested generics: when looking for `>`, split `>>` into two `>` tokens
120-
if self.current_token == Token::Operator(">>".to_string()) {
121-
// Replace `>>` with single `>` (the remaining part after consuming one `>`)
122-
self.current_token = Token::Operator(">".to_string());
123-
true
124-
} else if self.current_token == Token::Operator(">>=".to_string()) {
125-
// Replace `>>=` with `>=` (the remaining part after consuming one `>`)
126-
self.current_token = Token::Operator(">=".to_string());
127-
true
128-
} else {
129-
false
130-
}
131119
} else {
132-
false
120+
op == ">" && self.try_split_right_angle()
133121
}
134122
}
135123

@@ -187,14 +175,8 @@ impl<'a> Parser<'a> {
187175
if self.current_token == Token::Symbol(',') {
188176
result.push(',');
189177
self.next_token();
190-
} else if self.current_token == Token::Operator(">".to_string()) {
178+
} else if self.try_consume_operator(">") {
191179
result.push('>');
192-
self.next_token();
193-
break;
194-
} else if self.current_token == Token::Operator(">>".to_string()) {
195-
// Handle nested generics: split `>>` into `>` + `>`
196-
result.push('>');
197-
self.current_token = Token::Operator(">".to_string());
198180
break;
199181
} else {
200182
break;
@@ -225,6 +207,48 @@ impl<'a> Parser<'a> {
225207
}
226208
}
227209

210+
/// Parse a dotted identifier path: `initial.member1.member2...`
211+
/// Consumes `.identifier` pairs as long as they're available.
212+
pub fn parse_dotted_path(&mut self, initial: String) -> String {
213+
let mut path = initial;
214+
while self.current_token == Token::Symbol('.') {
215+
self.next_token();
216+
if let Token::Identifier(member) = &self.current_token {
217+
path.push('.');
218+
path.push_str(member);
219+
self.next_token();
220+
} else {
221+
break;
222+
}
223+
}
224+
path
225+
}
226+
227+
/// Parse a comma-separated list of identifiers enclosed by `close` char.
228+
/// Assumes the opening delimiter has already been consumed.
229+
/// Consumes the closing delimiter.
230+
pub fn parse_identifier_list(
231+
&mut self,
232+
close: char,
233+
context: &str,
234+
) -> crate::error::Result<Vec<String>> {
235+
let mut names = vec![];
236+
while self.current_token != Token::Symbol(close) && self.current_token != Token::Eof {
237+
let name = self.expect_identifier(context)?;
238+
names.push(name);
239+
if !self.try_consume_symbol(',') && self.current_token != Token::Symbol(close) {
240+
return Err(
241+
self.syntax_error(format!("Expected ',' or '{}' in {}", close, context))
242+
);
243+
}
244+
}
245+
if self.current_token != Token::Symbol(close) {
246+
return Err(self.syntax_error(format!("Expected '{}' to close {}", close, context)));
247+
}
248+
self.next_token(); // consume close
249+
Ok(names)
250+
}
251+
228252
// ========================================================================
229253
// STATE SAVE/RESTORE FOR LOOK-AHEAD
230254
// ========================================================================

0 commit comments

Comments
 (0)