use nmbrs_runtime::scope_tree::{ScopeKind, ScopeTree};
use nmbrs_workload::parse::parse_workload;
use std::collections::HashMap;
#[test]
fn for_each_partition_workload_produces_comprehension_scope() {
let yaml = r#"
scenarios:
sweep:
- for: "p in partitions(\"linear:3\")"
phases:
- walk
phases:
walk:
cycles: 2
concurrency: 1
bindings: |
n := mod_in(cycle, p)
ops:
emit:
adapter: stdout
stmt: "n={n}"
"#;
let workload = parse_workload(yaml, &HashMap::new()).expect("YAML should parse");
let scenario_nodes: Vec<_> = workload
.scenarios
.get("sweep")
.expect("scenario `sweep` should exist")
.clone();
let tree = ScopeTree::build("sweep", &scenario_nodes);
let kinds: Vec<String> = tree
.iter_dfs()
.map(|(idx, n)| format!("[{idx}] {}", n.kind.label()))
.collect();
eprintln!("scope tree:\n{}", kinds.join("\n"));
let comprehension_count = tree
.iter_dfs()
.filter(|(_, n)| matches!(n.kind, ScopeKind::Comprehension { .. }))
.count();
assert_eq!(
comprehension_count,
1,
"expected exactly one Comprehension scope; got {comprehension_count}.\n{}",
kinds.join("\n")
);
let (_, comp_node) = tree
.iter_dfs()
.find(|(_, n)| matches!(n.kind, ScopeKind::Comprehension { .. }))
.expect("comp scope present");
if let ScopeKind::Comprehension { comprehension } = &comp_node.kind {
let pairs = comprehension.coordinate_specs();
assert_eq!(pairs.len(), 1, "single-clause for-each");
let (var, spec) = &pairs[0];
assert_eq!(var, "p", "var name");
assert_eq!(
spec, "partitions(\"linear:3\")",
"spec text must round-trip with quotes intact, got {spec:?}"
);
}
}
#[test]
fn install_chain_preserves_partition_iter_var_type_through_phase() {
use nmbrs_runtime::scope::build_phase_scope_kernel;
use nmbrs_workload::model::BindingsDef;
use polydat::ast::PortType;
use std::sync::Arc;
let workload_root = nmbrs_runtime::scope_kernel::ScopeKernel::compile("\n").unwrap();
let comp_kernel = nmbrs_runtime::scope_synth::build_for_each_scope_kernel(
&[("p".to_string(), "partitions(\"linear:3\")".to_string())],
&[], &workload_root,
&HashMap::new(),
Vec::new(),
None,
false,
"comp_install",
None,
)
.expect("comp scope install");
assert_eq!(
comp_kernel.program().input_port_type("p"),
Some(PortType::Ext),
"comp scope must declare `p` as Ext",
);
let _arc = Arc::new(comp_kernel);
let comp_kernel = _arc;
let phase_bindings = BindingsDef::PolydatSource("n := mod_in(cycle, p)\n".to_string());
let phase_kernel = build_phase_scope_kernel(
&phase_bindings,
&[], &comp_kernel,
&HashMap::new(),
Vec::new(),
None,
false,
"phase_install",
)
.expect("phase kernel build");
assert_eq!(
phase_kernel.program().input_port_type("p"),
Some(PortType::Ext),
"phase kernel must declare `p` as Ext via the cascade",
);
}
#[test]
fn end_to_end_install_through_runner_pipeline_yields_ext_p() {
use nmbrs_runtime::scope_tree::{ScopeKind, ScopeTree};
use nmbrs_workload::parse::parse_workload;
use polydat::ast::PortType;
use std::sync::Arc;
let yaml = r#"
scenarios:
sweep:
- for: "p in partitions(\"linear:3\")"
phases:
- walk
phases:
walk:
cycles: 2
concurrency: 1
bindings: |
n := mod_in(cycle, p)
ops:
emit:
adapter: stdout
stmt: "n={n}"
"#;
let workload = parse_workload(yaml, &HashMap::new()).expect("parse_workload");
let scenario_nodes = workload
.scenarios
.get("sweep")
.expect("sweep scenario")
.clone();
let mut scope_tree = ScopeTree::build("sweep", &scenario_nodes);
scope_tree.extend_with_op_templates(&workload.phases);
let workload_root = Arc::new(
nmbrs_runtime::scope_kernel::ScopeKernel::compile("\n").expect("workload root compile"),
);
scope_tree.install_kernel(scope_tree.root, workload_root.clone());
for (idx, node) in scope_tree.iter_dfs() {
match &node.kind {
ScopeKind::Comprehension { comprehension } => {
let bindings = comprehension.coordinate_specs();
let mut cursor = node.parent;
let parent_kernel = loop {
let Some(p) = cursor else {
panic!("no installed ancestor for comprehension");
};
if let Some(k) = scope_tree.nodes[p].cached_kernel.get() {
break k.clone();
}
cursor = scope_tree.nodes[p].parent;
};
let comp_kernel = nmbrs_runtime::scope_synth::build_for_each_scope_kernel(
&bindings,
&[],
&parent_kernel,
&HashMap::new(),
Vec::new(),
None,
false,
&format!("scope idx {idx}"),
None,
)
.expect("comp scope kernel");
scope_tree.install_kernel(idx, Arc::new(comp_kernel));
}
ScopeKind::Phase { name } => {
if name != "walk" {
continue;
}
let phase = workload
.phases
.get(name.as_str())
.expect("phase walk in workload");
let mut cursor = node.parent;
let parent_kernel = loop {
let Some(p) = cursor else {
panic!("no installed ancestor for phase");
};
if let Some(k) = scope_tree.nodes[p].cached_kernel.get() {
break k.clone();
}
cursor = scope_tree.nodes[p].parent;
};
let phase_kernel = nmbrs_runtime::scope::build_phase_scope_kernel(
&phase.bindings,
&[],
&parent_kernel,
&HashMap::new(),
Vec::new(),
None,
false,
&format!("scope idx {idx} (phase '{name}')"),
)
.expect("phase kernel build");
assert_eq!(
phase_kernel.program().input_port_type("p"),
Some(PortType::Ext),
"phase kernel via runner pipeline must declare `p` as Ext",
);
return;
}
_ => {}
}
}
panic!("phase `walk` not reached — install loop didn't find it");
}