/// <summary> /// Remove a <see cref="Variable"/> and its references /// </summary> /// <param name="expr"> <see cref="Expression"/> resulting in a <see cref="Variable"/></param> /// <returns> <see cref="NullVar"/> (equivalent of null/void)</returns> private static NullVar deleteVarFunction(Expression expr) { // evaluate every expression Variable variable = expr.evaluate(); string var_name = variable.getName(); // delete var Debugging.assert(Global.variableExistsInCurrentScope(var_name), new AquilaExceptions.NameError($"Variable name \"{var_name}\" does not exist in the current Context")); // remove the Tracer if is traced if (variable.isTraced()) { // remove from the usable variables Global.usable_variables.Remove(var_name); // Deletion Alteration var alter = new Alteration("delete_var", variable, null, new dynamic[] {}); // Update the tracer with the death event variable.tracer.update(new Event(alter)); // Remove the tracer Global.var_tracers.Remove(variable.tracer); } // remove from the dict Global.getCurrentDict().Remove(var_name); return(new NullVar()); }
/// <summary> /// This function should be called at the end of every <see cref="Instruction.execute"/> call that is susceptible of /// changing the value of a <see cref="Variable"/>. It works in 3 steps: /// <para/>* Checks for any new assigned <see cref="Variable"/>s in the <see cref="Global._variable_stack"/> (if found: adds to the <see cref="Global.usable_variables"/>) /// <para/>* Update/Process all the awaiting <see cref="Event"/>s (<seealso cref="update"/>) /// <para/>* Check for any new <see cref="Event"/> which has not been processed by the <see cref="Global.tracer_update_handler_function"/> /// </summary> /// <param name="add_call_info"> stands for "additional calling information". If it has any value, it will be printed by the <see cref="Debugging.print"/> function for debugging</param> public static void updateTracers(string add_call_info = "") { if (Global.getSetting("test mode")) { return; } printTrace("updating tracers"); // printTrace alter info about the call if needed if (add_call_info != "") { printTrace(add_call_info); } // check for new usable variables foreach (var pair in Global.getCurrentDict().Where(pair => !Global.usable_variables.Contains(pair.Key))) { printTrace("checking potential var ", pair.Value is NullVar ? StringConstants.Types.NULL_TYPE : pair.Value.getName()); if (pair.Value is NullVar || !pair.Value.assigned) { continue; } // new usable variable ! printTrace("var ", pair.Value.getName(), " is usable (non-null & assigned)"); Global.usable_variables.Add(pair.Key); } // checking tracers checkAllAwaitingEvents(); // check tracer event stacks printTrace("checking variable tracers event stack counts"); foreach (VarTracer tracer in Global.var_tracers) { // unread tracers updates while (tracer.last_stack_count != tracer.getStackCount()) { printTrace("stack count changed for ", tracer.getVar().getName(), " from ", tracer.last_stack_count, " to ", tracer.getStackCount()); //Global.stdoutWriteLine("call graphical function " + StringUtils.varList2String(tracer.getVar().getRawValue()) + " & call event: " + tracer.peekEvent().ToString()); // traced functions have already been processed. checking awaiting stacks int diff = tracer.getStackCount() - tracer.last_stack_count; Debugging.assert(diff > 0); // will run forever tracer.last_stack_count++; //! here } // awaiting tracer stacks while (tracer._awaiting_events.Count != 0) { printTrace("awaiting stacks: ", tracer._awaiting_events.Count); Alteration alter = tracer._awaiting_events.Peek().alter; callUpdateHandler(alter); tracer.update(tracer._awaiting_events.Pop()); } } // update data_tree printTrace("Updating Global.data_tree"); // ReSharper disable once InvertIf if (Global.getSetting("update data tree")) { Debugging.assert(Global.data_tree != null, new AquilaExceptions.RuntimeError("Tried to update data_tree, but it is null")); Global.data_tree = Global.data_tree.update(); } }
public override void execute() { setContext(); // get variable value Variable variable_value = _var_expr.evaluate(); // is the value assigned ? (only relevant if other variable) variable_value.assertAssignment(); Variable variable = Variable.fromRawValue(variable_value.getRawValue()); // keep track of source vars -> should do something generic for lots of attributes ... if (variable is NumericalValue) { ((NumericalValue)variable).source_vars = new Dictionary <string, NumericalValue>(((NumericalValue)variable_value).source_vars); } variable.setName(_var_name); // explicit typing if (_var_type != StringConstants.Types.AUTO_TYPE) { Debugging.print("checking variable explicit type"); Expression default_value = Global.default_values_by_var_type[_var_type]; Debugging.assert(variable_value.hasSameParent(default_value.evaluate())); // TypeException } // constant if (_constant) { if (variable_value.isConst()) { variable.setConst(); } else { throw new AquilaExceptions.InvalidVariableClassifierException( "The \"const\" cannot be used when assigning to a non-const value"); } } // actually declare it to its value if (_global) { Global.addGlobalVariable(_var_name, variable); } else { Global.getCurrentDict()[_var_name] = variable; // overwriting is mandatory Debugging.print("variable exists ", Global.variableExistsInCurrentScope(_var_name)); if (_assignment) { variable.assign(); // should not need this, but doing anyway } else { variable.assigned = false; } } Debugging.print("finished declaration with value assignment: ", variable.assigned); // automatic tracing ? if (_assignment && Global.getSetting("auto trace")) { Debugging.print("Tracing variable: \"auto trace\" setting set to true"); // Does NOT work by simply doing "variable.startTracing()", and idk why Tracing tracing_instr = new RawInstruction($"trace ${_var_name}", line_index).toInstr() as Tracing; //Tracing tracing_instr = new Tracing(line_index, new List<Expression>{_var_expr}); // <- does not work either :( tracing_instr.execute(); } // update things 'n stuff Global.onElementaryInstruction(); // reset Context Context.reset(); }