BadVPN – Rev 1

Subversion Repositories:
Rev:
process main {
    # Turing machine specification.
    var("B") blank;
    var([
        {"0", "0"}:{"0", "0", "right"},
        {"0", "1"}:{"1", "x", "right"},
        {"1", "1"}:{"1", "1", "right"},
        {"1", "0"}:{"2", "0", "right"},
        {"2", "0"}:{"2", "0", "right"},
        {"2", "1"}:{"3", "1", "right"},
        {"3", "1"}:{"3", "1", "right"},
        {"3", "0"}:{"4", "1", "left"},
        {"3", "B"}:{"4", "1", "left"},
        {"4", "1"}:{"4", "1", "left"},
        {"4", "0"}:{"5", "0", "left"},
        {"5", "0"}:{"5", "0", "left"},
        {"5", "1"}:{"6", "1", "left"},
        {"5", "x"}:{"h", "x", "stay"},
        {"6", "1"}:{"6", "1", "left"},
        {"6", "x"}:{"0", "x", "right"},
        {"6", "0"}:{"0", "0", "right"}
    ]) rules;
    var("0") initial_state;
    var({}) initial_tape_left;
    var({
        "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
        "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
        "0", "0",
        "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
        "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"
    }) initial_tape_right;

    # Perform the computation, stopping when no rule matches.
    call("turing", {blank, rules, initial_state, initial_tape_left, initial_tape_right}) results;

    # Check results.

    val_equal(results.tape_left, {"B"}) a;
    assert(a);

    val_equal(results.tape_right,
        {"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
         "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
         "0", "0", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
         "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
         "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
         "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
         "1", "1"}
    ) a;
    assert(a);

    val_equal({results.side, results.pos}, {"right", "55"}) a;
    assert(a);

    val_equal(results.state, "h") a;
    assert(a);

    exit("0");
}

template turing {
    alias("_arg0") blank;
    value(_arg1) rules;
    alias("_arg2") initial_state;
    alias("_arg3") initial_tape_left;
    alias("_arg4") initial_tape_right;

    # Head state.
    var(initial_state) state;

    # Tape. Positions go like this: ... L2 L1 L0 R0 R1 R2 ... 
    value(initial_tape_left) tape_left;
    value(initial_tape_right) tape_right;

    # Make sure each side of the tape has at least one symbol so we can flip easily.
    tape_left->insert(tape_left.length, blank);
    tape_right->insert(tape_right.length, blank);

    # Head position.
    var("right") side;
    var("0") pos;

    # Enter loop.
    blocker() loop_blk;
    loop_blk->up();
    loop_blk->use();

    # Get symbol under head.
    concat("tape_", side) tape_name;
    alias(tape_name) cur_tape;
    cur_tape->get(pos) symbol;

    # Look for a matching rule.
    rules->try_get({state, symbol}) rule;

    If (rule.exists) {
        # Extract directions from rule.
        rule->get("0") new_state;
        rule->get("1") new_symbol;
        rule->get("2") move;

        # Change head state.
        state->set(new_state);

        # Replace symbol under head.
        cur_tape->remove(pos);
        cur_tape->insert(pos, new_symbol);

        # Branch based on how we move.
        strcmp(move, side) is_outside;
        strcmp(move, "stay") is_stay;
        strcmp(pos, "0") is_zero;
        If (is_outside) {
            # Increment position.
            num_add(pos, "1") new_pos;
            pos->set(new_pos);

            # If the new position is out of range, extend tape.
            strcmp(pos, cur_tape.length) need_extend;
            If (need_extend) {
                cur_tape->insert(pos, blank);
            };
        } elif (is_stay) {
            # Nop.
            getargs();
        } elif (is_zero) {
            # Flip side, leave pos at zero.
            side->set(move);
        } else {
            # Decrement position.
            num_subtract(pos, "1") new_pos;
            pos->set(new_pos);
        };

        # Continue loop.
        loop_blk->downup();
    };
}