pub fn label_keyword() -> impl BindingMonad<Binding=SyntaxCompiler> {
    // Binding function. Labels are pre-bound so they're available throughout the current context
    let bind = get_expression_arguments()
        .and_then(|ListWithTail((AtomId(atom_id), ), optional_value): ListWithTail<(AtomId, ), CellRef>| {

            // The optional argument can either not be supplied or specify the label value expression
            let label_value_expr = if optional_value.is_nil() {
                // Argument not supplied
                Ok(None)
            } else {
                // 
                let value = ListTuple::<(CellRef, )>::try_from(optional_value);
                value.map(|ListTuple((value, ))| Some(value))
            };

            BindingFn(move |bindings| {
                // If a value expression is specified, fetch its value
                let label_value_expr = match label_value_expr {
                    Ok(ref value)   => value.clone(),
                    Err(ref err)    => return (bindings, Err(err.clone().into()))
                };

                // Compile the value expression if there is one
                let label_value_and_bindings = match label_value_expr {
                    None                    => Ok((NIL.clone(), bindings)),
                    Some(label_value_expr)  => bind_statement(label_value_expr, bindings)
                };

                let (bindings, label_value_expr) = match label_value_and_bindings {
                    Ok((value, bindings))   => (bindings, value),
                    Err((err, bindings))    => return (bindings, Err(err))
                };

                // Fetch the label value function (we use this if no expression is specified)
                let mut bindings    = bindings;
                let label_value_fn  = if let Some(label_value) = bindings.look_up_and_import(*LABEL_VALUE_FUNCTION) {
                    label_value
                } else {
                    NIL.clone()
                };

                // Fetch the value assigned to the atom that represents the label
                let reference = bindings.look_up(atom_id);
                let reference = match reference { Some((reference, 0)) => reference.clone(), _ => return (bindings, Err(BindError::UnknownSymbol(name_for_atom_with_id(atom_id)))) };

                // TODO: check that we've got the reference we allocated in the pre-binding (if it's been rebound the label is invalid)

                let result = SafasCell::list_with_cells(vec![reference.into(), label_value_fn, label_value_expr]);
                (bindings, Ok(result))
            },

            move |mut bindings| {
                // TODO: the label can only be pre-bound once: check that the value has not already been bound

                // Labels are bound to their own syntax item, which reads the label value when used
                let label_cell      = bindings.alloc_cell();
                let label_reference = FrameReference(label_cell, 0, ReferenceType::Monad);
                let label_action    = label_binding(label_reference);
                bindings.symbols.insert(atom_id, SafasCell::Syntax(Box::new(label_action), label_reference.into()).into());
                bindings.export(atom_id);

                // Result is just the atom as for the main binding function
                let result = SafasCell::list_with_cells(iter::once(SafasCell::Atom(atom_id).into()));
                (bindings, result)
            })

        }).map(|value| {

            let value = value.clone();

            // Compiling function: labels bind themselves to a monad that allocates/retrieves the label value at the start of the code block and just bind to the label value later on 
            let compiler = |value: CellRef| -> Result<_, BindError> {
                // Results of the bindings is the cell reference
                let ListTuple((label_action, default_label_value_fn, label_value_expr)): ListTuple<(CellRef, CellRef, CellRef)> = value.clone().try_into()?;

                // The label should be bound to a syntax item, with the frame cell as the parameter
                let cell_reference = match &*label_action { SafasCell::Syntax(_, cell_reference) => Ok(cell_reference.clone()), _ => Err(BindError::MissingArgument) }?;

                // Fetch out the frame reference
                let (cell_id, frame_num, _) = cell_reference.frame_reference().ok_or(BindError::MissingArgument)?;
                if frame_num != 0 { return Err(BindError::CannotLoadCellInOtherFrame); }

                // Start generating the actions
                let mut actions = CompiledActions::empty();

                // Frame setup allocates the label. We use the cell ID as the label ID for updating it later
                actions.frame_setup.extend(vec![
                    Action::Value(ALLOC_LABEL.clone()),
                    Action::Push,
                    Action::Value(WRAP_VALUE.clone()),
                    Action::FlatMap,
                    Action::StoreCell(cell_id)
                ]);

                // Evaluate the value calculation
                let mut value_reference_type = default_label_value_fn.reference_type();
                if default_label_value_fn.is_nil() {
                    // Read the current bit position
                    value_reference_type = ReferenceType::ReturnsMonad;
                    actions.actions.extend(vec![
                        Action::Value(READ_BIT_POS.clone()),
                    ])
                } else {
                    // Calculate a value
                    if value_reference_type == ReferenceType::Value {
                        // Create the bit_pos monad on the stack
                        actions.actions.extend(vec![
                            // Bit_pos monad
                            Action::PushValue(READ_BIT_POS.clone()),
                            Action::PushValue(NIL.clone()),
                            Action::PopCall(1),
                            Action::Push,

                            // Function conversion routine (we call this to generate a flatmap method, then call flatmap on the monad we just created)
                            Action::PushValue(MAP_TO_FLAT_MAP.clone())
                        ])
                    }

                    // Get the value of the label_value function
                    actions.extend(compile_statement(default_label_value_fn)?);
                }

                // Map the value reference type
                match value_reference_type {
                    ReferenceType::Value        => actions.actions.extend(vec![Action::Push, Action::PopCall(1), Action::FlatMap]),
                    ReferenceType::ReturnsMonad => actions.actions.extend(vec![Action::Push, Action::PushValue(NIL.clone()), Action::PopCall(1)]),
                    ReferenceType::Monad        => { }
                }

                // To evaluate the label syntax itself, we fetch the label and flat_map via SET_LABEL_VALUE
                actions.actions.extend(vec![
                    // Push the monad containing the label value
                    Action::Push,

                    // Call the closure that generates the set_label_value function from the cell value monad
                    Action::PushValue(CREATE_SET_LABEL_VALUE.clone()),
                    Action::PushCell(cell_id),
                    Action::PopCall(1),

                    // FlatMap the result with the label value monad we pushed earlier
                    Action::FlatMap
                ]);

                Ok(actions)
            };

            SyntaxCompiler::with_compiler_and_reftype(compiler, value, ReferenceType::Monad)
        });

    WithReferenceType(bind, ReferenceType::Monad)
}
///
/// The `label` keyword creates a bitcode monad that specifies a label
/// 
/// `(label foo)` - declares a label that binds to the value of the `label_value` function at 
/// the point the label is declared (or the current bit position if no label_value function
/// is availble).
/// 
/// `(label foo <expr>)` - declares a label that binds to the value of `<expr>`.
/// 
/// Label values are available everywhere in the same context (and may be passed outside 
/// of that context as separate values if necessary): note that 'forward declaration' of
/// labels are specifically allowed via the pre-binding mechanism.
/// 
/// The `label_value` function can be defined as a constant: eg `(def label_value ip)` or
/// a function which takes the current bit position: for example 
/// `(def label_value (fun (bit_pos) (/ bit_pos 8)))`
///


`(label foo )` - declares a label that binds to the value of ``.

Label values are available everywhere in the same context (and may be passed outside
of that context as separate values if necessary): note that 'forward declaration' of
labels are specifically allowed via the pre-binding mechanism.


` ( label foo ) ` - declares a label that binds to the value of ` ` . Label values are available everywhere in the same context ( and may be passed outside of that context as separate values if necessary ) : note that ' forward declaration ' of labels are specifically allowed via the pre - binding mechanism .
pub fn label_keyword() -> impl BindingMonad<Binding=SyntaxCompiler> {
    // Binding function. Labels are pre-bound so they're available throughout the current context
    let bind = get_expression_arguments()
        .and_then(|ListWithTail((AtomId(atom_id), ), optional_value): ListWithTail<(AtomId, ), CellRef>| {
            // The optional argument can either not be supplied or specify the label value expression
            let label_value_expr = if optional_value.is_nil() {
                // Argument not supplied
                Ok(None)
            } else {
                // 
                let value = ListTuple::<(CellRef, )>::try_from(optional_value);
                value.map(|ListTuple((value, ))| Some(value))
            };
            BindingFn(move |bindings| {
                // If a value expression is specified, fetch its value
                let label_value_expr = match label_value_expr {
                    Ok(ref value)   => value.clone(),
                    Err(ref err)    => return (bindings, Err(err.clone().into()))
                };
                // Compile the value expression if there is one
                let label_value_and_bindings = match label_value_expr {
                    None                    => Ok((NIL.clone(), bindings)),
                    Some(label_value_expr)  => bind_statement(label_value_expr, bindings)
                };
                let (bindings, label_value_expr) = match label_value_and_bindings {
                    Ok((value, bindings))   => (bindings, value),
                    Err((err, bindings))    => return (bindings, Err(err))
                };
                // Fetch the label value function (we use this if no expression is specified)
                let mut bindings    = bindings;
                let label_value_fn  = if let Some(label_value) = bindings.look_up_and_import(*LABEL_VALUE_FUNCTION) {
                    label_value
                } else {
                    NIL.clone()
                };
                // Fetch the value assigned to the atom that represents the label
                let reference = bindings.look_up(atom_id);
                let reference = match reference { Some((reference, 0)) => reference.clone(), _ => return (bindings, Err(BindError::UnknownSymbol(name_for_atom_with_id(atom_id)))) };
                // TODO: check that we've got the reference we allocated in the pre-binding (if it's been rebound the label is invalid)
                let result = SafasCell::list_with_cells(vec![reference.into(), label_value_fn, label_value_expr]);
                (bindings, Ok(result))
            },
            move |mut bindings| {
                // TODO: the label can only be pre-bound once: check that the value has not already been bound
                // Labels are bound to their own syntax item, which reads the label value when used
                let label_cell      = bindings.alloc_cell();
                let label_reference = FrameReference(label_cell, 0, ReferenceType::Monad);
                let label_action    = label_binding(label_reference);
                bindings.symbols.insert(atom_id, SafasCell::Syntax(Box::new(label_action), label_reference.into()).into());
                bindings.export(atom_id);
                // Result is just the atom as for the main binding function
                let result = SafasCell::list_with_cells(iter::once(SafasCell::Atom(atom_id).into()));
                (bindings, result)
            })
        }).map(|value| {
            let value = value.clone();
            // Compiling function: labels bind themselves to a monad that allocates/retrieves the label value at the start of the code block and just bind to the label value later on 
            let compiler = |value: CellRef| -> Result<_, BindError> {
                // Results of the bindings is the cell reference
                let ListTuple((label_action, default_label_value_fn, label_value_expr)): ListTuple<(CellRef, CellRef, CellRef)> = value.clone().try_into()?;
                // The label should be bound to a syntax item, with the frame cell as the parameter
                let cell_reference = match &*label_action { SafasCell::Syntax(_, cell_reference) => Ok(cell_reference.clone()), _ => Err(BindError::MissingArgument) }?;
                // Fetch out the frame reference
                let (cell_id, frame_num, _) = cell_reference.frame_reference().ok_or(BindError::MissingArgument)?;
                if frame_num != 0 { return Err(BindError::CannotLoadCellInOtherFrame); }
                // Start generating the actions
                let mut actions = CompiledActions::empty();
                // Frame setup allocates the label. We use the cell ID as the label ID for updating it later
                actions.frame_setup.extend(vec![
                    Action::Value(ALLOC_LABEL.clone()),
                    Action::Push,
                    Action::Value(WRAP_VALUE.clone()),
                    Action::FlatMap,
                    Action::StoreCell(cell_id)
                ]);
                // Evaluate the value calculation
                let mut value_reference_type = default_label_value_fn.reference_type();
                if default_label_value_fn.is_nil() {
                    // Read the current bit position
                    value_reference_type = ReferenceType::ReturnsMonad;
                    actions.actions.extend(vec![
                        Action::Value(READ_BIT_POS.clone()),
                    ])
                } else {
                    // Calculate a value
                    if value_reference_type == ReferenceType::Value {
                        // Create the bit_pos monad on the stack
                        actions.actions.extend(vec![
                            // Bit_pos monad
                            Action::PushValue(READ_BIT_POS.clone()),
                            Action::PushValue(NIL.clone()),
                            Action::PopCall(1),
                            Action::Push,
                            // Function conversion routine (we call this to generate a flatmap method, then call flatmap on the monad we just created)
                            Action::PushValue(MAP_TO_FLAT_MAP.clone())
                        ])
                    }
                    // Get the value of the label_value function
                    actions.extend(compile_statement(default_label_value_fn)?);
                }
                // Map the value reference type
                match value_reference_type {
                    ReferenceType::Value        => actions.actions.extend(vec![Action::Push, Action::PopCall(1), Action::FlatMap]),
                    ReferenceType::ReturnsMonad => actions.actions.extend(vec![Action::Push, Action::PushValue(NIL.clone()), Action::PopCall(1)]),
                    ReferenceType::Monad        => { }
                }
                // To evaluate the label syntax itself, we fetch the label and flat_map via SET_LABEL_VALUE
                actions.actions.extend(vec![
                    // Push the monad containing the label value
                    Action::Push,
                    // Call the closure that generates the set_label_value function from the cell value monad
                    Action::PushValue(CREATE_SET_LABEL_VALUE.clone()),
                    Action::PushCell(cell_id),
                    Action::PopCall(1),
                    // FlatMap the result with the label value monad we pushed earlier
                    Action::FlatMap
                ]);
                Ok(actions)
            };
            SyntaxCompiler::with_compiler_and_reftype(compiler, value, ReferenceType::Monad)
        });
    WithReferenceType(bind, ReferenceType::Monad)
}
pub fn label_keyword ( ) -> impl BindingMonad < Binding = SyntaxCompiler > { // Binding function. Labels are pre-bound so they're available throughout the current context let bind = get_expression_arguments ( ) . and_then ( | ListWithTail ( ( AtomId ( atom_id ) , ) , optional_value ) : ListWithTail < ( AtomId , ) , CellRef > | { // The optional argument can either not be supplied or specify the label value expression let label_value_expr = if optional_value . is_nil ( ) { // Argument not supplied Ok ( None ) } else { //  let value = ListTuple :: < ( CellRef , ) > :: try_from ( optional_value ) ; value . map ( | ListTuple ( ( value , ) ) | Some ( value ) ) } ; BindingFn ( move | bindings | { // If a value expression is specified, fetch its value let label_value_expr = match label_value_expr { Ok ( ref value ) => value . clone ( ) , Err ( ref err ) => return ( bindings , Err ( err . clone ( ) . into ( ) ) ) } ; // Compile the value expression if there is one let label_value_and_bindings = match label_value_expr { None => Ok ( ( NIL . clone ( ) , bindings ) ) , Some ( label_value_expr ) => bind_statement ( label_value_expr , bindings ) } ; let ( bindings , label_value_expr ) = match label_value_and_bindings { Ok ( ( value , bindings ) ) => ( bindings , value ) , Err ( ( err , bindings ) ) => return ( bindings , Err ( err ) ) } ; // Fetch the label value function (we use this if no expression is specified) let mut bindings = bindings ; let label_value_fn = if let Some ( label_value ) = bindings . look_up_and_import ( * LABEL_VALUE_FUNCTION ) { label_value } else { NIL . clone ( ) } ; // Fetch the value assigned to the atom that represents the label let reference = bindings . look_up ( atom_id ) ; let reference = match reference { Some ( ( reference , 0 ) ) => reference . clone ( ) , _ => return ( bindings , Err ( BindError :: UnknownSymbol ( name_for_atom_with_id ( atom_id ) ) ) ) } ; // TODO: check that we've got the reference we allocated in the pre-binding (if it's been rebound the label is invalid) let result = SafasCell :: list_with_cells ( vec ! [ reference into ( ) label_value_fn label_value_expr ] ) ; ( bindings , Ok ( result ) ) } , move | mut bindings | { // TODO: the label can only be pre-bound once: check that the value has not already been bound // Labels are bound to their own syntax item, which reads the label value when used let label_cell = bindings . alloc_cell ( ) ; let label_reference = FrameReference ( label_cell , 0 , ReferenceType :: Monad ) ; let label_action = label_binding ( label_reference ) ; bindings . symbols . insert ( atom_id , SafasCell :: Syntax ( Box :: new ( label_action ) , label_reference . into ( ) ) . into ( ) ) ; bindings . export ( atom_id ) ; // Result is just the atom as for the main binding function let result = SafasCell :: list_with_cells ( iter :: once ( SafasCell :: Atom ( atom_id ) . into ( ) ) ) ; ( bindings , result ) } ) } ) . map ( | value | { let value = value . clone ( ) ; // Compiling function: labels bind themselves to a monad that allocates/retrieves the label value at the start of the code block and just bind to the label value later on  let compiler = | value : CellRef | -> Result < _ , BindError > { // Results of the bindings is the cell reference let ListTuple ( ( label_action , default_label_value_fn , label_value_expr ) ) : ListTuple < ( CellRef , CellRef , CellRef ) > = value . clone ( ) . try_into ( ) ? ; // The label should be bound to a syntax item, with the frame cell as the parameter let cell_reference = match & * label_action { SafasCell :: Syntax ( _ , cell_reference ) => Ok ( cell_reference . clone ( ) ) , _ => Err ( BindError :: MissingArgument ) } ? ; // Fetch out the frame reference let ( cell_id , frame_num , _ ) = cell_reference . frame_reference ( ) . ok_or ( BindError :: MissingArgument ) ? ; if frame_num != 0 { return Err ( BindError :: CannotLoadCellInOtherFrame ) ; } // Start generating the actions let mut actions = CompiledActions :: empty ( ) ; // Frame setup allocates the label. We use the cell ID as the label ID for updating it later actions . frame_setup . extend ( vec ! [ Action Value ( ALLOC_LABEL clone ( ) ) Action Push Action Value ( WRAP_VALUE clone ( ) ) Action FlatMap Action StoreCell ( cell_id ) ] ) ; // Evaluate the value calculation let mut value_reference_type = default_label_value_fn . reference_type ( ) ; if default_label_value_fn . is_nil ( ) { // Read the current bit position value_reference_type = ReferenceType :: ReturnsMonad ; actions . actions . extend ( vec ! [ Action Value ( READ_BIT_POS clone ( ) ) ] ) } else { // Calculate a value if value_reference_type == ReferenceType :: Value { // Create the bit_pos monad on the stack actions . actions . extend ( vec ! [ // Bit_pos monad Action PushValue ( READ_BIT_POS clone ( ) ) Action PushValue ( NIL clone ( ) ) Action PopCall ( 1 ) Action Push // Function conversion routine (we call this to generate a flatmap method, then call flatmap on the monad we just created) Action PushValue ( MAP_TO_FLAT_MAP clone ( ) ) ] ) } // Get the value of the label_value function actions . extend ( compile_statement ( default_label_value_fn ) ? ) ; } // Map the value reference type match value_reference_type { ReferenceType :: Value => actions . actions . extend ( vec ! [ Action Push Action PopCall ( 1 ) Action FlatMap ] ) , ReferenceType :: ReturnsMonad => actions . actions . extend ( vec ! [ Action Push Action PushValue ( NIL clone ( ) ) Action PopCall ( 1 ) ] ) , ReferenceType :: Monad => { } } // To evaluate the label syntax itself, we fetch the label and flat_map via SET_LABEL_VALUE actions . actions . extend ( vec ! [ // Push the monad containing the label value Action Push // Call the closure that generates the set_label_value function from the cell value monad Action PushValue ( CREATE_SET_LABEL_VALUE clone ( ) ) Action PushCell ( cell_id ) Action PopCall ( 1 ) // FlatMap the result with the label value monad we pushed earlier Action FlatMap ] ) ; Ok ( actions ) } ; SyntaxCompiler :: with_compiler_and_reftype ( compiler , value , ReferenceType :: Monad ) } ) ; WithReferenceType ( bind , ReferenceType :: Monad ) }
The `label` keyword creates a bitcode monad that specifies a label
`(label foo)` - declares a label that binds to the value of the `label_value` function at
the point the label is declared (or the current bit position if no label_value function
is availble).
The ` label ` keyword creates a bitcode monad that specifies a label ` ( label foo ) ` - declares a label that binds to the value of the ` label_value ` function at the point the label is declared ( or the current bit position if no label_value function is availble ) .