Unassignable-ABCDXYZ equivalency proof

Converting ABCDXYZ to ≠ is trivial. Below is a way to convert :≠ to ABCDXYZ.

For each object in a :≠ program, there are three things to do:


 * Replace its declaration with one that declares just  object(s).
 * Replace its definition with definitions for each new  object.
 * Replace method calls on it with ones on the new  object(s).

Once this is done, it is trivial to convert to ABCDXYZ... nearly.



And  is converted into.

Types
Each type will be dealt with separately:


 * -- made up name for 's type
 * -- new type to help convert s (see below)
 * -- made up name for 's type
 * -- new type to help convert s (see below)
 * -- new type to help convert s (see below)

(Names starting with  are reserved for use of the implementation. Here, the prefix   is used for new types and prefix   for new objects.)

Nothing to do.

Cannot declare anything of this type.

Let f be a  object. Then:

Declarations

function f = activated;      ==>   ABCD unao_fun_f = B; function f = deactivated;     ==>   ABCD unao_fun_f = C;

Definition

f { run { statements } }     ==>   unao_fun_f { event { statements } }

Method calls

f -> activate;               ==>   unao_fun_f -> Z; f -> deactivate;              ==>   unao_fun_f -> Y; f -> call;                    ==>   unao_fun_f -> X, Z;

(Note:  is shorthand for  .)

A  is a one-bit , with the following methods:

bit->toggle;     Toggle bit. bit->increment;  Toggle bit. If it becomes clear, run the carry event. bit->decrement;  Toggle bit. If it becomes set, run the borrow event. bit->loop;       Run the iterate event. bit->loopifset;  If currently set, run the iterateifset event.

A  is implemented with 4 ABCD objects, named (poorly and unimaginatively) a, b, c, and d:

a handles the  event. b handles the  event. c handles the  event. d handles the  event.

a, b and d's values are updated in tandem when the bit is toggled (c stays in state B).

Declarations

unat_bit bit = init;

becomes (A_or_C = A if init==set, C if init==clear):

ABCD unao_bita_bit = A_or_C; ABCD unao_bitb_bit = A_or_C; ABCD unao_bitc_bit = B; ABCD unao_bitd_bit = A_or_C;

Definitions

bit { carry       { stmts_carry } borrow      { stmts_borrow } iterate     { stmts_iterate } iterateifset { stmts_iterateifset } }

becomes

unao_bita_bit { event { stmts_carry  } } unao_bitb_bit { event { stmts_borrow  } } unao_bitc_bit { event { stmts_iterate  } } unao_bitd_bit { event { stmts_iterateifset } }

Method calls

bit->toggle   ==> unao_bita_bit->X, Y; unao_bitb_bit->X, Y; unao_bitd_bit->X, Y; bit->increment ==> unao_bita_bit->X, X; unao_bitb_bit->X, Y; unao_bitd_bit->X, Y; bit->decrement ==> unao_bita_bit->X, Y; unao_bitb_bit->Y, Y; unao_bitd_bit->X, Y; bit->loop      ==> unao_bitc_bit->X, Z; bit->loopifset ==> unao_bitd_bit->X, X, X, Y;

Let x be an  object. First, it is converted into individual, which can be converted into  s as above.

Declaration

integer x(max) = init;

is converted to

unat_bit unao_i0_x = init0 unat_bit unao_i1_x = init1 unat_bit unao_i2_x = init2 unat_bit unao_i3_x = init3 ... unat_bit unao_i(n-1)_x = init(n-1) (where n is number of bits in max, and initk is kth bit of init.)

Definition

x { overflow { stmts_overflow } underflow { stmts_underflow } iterate  { stmts_iterate } }

is converted to

unao_i0_x { carry       { unao_i1_x->increment; } borrow      { unao_i1_x->decrement; } iterate     { stmts_iterate } iterateifset { stmts_iterate } } unao_i1_x { carry       { unao_i2_x->increment; } borrow      { unao_i2_x->decrement; } iterate     { unao_i0_x->loop, loop; } iterateifset { unao_i0_x->loop, loop; } } ... unao_ik_x { carry       { unao_i(k+1)_x->increment; } borrow      { unao_i(k+1)_x->decrement; } iterate     { unao_i(k-1)_x->loop, loop; } iterateifset { unao_i(k-1)_x->loop, loop; } } ... unao_i(n-2)_x { carry       { unao_i(n-1)_x->increment; } borrow      { unao_i(n-1)_x->decrement; } iterate     { unao_i(n-3)_x->loop, loop; } iterateifset { unao_i(n-3)_x->loop, loop; } } unao_i(n-1)_x { carry       { stmts_overflow } borrow      { stmts_underflow } iterate     { unao_i(n-2)_x->loop, loop; } iterateifset { unao_i(n-2)_x->loop, loop; } }

Method calls

x -> increment(r); x -> decrement(r);

become (where r = 2 ** k)

unao_ik_x -> increment; unao_ik_x -> decrement;

and

x -> loop;

becomes

unao_i0_x -> loopifset; unao_i1_x -> loopifset; unao_i2_x -> loopifset; ... unao_i(n-1)_x -> loopifset;

How does all this work?

When ing/ ing x, it  s/ s the bit required, and if there is a carry/borrow, the next highest bit is  ed/ ed. ing on x will  on each of its bits. Each set bit k of x then performs x.iterate 2 ** k times, by ing the next-lower-order bit twice.

Example

Say x = 6 (dec) = 0110 (bin). So

x -> loop;

becomes

unao_i0_x -> loopifset; unao_i1_x -> loopifset; unao_i2_x -> loopifset; unao_i3_x -> loopifset;

The 0th  does nothing. The 1st  runs x.iterate 2 times. The 2nd  runs x.iterate 4 times. The 3rd  does nothing.

In all, x.iterate is run 6 times.