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] }
|
- FunctionCall: { kind: "FunctionCall", name: string, arguments: [Node] }
|
||||||
- Array: { kind: "Array", elements: [Node] }
|
- Array: { kind: "Array", elements: [Node] }
|
||||||
- Map: { kind: "Map", entries: [{k: string, v: Node}] }
|
- Map: { kind: "Map", entries: [{k: string, v: Node}] }
|
||||||
|
- Local: { kind: "Local", variables: [string], inits: [Node|null] }
|
||||||
|
|
||||||
LiteralValue
|
LiteralValue
|
||||||
- { type: "string", value: string }
|
- { type: "string", value: string }
|
||||||
|
|||||||
@ -27,6 +27,11 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
|
|||||||
"target": ast_to_json(&target),
|
"target": ast_to_json(&target),
|
||||||
"value": ast_to_json(&value),
|
"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!({
|
ASTNode::If { condition, then_body, else_body, .. } => json!({
|
||||||
"kind": "If",
|
"kind": "If",
|
||||||
"condition": ast_to_json(&condition),
|
"condition": ast_to_json(&condition),
|
||||||
@ -94,6 +99,13 @@ pub fn json_to_ast(v: &Value) -> Option<ASTNode> {
|
|||||||
"Break" => ASTNode::Break { span: Span::unknown() },
|
"Break" => ASTNode::Break { span: Span::unknown() },
|
||||||
"Continue" => ASTNode::Continue { 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() },
|
"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() },
|
"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 {
|
"FunctionDeclaration" => ASTNode::FunctionDeclaration {
|
||||||
name: v.get("name")?.as_str()?.to_string(),
|
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)]
|
#[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 {
|
pub fn analyze_macro_file(path: &str) -> MacroBehavior {
|
||||||
let src = match std::fs::read_to_string(path) { Ok(s) => s, Err(_) => return MacroBehavior::Identity };
|
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 {
|
if let ASTNode::Program { statements, .. } = ast {
|
||||||
for st in statements {
|
for st in statements {
|
||||||
if let ASTNode::BoxDeclaration { name: _, methods, .. } = st {
|
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 let Some(ASTNode::FunctionDeclaration { name: mname, body, params, .. }) = methods.get("expand") {
|
||||||
if mname == "expand" {
|
if mname == "expand" {
|
||||||
if expand_indicates_uppercase(body, params) {
|
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::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::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);
|
let out_json = crate::r#macro::ast_json::ast_to_json(&out_ast);
|
||||||
println!("{}", out_json.to_string());
|
println!("{}", out_json.to_string());
|
||||||
|
|||||||
Reference in New Issue
Block a user