2011-11-17 11:46:13 -08:00

309 lines
6.4 KiB
Rust

import std::bitv;
export t;
export create_tritv;
export tritv_clone;
export tritv_set;
export to_vec;
export trit;
export dont_care;
export ttrue;
export tfalse;
export tritv_get;
export tritv_set_all;
export tritv_difference;
export tritv_union;
export tritv_intersect;
export tritv_copy;
export tritv_clear;
export tritv_kill;
export tritv_doesntcare;
export to_str;
/* for a fixed index:
10 = "this constraint may or may not be true after execution"
01 = "this constraint is definitely true"
00 = "this constraint is definitely false"
11 should never appear
FIXME: typestate precondition (uncertain and val must
have the same length; 11 should never appear in a given position)
*/
type t = {uncertain: bitv::t, val: bitv::t, nbits: uint};
tag trit { ttrue; tfalse; dont_care; }
fn create_tritv(len: uint) -> t {
ret {uncertain: bitv::create(len, true),
val: bitv::create(len, false),
nbits: len};
}
fn trit_minus(a: trit, b: trit) -> trit {
/* 2 - anything = 2
1 - 1 = 2
1 - 0 is an error
1 - 2 = 1
0 - 1 is an error
0 - anything else - 0
*/
alt a {
dont_care. { dont_care }
ttrue. {
alt b {
ttrue. { dont_care }
tfalse. { ttrue }
/* internally contradictory, but
I guess it'll get flagged? */
dont_care. {
ttrue
}
}
}
tfalse. {
alt b {
ttrue. { tfalse }
/* see above comment */
_ {
tfalse
}
}
}
}
}
fn trit_or(a: trit, b: trit) -> trit {
alt a {
dont_care. { b }
ttrue. { ttrue }
tfalse. {
alt b {
ttrue. { dont_care }
/* FIXME: ?????? */
_ {
tfalse
}
}
}
}
}
// FIXME: This still seems kind of dodgy to me (that is,
// that 1 + ? = 1. But it might work out given that
// all variables start out in a 0 state. Probably I need
// to make it so that all constraints start out in a 0 state
// (we consider a constraint false until proven true), too.
fn trit_and(a: trit, b: trit) -> trit {
alt a {
dont_care. { b }
// also seems wrong for case b = ttrue
ttrue. {
alt b {
dont_care. { ttrue }
// ??? Seems wrong
ttrue. {
ttrue
}
// false wins, since if something is uninit
// on one path, we care
// (Rationale: it's always safe to assume that
// a var is uninitialized or that a constraint
// needs to be re-established)
tfalse. {
tfalse
}
}
}
// Rationale: if it's uninit on one path,
// we can consider it as uninit on all paths
tfalse. {
tfalse
}
}
// if the result is dont_care, that means
// a and b were both dont_care
}
fn change(changed: bool, old: trit, new: trit) -> bool {
changed || new != old
}
fn tritv_difference(p1: t, p2: t) -> bool {
let i: uint = 0u;
assert (p1.nbits == p2.nbits);
let sz: uint = p1.nbits;
let changed = false;
while i < sz {
let old = tritv_get(p1, i);
let new = trit_minus(old, tritv_get(p2, i));
changed = change(changed, old, new);
tritv_set(i, p1, new);
i += 1u;
}
ret changed;
}
fn tritv_union(p1: t, p2: t) -> bool {
let i: uint = 0u;
assert (p1.nbits == p2.nbits);
let sz: uint = p1.nbits;
let changed = false;
while i < sz {
let old = tritv_get(p1, i);
let new = trit_or(old, tritv_get(p2, i));
changed = change(changed, old, new);
tritv_set(i, p1, new);
i += 1u;
}
ret changed;
}
fn tritv_intersect(p1: t, p2: t) -> bool {
let i: uint = 0u;
assert (p1.nbits == p2.nbits);
let sz: uint = p1.nbits;
let changed = false;
while i < sz {
let old = tritv_get(p1, i);
let new = trit_and(old, tritv_get(p2, i));
changed = change(changed, old, new);
tritv_set(i, p1, new);
i += 1u;
}
ret changed;
}
fn tritv_get(v: t, i: uint) -> trit {
let b1 = bitv::get(v.uncertain, i);
let b2 = bitv::get(v.val, i);
assert (!(b1 && b2));
if b1 { dont_care } else if b2 { ttrue } else { tfalse }
}
fn tritv_set(i: uint, v: t, t: trit) -> bool {
let old = tritv_get(v, i);
alt t {
dont_care. {
bitv::set(v.uncertain, i, true);
bitv::set(v.val, i, false);
}
ttrue. { bitv::set(v.uncertain, i, false); bitv::set(v.val, i, true); }
tfalse. {
bitv::set(v.uncertain, i, false);
bitv::set(v.val, i, false);
}
}
ret change(false, old, t);
}
fn tritv_copy(target: t, source: t) -> bool {
assert (target.nbits == source.nbits);
let changed =
!bitv::equal(target.uncertain, source.uncertain) ||
!bitv::equal(target.val, source.val);
bitv::assign(target.uncertain, source.uncertain);
bitv::assign(target.val, source.val);
ret changed;
}
fn tritv_set_all(v: t) {
let i: uint = 0u;
while i < v.nbits { tritv_set(i, v, ttrue); i += 1u; }
}
fn tritv_clear(v: t) {
let i: uint = 0u;
while i < v.nbits { tritv_set(i, v, dont_care); i += 1u; }
}
fn tritv_kill(v: t) {
let i: uint = 0u;
while i < v.nbits { tritv_set(i, v, tfalse); i += 1u; }
}
fn tritv_clone(v: t) -> t {
ret {uncertain: bitv::clone(v.uncertain),
val: bitv::clone(v.val),
nbits: v.nbits};
}
fn tritv_doesntcare(v: t) -> bool {
let i: uint = 0u;
while i < v.nbits {
if tritv_get(v, i) != dont_care { ret false; }
i += 1u;
}
ret true;
}
fn to_vec(v: t) -> [uint] {
let i: uint = 0u;
let rslt: [uint] = [];
while i < v.nbits {
rslt +=
[alt tritv_get(v, i) {
dont_care. { 2u }
ttrue. { 1u }
tfalse. { 0u }
}];
i += 1u;
}
ret rslt;
}
fn to_str(v: t) -> str {
let i: uint = 0u;
let rs: str = "";
while i < v.nbits {
rs +=
alt tritv_get(v, i) {
dont_care. { "?" }
ttrue. { "1" }
tfalse. { "0" }
};
i += 1u;
}
ret rs;
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//