|
28 | 28 | //! “import/export” points. |
29 | 29 | //! |
30 | 30 | //! At query time, we can then load in the _partial paths_ for each file, instead of the files' |
31 | | -//! full stack graph structure. We can efficiently [concatenate][] partial paths together, |
| 31 | +//! full stack graph structure. We can efficiently [append][] or [prepend][] partial paths together, |
32 | 32 | //! producing the original "full" path that represents a name binding. |
33 | 33 | //! |
34 | | -//! [concatenate]: struct.PartialPath.html#method.concatenate |
| 34 | +//! [append]: struct.PartialPath.html#method.append_partial_path |
| 35 | +//! [prepend]: struct.PartialPath.html#method.prepend_partial_path |
35 | 36 |
|
36 | 37 | use std::collections::VecDeque; |
37 | 38 | use std::convert::TryFrom; |
@@ -814,8 +815,8 @@ impl PartialSymbolStack { |
814 | 815 | /// account any existing variable assignments, and updates those variable assignments with |
815 | 816 | /// whatever constraints are necessary to produce a correct result. |
816 | 817 | /// |
817 | | - /// Note that this operation is commutative. (Concatenating partial paths, defined in |
818 | | - /// [`PartialPath::concatenate`][], is not.) |
| 818 | + /// Note that this operation is commutative. (Appending and prepending partial paths, defined in |
| 819 | + /// [`PartialPath::append_partial_path`][]/[`PartialPath::prepend_partial_path`][], is not.) |
819 | 820 | pub fn unify( |
820 | 821 | self, |
821 | 822 | partials: &mut PartialPaths, |
@@ -1242,8 +1243,8 @@ impl PartialScopeStack { |
1242 | 1243 | /// account any existing variable assignments, and updates those variable assignments with |
1243 | 1244 | /// whatever constraints are necessary to produce a correct result. |
1244 | 1245 | /// |
1245 | | - /// Note that this operation is commutative. (Concatenating partial paths, defined in |
1246 | | - /// [`PartialPath::concatenate`][], is not.) |
| 1246 | + /// Note that this operation is commutative. (Appending and prepending partial paths, defined in |
| 1247 | + /// [`PartialPath::append_partial_path`][]/[`PartialPath::prepend_partial_path`][], is not.) |
1247 | 1248 | pub fn unify( |
1248 | 1249 | self, |
1249 | 1250 | partials: &mut PartialPaths, |
@@ -2795,16 +2796,15 @@ impl Path { |
2795 | 2796 | // Extending partial paths with partial paths |
2796 | 2797 |
|
2797 | 2798 | impl PartialPath { |
2798 | | - /// Attempts to concatenate two partial paths. If the postcondition of the “left” partial path |
2799 | | - /// is not compatible with the precondition of the “right” path, we return an error describing |
2800 | | - /// why. |
| 2799 | + /// Attempts to append a partial path to this one. If the postcondition of the “left” partial path |
| 2800 | + /// is not compatible with the precondition of the “right” path, we return an error describing why. |
2801 | 2801 | /// |
2802 | 2802 | /// If the left- and right-hand partial paths have any symbol or scope stack variables in |
2803 | 2803 | /// common, then we ensure that the variables bind to the same values on both sides. It's your |
2804 | 2804 | /// responsibility to update the two partial paths so that they have no variables in common, if |
2805 | 2805 | /// that's needed for your use case. |
2806 | 2806 | #[cfg_attr(not(feature = "copious-debugging"), allow(unused_variables))] |
2807 | | - pub fn concatenate( |
| 2807 | + pub fn append_partial_path( |
2808 | 2808 | &mut self, |
2809 | 2809 | graph: &StackGraph, |
2810 | 2810 | partials: &mut PartialPaths, |
@@ -2864,6 +2864,74 @@ impl PartialPath { |
2864 | 2864 | Ok(()) |
2865 | 2865 | } |
2866 | 2866 |
|
| 2867 | + /// Attempts to prepend a partial path to this one. If the postcondition of the “left” partial path |
| 2868 | + /// is not compatible with the precondition of the “right” path, we return an error describing why. |
| 2869 | + /// |
| 2870 | + /// If the left- and right-hand partial paths have any symbol or scope stack variables in |
| 2871 | + /// common, then we ensure that the variables bind to the same values on both sides. It's your |
| 2872 | + /// responsibility to update the two partial paths so that they have no variables in common, if |
| 2873 | + /// that's needed for your use case. |
| 2874 | + #[cfg_attr(not(feature = "copious-debugging"), allow(unused_variables))] |
| 2875 | + pub fn prepend_partial_path( |
| 2876 | + &mut self, |
| 2877 | + graph: &StackGraph, |
| 2878 | + partials: &mut PartialPaths, |
| 2879 | + lhs: &PartialPath, |
| 2880 | + ) -> Result<(), PathResolutionError> { |
| 2881 | + let rhs = self; |
| 2882 | + |
| 2883 | + #[cfg_attr(not(feature = "copious-debugging"), allow(unused_mut))] |
| 2884 | + let mut join = Self::compute_join(graph, partials, lhs, rhs)?; |
| 2885 | + #[cfg(feature = "copious-debugging")] |
| 2886 | + { |
| 2887 | + let unified_symbol_stack = join |
| 2888 | + .unified_symbol_stack |
| 2889 | + .display(graph, partials) |
| 2890 | + .to_string(); |
| 2891 | + let unified_scope_stack = join |
| 2892 | + .unified_scope_stack |
| 2893 | + .display(graph, partials) |
| 2894 | + .to_string(); |
| 2895 | + let symbol_bindings = join.symbol_bindings.display(graph, partials).to_string(); |
| 2896 | + let scope_bindings = join.scope_bindings.display(graph, partials).to_string(); |
| 2897 | + copious_debugging!( |
| 2898 | + " via <{}> ({}) {} {}", |
| 2899 | + unified_symbol_stack, |
| 2900 | + unified_scope_stack, |
| 2901 | + symbol_bindings, |
| 2902 | + scope_bindings, |
| 2903 | + ); |
| 2904 | + } |
| 2905 | + |
| 2906 | + rhs.symbol_stack_precondition = lhs.symbol_stack_precondition.apply_partial_bindings( |
| 2907 | + partials, |
| 2908 | + &join.symbol_bindings, |
| 2909 | + &join.scope_bindings, |
| 2910 | + )?; |
| 2911 | + rhs.symbol_stack_postcondition = rhs.symbol_stack_postcondition.apply_partial_bindings( |
| 2912 | + partials, |
| 2913 | + &join.symbol_bindings, |
| 2914 | + &join.scope_bindings, |
| 2915 | + )?; |
| 2916 | + |
| 2917 | + rhs.scope_stack_precondition = lhs |
| 2918 | + .scope_stack_precondition |
| 2919 | + .apply_partial_bindings(partials, &join.scope_bindings)?; |
| 2920 | + rhs.scope_stack_postcondition = rhs |
| 2921 | + .scope_stack_postcondition |
| 2922 | + .apply_partial_bindings(partials, &join.scope_bindings)?; |
| 2923 | + |
| 2924 | + let mut edges = lhs.edges; |
| 2925 | + while let Some(edge) = edges.pop_back(partials) { |
| 2926 | + rhs.edges.push_front(partials, edge); |
| 2927 | + } |
| 2928 | + rhs.start_node = lhs.start_node; |
| 2929 | + |
| 2930 | + rhs.resolve(graph, partials)?; |
| 2931 | + |
| 2932 | + Ok(()) |
| 2933 | + } |
| 2934 | + |
2867 | 2935 | /// Compute the bindings to join to partial paths. It is the caller's responsibility |
2868 | 2936 | /// to ensure non-overlapping variables, if that is required. |
2869 | 2937 | fn compute_join( |
|
0 commit comments