parser(match): add MVP type patterns (IntegerBox(x)/StringBox(s)) via AST If-chain; keep literal-only path using PeekExpr; add smoke app (apps/tests/match_type_pattern_basic.nyash); build + stage-2 smokes green

This commit is contained in:
Selfhosting Dev
2025-09-19 08:34:29 +09:00
parent f4e340da08
commit 9142476484
348 changed files with 2539 additions and 281 deletions

View File

@ -0,0 +1,90 @@
//! Header parsing: `Name<T...> from Parent1, Parent2`
//! Assumes the caller already consumed the leading `box` token.
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
/// Parse the leading header of a box declaration and return
/// (name, type_params, extends, implements). Does not consume the opening '{'.
pub fn parse_header(
p: &mut NyashParser,
) -> Result<(String, Vec<String>, Vec<String>, Vec<String>), ParseError> {
// Name
let name = if let TokenType::IDENTIFIER(name) = &p.current_token().token_type {
let name = name.clone();
p.advance();
name
} else {
let line = p.current_token().line;
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "identifier".to_string(),
line,
});
};
// Generic type parameters: <T, U>
let type_parameters = if p.match_token(&TokenType::LESS) {
p.advance(); // consume '<'
let mut params = Vec::new();
while !p.match_token(&TokenType::GREATER) && !p.is_at_end() {
crate::must_advance!(p, _unused, "generic type parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance();
if p.match_token(&TokenType::COMMA) {
p.advance();
p.skip_newlines();
}
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "type parameter name".to_string(),
line: p.current_token().line,
});
}
}
p.consume(TokenType::GREATER)?; // consume '>'
params
} else {
Vec::new()
};
// extends: from Parent1, Parent2
let extends = if p.match_token(&TokenType::FROM) {
p.advance(); // consume 'from'
let mut parents = Vec::new();
if let TokenType::IDENTIFIER(parent) = &p.current_token().token_type {
parents.push(parent.clone());
p.advance();
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "parent box name after 'from'".to_string(),
line: p.current_token().line,
});
}
while p.match_token(&TokenType::COMMA) {
p.advance(); // consume ','
p.skip_newlines();
if let TokenType::IDENTIFIER(parent) = &p.current_token().token_type {
parents.push(parent.clone());
p.advance();
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "parent box name after comma".to_string(),
line: p.current_token().line,
});
}
}
parents
} else {
Vec::new()
};
// implements: not supported (TokenType::IMPLEMENTS not defined yet)
let implements: Vec<String> = Vec::new();
Ok((name, type_parameters, extends, implements))
}

View File

@ -0,0 +1,57 @@
//! Shared helpers for members parsing (scaffold)
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MemberKind {
Field,
Method,
Constructor,
PropertyComputed,
PropertyOnce,
PropertyBirthOnce,
}
/// Decide member kind via simple lookahead (scaffold placeholder)
pub fn classify_member(p: &mut NyashParser) -> Result<MemberKind, ParseError> {
// block-first: { body } as (once|birth_once)? name : Type
if crate::config::env::unified_members() && p.match_any_token(&[TokenType::LBRACE]) {
return Ok(MemberKind::PropertyComputed);
}
// Constructors by keyword or name
match &p.current_token().token_type {
TokenType::PACK | TokenType::BIRTH => {
if p.peek_token() == &TokenType::LPAREN { return Ok(MemberKind::Constructor); }
}
TokenType::IDENTIFIER(name) if (name == "init" || name == "birth" || name == "pack")
&& p.peek_token() == &TokenType::LPAREN => {
return Ok(MemberKind::Constructor);
}
_ => {}
}
// Method: ident '(' ...
if matches!(&p.current_token().token_type, TokenType::IDENTIFIER(_))
&& p.peek_token() == &TokenType::LPAREN
{
return Ok(MemberKind::Method);
}
// Field: [weak] ident ':' Type
if p.match_any_token(&[TokenType::WEAK]) {
// weak IDENT ':'
// do not consume; use peek via offset: current is WEAK, next should be IDENT, then ':'
// We only classify; the main parser will handle errors.
return Ok(MemberKind::Field);
}
if matches!(&p.current_token().token_type, TokenType::IDENTIFIER(_))
&& p.peek_token() == &TokenType::COLON
{
return Ok(MemberKind::Field);
}
// Default: treat as method for graceful recovery
Ok(MemberKind::Method)
}

