## 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);
};