/*
A clone function is required to clone
state on block transitions
if this one does not work for you,
provide your own in your script
*/
function clone(myObj)
{
  if(typeof(myObj) != 'object') return myObj;
  if(myObj == null) return myObj;
  if(myObj.constructor == Array) {
    return myObj.map(clone)
  }
  var myNewObj = new Object();

  for(var i in myObj)
    myNewObj[i] = clone(myObj[i]);

  return myNewObj;
}
/* Uno-style programming support */
/*

ALIAS address taken &symbol
ARRAY_DECL appears as basename in an array declaration struct X symbol[8]
DECL symbol appears as scalar in a declaration int symbol
DEF symbol assigned a new value symbol = x
DEREF dereferenced *symbol
FCALL used as name of function symbol(x)
PARAM formal parameter of a function function(int symbol) { ... }
REF0 dereferenced to access structure symbol->x
REF1 used as structure name symbol.x
REF2 used as structure element x->symbol, x.symbol
USE evaluated to derive value x = symbol
USEafterdef both DEF and USE, but USE occurs after DEF if ((symbol = x) > 0)
USEbeforedef both DEF and USE, but USE occurs before DEF symbol++ _ ________________________________________________________________________________________
*/
// The following are supported
var FCALL = "isFcall", DEF = "isDef", USE = "isUse", ALIAS = "isAlias" ,
    DECL = "isDecl" , DEREF = "isDeref" , PARAM = "isParam"


function filterVars(vars, name, flags) {
  if(!flags)
    flags = []
  return vars.filter(
    function (v) {
      if(name.length && name != v.name)
        return false;
      if(flags.length == 0)
        return true;

      for(var tag in v) {
        if(!v[tag])
          continue
        if(flags.some( function (x) { return x == tag } ))
          return true
      }
      return false
    });
}

/*
Selects symbols from the current statement, based on their name or on def-use
tags from the dataflow analysis. The call erases earlier results of selections.
This is a boolean function that returns true if the resulting selection is nonempty,
and otherwise returns false.
*/
function select(name, flags) {
  _selected = filterVars(_vars, name, flags)
  return _selected.length > 0
}

/*
Like select, but this time the selection refines the result of earlier selections,
picking a subset of the symbols that match the additional criteria specified
here.
*/
function refine(name, flags) {
  if(!_selected)
    return false
  _selected = filterVars(_selected, name, flags)
  return _selected.length > 0
}

function display(vars) {
  for each (var v in vars) {
    var str = ""
    for(var p in v) {
      str += p + ":" + v[p] + " "
    }
    print(str)
  }
}
  
/*
Reduces the current selection to those symbols that match the additional criteria
and that have a specified (non-zero) mark, assigned through an earlier use
of the mark primitive.
*/
function match(tag, flags) {
  if(!_state)
    return false
  if(!_state[tag] || !refine("", flags))
    return false
  _selected.filter(
    function (selectedV) {
      return _state[tag].some(
        function (v) {
          return selectedV.name == v.name
        }
      )
    }
   )
  return _selected.length > 0
}

/*
Removes the markings for all currently selected
symbols.
*/
function unmark() {
  if(!_selected || !_state)
    return

  var removes = _selected.map(function (x) {return x.name})
  _state.map(function (x) {
              return x.filter(function (v) { return removes.indexOf(v.name) != -1 })
            })

  _state = _state.filter(function (x) {x.length > 0})
}

/*
Assigns an integer marking N to all currently selected symbols. Since the default
marking is zero, the marking should be non-zero to be detectable later.
The marking in effect assigns an individual state to a symbol of interest, so
that the evolution of its state can be tracked and checked in the property.
*/
function mark(tag) {
  if(!_state) {
    _state = []
  }
  _state[tag] = _selected.slice()
}

/*
Triggers the printing of a list of all symbols that appear on the depth-first
search stack at the point of call, and all symbols that appear in the def-use list
for the current statement. It also shows all symbols that were selected through
use of the primitives select, refine, and unselect.
*/
function list() {
  if(typeof _selected == "object") {
    print("SELECTED:")
    display(_selected)
  }
  
  for(i in _state) {
    print("MARKED " +i +":")
    display(_state[i])
  }
}

/*
Returns true if symbols exist that match the criteria specified, and that have
 the specified (non-zero) mark
*/
function marked(tag, flags) {
  if(!_state || !_state[tag])
    return false
  _selected = filterVars(_state[tag], "", flags)

  return _selected.length > 0
}  

