PreviousUpNext

15.4.842  src/lib/reactive/reactive.pkg

## reactive.pkg

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

# A simple ractive engine modelled after RC and SugarCubes.


package   reactive
: (weak)  Reactive                      # Reactive      is from   src/lib/reactive/reactive.api
{
    package i=  instruction;            # instruction   is from   src/lib/reactive/instruction.pkg
    package m=  machine;                # machine       is from   src/lib/reactive/machine.pkg

    Machine     =  m::Machine;
    Instruction =  instruction::Instr( Machine );

    Signal =  i::Signal;
    Config =  i::Config( i::Signal );

    In_Signal  =  m::In_Signal;
    Out_Signal =  m::Out_Signal;

    package amap =  quickstring_binary_map;         # Used to bind internal signal names 

    exception UNBOUND_SIGNAL  i::Signal;

    fun machine { inputs, outputs, body }
        =
        {   next_id  =  REF 0;
            signal_list =  REF [];

            fun new_signal s
                =
                {   id = *next_id;

                    s' = m::SIGNAL { name=>s, id, state => REF 0 };

                    next_id  :=  id+1;
                    signal_list :=  s' ! *signal_list;

                    s';
                };

            fun bind_signal (dictionary, s)
                =
                case (amap::get (dictionary, s))
                  
                    NULL   =>   raise exception UNBOUND_SIGNAL s;
                    THE s' =>   s';
                esac;


            fun trans (instruction, dictionary)
                =
                case instruction
                  
                    i::OR  (i1, i2) =>  m::(|||) (trans (i1, dictionary), trans (i2, dictionary));
                    i::AND (i1, i2) =>  m::(&&&) (trans (i1, dictionary), trans (i2, dictionary));

                    i::NOTHING    =>  m::nothing;
                    i::STOP       =>  m::stop ();
                    i::SUSPEND    =>  m::suspend ();
                    i::ACTION act =>  m::action act;
                    i::EXEC f     =>  m::exec f;

                    i::IF_THEN_ELSE (prior, i1, i2)
                        =>
                        m::if_then_else (prior, trans (i1, dictionary), trans (i2, dictionary));

                    i::REPEAT (count, i) =>  m::repeat (count, trans (i, dictionary));
                    i::LOOP i          =>  m::loop (trans (i, dictionary));
                    i::CLOSE i         =>  m::close (trans (i, dictionary));

                    i::SIGNAL (s, i)
                        =>
                        trans (i, amap::set (dictionary, s, new_signal s));

                    i::REBIND (s1, s2, i)
                        =>
                        trans (i, amap::set (dictionary, s2, bind_signal (dictionary, s1)));

                    i::EMIT s    =>   m::emit (bind_signal (dictionary, s));
                    i::AWAIT mcg =>   m::await (trans_config (mcg, dictionary));

                    i::WHEN (mcg, i1, i2)
                        =>
                        m::when (trans_config (mcg, dictionary), trans (i1, dictionary), trans (i2, dictionary));

                    i::TRAP_WITH (mcg, i1, i2)
                        =>
                        m::trap_with (trans_config (mcg, dictionary), trans (i1, dictionary), trans (i2, dictionary));
                esac


            also
            fun trans_config (mcg, dictionary)
                =
                trans_cfg mcg
                where 

                    fun trans_cfg (i::POS_CONFIG s) =>  i::POS_CONFIG (bind_signal (dictionary, s));
                        trans_cfg (i::NEG_CONFIG s) =>  i::NEG_CONFIG (bind_signal (dictionary, s));

                        trans_cfg (i::OR_CONFIG (cfg1, cfg2))
                            =>
                            i::OR_CONFIG (trans_cfg cfg1, trans_cfg cfg2);

                        trans_cfg (i::AND_CONFIG (cfg1, cfg2))
                            =>
                            i::AND_CONFIG (trans_cfg cfg1, trans_cfg cfg2);
                    end;
                end;

            inputs'  =  list::map new_signal  inputs;
            outputs' =  list::map new_signal  outputs;

            fun ins (s as m::SIGNAL { name, ... }, dictionary)
                =
                amap::set (dictionary, name, s);

            initial_dictionary
                =
                list::fold_forward ins (list::fold_forward ins amap::empty inputs') outputs';

            body' = trans (body, initial_dictionary);
          
            m::MACHINE {
                now            =>  REF 0,
                move_flag      =>  REF FALSE,
                end_of_instant =>  REF FALSE,

                program =>  body',
                signals =>  *signal_list,

                inputs  =>  inputs',
                outputs =>  outputs'
            };
        };

    run   =  m::run_machine;
    reset =  m::reset_machine;

    inputs_of  =  m::inputs_of;
    outputs_of =  m::outputs_of;

    input_signal  =  m::input_signal;
    output_signal =  m::output_signal;
    set_in_signal =  m::set_in_signal;

    get_in_signal  =  m::get_in_signal;
    get_out_signal =  m::get_out_signal;

    pos_config =  i::POS_CONFIG;
    neg_config =  i::NEG_CONFIG;

    or_config  =  i::OR_CONFIG;
    and_config =  i::AND_CONFIG;

    my |||   = i::OR;
    my &&&   = i::AND;
    nothing = i::NOTHING;
    stop    = i::STOP;
    suspend = i::SUSPEND;
    action  = i::ACTION;
    exec    = i::EXEC;
    if_then_else = i::IF_THEN_ELSE;
    repeat = i::REPEAT;
    loop   = i::LOOP;
    close  = i::CLOSE;
    signal = i::SIGNAL;
    rebind = i::REBIND;
    when   = i::WHEN;
    trap_with = i::TRAP_WITH;
    emit  = i::EMIT;
    await = i::AWAIT;

    fun trap (c, i)
        =
        i::TRAP_WITH (c, i, i::NOTHING);

};


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext