Sunday, November 12, 2006

Taming variables

I developed some new tools which perform static analysis of variable usage.

Factor's variables are dynamically scoped and very simple, there is a global namestack holding hashtables. Nesting a scope pushes a hashtable on the stack, variable lookups search up the namestack, and variable assignments store the new value in the topmost hashtable on the namestack.

The infer word has been replaced with an infer. word which gives variable usage information obtained by statically analyzing the code. Those in the know will recognize that this is a ripoff of InterLisp's MASTERSCOPE package. Here is an example:
  SYMBOL: x
[ 3 * x set ] infer.

* Stack effect:
( object -- )
* Writes free variables:
x

But if you wrap this in a with-scope, the assignment is lost as soon as the scope ends and there is no observable side effect:
  [ [ 3 * x set ] with-scope ] infer.
* Stack effect:
( object -- )

On the other hand, reading a variable from a nested scope might go up a scope if the variable is not defined, and so it can be observed from the outside:
  [ [ x get ] with-scope ] infer.
* Stack effect:
( -- object )
* Reads free variables:
x

But if you assign the variable in scope first, then we cannot observe the read:
  [ [ 5 x set [ x get ] with-scope ] with-scope ] infer.
* Stack effect:
( -- object )

Now, of course because this is built on stack effect inference, everything works if you have a word which indirectly calls get or set.

It even understands combinators, for example this one that applies 2 * to the value of x:
  [ x [ 2 * ] change ] infer.
* Stack effect:
( -- )
* Reads free variables:
x
* Writes free variables:
x

No special support for inferring change is defined, it just looks at the definition of change;
: change ( variable quot -- ) 
>r dup get r> rot slip set ; inline

Finally, it has special support for recording words which directly read and write globals:
  [ [ 5 x set-global ] with-scope ] infer.
* Stack effect:
( -- )
* Writes global variables:
x

No comments: