17 KiB
17 KiB
Phase 16 Technical Specification: Box-Based Macro System
Date: 2025-09-19
Version: 0.1.0
Status: DRAFT - 実装前仕様
🏗️ アーキテクチャ概要
システム構成
Nyash Source Code
↓
Lexer/Parser
↓
Raw AST
↓
┌─────────────────────┐
│ Macro Expansion │ ← 新規実装部分
│ ┌───────────────┐ │
│ │ AST Pattern │ │ ← Phase 1
│ │ Matching │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ Quote/Unquote │ │ ← Phase 2
│ │ System │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ HIR Patch │ │ ← Phase 3
│ │ Engine │ │
│ └───────────────┘ │
└─────────────────────┘
↓
Expanded AST
↓
MIR Lowering ← 既存システム(無変更)
↓
MIR14 Instructions
↓
VM/JIT/AOT Execution
🎯 Phase 1: AST Pattern Matching
新規AST構造体
PatternAst
#[derive(Debug, Clone)]
pub enum PatternAst {
// 基本パターン
Wildcard { span: Span }, // _
Identifier { name: String, span: Span }, // variable
Literal { value: LiteralValue, span: Span }, // 42, "hello"
// 構造パターン
BoxPattern {
name: String, // BoxDeclaration
fields: Vec<FieldPattern>, // { field1, field2, .. }
span: Span,
},
// 配列パターン
ArrayPattern {
elements: Vec<PatternAst>, // [first, second, ...]
rest: Option<String>, // ...rest
span: Span,
},
// OR パターン
OrPattern {
patterns: Vec<PatternAst>, // pattern1 | pattern2
span: Span,
},
// バインドパターン
BindPattern {
name: String, // @variable
pattern: Box<PatternAst>, // @var pattern
span: Span,
},
}
#[derive(Debug, Clone)]
pub struct FieldPattern {
pub name: String,
pub pattern: PatternAst,
pub span: Span,
}
MatchExpression
#[derive(Debug, Clone)]
pub struct MatchExpression {
pub target: Box<ASTNode>, // match対象
pub arms: Vec<MatchArm>, // マッチアーム
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct MatchArm {
pub pattern: PatternAst, // パターン
pub guard: Option<Box<ASTNode>>, // if guard
pub body: Vec<ASTNode>, // 実行文
pub span: Span,
}
パターンマッチング構文
基本構文
match ast_node {
BoxDeclaration { name, fields, .. } => {
// Box宣言の処理
}
FunctionDeclaration { name: "main", .. } => {
// main関数の特別処理
}
_ => {
// その他
}
}
高度なパターン
match ast_node {
// 束縛パターン
BoxDeclaration { name: @box_name, fields: [first, ...rest] } => {
// box_nameにnameをバインド
// firstに最初のフィールド、restに残り
}
// ORパターン
Literal { value: IntegerValue | StringValue } => {
// 整数または文字列リテラル
}
// ガード
BoxDeclaration { fields } if fields.length > 5 => {
// フィールドが5個より多いBox
}
}
実装詳細
Parser拡張
impl NyashParser {
/// match式のパース
pub fn parse_match_expression(&mut self) -> Result<MatchExpression, ParseError> {
self.consume(TokenType::MATCH)?;
let target = self.parse_expression()?;
self.consume(TokenType::LBRACE)?;
let mut arms = Vec::new();
while !self.match_token(&TokenType::RBRACE) {
arms.push(self.parse_match_arm()?);
}
self.consume(TokenType::RBRACE)?;
Ok(MatchExpression { target: Box::new(target), arms, span: Span::unknown() })
}
/// パターンのパース
pub fn parse_pattern(&mut self) -> Result<PatternAst, ParseError> {
// パターン実装...
}
}
PatternMatcher
pub struct PatternMatcher {
bindings: HashMap<String, ASTNode>,
}
impl PatternMatcher {
/// パターンマッチング実行
pub fn match_pattern(&mut self, pattern: &PatternAst, value: &ASTNode) -> bool {
match (pattern, value) {
(PatternAst::Wildcard { .. }, _) => true,
(PatternAst::Identifier { name, .. }, value) => {
self.bindings.insert(name.clone(), value.clone());
true
}
(PatternAst::BoxPattern { name, fields, .. },
ASTNode::BoxDeclaration { name: box_name, fields: box_fields, .. }) => {
if name == box_name {
self.match_fields(fields, box_fields)
} else {
false
}
}
// その他のパターン...
_ => false,
}
}
}
🎯 Phase 2: Quote/Unquote System
新規AST構造体
QuoteExpression
#[derive(Debug, Clone)]
pub struct QuoteExpression {
pub template: Vec<ASTNode>, // テンプレート
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct UnquoteExpression {
pub template: Box<QuoteExpression>, // 展開するテンプレート
pub substitutions: HashMap<String, ASTNode>, // 置換マップ
pub span: Span,
}
// テンプレート内の変数展開
#[derive(Debug, Clone)]
pub struct TemplateVariable {
pub name: String, // $(variable_name)
pub span: Span,
}
Quote/Unquote構文
基本構文
// コードテンプレート作成
let template = quote! {
$(method_name)(other) {
return me.$(field_name).equals(other.$(field_name))
}
}
// テンプレート展開
let generated = unquote! {
template with {
method_name: "equals",
field_name: "name"
}
}
高度な展開
// リスト展開
let field_comparisons = quote! {
$(for field in fields) {
me.$(field.name).equals(other.$(field.name))
}
}
// 条件展開
let method_body = quote! {
$(if has_fields) {
return $(field_comparisons)
} else {
return true
}
}
実装詳細
TemplateEngine
pub struct TemplateEngine {
substitutions: HashMap<String, ASTNode>,
}
impl TemplateEngine {
/// テンプレート展開
pub fn expand_template(&self, template: &QuoteExpression) -> Result<Vec<ASTNode>, MacroError> {
let mut result = Vec::new();
for node in &template.template {
match self.expand_node(node)? {
ExpandResult::Single(n) => result.push(n),
ExpandResult::Multiple(nodes) => result.extend(nodes),
}
}
Ok(result)
}
/// 単一ノード展開
fn expand_node(&self, node: &ASTNode) -> Result<ExpandResult, MacroError> {
match node {
ASTNode::TemplateVariable { name, .. } => {
if let Some(substitution) = self.substitutions.get(name) {
Ok(ExpandResult::Single(substitution.clone()))
} else {
Err(MacroError::UnboundVariable(name.clone()))
}
}
// 再帰的展開
_ => self.expand_node_recursive(node),
}
}
}
🎯 Phase 3: HIRパッチ式マクロエンジン
MacroEngine Core
MacroRegistry
pub struct MacroRegistry {
derive_macros: HashMap<String, Box<dyn DeriveMacro>>,
attribute_macros: HashMap<String, Box<dyn AttributeMacro>>,
function_macros: HashMap<String, Box<dyn FunctionMacro>>,
}
impl MacroRegistry {
pub fn register_derive<T: DeriveMacro + 'static>(&mut self, name: &str, macro_impl: T) {
self.derive_macros.insert(name.to_string(), Box::new(macro_impl));
}
pub fn expand_derive(&self, name: &str, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError> {
if let Some(macro_impl) = self.derive_macros.get(name) {
macro_impl.expand(input)
} else {
Err(MacroError::UnknownDeriveMacro(name.to_string()))
}
}
}
DeriveMacro Trait
pub trait DeriveMacro {
/// derive マクロ展開
fn expand(&self, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError>;
/// サポートする型チェック
fn supports_box(&self, box_decl: &BoxDeclaration) -> bool {
true // デフォルト:すべてのBoxをサポート
}
}
@derive実装例
EqualsDeriveMacro
pub struct EqualsDeriveMacro;
impl DeriveMacro for EqualsDeriveMacro {
fn expand(&self, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError> {
let method_name = "equals";
let param_name = "other";
// フィールド比較の生成
let field_comparisons = self.generate_field_comparisons(&input.fields)?;
// equals メソッドの生成
let equals_method = ASTNode::FunctionDeclaration {
name: method_name.to_string(),
params: vec![param_name.to_string()],
body: vec![
ASTNode::Return {
value: Some(Box::new(field_comparisons)),
span: Span::unknown(),
}
],
is_static: false,
is_override: false,
span: Span::unknown(),
};
Ok(vec![equals_method])
}
fn generate_field_comparisons(&self, fields: &[String]) -> Result<ASTNode, MacroError> {
if fields.is_empty() {
// フィールドなし:常にtrue
return Ok(ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
});
}
// フィールド比較の連鎖
let mut comparison = self.generate_single_field_comparison(&fields[0])?;
for field in &fields[1..] {
let field_comp = self.generate_single_field_comparison(field)?;
comparison = ASTNode::BinaryOp {
operator: BinaryOperator::And,
left: Box::new(comparison),
right: Box::new(field_comp),
span: Span::unknown(),
};
}
Ok(comparison)
}
fn generate_single_field_comparison(&self, field: &str) -> Result<ASTNode, MacroError> {
// me.field.equals(other.field)
Ok(ASTNode::MethodCall {
object: Box::new(ASTNode::FieldAccess {
object: Box::new(ASTNode::Me { span: Span::unknown() }),
field: field.to_string(),
span: Span::unknown(),
}),
method: "equals".to_string(),
arguments: vec![
ASTNode::FieldAccess {
object: Box::new(ASTNode::Variable {
name: "other".to_string(),
span: Span::unknown(),
}),
field: field.to_string(),
span: Span::unknown(),
}
],
span: Span::unknown(),
})
}
}
TestMacro
pub struct TestMacro;
impl AttributeMacro for TestMacro {
fn expand(&self, input: &FunctionDeclaration) -> Result<Vec<ASTNode>, MacroError> {
// テスト関数をテストレジストリに登録
let register_call = ASTNode::MethodCall {
object: Box::new(ASTNode::Variable {
name: "TestRegistry".to_string(),
span: Span::unknown(),
}),
method: "register".to_string(),
arguments: vec![
ASTNode::Literal {
value: LiteralValue::String(input.name.clone()),
span: Span::unknown(),
},
ASTNode::Variable {
name: input.name.clone(),
span: Span::unknown(),
}
],
span: Span::unknown(),
};
Ok(vec![
register_call,
ASTNode::FunctionDeclaration {
name: input.name.clone(),
params: input.params.clone(),
body: input.body.clone(),
is_static: input.is_static,
is_override: input.is_override,
span: input.span.clone(),
}
])
}
}
🛡️ エラーハンドリング
MacroError定義
#[derive(Debug, Clone)]
pub enum MacroError {
// パターンマッチングエラー
PatternMismatch { expected: String, found: String },
UnboundVariable(String),
// Quote/Unquoteエラー
TemplateExpansionFailed(String),
InvalidSubstitution { variable: String, reason: String },
// Deriveマクロエラー
UnknownDeriveMacro(String),
UnsupportedBoxType { derive_name: String, box_name: String },
// 一般エラー
RecursionLimitExceeded,
CircularDependency(Vec<String>),
}
エラーメッセージ
impl MacroError {
pub fn user_message(&self) -> String {
match self {
MacroError::UnknownDeriveMacro(name) => {
format!("Unknown derive trait '{}'
Available traits: Equals, ToString, Clone, Debug
Did you mean 'ToString'?", name)
}
MacroError::PatternMismatch { expected, found } => {
format!("Pattern mismatch: expected {}, found {}", expected, found)
}
_ => format!("Macro error: {:?}", self),
}
}
}
🎨 CLI統合
新規コマンドオプション
既に実装済み:
// src/cli.rs で確認済み
.arg(
Arg::new("expand")
.long("expand")
.help("Macro: enable macro engine and dump expansion traces")
.action(clap::ArgAction::SetTrue)
)
.arg(
Arg::new("run-tests")
.long("run-tests")
.help("Run tests: enable macro engine and inject test harness")
.action(clap::ArgAction::SetTrue)
)
.arg(
Arg::new("test-filter")
.long("test-filter")
.value_name("SUBSTR")
.help("Only run tests whose name contains SUBSTR")
)
環境変数
// マクロエンジン有効化
NYASH_MACRO_ENABLE=1
// マクロ展開トレース
NYASH_MACRO_TRACE=1
// テスト実行
NYASH_TEST_RUN=1
// テストフィルタ
NYASH_TEST_FILTER="substring"
📊 パフォーマンス要件
目標指標
- 展開時間: < 100ms(中規模プロジェクト)
- メモリ使用量: < 20% 増加(ベースコンパイラ比)
- 型チェック: 100% コンパイル時
- エラー検出: 100% コンパイル時
最適化戦略
- 遅延展開: 必要な時のみマクロ展開
- キャッシュ: 同一パターンの結果をキャッシュ
- 並列処理: 独立なマクロの並列展開
- メモリプール: AST ノードの効率的割り当て
🚀 実装順序
Week 1-2: AST Pattern Matching
- PatternAst構造体定義
- Parser拡張(match式)
- PatternMatcher実装
- 基本テストケース
Week 3-4: Quote/Unquote
- QuoteExpression定義
- TemplateEngine実装
- 変数置換システム
- エラーハンドリング
Week 5-6: HIRパッチエンジン
- MacroRegistry実装
- DeriveMacro trait定義
- EqualsDeriveMacro実装
- TestMacro実装
Week 7-8: 統合・最適化
- CLI統合
- エラーメッセージ改善
- パフォーマンス最適化
- ドキュメント作成
この仕様に基づいて、世界最強のBox-Basedマクロシステムを実装する! 🌟