chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更
Phase 25.1 完了成果: - ✅ LoopForm v2 テスト・ドキュメント・コメント完備 - 4ケース(A/B/C/D)完全テストカバレッジ - 最小再現ケース作成(SSAバグ調査用) - SSOT文書作成(loopform_ssot.md) - 全ソースに [LoopForm] コメントタグ追加 - ✅ Stage-1 CLI デバッグ環境構築 - stage1_cli.hako 実装 - stage1_bridge.rs ブリッジ実装 - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh) - アーキテクチャ改善提案文書 - ✅ 環境変数削減計画策定 - 25変数の完全調査・分類 - 6段階削減ロードマップ(25→5、80%削減) - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG) Phase 26-D からの累積変更: - PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等) - MIRビルダーリファクタリング - 型伝播・最適化パス改善 - その他約300ファイルの累積変更 🎯 技術的成果: - SSAバグ根本原因特定(条件分岐内loop変数変更) - Region+next_iパターン適用完了(UsingCollectorBox等) - LoopFormパターン文書化・テスト化完了 - セルフホスティング基盤強化 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com> Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
@ -5,32 +5,110 @@ pub(super) fn transform_array_prepend_zero(ast: &nyash_rust::ASTNode) -> nyash_r
|
||||
let mut new_elems: Vec<A> = Vec::with_capacity(elements.len() + 1);
|
||||
let already_zero = elements
|
||||
.get(0)
|
||||
.and_then(|n| match n { A::Literal { value: LiteralValue::Integer(0), .. } => Some(()), _ => None })
|
||||
.and_then(|n| match n {
|
||||
A::Literal {
|
||||
value: LiteralValue::Integer(0),
|
||||
..
|
||||
} => Some(()),
|
||||
_ => None,
|
||||
})
|
||||
.is_some();
|
||||
if already_zero {
|
||||
for e in elements { new_elems.push(transform_array_prepend_zero(e)); }
|
||||
for e in elements {
|
||||
new_elems.push(transform_array_prepend_zero(e));
|
||||
}
|
||||
} else {
|
||||
new_elems.push(A::Literal { value: LiteralValue::Integer(0), span: Span::unknown() });
|
||||
for e in elements { new_elems.push(transform_array_prepend_zero(e)); }
|
||||
new_elems.push(A::Literal {
|
||||
value: LiteralValue::Integer(0),
|
||||
span: Span::unknown(),
|
||||
});
|
||||
for e in elements {
|
||||
new_elems.push(transform_array_prepend_zero(e));
|
||||
}
|
||||
}
|
||||
A::ArrayLiteral {
|
||||
elements: new_elems,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
A::ArrayLiteral { elements: new_elems, span: Span::unknown() }
|
||||
}
|
||||
A::Program { statements, .. } => A::Program { statements: statements.iter().map(transform_array_prepend_zero).collect(), span: Span::unknown() },
|
||||
A::Print { expression, .. } => A::Print { expression: Box::new(transform_array_prepend_zero(expression)), span: Span::unknown() },
|
||||
A::Return { value, .. } => A::Return { value: value.as_ref().map(|v| Box::new(transform_array_prepend_zero(v))), span: Span::unknown() },
|
||||
A::Assignment { target, value, .. } => A::Assignment { target: Box::new(transform_array_prepend_zero(target)), value: Box::new(transform_array_prepend_zero(value)), span: Span::unknown() },
|
||||
A::If { condition, then_body, else_body, .. } => A::If {
|
||||
condition: Box::new(transform_array_prepend_zero(condition)),
|
||||
then_body: then_body.iter().map(transform_array_prepend_zero).collect(),
|
||||
else_body: else_body.as_ref().map(|v| v.iter().map(transform_array_prepend_zero).collect()),
|
||||
A::Program { statements, .. } => A::Program {
|
||||
statements: statements
|
||||
.iter()
|
||||
.map(transform_array_prepend_zero)
|
||||
.collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Print { expression, .. } => A::Print {
|
||||
expression: Box::new(transform_array_prepend_zero(expression)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Return { value, .. } => A::Return {
|
||||
value: value
|
||||
.as_ref()
|
||||
.map(|v| Box::new(transform_array_prepend_zero(v))),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Assignment { target, value, .. } => A::Assignment {
|
||||
target: Box::new(transform_array_prepend_zero(target)),
|
||||
value: Box::new(transform_array_prepend_zero(value)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
} => A::If {
|
||||
condition: Box::new(transform_array_prepend_zero(condition)),
|
||||
then_body: then_body.iter().map(transform_array_prepend_zero).collect(),
|
||||
else_body: else_body
|
||||
.as_ref()
|
||||
.map(|v| v.iter().map(transform_array_prepend_zero).collect()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} => A::BinaryOp {
|
||||
operator: operator.clone(),
|
||||
left: Box::new(transform_array_prepend_zero(left)),
|
||||
right: Box::new(transform_array_prepend_zero(right)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator, operand, ..
|
||||
} => A::UnaryOp {
|
||||
operator: operator.clone(),
|
||||
operand: Box::new(transform_array_prepend_zero(operand)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
..
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_array_prepend_zero(object)),
|
||||
method: method.clone(),
|
||||
arguments: arguments.iter().map(transform_array_prepend_zero).collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::FunctionCall {
|
||||
name, arguments, ..
|
||||
} => A::FunctionCall {
|
||||
name: name.clone(),
|
||||
arguments: arguments.iter().map(transform_array_prepend_zero).collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::MapLiteral { entries, .. } => A::MapLiteral {
|
||||
entries: entries
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), transform_array_prepend_zero(v)))
|
||||
.collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::BinaryOp { operator, left, right, .. } => A::BinaryOp { operator: operator.clone(), left: Box::new(transform_array_prepend_zero(left)), right: Box::new(transform_array_prepend_zero(right)), span: Span::unknown() },
|
||||
A::UnaryOp { operator, operand, .. } => A::UnaryOp { operator: operator.clone(), operand: Box::new(transform_array_prepend_zero(operand)), span: Span::unknown() },
|
||||
A::MethodCall { object, method, arguments, .. } => A::MethodCall { object: Box::new(transform_array_prepend_zero(object)), method: method.clone(), arguments: arguments.iter().map(transform_array_prepend_zero).collect(), span: Span::unknown() },
|
||||
A::FunctionCall { name, arguments, .. } => A::FunctionCall { name: name.clone(), arguments: arguments.iter().map(transform_array_prepend_zero).collect(), span: Span::unknown() },
|
||||
A::MapLiteral { entries, .. } => A::MapLiteral { entries: entries.iter().map(|(k,v)| (k.clone(), transform_array_prepend_zero(v))).collect(), span: Span::unknown() },
|
||||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,112 @@
|
||||
fn subst_var(node: &nyash_rust::ASTNode, name: &str, replacement: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
fn subst_var(
|
||||
node: &nyash_rust::ASTNode,
|
||||
name: &str,
|
||||
replacement: &nyash_rust::ASTNode,
|
||||
) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match node.clone() {
|
||||
A::Variable { name: n, .. } if n == name => replacement.clone(),
|
||||
A::Program { statements, span } => A::Program { statements: statements.iter().map(|s| subst_var(s, name, replacement)).collect(), span },
|
||||
A::Print { expression, span } => A::Print { expression: Box::new(subst_var(&expression, name, replacement)), span },
|
||||
A::Return { value, span } => A::Return { value: value.as_ref().map(|v| Box::new(subst_var(v, name, replacement))), span },
|
||||
A::Assignment { target, value, span } => A::Assignment { target: Box::new(subst_var(&target, name, replacement)), value: Box::new(subst_var(&value, name, replacement)), span },
|
||||
A::If { condition, then_body, else_body, span } => A::If {
|
||||
condition: Box::new(subst_var(&condition, name, replacement)),
|
||||
then_body: then_body.iter().map(|s| subst_var(s, name, replacement)).collect(),
|
||||
else_body: else_body.map(|v| v.iter().map(|s| subst_var(s, name, replacement)).collect()),
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.iter()
|
||||
.map(|s| subst_var(s, name, replacement))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::Print { expression, span } => A::Print {
|
||||
expression: Box::new(subst_var(&expression, name, replacement)),
|
||||
span,
|
||||
},
|
||||
A::Return { value, span } => A::Return {
|
||||
value: value
|
||||
.as_ref()
|
||||
.map(|v| Box::new(subst_var(v, name, replacement))),
|
||||
span,
|
||||
},
|
||||
A::Assignment {
|
||||
target,
|
||||
value,
|
||||
span,
|
||||
} => A::Assignment {
|
||||
target: Box::new(subst_var(&target, name, replacement)),
|
||||
value: Box::new(subst_var(&value, name, replacement)),
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(subst_var(&condition, name, replacement)),
|
||||
then_body: then_body
|
||||
.iter()
|
||||
.map(|s| subst_var(s, name, replacement))
|
||||
.collect(),
|
||||
else_body: else_body
|
||||
.map(|v| v.iter().map(|s| subst_var(s, name, replacement)).collect()),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(subst_var(&left, name, replacement)),
|
||||
right: Box::new(subst_var(&right, name, replacement)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(subst_var(&operand, name, replacement)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(subst_var(&object, name, replacement)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.iter()
|
||||
.map(|a| subst_var(a, name, replacement))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name: fn_name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name: fn_name,
|
||||
arguments: arguments
|
||||
.iter()
|
||||
.map(|a| subst_var(a, name, replacement))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.iter()
|
||||
.map(|e| subst_var(e, name, replacement))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), subst_var(v, name, replacement)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(subst_var(&left, name, replacement)), right: Box::new(subst_var(&right, name, replacement)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(subst_var(&operand, name, replacement)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(subst_var(&object, name, replacement)), method, arguments: arguments.iter().map(|a| subst_var(a, name, replacement)).collect(), span },
|
||||
A::FunctionCall { name: fn_name, arguments, span } => A::FunctionCall { name: fn_name, arguments: arguments.iter().map(|a| subst_var(a, name, replacement)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.iter().map(|e| subst_var(e, name, replacement)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.iter().map(|(k,v)| (k.clone(), subst_var(v, name, replacement))).collect(), span },
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
@ -28,7 +117,9 @@ pub(super) fn transform_for_foreach(ast: &nyash_rust::ASTNode) -> nyash_rust::AS
|
||||
let mut out: Vec<A> = Vec::new();
|
||||
for st in list.into_iter() {
|
||||
match st.clone() {
|
||||
A::FunctionCall { name, arguments, .. } if (name == "ny_for" || name == "for") && arguments.len() == 4 => {
|
||||
A::FunctionCall {
|
||||
name, arguments, ..
|
||||
} if (name == "ny_for" || name == "for") && arguments.len() == 4 => {
|
||||
let init = arguments[0].clone();
|
||||
let cond = arguments[1].clone();
|
||||
let step = arguments[2].clone();
|
||||
@ -37,38 +128,117 @@ pub(super) fn transform_for_foreach(ast: &nyash_rust::ASTNode) -> nyash_rust::AS
|
||||
if params.is_empty() {
|
||||
match init.clone() {
|
||||
A::Assignment { .. } | A::Local { .. } => out.push(init),
|
||||
A::Lambda { params: p2, body: b2, .. } if p2.is_empty() => { for s in b2 { out.push(transform_for_foreach(&s)); } }
|
||||
A::Lambda {
|
||||
params: p2,
|
||||
body: b2,
|
||||
..
|
||||
} if p2.is_empty() => {
|
||||
for s in b2 {
|
||||
out.push(transform_for_foreach(&s));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut loop_body: Vec<A> = body.into_iter().map(|n| transform_for_foreach(&n)).collect();
|
||||
let mut loop_body: Vec<A> = body
|
||||
.into_iter()
|
||||
.map(|n| transform_for_foreach(&n))
|
||||
.collect();
|
||||
match step.clone() {
|
||||
A::Assignment { .. } => loop_body.push(step),
|
||||
A::Lambda { params: p2, body: b2, .. } if p2.is_empty() => { for s in b2 { loop_body.push(transform_for_foreach(&s)); } }
|
||||
A::Lambda {
|
||||
params: p2,
|
||||
body: b2,
|
||||
..
|
||||
} if p2.is_empty() => {
|
||||
for s in b2 {
|
||||
loop_body.push(transform_for_foreach(&s));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
out.push(A::Loop { condition: Box::new(transform_for_foreach(&cond)), body: loop_body, span: Span::unknown() });
|
||||
out.push(A::Loop {
|
||||
condition: Box::new(transform_for_foreach(&cond)),
|
||||
body: loop_body,
|
||||
span: Span::unknown(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push(st);
|
||||
}
|
||||
A::FunctionCall { name, arguments, .. } if (name == "ny_foreach" || name == "foreach") && arguments.len() == 3 => {
|
||||
A::FunctionCall {
|
||||
name, arguments, ..
|
||||
} if (name == "ny_foreach" || name == "foreach") && arguments.len() == 3 => {
|
||||
let array = arguments[0].clone();
|
||||
let param_name = match &arguments[1] { A::Variable { name, .. } => name.clone(), _ => "it".to_string() };
|
||||
let param_name = match &arguments[1] {
|
||||
A::Variable { name, .. } => name.clone(),
|
||||
_ => "it".to_string(),
|
||||
};
|
||||
let body_lam = arguments[2].clone();
|
||||
if let A::Lambda { params, body, .. } = body_lam {
|
||||
if params.is_empty() {
|
||||
let iter = A::Variable { name: "__i".to_string(), span: Span::unknown() };
|
||||
let zero = A::Literal { value: LiteralValue::Integer(0), span: Span::unknown() };
|
||||
let one = A::Literal { value: LiteralValue::Integer(1), span: Span::unknown() };
|
||||
let init = A::Local { variables: vec!["__i".to_string()], initial_values: vec![Some(Box::new(zero))], span: Span::unknown() };
|
||||
let len_call = A::MethodCall { object: Box::new(transform_for_foreach(&array)), method: "len".to_string(), arguments: vec![], span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Less, left: Box::new(iter.clone()), right: Box::new(len_call), span: Span::unknown() };
|
||||
let get_call = A::MethodCall { object: Box::new(transform_for_foreach(&array)), method: "get".to_string(), arguments: vec![iter.clone()], span: Span::unknown() };
|
||||
let body_stmts: Vec<A> = body.into_iter().map(|s| subst_var(&s, ¶m_name, &get_call)).collect();
|
||||
let step = A::Assignment { target: Box::new(iter.clone()), value: Box::new(A::BinaryOp { operator: BinaryOperator::Add, left: Box::new(iter), right: Box::new(one), span: Span::unknown() }), span: Span::unknown() };
|
||||
let iter = A::Variable {
|
||||
name: "__i".to_string(),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let zero = A::Literal {
|
||||
value: LiteralValue::Integer(0),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let one = A::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let init = A::Local {
|
||||
variables: vec!["__i".to_string()],
|
||||
initial_values: vec![Some(Box::new(zero))],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let len_call = A::MethodCall {
|
||||
object: Box::new(transform_for_foreach(&array)),
|
||||
method: "len".to_string(),
|
||||
arguments: vec![],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let cond = A::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(iter.clone()),
|
||||
right: Box::new(len_call),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let get_call = A::MethodCall {
|
||||
object: Box::new(transform_for_foreach(&array)),
|
||||
method: "get".to_string(),
|
||||
arguments: vec![iter.clone()],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let body_stmts: Vec<A> = body
|
||||
.into_iter()
|
||||
.map(|s| subst_var(&s, ¶m_name, &get_call))
|
||||
.collect();
|
||||
let step = A::Assignment {
|
||||
target: Box::new(iter.clone()),
|
||||
value: Box::new(A::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(iter),
|
||||
right: Box::new(one),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
out.push(init);
|
||||
out.push(A::Loop { condition: Box::new(cond), body: { let mut b = Vec::new(); for s in body_stmts { b.push(transform_for_foreach(&s)); } b.push(step); b }, span: Span::unknown() });
|
||||
out.push(A::Loop {
|
||||
condition: Box::new(cond),
|
||||
body: {
|
||||
let mut b = Vec::new();
|
||||
for s in body_stmts {
|
||||
b.push(transform_for_foreach(&s));
|
||||
}
|
||||
b.push(step);
|
||||
b
|
||||
},
|
||||
span: Span::unknown(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -81,18 +251,98 @@ pub(super) fn transform_for_foreach(ast: &nyash_rust::ASTNode) -> nyash_rust::AS
|
||||
}
|
||||
// `A` is already imported above
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: rewrite_stmt_list(statements), span },
|
||||
A::If { condition, then_body, else_body, span } => A::If { condition: Box::new(transform_for_foreach(&condition)), then_body: rewrite_stmt_list(then_body), else_body: else_body.map(rewrite_stmt_list), span },
|
||||
A::Loop { condition, body, span } => A::Loop { condition: Box::new(transform_for_foreach(&condition)), body: rewrite_stmt_list(body), span },
|
||||
A::Print { expression, span } => A::Print { expression: Box::new(transform_for_foreach(&expression)), span },
|
||||
A::Return { value, span } => A::Return { value: value.as_ref().map(|v| Box::new(transform_for_foreach(v))), span },
|
||||
A::Assignment { target, value, span } => A::Assignment { target: Box::new(transform_for_foreach(&target)), value: Box::new(transform_for_foreach(&value)), span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_for_foreach(&left)), right: Box::new(transform_for_foreach(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_for_foreach(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_for_foreach(&object)), method, arguments: arguments.iter().map(|a| transform_for_foreach(a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments: arguments.iter().map(|a| transform_for_foreach(a)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.iter().map(|e| transform_for_foreach(e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.iter().map(|(k,v)| (k.clone(), transform_for_foreach(v))).collect(), span },
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: rewrite_stmt_list(statements),
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(transform_for_foreach(&condition)),
|
||||
then_body: rewrite_stmt_list(then_body),
|
||||
else_body: else_body.map(rewrite_stmt_list),
|
||||
span,
|
||||
},
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => A::Loop {
|
||||
condition: Box::new(transform_for_foreach(&condition)),
|
||||
body: rewrite_stmt_list(body),
|
||||
span,
|
||||
},
|
||||
A::Print { expression, span } => A::Print {
|
||||
expression: Box::new(transform_for_foreach(&expression)),
|
||||
span,
|
||||
},
|
||||
A::Return { value, span } => A::Return {
|
||||
value: value.as_ref().map(|v| Box::new(transform_for_foreach(v))),
|
||||
span,
|
||||
},
|
||||
A::Assignment {
|
||||
target,
|
||||
value,
|
||||
span,
|
||||
} => A::Assignment {
|
||||
target: Box::new(transform_for_foreach(&target)),
|
||||
value: Box::new(transform_for_foreach(&value)),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_for_foreach(&left)),
|
||||
right: Box::new(transform_for_foreach(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_for_foreach(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_for_foreach(&object)),
|
||||
method,
|
||||
arguments: arguments.iter().map(|a| transform_for_foreach(a)).collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments.iter().map(|a| transform_for_foreach(a)).collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements.iter().map(|e| transform_for_foreach(e)).collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), transform_for_foreach(v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,123 @@
|
||||
pub(super) fn transform_if_to_loopform(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::{ASTNode as A, Span};
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: statements.into_iter().map(|n| transform_if_to_loopform(&n)).collect(), span },
|
||||
A::If { condition, then_body, else_body, span } => {
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.into_iter()
|
||||
.map(|n| transform_if_to_loopform(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => {
|
||||
let cond_t = Box::new(transform_if_to_loopform(&condition));
|
||||
let then_t = then_body.into_iter().map(|n| transform_if_to_loopform(&n)).collect();
|
||||
let else_t = else_body.map(|v| v.into_iter().map(|n| transform_if_to_loopform(&n)).collect());
|
||||
let inner_if = A::If { condition: cond_t, then_body: then_t, else_body: else_t, span: Span::unknown() };
|
||||
let one = A::Literal { value: nyash_rust::ast::LiteralValue::Integer(1), span: Span::unknown() };
|
||||
let loop_body = vec![inner_if, A::Break { span: Span::unknown() }];
|
||||
A::Loop { condition: Box::new(one), body: loop_body, span }
|
||||
let then_t = then_body
|
||||
.into_iter()
|
||||
.map(|n| transform_if_to_loopform(&n))
|
||||
.collect();
|
||||
let else_t = else_body.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|n| transform_if_to_loopform(&n))
|
||||
.collect()
|
||||
});
|
||||
let inner_if = A::If {
|
||||
condition: cond_t,
|
||||
then_body: then_t,
|
||||
else_body: else_t,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let one = A::Literal {
|
||||
value: nyash_rust::ast::LiteralValue::Integer(1),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let loop_body = vec![
|
||||
inner_if,
|
||||
A::Break {
|
||||
span: Span::unknown(),
|
||||
},
|
||||
];
|
||||
A::Loop {
|
||||
condition: Box::new(one),
|
||||
body: loop_body,
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::Loop { condition, body, span } => A::Loop { condition: Box::new(transform_if_to_loopform(&condition)), body: body.into_iter().map(|n| transform_if_to_loopform(&n)).collect(), span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_if_to_loopform(&left)), right: Box::new(transform_if_to_loopform(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_if_to_loopform(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_if_to_loopform(&object)), method, arguments: arguments.into_iter().map(|a| transform_if_to_loopform(&a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments: arguments.into_iter().map(|a| transform_if_to_loopform(&a)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| transform_if_to_loopform(&e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k, v)| (k, transform_if_to_loopform(&v))).collect(), span },
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => A::Loop {
|
||||
condition: Box::new(transform_if_to_loopform(&condition)),
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|n| transform_if_to_loopform(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_if_to_loopform(&left)),
|
||||
right: Box::new(transform_if_to_loopform(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_if_to_loopform(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_if_to_loopform(&object)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_if_to_loopform(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_if_to_loopform(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| transform_if_to_loopform(&e))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, transform_if_to_loopform(&v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,86 +2,302 @@ pub(super) fn transform_lift_nested_functions(ast: &nyash_rust::ASTNode) -> nyas
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
fn gensym(base: &str) -> String { let n = COUNTER.fetch_add(1, Ordering::Relaxed); format!("__ny_lifted_{}_{}", base, n) }
|
||||
fn gensym(base: &str) -> String {
|
||||
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
format!("__ny_lifted_{}_{}", base, n)
|
||||
}
|
||||
fn collect_locals(n: &A, set: &mut std::collections::HashSet<String>) {
|
||||
match n {
|
||||
A::Local { variables, .. } => { for v in variables { set.insert(v.clone()); } }
|
||||
A::Program { statements, .. } => for s in statements { collect_locals(s, set); },
|
||||
A::FunctionDeclaration { body, .. } => for s in body { collect_locals(s, set); },
|
||||
A::If { then_body, else_body, .. } => { for s in then_body { collect_locals(s, set); } if let Some(b) = else_body { for s in b { collect_locals(s, set); } } }
|
||||
A::Local { variables, .. } => {
|
||||
for v in variables {
|
||||
set.insert(v.clone());
|
||||
}
|
||||
}
|
||||
A::Program { statements, .. } => {
|
||||
for s in statements {
|
||||
collect_locals(s, set);
|
||||
}
|
||||
}
|
||||
A::FunctionDeclaration { body, .. } => {
|
||||
for s in body {
|
||||
collect_locals(s, set);
|
||||
}
|
||||
}
|
||||
A::If {
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
} => {
|
||||
for s in then_body {
|
||||
collect_locals(s, set);
|
||||
}
|
||||
if let Some(b) = else_body {
|
||||
for s in b {
|
||||
collect_locals(s, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn collect_vars(n: &A, set: &mut std::collections::HashSet<String>) {
|
||||
match n {
|
||||
A::Variable { name, .. } => { set.insert(name.clone()); }
|
||||
A::Program { statements, .. } => for s in statements { collect_vars(s, set); },
|
||||
A::FunctionDeclaration { body, .. } => for s in body { collect_vars(s, set); },
|
||||
A::If { condition, then_body, else_body, .. } => {
|
||||
collect_vars(condition, set);
|
||||
for s in then_body { collect_vars(s, set); }
|
||||
if let Some(b) = else_body { for s in b { collect_vars(s, set); } }
|
||||
A::Variable { name, .. } => {
|
||||
set.insert(name.clone());
|
||||
}
|
||||
A::Program { statements, .. } => {
|
||||
for s in statements {
|
||||
collect_vars(s, set);
|
||||
}
|
||||
}
|
||||
A::FunctionDeclaration { body, .. } => {
|
||||
for s in body {
|
||||
collect_vars(s, set);
|
||||
}
|
||||
}
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
} => {
|
||||
collect_vars(condition, set);
|
||||
for s in then_body {
|
||||
collect_vars(s, set);
|
||||
}
|
||||
if let Some(b) = else_body {
|
||||
for s in b {
|
||||
collect_vars(s, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
A::Assignment { target, value, .. } => {
|
||||
collect_vars(target, set);
|
||||
collect_vars(value, set);
|
||||
}
|
||||
A::Return { value, .. } => {
|
||||
if let Some(v) = value {
|
||||
collect_vars(v, set);
|
||||
}
|
||||
}
|
||||
A::Assignment { target, value, .. } => { collect_vars(target, set); collect_vars(value, set); }
|
||||
A::Return { value, .. } => { if let Some(v) = value { collect_vars(v, set); } }
|
||||
A::Print { expression, .. } => collect_vars(expression, set),
|
||||
A::BinaryOp { left, right, .. } => { collect_vars(left, set); collect_vars(right, set); }
|
||||
A::BinaryOp { left, right, .. } => {
|
||||
collect_vars(left, set);
|
||||
collect_vars(right, set);
|
||||
}
|
||||
A::UnaryOp { operand, .. } => collect_vars(operand, set),
|
||||
A::MethodCall { object, arguments, .. } => { collect_vars(object, set); for a in arguments { collect_vars(a, set); } }
|
||||
A::FunctionCall { arguments, .. } => { for a in arguments { collect_vars(a, set); } }
|
||||
A::ArrayLiteral { elements, .. } => { for e in elements { collect_vars(e, set); } }
|
||||
A::MapLiteral { entries, .. } => { for (_,v) in entries { collect_vars(v, set); } }
|
||||
A::MethodCall {
|
||||
object, arguments, ..
|
||||
} => {
|
||||
collect_vars(object, set);
|
||||
for a in arguments {
|
||||
collect_vars(a, set);
|
||||
}
|
||||
}
|
||||
A::FunctionCall { arguments, .. } => {
|
||||
for a in arguments {
|
||||
collect_vars(a, set);
|
||||
}
|
||||
}
|
||||
A::ArrayLiteral { elements, .. } => {
|
||||
for e in elements {
|
||||
collect_vars(e, set);
|
||||
}
|
||||
}
|
||||
A::MapLiteral { entries, .. } => {
|
||||
for (_, v) in entries {
|
||||
collect_vars(v, set);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn rename_calls(n: &A, mapping: &std::collections::HashMap<String, String>) -> A {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match n.clone() {
|
||||
A::FunctionCall { name, arguments, span } => {
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => {
|
||||
let new_name = mapping.get(&name).cloned().unwrap_or(name);
|
||||
A::FunctionCall { name: new_name, arguments: arguments.into_iter().map(|a| rename_calls(&a, mapping)).collect(), span }
|
||||
A::FunctionCall {
|
||||
name: new_name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| rename_calls(&a, mapping))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::Program { statements, span } => A::Program { statements: statements.into_iter().map(|s| rename_calls(&s, mapping)).collect(), span },
|
||||
A::FunctionDeclaration { name, params, body, is_static, is_override, span } => {
|
||||
A::FunctionDeclaration { name, params, body: body.into_iter().map(|s| rename_calls(&s, mapping)).collect(), is_static, is_override, span }
|
||||
}
|
||||
A::If { condition, then_body, else_body, span } => A::If {
|
||||
condition: Box::new(rename_calls(&condition, mapping)),
|
||||
then_body: then_body.into_iter().map(|s| rename_calls(&s, mapping)).collect(),
|
||||
else_body: else_body.map(|v| v.into_iter().map(|s| rename_calls(&s, mapping)).collect()),
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.into_iter()
|
||||
.map(|s| rename_calls(&s, mapping))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionDeclaration {
|
||||
name,
|
||||
params,
|
||||
body,
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
} => A::FunctionDeclaration {
|
||||
name,
|
||||
params,
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|s| rename_calls(&s, mapping))
|
||||
.collect(),
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(rename_calls(&condition, mapping)),
|
||||
then_body: then_body
|
||||
.into_iter()
|
||||
.map(|s| rename_calls(&s, mapping))
|
||||
.collect(),
|
||||
else_body: else_body
|
||||
.map(|v| v.into_iter().map(|s| rename_calls(&s, mapping)).collect()),
|
||||
span,
|
||||
},
|
||||
A::Assignment {
|
||||
target,
|
||||
value,
|
||||
span,
|
||||
} => A::Assignment {
|
||||
target: Box::new(rename_calls(&target, mapping)),
|
||||
value: Box::new(rename_calls(&value, mapping)),
|
||||
span,
|
||||
},
|
||||
A::Return { value, span } => A::Return {
|
||||
value: value.as_ref().map(|v| Box::new(rename_calls(v, mapping))),
|
||||
span,
|
||||
},
|
||||
A::Print { expression, span } => A::Print {
|
||||
expression: Box::new(rename_calls(&expression, mapping)),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(rename_calls(&left, mapping)),
|
||||
right: Box::new(rename_calls(&right, mapping)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(rename_calls(&operand, mapping)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(rename_calls(&object, mapping)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| rename_calls(&a, mapping))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| rename_calls(&e, mapping))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, rename_calls(&v, mapping)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::Assignment { target, value, span } => A::Assignment { target: Box::new(rename_calls(&target, mapping)), value: Box::new(rename_calls(&value, mapping)), span },
|
||||
A::Return { value, span } => A::Return { value: value.as_ref().map(|v| Box::new(rename_calls(v, mapping))), span },
|
||||
A::Print { expression, span } => A::Print { expression: Box::new(rename_calls(&expression, mapping)), span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(rename_calls(&left, mapping)), right: Box::new(rename_calls(&right, mapping)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(rename_calls(&operand, mapping)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(rename_calls(&object, mapping)), method, arguments: arguments.into_iter().map(|a| rename_calls(&a, mapping)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| rename_calls(&e, mapping)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k,v)| (k, rename_calls(&v, mapping))).collect(), span },
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
fn lift_in_body(body: Vec<A>, hoisted: &mut Vec<A>, mapping: &mut std::collections::HashMap<String,String>) -> Vec<A> {
|
||||
fn lift_in_body(
|
||||
body: Vec<A>,
|
||||
hoisted: &mut Vec<A>,
|
||||
mapping: &mut std::collections::HashMap<String, String>,
|
||||
) -> Vec<A> {
|
||||
use std::collections::HashSet;
|
||||
let mut out: Vec<A> = Vec::new();
|
||||
for st in body.into_iter() {
|
||||
match st.clone() {
|
||||
A::FunctionDeclaration { name, params, body, is_static, is_override, span } => {
|
||||
A::FunctionDeclaration {
|
||||
name,
|
||||
params,
|
||||
body,
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
} => {
|
||||
let mut locals: HashSet<String> = HashSet::new();
|
||||
collect_locals(&A::FunctionDeclaration{ name: name.clone(), params: params.clone(), body: body.clone(), is_static, is_override, span }, &mut locals);
|
||||
collect_locals(
|
||||
&A::FunctionDeclaration {
|
||||
name: name.clone(),
|
||||
params: params.clone(),
|
||||
body: body.clone(),
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
},
|
||||
&mut locals,
|
||||
);
|
||||
let mut used: HashSet<String> = HashSet::new();
|
||||
collect_vars(&A::FunctionDeclaration{ name: name.clone(), params: params.clone(), body: body.clone(), is_static, is_override, span }, &mut used);
|
||||
collect_vars(
|
||||
&A::FunctionDeclaration {
|
||||
name: name.clone(),
|
||||
params: params.clone(),
|
||||
body: body.clone(),
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
},
|
||||
&mut used,
|
||||
);
|
||||
let params_set: HashSet<String> = params.iter().cloned().collect();
|
||||
let mut extra: HashSet<String> = used.drain().collect();
|
||||
extra.retain(|v| !params_set.contains(v) && !locals.contains(v));
|
||||
if extra.is_empty() {
|
||||
let new_name = gensym(&name);
|
||||
let lifted = A::FunctionDeclaration { name: new_name.clone(), params, body, is_static: true, is_override, span };
|
||||
let lifted = A::FunctionDeclaration {
|
||||
name: new_name.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: true,
|
||||
is_override,
|
||||
span,
|
||||
};
|
||||
hoisted.push(lifted);
|
||||
mapping.insert(name, new_name);
|
||||
continue;
|
||||
} else { out.push(st); }
|
||||
} else {
|
||||
out.push(st);
|
||||
}
|
||||
}
|
||||
other => out.push(other),
|
||||
}
|
||||
@ -93,30 +309,115 @@ pub(super) fn transform_lift_nested_functions(ast: &nyash_rust::ASTNode) -> nyas
|
||||
match n.clone() {
|
||||
A::Program { statements, span } => {
|
||||
let mut mapping = std::collections::HashMap::new();
|
||||
let stmts2 = lift_in_body(statements.into_iter().map(|s| walk(&s, hoisted)).collect(), hoisted, &mut mapping);
|
||||
A::Program { statements: stmts2, span }
|
||||
let stmts2 = lift_in_body(
|
||||
statements.into_iter().map(|s| walk(&s, hoisted)).collect(),
|
||||
hoisted,
|
||||
&mut mapping,
|
||||
);
|
||||
A::Program {
|
||||
statements: stmts2,
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::FunctionDeclaration { name, params, body, is_static, is_override, span } => {
|
||||
A::FunctionDeclaration {
|
||||
name,
|
||||
params,
|
||||
body,
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
} => {
|
||||
let mut mapping = std::collections::HashMap::new();
|
||||
let body2: Vec<A> = body.into_iter().map(|s| walk(&s, hoisted)).collect();
|
||||
let body3 = lift_in_body(body2, hoisted, &mut mapping);
|
||||
A::FunctionDeclaration { name, params, body: body3, is_static, is_override, span }
|
||||
A::FunctionDeclaration {
|
||||
name,
|
||||
params,
|
||||
body: body3,
|
||||
is_static,
|
||||
is_override,
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::If { condition, then_body, else_body, span } => A::If {
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(walk(&condition, hoisted)),
|
||||
then_body: then_body.into_iter().map(|s| walk(&s, hoisted)).collect(),
|
||||
else_body: else_body.map(|v| v.into_iter().map(|s| walk(&s, hoisted)).collect()),
|
||||
span,
|
||||
},
|
||||
A::Assignment { target, value, span } => A::Assignment { target: Box::new(walk(&target, hoisted)), value: Box::new(walk(&value, hoisted)), span },
|
||||
A::Return { value, span } => A::Return { value: value.as_ref().map(|v| Box::new(walk(v, hoisted))), span },
|
||||
A::Print { expression, span } => A::Print { expression: Box::new(walk(&expression, hoisted)), span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(walk(&left, hoisted)), right: Box::new(walk(&right, hoisted)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(walk(&operand, hoisted)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(walk(&object, hoisted)), method, arguments: arguments.into_iter().map(|a| walk(&a, hoisted)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments: arguments.into_iter().map(|a| walk(&a, hoisted)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| walk(&e, hoisted)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k,v)| (k, walk(&v, hoisted))).collect(), span },
|
||||
A::Assignment {
|
||||
target,
|
||||
value,
|
||||
span,
|
||||
} => A::Assignment {
|
||||
target: Box::new(walk(&target, hoisted)),
|
||||
value: Box::new(walk(&value, hoisted)),
|
||||
span,
|
||||
},
|
||||
A::Return { value, span } => A::Return {
|
||||
value: value.as_ref().map(|v| Box::new(walk(v, hoisted))),
|
||||
span,
|
||||
},
|
||||
A::Print { expression, span } => A::Print {
|
||||
expression: Box::new(walk(&expression, hoisted)),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(walk(&left, hoisted)),
|
||||
right: Box::new(walk(&right, hoisted)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(walk(&operand, hoisted)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(walk(&object, hoisted)),
|
||||
method,
|
||||
arguments: arguments.into_iter().map(|a| walk(&a, hoisted)).collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments.into_iter().map(|a| walk(&a, hoisted)).collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements.into_iter().map(|e| walk(&e, hoisted)).collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, walk(&v, hoisted)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
@ -125,8 +426,10 @@ pub(super) fn transform_lift_nested_functions(ast: &nyash_rust::ASTNode) -> nyas
|
||||
if let A::Program { statements, span } = out.clone() {
|
||||
let mut ss = statements;
|
||||
ss.extend(hoisted.into_iter());
|
||||
out = A::Program { statements: ss, span };
|
||||
out = A::Program {
|
||||
statements: ss,
|
||||
span,
|
||||
};
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
|
||||
@ -1,25 +1,103 @@
|
||||
pub(super) fn transform_loop_normalize(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: statements.into_iter().map(|n| transform_loop_normalize(&n)).collect(), span },
|
||||
A::If { condition, then_body, else_body, span } => A::If {
|
||||
condition: Box::new(transform_loop_normalize(&condition)),
|
||||
then_body: then_body.into_iter().map(|n| transform_loop_normalize(&n)).collect(),
|
||||
else_body: else_body.map(|v| v.into_iter().map(|n| transform_loop_normalize(&n)).collect()),
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.into_iter()
|
||||
.map(|n| transform_loop_normalize(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::Loop { condition, body, span } => A::Loop {
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(transform_loop_normalize(&condition)),
|
||||
body: body.into_iter().map(|n| transform_loop_normalize(&n)).collect(),
|
||||
then_body: then_body
|
||||
.into_iter()
|
||||
.map(|n| transform_loop_normalize(&n))
|
||||
.collect(),
|
||||
else_body: else_body.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|n| transform_loop_normalize(&n))
|
||||
.collect()
|
||||
}),
|
||||
span,
|
||||
},
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => A::Loop {
|
||||
condition: Box::new(transform_loop_normalize(&condition)),
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|n| transform_loop_normalize(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_loop_normalize(&left)),
|
||||
right: Box::new(transform_loop_normalize(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_loop_normalize(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_loop_normalize(&object)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_loop_normalize(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_loop_normalize(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| transform_loop_normalize(&e))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, transform_loop_normalize(&v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_loop_normalize(&left)), right: Box::new(transform_loop_normalize(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_loop_normalize(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_loop_normalize(&object)), method, arguments: arguments.into_iter().map(|a| transform_loop_normalize(&a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments: arguments.into_iter().map(|a| transform_loop_normalize(&a)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| transform_loop_normalize(&e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k,v)| (k, transform_loop_normalize(&v))).collect(), span },
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,31 +5,94 @@ pub(super) fn transform_map_insert_tag(ast: &nyash_rust::ASTNode) -> nyash_rust:
|
||||
let mut new_entries: Vec<(String, A)> = Vec::with_capacity(entries.len() + 1);
|
||||
let already_tagged = entries.get(0).map(|(k, _)| k == "__macro").unwrap_or(false);
|
||||
if already_tagged {
|
||||
for (k, v) in entries { new_entries.push((k.clone(), transform_map_insert_tag(v))); }
|
||||
for (k, v) in entries {
|
||||
new_entries.push((k.clone(), transform_map_insert_tag(v)));
|
||||
}
|
||||
} else {
|
||||
new_entries.push((
|
||||
"__macro".to_string(),
|
||||
A::Literal { value: LiteralValue::String("on".to_string()), span: Span::unknown() },
|
||||
A::Literal {
|
||||
value: LiteralValue::String("on".to_string()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
));
|
||||
for (k, v) in entries { new_entries.push((k.clone(), transform_map_insert_tag(v))); }
|
||||
for (k, v) in entries {
|
||||
new_entries.push((k.clone(), transform_map_insert_tag(v)));
|
||||
}
|
||||
}
|
||||
A::MapLiteral {
|
||||
entries: new_entries,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
A::MapLiteral { entries: new_entries, span: Span::unknown() }
|
||||
}
|
||||
A::Program { statements, .. } => A::Program { statements: statements.iter().map(transform_map_insert_tag).collect(), span: Span::unknown() },
|
||||
A::Print { expression, .. } => A::Print { expression: Box::new(transform_map_insert_tag(expression)), span: Span::unknown() },
|
||||
A::Return { value, .. } => A::Return { value: value.as_ref().map(|v| Box::new(transform_map_insert_tag(v))), span: Span::unknown() },
|
||||
A::Assignment { target, value, .. } => A::Assignment { target: Box::new(transform_map_insert_tag(target)), value: Box::new(transform_map_insert_tag(value)), span: Span::unknown() },
|
||||
A::If { condition, then_body, else_body, .. } => A::If {
|
||||
condition: Box::new(transform_map_insert_tag(condition)),
|
||||
then_body: then_body.iter().map(transform_map_insert_tag).collect(),
|
||||
else_body: else_body.as_ref().map(|v| v.iter().map(transform_map_insert_tag).collect()),
|
||||
A::Program { statements, .. } => A::Program {
|
||||
statements: statements.iter().map(transform_map_insert_tag).collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Print { expression, .. } => A::Print {
|
||||
expression: Box::new(transform_map_insert_tag(expression)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Return { value, .. } => A::Return {
|
||||
value: value
|
||||
.as_ref()
|
||||
.map(|v| Box::new(transform_map_insert_tag(v))),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::Assignment { target, value, .. } => A::Assignment {
|
||||
target: Box::new(transform_map_insert_tag(target)),
|
||||
value: Box::new(transform_map_insert_tag(value)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
} => A::If {
|
||||
condition: Box::new(transform_map_insert_tag(condition)),
|
||||
then_body: then_body.iter().map(transform_map_insert_tag).collect(),
|
||||
else_body: else_body
|
||||
.as_ref()
|
||||
.map(|v| v.iter().map(transform_map_insert_tag).collect()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} => A::BinaryOp {
|
||||
operator: operator.clone(),
|
||||
left: Box::new(transform_map_insert_tag(left)),
|
||||
right: Box::new(transform_map_insert_tag(right)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator, operand, ..
|
||||
} => A::UnaryOp {
|
||||
operator: operator.clone(),
|
||||
operand: Box::new(transform_map_insert_tag(operand)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
..
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_map_insert_tag(object)),
|
||||
method: method.clone(),
|
||||
arguments: arguments.iter().map(transform_map_insert_tag).collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::FunctionCall {
|
||||
name, arguments, ..
|
||||
} => A::FunctionCall {
|
||||
name: name.clone(),
|
||||
arguments: arguments.iter().map(transform_map_insert_tag).collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
A::BinaryOp { operator, left, right, .. } => A::BinaryOp { operator: operator.clone(), left: Box::new(transform_map_insert_tag(left)), right: Box::new(transform_map_insert_tag(right)), span: Span::unknown() },
|
||||
A::UnaryOp { operator, operand, .. } => A::UnaryOp { operator: operator.clone(), operand: Box::new(transform_map_insert_tag(operand)), span: Span::unknown() },
|
||||
A::MethodCall { object, method, arguments, .. } => A::MethodCall { object: Box::new(transform_map_insert_tag(object)), method: method.clone(), arguments: arguments.iter().map(transform_map_insert_tag).collect(), span: Span::unknown() },
|
||||
A::FunctionCall { name, arguments, .. } => A::FunctionCall { name: name.clone(), arguments: arguments.iter().map(transform_map_insert_tag).collect(), span: Span::unknown() },
|
||||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
* Macro child transforms — split modules
|
||||
*/
|
||||
|
||||
mod peek;
|
||||
mod array;
|
||||
mod map;
|
||||
mod loops;
|
||||
mod foreach;
|
||||
mod scopebox;
|
||||
mod lift;
|
||||
mod if_to_loopform;
|
||||
mod lift;
|
||||
mod loops;
|
||||
mod map;
|
||||
mod peek;
|
||||
mod postfix;
|
||||
mod scopebox;
|
||||
|
||||
// Re-exported via thin wrappers to keep names stable
|
||||
pub(super) fn transform_peek_match_literal(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
@ -47,15 +47,33 @@ pub fn normalize_core_pass(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
let a1 = transform_for_foreach(ast);
|
||||
let a2 = transform_peek_match_literal(&a1);
|
||||
let a3 = transform_loop_normalize(&a2);
|
||||
let a4 = if std::env::var("NYASH_SCOPEBOX_ENABLE").ok().map(|v| v=="1"||v=="true"||v=="on").unwrap_or(false) {
|
||||
let a4 = if std::env::var("NYASH_SCOPEBOX_ENABLE")
|
||||
.ok()
|
||||
.map(|v| v == "1" || v == "true" || v == "on")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
transform_scopebox_inject(&a3)
|
||||
} else { a3 };
|
||||
} else {
|
||||
a3
|
||||
};
|
||||
let a4b = transform_lift_nested_functions(&a4);
|
||||
let a5 = if std::env::var("NYASH_IF_AS_LOOPFORM").ok().map(|v| v=="1"||v=="true"||v=="on").unwrap_or(false) {
|
||||
let a5 = if std::env::var("NYASH_IF_AS_LOOPFORM")
|
||||
.ok()
|
||||
.map(|v| v == "1" || v == "true" || v == "on")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
transform_if_to_loopform(&a4b)
|
||||
} else { a4b };
|
||||
let a6 = if std::env::var("NYASH_CATCH_NEW").ok().map(|v| v=="1"||v=="true"||v=="on").unwrap_or(false) {
|
||||
} else {
|
||||
a4b
|
||||
};
|
||||
let a6 = if std::env::var("NYASH_CATCH_NEW")
|
||||
.ok()
|
||||
.map(|v| v == "1" || v == "true" || v == "on")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
transform_postfix_handlers(&a5)
|
||||
} else { a5 };
|
||||
} else {
|
||||
a5
|
||||
};
|
||||
a6
|
||||
}
|
||||
|
||||
@ -1,113 +1,329 @@
|
||||
fn map_expr_to_stmt(e: nyash_rust::ASTNode) -> nyash_rust::ASTNode { e }
|
||||
fn map_expr_to_stmt(e: nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
e
|
||||
}
|
||||
|
||||
fn transform_peek_to_if_expr(peek: &nyash_rust::ASTNode) -> Option<nyash_rust::ASTNode> {
|
||||
use nyash_rust::ast::{ASTNode as A, BinaryOperator, Span};
|
||||
if let A::MatchExpr { scrutinee, arms, else_expr, .. } = peek {
|
||||
if let A::MatchExpr {
|
||||
scrutinee,
|
||||
arms,
|
||||
else_expr,
|
||||
..
|
||||
} = peek
|
||||
{
|
||||
let mut conds_bodies: Vec<(nyash_rust::ast::LiteralValue, A)> = Vec::new();
|
||||
for (lit, body) in arms { conds_bodies.push((lit.clone(), (*body).clone())); }
|
||||
for (lit, body) in arms {
|
||||
conds_bodies.push((lit.clone(), (*body).clone()));
|
||||
}
|
||||
let mut current: A = *(*else_expr).clone();
|
||||
for (lit, body) in conds_bodies.into_iter().rev() {
|
||||
let rhs = A::Literal { value: lit, span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Equal, left: scrutinee.clone(), right: Box::new(rhs), span: Span::unknown() };
|
||||
let rhs = A::Literal {
|
||||
value: lit,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let cond = A::BinaryOp {
|
||||
operator: BinaryOperator::Equal,
|
||||
left: scrutinee.clone(),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let then_body = vec![map_expr_to_stmt(body)];
|
||||
let else_body = Some(vec![map_expr_to_stmt(current)]);
|
||||
current = A::If { condition: Box::new(cond), then_body, else_body, span: Span::unknown() };
|
||||
current = A::If {
|
||||
condition: Box::new(cond),
|
||||
then_body,
|
||||
else_body,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
Some(current)
|
||||
} else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_peek_to_if_stmt_assign(peek: &nyash_rust::ASTNode, target: &nyash_rust::ASTNode) -> Option<nyash_rust::ASTNode> {
|
||||
fn transform_peek_to_if_stmt_assign(
|
||||
peek: &nyash_rust::ASTNode,
|
||||
target: &nyash_rust::ASTNode,
|
||||
) -> Option<nyash_rust::ASTNode> {
|
||||
use nyash_rust::ast::{ASTNode as A, BinaryOperator, Span};
|
||||
if let A::MatchExpr { scrutinee, arms, else_expr, .. } = peek {
|
||||
if let A::MatchExpr {
|
||||
scrutinee,
|
||||
arms,
|
||||
else_expr,
|
||||
..
|
||||
} = peek
|
||||
{
|
||||
let mut pairs: Vec<(nyash_rust::ast::LiteralValue, A)> = Vec::new();
|
||||
for (lit, body) in arms { pairs.push((lit.clone(), (*body).clone())); }
|
||||
for (lit, body) in arms {
|
||||
pairs.push((lit.clone(), (*body).clone()));
|
||||
}
|
||||
let mut current: A = *(*else_expr).clone();
|
||||
for (lit, body) in pairs.into_iter().rev() {
|
||||
let rhs = A::Literal { value: lit, span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Equal, left: scrutinee.clone(), right: Box::new(rhs), span: Span::unknown() };
|
||||
let then_body = vec![A::Assignment { target: Box::new(target.clone()), value: Box::new(body), span: Span::unknown() }];
|
||||
let rhs = A::Literal {
|
||||
value: lit,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let cond = A::BinaryOp {
|
||||
operator: BinaryOperator::Equal,
|
||||
left: scrutinee.clone(),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let then_body = vec![A::Assignment {
|
||||
target: Box::new(target.clone()),
|
||||
value: Box::new(body),
|
||||
span: Span::unknown(),
|
||||
}];
|
||||
let else_body = Some(vec![map_expr_to_stmt(current)]);
|
||||
current = A::If { condition: Box::new(cond), then_body, else_body, span: Span::unknown() };
|
||||
current = A::If {
|
||||
condition: Box::new(cond),
|
||||
then_body,
|
||||
else_body,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
Some(current)
|
||||
} else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_peek_to_if_stmt_return(peek: &nyash_rust::ASTNode) -> Option<nyash_rust::ASTNode> {
|
||||
use nyash_rust::ast::{ASTNode as A, BinaryOperator, Span};
|
||||
if let A::MatchExpr { scrutinee, arms, else_expr, .. } = peek {
|
||||
if let A::MatchExpr {
|
||||
scrutinee,
|
||||
arms,
|
||||
else_expr,
|
||||
..
|
||||
} = peek
|
||||
{
|
||||
let mut pairs: Vec<(nyash_rust::ast::LiteralValue, A)> = Vec::new();
|
||||
for (lit, body) in arms { pairs.push((lit.clone(), (*body).clone())); }
|
||||
for (lit, body) in arms {
|
||||
pairs.push((lit.clone(), (*body).clone()));
|
||||
}
|
||||
let mut current: A = *(*else_expr).clone();
|
||||
for (lit, body) in pairs.into_iter().rev() {
|
||||
let rhs = A::Literal { value: lit, span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Equal, left: scrutinee.clone(), right: Box::new(rhs), span: Span::unknown() };
|
||||
let then_body = vec![A::Return { value: Some(Box::new(body)), span: Span::unknown() }];
|
||||
let rhs = A::Literal {
|
||||
value: lit,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let cond = A::BinaryOp {
|
||||
operator: BinaryOperator::Equal,
|
||||
left: scrutinee.clone(),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let then_body = vec![A::Return {
|
||||
value: Some(Box::new(body)),
|
||||
span: Span::unknown(),
|
||||
}];
|
||||
let else_body = Some(vec![map_expr_to_stmt(current)]);
|
||||
current = A::If { condition: Box::new(cond), then_body, else_body, span: Span::unknown() };
|
||||
current = A::If {
|
||||
condition: Box::new(cond),
|
||||
then_body,
|
||||
else_body,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
Some(current)
|
||||
} else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_peek_to_if_stmt_print(peek: &nyash_rust::ASTNode) -> Option<nyash_rust::ASTNode> {
|
||||
use nyash_rust::ast::{ASTNode as A, BinaryOperator, Span};
|
||||
if let A::MatchExpr { scrutinee, arms, else_expr, .. } = peek {
|
||||
if let A::MatchExpr {
|
||||
scrutinee,
|
||||
arms,
|
||||
else_expr,
|
||||
..
|
||||
} = peek
|
||||
{
|
||||
let mut pairs: Vec<(nyash_rust::ast::LiteralValue, A)> = Vec::new();
|
||||
for (lit, body) in arms { pairs.push((lit.clone(), (*body).clone())); }
|
||||
for (lit, body) in arms {
|
||||
pairs.push((lit.clone(), (*body).clone()));
|
||||
}
|
||||
let mut current: A = *(*else_expr).clone();
|
||||
for (lit, body) in pairs.into_iter().rev() {
|
||||
let rhs = A::Literal { value: lit, span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Equal, left: scrutinee.clone(), right: Box::new(rhs), span: Span::unknown() };
|
||||
let then_body = vec![A::Print { expression: Box::new(body), span: Span::unknown() }];
|
||||
let rhs = A::Literal {
|
||||
value: lit,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let cond = A::BinaryOp {
|
||||
operator: BinaryOperator::Equal,
|
||||
left: scrutinee.clone(),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let then_body = vec![A::Print {
|
||||
expression: Box::new(body),
|
||||
span: Span::unknown(),
|
||||
}];
|
||||
let else_body = Some(vec![map_expr_to_stmt(current)]);
|
||||
current = A::If { condition: Box::new(cond), then_body, else_body, span: Span::unknown() };
|
||||
current = A::If {
|
||||
condition: Box::new(cond),
|
||||
then_body,
|
||||
else_body,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
Some(current)
|
||||
} else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn transform_peek_match_literal(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: statements.into_iter().map(|n| transform_peek_match_literal(&n)).collect(), span },
|
||||
A::If { condition, then_body, else_body, span } => A::If {
|
||||
condition: Box::new(transform_peek_match_literal(&condition)),
|
||||
then_body: then_body.into_iter().map(|n| transform_peek_match_literal(&n)).collect(),
|
||||
else_body: else_body.map(|v| v.into_iter().map(|n| transform_peek_match_literal(&n)).collect()),
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.into_iter()
|
||||
.map(|n| transform_peek_match_literal(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::Loop { condition, body, span } => A::Loop {
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(transform_peek_match_literal(&condition)),
|
||||
body: body.into_iter().map(|n| transform_peek_match_literal(&n)).collect(),
|
||||
then_body: then_body
|
||||
.into_iter()
|
||||
.map(|n| transform_peek_match_literal(&n))
|
||||
.collect(),
|
||||
else_body: else_body.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|n| transform_peek_match_literal(&n))
|
||||
.collect()
|
||||
}),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_peek_match_literal(&left)), right: Box::new(transform_peek_match_literal(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_peek_match_literal(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_peek_match_literal(&object)), method, arguments: arguments.into_iter().map(|a| transform_peek_match_literal(&a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => {
|
||||
if let Some(if_expr) = transform_peek_to_if_expr(&A::FunctionCall { name: name.clone(), arguments: arguments.clone(), span }) {
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => A::Loop {
|
||||
condition: Box::new(transform_peek_match_literal(&condition)),
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|n| transform_peek_match_literal(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_peek_match_literal(&left)),
|
||||
right: Box::new(transform_peek_match_literal(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_peek_match_literal(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_peek_match_literal(&object)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_peek_match_literal(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => {
|
||||
if let Some(if_expr) = transform_peek_to_if_expr(&A::FunctionCall {
|
||||
name: name.clone(),
|
||||
arguments: arguments.clone(),
|
||||
span,
|
||||
}) {
|
||||
if_expr
|
||||
} else { A::FunctionCall { name, arguments: arguments.into_iter().map(|a| transform_peek_match_literal(&a)).collect(), span } }
|
||||
} else {
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_peek_match_literal(&a))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| transform_peek_match_literal(&e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k, v)| (k, transform_peek_match_literal(&v))).collect(), span },
|
||||
A::Assignment { target, value, span } => {
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_assign(&value, &target) { ifstmt }
|
||||
else { A::Assignment { target, value: Box::new(transform_peek_match_literal(&value)), span } }
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| transform_peek_match_literal(&e))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, transform_peek_match_literal(&v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::Assignment {
|
||||
target,
|
||||
value,
|
||||
span,
|
||||
} => {
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_assign(&value, &target) {
|
||||
ifstmt
|
||||
} else {
|
||||
A::Assignment {
|
||||
target,
|
||||
value: Box::new(transform_peek_match_literal(&value)),
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
A::Return { value, span } => {
|
||||
if let Some(v) = &value {
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_return(v) { ifstmt }
|
||||
else { A::Return { value: Some(Box::new(transform_peek_match_literal(v))), span } }
|
||||
} else { A::Return { value: None, span } }
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_return(v) {
|
||||
ifstmt
|
||||
} else {
|
||||
A::Return {
|
||||
value: Some(Box::new(transform_peek_match_literal(v))),
|
||||
span,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
A::Return { value: None, span }
|
||||
}
|
||||
}
|
||||
A::Print { expression, span } => {
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_print(&expression) { ifstmt }
|
||||
else { A::Print { expression: Box::new(transform_peek_match_literal(&expression)), span } }
|
||||
if let Some(ifstmt) = transform_peek_to_if_stmt_print(&expression) {
|
||||
ifstmt
|
||||
} else {
|
||||
A::Print {
|
||||
expression: Box::new(transform_peek_match_literal(&expression)),
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,74 @@
|
||||
pub(super) fn transform_postfix_handlers(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::{ASTNode as A, CatchClause, Span};
|
||||
fn map_vec(v: Vec<A>) -> Vec<A> { v.into_iter().map(|n| transform_postfix_handlers(&n)).collect() }
|
||||
fn map_vec(v: Vec<A>) -> Vec<A> {
|
||||
v.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect()
|
||||
}
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: map_vec(statements), span },
|
||||
A::If { condition, then_body, else_body, span } => A::If { condition: Box::new(transform_postfix_handlers(&condition)), then_body: map_vec(then_body), else_body: else_body.map(map_vec), span },
|
||||
A::Loop { condition, body, span } => A::Loop { condition: Box::new(transform_postfix_handlers(&condition)), body: map_vec(body), span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_postfix_handlers(&left)), right: Box::new(transform_postfix_handlers(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_postfix_handlers(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_postfix_handlers(&object)), method, arguments: arguments.into_iter().map(|a| transform_postfix_handlers(&a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => {
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: map_vec(statements),
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => A::If {
|
||||
condition: Box::new(transform_postfix_handlers(&condition)),
|
||||
then_body: map_vec(then_body),
|
||||
else_body: else_body.map(map_vec),
|
||||
span,
|
||||
},
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => A::Loop {
|
||||
condition: Box::new(transform_postfix_handlers(&condition)),
|
||||
body: map_vec(body),
|
||||
span,
|
||||
},
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_postfix_handlers(&left)),
|
||||
right: Box::new(transform_postfix_handlers(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_postfix_handlers(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_postfix_handlers(&object)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_postfix_handlers(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => {
|
||||
let name_l = name.to_ascii_lowercase();
|
||||
if name_l == "postfix_catch" {
|
||||
let mut args = arguments;
|
||||
@ -17,17 +77,32 @@ pub(super) fn transform_postfix_handlers(ast: &nyash_rust::ASTNode) -> nyash_rus
|
||||
let (type_opt, handler) = if args.len() == 1 {
|
||||
(None, args.remove(0))
|
||||
} else if args.len() >= 2 {
|
||||
let ty = match args.remove(0) { A::Literal { value: nyash_rust::ast::LiteralValue::String(s), .. } => Some(s), _ => None };
|
||||
let ty = match args.remove(0) {
|
||||
A::Literal {
|
||||
value: nyash_rust::ast::LiteralValue::String(s),
|
||||
..
|
||||
} => Some(s),
|
||||
_ => None,
|
||||
};
|
||||
(ty, args.remove(0))
|
||||
} else {
|
||||
(None, A::Literal { value: nyash_rust::ast::LiteralValue::Integer(0), span: Span::unknown() })
|
||||
(
|
||||
None,
|
||||
A::Literal {
|
||||
value: nyash_rust::ast::LiteralValue::Integer(0),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
)
|
||||
};
|
||||
if let A::Lambda { params, body, .. } = handler {
|
||||
if params.len() == 1 {
|
||||
let cc = CatchClause {
|
||||
exception_type: type_opt,
|
||||
variable_name: Some(params[0].clone()),
|
||||
body: body.into_iter().map(|n| transform_postfix_handlers(&n)).collect(),
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect(),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
return A::TryCatch {
|
||||
@ -39,7 +114,14 @@ pub(super) fn transform_postfix_handlers(ast: &nyash_rust::ASTNode) -> nyash_rus
|
||||
}
|
||||
}
|
||||
}
|
||||
A::FunctionCall { name, arguments: args.into_iter().map(|n| transform_postfix_handlers(&n)).collect(), span }
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments: args
|
||||
.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
} else if name_l == "with_cleanup" {
|
||||
let mut args = arguments;
|
||||
if args.len() >= 2 {
|
||||
@ -50,20 +132,49 @@ pub(super) fn transform_postfix_handlers(ast: &nyash_rust::ASTNode) -> nyash_rus
|
||||
return A::TryCatch {
|
||||
try_body: vec![expr],
|
||||
catch_clauses: vec![],
|
||||
finally_body: Some(body.into_iter().map(|n| transform_postfix_handlers(&n)).collect()),
|
||||
finally_body: Some(
|
||||
body.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect(),
|
||||
),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
A::FunctionCall { name, arguments: args.into_iter().map(|n| transform_postfix_handlers(&n)).collect(), span }
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments: args
|
||||
.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
} else {
|
||||
A::FunctionCall { name, arguments: arguments.into_iter().map(|n| transform_postfix_handlers(&n)).collect(), span }
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|n| transform_postfix_handlers(&n))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| transform_postfix_handlers(&e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k,v)| (k, transform_postfix_handlers(&v))).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| transform_postfix_handlers(&e))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, transform_postfix_handlers(&v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,25 +1,122 @@
|
||||
pub(super) fn transform_scopebox_inject(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match ast.clone() {
|
||||
A::Program { statements, span } => A::Program { statements: statements.into_iter().map(|n| transform_scopebox_inject(&n)).collect(), span },
|
||||
A::If { condition, then_body, else_body, span } => {
|
||||
A::Program { statements, span } => A::Program {
|
||||
statements: statements
|
||||
.into_iter()
|
||||
.map(|n| transform_scopebox_inject(&n))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
span,
|
||||
} => {
|
||||
let cond = Box::new(transform_scopebox_inject(&condition));
|
||||
let then_wrapped = vec![A::ScopeBox { body: then_body.into_iter().map(|n| transform_scopebox_inject(&n)).collect(), span: nyash_rust::ast::Span::unknown() }];
|
||||
let else_wrapped = else_body.map(|v| vec![A::ScopeBox { body: v.into_iter().map(|n| transform_scopebox_inject(&n)).collect(), span: nyash_rust::ast::Span::unknown() }]);
|
||||
A::If { condition: cond, then_body: then_wrapped, else_body: else_wrapped, span }
|
||||
let then_wrapped = vec![A::ScopeBox {
|
||||
body: then_body
|
||||
.into_iter()
|
||||
.map(|n| transform_scopebox_inject(&n))
|
||||
.collect(),
|
||||
span: nyash_rust::ast::Span::unknown(),
|
||||
}];
|
||||
let else_wrapped = else_body.map(|v| {
|
||||
vec![A::ScopeBox {
|
||||
body: v
|
||||
.into_iter()
|
||||
.map(|n| transform_scopebox_inject(&n))
|
||||
.collect(),
|
||||
span: nyash_rust::ast::Span::unknown(),
|
||||
}]
|
||||
});
|
||||
A::If {
|
||||
condition: cond,
|
||||
then_body: then_wrapped,
|
||||
else_body: else_wrapped,
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::Loop { condition, body, span } => {
|
||||
A::Loop {
|
||||
condition,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let cond = Box::new(transform_scopebox_inject(&condition));
|
||||
let body_wrapped = vec![A::ScopeBox { body: body.into_iter().map(|n| transform_scopebox_inject(&n)).collect(), span: nyash_rust::ast::Span::unknown() }];
|
||||
A::Loop { condition: cond, body: body_wrapped, span }
|
||||
let body_wrapped = vec![A::ScopeBox {
|
||||
body: body
|
||||
.into_iter()
|
||||
.map(|n| transform_scopebox_inject(&n))
|
||||
.collect(),
|
||||
span: nyash_rust::ast::Span::unknown(),
|
||||
}];
|
||||
A::Loop {
|
||||
condition: cond,
|
||||
body: body_wrapped,
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left: Box::new(transform_scopebox_inject(&left)), right: Box::new(transform_scopebox_inject(&right)), span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand: Box::new(transform_scopebox_inject(&operand)), span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object: Box::new(transform_scopebox_inject(&object)), method, arguments: arguments.into_iter().map(|a| transform_scopebox_inject(&a)).collect(), span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments: arguments.into_iter().map(|a| transform_scopebox_inject(&a)).collect(), span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements: elements.into_iter().map(|e| transform_scopebox_inject(&e)).collect(), span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries: entries.into_iter().map(|(k, v)| (k, transform_scopebox_inject(&v))).collect(), span },
|
||||
A::BinaryOp {
|
||||
operator,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
} => A::BinaryOp {
|
||||
operator,
|
||||
left: Box::new(transform_scopebox_inject(&left)),
|
||||
right: Box::new(transform_scopebox_inject(&right)),
|
||||
span,
|
||||
},
|
||||
A::UnaryOp {
|
||||
operator,
|
||||
operand,
|
||||
span,
|
||||
} => A::UnaryOp {
|
||||
operator,
|
||||
operand: Box::new(transform_scopebox_inject(&operand)),
|
||||
span,
|
||||
},
|
||||
A::MethodCall {
|
||||
object,
|
||||
method,
|
||||
arguments,
|
||||
span,
|
||||
} => A::MethodCall {
|
||||
object: Box::new(transform_scopebox_inject(&object)),
|
||||
method,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_scopebox_inject(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::FunctionCall {
|
||||
name,
|
||||
arguments,
|
||||
span,
|
||||
} => A::FunctionCall {
|
||||
name,
|
||||
arguments: arguments
|
||||
.into_iter()
|
||||
.map(|a| transform_scopebox_inject(&a))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral {
|
||||
elements: elements
|
||||
.into_iter()
|
||||
.map(|e| transform_scopebox_inject(&e))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
A::MapLiteral { entries, span } => A::MapLiteral {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, transform_scopebox_inject(&v)))
|
||||
.collect(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user