feat(parser): Phase 285A1.3 - Unify weak field parsing into fields.rs
Unified weak modifier parsing logic into fields.rs for extensibility.
Changes:
- fields.rs: Add weak handling in visibility block parser (~40 lines)
- parse_weak_field() unified function for all weak parsing
- Visibility block now supports "public { weak parent }" syntax
- mod.rs: Delegate WEAK parsing to fields.rs (thin wrapper)
- Removed inline processing, now calls parse_weak_field()
Tests:
- phase285_weak_visibility_block.hako - public { weak parent }
- phase285_weak_mixed_members.hako - weak + method + visibility
Results:
- All 6 existing Phase 285A1 tests pass
- All 2 new tests pass
- Smoke tests: 46 PASS, 1 FAIL (pre-existing, unrelated)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -11,12 +11,14 @@ use std::collections::HashMap;
|
||||
/// - `name: Type = expr` → field with initializer (initializer is parsed then discarded at P0)
|
||||
/// - `name: Type => expr` → computed property (getter function generated)
|
||||
/// - `name: Type { ... } [catch|cleanup]` → computed property block with optional postfix handlers
|
||||
/// Note: weak field parsing is handled at the top level in parse_box_declaration (Phase 285A1.2)
|
||||
/// Returns Ok(true) when this function consumed and handled the construct; Ok(false) if not applicable.
|
||||
pub(crate) fn try_parse_header_first_field_or_property(
|
||||
p: &mut NyashParser,
|
||||
fname: String,
|
||||
methods: &mut HashMap<String, ASTNode>,
|
||||
fields: &mut Vec<String>,
|
||||
weak_fields: &mut Vec<String>,
|
||||
) -> Result<bool, ParseError> {
|
||||
// Expect ':' Type after name
|
||||
if !p.match_token(&TokenType::COLON) {
|
||||
@ -102,6 +104,7 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
public_fields: &mut Vec<String>,
|
||||
private_fields: &mut Vec<String>,
|
||||
last_method_name: &mut Option<String>,
|
||||
weak_fields: &mut Vec<String>,
|
||||
) -> Result<bool, ParseError> {
|
||||
if visibility != "public" && visibility != "private" {
|
||||
return Ok(false);
|
||||
@ -109,6 +112,14 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
if p.match_token(&TokenType::LBRACE) {
|
||||
p.advance();
|
||||
while !p.match_token(&TokenType::RBRACE) && !p.is_at_end() {
|
||||
// Phase 285A1.3: Check for weak modifier in visibility block
|
||||
let is_weak = if p.match_token(&TokenType::WEAK) {
|
||||
p.advance();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if let TokenType::IDENTIFIER(fname) = &p.current_token().token_type {
|
||||
let fname = fname.clone();
|
||||
if visibility == "public" {
|
||||
@ -116,6 +127,9 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
} else {
|
||||
private_fields.push(fname.clone());
|
||||
}
|
||||
if is_weak {
|
||||
weak_fields.push(fname.clone());
|
||||
}
|
||||
fields.push(fname);
|
||||
p.advance();
|
||||
if p.match_token(&TokenType::COMMA) {
|
||||
@ -124,7 +138,12 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
continue;
|
||||
}
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "identifier in visibility block".to_string(),
|
||||
expected: if is_weak {
|
||||
"field name after 'weak' in visibility block"
|
||||
} else {
|
||||
"identifier in visibility block"
|
||||
}
|
||||
.to_string(),
|
||||
found: p.current_token().token_type.clone(),
|
||||
line: p.current_token().line,
|
||||
});
|
||||
@ -135,7 +154,7 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
if let TokenType::IDENTIFIER(n) = &p.current_token().token_type {
|
||||
let fname = n.clone();
|
||||
p.advance();
|
||||
if try_parse_header_first_field_or_property(p, fname.clone(), methods, fields)? {
|
||||
if try_parse_header_first_field_or_property(p, fname.clone(), methods, fields, weak_fields)? {
|
||||
if visibility == "public" {
|
||||
public_fields.push(fname.clone());
|
||||
} else {
|
||||
@ -156,6 +175,24 @@ pub(crate) fn try_parse_visibility_block_or_single(
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Parse a weak field after WEAK token has been consumed.
|
||||
/// Handles both bare `weak parent` and `weak parent: Type` syntax.
|
||||
/// Returns Ok(()) on success.
|
||||
/// Phase 285A1.3: Unified weak field parsing logic.
|
||||
pub(crate) fn parse_weak_field(
|
||||
p: &mut NyashParser,
|
||||
field_name: String,
|
||||
methods: &mut HashMap<String, ASTNode>,
|
||||
fields: &mut Vec<String>,
|
||||
weak_fields: &mut Vec<String>,
|
||||
) -> Result<(), ParseError> {
|
||||
// Parse optional type annotation or property syntax via header-first parser
|
||||
try_parse_header_first_field_or_property(p, field_name.clone(), methods, fields, weak_fields)?;
|
||||
// Add to weak_fields vector (unified location for all weak field tracking)
|
||||
weak_fields.push(field_name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse `init { ... }` non-call block to collect initializable fields and weak flags.
|
||||
/// Returns Ok(true) if consumed; Ok(false) if no `init {` at current position.
|
||||
pub(crate) fn parse_init_block_if_any(
|
||||
|
||||
@ -59,6 +59,7 @@ fn box_try_visibility(
|
||||
public_fields: &mut Vec<String>,
|
||||
private_fields: &mut Vec<String>,
|
||||
last_method_name: &mut Option<String>,
|
||||
weak_fields: &mut Vec<String>,
|
||||
) -> Result<bool, ParseError> {
|
||||
members::fields::try_parse_visibility_block_or_single(
|
||||
p,
|
||||
@ -68,6 +69,7 @@ fn box_try_visibility(
|
||||
public_fields,
|
||||
private_fields,
|
||||
last_method_name,
|
||||
weak_fields,
|
||||
)
|
||||
}
|
||||
|
||||
@ -81,6 +83,7 @@ fn box_try_method_or_field(
|
||||
fields: &mut Vec<String>,
|
||||
birth_once_props: &Vec<String>,
|
||||
last_method_name: &mut Option<String>,
|
||||
weak_fields: &mut Vec<String>,
|
||||
) -> Result<bool, ParseError> {
|
||||
if let Some(method) =
|
||||
members::methods::try_parse_method(p, name.clone(), is_override, birth_once_props)?
|
||||
@ -90,7 +93,7 @@ fn box_try_method_or_field(
|
||||
return Ok(true);
|
||||
}
|
||||
// Fallback: header-first field/property (computed/once/birth_once handled inside)
|
||||
members::fields::try_parse_header_first_field_or_property(p, name, methods, fields)
|
||||
members::fields::try_parse_header_first_field_or_property(p, name, methods, fields, weak_fields)
|
||||
}
|
||||
|
||||
/// box宣言をパース: box Name { fields... methods... }
|
||||
@ -162,6 +165,30 @@ pub fn parse_box_declaration(p: &mut NyashParser) -> Result<ASTNode, ParseError>
|
||||
// 🚨 birth()統一システム: Box名コンストラクタ無効化
|
||||
validators::forbid_box_named_constructor(p, &name)?;
|
||||
|
||||
// Phase 285A1.3: Delegate weak field parsing to unified fields.rs logic
|
||||
if p.match_token(&TokenType::WEAK) {
|
||||
p.advance(); // consume WEAK
|
||||
if let TokenType::IDENTIFIER(field_name) = &p.current_token().token_type {
|
||||
let field_name = field_name.clone();
|
||||
p.advance();
|
||||
// Unified weak field parsing (Phase 285A1.3)
|
||||
members::fields::parse_weak_field(
|
||||
p,
|
||||
field_name,
|
||||
&mut methods,
|
||||
&mut fields,
|
||||
&mut weak_fields,
|
||||
)?;
|
||||
continue;
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "field name after 'weak'".to_string(),
|
||||
found: p.current_token().token_type.clone(),
|
||||
line: p.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 通常のフィールド名またはメソッド名、または unified members の先頭キーワードを読み取り
|
||||
if let TokenType::IDENTIFIER(field_or_method) = &p.current_token().token_type {
|
||||
let field_or_method = field_or_method.clone();
|
||||
@ -176,6 +203,7 @@ pub fn parse_box_declaration(p: &mut NyashParser) -> Result<ASTNode, ParseError>
|
||||
&mut public_fields,
|
||||
&mut private_fields,
|
||||
&mut last_method_name,
|
||||
&mut weak_fields,
|
||||
)? {
|
||||
continue;
|
||||
}
|
||||
@ -204,6 +232,7 @@ pub fn parse_box_declaration(p: &mut NyashParser) -> Result<ASTNode, ParseError>
|
||||
&mut fields,
|
||||
&birth_once_props,
|
||||
&mut last_method_name,
|
||||
&mut weak_fields,
|
||||
)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user