macro(loopform): add LoopNormalize behavior routing (identity for MVP); AST JSON Local support
This commit is contained in:
@ -25,6 +25,7 @@ Kinds (subset for Phase 2+)
|
||||
- FunctionCall: { kind: "FunctionCall", name: string, arguments: [Node] }
|
||||
- Array: { kind: "Array", elements: [Node] }
|
||||
- Map: { kind: "Map", entries: [{k: string, v: Node}] }
|
||||
- Local: { kind: "Local", variables: [string], inits: [Node|null] }
|
||||
|
||||
LiteralValue
|
||||
- { type: "string", value: string }
|
||||
|
||||
@ -27,6 +27,11 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
|
||||
"target": ast_to_json(&target),
|
||||
"value": ast_to_json(&value),
|
||||
}),
|
||||
ASTNode::Local { variables, initial_values, .. } => json!({
|
||||
"kind": "Local",
|
||||
"variables": variables,
|
||||
"inits": initial_values.into_iter().map(|opt| opt.map(|v| ast_to_json(&v))).collect::<Vec<_>>()
|
||||
}),
|
||||
ASTNode::If { condition, then_body, else_body, .. } => json!({
|
||||
"kind": "If",
|
||||
"condition": ast_to_json(&condition),
|
||||
@ -94,6 +99,13 @@ pub fn json_to_ast(v: &Value) -> Option<ASTNode> {
|
||||
"Break" => ASTNode::Break { span: Span::unknown() },
|
||||
"Continue" => ASTNode::Continue { span: Span::unknown() },
|
||||
"Assignment" => ASTNode::Assignment { target: Box::new(json_to_ast(v.get("target")?)?), value: Box::new(json_to_ast(v.get("value")?)?), span: Span::unknown() },
|
||||
"Local" => {
|
||||
let vars = v.get("variables")?.as_array()?.iter().filter_map(|s| s.as_str().map(|x| x.to_string())).collect();
|
||||
let inits = v.get("inits")?.as_array()?.iter().map(|initv| {
|
||||
if initv.is_null() { None } else { json_to_ast(initv).map(Box::new) }
|
||||
}).collect();
|
||||
ASTNode::Local { variables: vars, initial_values: inits, span: Span::unknown() }
|
||||
},
|
||||
"If" => ASTNode::If { condition: Box::new(json_to_ast(v.get("condition")?)?), then_body: v.get("then")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>(), else_body: v.get("else").and_then(|a| a.as_array().map(|arr| arr.iter().filter_map(json_to_ast).collect::<Vec<_>>())), span: Span::unknown() },
|
||||
"FunctionDeclaration" => ASTNode::FunctionDeclaration {
|
||||
name: v.get("name")?.as_str()?.to_string(),
|
||||
|
||||
@ -175,7 +175,7 @@ fn expand_indicates_uppercase(body: &Vec<ASTNode>, params: &Vec<String>) -> bool
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MacroBehavior { Identity, Uppercase, ArrayPrependZero, MapInsertTag }
|
||||
pub enum MacroBehavior { Identity, Uppercase, ArrayPrependZero, MapInsertTag, LoopNormalize }
|
||||
|
||||
pub fn analyze_macro_file(path: &str) -> MacroBehavior {
|
||||
let src = match std::fs::read_to_string(path) { Ok(s) => s, Err(_) => return MacroBehavior::Identity };
|
||||
@ -241,6 +241,18 @@ pub fn analyze_macro_file(path: &str) -> MacroBehavior {
|
||||
if let ASTNode::Program { statements, .. } = ast {
|
||||
for st in statements {
|
||||
if let ASTNode::BoxDeclaration { name: _, methods, .. } = st {
|
||||
// Detect LoopNormalize by name() returning a specific string
|
||||
if let Some(ASTNode::FunctionDeclaration { name: mname, body, .. }) = methods.get("name") {
|
||||
if mname == "name" {
|
||||
if body.len() == 1 {
|
||||
if let ASTNode::Return { value: Some(v), .. } = &body[0] {
|
||||
if let ASTNode::Literal { value: nyash_rust::ast::LiteralValue::String(s), .. } = &**v {
|
||||
if s == "LoopNormalize" { return MacroBehavior::LoopNormalize; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ASTNode::FunctionDeclaration { name: mname, body, params, .. }) = methods.get("expand") {
|
||||
if mname == "expand" {
|
||||
if expand_indicates_uppercase(body, params) {
|
||||
|
||||
@ -95,6 +95,10 @@ 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()
|
||||
}
|
||||
};
|
||||
let out_json = crate::r#macro::ast_json::ast_to_json(&out_ast);
|
||||
println!("{}", out_json.to_string());
|
||||
|
||||
Reference in New Issue
Block a user