1use crate::operation::builtin::LibBuiltinOperation;
62use crate::operation::marker::Marker;
63use crate::operation::query::{BuiltinQuery, GraphShapeQuery, ShapeNodeIdentifier};
64use crate::operation::signature::parameter::{
65 AbstractOperationOutput, AbstractOutputNodeMarker, GraphWithSubstitution, OperationParameter,
66 ParameterSubstitution,
67};
68use crate::operation::signature::parameterbuilder::OperationParameterBuilder;
69use crate::operation::signature::{AbstractSignatureNodeId, OperationSignature};
70use crate::operation::user_defined::{
71 AbstractNodeId, AbstractOperationArgument, AbstractOperationResultMarker,
72 AbstractUserDefinedOperationOutput, NamedMarker, OpLikeInstruction, QueryInstructions,
73 UserDefinedOperation,
74};
75use crate::operation::{
76 BuiltinOperation, Operation, OperationError, OperationResult, get_substitution,
77};
78use crate::prelude::*;
79use crate::semantics::{AbstractGraph, AbstractMatcher};
80use crate::util::bimap::BiMap;
81use crate::util::log;
82use crate::{NodeKey, Semantics, SubstMarker};
83use error_stack::{FutureExt, Result, ResultExt, bail, report};
84use petgraph::dot;
85use petgraph::dot::Dot;
86use std::cell::RefCell;
87use std::collections::{HashMap, HashSet};
88use std::fmt::Debug;
89use std::iter::Peekable;
90use std::marker::PhantomData;
91use std::mem;
92use std::slice::Iter;
93use thiserror::Error;
94
95mod programming_by_demonstration;
96pub mod stack_based_builder;
97enum AbstractOperation<'a, S: Semantics> {
118 Op(Operation<'a, S>),
119 Partial(&'a OperationSignature<S>),
120}
121
122impl<'a, S: Semantics> AbstractOperation<'a, S> {
123 fn parameter(&self) -> OperationParameter<S> {
124 match self {
125 AbstractOperation::Op(op) => op.parameter(),
126 AbstractOperation::Partial(sig) => sig.parameter.clone(),
127 }
128 }
129
130 fn apply_abstract(
131 &self,
132 op_ctx: &OperationContext<S>,
133 g: &mut GraphWithSubstitution<AbstractGraph<S>>,
134 ) -> OperationResult<AbstractOperationOutput<S>> {
135 match self {
136 AbstractOperation::Op(op) => op.apply_abstract(op_ctx, g),
137 AbstractOperation::Partial(sig) => Ok(sig.output.apply_abstract(g)),
138 }
139 }
140
141 fn from_operation(op: Operation<'a, S>) -> AbstractOperation<'a, S> {
144 AbstractOperation::Op(op)
145 }
146}
147
148pub enum BuilderOpLike<S: Semantics> {
149 Builtin(S::BuiltinOperation),
150 LibBuiltin(LibBuiltinOperation<S>),
151 FromOperationId(OperationId),
152 Recurse,
153}
154
155impl<S: Semantics> BuilderOpLike<S> {
156 fn as_abstract_operation<'a>(
157 &'a self,
158 op_ctx: &'a OperationContext<S>,
159 partial_self_signature: &'a OperationSignature<S>,
160 ) -> Result<AbstractOperation<'a, S>, OperationBuilderError> {
161 let op = match self {
162 BuilderOpLike::Builtin(op) => AbstractOperation::Op(Operation::Builtin(op)),
163 BuilderOpLike::LibBuiltin(op) => AbstractOperation::Op(Operation::LibBuiltin(op)),
164 BuilderOpLike::FromOperationId(id) => {
165 let op = op_ctx
166 .get(*id)
167 .ok_or_else(|| OperationBuilderError::NotFoundOperationId(*id))?;
168 AbstractOperation::Op(op)
169 }
170 BuilderOpLike::Recurse => AbstractOperation::Partial(partial_self_signature),
171 };
172 Ok(op)
173 }
174
175 fn to_op_like_instruction(self, self_op_id: OperationId) -> OpLikeInstruction<S> {
176 match self {
177 BuilderOpLike::Builtin(op) => OpLikeInstruction::Builtin(op),
178 BuilderOpLike::LibBuiltin(op) => OpLikeInstruction::LibBuiltin(op),
179 BuilderOpLike::FromOperationId(id) => OpLikeInstruction::Operation(id),
180 BuilderOpLike::Recurse => OpLikeInstruction::Operation(self_op_id),
181 }
182 }
183}
184
185impl<S: Semantics<BuiltinOperation: Clone, BuiltinQuery: Clone>> Clone for BuilderOpLike<S> {
186 fn clone(&self) -> Self {
187 match self {
188 BuilderOpLike::Builtin(op) => BuilderOpLike::Builtin(op.clone()),
189 BuilderOpLike::LibBuiltin(op) => BuilderOpLike::LibBuiltin(op.clone()),
190 BuilderOpLike::FromOperationId(id) => BuilderOpLike::FromOperationId(*id),
191 BuilderOpLike::Recurse => BuilderOpLike::Recurse,
192 }
193 }
194}
195
196#[derive(derive_more::Debug)]
198pub enum BuilderInstruction<S: Semantics> {
199 #[debug("ExpectParameterNode({_0:?}, ???)")]
200 ExpectParameterNode(SubstMarker, S::NodeAbstract),
201 #[debug("ExpectContextNode({_0:?}, ???)")]
202 ExpectContextNode(SubstMarker, S::NodeAbstract),
203 #[debug("ExpectParameterEdge({_0:?}, {_1:?}, ???)")]
204 ExpectParameterEdge(SubstMarker, SubstMarker, S::EdgeAbstract),
205 #[debug("StartQuery(???, args: {_1:?})")]
206 StartQuery(S::BuiltinQuery, Vec<AbstractNodeId>),
207 #[debug("EnterTrueBranch")]
208 EnterTrueBranch,
209 #[debug("EnterFalseBranch")]
210 EnterFalseBranch,
211 #[debug("StartShapeQuery({_0:?})")]
215 StartShapeQuery(AbstractOperationResultMarker),
216 #[debug("EndQuery")]
217 EndQuery,
218 #[debug("ExpectShapeNode({_0:?}, ???)")]
219 ExpectShapeNode(AbstractOutputNodeMarker, S::NodeAbstract),
221 #[debug("ExpectShapeNodeChange({_0:?}, ???)")]
222 ExpectShapeNodeChange(AbstractNodeId, S::NodeAbstract),
223 #[debug("ExpectShapeEdge({_0:?}, {_1:?}, ???)")]
224 ExpectShapeEdge(AbstractNodeId, AbstractNodeId, S::EdgeAbstract),
225 #[debug("SkipMarker({_0:?})")]
226 SkipMarker(Marker),
227 #[debug("SkipAllMarkers")]
228 SkipAllMarkers,
229 #[debug("AddNamedOperation({_0:?}, ???, args: {_2:?})")]
230 AddNamedOperation(
231 AbstractOperationResultMarker,
232 BuilderOpLike<S>,
233 Vec<AbstractNodeId>,
234 ),
235 #[debug("AddBangOperation({_0:?}, ???, args: {_2:?})")]
238 AddBangOperation(NamedMarker, BuilderOpLike<S>, Vec<AbstractNodeId>),
239 #[debug("AddOperation(???, args: {_1:?})")]
240 AddOperation(BuilderOpLike<S>, Vec<AbstractNodeId>),
241 #[debug("ReturnNode({_0:?}, {_1:?}, ???)")]
242 ReturnNode(AbstractNodeId, AbstractOutputNodeMarker, S::NodeAbstract),
243 #[debug("ReturnEdge({_0:?}, {_1:?}, ???)")]
244 ReturnEdge(AbstractNodeId, AbstractNodeId, S::EdgeAbstract),
245 #[debug("RenameNode({_0:?}, {_1:?})")]
246 RenameNode(AbstractNodeId, NamedMarker),
249 Finalize,
250 #[debug("SelfReturnNode({_0:?}, ???)")]
252 SelfReturnNode(AbstractOutputNodeMarker, S::NodeAbstract),
253 #[debug("Diverge({_0})")]
256 Diverge(String),
257}
258
259impl<S: Semantics> BuilderInstruction<S> {
260 fn can_break_body(&self) -> bool {
263 use BuilderInstruction::*;
264 match self {
265 EnterTrueBranch | EnterFalseBranch | EndQuery | ReturnNode(..) | ReturnEdge(..)
266 | Finalize => true,
267 _ => false,
268 }
269 }
270}
271
272impl<S: Semantics<BuiltinOperation: Clone, BuiltinQuery: Clone>> Clone for BuilderInstruction<S> {
273 fn clone(&self) -> Self {
274 use BuilderInstruction::*;
275 match self {
276 ExpectParameterNode(marker, node) => ExpectParameterNode(marker.clone(), node.clone()),
277 ExpectContextNode(marker, node) => ExpectContextNode(marker.clone(), node.clone()),
278 ExpectParameterEdge(source_marker, target_marker, edge) => {
279 ExpectParameterEdge(source_marker.clone(), target_marker.clone(), edge.clone())
280 }
281 StartQuery(query, args) => StartQuery(query.clone(), args.clone()),
282 EnterTrueBranch => EnterTrueBranch,
283 EnterFalseBranch => EnterFalseBranch,
284 StartShapeQuery(op_marker) => StartShapeQuery(op_marker.clone()),
285 EndQuery => EndQuery,
286 ExpectShapeNode(marker, node) => ExpectShapeNode(marker.clone(), node.clone()),
287 ExpectShapeNodeChange(aid, node) => ExpectShapeNodeChange(aid.clone(), node.clone()),
288 ExpectShapeEdge(source, target, edge) => {
289 ExpectShapeEdge(source.clone(), target.clone(), edge.clone())
290 }
291 SkipMarker(marker) => SkipMarker(marker.clone()),
292 SkipAllMarkers => SkipAllMarkers,
293 AddNamedOperation(name, op, args) => {
294 AddNamedOperation(name.clone(), op.clone(), args.clone())
295 }
296 AddBangOperation(name, op, args) => {
297 AddBangOperation(name.clone(), op.clone(), args.clone())
298 }
299 AddOperation(op, args) => AddOperation(op.clone(), args.clone()),
300 ReturnNode(aid, output_marker, node) => {
301 ReturnNode(aid.clone(), output_marker.clone(), node.clone())
302 }
303 ReturnEdge(src, dst, edge) => ReturnEdge(src.clone(), dst.clone(), edge.clone()),
304 RenameNode(old_aid, new_name) => RenameNode(old_aid.clone(), new_name.clone()),
305 Finalize => Finalize,
306 SelfReturnNode(marker, node) => SelfReturnNode(marker.clone(), node.clone()),
307 Diverge(msg) => Diverge(msg.clone()),
308 }
309 }
310}
311
312#[derive(Error, Debug, Clone)]
313pub enum OperationBuilderError {
314 #[error("Expected a new unique subst marker, found repeat: {0:?}")]
315 ReusedSubstMarker(SubstMarker),
316 #[error("Expected an existing subst marker, but {0:?} was not found")]
317 NotFoundSubstMarker(SubstMarker),
318 #[error("Expected a new unique subst marker, found repeat: {0:?}")]
319 ReusedShapeIdent(ShapeNodeIdentifier),
320 #[error("Cannot call this while in a query context")]
321 InvalidInQuery,
322 #[error("Expected an operation or query")]
323 ExpectedOperationOrQuery,
324 #[error("Already visited the {0} branch of the active query")]
325 AlreadyVisitedBranch(bool),
326 #[error("Could not find abstract node id: {0:?}")]
327 NotFoundAid(AbstractNodeId),
328 #[error("AID {0:?} already exists")]
329 AlreadyExistsAid(AbstractNodeId),
330 #[error("Could not find operation ID: {0}")]
331 NotFoundOperationId(OperationId),
332 #[error("Could not apply operation due to mismatched arguments: {0}")]
333 SubstitutionError(#[from] crate::operation::SubstitutionError),
334 #[error("Could not apply operation due to mismatched arguments")]
335 SubstitutionErrorNew,
336 #[error("Could not abstractly apply operation {0} due to: {1}")]
337 AbstractApplyOperationErrorWithId(OperationId, OperationError),
338 #[error("Could not abstractly apply operation due to: {0}")]
339 AbstractApplyOperationError(OperationError),
340 #[error("Could not abstractly apply operation")]
341 AbstractApplyOperationError2,
342 #[error("Superfluous instruction {0}")]
343 SuperfluousInstruction(String),
344 #[error("Already selected to return node {0:?}")]
345 AlreadySelectedReturnNode(AbstractNodeId),
346 #[error("Already selected to return edge {0:?}->{1:?}")]
347 AlreadySelectedReturnEdge(AbstractNodeId, AbstractNodeId),
348 #[error("Could not find AID {0:?} for return node")]
349 NotFoundReturnNode(AbstractNodeId),
350 #[error("Invalid return node type for AID {0:?}, must be more generic")]
351 InvalidReturnNodeType(AbstractNodeId),
352 #[error("Returned {0:?} node may have been created by a shape query, which is not allowed")]
355 ReturnNodeMayOriginateFromShapeQuery(AbstractNodeId),
356 #[error("Cannot return a parameter node: {0:?}")]
357 CannotReturnParameter(AbstractNodeId),
358 #[error("Could not find AID {0:?} for return edge source")]
359 NotFoundReturnEdgeSource(AbstractNodeId),
360 #[error("Could not find AID {0:?} for return edge target")]
361 NotFoundReturnEdgeTarget(AbstractNodeId),
362 #[error("Could not statically determine edge {0:?}->{1:?} to be available")]
363 NotFoundReturnEdge(AbstractNodeId, AbstractNodeId),
364 #[error("Invalid return edge type for AID {0:?}->{1:?}, must be more generic")]
365 InvalidReturnEdgeType(AbstractNodeId, AbstractNodeId),
366 #[error(
367 "Return edge {0:?}->{1:?} may have been created by a shape query, which is not allowed"
368 )]
369 ReturnEdgeMayOriginateFromShapeQuery(AbstractNodeId, AbstractNodeId),
370 #[error("internal error: {0}")]
371 InternalError(&'static str),
372 #[error("Explicitly selected input AID not found")]
373 SelectedInputsNotFoundAid,
374 #[error("Shape edge target node not found")]
375 ShapeEdgeTargetNotFound,
376 #[error("Shape edge source node not found")]
377 ShapeEdgeSourceNotFound,
378 #[error(
379 "Cannot rename parameter node {0:?}, only new nodes from operation calls can be renamed"
380 )]
381 CannotRenameParameterNode(AbstractNodeId),
382 #[error("Invalid parameter")]
383 InvalidParameter,
384 #[error("New builder error")]
386 NewBuilderError,
387}
388
389pub type OperationBuilder<'a, S> = stack_based_builder::OperationBuilder2<'a, S>;
392
393pub struct OperationBuilderInefficient<'a, S: Semantics> {
394 op_ctx: &'a OperationContext<S>,
395 self_op_id: OperationId,
396 instructions: Vec<BuilderInstruction<S>>,
397 previous_user_defined_operation: RefCell<UserDefinedOperation<S>>,
399}
400
401impl<'a, S: Semantics<BuiltinQuery: Clone, BuiltinOperation: Clone>>
402 OperationBuilderInefficient<'a, S>
403{
404 pub fn new(op_ctx: &'a OperationContext<S>, self_op_id: OperationId) -> Self {
405 Self {
406 self_op_id,
407 instructions: Vec::new(),
408 op_ctx,
409 previous_user_defined_operation: RefCell::new(UserDefinedOperation::new_noop()),
410 }
411 }
412
413 pub fn undo_last_instruction(&mut self) {
414 if !self.instructions.is_empty() {
415 self.instructions.pop();
416 }
417 self.check_instructions()
418 .expect("internal error: a prefix slice of instructions should always be valid");
419 }
420
421 pub fn rename_node(
422 &mut self,
423 old_aid: AbstractNodeId,
424 new_name: impl Into<NamedMarker>,
425 ) -> Result<(), OperationBuilderError> {
426 let new_name = new_name.into();
427 self.instructions
428 .push(BuilderInstruction::RenameNode(old_aid, new_name));
429 self.check_instructions_or_rollback()
430 }
431
432 pub fn expect_parameter_node(
433 &mut self,
434 marker: impl Into<SubstMarker>,
435 node: S::NodeAbstract,
436 ) -> Result<(), OperationBuilderError> {
437 let marker = marker.into();
438 self.instructions
439 .push(BuilderInstruction::ExpectParameterNode(marker, node));
440 self.check_instructions_or_rollback()
441 }
442
443 pub fn expect_context_node(
444 &mut self,
445 marker: impl Into<SubstMarker>,
446 node: S::NodeAbstract,
447 ) -> Result<(), OperationBuilderError> {
448 let marker = marker.into();
449 self.instructions
450 .push(BuilderInstruction::ExpectContextNode(marker, node));
451 self.check_instructions_or_rollback()
453 }
454
455 pub fn expect_parameter_edge(
456 &mut self,
457 source_marker: impl Into<SubstMarker>,
458 target_marker: impl Into<SubstMarker>,
459 edge: S::EdgeAbstract,
460 ) -> Result<(), OperationBuilderError> {
461 let source_marker = source_marker.into();
462 let target_marker = target_marker.into();
463 self.instructions
464 .push(BuilderInstruction::ExpectParameterEdge(
465 source_marker,
466 target_marker,
467 edge,
468 ));
469 self.check_instructions_or_rollback()
471 }
472
473 pub fn start_query(
474 &mut self,
475 query: S::BuiltinQuery,
476 args: Vec<AbstractNodeId>,
477 ) -> Result<(), OperationBuilderError> {
478 self.instructions
480 .push(BuilderInstruction::StartQuery(query, args));
481 self.check_instructions_or_rollback()
482 }
483
484 pub fn enter_true_branch(&mut self) -> Result<(), OperationBuilderError> {
485 self.instructions.push(BuilderInstruction::EnterTrueBranch);
487 self.check_instructions_or_rollback()
488 }
489
490 pub fn enter_false_branch(&mut self) -> Result<(), OperationBuilderError> {
491 self.instructions.push(BuilderInstruction::EnterFalseBranch);
493 self.check_instructions_or_rollback()
494 }
495
496 pub fn start_shape_query(
501 &mut self,
502 op_marker: impl Into<AbstractOperationResultMarker>,
503 ) -> Result<(), OperationBuilderError> {
504 self.instructions
506 .push(BuilderInstruction::StartShapeQuery(op_marker.into()));
507 self.check_instructions_or_rollback()
508 }
509
510 pub fn end_query(&mut self) -> Result<(), OperationBuilderError> {
511 self.instructions.push(BuilderInstruction::EndQuery);
513 self.check_instructions_or_rollback()
514 }
515
516 pub fn expect_shape_node(
519 &mut self,
520 marker: AbstractOutputNodeMarker,
521 node: S::NodeAbstract,
522 ) -> Result<(), OperationBuilderError> {
523 self.instructions
525 .push(BuilderInstruction::ExpectShapeNode(marker, node));
526 self.check_instructions_or_rollback()
527 }
528
529 pub fn expect_shape_node_change(
530 &mut self,
531 aid: AbstractNodeId,
532 node: S::NodeAbstract,
533 ) -> Result<(), OperationBuilderError> {
534 self.instructions
535 .push(BuilderInstruction::ExpectShapeNodeChange(aid, node));
536 self.check_instructions_or_rollback()
537 }
538
539 pub fn expect_shape_edge(
540 &mut self,
541 source: AbstractNodeId,
542 target: AbstractNodeId,
543 edge: S::EdgeAbstract,
544 ) -> Result<(), OperationBuilderError> {
545 self.instructions
547 .push(BuilderInstruction::ExpectShapeEdge(source, target, edge));
548 self.check_instructions_or_rollback()
549 }
550
551 pub fn add_named_operation(
552 &mut self,
553 name: AbstractOperationResultMarker,
554 op: BuilderOpLike<S>,
555 args: Vec<AbstractNodeId>,
556 ) -> Result<(), OperationBuilderError> {
557 self.instructions
559 .push(BuilderInstruction::AddNamedOperation(name, op, args));
560 self.check_instructions_or_rollback()
561 }
562
563 pub fn add_bang_operation(
564 &mut self,
565 name: impl Into<NamedMarker>,
566 op: BuilderOpLike<S>,
567 args: Vec<AbstractNodeId>,
568 ) -> Result<(), OperationBuilderError> {
569 self.instructions
571 .push(BuilderInstruction::AddBangOperation(name.into(), op, args));
572 self.check_instructions_or_rollback()
573 }
574
575 pub fn add_operation(
576 &mut self,
577 op: BuilderOpLike<S>,
578 args: Vec<AbstractNodeId>,
579 ) -> Result<(), OperationBuilderError> {
580 self.instructions
582 .push(BuilderInstruction::AddOperation(op, args));
583 self.check_instructions_or_rollback()?;
584 Ok(())
585 }
586
587 pub fn return_node(
595 &mut self,
596 aid: AbstractNodeId,
597 output_marker: AbstractOutputNodeMarker,
598 node: S::NodeAbstract,
599 ) -> Result<(), OperationBuilderError> {
600 if let AbstractNodeId::ParameterMarker(..) = &aid {
602 bail!(OperationBuilderError::CannotReturnParameter(aid));
603 }
604 self.instructions
605 .push(BuilderInstruction::ReturnNode(aid, output_marker, node));
606 self.check_instructions_or_rollback()
607 }
608
609 pub fn return_edge(
620 &mut self,
621 src: AbstractNodeId,
622 dst: AbstractNodeId,
623 edge: S::EdgeAbstract,
624 ) -> Result<(), OperationBuilderError> {
625 self.instructions
627 .push(BuilderInstruction::ReturnEdge(src, dst, edge));
628 self.check_instructions_or_rollback()
629 }
630
631 pub fn build(&self) -> Result<UserDefinedOperation<S>, OperationBuilderError> {
634 let builder_result = IntermediateStateBuilder::run(&self.instructions, self.op_ctx)?;
638
639 let param = builder_result.operation_parameter;
640 let instructions = builder_result.instructions;
641 let prev_user_ref = self.previous_user_defined_operation.borrow();
642 let mut interpreter = IntermediateInterpreter::new_for_self_op_id(
643 self.self_op_id,
644 param,
645 self.op_ctx,
646 &prev_user_ref,
647 );
648
649 let user_def_op = interpreter.create_user_defined_operation(
650 instructions,
651 builder_result.return_nodes,
652 builder_result.return_edges,
653 )?;
654
655 user_def_op
660 .signature
661 .parameter
662 .check_validity()
663 .change_context(OperationBuilderError::InvalidParameter)?;
664
665 Ok(user_def_op)
666 }
667
668 fn check_instructions_or_rollback(&mut self) -> Result<(), OperationBuilderError> {
669 match self.check_instructions() {
670 Ok(_) => Ok(()),
671 Err(e) => {
672 if !self.instructions.is_empty() {
675 self.instructions.pop();
676 }
677 Err(e)
678 }
679 }
680 }
681
682 fn check_instructions(&self) -> Result<(), OperationBuilderError> {
683 let builder_result = IntermediateStateBuilder::run(&self.instructions, self.op_ctx)?;
684
685 let partial_user_def_op = {
686 let prev_user_ref = self.previous_user_defined_operation.borrow();
687 let mut interpreter = IntermediateInterpreter::new_for_self_op_id(
688 0, builder_result.operation_parameter,
690 self.op_ctx,
691 &prev_user_ref,
692 );
693 interpreter.create_user_defined_operation(
694 builder_result.instructions,
695 builder_result.return_nodes,
696 builder_result.return_edges,
697 )?
698 };
699 *self.previous_user_defined_operation.borrow_mut() = partial_user_def_op;
700
701 Ok(())
703 }
704}
705
706impl<
707 'a,
708 S: Semantics<
709 NodeAbstract: Debug,
710 EdgeAbstract: Debug,
711 BuiltinOperation: Clone,
712 BuiltinQuery: Clone,
713 >,
714> OperationBuilderInefficient<'a, S>
715{
716 fn get_intermediate_state(
717 &self,
718 ) -> Result<(IntermediateState<S>, Vec<IntermediateStatePath>), OperationBuilderError> {
719 let builder_result = IntermediateStateBuilder::run(&self.instructions, self.op_ctx)?;
720 let prev_user_ref = self.previous_user_defined_operation.borrow();
721 let mut interpreter = IntermediateInterpreter::new_for_self_op_id(
722 0, builder_result.operation_parameter,
724 self.op_ctx,
725 &prev_user_ref,
726 );
727
728 let (_, interp_instructions) =
729 interpreter.interpret_instructions(builder_result.instructions)?;
730 let path = builder_result.state_path;
731 let mut path_iter = path.iter().peekable().cloned();
732
733 let mut intermediate_state = get_state_for_path(
734 &interpreter.initial_state,
735 &interp_instructions,
736 &mut path_iter,
737 )
738 .expect("internal error: Failed to get intermediate state for path");
739
740 let query_path = get_query_path_for_path::<S>(&mut path.iter().peekable().cloned());
741 intermediate_state.query_path = query_path;
743
744 Ok((intermediate_state, path))
749 }
750
751 pub fn show_state(&self) -> Result<IntermediateState<S>, OperationBuilderError> {
755 Ok(self.get_intermediate_state()?.0)
768 }
769
770 pub fn format_state(&self) -> String {
771 let (state, path) = self.get_intermediate_state().unwrap();
773 let dot = state.graph.dot();
774 let mapping = state.node_keys_to_aid.into_inner().0;
775 let query_path = state.query_path;
776 format!("\nIntermediate State:\n{dot}\nmapping: {mapping:#?}\nTODO query path")
777 }
778}
779
780struct IntermediateStateBuilder<'a, S: Semantics> {
781 path: Vec<IntermediateStatePath>,
782 _phantom_data: PhantomData<&'a S>,
783}
784
785use super::user_defined::Instruction as UDInstruction;
786
787#[derive(derive_more::Debug)]
788enum IntermediateInstruction<S: Semantics> {
789 OpLike(IntermediateOpLike<S>),
790 GraphShapeQuery {
792 is_finished: bool,
794 marker: AbstractOperationResultMarker,
795 graph_instructions: Vec<GraphShapeQueryInstruction<S>>,
796 query_instructions: IntermediateQueryInstructions<S>,
797 },
798 #[debug("BuiltinQuery(???, {_1:#?}, {_2:#?})")]
799 BuiltinQuery(
800 S::BuiltinQuery,
801 Vec<AbstractNodeId>,
802 IntermediateQueryInstructions<S>,
803 ),
804 RenameNode {
806 aid: AbstractNodeId,
807 new_name: NamedMarker,
808 },
809}
810
811#[derive(derive_more::Debug)]
812enum IntermediateOpLike<S: Semantics> {
813 #[debug("Builtin(???, {_1:#?})")]
814 Builtin(S::BuiltinOperation, Vec<AbstractNodeId>),
815 LibBuiltin(LibBuiltinOperation<S>, Vec<AbstractNodeId>),
816 Operation(OperationId, Vec<AbstractNodeId>),
817 Recurse(Vec<AbstractNodeId>),
818}
819
820#[derive(derive_more::Debug)]
821struct IntermediateQueryInstructions<S: Semantics> {
822 #[debug("[{}]", true_branch.iter().map(|(opt, inst)| format!("({opt:#?}, {:#?})", inst)).collect::<Vec<_>>().join(", "))]
823 true_branch: Vec<(
824 Option<AbstractOperationResultMarker>,
825 IntermediateInstruction<S>,
826 )>,
827 #[debug("[{}]", false_branch.iter().map(|(opt, inst)| format!("({opt:#?}, {:#?})", inst)).collect::<Vec<_>>().join(", "))]
828 false_branch: Vec<(
829 Option<AbstractOperationResultMarker>,
830 IntermediateInstruction<S>,
831 )>,
832}
833
834#[derive(derive_more::Debug)]
835enum GraphShapeQueryInstruction<S: Semantics> {
836 #[debug("ExpectShapeNode({_0:#?})")]
837 ExpectShapeNode(AbstractOutputNodeMarker, S::NodeAbstract),
838 #[debug("ExpectShapeNodeChange({_0:#?})")]
839 ExpectShapeNodeChange(AbstractNodeId, S::NodeAbstract),
840 #[debug("ExpectShapeEdge({_0:#?}, {_1:#?})")]
841 ExpectShapeEdge(AbstractNodeId, AbstractNodeId, S::EdgeAbstract),
842}
843
844struct BuilderResult<S: Semantics> {
845 operation_parameter: OperationParameter<S>,
846 instructions: Vec<(
847 Option<AbstractOperationResultMarker>,
848 IntermediateInstruction<S>,
849 )>,
850 state_path: Vec<IntermediateStatePath>,
851 return_nodes: HashMap<AbstractNodeId, (AbstractOutputNodeMarker, S::NodeAbstract)>,
852 return_edges: HashMap<(AbstractNodeId, AbstractNodeId), S::EdgeAbstract>,
853}
854
855impl<'a, S: Semantics<BuiltinOperation: Clone, BuiltinQuery: Clone>>
857 IntermediateStateBuilder<'a, S>
858{
859 fn run(
860 builder_instructions: &'a [BuilderInstruction<S>],
861 op_ctx: &'a OperationContext<S>,
862 ) -> Result<BuilderResult<S>, OperationBuilderError> {
863 let mut iter = builder_instructions.iter().peekable();
989
990 let op_parameter = Self::build_operation_parameter(&mut iter)?;
991
992 if iter.peek().is_some() {
994 op_parameter
995 .check_validity()
996 .change_context(OperationBuilderError::InvalidParameter)?;
997 }
998
999 let mut builder = Self {
1000 _phantom_data: PhantomData,
1001 path: Vec::new(),
1002 };
1003
1004 let instructions = builder.build_many_instructions(&mut iter)?;
1005
1006 let mut return_nodes = HashMap::new();
1007 let mut return_edges = HashMap::new();
1008 if !builder
1010 .path
1011 .iter()
1012 .any(|i| matches!(i, IntermediateStatePath::StartQuery(..)))
1013 {
1014 (return_nodes, return_edges) = Self::collect_return_instructions(&mut iter)?;
1016 }
1018
1019 if let Some(next_instruction) = iter.peek() {
1021 bail!(OperationBuilderError::SuperfluousInstruction(format!(
1022 "{next_instruction:?}"
1023 )));
1024 }
1025
1026 Ok(BuilderResult {
1027 operation_parameter: op_parameter,
1028 instructions,
1029 state_path: builder.path,
1030 return_nodes,
1031 return_edges,
1032 })
1033 }
1034
1035 fn build_many_instructions(
1036 &mut self,
1037 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1038 ) -> Result<
1039 Vec<(
1040 Option<AbstractOperationResultMarker>,
1041 IntermediateInstruction<S>,
1042 )>,
1043 OperationBuilderError,
1044 > {
1045 let mut instructions = Vec::new();
1046
1047 while let Some(instr) = iter.peek() {
1048 if instr.can_break_body() {
1050 break;
1051 }
1052 instructions.push(self.build_instruction(iter)?);
1053 }
1054 Ok(instructions)
1055 }
1056
1057 fn build_instruction(
1058 &mut self,
1059 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1060 ) -> Result<
1061 (
1062 Option<AbstractOperationResultMarker>,
1063 IntermediateInstruction<S>,
1064 ),
1065 OperationBuilderError,
1066 > {
1067 let next_instruction = iter
1068 .peek()
1069 .expect("should only be called when there is an instruction");
1070 match next_instruction {
1071 BuilderInstruction::AddNamedOperation(_, oplike, args)
1072 | BuilderInstruction::AddOperation(oplike, args) => {
1073 let name =
1074 if let BuilderInstruction::AddNamedOperation(name, _, _) = next_instruction {
1075 Some(name.clone())
1076 } else {
1077 None
1078 };
1079 iter.next();
1080
1081 let oplike = match oplike {
1082 BuilderOpLike::Builtin(builtin_op) => {
1083 IntermediateOpLike::Builtin(builtin_op.clone(), args.clone())
1084 }
1085 BuilderOpLike::LibBuiltin(lib_builtin_op) => {
1086 IntermediateOpLike::LibBuiltin(lib_builtin_op.clone(), args.clone())
1087 }
1088 BuilderOpLike::FromOperationId(op_id) => {
1089 IntermediateOpLike::Operation(op_id.clone(), args.clone())
1090 }
1091 BuilderOpLike::Recurse => IntermediateOpLike::Recurse(args.clone()),
1092 };
1093 self.path.push(IntermediateStatePath::Advance);
1094 Ok((name, IntermediateInstruction::OpLike(oplike)))
1095 }
1096 BuilderInstruction::StartQuery(query, args) => {
1097 iter.next();
1098 self.path.push(IntermediateStatePath::StartQuery(None));
1100 let query_instructions = self.build_query_instruction(iter)?;
1101 Ok((
1102 None,
1103 IntermediateInstruction::BuiltinQuery(
1104 query.clone(),
1105 args.clone(),
1106 query_instructions,
1107 ),
1108 ))
1109 }
1110 BuilderInstruction::StartShapeQuery(op_marker) => {
1111 iter.next();
1112 self.path
1113 .push(IntermediateStatePath::StartQuery(Some(format!(
1114 "{op_marker:?}"
1115 ))));
1116 let (is_finished, gsq_instructions, branch_instructions) =
1118 self.build_shape_query(iter, op_marker.clone())?;
1119 Ok((
1121 Some(op_marker.clone()), IntermediateInstruction::GraphShapeQuery {
1123 is_finished,
1124 marker: op_marker.clone(),
1125 graph_instructions: gsq_instructions,
1126 query_instructions: branch_instructions,
1127 },
1128 ))
1129 }
1130 BuilderInstruction::RenameNode(old_aid, new_name) => {
1131 iter.next();
1132 self.path.push(IntermediateStatePath::Advance);
1133 Ok((
1134 None,
1135 IntermediateInstruction::RenameNode {
1136 aid: *old_aid,
1137 new_name: *new_name,
1138 },
1139 ))
1140 }
1141 _ => bail!(OperationBuilderError::ExpectedOperationOrQuery),
1142 }
1143 }
1144
1145 fn build_shape_query(
1146 &mut self,
1147 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1148 operation_marker: AbstractOperationResultMarker,
1149 ) -> Result<
1150 (
1151 bool,
1152 Vec<GraphShapeQueryInstruction<S>>,
1153 IntermediateQueryInstructions<S>,
1154 ),
1155 OperationBuilderError,
1156 > {
1157 let mut gsq_instructions = vec![];
1172
1173 let mut true_branch_instructions = None;
1174 let mut false_branch_instructions = None;
1175
1176 let mut did_query_finish = false;
1179
1180 while let Some(instruction) = iter.peek() {
1181 match instruction {
1182 BuilderInstruction::EnterTrueBranch => {
1183 iter.next();
1184 if true_branch_instructions.is_some() {
1185 bail!(OperationBuilderError::AlreadyVisitedBranch(true));
1186 }
1187 self.remove_until_branch(false);
1189 self.path.push(IntermediateStatePath::EnterTrue);
1190 true_branch_instructions = Some(self.build_many_instructions(iter)?);
1191 did_query_finish = true;
1192 }
1193 BuilderInstruction::EnterFalseBranch => {
1194 iter.next();
1195 if false_branch_instructions.is_some() {
1196 bail!(OperationBuilderError::AlreadyVisitedBranch(false));
1197 }
1198 self.remove_until_branch(true);
1200 self.path.push(IntermediateStatePath::EnterFalse);
1201 false_branch_instructions = Some(self.build_many_instructions(iter)?);
1202 did_query_finish = true;
1203 }
1204 BuilderInstruction::EndQuery => {
1205 iter.next();
1206 self.remove_until_query_start();
1208 self.path.push(IntermediateStatePath::SkipQuery);
1209 did_query_finish = true;
1210 break;
1211 }
1212 BuilderInstruction::ExpectShapeNode(marker, abstract_value) => {
1213 iter.next();
1215 gsq_instructions.push(GraphShapeQueryInstruction::ExpectShapeNode(
1224 marker.clone(),
1225 abstract_value.clone(),
1226 ));
1227 }
1228 BuilderInstruction::ExpectShapeNodeChange(aid, new_av) => {
1229 iter.next();
1230 gsq_instructions.push(GraphShapeQueryInstruction::ExpectShapeNodeChange(
1231 aid.clone(),
1232 new_av.clone(),
1233 ));
1234 }
1235 BuilderInstruction::ExpectShapeEdge(source, target, abstract_value) => {
1236 iter.next();
1237 gsq_instructions.push(GraphShapeQueryInstruction::ExpectShapeEdge(
1241 source.clone(),
1242 target.clone(),
1243 abstract_value.clone(),
1244 ));
1245 }
1246 _ => {
1247 bail!(OperationBuilderError::InvalidInQuery);
1248 }
1249 }
1250 }
1251
1252 Ok((
1253 did_query_finish,
1254 gsq_instructions,
1255 IntermediateQueryInstructions {
1256 true_branch: true_branch_instructions.unwrap_or_default(),
1257 false_branch: false_branch_instructions.unwrap_or_default(),
1258 },
1259 ))
1260 }
1261
1262 fn build_query_instruction(
1263 &mut self,
1264 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1265 ) -> Result<IntermediateQueryInstructions<S>, OperationBuilderError> {
1266 let mut true_branch_instructions = None;
1268 let mut false_branch_instructions = None;
1269 while let Some(instruction) = iter.peek() {
1270 match instruction {
1271 BuilderInstruction::EnterTrueBranch => {
1272 iter.next();
1273 if true_branch_instructions.is_some() {
1274 bail!(OperationBuilderError::AlreadyVisitedBranch(true));
1275 }
1276 self.remove_until_branch(false);
1278 self.path.push(IntermediateStatePath::EnterTrue);
1279 true_branch_instructions = Some(self.build_many_instructions(iter)?);
1280 }
1281 BuilderInstruction::EnterFalseBranch => {
1282 iter.next();
1283 if false_branch_instructions.is_some() {
1284 bail!(OperationBuilderError::AlreadyVisitedBranch(false));
1285 }
1286 self.remove_until_branch(true);
1288 self.path.push(IntermediateStatePath::EnterFalse);
1289 false_branch_instructions = Some(self.build_many_instructions(iter)?);
1290 }
1291 BuilderInstruction::EndQuery => {
1292 iter.next();
1293 self.remove_until_query_start();
1295 self.path.push(IntermediateStatePath::SkipQuery);
1296 break;
1297 }
1298 _ => {
1299 bail!(OperationBuilderError::InvalidInQuery);
1300 }
1301 }
1302 }
1303 let true_branch = true_branch_instructions.unwrap_or_default();
1304 let false_branch = false_branch_instructions.unwrap_or_default();
1305 Ok(IntermediateQueryInstructions {
1306 true_branch,
1307 false_branch,
1308 })
1309 }
1310
1311 fn build_operation_parameter(
1312 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1313 ) -> Result<OperationParameter<S>, OperationBuilderError> {
1314 let mut builder = OperationParameterBuilder::new();
1315
1316 while let Some(instruction) = iter.peek() {
1317 match instruction {
1318 BuilderInstruction::ExpectParameterNode(marker, node_abstract) => {
1319 iter.next();
1320 builder
1321 .expect_explicit_input_node(*marker, node_abstract.clone())
1322 .change_context(OperationBuilderError::InvalidParameter)?;
1323 }
1324 BuilderInstruction::ExpectContextNode(marker, node_abstract) => {
1325 iter.next();
1326 builder
1327 .expect_context_node(*marker, node_abstract.clone())
1328 .change_context(OperationBuilderError::InvalidParameter)?;
1329 }
1330 BuilderInstruction::ExpectParameterEdge(
1331 source_marker,
1332 target_marker,
1333 edge_abstract,
1334 ) => {
1335 iter.next();
1336 builder
1337 .expect_edge(*source_marker, *target_marker, edge_abstract.clone())
1338 .change_context(OperationBuilderError::InvalidParameter)?;
1339 }
1340 _ => {
1341 break;
1342 }
1343 }
1344 }
1345
1346 builder
1347 .build()
1348 .change_context(OperationBuilderError::InvalidParameter)
1349 }
1350
1351 fn collect_return_instructions(
1353 iter: &mut Peekable<Iter<BuilderInstruction<S>>>,
1354 ) -> Result<
1355 (
1356 HashMap<AbstractNodeId, (AbstractOutputNodeMarker, S::NodeAbstract)>,
1357 HashMap<(AbstractNodeId, AbstractNodeId), S::EdgeAbstract>,
1358 ),
1359 OperationBuilderError,
1360 > {
1361 let mut return_nodes = HashMap::new();
1362 let mut return_edges = HashMap::new();
1363 while let Some(instruction) = iter.peek() {
1364 match instruction {
1365 BuilderInstruction::ReturnNode(aid, output_marker, node) => {
1366 iter.next();
1367 if return_nodes.contains_key(aid) {
1368 bail!(OperationBuilderError::AlreadySelectedReturnNode(
1369 aid.clone(),
1370 ));
1371 }
1372 return_nodes.insert(aid.clone(), (output_marker.clone(), node.clone()));
1373 }
1374 BuilderInstruction::ReturnEdge(source, target, edge) => {
1375 iter.next();
1376 if return_edges.contains_key(&(source.clone(), target.clone())) {
1377 bail!(OperationBuilderError::AlreadySelectedReturnEdge(
1378 source.clone(),
1379 target.clone(),
1380 ));
1381 }
1382 return_edges.insert((source.clone(), target.clone()), edge.clone());
1383 }
1384
1385 _ => break,
1386 }
1387 }
1388 Ok((return_nodes, return_edges))
1389 }
1390
1391 fn remove_until_branch(&mut self, branch: bool) {
1392 let branch_to_find = if branch {
1394 IntermediateStatePath::EnterTrue
1395 } else {
1396 IntermediateStatePath::EnterFalse
1397 };
1398
1399 let mut found = false;
1400 for last in self.path.iter().rev() {
1401 if last == &branch_to_find {
1402 found = true;
1404 }
1405 if matches!(last, IntermediateStatePath::StartQuery(..)) {
1406 break;
1408 }
1409 }
1410 if !found {
1411 return;
1413 }
1414
1415 while let Some(last) = self.path.pop() {
1416 if (branch && last == IntermediateStatePath::EnterTrue)
1417 || (!branch && last == IntermediateStatePath::EnterFalse)
1418 {
1419 break;
1420 }
1421 }
1422 }
1423
1424 fn remove_until_query_start(&mut self) {
1425 while let Some(last) = self.path.pop() {
1426 if matches!(last, IntermediateStatePath::StartQuery(..)) {
1427 break;
1428 }
1429 }
1430 }
1431}
1432
1433#[derive(Debug, Clone, PartialEq, Eq)]
1434enum IntermediateStatePath {
1435 Advance,
1437 EnterTrue,
1438 EnterFalse,
1439 SkipQuery,
1441 StartQuery(Option<String>), }
1443
1444#[derive(Clone, Debug, Eq, PartialEq)]
1470pub enum QueryPath {
1471 Query(String),
1472 TrueBranch,
1473 FalseBranch,
1474}
1475
1476#[derive(Clone, Debug, Eq, PartialEq)]
1477struct IntermediateStateAbstractOutputResult {
1478 new_aids: Vec<AbstractNodeId>,
1479 removed_aids: Vec<AbstractNodeId>,
1480}
1481
1482pub struct IntermediateState<S: Semantics> {
1489 pub graph: AbstractGraph<S>,
1490 pub node_keys_to_aid: BiMap<NodeKey, AbstractNodeId>,
1491 pub node_may_originate_from_shape_query: HashSet<AbstractNodeId>,
1498 pub edge_may_originate_from_shape_query: HashSet<(AbstractNodeId, AbstractNodeId)>,
1499
1500 pub node_may_be_written_to: HashMap<AbstractNodeId, S::NodeAbstract>,
1502 pub edge_may_be_written_to: HashMap<(AbstractNodeId, AbstractNodeId), S::EdgeAbstract>,
1504
1505 pub query_path: Vec<QueryPath>,
1508
1509 pub op_marker_counter: u64,
1510
1511 pub has_diverged: bool,
1512}
1513
1514impl<S: Semantics> Clone for IntermediateState<S> {
1517 fn clone(&self) -> Self {
1518 IntermediateState {
1519 graph: self.graph.clone(),
1520 node_keys_to_aid: self.node_keys_to_aid.clone(),
1521 node_may_originate_from_shape_query: self.node_may_originate_from_shape_query.clone(),
1522 edge_may_originate_from_shape_query: self.edge_may_originate_from_shape_query.clone(),
1523 node_may_be_written_to: self.node_may_be_written_to.clone(),
1524 edge_may_be_written_to: self.edge_may_be_written_to.clone(),
1525 query_path: self.query_path.clone(),
1526 op_marker_counter: self.op_marker_counter,
1527 has_diverged: self.has_diverged,
1528 }
1529 }
1530}
1531
1532impl<S: Semantics> IntermediateState<S> {
1533 fn new() -> Self {
1534 IntermediateState {
1535 graph: AbstractGraph::<S>::new(),
1536 node_keys_to_aid: BiMap::new(),
1537 node_may_originate_from_shape_query: HashSet::new(),
1538 edge_may_originate_from_shape_query: HashSet::new(),
1539 node_may_be_written_to: HashMap::new(),
1540 edge_may_be_written_to: HashMap::new(),
1541 query_path: Vec::new(),
1542 op_marker_counter: 50000,
1543 has_diverged: false,
1544 }
1545 }
1546
1547 fn from_param(param: &OperationParameter<S>) -> Self {
1548 let initial_graph = param.parameter_graph.clone();
1549
1550 let mut initial_mapping = BiMap::new();
1551
1552 for (key, subst) in param.node_keys_to_subst.iter() {
1553 let aid = AbstractNodeId::ParameterMarker(*subst);
1554 initial_mapping.insert(*key, aid);
1555 }
1556
1557 IntermediateState {
1558 graph: initial_graph,
1559 node_keys_to_aid: initial_mapping,
1560 node_may_originate_from_shape_query: HashSet::new(),
1561 edge_may_originate_from_shape_query: HashSet::new(),
1562 node_may_be_written_to: HashMap::new(),
1563 edge_may_be_written_to: HashMap::new(),
1564 query_path: Vec::new(),
1565 op_marker_counter: 50000,
1566 has_diverged: false,
1567 }
1568 }
1569
1570 fn get_next_op_result_marker(&mut self) -> AbstractOperationResultMarker {
1571 let marker = AbstractOperationResultMarker::Implicit(self.op_marker_counter);
1572 self.op_marker_counter += 1;
1573 marker
1574 }
1575
1576 fn add_node(
1577 &mut self,
1578 aid: AbstractNodeId,
1579 node_abstract: S::NodeAbstract,
1580 from_shape_query: bool,
1581 ) {
1582 let node_key = self.graph.add_node(node_abstract);
1583 self.node_keys_to_aid.insert(node_key, aid);
1584 if from_shape_query {
1585 self.node_may_originate_from_shape_query.insert(aid);
1586 } else {
1587 }
1589 }
1590
1591 fn add_edge(
1592 &mut self,
1593 source: AbstractNodeId,
1594 target: AbstractNodeId,
1595 edge_abstract: S::EdgeAbstract,
1596 from_shape_query: bool,
1597 ) -> Result<(), OperationBuilderError> {
1598 let source_key = self
1599 .node_keys_to_aid
1600 .get_right(&source)
1601 .ok_or(OperationBuilderError::NotFoundAid(source))?;
1602 let target_key = self
1603 .node_keys_to_aid
1604 .get_right(&target)
1605 .ok_or(OperationBuilderError::NotFoundAid(target))?;
1606
1607 self.graph.add_edge(*source_key, *target_key, edge_abstract);
1608
1609 if from_shape_query {
1610 self.edge_may_originate_from_shape_query
1611 .insert((source, target));
1612 } else {
1613 }
1615 Ok(())
1616 }
1617
1618 fn set_node_av(
1619 &mut self,
1620 aid: AbstractNodeId,
1621 node_abstract: S::NodeAbstract,
1622 ) -> Result<(), OperationBuilderError> {
1623 let node_key = self
1624 .node_keys_to_aid
1625 .get_right(&aid)
1626 .ok_or(OperationBuilderError::NotFoundAid(aid))?;
1627 self.graph.set_node_attr(*node_key, node_abstract);
1628 Ok(())
1629 }
1630
1631 fn contains_aid(&self, aid: &AbstractNodeId) -> bool {
1632 self.node_keys_to_aid.contains_right(aid)
1633 }
1634
1635 fn contains_edge(&self, source: &AbstractNodeId, target: &AbstractNodeId) -> bool {
1636 let Some(source_key) = self.node_keys_to_aid.get_right(source) else {
1637 return false;
1638 };
1639 let Some(target_key) = self.node_keys_to_aid.get_right(target) else {
1640 return false;
1641 };
1642 self.graph
1643 .get_edge_attr((*source_key, *target_key))
1644 .is_some()
1645 }
1646
1647 pub fn node_av_of_aid(&self, aid: &AbstractNodeId) -> Option<&S::NodeAbstract> {
1648 let node_key = self.node_keys_to_aid.get_right(aid)?;
1649 self.graph.get_node_attr(*node_key)
1650 }
1651
1652 pub fn edge_av_of_aid(
1653 &self,
1654 source: &AbstractNodeId,
1655 target: &AbstractNodeId,
1656 ) -> Option<&S::EdgeAbstract> {
1657 let source_key = self.node_keys_to_aid.get_right(source)?;
1658 let target_key = self.node_keys_to_aid.get_right(target)?;
1659 self.graph.get_edge_attr((*source_key, *target_key))
1660 }
1661
1662 fn rename_aid(
1664 &mut self,
1665 old_aid: AbstractNodeId,
1666 new_aid: AbstractNodeId,
1667 ) -> Result<(), OperationBuilderError> {
1668 if self.node_keys_to_aid.contains_right(&new_aid) {
1670 bail!(OperationBuilderError::AlreadyExistsAid(new_aid));
1671 }
1672 if let Some(node_key) = self.node_keys_to_aid.remove_right(&old_aid) {
1674 self.node_keys_to_aid.insert(node_key, new_aid);
1675 } else {
1676 bail!(OperationBuilderError::NotFoundAid(old_aid));
1677 }
1678
1679 if self.node_may_originate_from_shape_query.remove(&old_aid) {
1681 self.node_may_originate_from_shape_query.insert(new_aid);
1682 }
1683 self.edge_may_originate_from_shape_query = self
1685 .edge_may_originate_from_shape_query
1686 .iter()
1687 .map(|&(src, dst)| {
1688 let new_src = if src == old_aid { new_aid } else { src };
1689 let new_dst = if dst == old_aid { new_aid } else { dst };
1690 (new_src, new_dst)
1691 })
1692 .collect();
1693
1694 if let Some(node_av) = self.node_may_be_written_to.remove(&old_aid) {
1696 self.node_may_be_written_to.insert(new_aid, node_av);
1697 }
1698 self.edge_may_be_written_to = self
1699 .edge_may_be_written_to
1700 .iter()
1701 .map(|(&(src, dst), edge_av)| {
1702 let new_src = if src == old_aid { new_aid } else { src };
1703 let new_dst = if dst == old_aid { new_aid } else { dst };
1704 ((new_src, new_dst), edge_av.clone())
1705 })
1706 .collect();
1707
1708 Ok(())
1709 }
1710
1711 fn diverge(&mut self) {
1712 if !self.has_diverged {
1714 self.has_diverged = true;
1715 }
1716 }
1717
1718 fn interpret_op(
1720 &mut self,
1721 op_ctx: &OperationContext<S>,
1722 marker: Option<AbstractOperationResultMarker>,
1723 op: AbstractOperation<S>,
1724 args: Vec<AbstractNodeId>,
1725 ) -> Result<
1726 (
1727 AbstractOperationArgument,
1728 IntermediateStateAbstractOutputResult,
1729 ),
1730 OperationBuilderError,
1731 > {
1732 if self.has_diverged {
1734 log::warn!(
1735 "Trying to issue new instruction with name {marker:?} after path has diverged. This may lead to unexpected results regarding available node names."
1736 );
1737 }
1738 let param = op.parameter();
1739 let (subst, abstract_arg) = self.get_substitution(¶m, args)?;
1740
1741 let operation_output = {
1743 let mut gws = GraphWithSubstitution::new(&mut self.graph, &subst);
1744 op.apply_abstract(op_ctx, &mut gws)
1745 .change_context(OperationBuilderError::AbstractApplyOperationError2)?
1746 };
1747 let output = self.handle_abstract_output_changes(marker, operation_output)?;
1748
1749 Ok((abstract_arg, output))
1750 }
1751
1752 fn interpret_builtin_query(
1753 &mut self,
1754 query: &S::BuiltinQuery,
1755 args: Vec<AbstractNodeId>,
1756 ) -> Result<AbstractOperationArgument, OperationBuilderError> {
1757 let param = query.parameter();
1758 let (subst, abstract_arg) = self.get_substitution(¶m, args)?;
1759 let mut gws = GraphWithSubstitution::new(&mut self.graph, &subst);
1761 query.apply_abstract(&mut gws);
1762 Ok(abstract_arg)
1763 }
1764
1765 fn handle_abstract_output_changes(
1767 &mut self,
1768 marker: Option<AbstractOperationResultMarker>,
1769 operation_output: AbstractOperationOutput<S>,
1770 ) -> Result<IntermediateStateAbstractOutputResult, OperationBuilderError> {
1771 let mut new_aids = Vec::new();
1773 for (node_marker, node_key) in operation_output.new_nodes {
1774 if let Some(op_marker) = marker {
1775 let aid = AbstractNodeId::DynamicOutputMarker(op_marker, node_marker);
1776 self.node_keys_to_aid.insert(node_key, aid);
1778 new_aids.push(aid);
1779 } else {
1780 self.graph.remove_node(node_key);
1782 }
1783 }
1784 let mut removed_aids = Vec::new();
1785 for node_key in &operation_output.removed_nodes {
1786 if let Some(removed_aid) = self.node_keys_to_aid.remove_left(&node_key) {
1788 removed_aids.push(removed_aid);
1789 }
1790 }
1791
1792 for (key, node_abstract) in operation_output.changed_abstract_values_nodes {
1797 let aid = self
1798 .get_aid_from_key(&key)
1799 .expect("internal error: changed node not found in mapping");
1800 self.node_may_be_written_to.insert(aid, node_abstract);
1801 }
1802 for ((source, target), edge_abstract) in operation_output.changed_abstract_values_edges {
1803 let source_aid = self
1804 .get_aid_from_key(&source)
1805 .expect("internal error: changed edge source not found in mapping");
1806 let target_aid = self
1807 .get_aid_from_key(&target)
1808 .expect("internal error: changed edge target not found in mapping");
1809 self.edge_may_be_written_to
1810 .insert((source_aid, target_aid), edge_abstract);
1811 }
1812
1813 Ok(IntermediateStateAbstractOutputResult {
1814 new_aids,
1815 removed_aids,
1816 })
1817 }
1818
1819 fn get_substitution(
1820 &self,
1821 param: &OperationParameter<S>,
1822 args: Vec<AbstractNodeId>,
1823 ) -> Result<(ParameterSubstitution, AbstractOperationArgument), OperationBuilderError> {
1824 let selected_inputs = args
1825 .iter()
1826 .map(|aid| self.get_key_from_aid(aid))
1827 .collect::<Result<Vec<_>, _>>()
1828 .change_context(OperationBuilderError::SelectedInputsNotFoundAid)?;
1829 let subst = get_substitution(&self.graph, ¶m, &selected_inputs)
1830 .change_context(OperationBuilderError::SubstitutionErrorNew)?;
1831 let subst_to_aid = subst.mapping.iter().map(|(subst, key)| {
1832 let aid = self.get_aid_from_key(key)
1833 .change_context(OperationBuilderError::InternalError("node key should be in mapping, because all node keys from the abstract graph should be in the mapping"))
1834 .unwrap();
1835 (subst.clone(), aid)
1836 }).collect();
1837
1838 let abstract_arg = AbstractOperationArgument {
1839 selected_input_nodes: args,
1840 subst_to_aid,
1841 };
1842
1843 Ok((subst, abstract_arg))
1844 }
1845
1846 fn get_key_from_aid(&self, aid: &AbstractNodeId) -> Result<NodeKey, OperationBuilderError> {
1847 self.node_keys_to_aid
1848 .get_right(aid)
1849 .cloned()
1850 .ok_or(report!(OperationBuilderError::NotFoundAid(*aid)))
1851 }
1852
1853 fn get_aid_from_key(&self, key: &NodeKey) -> Result<AbstractNodeId, OperationBuilderError> {
1854 self.node_keys_to_aid.get_left(key).cloned().ok_or(report!(
1855 OperationBuilderError::InternalError("could not find node key")
1856 ))
1857 }
1858
1859 fn as_param_for_shape_query(&self) -> (OperationParameter<S>, AbstractOperationArgument) {
1860 let param_graph = self.graph.clone();
1861
1862 let mut all_node_keys = param_graph
1863 .node_attr_map
1864 .keys()
1865 .cloned()
1866 .collect::<Vec<_>>();
1867 all_node_keys.sort_unstable(); let mut node_keys_to_subst: BiMap<NodeKey, SubstMarker> = BiMap::new();
1870 let mut explicit_input_nodes = Vec::new();
1871 let mut aid_args = Vec::new();
1872 let mut subst_to_aid = HashMap::new();
1873 for key in all_node_keys {
1874 let subst = SubstMarker::from(format!("{:?}", key));
1875 node_keys_to_subst.insert(key, subst);
1876 explicit_input_nodes.push(subst);
1877 let aid = self.get_aid_from_key(&key).unwrap();
1879 aid_args.push(aid);
1880 subst_to_aid.insert(subst, aid);
1881 }
1882
1883 let abstract_args = AbstractOperationArgument {
1884 selected_input_nodes: aid_args,
1885 subst_to_aid,
1886 };
1887
1888 (
1889 OperationParameter {
1890 explicit_input_nodes,
1891 parameter_graph: param_graph,
1892 node_keys_to_subst,
1893 },
1894 abstract_args,
1895 )
1896 }
1897}
1898
1899impl<S: Semantics<NodeAbstract: Debug, EdgeAbstract: Debug>> IntermediateState<S> {
1900 pub fn dot_with_aid(&self) -> String {
1901 struct PrettyAid<'a>(&'a AbstractNodeId);
1902
1903 impl Debug for PrettyAid<'_> {
1904 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1905 match self.0 {
1906 AbstractNodeId::ParameterMarker(subst) => write!(f, "P({})", subst.0),
1907 AbstractNodeId::DynamicOutputMarker(marker, node_marker) => {
1908 let op_marker = match marker {
1909 AbstractOperationResultMarker::Custom(c) => c,
1910 AbstractOperationResultMarker::Implicit(num) => "<unnamed>",
1911 };
1912 write!(f, "O({}, {})", op_marker, node_marker.0)
1913 }
1914 AbstractNodeId::Named(name) => {
1915 write!(f, "{:?}", name)
1916 }
1917 }
1918 }
1919 }
1920
1921 format!(
1924 "{:?}",
1925 Dot::with_attr_getters(
1926 &self.graph.graph,
1927 &[dot::Config::EdgeNoLabel, dot::Config::NodeNoLabel],
1928 &|g, (src, target, attr)| {
1929 let dbg_attr_format = format!("{:?}", attr.edge_attr);
1930 let dbg_attr_replaced = dbg_attr_format.escape_debug();
1931 format!("label = \"{dbg_attr_replaced}\"")
1932 },
1933 &|g, (node, _)| {
1934 let aid = self
1935 .node_keys_to_aid
1936 .get_left(&node)
1937 .expect("NodeKey not found in node_keys_to_aid");
1938 let aid = PrettyAid(aid);
1939 let aid = format!("{aid:?}");
1940 let aid_replaced = aid.escape_debug();
1941 let av = self
1942 .graph
1943 .get_node_attr(node)
1944 .expect("NodeKey not found in graph");
1945 let dbg_attr_format = format!("{:?}", av);
1946 let dbg_attr_replaced = dbg_attr_format.escape_debug();
1947
1948 format!("shape=Mrecord, label = \"{aid_replaced}|{dbg_attr_replaced}\"")
1951 }
1952 )
1953 )
1954 }
1955}
1956
1957enum InterpretedInstruction<S: Semantics> {
1958 OpLike,
1959 Query(InterpretedQueryInstructions<S>),
1960}
1961
1962struct InterpretedQueryInstructions<S: Semantics> {
1963 initial_state_true_branch: IntermediateState<S>,
1964 initial_state_false_branch: IntermediateState<S>,
1965 true_branch: InterpretedInstructions<S>,
1966 false_branch: InterpretedInstructions<S>,
1967}
1968
1969struct InterpretedInstructionWithState<S: Semantics> {
1970 instruction: InterpretedInstruction<S>,
1971 state_after: IntermediateState<S>,
1972}
1973
1974struct IntermediateInterpreter<'a, S: Semantics> {
1975 self_op_id: OperationId,
1976 op_ctx: &'a OperationContext<S>,
1977 op_param: OperationParameter<S>,
1978 initial_state: IntermediateState<S>,
1979 current_state: IntermediateState<S>,
1980 partial_self_user_defined_op: &'a UserDefinedOperation<S>,
1982 counter: u64,
1984}
1985
1986type UDInstructionsWithMarker<S> = Vec<(Option<AbstractOperationResultMarker>, UDInstruction<S>)>;
1987
1988type InterpretedInstructions<S> = Vec<(
1989 Option<AbstractOperationResultMarker>,
1990 InterpretedInstructionWithState<S>,
1991)>;
1992
1993impl<'a, S: Semantics> IntermediateInterpreter<'a, S> {
1994 fn new_for_self_op_id(
1995 self_op_id: OperationId,
1996 op_param: OperationParameter<S>,
1997 op_ctx: &'a OperationContext<S>,
1998 partial_self_user_defined_op: &'a UserDefinedOperation<S>,
1999 ) -> Self {
2000 let initial_state = IntermediateState::from_param(&op_param);
2001
2002 let current_state = initial_state.clone();
2003
2004 let interpreter = IntermediateInterpreter {
2005 self_op_id,
2006 op_ctx,
2007 op_param,
2008 initial_state,
2009 current_state,
2010 partial_self_user_defined_op,
2011 counter: 0,
2012 };
2013
2014 interpreter
2015 }
2016
2017 fn create_user_defined_operation(
2018 &mut self,
2019 intermediate_instructions: Vec<(
2020 Option<AbstractOperationResultMarker>,
2021 IntermediateInstruction<S>,
2022 )>,
2023 return_nodes: HashMap<AbstractNodeId, (AbstractOutputNodeMarker, S::NodeAbstract)>,
2024 return_edges: HashMap<(AbstractNodeId, AbstractNodeId), S::EdgeAbstract>,
2025 ) -> Result<UserDefinedOperation<S>, OperationBuilderError> {
2026 let (ud_instructions, _interp_instructions) =
2027 self.interpret_instructions(intermediate_instructions)?;
2028
2029 let (ud_output, signature) = self.determine_signature(return_nodes, return_edges)?;
2032
2033 Ok(UserDefinedOperation {
2034 instructions: ud_instructions,
2036 output_changes: ud_output,
2037 signature,
2038 })
2039 }
2040
2041 fn determine_signature(
2043 &self,
2044 return_nodes: HashMap<AbstractNodeId, (AbstractOutputNodeMarker, S::NodeAbstract)>,
2045 return_edges: HashMap<(AbstractNodeId, AbstractNodeId), S::EdgeAbstract>,
2046 ) -> Result<(AbstractUserDefinedOperationOutput, OperationSignature<S>), OperationBuilderError>
2047 {
2048 let mut ud_output = AbstractUserDefinedOperationOutput::new();
2050 let mut signature = OperationSignature::empty_new("name", self.op_param.clone());
2052
2053 for (aid, (output_marker, node_abstract)) in return_nodes {
2055 let inferred_av = self
2057 .current_state
2058 .node_av_of_aid(&aid)
2059 .ok_or(OperationBuilderError::NotFoundReturnNode(aid.clone()))?;
2060 if !S::NodeMatcher::matches(inferred_av, &node_abstract) {
2061 bail!(OperationBuilderError::InvalidReturnNodeType(aid));
2062 }
2063 if self
2064 .current_state
2065 .node_may_originate_from_shape_query
2066 .contains(&aid)
2067 {
2068 bail!(OperationBuilderError::ReturnNodeMayOriginateFromShapeQuery(
2069 aid,
2070 ));
2071 }
2072 ud_output.new_nodes.insert(aid, output_marker);
2073 signature
2075 .output
2076 .new_nodes
2077 .insert(output_marker, node_abstract);
2078 }
2079
2080 let get_param_or_output_sig_id = |aid: &AbstractNodeId| {
2081 match *aid {
2082 AbstractNodeId::ParameterMarker(s) => Ok(AbstractSignatureNodeId::ExistingNode(s)),
2083 AbstractNodeId::DynamicOutputMarker(_, _) | AbstractNodeId::Named(..) => {
2084 let Some(output_marker) = ud_output.new_nodes.get(aid) else {
2086 bail!(OperationBuilderError::NotFoundReturnNode(aid.clone()));
2087 };
2088 Ok(AbstractSignatureNodeId::NewNode(output_marker.clone()))
2089 }
2090 }
2091 };
2092
2093 for ((source_aid, target_aid), edge_abstract) in return_edges {
2095 let Some(source_key) = self.current_state.node_keys_to_aid.get_right(&source_aid)
2096 else {
2097 bail!(OperationBuilderError::NotFoundReturnEdgeSource(source_aid));
2098 };
2099 let Some(target_key) = self.current_state.node_keys_to_aid.get_right(&target_aid)
2100 else {
2101 bail!(OperationBuilderError::NotFoundReturnEdgeTarget(target_aid));
2102 };
2103 let inferred_edge_av = self
2104 .current_state
2105 .edge_av_of_aid(&source_aid, &target_aid)
2106 .ok_or(OperationBuilderError::NotFoundReturnEdge(
2107 source_aid.clone(),
2108 target_aid.clone(),
2109 ))?;
2110 if !S::EdgeMatcher::matches(inferred_edge_av, &edge_abstract) {
2111 bail!(OperationBuilderError::InvalidReturnEdgeType(
2112 source_aid, target_aid,
2113 ));
2114 }
2115 if self
2116 .current_state
2117 .edge_may_originate_from_shape_query
2118 .contains(&(source_aid, target_aid))
2119 {
2120 bail!(OperationBuilderError::ReturnEdgeMayOriginateFromShapeQuery(
2121 source_aid, target_aid,
2122 ));
2123 }
2124
2125 let source_sig_id = get_param_or_output_sig_id(&source_aid)?;
2127 let target_sig_id = get_param_or_output_sig_id(&target_aid)?;
2128 signature
2129 .output
2130 .new_edges
2131 .insert((source_sig_id, target_sig_id), edge_abstract.clone());
2132 }
2133
2134 let initial_subst_nodes = self
2137 .op_param
2138 .node_keys_to_subst
2139 .right_values()
2140 .cloned()
2141 .collect::<HashSet<_>>();
2142 let current_subst_nodes = self
2143 .current_state
2144 .node_keys_to_aid
2145 .right_values()
2146 .filter_map(|aid| {
2147 if let AbstractNodeId::ParameterMarker(subst) = aid {
2148 Some(subst.clone())
2149 } else {
2150 None
2151 }
2152 })
2153 .collect::<HashSet<_>>();
2154
2155 let deleted_nodes: HashSet<_> = initial_subst_nodes
2157 .difference(¤t_subst_nodes)
2158 .cloned()
2159 .collect();
2160 signature.output.maybe_deleted_nodes = deleted_nodes;
2161
2162 let mut initial_edges = HashSet::new();
2163 for (source, target, _) in self.op_param.parameter_graph.graph.all_edges() {
2164 let Some(source_subst) = self.op_param.node_keys_to_subst.get_left(&source) else {
2165 continue; };
2167 let Some(target_subst) = self.op_param.node_keys_to_subst.get_left(&target) else {
2168 continue; };
2170 initial_edges.insert((*source_subst, *target_subst));
2171 }
2172
2173 let mut current_edges = HashSet::new();
2174 for (source, target, _) in self.current_state.graph.graph.all_edges() {
2175 let Some(source_aid) = self.current_state.node_keys_to_aid.get_left(&source) else {
2176 continue; };
2178 let Some(target_aid) = self.current_state.node_keys_to_aid.get_left(&target) else {
2179 continue; };
2181 if let (
2182 AbstractNodeId::ParameterMarker(source_subst),
2183 AbstractNodeId::ParameterMarker(target_subst),
2184 ) = (source_aid, target_aid)
2185 {
2186 current_edges.insert((source_subst.clone(), target_subst.clone()));
2187 }
2188 }
2189
2190 let deleted_edges: HashSet<_> = initial_edges.difference(¤t_edges).cloned().collect();
2192 signature.output.maybe_deleted_edges = deleted_edges;
2193
2194 for (aid, node_abstract) in &self.current_state.node_may_be_written_to {
2197 let AbstractNodeId::ParameterMarker(subst) = aid else {
2199 continue;
2200 };
2201 signature
2202 .output
2203 .maybe_changed_nodes
2204 .insert(*subst, node_abstract.clone());
2205 }
2206
2207 for ((source_aid, target_aid), edge_abstract) in &self.current_state.edge_may_be_written_to
2208 {
2209 let AbstractNodeId::ParameterMarker(source_subst) = source_aid else {
2211 continue;
2212 };
2213 let AbstractNodeId::ParameterMarker(target_subst) = target_aid else {
2214 continue;
2215 };
2216 signature
2217 .output
2218 .maybe_changed_edges
2219 .insert((*source_subst, *target_subst), edge_abstract.clone());
2220 }
2221
2222 Ok((ud_output, signature))
2223 }
2224
2225 fn interpret_instructions(
2226 &mut self,
2227 intermediate_instructions: Vec<(
2228 Option<AbstractOperationResultMarker>,
2229 IntermediateInstruction<S>,
2230 )>,
2231 ) -> Result<(UDInstructionsWithMarker<S>, InterpretedInstructions<S>), OperationBuilderError>
2232 {
2233 let mut ud_instructions = Vec::new();
2234 let mut interpreted_instructions = Vec::new();
2235 for (marker, instruction) in intermediate_instructions {
2236 let (ud_instruction, interpreted_instruction) =
2237 self.interpret_single_instruction(marker.clone(), instruction)?;
2238 ud_instructions.push((marker.clone(), ud_instruction));
2239 interpreted_instructions.push((
2240 marker,
2241 InterpretedInstructionWithState {
2242 instruction: interpreted_instruction,
2243 state_after: self.current_state.clone(),
2244 },
2245 ));
2246 }
2247 Ok((ud_instructions, interpreted_instructions))
2248 }
2249
2250 fn interpret_single_instruction(
2251 &mut self,
2252 marker: Option<AbstractOperationResultMarker>,
2253 instruction: IntermediateInstruction<S>,
2254 ) -> Result<(UDInstruction<S>, InterpretedInstruction<S>), OperationBuilderError> {
2255 match instruction {
2256 IntermediateInstruction::OpLike(oplike) => Ok((
2257 self.interpret_op_like(marker, oplike)
2258 .attach_printable_lazy(|| format!("Failed OpLike"))?,
2259 InterpretedInstruction::OpLike,
2260 )),
2261 IntermediateInstruction::BuiltinQuery(query, args, query_instructions) => {
2262 self.interpret_builtin_query(query, args, query_instructions)
2263 }
2264 IntermediateInstruction::GraphShapeQuery {
2265 is_finished,
2266 marker,
2267 graph_instructions,
2268 query_instructions,
2269 } => self.interpret_graph_shape_query(
2270 is_finished,
2271 marker,
2272 graph_instructions,
2273 query_instructions,
2274 ),
2275 IntermediateInstruction::RenameNode { aid, new_name } => {
2276 let new_aid = AbstractNodeId::named(new_name);
2277
2278 Ok((
2279 self.rename_node(aid, new_aid)?,
2280 InterpretedInstruction::OpLike,
2281 ))
2282 }
2283 }
2284 }
2285
2286 fn rename_node(
2287 &mut self,
2288 old_aid: AbstractNodeId,
2289 new_aid: AbstractNodeId,
2290 ) -> Result<UDInstruction<S>, OperationBuilderError> {
2291 if let AbstractNodeId::ParameterMarker(_) = old_aid {
2293 bail!(OperationBuilderError::CannotRenameParameterNode(old_aid));
2294 }
2295 self.current_state.rename_aid(old_aid, new_aid)?;
2296 Ok(UDInstruction::RenameNode {
2297 old: old_aid,
2298 new: new_aid,
2299 })
2300 }
2301
2302 fn interpret_op_like(
2303 &mut self,
2304 marker: Option<AbstractOperationResultMarker>,
2305 oplike: IntermediateOpLike<S>,
2306 ) -> Result<UDInstruction<S>, OperationBuilderError> {
2307 match oplike {
2308 IntermediateOpLike::Builtin(builtin_op, args) => {
2309 let op = Operation::Builtin(&builtin_op);
2310 let abstract_arg =
2311 self.interpret_op(marker, op, args)
2312 .attach_printable_lazy(|| {
2313 format!("Failed to interpret builtin operation: {builtin_op:?}")
2314 })?;
2315
2316 Ok(UDInstruction::OpLike(
2317 OpLikeInstruction::Builtin(builtin_op),
2318 abstract_arg,
2319 ))
2320 }
2321 IntermediateOpLike::LibBuiltin(lib_builtin_op, args) => {
2322 let op = Operation::LibBuiltin(&lib_builtin_op);
2323 let abstract_arg =
2324 self.interpret_op(marker, op, args)
2325 .attach_printable_lazy(|| {
2326 format!("Failed to interpret lib builtin operation: {lib_builtin_op:?}")
2327 })?;
2328
2329 Ok(UDInstruction::OpLike(
2330 OpLikeInstruction::LibBuiltin(lib_builtin_op),
2331 abstract_arg,
2332 ))
2333 }
2334 IntermediateOpLike::Operation(id, args) => {
2335 let op = self
2336 .op_ctx
2337 .get(id)
2338 .ok_or(OperationBuilderError::NotFoundOperationId(id))?;
2339 let abstract_arg = self
2340 .interpret_op(marker, op, args)
2341 .attach_printable_lazy(|| format!("Failed to interpret operation: {id:?}"))?;
2342
2343 Ok(UDInstruction::OpLike(
2344 OpLikeInstruction::Operation(id),
2345 abstract_arg,
2346 ))
2347 }
2348 IntermediateOpLike::Recurse(args) => {
2349 let op = Operation::Custom(&self.partial_self_user_defined_op);
2360
2361 let abstract_arg = self
2362 .interpret_op(marker, op, args)
2363 .attach_printable_lazy(|| "Failed to interpret recursive call")?;
2364
2365 Ok(UDInstruction::OpLike(
2366 OpLikeInstruction::Operation(self.self_op_id),
2367 abstract_arg,
2368 ))
2369 }
2370 }
2371 }
2372
2373 fn interpret_op(
2374 &mut self,
2375 marker: Option<AbstractOperationResultMarker>,
2376 op: Operation<S>,
2377 args: Vec<AbstractNodeId>,
2378 ) -> Result<AbstractOperationArgument, OperationBuilderError> {
2379 self.current_state
2380 .interpret_op(
2381 &self.op_ctx,
2382 marker,
2383 AbstractOperation::from_operation(op),
2384 args,
2385 )
2386 .map(|x| x.0)
2387 }
2388
2389 fn interpret_builtin_query(
2390 &mut self,
2391 query: S::BuiltinQuery,
2392 args: Vec<AbstractNodeId>,
2393 query_instructions: IntermediateQueryInstructions<S>,
2394 ) -> Result<(UDInstruction<S>, InterpretedInstruction<S>), OperationBuilderError> {
2395 let param = query.parameter();
2396 let (subst, arg) = self.get_current_substitution(¶m, args)?;
2397
2398 query.apply_abstract(&mut GraphWithSubstitution::new(
2400 &mut self.current_state.graph,
2401 &subst,
2402 ));
2403
2404 let state_before = self.current_state.clone();
2409 let false_branch_state = self.current_state.clone();
2410
2411 let initial_true_branch_state = self.current_state.clone();
2412 let initial_false_branch_state = self.current_state.clone();
2413
2414 let (ud_true_branch, interp_true_branch) =
2416 self.interpret_instructions(query_instructions.true_branch)?;
2417 let after_true_branch_state = mem::replace(&mut self.current_state, false_branch_state);
2418 let (ud_false_branch, interp_false_branch) =
2419 self.interpret_instructions(query_instructions.false_branch)?;
2420 let after_false_branch_state = mem::replace(&mut self.current_state, state_before);
2421
2422 let merged_state = merge_states(false, &after_true_branch_state, &after_false_branch_state);
2431 self.current_state = merged_state;
2432
2433 let ud_instr = UDInstruction::BuiltinQuery(
2434 query,
2435 arg,
2436 QueryInstructions {
2437 taken: ud_true_branch,
2438 not_taken: ud_false_branch,
2439 },
2440 );
2441
2442 let interp_instruction = InterpretedInstruction::Query(InterpretedQueryInstructions {
2443 initial_state_true_branch: initial_true_branch_state,
2444 initial_state_false_branch: initial_false_branch_state,
2445 true_branch: interp_true_branch,
2446 false_branch: interp_false_branch,
2447 });
2448
2449 Ok((ud_instr, interp_instruction))
2450 }
2451
2452 fn collect_self_state_to_parameter(
2454 &self,
2455 ) -> (OperationParameter<S>, AbstractOperationArgument) {
2456 self.current_state.as_param_for_shape_query()
2457 }
2458
2459 fn interpret_graph_shape_query(
2463 &mut self,
2464 is_finished: bool,
2465 gsq_op_marker: AbstractOperationResultMarker,
2466 gsq_instructions: Vec<GraphShapeQueryInstruction<S>>,
2467 query_instructions: IntermediateQueryInstructions<S>,
2468 ) -> Result<(UDInstruction<S>, InterpretedInstruction<S>), OperationBuilderError> {
2469 let state_before = self.current_state.clone();
2470
2471 let false_branch_state = self.current_state.clone();
2473 let initial_false_branch_state = false_branch_state.clone();
2474
2475 let (param, abstract_args) = self.collect_self_state_to_parameter();
2477
2478 let mut expected_graph = param.parameter_graph.clone();
2484 let mut node_keys_to_shape_idents: BiMap<NodeKey, ShapeNodeIdentifier> = BiMap::new();
2485
2486 macro_rules! aid_to_node_key_hack {
2507 ($aid:expr) => {
2508 arg_aid_to_node_keys
2509 .get_left(&$aid)
2510 .cloned()
2511 .or_else(|| {
2512 if let AbstractNodeId::DynamicOutputMarker(orm, node_marker) = $aid {
2513 if orm == gsq_op_marker {
2514 let sni: ShapeNodeIdentifier = node_marker.0.into();
2516 node_keys_to_shape_idents.get_right(&sni).copied()
2517 } else {
2518 None
2519 }
2520 } else {
2521 None
2522 }
2523 })
2524 .ok_or(OperationBuilderError::NotFoundAid($aid))
2525 };
2526 }
2527
2528 for instruction in gsq_instructions {
2529 match instruction {
2530 GraphShapeQueryInstruction::ExpectShapeNode(marker, av) => {
2531 let key = expected_graph.add_node(av.clone());
2532 let shape_node_ident = marker.0.clone().into();
2533 node_keys_to_shape_idents.insert(key, shape_node_ident);
2536
2537 let state_key = self.current_state.graph.add_node(av);
2539 let aid =
2540 AbstractNodeId::DynamicOutputMarker(gsq_op_marker.clone(), marker.clone());
2541 self.current_state
2542 .node_keys_to_aid
2543 .insert(state_key, aid.clone());
2544 self.current_state
2545 .node_may_originate_from_shape_query
2546 .insert(aid.clone());
2547 }
2548 GraphShapeQueryInstruction::ExpectShapeNodeChange(aid, av) => {
2549 let key = self.get_current_key_from_aid(aid.clone())?;
2551 expected_graph.set_node_attr(key, av.clone());
2552
2553 let state_key = self
2555 .get_current_key_from_aid(aid)
2556 .change_context(OperationBuilderError::NotFoundAid(aid))?;
2557 self.current_state.graph.set_node_attr(state_key, av);
2558 }
2559 GraphShapeQueryInstruction::ExpectShapeEdge(src, target, av) => {
2560 let src_key = self.get_current_key_from_aid(src.clone())?;
2561 let target_key = self.get_current_key_from_aid(target.clone())?;
2562 expected_graph.add_edge(src_key, target_key, av.clone());
2563
2564 let state_src_key = self
2566 .get_current_key_from_aid(src)
2567 .change_context(OperationBuilderError::ShapeEdgeSourceNotFound)?;
2568 let state_target_key = self
2569 .get_current_key_from_aid(target)
2570 .change_context(OperationBuilderError::ShapeEdgeTargetNotFound)?;
2571 self.current_state
2572 .graph
2573 .add_edge(state_src_key, state_target_key, av);
2574 self.current_state
2575 .edge_may_originate_from_shape_query
2576 .insert((src.clone(), target.clone()));
2577 }
2578 }
2579 }
2580
2581 let gsq = GraphShapeQuery::new(param, expected_graph, node_keys_to_shape_idents);
2582
2583 let initial_true_branch_state = self.current_state.clone();
2588
2589 let (ud_true_branch, interp_true_branch) =
2590 self.interpret_instructions(query_instructions.true_branch)?;
2591 let after_true_branch_state = mem::replace(&mut self.current_state, false_branch_state);
2593 let (ud_false_branch, interp_false_branch) =
2594 self.interpret_instructions(query_instructions.false_branch)?;
2595 let after_false_branch_state = mem::replace(&mut self.current_state, state_before);
2596 let merged_state = merge_states(true, &after_true_branch_state, &after_false_branch_state);
2602 self.current_state = merged_state;
2603
2604 let ud_instruction = UDInstruction::ShapeQuery(
2605 gsq,
2606 abstract_args,
2607 QueryInstructions {
2608 taken: ud_true_branch,
2609 not_taken: ud_false_branch,
2610 },
2611 );
2612
2613 let interp_instruction = InterpretedInstruction::Query(InterpretedQueryInstructions {
2614 initial_state_true_branch: initial_true_branch_state,
2615 initial_state_false_branch: initial_false_branch_state,
2616 true_branch: interp_true_branch,
2617 false_branch: interp_false_branch,
2618 });
2619
2620 Ok((ud_instruction, interp_instruction))
2621 }
2622
2623 fn interpret_graph_shape_query_old(
2624 &mut self,
2625 is_finished: bool,
2626 gsq_op_marker: AbstractOperationResultMarker,
2627 gsq_instructions: Vec<GraphShapeQueryInstruction<S>>,
2628 query_instructions: IntermediateQueryInstructions<S>,
2629 ) -> Result<(UDInstruction<S>, InterpretedInstruction<S>), OperationBuilderError> {
2630 let state_before = self.current_state.clone();
2631
2632 let false_branch_state = self.current_state.clone();
2634 let initial_false_branch_state = false_branch_state.clone();
2635
2636 let mut param_builder = OperationParameterBuilder::new();
2638
2639 let mut abstract_args = Vec::new();
2640
2641 let mut arg_aid_to_param_subst: BiMap<AbstractNodeId, SubstMarker> = BiMap::new();
2642 let mut arg_aid_to_node_keys: BiMap<AbstractNodeId, NodeKey> = BiMap::new();
2643
2644 let mut collect_aid = |aid: AbstractNodeId| -> Result<(), OperationBuilderError> {
2647 if arg_aid_to_param_subst.contains_left(&aid) {
2648 return Ok(());
2650 }
2651 let subst_marker = param_builder.next_subst_marker();
2653 let key = self.get_current_key_from_aid(aid)?;
2654 let abstract_value = self
2655 .current_state
2656 .graph
2657 .get_node_attr(key)
2658 .expect(
2659 "internal error: node key should be in state graph since it is in the mapping",
2660 )
2661 .clone();
2662 param_builder
2665 .expect_explicit_input_node(subst_marker, abstract_value)
2666 .change_context(OperationBuilderError::InternalError(
2667 "node should not be in param",
2668 ))?;
2669 abstract_args.push(aid.clone());
2671 arg_aid_to_param_subst.insert(aid.clone(), subst_marker.clone());
2672 arg_aid_to_node_keys.insert(aid.clone(), key);
2673 Ok(())
2674 };
2675
2676 let mut collect_non_shape_ident =
2678 |&aid: &AbstractNodeId| -> Result<(), OperationBuilderError> {
2679 match aid {
2680 AbstractNodeId::ParameterMarker(_) => {
2681 collect_aid(aid)?;
2683 }
2684 AbstractNodeId::DynamicOutputMarker(orm, node_marker) => {
2685 if orm != gsq_op_marker {
2687 collect_aid(aid)?;
2688 }
2689 }
2690 AbstractNodeId::Named(..) => {
2691 collect_aid(aid)?;
2694 }
2695 }
2696 Ok(())
2697 };
2698
2699 for instruction in &gsq_instructions {
2700 match instruction {
2701 GraphShapeQueryInstruction::ExpectShapeNode(_, _) => {
2702 }
2704 GraphShapeQueryInstruction::ExpectShapeEdge(src, target, _) => {
2705 collect_non_shape_ident(src)?;
2708 collect_non_shape_ident(target)?;
2709 }
2710 GraphShapeQueryInstruction::ExpectShapeNodeChange(aid, _) => {
2711 collect_non_shape_ident(aid)?;
2713 }
2714 }
2715 }
2716
2717 let param = param_builder
2718 .build()
2719 .change_context(OperationBuilderError::InternalError(
2720 "Failed to build operation parameter for graph shape query",
2721 ))?;
2722
2723 let mut expected_graph = param.parameter_graph.clone();
2729 let mut node_keys_to_shape_idents: BiMap<NodeKey, ShapeNodeIdentifier> = BiMap::new();
2730
2731 macro_rules! aid_to_node_key_hack {
2752 ($aid:expr) => {
2753 arg_aid_to_node_keys
2754 .get_left(&$aid)
2755 .cloned()
2756 .or_else(|| {
2757 if let AbstractNodeId::DynamicOutputMarker(orm, node_marker) = $aid {
2758 if orm == gsq_op_marker {
2759 let sni: ShapeNodeIdentifier = node_marker.0.into();
2761 node_keys_to_shape_idents.get_right(&sni).copied()
2762 } else {
2763 None
2764 }
2765 } else {
2766 None
2767 }
2768 })
2769 .ok_or(OperationBuilderError::NotFoundAid($aid))
2770 };
2771 }
2772
2773 for instruction in gsq_instructions {
2774 match instruction {
2775 GraphShapeQueryInstruction::ExpectShapeNode(marker, av) => {
2776 let key = expected_graph.add_node(av.clone());
2777 let shape_node_ident = marker.0.clone().into();
2778 node_keys_to_shape_idents.insert(key, shape_node_ident);
2781
2782 let state_key = self.current_state.graph.add_node(av);
2784 let aid =
2785 AbstractNodeId::DynamicOutputMarker(gsq_op_marker.clone(), marker.clone());
2786 self.current_state
2787 .node_keys_to_aid
2788 .insert(state_key, aid.clone());
2789 self.current_state
2790 .node_may_originate_from_shape_query
2791 .insert(aid.clone());
2792 }
2793 GraphShapeQueryInstruction::ExpectShapeNodeChange(aid, av) => {
2794 let key = aid_to_node_key_hack!(aid.clone())?;
2796 expected_graph.set_node_attr(key, av.clone());
2797
2798 let state_key = self
2800 .get_current_key_from_aid(aid)
2801 .change_context(OperationBuilderError::NotFoundAid(aid))?;
2802 self.current_state.graph.set_node_attr(state_key, av);
2803 }
2804 GraphShapeQueryInstruction::ExpectShapeEdge(src, target, av) => {
2805 let src_key = aid_to_node_key_hack!(src.clone())?;
2806 let target_key = aid_to_node_key_hack!(target.clone())?;
2807 expected_graph.add_edge(src_key, target_key, av.clone());
2808
2809 let state_src_key = self
2811 .get_current_key_from_aid(src)
2812 .change_context(OperationBuilderError::ShapeEdgeSourceNotFound)?;
2813 let state_target_key = self
2814 .get_current_key_from_aid(target)
2815 .change_context(OperationBuilderError::ShapeEdgeTargetNotFound)?;
2816 self.current_state
2817 .graph
2818 .add_edge(state_src_key, state_target_key, av);
2819 self.current_state
2820 .edge_may_originate_from_shape_query
2821 .insert((src.clone(), target.clone()));
2822 }
2823 }
2824 }
2825
2826 let gsq = GraphShapeQuery::new(param, expected_graph, node_keys_to_shape_idents);
2827
2828 let initial_true_branch_state = self.current_state.clone();
2833
2834 let (ud_true_branch, interp_true_branch) =
2835 self.interpret_instructions(query_instructions.true_branch)?;
2836 let after_true_branch_state = mem::replace(&mut self.current_state, false_branch_state);
2838 let (ud_false_branch, interp_false_branch) =
2839 self.interpret_instructions(query_instructions.false_branch)?;
2840 let after_false_branch_state = mem::replace(&mut self.current_state, state_before);
2841 let merged_state = merge_states(true, &after_true_branch_state, &after_false_branch_state);
2847 self.current_state = merged_state;
2848
2849 let ud_instruction = UDInstruction::ShapeQuery(
2850 gsq,
2851 AbstractOperationArgument {
2852 selected_input_nodes: abstract_args,
2853 subst_to_aid: arg_aid_to_param_subst.into_right_map(),
2854 },
2855 QueryInstructions {
2856 taken: ud_true_branch,
2857 not_taken: ud_false_branch,
2858 },
2859 );
2860
2861 let interp_instruction = InterpretedInstruction::Query(InterpretedQueryInstructions {
2862 initial_state_true_branch: initial_true_branch_state,
2863 initial_state_false_branch: initial_false_branch_state,
2864 true_branch: interp_true_branch,
2865 false_branch: interp_false_branch,
2866 });
2867
2868 Ok((ud_instruction, interp_instruction))
2869 }
2870
2871 fn get_current_substitution(
2872 &self,
2873 param: &OperationParameter<S>,
2874 args: Vec<AbstractNodeId>,
2875 ) -> Result<(ParameterSubstitution, AbstractOperationArgument), OperationBuilderError> {
2876 self.current_state.get_substitution(param, args)
2877 }
2878
2879 fn get_new_unnamed_abstract_operation_marker(&mut self) -> AbstractOperationResultMarker {
2880 let val = self.counter;
2881 self.counter += 1;
2882 AbstractOperationResultMarker::Implicit(val)
2883 }
2884
2885 fn get_current_key_from_aid(
2886 &self,
2887 aid: AbstractNodeId,
2888 ) -> Result<NodeKey, OperationBuilderError> {
2889 self.current_state.get_key_from_aid(&aid)
2890 }
2891
2892 fn get_current_aid_from_key(
2893 &self,
2894 key: NodeKey,
2895 ) -> Result<AbstractNodeId, OperationBuilderError> {
2896 self.current_state.get_aid_from_key(&key)
2897 }
2898}
2899
2900fn get_state_for_path<S: Semantics>(
2901 initial_state: &IntermediateState<S>,
2902 interpreted_instructions: &InterpretedInstructions<S>,
2903 path: &mut impl Iterator<Item = IntermediateStatePath>,
2904) -> Option<IntermediateState<S>> {
2905 let mut current_state = initial_state;
2906
2907 for (_, instruction) in interpreted_instructions {
2908 match path.next() {
2909 None => {
2910 return Some(current_state.clone());
2912 }
2913 Some(path_element) => {
2914 match path_element {
2915 IntermediateStatePath::Advance | IntermediateStatePath::SkipQuery => {
2916 current_state = &instruction.state_after;
2917 }
2918 IntermediateStatePath::EnterTrue | IntermediateStatePath::EnterFalse => {
2919 panic!(
2921 "internal error: unexpected path element: {:?}",
2922 path_element
2923 );
2924 }
2925 IntermediateStatePath::StartQuery(..) => {
2926 if let InterpretedInstruction::Query(query_instructions) =
2927 &instruction.instruction
2928 {
2929 current_state = &query_instructions.initial_state_true_branch;
2932
2933 match path.next() {
2935 Some(IntermediateStatePath::EnterTrue) => {
2936 return get_state_for_path(
2938 ¤t_state,
2939 &query_instructions.true_branch,
2940 path,
2941 );
2942 }
2943 Some(IntermediateStatePath::EnterFalse) => {
2944 current_state = &query_instructions.initial_state_false_branch;
2946 return get_state_for_path(
2947 ¤t_state,
2948 &query_instructions.false_branch,
2949 path,
2950 );
2951 }
2952 _ => {
2953 return Some(current_state.clone());
2955 }
2956 }
2957 } else {
2958 return None;
2960 }
2961 }
2962 }
2963 }
2964 }
2965 }
2966
2967 Some(current_state.clone())
2968}
2969
2970fn get_query_path_for_path<S: Semantics>(
2971 path: &mut impl Iterator<Item = IntermediateStatePath>,
2972) -> Vec<QueryPath> {
2973 let mut query_path = Vec::new();
2974
2975 for pe in path {
2976 match pe {
2977 IntermediateStatePath::EnterTrue => query_path.push(QueryPath::TrueBranch),
2978 IntermediateStatePath::EnterFalse => query_path.push(QueryPath::FalseBranch),
2979 IntermediateStatePath::StartQuery(name) => {
2980 query_path.push(QueryPath::Query(
2981 name.unwrap_or("<unnamed query>".to_string()),
2982 ));
2983 }
2984 _ => {}
2985 }
2986 }
2987
2988 query_path
2989}
2990
2991fn merge_states<S: Semantics>(
3010 is_true_shape: bool,
3011 state_true: &IntermediateState<S>,
3012 state_false: &IntermediateState<S>,
3013) -> IntermediateState<S> {
3014 merge_states_result(is_true_shape, state_true, state_false).merged_state
3015}
3016
3017struct MergeStatesResult<S: Semantics> {
3018 merged_state: IntermediateState<S>,
3019 missing_from_true: HashSet<AbstractNodeId>,
3021 missing_from_false: HashSet<AbstractNodeId>,
3023}
3024
3025fn merge_states_result<S: Semantics>(
3026 is_true_shape: bool,
3027 state_true: &IntermediateState<S>,
3028 state_false: &IntermediateState<S>,
3029) -> MergeStatesResult<S> {
3030 if state_true.has_diverged {
3037 return MergeStatesResult {
3038 merged_state: state_false.clone(),
3039 missing_from_true: state_true
3042 .node_keys_to_aid
3043 .right_values()
3044 .copied()
3045 .collect(),
3046 missing_from_false: HashSet::new(),
3047 };
3048 }
3049 if state_false.has_diverged {
3050 return MergeStatesResult {
3051 merged_state: state_true.clone(),
3052 missing_from_true: HashSet::new(),
3055 missing_from_false: state_false
3056 .node_keys_to_aid
3057 .right_values()
3058 .copied()
3059 .collect(),
3060 };
3061 }
3062
3063 let mut new_state = IntermediateState::new();
3064
3065 let mut common_aids = HashSet::new();
3066 for aid in state_true.node_keys_to_aid.right_values() {
3068 if state_false.node_keys_to_aid.contains_right(aid) {
3069 common_aids.insert(aid.clone());
3070 }
3071 }
3072
3073 for aid in common_aids {
3075 let key_true = *state_true
3076 .node_keys_to_aid
3077 .get_right(&aid)
3078 .expect("internal error: AID should be in mapping");
3079 let key_false = *state_false
3080 .node_keys_to_aid
3081 .get_right(&aid)
3082 .expect("internal error: AID should be in mapping");
3083
3084 let av_true = state_true
3086 .graph
3087 .get_node_attr(key_true)
3088 .expect("internal error: Key should be in graph");
3089 let av_false = state_false
3090 .graph
3091 .get_node_attr(key_false)
3092 .expect("internal error: Key should be in graph");
3093
3094 let Some(merged_av) = S::join_nodes(av_true, av_false) else {
3096 continue;
3098 };
3099
3100 let new_key = new_state.graph.add_node(merged_av);
3102 new_state.node_keys_to_aid.insert(new_key, aid.clone());
3103 if state_true
3105 .node_may_originate_from_shape_query
3106 .contains(&aid)
3107 || state_false
3108 .node_may_originate_from_shape_query
3109 .contains(&aid)
3110 {
3111 new_state.node_may_originate_from_shape_query.insert(aid);
3112 }
3113 let written_av_true = state_true.node_may_be_written_to.get(&aid).cloned();
3116 let written_av_false = state_false.node_may_be_written_to.get(&aid).cloned();
3117 let merged_written_av = match (written_av_true, written_av_false) {
3118 (Some(av_true), Some(av_false)) => {
3119 Some(S::join_nodes(&av_true, &av_false).expect(
3122 "client semantics error: expected to be able to merge written node attributes",
3123 ))
3124 }
3125 (Some(av_true), None) => Some(av_true),
3126 (None, Some(av_false)) => Some(av_false),
3127 (None, None) => None,
3128 };
3129 if let Some(merged_av) = merged_written_av {
3130 new_state.node_may_be_written_to.insert(aid, merged_av);
3131 }
3132 }
3133
3134 for (from_key_true, to_key_true, attr) in state_true.graph.graph.all_edges() {
3136 let from_aid = state_true
3137 .node_keys_to_aid
3138 .get_left(&from_key_true)
3139 .expect("internal error: from key should be in mapping");
3140 let to_aid = state_true
3141 .node_keys_to_aid
3142 .get_left(&to_key_true)
3143 .expect("internal error: to key should be in mapping");
3144 let Some(from_key_merged) = new_state.node_keys_to_aid.get_right(from_aid) else {
3145 continue;
3147 };
3148 let Some(to_key_merged) = new_state.node_keys_to_aid.get_right(to_aid) else {
3149 continue;
3151 };
3152 let av_true = state_true
3153 .graph
3154 .get_edge_attr((from_key_true, to_key_true))
3155 .expect("internal error: edge should be in graph");
3156
3157 let Some(from_key_false) = state_false.node_keys_to_aid.get_right(from_aid) else {
3160 continue;
3161 };
3162 let Some(to_key_false) = state_false.node_keys_to_aid.get_right(to_aid) else {
3163 continue;
3164 };
3165
3166 let Some(av_false) = state_false
3168 .graph
3169 .get_edge_attr((*from_key_false, *to_key_false))
3170 else {
3171 continue;
3173 };
3174 let Some(merged_av) = S::join_edges(av_true, av_false) else {
3175 continue;
3177 };
3178 new_state
3180 .graph
3181 .add_edge(*from_key_merged, *to_key_merged, merged_av);
3182 let edge = (from_aid.clone(), to_aid.clone());
3184 if state_true
3185 .edge_may_originate_from_shape_query
3186 .contains(&edge)
3187 || state_false
3188 .edge_may_originate_from_shape_query
3189 .contains(&edge)
3190 {
3191 new_state.edge_may_originate_from_shape_query.insert(edge);
3192 }
3193
3194 let written_av_true = state_true
3195 .edge_may_be_written_to
3196 .get(&(from_aid.clone(), to_aid.clone()))
3197 .cloned();
3198 let written_av_false = state_false
3199 .edge_may_be_written_to
3200 .get(&(from_aid.clone(), to_aid.clone()))
3201 .cloned();
3202 let merged_written_av = match (written_av_true, written_av_false) {
3203 (Some(av_true), Some(av_false)) => {
3204 Some(S::join_edges(&av_true, &av_false).expect(
3217 "client semantics error: expected to be able to merge written edge attributes",
3218 ))
3219 }
3220 (Some(av_true), None) => Some(av_true),
3221 (None, Some(av_false)) => Some(av_false),
3222 (None, None) => None,
3223 };
3224 if let Some(merged_av) = merged_written_av {
3225 new_state
3226 .edge_may_be_written_to
3227 .insert((from_aid.clone(), to_aid.clone()), merged_av);
3228 }
3229
3230 }
3232
3233 let final_merged_state_aids = new_state
3235 .node_keys_to_aid
3236 .right_values()
3237 .cloned()
3238 .collect::<HashSet<_>>();
3239
3240 MergeStatesResult {
3241 merged_state: new_state,
3242 missing_from_true: state_true
3243 .node_keys_to_aid
3244 .right_values()
3245 .cloned()
3246 .filter(|aid| !final_merged_state_aids.contains(aid))
3247 .collect(),
3248 missing_from_false: state_false
3249 .node_keys_to_aid
3250 .right_values()
3251 .cloned()
3252 .filter(|aid| !final_merged_state_aids.contains(aid))
3253 .collect(),
3254 }
3255}