fn bind_syntax_monad(bindings: SymbolBindings, substitutions: Vec<(usize, CellRef)>, symbol_reference_type: ReferenceType, partially_bound: &CellRef, imported_bindings: Arc<HashMap<usize, CellRef>>) -> (SymbolBindings, Result<SyntaxBindingResult, BindError>) {
    // Iterate through the substitutions. We're looking for the first one that has a monad reference type
    let monad_index = (0..substitutions.len()).into_iter()
        .filter(|index| substitutions[*index].1.reference_type() == ReferenceType::Monad)
        .nth(0);

    if let Some(monad_index) = monad_index {
        // Replace the monad with the parameter of a stack closure and try again

        // Create an interior frame
        let mut interior_bindings   = bindings.push_new_frame();

        // The monad parameter becomes argument one of the closure
        let monad_value_cell        = interior_bindings.alloc_cell();

        // Other substitutions are passed in as parameters to the closure we're generating
        let mut new_substitutions   = vec![];
        let mut import_cells        = vec![];

        for substitution_index in 0..substitutions.len() {
            let (bound_cell_id, value) = &substitutions[substitution_index];

            if substitution_index != monad_index {
                // Cell value will be captured by the closure
                let closure_cell    = interior_bindings.alloc_cell();
                let reference_type  = value.reference_type();
                import_cells.push(closure_cell);

                new_substitutions.push((*bound_cell_id, CellRef::new(SafasCell::FrameReference(closure_cell, 0, reference_type))));
            } else {
                // Monad value cell (ie, the flat_map argument)
                new_substitutions.push((*bound_cell_id, CellRef::new(SafasCell::FrameReference(monad_value_cell, 0, ReferenceType::Value))));
            }
        }

        // Bring in the imported bindings
        let (interior_bindings, new_imported_bindings) = rebind_imported_bindings(imported_bindings.clone(), interior_bindings, 1);
        let imported_bindings   = new_imported_bindings.unwrap_or(imported_bindings);

        // Create the closure implementation by binding again (if there are more monad arguments, they'll get rebound here)
        let (interior_bindings, closure_binding) = bind_syntax_monad(interior_bindings, new_substitutions, symbol_reference_type, partially_bound, imported_bindings);
        let closure_binding     = match closure_binding { 
            Ok(bound_value) => bound_value, 
            Err(err)        => {
                let (bindings, _import) = interior_bindings.pop();
                return (bindings, Err(err));
            }
        };

        // Compile the closure (TODO: nearly the same as the compile implementation above, extract to its own method)
        let mut actions = CompiledActions::empty();

        match closure_binding {
            SyntaxBindingResult::Statements(closure_binding) => {
                let is_monad    = symbol_reference_type == ReferenceType::Monad;

                let mut first   = true;
                let mut pos     = &*closure_binding;

                while let SafasCell::List(statement, next) = pos {
                    // Compile the statement
                    let compiled_actions = compile_statement(statement.clone());
                    let compiled_actions = match compiled_actions {
                        Ok(actions) => actions,
                        Err(err)    => {
                            let (bindings, _import) = interior_bindings.pop();
                            return (bindings, Err(err));
                        }
                    };

                    // Add the compiled statements to the actions for the closure
                    actions.extend(compiled_actions);

                    // Map between values if the value is a monad
                    if is_monad {
                        if statement.reference_type() != ReferenceType::Monad {
                            // Wrap the statement if it doesn't return a monad
                            actions.push(Action::Wrap);
                        }

                        if first {
                            // First monad is just pushed onto the stack
                            actions.push(Action::Push);
                        } else {
                            // Others are mapped using the next function
                            actions.push(Action::Next);
                        }
                    }

                    first   = false;
                    pos     = next;
                }

                if is_monad {
                    if !first {
                        // Pop the monad value
                        actions.push(Action::Pop);
                    }
                } else {
                    // Wrap the value to create a monad
                    actions.push(Action::Wrap)
                }
            }

            SyntaxBindingResult::FlatMap(monad_value, closure_value) => {
                let flat_map_actions = compile_flat_map(monad_value, closure_value);
                let flat_map_actions = match flat_map_actions {
                    Ok(actions) => actions,
                    Err(err)    => {
                        let (bindings, _import) = interior_bindings.pop();
                        return (bindings, Err(err));
                    }
                };
                actions.extend(flat_map_actions);
            }

            SyntaxBindingResult::Fallback(_fallback) => {
                unimplemented!()
            }
        }

        // Pop the interior frame
        let interior_frame_size = interior_bindings.num_cells;
        let (bindings, imports) = interior_bindings.pop();

        for (_cell_value, cell_id) in imports.iter() {
            import_cells.push(*cell_id);
        }

        // Generate the closure that gets passed to flat_map
        let actions = actions.to_actions().collect::<Vec<_>>();
        let closure = StackClosure::new(actions, import_cells, interior_frame_size, 1, true);

        // Generate the closure expression: a list starting with the closure, followed by its arguments
        let mut closure_expression = vec![CellRef::new(SafasCell::FrameMonad(Box::new(closure)))];

        // Substitution values first (everything except the monad we're flat_mapping)
        for substitution_index in 0..substitutions.len() {
            if substitution_index != monad_index {
                let (_, defn) = &substitutions[substitution_index];
                closure_expression.push(defn.clone());
            }
        }

        // Next, any cells we wound up importing
        for (cell_value, _cell_id) in imports {
            closure_expression.push(cell_value);
        }

        // Generate a flatmap syntax result
        let (_, monad_defn) = &substitutions[monad_index];
        (bindings, Ok(SyntaxBindingResult::FlatMap(monad_defn.clone(), SafasCell::list_with_cells(closure_expression).into())))

    } else {

        // If none of the parameters are monads, we can just substitute straight into the macro
        let substitutions = substitutions.into_iter().collect::<HashMap<_, _>>();

        let (bound, bindings) = substitute_cells(bindings, &mut HashMap::new(), partially_bound, &move |cell_id| {
            substitutions.get(&cell_id)
                .or_else(|| imported_bindings.get(&cell_id))
                .cloned()
        });

        // This is the result
        (bindings, Ok(SyntaxBindingResult::Statements(bound)))
    }
}
///
/// If the specified set of substitutions contains a monad, rebinds with a flat_map to generate the final expression
///
If the specified set of substitutions contains a monad, rebinds with a flat_map to generate the final expression
If the specified set of substitutions contains a monad rebinds with a flat_map to generate the final expression
fn bind_syntax_monad(bindings: SymbolBindings, substitutions: Vec<(usize, CellRef)>, symbol_reference_type: ReferenceType, partially_bound: &CellRef, imported_bindings: Arc<HashMap<usize, CellRef>>) -> (SymbolBindings, Result<SyntaxBindingResult, BindError>) {
    // Iterate through the substitutions. We're looking for the first one that has a monad reference type
    let monad_index = (0..substitutions.len()).into_iter()
        .filter(|index| substitutions[*index].1.reference_type() == ReferenceType::Monad)
        .nth(0);
    if let Some(monad_index) = monad_index {
        // Replace the monad with the parameter of a stack closure and try again
        // Create an interior frame
        let mut interior_bindings   = bindings.push_new_frame();
        // The monad parameter becomes argument one of the closure
        let monad_value_cell        = interior_bindings.alloc_cell();
        // Other substitutions are passed in as parameters to the closure we're generating
        let mut new_substitutions   = vec![];
        let mut import_cells        = vec![];
        for substitution_index in 0..substitutions.len() {
            let (bound_cell_id, value) = &substitutions[substitution_index];
            if substitution_index != monad_index {
                // Cell value will be captured by the closure
                let closure_cell    = interior_bindings.alloc_cell();
                let reference_type  = value.reference_type();
                import_cells.push(closure_cell);
                new_substitutions.push((*bound_cell_id, CellRef::new(SafasCell::FrameReference(closure_cell, 0, reference_type))));
            } else {
                // Monad value cell (ie, the flat_map argument)
                new_substitutions.push((*bound_cell_id, CellRef::new(SafasCell::FrameReference(monad_value_cell, 0, ReferenceType::Value))));
            }
        }
        // Bring in the imported bindings
        let (interior_bindings, new_imported_bindings) = rebind_imported_bindings(imported_bindings.clone(), interior_bindings, 1);
        let imported_bindings   = new_imported_bindings.unwrap_or(imported_bindings);
        // Create the closure implementation by binding again (if there are more monad arguments, they'll get rebound here)
        let (interior_bindings, closure_binding) = bind_syntax_monad(interior_bindings, new_substitutions, symbol_reference_type, partially_bound, imported_bindings);
        let closure_binding     = match closure_binding { 
            Ok(bound_value) => bound_value, 
            Err(err)        => {
                let (bindings, _import) = interior_bindings.pop();
                return (bindings, Err(err));
            }
        };
        // Compile the closure (TODO: nearly the same as the compile implementation above, extract to its own method)
        let mut actions = CompiledActions::empty();
        match closure_binding {
            SyntaxBindingResult::Statements(closure_binding) => {
                let is_monad    = symbol_reference_type == ReferenceType::Monad;
                let mut first   = true;
                let mut pos     = &*closure_binding;
                while let SafasCell::List(statement, next) = pos {
                    // Compile the statement
                    let compiled_actions = compile_statement(statement.clone());
                    let compiled_actions = match compiled_actions {
                        Ok(actions) => actions,
                        Err(err)    => {
                            let (bindings, _import) = interior_bindings.pop();
                            return (bindings, Err(err));
                        }
                    };
                    // Add the compiled statements to the actions for the closure
                    actions.extend(compiled_actions);
                    // Map between values if the value is a monad
                    if is_monad {
                        if statement.reference_type() != ReferenceType::Monad {
                            // Wrap the statement if it doesn't return a monad
                            actions.push(Action::Wrap);
                        }
                        if first {
                            // First monad is just pushed onto the stack
                            actions.push(Action::Push);
                        } else {
                            // Others are mapped using the next function
                            actions.push(Action::Next);
                        }
                    }
                    first   = false;
                    pos     = next;
                }
                if is_monad {
                    if !first {
                        // Pop the monad value
                        actions.push(Action::Pop);
                    }
                } else {
                    // Wrap the value to create a monad
                    actions.push(Action::Wrap)
                }
            }
            SyntaxBindingResult::FlatMap(monad_value, closure_value) => {
                let flat_map_actions = compile_flat_map(monad_value, closure_value);
                let flat_map_actions = match flat_map_actions {
                    Ok(actions) => actions,
                    Err(err)    => {
                        let (bindings, _import) = interior_bindings.pop();
                        return (bindings, Err(err));
                    }
                };
                actions.extend(flat_map_actions);
            }
            SyntaxBindingResult::Fallback(_fallback) => {
                unimplemented!()
            }
        }
        // Pop the interior frame
        let interior_frame_size = interior_bindings.num_cells;
        let (bindings, imports) = interior_bindings.pop();
        for (_cell_value, cell_id) in imports.iter() {
            import_cells.push(*cell_id);
        }
        // Generate the closure that gets passed to flat_map
        let actions = actions.to_actions().collect::<Vec<_>>();
        let closure = StackClosure::new(actions, import_cells, interior_frame_size, 1, true);
        // Generate the closure expression: a list starting with the closure, followed by its arguments
        let mut closure_expression = vec![CellRef::new(SafasCell::FrameMonad(Box::new(closure)))];
        // Substitution values first (everything except the monad we're flat_mapping)
        for substitution_index in 0..substitutions.len() {
            if substitution_index != monad_index {
                let (_, defn) = &substitutions[substitution_index];
                closure_expression.push(defn.clone());
            }
        }
        // Next, any cells we wound up importing
        for (cell_value, _cell_id) in imports {
            closure_expression.push(cell_value);
        }
        // Generate a flatmap syntax result
        let (_, monad_defn) = &substitutions[monad_index];
        (bindings, Ok(SyntaxBindingResult::FlatMap(monad_defn.clone(), SafasCell::list_with_cells(closure_expression).into())))
    } else {
        // If none of the parameters are monads, we can just substitute straight into the macro
        let substitutions = substitutions.into_iter().collect::<HashMap<_, _>>();
        let (bound, bindings) = substitute_cells(bindings, &mut HashMap::new(), partially_bound, &move |cell_id| {
            substitutions.get(&cell_id)
                .or_else(|| imported_bindings.get(&cell_id))
                .cloned()
        });
        // This is the result
        (bindings, Ok(SyntaxBindingResult::Statements(bound)))
    }
}
fn bind_syntax_monad ( bindings : SymbolBindings , substitutions : Vec < ( usize , CellRef ) > , symbol_reference_type : ReferenceType , partially_bound : & CellRef , imported_bindings : Arc < HashMap < usize , CellRef > > ) -> ( SymbolBindings , Result < SyntaxBindingResult , BindError > ) { // Iterate through the substitutions. We're looking for the first one that has a monad reference type let monad_index = ( 0 .. substitutions . len ( ) ) . into_iter ( ) . filter ( | index | substitutions [ * index ] . 1 . reference_type ( ) == ReferenceType :: Monad ) . nth ( 0 ) ; if let Some ( monad_index ) = monad_index { // Replace the monad with the parameter of a stack closure and try again // Create an interior frame let mut interior_bindings = bindings . push_new_frame ( ) ; // The monad parameter becomes argument one of the closure let monad_value_cell = interior_bindings . alloc_cell ( ) ; // Other substitutions are passed in as parameters to the closure we're generating let mut new_substitutions = vec ! [ ] ; let mut import_cells = vec ! [ ] ; for substitution_index in 0 .. substitutions . len ( ) { let ( bound_cell_id , value ) = & substitutions [ substitution_index ] ; if substitution_index != monad_index { // Cell value will be captured by the closure let closure_cell = interior_bindings . alloc_cell ( ) ; let reference_type = value . reference_type ( ) ; import_cells . push ( closure_cell ) ; new_substitutions . push ( ( * bound_cell_id , CellRef :: new ( SafasCell :: FrameReference ( closure_cell , 0 , reference_type ) ) ) ) ; } else { // Monad value cell (ie, the flat_map argument) new_substitutions . push ( ( * bound_cell_id , CellRef :: new ( SafasCell :: FrameReference ( monad_value_cell , 0 , ReferenceType :: Value ) ) ) ) ; } } // Bring in the imported bindings let ( interior_bindings , new_imported_bindings ) = rebind_imported_bindings ( imported_bindings . clone ( ) , interior_bindings , 1 ) ; let imported_bindings = new_imported_bindings . unwrap_or ( imported_bindings ) ; // Create the closure implementation by binding again (if there are more monad arguments, they'll get rebound here) let ( interior_bindings , closure_binding ) = bind_syntax_monad ( interior_bindings , new_substitutions , symbol_reference_type , partially_bound , imported_bindings ) ; let closure_binding = match closure_binding { Ok ( bound_value ) => bound_value , Err ( err ) => { let ( bindings , _import ) = interior_bindings . pop ( ) ; return ( bindings , Err ( err ) ) ; } } ; // Compile the closure (TODO: nearly the same as the compile implementation above, extract to its own method) let mut actions = CompiledActions :: empty ( ) ; match closure_binding { SyntaxBindingResult :: Statements ( closure_binding ) => { let is_monad = symbol_reference_type == ReferenceType :: Monad ; let mut first = true ; let mut pos = & * closure_binding ; while let SafasCell :: List ( statement , next ) = pos { // Compile the statement let compiled_actions = compile_statement ( statement . clone ( ) ) ; let compiled_actions = match compiled_actions { Ok ( actions ) => actions , Err ( err ) => { let ( bindings , _import ) = interior_bindings . pop ( ) ; return ( bindings , Err ( err ) ) ; } } ; // Add the compiled statements to the actions for the closure actions . extend ( compiled_actions ) ; // Map between values if the value is a monad if is_monad { if statement . reference_type ( ) != ReferenceType :: Monad { // Wrap the statement if it doesn't return a monad actions . push ( Action :: Wrap ) ; } if first { // First monad is just pushed onto the stack actions . push ( Action :: Push ) ; } else { // Others are mapped using the next function actions . push ( Action :: Next ) ; } } first = false ; pos = next ; } if is_monad { if ! first { // Pop the monad value actions . push ( Action :: Pop ) ; } } else { // Wrap the value to create a monad actions . push ( Action :: Wrap ) } } SyntaxBindingResult :: FlatMap ( monad_value , closure_value ) => { let flat_map_actions = compile_flat_map ( monad_value , closure_value ) ; let flat_map_actions = match flat_map_actions { Ok ( actions ) => actions , Err ( err ) => { let ( bindings , _import ) = interior_bindings . pop ( ) ; return ( bindings , Err ( err ) ) ; } } ; actions . extend ( flat_map_actions ) ; } SyntaxBindingResult :: Fallback ( _fallback ) => { unimplemented ! ( ) } } // Pop the interior frame let interior_frame_size = interior_bindings . num_cells ; let ( bindings , imports ) = interior_bindings . pop ( ) ; for ( _cell_value , cell_id ) in imports . iter ( ) { import_cells . push ( * cell_id ) ; } // Generate the closure that gets passed to flat_map let actions = actions . to_actions ( ) . collect :: < Vec < _ > > ( ) ; let closure = StackClosure :: new ( actions , import_cells , interior_frame_size , 1 , true ) ; // Generate the closure expression: a list starting with the closure, followed by its arguments let mut closure_expression = vec ! [ CellRef new ( SafasCell FrameMonad ( Box new ( closure ) ) ) ] ; // Substitution values first (everything except the monad we're flat_mapping) for substitution_index in 0 .. substitutions . len ( ) { if substitution_index != monad_index { let ( _ , defn ) = & substitutions [ substitution_index ] ; closure_expression . push ( defn . clone ( ) ) ; } } // Next, any cells we wound up importing for ( cell_value , _cell_id ) in imports { closure_expression . push ( cell_value ) ; } // Generate a flatmap syntax result let ( _ , monad_defn ) = & substitutions [ monad_index ] ; ( bindings , Ok ( SyntaxBindingResult :: FlatMap ( monad_defn . clone ( ) , SafasCell :: list_with_cells ( closure_expression ) . into ( ) ) ) ) } else { // If none of the parameters are monads, we can just substitute straight into the macro let substitutions = substitutions . into_iter ( ) . collect :: < HashMap < _ , _ > > ( ) ; let ( bound , bindings ) = substitute_cells ( bindings , & mut HashMap :: new ( ) , partially_bound , & move | cell_id | { substitutions . get ( & cell_id ) . or_else ( | | imported_bindings . get ( & cell_id ) ) . cloned ( ) } ) ; // This is the result ( bindings , Ok ( SyntaxBindingResult :: Statements ( bound ) ) ) } }
If the specified set of substitutions contains a monad, rebinds with a flat_map to generate the final expression
If the specified set of substitutions contains a monad rebinds with a flat_map to generate the final expression
bindings
SymbolBindings
substitutions
Vec<(usize, CellRef)>
symbol_reference_type
ReferenceType
partially_bound
&CellRef
imported_bindings
Arc<HashMap<usize, CellRef>>
bindings
SymbolBindings
substitutions
Vec<(usize, CellRef)>
symbol_reference_type
ReferenceType
partially_bound
&CellRef
imported_bindings
Arc<HashMap<usize, CellRef>>