View File

@ -0,0 +1,160 @@
//! Constructors parsing (init/pack/birth)
use crate::ast::{ASTNode, Span};
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
/// Try to parse a constructor at current position.
/// Supported: `init(...) {}`, `pack(...) {}`, `birth(...) {}`.
/// Returns Ok(Some((key, node))) when a constructor was parsed and consumed.
pub fn try_parse_constructor(
p: &mut NyashParser,
is_override: bool,
) -> Result<Option<(String, ASTNode)>, ParseError> {
// init(...)
if p.match_token(&TokenType::INIT) && p.peek_token() == &TokenType::LPAREN {
if is_override {
return Err(ParseError::UnexpectedToken {
expected: "method definition, not constructor after override keyword".to_string(),
found: TokenType::INIT,
line: p.current_token().line,
});
}
let name = "init".to_string();
p.advance(); // consume 'init'
p.consume(TokenType::LPAREN)?;
let mut params = Vec::new();
while !p.match_token(&TokenType::RPAREN) && !p.is_at_end() {
crate::must_advance!(p, _unused, "constructor parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance();
}
if p.match_token(&TokenType::COMMA) {
p.advance();
}
}
p.consume(TokenType::RPAREN)?;
let mut body = p.parse_block_statements()?;
p.skip_newlines();
// Optional postfix catch/cleanup (method-level gate)
if p.match_token(&TokenType::CATCH) || p.match_token(&TokenType::CLEANUP) {
let mut catch_clauses: Vec<crate::ast::CatchClause> = Vec::new();
if p.match_token(&TokenType::CATCH) {
p.advance();
p.consume(TokenType::LPAREN)?;
let (exc_ty, exc_var) = p.parse_catch_param()?;
p.consume(TokenType::RPAREN)?;
let catch_body = p.parse_block_statements()?;
catch_clauses.push(crate::ast::CatchClause {
exception_type: exc_ty,
variable_name: exc_var,
body: catch_body,
span: Span::unknown(),
});
p.skip_newlines();
if p.match_token(&TokenType::CATCH) {
let line = p.current_token().line;
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "single catch only after method body".to_string(),
line,
});
}
}
let finally_body = if p.match_token(&TokenType::CLEANUP) {
p.advance();
Some(p.parse_block_statements()?)
} else {
None
};
body = vec![ASTNode::TryCatch { try_body: body, catch_clauses, finally_body, span: Span::unknown() }];
}
let node = ASTNode::FunctionDeclaration {
name: name.clone(),
params: params.clone(),
body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
let key = format!("{}/{}", name, params.len());
return Ok(Some((key, node)));
}
// pack(...)
if p.match_token(&TokenType::PACK) && p.peek_token() == &TokenType::LPAREN {
if is_override {
return Err(ParseError::UnexpectedToken {
expected: "method definition, not constructor after override keyword".to_string(),
found: TokenType::PACK,
line: p.current_token().line,
});
}
let name = "pack".to_string();
p.advance(); // consume 'pack'
p.consume(TokenType::LPAREN)?;
let mut params = Vec::new();
while !p.match_token(&TokenType::RPAREN) && !p.is_at_end() {
crate::must_advance!(p, _unused, "pack parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance();
}
if p.match_token(&TokenType::COMMA) {
p.advance();
}
}
p.consume(TokenType::RPAREN)?;
let body = p.parse_block_statements()?;
let node = ASTNode::FunctionDeclaration {
name: name.clone(),
params: params.clone(),
body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
let key = format!("{}/{}", name, params.len());
return Ok(Some((key, node)));
}
// birth(...)
if p.match_token(&TokenType::BIRTH) && p.peek_token() == &TokenType::LPAREN {
if is_override {
return Err(ParseError::UnexpectedToken {
expected: "method definition, not constructor after override keyword".to_string(),
found: TokenType::BIRTH,
line: p.current_token().line,
});
}
let name = "birth".to_string();
p.advance(); // consume 'birth'
p.consume(TokenType::LPAREN)?;
let mut params = Vec::new();
while !p.match_token(&TokenType::RPAREN) && !p.is_at_end() {
crate::must_advance!(p, _unused, "birth parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance();
}
if p.match_token(&TokenType::COMMA) {
p.advance();
}
}
p.consume(TokenType::RPAREN)?;
let body = p.parse_block_statements()?;
let node = ASTNode::FunctionDeclaration {
name: name.clone(),
params: params.clone(),
body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
let key = format!("{}/{}", name, params.len());
return Ok(Some((key, node)));
}
Ok(None)
}

View File

@ -0,0 +1,89 @@
//! Fields parsing (header-first: `name: Type` + unified members gates)
use crate::ast::{ASTNode, Span};
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
use std::collections::HashMap;
/// Parse a header-first field or property that starts with an already parsed identifier `fname`.
/// Handles:
/// - `name: Type` → field
/// - `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
/// Returns Ok(true) when this function consumed and handled the construct; Ok(false) if not applicable.
pub fn try_parse_header_first_field_or_property(
p: &mut NyashParser,
fname: String,
methods: &mut HashMap<String, ASTNode>,
fields: &mut Vec<String>,
) -> Result<bool, ParseError> {
// Expect ':' Type after name
if !p.match_token(&TokenType::COLON) {
// No type annotation: treat as bare stored field
fields.push(fname);
return Ok(true);
}
p.advance(); // consume ':'
// Optional type name (identifier). For now we accept and ignore.
if let TokenType::IDENTIFIER(_ty) = &p.current_token().token_type {
p.advance();
} else {
// If no type present, still proceed (tolerant parsing), but only when unified_members gate is off
// Keep behavior aligned with existing parser (it allowed missing type in some branches)
}
// Unified members gate behavior
if crate::config::env::unified_members() {
// name: Type = expr → field with initializer (store as field, initializer discarded at P0)
if p.match_token(&TokenType::ASSIGN) {
p.advance();
let _init_expr = p.parse_expression()?; // P0: parse and discard
fields.push(fname);
p.skip_newlines();
return Ok(true);
}
// name: Type => expr → computed property (getter method with return expr)
if p.match_token(&TokenType::FatArrow) {
p.advance();
let expr = p.parse_expression()?;
let body = vec![ASTNode::Return {
value: Some(Box::new(expr)),
span: Span::unknown(),
}];
let getter_name = format!("__get_{}", fname);
let method = ASTNode::FunctionDeclaration {
name: getter_name.clone(),
params: vec![],
body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
methods.insert(getter_name, method);
p.skip_newlines();
return Ok(true);
}
// name: Type { ... } [postfix]
if p.match_token(&TokenType::LBRACE) {
let body = p.parse_block_statements()?;
let body = crate::parser::declarations::box_def::members::postfix::wrap_with_optional_postfix(p, body)?;
let getter_name = format!("__get_{}", fname);
let method = ASTNode::FunctionDeclaration {
name: getter_name.clone(),
params: vec![],
body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
methods.insert(getter_name, method);
p.skip_newlines();
return Ok(true);
}
}
// Default: treat as a plain field when unified-members gate didn't match any special form
fields.push(fname);
Ok(true)
}

View File

@ -0,0 +1,80 @@
//! Methods parsing (name(params){ body }) with special birth() prologue
use crate::ast::{ASTNode, Span};
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
/// Try to parse a method declaration starting at `method_name` (already consumed identifier).
/// Returns Some(method_node) when parsed; None when not applicable (i.e., next token is not '(').
pub fn try_parse_method(
p: &mut NyashParser,
method_name: String,
is_override: bool,
birth_once_props: &Vec<String>,
) -> Result<Option<ASTNode>, ParseError> {
if !p.match_token(&TokenType::LPAREN) {
return Ok(None);
}
p.advance(); // consume '('
let mut params = Vec::new();
while !p.match_token(&TokenType::RPAREN) && !p.is_at_end() {
crate::must_advance!(p, _unused, "method parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance();
}
if p.match_token(&TokenType::COMMA) {
p.advance();
}
}
p.consume(TokenType::RPAREN)?;
let mut body = p.parse_block_statements()?;
// Inject eager init for birth_once at the very beginning of user birth()
if method_name == "birth" && !birth_once_props.is_empty() {
let mut injected: Vec<ASTNode> = Vec::new();
for pprop in birth_once_props.iter() {
let me_node = ASTNode::Me { span: Span::unknown() };
let compute_call = ASTNode::MethodCall {
object: Box::new(me_node.clone()),
method: format!("__compute_birth_{}", pprop),
arguments: vec![],
span: Span::unknown(),
};
let tmp = format!("__ny_birth_{}", pprop);
let local_tmp = ASTNode::Local {
variables: vec![tmp.clone()],
initial_values: vec![Some(Box::new(compute_call))],
span: Span::unknown(),
};
let set_call = ASTNode::MethodCall {
object: Box::new(me_node.clone()),
method: "setField".to_string(),
arguments: vec![
ASTNode::Literal {
value: crate::ast::LiteralValue::String(format!("__birth_{}", pprop)),
span: Span::unknown(),
},
ASTNode::Variable { name: tmp, span: Span::unknown() },
],
span: Span::unknown(),
};
injected.push(local_tmp);
injected.push(set_call);
}
let mut new_body = injected;
new_body.extend(body.into_iter());
body = new_body;
}
let method = ASTNode::FunctionDeclaration {
name: method_name.clone(),
params,
body,
is_static: false,
is_override,
span: Span::unknown(),
};
Ok(Some(method))
}

View File

@ -0,0 +1,7 @@
pub mod common;
pub mod fields;
pub mod methods;
pub mod constructors;
pub mod properties;
pub mod postfix;

View File

@ -0,0 +1,54 @@
//! Postfix handlers (catch/cleanup) utilities for unified members
use crate::ast::{ASTNode, Span};
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
/// If Stage-3 gate allows, parse optional catch/cleanup after a block body and wrap it.
/// Returns a (possibly) wrapped body.
pub fn wrap_with_optional_postfix(
p: &mut NyashParser,
body: Vec<ASTNode>,
) -> Result<Vec<ASTNode>, ParseError> {
if !(crate::config::env::parser_stage3()
&& (p.match_token(&TokenType::CATCH) || p.match_token(&TokenType::CLEANUP)))
{
return Ok(body);
}
let mut catch_clauses: Vec<crate::ast::CatchClause> = Vec::new();
if p.match_token(&TokenType::CATCH) {
p.advance();
p.consume(TokenType::LPAREN)?;
let (exc_ty, exc_var) = p.parse_catch_param()?;
p.consume(TokenType::RPAREN)?;
let catch_body = p.parse_block_statements()?;
catch_clauses.push(crate::ast::CatchClause {
exception_type: exc_ty,
variable_name: exc_var,
body: catch_body,
span: Span::unknown(),
});
p.skip_newlines();
if p.match_token(&TokenType::CATCH) {
let line = p.current_token().line;
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "single catch only after member body".to_string(),
line,
});
}
}
let finally_body = if p.match_token(&TokenType::CLEANUP) {
p.advance();
Some(p.parse_block_statements()?)
} else {
None
};
Ok(vec![ASTNode::TryCatch {
try_body: body,
catch_clauses,
finally_body,
span: Span::unknown(),
}])
}

View File

@ -0,0 +1,117 @@
//! Properties parsing (once/birth_once, header-first)
use crate::ast::{ASTNode, Span};
use crate::parser::{NyashParser, ParseError};
use crate::parser::common::ParserUtils;
use crate::tokenizer::TokenType;
use std::collections::HashMap;
/// Try to parse a unified member property: `once name: Type ...` or `birth_once name: Type ...`
/// Returns Ok(true) if consumed and handled; otherwise Ok(false).
pub fn try_parse_unified_property(
p: &mut NyashParser,
kind_kw: &str,
methods: &mut HashMap<String, ASTNode>,
birth_once_props: &mut Vec<String>,
) -> Result<bool, ParseError> {
if !(kind_kw == "once" || kind_kw == "birth_once") {
return Ok(false);
}
// Name
let name = if let TokenType::IDENTIFIER(n) = &p.current_token().token_type {
let n2 = n.clone();
p.advance();
n2
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "identifier after once/birth_once".to_string(),
line: p.current_token().line,
});
};
// ':' TYPE (type is accepted and ignored for now)
if p.match_token(&TokenType::COLON) {
p.advance();
if let TokenType::IDENTIFIER(_ty) = &p.current_token().token_type {
p.advance();
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: "type name".to_string(),
line: p.current_token().line,
});
}
} else {
return Err(ParseError::UnexpectedToken {
found: p.current_token().token_type.clone(),
expected: ": type".to_string(),
line: p.current_token().line,
});
}
// Body: either fat arrow expr or block
let orig_body: Vec<ASTNode> = if p.match_token(&TokenType::FatArrow) {
p.advance(); // consume '=>'
let expr = p.parse_expression()?;
vec![ASTNode::Return { value: Some(Box::new(expr)), span: Span::unknown() }]
} else {
p.parse_block_statements()?
};
// Optional postfix handlers (Stage-3) directly after body
let final_body = crate::parser::declarations::box_def::members::postfix::wrap_with_optional_postfix(p, orig_body)?;
if kind_kw == "once" {
// once: synthesize compute + getter with poison/cache
let compute_name = format!("__compute_once_{}", name);
let compute = ASTNode::FunctionDeclaration {
name: compute_name.clone(),
params: vec![],
body: final_body,
is_static: false,
is_override: false,
span: Span::unknown(),
};
methods.insert(compute_name.clone(), compute);
// Build complex getter wrapper identical to legacy impl
let key = format!("__once_{}", name);
let poison_key = format!("__once_poison_{}", name);
let cached_local = format!("__ny_cached_{}", name);
let poison_local = format!("__ny_poison_{}", name);
let val_local = format!("__ny_val_{}", name);
let me_node = ASTNode::Me { span: Span::unknown() };
let get_cached = ASTNode::MethodCall {
object: Box::new(me_node.clone()),
method: "getField".to_string(),
arguments: vec![ASTNode::Literal { value: crate::ast::LiteralValue::String(key.clone()), span: Span::unknown() }],
span: Span::unknown(),
};
let local_cached = ASTNode::Local { variables: vec![cached_local.clone()], initial_values: vec![Some(Box::new(get_cached))], span: Span::unknown() };
let cond_cached = ASTNode::BinaryOp { operator: crate::ast::BinaryOperator::NotEqual, left: Box::new(ASTNode::Variable { name: cached_local.clone(), span: Span::unknown() }), right: Box::new(ASTNode::Literal { value: crate::ast::LiteralValue::Null, span: Span::unknown() }), span: Span::unknown() };
let then_ret_cached = vec![ASTNode::Return { value: Some(Box::new(ASTNode::Variable { name: cached_local.clone(), span: Span::unknown() })), span: Span::unknown() }];
let if_cached = ASTNode::If { condition: Box::new(cond_cached), then_body: then_ret_cached, else_body: None, span: Span::unknown() };
let get_poison = ASTNode::MethodCall { object: Box::new(me_node.clone()), method: "getField".to_string(), arguments: vec![ASTNode::Literal { value: crate::ast::LiteralValue::String(poison_key.clone()), span: Span::unknown() }], span: Span::unknown() };
let local_poison = ASTNode::Local { variables: vec![poison_local.clone()], initial_values: vec![Some(Box::new(get_poison))], span: Span::unknown() };
let cond_poison = ASTNode::BinaryOp { operator: crate::ast::BinaryOperator::NotEqual, left: Box::new(ASTNode::Variable { name: poison_local.clone(), span: Span::unknown() }), right: Box::new(ASTNode::Literal { value: crate::ast::LiteralValue::Null, span: Span::unknown() }), span: Span::unknown() };
let then_throw = vec![ASTNode::Throw { expression: Box::new(ASTNode::Literal { value: crate::ast::LiteralValue::String(format!("once '{}' previously failed", name)), span: Span::unknown() }), span: Span::unknown() }];
let if_poison = ASTNode::If { condition: Box::new(cond_poison), then_body: then_throw, else_body: None, span: Span::unknown() };
let call_compute = ASTNode::MethodCall { object: Box::new(me_node.clone()), method: compute_name.clone(), arguments: vec![], span: Span::unknown() };
let local_val = ASTNode::Local { variables: vec![val_local.clone()], initial_values: vec![Some(Box::new(call_compute))], span: Span::unknown() };
let set_call = ASTNode::MethodCall { object: Box::new(me_node.clone()), method: "setField".to_string(), arguments: vec![ASTNode::Literal { value: crate::ast::LiteralValue::String(key.clone()), span: Span::unknown() }, ASTNode::Variable { name: val_local.clone(), span: Span::unknown() }], span: Span::unknown() };
let ret_stmt = ASTNode::Return { value: Some(Box::new(ASTNode::Variable { name: val_local.clone(), span: Span::unknown() })), span: Span::unknown() };
let getter_body = vec![local_cached, if_cached, local_poison, if_poison, local_val, set_call, ret_stmt];
let getter_name = format!("__get_once_{}", name);
let getter = ASTNode::FunctionDeclaration { name: getter_name.clone(), params: vec![], body: getter_body, is_static: false, is_override: false, span: Span::unknown() };
methods.insert(getter_name, getter);
return Ok(true);
}
// birth_once
birth_once_props.push(name.clone());
let compute_name = format!("__compute_birth_{}", name);
let compute = ASTNode::FunctionDeclaration { name: compute_name.clone(), params: vec![], body: final_body, is_static: false, is_override: false, span: Span::unknown() };
methods.insert(compute_name.clone(), compute);
let me_node = ASTNode::Me { span: Span::unknown() };
// getter: me.getField("__birth_name")
let get_call = ASTNode::MethodCall { object: Box::new(me_node.clone()), method: "getField".to_string(), arguments: vec![ASTNode::Literal { value: crate::ast::LiteralValue::String(format!("__birth_{}", name)), span: Span::unknown() }], span: Span::unknown() };
let getter_body = vec![ASTNode::Return { value: Some(Box::new(get_call)), span: Span::unknown() }];
let getter_name = format!("__get_birth_{}", name);
let getter = ASTNode::FunctionDeclaration { name: getter_name.clone(), params: vec![], body: getter_body, is_static: false, is_override: false, span: Span::unknown() };
methods.insert(getter_name, getter);
Ok(true)
}

View File

@ -6,6 +6,7 @@
*/
pub mod box_definition;
pub mod box_def;
pub mod dependency_helpers;
pub mod static_box;