-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Resolve scopes before flattening Network #4235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c95250e
7b079f9
f2f4fcc
e56d37b
fae8c50
12ba144
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -655,6 +655,73 @@ impl NodeNetwork { | |
| } | ||
| } | ||
|
|
||
| // Functions for resolving scope inputs | ||
| impl NodeNetwork { | ||
| pub fn resolve_scope_inputs(&mut self) { | ||
| let mut leftover = Vec::new(); | ||
| self.resolve_scope_inputs_impl(None, &mut leftover); | ||
| assert!(leftover.is_empty(), "Unresolved scope keys at top level: {leftover:?}"); | ||
| } | ||
|
Comment on lines
+660
to
+664
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pub fn resolve_scope_inputs(&mut self) {
self.resolve_scope_inputs_with(None, &mut Vec::new());
} |
||
|
|
||
| fn resolve_scope_inputs_impl(&mut self, parent: Option<&ScopeChain<'_>>, network_inputs: &mut Vec<NodeInput>) { | ||
| let scope_chain = ScopeChain { | ||
| scopes: &self.scope_injections, | ||
| parent, | ||
| }; | ||
|
|
||
| for node in self.nodes.values_mut() { | ||
| let DocumentNodeImplementation::Network(network) = &mut node.implementation else { continue }; | ||
| network.resolve_scope_inputs_impl(Some(&scope_chain), &mut node.inputs); | ||
| } | ||
|
|
||
| let mut key_to_idx: FxHashMap<Cow<'static, str>, usize> = FxHashMap::default(); | ||
| for node in self.nodes.values_mut() { | ||
| for input in node.inputs.iter_mut() { | ||
| let NodeInput::Scope(key) = input else { continue }; | ||
| *input = match scope_chain.lookup(key) { | ||
| ScopeChainLookup::Current(node_id, _ty) => NodeInput::node(*node_id, 0), | ||
| ScopeChainLookup::Parent(_node_id, ty) => { | ||
| let import_index = *key_to_idx.entry(key.clone()).or_insert_with(|| { | ||
| let index = network_inputs.len(); | ||
| network_inputs.push(NodeInput::Scope(key.clone())); | ||
| index | ||
| }); | ||
| NodeInput::Import { | ||
| import_type: ty.clone(), | ||
| import_index, | ||
| } | ||
| } | ||
| ScopeChainLookup::None => panic!("Scope key `{key}` not found in any ancestor scope_injections"), | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct ScopeChain<'a> { | ||
| scopes: &'a FxHashMap<String, (NodeId, Type)>, | ||
| parent: Option<&'a ScopeChain<'a>>, | ||
| } | ||
| enum ScopeChainLookup<'a> { | ||
| Current(&'a NodeId, &'a Type), | ||
| Parent(&'a NodeId, &'a Type), | ||
| None, | ||
| } | ||
| impl ScopeChain<'_> { | ||
| fn lookup(&'_ self, key: &str) -> ScopeChainLookup<'_> { | ||
| self.scopes | ||
| .get(key) | ||
| .map(|(id, ty)| ScopeChainLookup::Current(id, ty)) | ||
| .or_else(|| { | ||
| self.parent.and_then(|parent| match parent.lookup(key) { | ||
| ScopeChainLookup::Current(id, ty) | ScopeChainLookup::Parent(id, ty) => Some(ScopeChainLookup::Parent(id, ty)), | ||
| ScopeChainLookup::None => None, | ||
| }) | ||
| }) | ||
| .unwrap_or(ScopeChainLookup::None) | ||
| } | ||
| } | ||
|
|
||
| /// Functions for compiling the network | ||
| impl NodeNetwork { | ||
| /// Replace all references in the graph of a node ID with a new node ID defined by the function `f`. | ||
|
|
@@ -784,18 +851,6 @@ impl NodeNetwork { | |
| are_inputs_used | ||
| } | ||
|
|
||
| pub fn resolve_scope_inputs(&mut self) { | ||
| for node in self.nodes.values_mut() { | ||
| for input in node.inputs.iter_mut() { | ||
| if let NodeInput::Scope(key) = input { | ||
| let (import_id, _ty) = self.scope_injections.get(key.as_ref()).expect("Tried to import a non existent key from scope"); | ||
| // TODO use correct output index | ||
| *input = NodeInput::node(*import_id, 0); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Remove all nodes that contain [`DocumentNodeImplementation::Network`] by moving the nested nodes into the parent network. | ||
| pub fn flatten(&mut self, node_id: NodeId) { | ||
| self.flatten_with_fns(node_id, merge_ids, NodeId::new) | ||
|
|
@@ -886,11 +941,7 @@ impl NodeNetwork { | |
| } | ||
| NodeInput::Value { .. } => unreachable!("Value inputs should have been replaced with value nodes"), | ||
| NodeInput::Inline(_) => (), | ||
| NodeInput::Scope(ref key) => { | ||
| let (import_id, _ty) = self.scope_injections.get(key.as_ref()).expect("Tried to import a non existent key from scope"); | ||
| // TODO use correct output index | ||
| nested_node.inputs[nested_input_index] = NodeInput::node(*import_id, 0); | ||
| } | ||
| NodeInput::Scope(_) => unreachable!("Scope inputs should have been resolved by resolve_scope_inputs_recursive before flattening"), | ||
| NodeInput::Reflection(_) => unreachable!("Reflection inputs should have been replaced with value nodes"), | ||
| } | ||
| } | ||
|
|
@@ -906,21 +957,8 @@ impl NodeNetwork { | |
| } | ||
| } | ||
|
|
||
| /// Connect all nodes that were previously connected to this node to the nodes of the inner network | ||
| fn replace_node_with_its_exports(&mut self, id: NodeId, original_location: &OriginalLocation, exports: &[NodeInput]) { | ||
| // Connect scope injections to the inner network export | ||
| self.scope_injections.values_mut().for_each(|(node_id, _ty)| { | ||
| if node_id == &id { | ||
| let Some(export) = exports.first() else { | ||
| log::error!("Inner network should have at least one export"); | ||
| return; | ||
| }; | ||
| if let NodeInput::Node { node_id: export_id, output_index: _ } = export { | ||
| *node_id = *export_id; | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| // Connect all nodes that were previously connected to this node to the nodes of the inner network | ||
| for (i, export) in exports.iter().enumerate() { | ||
| if let NodeInput::Node { node_id, output_index, .. } = &export { | ||
| for deps in &original_location.dependants { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -242,10 +242,10 @@ fn compile_graph(document_string: String, editor_api: Arc<PlatformEditorApi>) -> | |
| let mut network = load_network(&document_string); | ||
| fix_nodes(&mut network); | ||
|
|
||
| let preprocessor = preprocessor::Preprocessor::new(); | ||
| preprocessor.expand_network(&mut network, &ResourceRegistry::default()).expect("Failed to expand network"); // TODO: actually load the resources from the document | ||
| let mut wrapped_network = wrap_network_in_scope(network, editor_api); | ||
|
|
||
| let wrapped_network = wrap_network_in_scope(network.clone(), editor_api); | ||
| let preprocessor = preprocessor::Preprocessor::new(); | ||
| preprocessor.preprocess(&mut wrapped_network, &ResourceRegistry::default()).expect("Failed to expand network"); // TODO: actually load the resources from the document | ||
|
|
||
| let compiler = Compiler {}; | ||
| compiler.compile_single(wrapped_network).map_err(|x| x.into()) | ||
|
Comment on lines
247
to
251
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The variable let mut wrapped_network = wrap_network_in_scope(network, editor_api);
let preprocessor = preprocessor::Preprocessor::new();
preprocessor.expand_network(&mut wrapped_network, &ResourceRegistry::default()).expect("Failed to expand network"); // TODO: actually load the resources from the document
let compiler = Compiler {};
compiler.compile_single(wrapped_network).map_err(|x| x.into()) |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: The
leftovervector and the subsequent assertion are dead code. At the top level, if a scope key is not found inself.scope_injections,chain.get()will also fail (sinceparentisNone), causing theunwrap_or_elseto panic before anything is pushed toleftover. The vector is guaranteed to always be empty.Prompt for AI agents