core: for/foreach -> Loop normalization (always-on); LoopForm MVP-3 per-segment reorder; smokes stabilized (VM + LLVM PHI); docs updated (macro-system, loopform); quiet macro load logs
This commit is contained in:
@ -31,6 +31,7 @@ impl NyashRunner {
|
||||
};
|
||||
// Macro expansion (env-gated)
|
||||
let ast = crate::r#macro::maybe_expand_and_dump(&ast, false);
|
||||
let ast = crate::runner::modes::macro_child::normalize_core_pass(&ast);
|
||||
|
||||
// Compile to MIR
|
||||
let mut mir_compiler = MirCompiler::new();
|
||||
|
||||
@ -206,6 +206,354 @@ fn transform_map_insert_tag(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_loop_normalize(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::ASTNode as A;
|
||||
match ast.clone() {
|
||||
// Recurse into container nodes first
|
||||
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()),
|
||||
span,
|
||||
}
|
||||
}
|
||||
A::Loop { condition, body, span } => {
|
||||
// First, normalize inside children
|
||||
let condition = Box::new(transform_loop_normalize(&condition));
|
||||
let body_norm: Vec<A> = body.into_iter().map(|n| transform_loop_normalize(&n)).collect();
|
||||
|
||||
// MVP-3: break/continue 最小対応
|
||||
// 方針: 本体を control(Break/Continue) でセグメントに分割し、
|
||||
// 各セグメント内のみ安全に「非代入→代入」に整列する(順序維持の安定版)。
|
||||
// 追加ガード: 代入先は変数に限る。変数の種類は全体で最大2種まで(MVP-2 制約維持)。
|
||||
|
||||
// まず全体の更新変数の種類数を計測(上限2)。
|
||||
let mut uniq_targets_overall: Vec<String> = Vec::new();
|
||||
for stmt in &body_norm {
|
||||
if let A::Assignment { target, .. } = stmt {
|
||||
if let A::Variable { name, .. } = target.as_ref() {
|
||||
if !uniq_targets_overall.iter().any(|s| s == name) {
|
||||
uniq_targets_overall.push(name.clone());
|
||||
if uniq_targets_overall.len() > 2 { // 超過したら全体の並べ替えは不許可
|
||||
return A::Loop { condition, body: body_norm, span };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 複合ターゲットを含む場合は保守的にスキップ
|
||||
return A::Loop { condition, body: body_norm, span };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// セグメント分解 → セグメント毎に安全整列
|
||||
let mut rebuilt: Vec<A> = Vec::with_capacity(body_norm.len());
|
||||
let mut seg: Vec<A> = Vec::new();
|
||||
let flush_seg = |seg: &mut Vec<A>, out: &mut Vec<A>| {
|
||||
// セグメント内で「代入の後に非代入」が存在したら整列しない
|
||||
let mut saw_assign = false;
|
||||
let mut safe = true;
|
||||
for n in seg.iter() {
|
||||
match n {
|
||||
A::Assignment { .. } => { saw_assign = true; }
|
||||
_ => {
|
||||
if saw_assign { safe = false; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if safe {
|
||||
// others → assigns の順で安定整列
|
||||
let mut others: Vec<A> = Vec::new();
|
||||
let mut assigns: Vec<A> = Vec::new();
|
||||
for n in seg.drain(..) {
|
||||
match n {
|
||||
A::Assignment { .. } => assigns.push(n),
|
||||
_ => others.push(n),
|
||||
}
|
||||
}
|
||||
out.extend(others.into_iter());
|
||||
out.extend(assigns.into_iter());
|
||||
} else {
|
||||
// そのまま吐き出す
|
||||
out.extend(seg.drain(..));
|
||||
}
|
||||
};
|
||||
|
||||
for stmt in body_norm.into_iter() {
|
||||
match stmt.clone() {
|
||||
A::Break { .. } | A::Continue { .. } => {
|
||||
// control の直前までをフラッシュしてから control を出力
|
||||
flush_seg(&mut seg, &mut rebuilt);
|
||||
rebuilt.push(stmt);
|
||||
}
|
||||
other => seg.push(other),
|
||||
}
|
||||
}
|
||||
// 末尾セグメントをフラッシュ
|
||||
flush_seg(&mut seg, &mut rebuilt);
|
||||
|
||||
A::Loop { condition, body: rebuilt, span }
|
||||
}
|
||||
// Leaf and other nodes: unchanged
|
||||
A::Local { variables, initial_values, span } => A::Local { variables, initial_values, span },
|
||||
A::Assignment { target, value, span } => A::Assignment { target, value, span },
|
||||
A::Return { value, span } => A::Return { value, span },
|
||||
A::Print { expression, span } => A::Print { expression, span },
|
||||
A::BinaryOp { operator, left, right, span } => A::BinaryOp { operator, left, right, span },
|
||||
A::UnaryOp { operator, operand, span } => A::UnaryOp { operator, operand, span },
|
||||
A::MethodCall { object, method, arguments, span } => A::MethodCall { object, method, arguments, span },
|
||||
A::FunctionCall { name, arguments, span } => A::FunctionCall { name, arguments, span },
|
||||
A::ArrayLiteral { elements, span } => A::ArrayLiteral { elements, span },
|
||||
A::MapLiteral { entries, span } => A::MapLiteral { entries, span },
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
// Core normalization pass used by runners (always-on when macros enabled).
|
||||
// Order matters: for/foreach → match(PeekExpr) → loop tail alignment.
|
||||
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);
|
||||
a3
|
||||
}
|
||||
|
||||
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()),
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_for_foreach(ast: &nyash_rust::ASTNode) -> nyash_rust::ASTNode {
|
||||
use nyash_rust::ast::{ASTNode as A, BinaryOperator, LiteralValue, Span};
|
||||
|
||||
fn rewrite_stmt_list(list: Vec<A>) -> Vec<A> {
|
||||
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 => {
|
||||
let init = arguments[0].clone();
|
||||
let cond = arguments[1].clone();
|
||||
let step = arguments[2].clone();
|
||||
let body_lam = arguments[3].clone();
|
||||
if let A::Lambda { params, body, .. } = body_lam {
|
||||
if params.is_empty() {
|
||||
// Accept init as Local/Assignment or Lambda(); step as Assignment or Lambda()
|
||||
// Emit init statements (0..n)
|
||||
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)); }
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut loop_body: Vec<A> = body
|
||||
.into_iter()
|
||||
.map(|n| transform_for_foreach(&n))
|
||||
.collect();
|
||||
// Append step statements at tail
|
||||
match step.clone() {
|
||||
A::Assignment { .. } => loop_body.push(step),
|
||||
A::Lambda { params: p3, body: b3, .. } if p3.is_empty() => {
|
||||
for s in b3 { loop_body.push(transform_for_foreach(&s)); }
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
out.push(A::Loop { condition: Box::new(cond), body: loop_body, span: Span::unknown() });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Fallback: keep as-is
|
||||
out.push(A::FunctionCall { name, arguments, span: Span::unknown() });
|
||||
}
|
||||
A::FunctionCall { name, arguments, .. } if (name == "ny_foreach" || name == "foreach") && arguments.len() == 3 => {
|
||||
let arr = arguments[0].clone();
|
||||
let var_name_opt = match &arguments[1] { A::Literal { value: LiteralValue::String(s), .. } => Some(s.clone()), _ => None };
|
||||
let lam = arguments[2].clone();
|
||||
if let (Some(vn), A::Lambda { params, body, .. }) = (var_name_opt, lam) {
|
||||
if params.is_empty() {
|
||||
let idx_name = "__ny_i".to_string();
|
||||
let idx_var = A::Variable { name: idx_name.clone(), span: Span::unknown() };
|
||||
let init_idx = A::Local { variables: vec![idx_name.clone()], initial_values: vec![Some(Box::new(A::Literal { value: LiteralValue::Integer(0), span: Span::unknown() }))], span: Span::unknown() };
|
||||
let size_call = A::MethodCall { object: Box::new(arr.clone()), method: "size".to_string(), arguments: vec![], span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Less, left: Box::new(idx_var.clone()), right: Box::new(size_call), span: Span::unknown() };
|
||||
let elem = A::MethodCall { object: Box::new(arr.clone()), method: "get".to_string(), arguments: vec![idx_var.clone()], span: Span::unknown() };
|
||||
let mut loop_body: Vec<A> = body.into_iter().map(|n| subst_var(&n, &vn, &elem)).map(|n| transform_for_foreach(&n)).collect();
|
||||
let step = A::Assignment { target: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), value: Box::new(A::BinaryOp { operator: BinaryOperator::Add, left: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), right: Box::new(A::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), span: Span::unknown() }), span: Span::unknown() };
|
||||
loop_body.push(step);
|
||||
out.push(init_idx);
|
||||
out.push(A::Loop { condition: Box::new(cond), body: loop_body, span: Span::unknown() });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push(A::FunctionCall { name, arguments, span: Span::unknown() });
|
||||
}
|
||||
A::Local { variables, initial_values, .. } => {
|
||||
let mut expanded_any = false;
|
||||
for opt in &initial_values {
|
||||
if let Some(v) = opt {
|
||||
if let A::FunctionCall { name, arguments, .. } = v.as_ref() {
|
||||
if ((name == "ny_for" || name == "for") && arguments.len() == 4)
|
||||
|| ((name == "ny_foreach" || name == "foreach") && arguments.len() == 3)
|
||||
{
|
||||
expanded_any = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if expanded_any {
|
||||
for opt in initial_values {
|
||||
if let Some(v) = opt {
|
||||
match v.as_ref() {
|
||||
A::FunctionCall { name: _, arguments, .. } if (arguments.len() == 4) => {
|
||||
// Reuse handling by fabricating a statement call
|
||||
let fake = A::FunctionCall { name: "for".to_string(), arguments: arguments.clone(), span: Span::unknown() };
|
||||
// Route into the top arm by re-matching
|
||||
match fake.clone() {
|
||||
A::FunctionCall { name: _, arguments, .. } => {
|
||||
let init = arguments[0].clone();
|
||||
let cond = arguments[1].clone();
|
||||
let step = arguments[2].clone();
|
||||
let body_lam = arguments[3].clone();
|
||||
if let A::Lambda { params, body, .. } = body_lam {
|
||||
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)); } }
|
||||
_ => {}
|
||||
}
|
||||
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: p3, body: b3, .. } if p3.is_empty() => { for s in b3 { loop_body.push(transform_for_foreach(&s)); } }
|
||||
_ => {}
|
||||
}
|
||||
out.push(A::Loop { condition: Box::new(cond), body: loop_body, span: Span::unknown() });
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
A::FunctionCall { name: _, arguments, .. } if (arguments.len() == 3) => {
|
||||
let arr = arguments[0].clone();
|
||||
let var_name_opt = match &arguments[1] { A::Literal { value: LiteralValue::String(s), .. } => Some(s.clone()), _ => None };
|
||||
let lam = arguments[2].clone();
|
||||
if let (Some(vn), A::Lambda { params, body, .. }) = (var_name_opt, lam) {
|
||||
if params.is_empty() {
|
||||
let idx_name = "__ny_i".to_string();
|
||||
let idx_var = A::Variable { name: idx_name.clone(), span: Span::unknown() };
|
||||
let init_idx = A::Local { variables: vec![idx_name.clone()], initial_values: vec![Some(Box::new(A::Literal { value: LiteralValue::Integer(0), span: Span::unknown() }))], span: Span::unknown() };
|
||||
let size_call = A::MethodCall { object: Box::new(arr.clone()), method: "size".to_string(), arguments: vec![], span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Less, left: Box::new(idx_var.clone()), right: Box::new(size_call), span: Span::unknown() };
|
||||
let elem = A::MethodCall { object: Box::new(arr.clone()), method: "get".to_string(), arguments: vec![idx_var.clone()], span: Span::unknown() };
|
||||
let mut loop_body: Vec<A> = body.into_iter().map(|n| subst_var(&n, &vn, &elem)).map(|n| transform_for_foreach(&n)).collect();
|
||||
let step = A::Assignment { target: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), value: Box::new(A::BinaryOp { operator: BinaryOperator::Add, left: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), right: Box::new(A::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), span: Span::unknown() }), span: Span::unknown() };
|
||||
loop_body.push(step);
|
||||
out.push(init_idx);
|
||||
out.push(A::Loop { condition: Box::new(cond), body: loop_body, span: Span::unknown() });
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Drop original Local that carried macros
|
||||
continue;
|
||||
} else {
|
||||
out.push(A::Local { variables, initial_values, span: Span::unknown() });
|
||||
}
|
||||
}
|
||||
A::FunctionCall { name, arguments, .. } if name == "foreach_" && arguments.len() == 3 => {
|
||||
let arr = arguments[0].clone();
|
||||
let var_name_opt = match &arguments[1] { A::Literal { value: LiteralValue::String(s), .. } => Some(s.clone()), _ => None };
|
||||
let lam = arguments[2].clone();
|
||||
if let (Some(vn), A::Lambda { params, body, .. }) = (var_name_opt, lam) {
|
||||
if params.is_empty() {
|
||||
// __ny_i = 0; loop(__ny_i < arr.size()) { body[var=arr.get(__ny_i)]; __ny_i = __ny_i + 1 }
|
||||
let idx_name = "__ny_i".to_string();
|
||||
let idx_var = A::Variable { name: idx_name.clone(), span: Span::unknown() };
|
||||
let init_idx = A::Local { variables: vec![idx_name.clone()], initial_values: vec![Some(Box::new(A::Literal { value: LiteralValue::Integer(0), span: Span::unknown() }))], span: Span::unknown() };
|
||||
let size_call = A::MethodCall { object: Box::new(arr.clone()), method: "size".to_string(), arguments: vec![], span: Span::unknown() };
|
||||
let cond = A::BinaryOp { operator: BinaryOperator::Less, left: Box::new(idx_var.clone()), right: Box::new(size_call), span: Span::unknown() };
|
||||
let elem = A::MethodCall { object: Box::new(arr.clone()), method: "get".to_string(), arguments: vec![idx_var.clone()], span: Span::unknown() };
|
||||
let mut loop_body: Vec<A> = body.into_iter().map(|n| subst_var(&n, &vn, &elem)).map(|n| transform_for_foreach(&n)).collect();
|
||||
let step = A::Assignment { target: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), value: Box::new(A::BinaryOp { operator: BinaryOperator::Add, left: Box::new(A::Variable { name: idx_name.clone(), span: Span::unknown() }), right: Box::new(A::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), span: Span::unknown() }), span: Span::unknown() };
|
||||
loop_body.push(step);
|
||||
out.push(init_idx);
|
||||
out.push(A::Loop { condition: Box::new(cond), body: loop_body, span: Span::unknown() });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push(A::FunctionCall { name, arguments, span: Span::unknown() });
|
||||
}
|
||||
// Recurse into container nodes and preserve others
|
||||
A::If { condition, then_body, else_body, span } => {
|
||||
out.push(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 } => {
|
||||
out.push(A::Loop {
|
||||
condition: Box::new(transform_for_foreach(&condition)),
|
||||
body: rewrite_stmt_list(body),
|
||||
span,
|
||||
});
|
||||
}
|
||||
other => out.push(transform_for_foreach(&other)),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
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 },
|
||||
// Leaf and expression nodes: descend but no statement expansion
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_macro_child(macro_file: &str) {
|
||||
// Read stdin all
|
||||
use std::io::Read;
|
||||
@ -234,12 +582,14 @@ pub fn run_macro_child(macro_file: &str) {
|
||||
crate::r#macro::macro_box_ny::MacroBehavior::ArrayPrependZero => transform_array_prepend_zero(&ast),
|
||||
crate::r#macro::macro_box_ny::MacroBehavior::MapInsertTag => transform_map_insert_tag(&ast),
|
||||
crate::r#macro::macro_box_ny::MacroBehavior::LoopNormalize => {
|
||||
// MVP: identity (future: normalize Loop into carrier-based form)
|
||||
ast.clone()
|
||||
transform_loop_normalize(&ast)
|
||||
}
|
||||
crate::r#macro::macro_box_ny::MacroBehavior::IfMatchNormalize => {
|
||||
transform_peek_match_literal(&ast)
|
||||
}
|
||||
crate::r#macro::macro_box_ny::MacroBehavior::ForForeachNormalize => {
|
||||
transform_for_foreach(&ast)
|
||||
}
|
||||
};
|
||||
let out_json = crate::r#macro::ast_json::ast_to_json(&out_ast);
|
||||
println!("{}", out_json.to_string());
|
||||
|
||||
@ -22,6 +22,7 @@ pub fn execute_pyvm_only(_runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
};
|
||||
let ast = crate::r#macro::maybe_expand_and_dump(&ast, false);
|
||||
let ast = crate::runner::modes::macro_child::normalize_core_pass(&ast);
|
||||
|
||||
// Compile to MIR (respect default optimizer setting)
|
||||
let mut mir_compiler = MirCompiler::with_options(true);
|
||||
|
||||
Reference in New Issue
Block a user