private void GetFreeVars(VM vm, Statement st, Stack<string> boundVars, Scope result) { // InternalCount and store the names defined by this statement int nNewVars = 0; foreach (string name in st.GetDefinedNames()) { ++nNewVars; boundVars.Push(name); } // Iterate over all names used by expressions in the statement foreach (string name in st.GetUsedNames()) { // Is this not a boundVar, and not already marked as a free var if (!boundVars.Contains(name) && !result.HasName(name)) { // Throws an exception if the name is not found HeronValue v = vm.LookupName(name); result.Add(new VarDesc(name), v); } } // Recurse over all sub statements, getting the free vars foreach (Statement child in st.GetSubStatements()) GetFreeVars(vm, child, boundVars, result); // Pop all variables added by this variable for (int i = 0; i < nNewVars; ++i) boundVars.Pop(); }
/// <summary> /// This is a second stage of construction needed for closures. /// It computes any free variables in the function, and binds them /// to values /// </summary> /// <param name="vm"></param> public void ComputeFreeVars(VM vm) { freeVars = new Scope(); var boundVars = new Stack<string>(); boundVars.Push(fun.name); foreach (FormalArg arg in fun.formals) boundVars.Push(arg.name); GetFreeVars(vm, fun.body, boundVars, freeVars); }
/// <summary> /// Add a group of variables at once /// </summary> /// <param name="vars"></param> public void AddVars(Scope vars) { for (int i=0; i < vars.Count; ++i) AddVar(vars.GetVar(i), vars.GetValue(i)); }
/// <summary> /// Creates a scope, and when DisposableScope.Dispose is called removes it /// Normally you would use this as follows: /// <code> /// using (vm.CreateScope(scope)) /// { /// ... /// } /// </code> /// </summary> /// <returns></returns> public DisposableScope CreateScope(Scope scope) { return new DisposableScope(this, scope); }
/// <summary> /// Creates a new scope, with a predefined set of variable names. Useful for function arguments /// or class exposedFields. /// </summary> /// <param name="scope"></param> public void PushScope(Scope scope) { frames.Peek().AddScope(scope); }
public DisposableScope(VM vm, Scope scope) { this.vm = vm; vm.PushScope(scope); }
public void AddScope(Scope scope) { scopes.Add(scope); }