PreviousUpNext

15.4.850  src/lib/reactive/machine.pkg

## machine.pkg

# Compiled by:
#     src/lib/reactive/reactive.lib

# This is an implementation of the reactive interpreter instructions,
# and functions to generate them.

package machine: (weak)
api {


    State = TERM | STOP | SUSP;

        # Activation return codes: 
        #
        # TERM: Execution of the instruction is complete.
        #       Activation at future instances has no effect.
        
        # STOP: Execution is stopped in this instant,
        #       but could progress in the next instant.
        
        # SUSP: Execution is suspended and must be resumed
        #       during this instant.


    In_Signal;
    Out_Signal;

    Instant = Int;

    Signal_State = Ref( Instant );

    Signal =  SIGNAL  {
                  name:  quickstring__premicrothread::Quickstring,
                  id:    Int,
                  state: Signal_State
              };

    Machine = MACHINE  {
                  now:             Ref( Instant ),
                  move_flag:       Ref( Bool ),
                  end_of_instant:  Ref( Bool ),

                  program:         Code,

                  signals:         List( Signal ),
                  inputs:          List( Signal ),
                  outputs:         List( Signal )
                }

    also
    Code =  CODE {
                is_term:         Void -> Bool,
                terminate:       Void -> Void,
                reset:           Void -> Void,
                preempt:         Machine -> Void,
                activation:      Machine -> State
            };

    run_machine:    Machine -> Bool;
    reset_machine:  Machine -> Void;
    inputs_of:      Machine -> List( In_Signal );
    outputs_of:     Machine -> List( Out_Signal );

    input_signal:   In_Signal  -> quickstring__premicrothread::Quickstring;
    output_signal:  Out_Signal -> quickstring__premicrothread::Quickstring;

    set_in_signal:  ((In_Signal, Bool)) -> Void;

    get_in_signal:  In_Signal  -> Bool;
    get_out_signal: Out_Signal -> Bool;

    Config;

    ||| : ((Code, Code)) -> Code;
    &&& : ((Code, Code)) -> Code;

    nothing:  Code;
    stop:  Void -> Code;
    suspend:  Void -> Code;
    action:  (Machine -> Void) -> Code;
    exec:    (Machine -> { stop:  Void -> Void, done:  Void -> Bool } ) -> Code;
    if_then_else:  (((Machine -> Bool), Code, Code)) -> Code;
    repeat:      ((Int, Code)) -> Code;
    loop:        Code -> Code;
    close:       Code -> Code;
    emit:        Signal -> Code;
    await:       Config -> Code;
    when:        ((Config, Code, Code)) -> Code;
    trap_with:    ((Config, Code, Code)) -> Code;

}
{

    package i = instruction;            #  For the config type. 

    State
        = TERM
        | STOP
        | SUSP;

    Instant =  Int;

    Signal_State =  Ref( Instant );

    Signal = SIGNAL {
                 name:  quickstring__premicrothread::Quickstring,
                 id:    Int,
                 state: Signal_State
             };

    Config = i::Config( Signal );

    Machine = MACHINE  {
        now:            Ref( Instant ),
        move_flag:      Ref( Bool ),
        end_of_instant: Ref( Bool ),
        program:        Code,
        signals:        List( Signal ),
        inputs:         List( Signal ),
        outputs:        List( Signal )
      }

    also
    Code = CODE  {
               is_term:     Void -> Bool,
               terminate:   Void -> Void,
               reset:       Void -> Void,
               preempt:     Machine -> Void,
               activation:  Machine -> State
           };


    fun now               (MACHINE m) =  *m.now;
    fun new_move          (MACHINE m) =   m.move_flag := TRUE;
    fun is_end_of_instant (MACHINE m) =  *m.end_of_instant;

    Presence = PRESENT | ABSENT | UNKNOWN;

    fun presence (m, SIGNAL s)
        =
        {   ts  =  *s.state;
            now =  now m;
          
            if   (now == ts)
                 PRESENT;
            else
                 if  (now == -ts  or
                      is_end_of_instant m)

                      ABSENT;
                 else
                      UNKNOWN;
                 fi;
            fi;
        };

    fun present (m, SIGNAL s) =   now m ==   *s.state;
    fun absent  (m, SIGNAL s) =   now m == -(*s.state);

    fun put_sig (m, SIGNAL s) =   s.state :=    now m;
    fun put_not (m, SIGNAL s) =   s.state :=  -(now m);

    In_Signal  = IN   ((Machine, Signal));
    Out_Signal = OUT  ((Machine, Signal));

    fun input_signal  (IN (_, SIGNAL s)) =   s.name;
    fun output_signal (OUT(_, SIGNAL s)) =   s.name;

    fun set_in_signal (IN (m, s), FALSE) =>   put_not (m, s);
        set_in_signal (IN (m, s), TRUE ) =>   put_sig (m, s);
    end;

    fun get_in_signal  (IN  (m, s)) =   present (m, s);
    fun get_out_signal (OUT (m, s)) =   present (m, s);

    fun terminate  (CODE c   ) =   c.terminate ();
    fun is_term    (CODE c   ) =   c.is_term   ();
    fun reset      (CODE c   ) =   c.reset     ();
    fun preemption (CODE c, m) =   c.preempt    m;
    fun activation (CODE c, m) =   c.activation m;

    fun activate (i, m)
        =
        if  (is_term i)
             TERM;
        else
             case (activation  (i, m))
               
                  TERM   =>  { terminate i;   TERM; };
                  result =>  result;
             esac;
        fi;

    fun preempt (i, m)
        =
        if   (not (is_term i))
             preemption (i, m);
             terminate i;
        fi;

    # Default instruction methods:
    fun is_term_meth   term_flag () =  *term_flag;
    fun terminate_meth term_flag () =   term_flag := TRUE;
    fun reset_meth     term_flag () =   term_flag := FALSE;

    fun ||| (i1, i2)
        =
        {
            term_flag  = REF FALSE;

            left_sts  = REF SUSP;       # "sts" may be "status"
            right_sts = REF SUSP;

            fun reset_meth ()
                =
                {   term_flag := FALSE;

                    left_sts  := SUSP;
                    right_sts := SUSP;

                    reset i1;
                    reset i2;
                };

            fun preempt_meth m
                =
                {   preempt (i1, m);
                    preempt (i2, m);
                };

            fun activation_meth m
                =
                {   if (*left_sts  == SUSP)  left_sts  := activate (i1, m); fi;
                    if (*right_sts == SUSP)  right_sts := activate (i2, m); fi;

                    case (*left_sts, *right_sts)
                      
                         (TERM, TERM) =>  TERM;
                         (SUSP, _)    =>  SUSP;
                         (_, SUSP)    =>  SUSP;
                         _            =>  {   left_sts  := SUSP;
                                              right_sts := SUSP;
                                              STOP;
                                          };
                    esac;
                };

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };

    fun &&& (i1, i2)
        =
        {   term_flag = REF FALSE;

            fun reset_meth ()
                =
                {   term_flag := FALSE;

                    reset i1;
                    reset i2;
                };

            fun preempt_meth m
                =
                {   preempt (i1, m);
                    preempt (i2, m);
                };

            fun activation_meth m
                =
                if  (is_term  i1)
                     activate (i2, m);
                else
                     case (activate (i1, m))
                          TERM   =>  activate (i2, m);
                          result =>  result;
                     esac;
                fi;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
              };
        };

    nothing = CODE {
            is_term     =>  \\ () =  TRUE,
            terminate   =>  \\ () =  (),
            reset       =>  \\ () =  (),
            preempt     =>  \\ _  =  (),
            activation  =>  \\ _  =  TERM
          };

    fun stop ()
        =
        {   term_flag =  REF FALSE;
          
            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth     term_flag,
                preempt         => \\ _ =  (),
                activation      => \\ _ =  STOP
            };
        };

    fun suspend ()
        =
        {   term_flag = REF FALSE;
          
            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth     term_flag,
                preempt         => \\ _ =  (),
                activation      => \\ _ =  {   term_flag := TRUE;   STOP;  }
              };
          };

    fun action f
        =
        {   term_flag =  REF FALSE;
          
            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth     term_flag,
                preempt         => \\ _ =  (),
                activation      => \\ m =  {   f m;   TERM;   }
            };
        };

    fun exec f
        =
        {   term_flag =  REF FALSE;

            ops =  REF (NULL:   Null_Or { stop:  Void -> Void, done:  Void -> Bool } );

            # NOTE: what if a reset occurs while we are running?
            # We would need to change the type of reset_meth
            # to take a machine parameter.

            fun reset_meth ()
                =
                term_flag := FALSE;

            fun preempt_meth m
                =
                case *ops
                  
                     NULL  => ();
                     THE a => {   ops := NULL;   a.stop ();  };
                esac;

            fun activation_meth m
                =
                case *ops
                  
                     THE a
                         =>
                         if   (a.done ()   )   ops := NULL;   TERM;
                                          else                  STOP;   fi;
                     NULL
                         =>
                         {   ops := THE (f m);   SUSP;   };
                esac;
          
            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };

    fun if_then_else (prior, i1, i2)
        =
        {
            term_flag =  REF FALSE;
            cond     =  REF NULL;

            fun reset_meth ()
                =
                {   term_flag := FALSE;

                    case *cond
                      
                         THE TRUE  =>  reset i1;
                         THE FALSE =>  reset i2;
                         NULL      =>  ();
                    esac;

                    cond := NULL;
                };

            fun preempt_meth m
                =
                case *cond
                  
                     THE TRUE  =>  preempt (i1, m);
                     THE FALSE =>  preempt (i2, m);
                     NULL      =>  ();
                esac;


            fun activation_meth m
                =
                case *cond
                  
                     THE TRUE  =>  activate (i1, m);
                     THE FALSE =>  activate (i2, m);

                     NULL
                         =>
                         {   b = prior m;

                             cond := THE b;

                             if   b      activate (i1, m);
                                      else   activate (i2, m);   fi;
                         };
                esac;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };

    fun repeat (n, i)
        =
        {   term_flag = REF FALSE;
            counter  = REF n;

            fun reset_meth ()
                =
                {   term_flag := FALSE;
                    counter  := n;
                };

            fun preempt_meth m
                =
                preempt (i, m);

            fun activation_meth m
                =
                if   (*counter > 0)

                     case (activate (i, m))
                       
                          TERM
                              =>
                              {   counter := *counter - 1;
                                  reset i;
                                  TERM;
                              };

                          result =>  result;
                     esac;
                else
                     TERM;
                fi;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
              };
        };

    fun loop i
        =
        {   term_flag    =  REF FALSE;
            end_reached =  REF FALSE;

            fun reset_meth ()
                =
                {   term_flag    := FALSE;
                    end_reached := FALSE;
                };

            fun preempt_meth m
                =
                preempt (i, m);

            fun activation_meth m
                =
                case (activate (i, m))
                  
                   STOP => {   end_reached := FALSE;   STOP;  };
                   SUSP => SUSP;
                   TERM
                       =>
                       if   *end_reached

#                             say (m, "instantaneous loop detected\n"); 
                            STOP;
                       else
                            end_reached := TRUE;
                            reset i;
                            TERM;
                       fi;
                esac;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };

    fun close i
        =
        {   term_flag =  REF FALSE;

            fun activation_meth m
                =
                case (activate (i, m))
                  
                     SUSP   =>  activation_meth m;
                     result =>  result;
                esac;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth term_flag,
                preempt         => \\ _ =  (),
                activation      => activation_meth
            };
        };

    # Configuration evaluation
    fun fixed (m, c)
        =
        fix c
        where 

            fun fix (i::POS_CONFIG id) =>  (presence (m, id) != UNKNOWN);
                fix (i::NEG_CONFIG id) =>  (presence (m, id) != UNKNOWN);

                fix (i::OR_CONFIG (c1, c2))
                    =>
                    {   b1 = fix c1;
                        b2 = fix c2;

                        (b1 and evaluate (m, c1)) or
                        (b2 and evaluate (m, c2)) or
                        (b1 and b2);
                    };

                fix (i::AND_CONFIG (c1, c2))
                    =>
                    {
                        b1 = fix c1;
                        b2 = fix c2;

                        (b1 and not (evaluate (m, c1))) or
                        (b2 and not (evaluate (m, c2))) or
                        (b1 and b2);
                    };
            end;
          
          end

    also
    fun evaluate (m, c)
         =
         evaluate c
         where 

             fun evaluate (i::POS_CONFIG id)       =>        present (m, id);
                 evaluate (i::NEG_CONFIG id)       =>   not (present (m, id));

                 evaluate (i::OR_CONFIG  (c1, c2)) =>   evaluate c1  or   evaluate c2;
                 evaluate (i::AND_CONFIG (c1, c2)) =>   evaluate c1  and  evaluate c2;
             end;
         end;

    fun fixed_eval (m, c)
        =
        f c
        where 

            fun f (i::POS_CONFIG id)
                    =>
                    case (presence (m, id))
                      
                         UNKNOWN => NULL;
                         PRESENT => THE TRUE;
                         ABSENT  => THE FALSE;
                    esac;

                f (i::NEG_CONFIG id)
                    =>
                    case (presence (m, id))
                      
                         UNKNOWN =>  NULL;
                         PRESENT =>  THE FALSE;
                         ABSENT  =>  THE TRUE;
                    esac;

                f (i::AND_CONFIG (c1, c2))
                    =>
                    case (f c1, f c2)
                      
                         (THE FALSE, _        ) =>  THE FALSE;
                         (_,         THE FALSE) =>  THE FALSE;
                         (THE TRUE,  THE TRUE ) =>  THE TRUE;
                         _                      =>  NULL;
                    esac;


                f (i::OR_CONFIG (c1, c2))
                    =>
                    case (f c1, f c2)
                      
                         (THE TRUE,  _        ) =>  THE TRUE;
                         (_,         THE TRUE ) =>  THE TRUE;
                         (THE FALSE, THE FALSE) =>  THE FALSE;
                         _                      =>  NULL;
                    esac;
            end;
        end;

    fun emit signal
        =
        {   term_flag =  REF FALSE;

            fun activation_meth m
                =
                {   new_move m;
                    put_sig (m, signal);
                    TERM;
                };

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth     term_flag,
                preempt         => \\ _ =  (),
                activation      => activation_meth
            };
        };

    fun await c
        =
        {   term_flag =  REF FALSE;

            fun activation_meth m
                =
                case (fixed_eval (m, c))
                  
                    NULL     =>  SUSP;
                    THE TRUE =>  STOP;

                    THE FALSE
                        =>
                        {   term_flag := TRUE;

                            if   (is_end_of_instant m   )   STOP;
                                                       else   TERM;   fi;
                        };
                esac;


            CODE {
                is_term    =>  is_term_meth   term_flag,
                terminate  =>  terminate_meth term_flag,
                reset      =>  reset_meth     term_flag,
                preempt    =>  \\ _ =  (),
                activation =>  activation_meth
            };
        };

    fun when (c, i1, i2)
        =
        {   term_flag =  REF FALSE;
            value     =  REF NULL;

            fun reset_meth m
                =
                {   term_flag := FALSE;
                    reset i1;
                    reset i2;
                    value := NULL;
                };

            fun preempt_meth m
                =
                {   preempt (i1, m);
                    preempt (i2, m);
                };

            fun activation_meth m
                =
                case *value
                  
                     NULL
                         =>
                         case (fixed_eval (m, c))
                           
                              NULL => SUSP;

                              THE v
                                  =>
                                  {   value := THE v;

                                      if  (is_end_of_instant m)

                                           STOP;
                                      else
                                           if   v      activate (i1, m);
                                                    else   activate (i2, m);   fi;
                                      fi;
                                  };
                         esac;

                     THE TRUE  =>  activate (i1, m);
                     THE FALSE =>  activate (i2, m);
                esac;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };

    fun trap_with (c, i1, i2)
        =
        {   term_flag      =  REF FALSE;
            active_handle =  REF FALSE;
            resume_body   =  REF TRUE;

            fun reset_meth m
                =
                {   term_flag := FALSE;

                    reset i1;
                    reset i2;

                    active_handle := FALSE;
                    resume_body   := TRUE;
                };

            fun preempt_meth m
                =
                if   *active_handle      preempt (i2, m);
                                      else   preempt (i1, m);   fi;

            fun activation_meth m
                =
                if   *active_handle

                     activate (i2, m);
                else
                     fun check_config ()
                         =
                         case (fixed_eval (m, c))
                           
                              NULL => SUSP;

                              THE TRUE
                                  =>
                                  {   #  Actual preemption 
                                      preempt (i1, m);
                                      active_handle := TRUE;

                                      if   (is_end_of_instant m)
                                           STOP;
                                      else
                                           activate (i2, m);
                                      fi;
                                  };

                              THE FALSE
                                  =>
                                  {   resume_body := TRUE;
                                      STOP;
                                  };
                         esac;

                     if   *resume_body

                          case (activate (i1, m))
                               STOP   => {   resume_body := FALSE;   check_config();   };
                               result => result;
                          esac;
                     else
                          check_config();
                     fi;
                fi;

            CODE {
                is_term         => is_term_meth   term_flag,
                terminate       => terminate_meth term_flag,
                reset           => reset_meth,
                preempt         => preempt_meth,
                activation      => activation_meth
            };
        };


    # Run a machine to a stable state.
    # Return TRUE if that is a terminal state 

    fun run_machine (machine as MACHINE m)
        =
        {   fun until_stop ()
                =
                case (activate (m.program, machine))
                  
                     SUSP
                         =>
                         {   if   *m.move_flag      m.move_flag      :=  FALSE;
                                                 else   m.end_of_instant :=  TRUE;   fi;
                             until_stop ();
                         };

                     STOP => FALSE;
                     TERM => TRUE;
                esac;
          
            m.end_of_instant :=  FALSE;
            m.move_flag      :=  FALSE;

            until_stop ()
            then
                m.now := *m.now + 1;
        };


    # Reset a machine back to its initial state 

    fun reset_machine ( MACHINE m )
        =
        {   fun reset_sig (SIGNAL s)
                =
                s.state := 0;
          
            m.now := 1;

            m.move_flag      :=  FALSE;
            m.end_of_instant :=  FALSE;

            reset m.program;

            list::apply  reset_sig  m.signals;
            list::apply  reset_sig  m.inputs;
            list::apply  reset_sig  m.outputs;
        };

    fun inputs_of  (m as MACHINE r) =   list::map  (\\ s =  IN  (m, s))  r.inputs;
    fun outputs_of (m as MACHINE r) =   list::map  (\\ s =  OUT (m, s))  r.inputs;      # Or r.outputs? XXX BUGGO FIXME

};


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext