/// <summary> /// Prints the value of an <see cref="Expression"/> to the stdout. Does add a return '\n' symbol /// </summary> /// <param name="value"> Expression you want to print (the evaluated value)</param> /// <returns> <see cref="NullVar"/> (equivalent of null/void)</returns> private static NullVar printValEndlFunction(Expression value) { Debugging.print("begin printing to console: (" + value.expr + ")"); Global.stdoutWriteLine(value.evaluate().ToString()); Debugging.print("end printing to console"); return(new NullVar()); }
/// <summary> /// Execute the Algorithm/Function. <see cref="Instruction"/> by <see cref="Instruction"/>, /// until the list of instructions is exhausted and we can return the <see cref="_return_value"/>, /// using <see cref="Expression.parse"/> on it (it is an <see cref="Expression"/>) /// </summary> /// <returns> The evaluated <see cref="_return_value"/> after all the <see cref="_instructions"/> have been executed</returns> /// <exception cref="AquilaExceptions.RuntimeError"> ReturnValueException is null</exception> public Variable run() { try { // Algorithm start setStartContext(); foreach (Instruction instr in _instructions) { try { instr.execute(); } catch (System.Reflection.TargetInvocationException out_exception) { // normal TargetInvocationException if (!(out_exception.InnerException is AquilaControlFlowExceptions.ReturnValueException)) { throw; } // casted ReturnValueException AquilaControlFlowExceptions.ReturnValueException exception = (AquilaControlFlowExceptions.ReturnValueException)out_exception.InnerException; if (exception == null) { throw new AquilaExceptions.RuntimeError( "The inner ReturnValueException in the TargetInvocationException is null"); // something went wrong } _return_value = new Expression(exception.getExprStr()); Context.reset(); return(_return_value.evaluate()); } } // no resetting here. algorithm finished setEndContext(); return(new NullVar()); // NoReturnCallWarning } catch (StopInterpreterException) { Global.stdoutWriteLine("Stopped Interpreter"); Global.resetEnv(); return(new NullVar()); } catch (Exception e) { Global.stdoutWriteLine(e.ToString()); return(new NullVar()); } }
/// <summary> /// Run the Algorithm as a test run. <see cref="Instruction"/> by <see cref="Instruction"/>, /// until the list of instructions is exhausted and we can return the <see cref="_return_value"/>, /// using <see cref="Expression.parse"/> on it (it is an <see cref="Expression"/>) /// </summary> /// <returns> The evaluated <see cref="_return_value"/> after all the <see cref="_instructions"/> have been executed</returns> /// <exception cref="AquilaExceptions.RuntimeError"> ReturnValueException is null</exception> public Variable testRun() { initTestMode(); try { // Run start Debugging.print("Starting Algorithm test run"); setStartContext(); foreach (Instruction instr in _instructions) { try { instr.execute(); } catch (System.Reflection.TargetInvocationException out_exception) { // normal TargetInvocationException if (!(out_exception.InnerException is AquilaControlFlowExceptions.ReturnValueException)) { throw; } // casted ReturnValueException AquilaControlFlowExceptions.ReturnValueException exception = (AquilaControlFlowExceptions.ReturnValueException)out_exception.InnerException; if (exception == null) { throw new AquilaExceptions.RuntimeError("The inner ReturnValueException in the TargetInvocationException is null"); // something went wrong } _return_value = new Expression(exception.getExprStr()); Context.reset(); Debugging.print("Ended Algorithm test run with return value"); Global.setSetting("test mode", false); return(_return_value.evaluate()); } } // no resetting here. algorithm finished setEndContext(); Debugging.print("Ended Algorithm test run with no return"); Global.setSetting("test mode", false); return(new NullVar()); // NoReturnCallWarning } catch (Exception e) { Global.stdoutWriteLine(e.ToString()); Debugging.print("Ended Algorithm test run with exception"); Global.setSetting("test mode", false); return(new NullVar()); } }
/// <summary> /// Print the whole event stack (deconstructing progressively). A copy of the event stack is used. /// The real event stack is not altered /// </summary> public void printEventStack() { var events_copy = getEventStackCopy(); int i = 0; int size = events_copy.Count; for (; i < size; i++) { Global.stdoutWrite($"{i}: "); Global.stdoutWriteLine(events_copy.Pop().ToString()); } }
/// <summary> /// This function is used to read a raw Aquila source code text-based file and /// purge the code (remove comments and all unnecessary spaces and tabs) /// </summary> /// <param name="path"> lib_path to your source code file</param> /// <returns> list of lines containing your purged code</returns> internal static Dictionary <int, string> readSourceCode(string path) { Dictionary <int, string> lines = readLines(path); print(lines.Count + " lines read"); lines = StringUtils.normalizeWhiteSpacesInStrings(lines); print($"lines normalized. remaining: {lines.Count}"); foreach (var pair in lines) { Global.stdoutWriteLine($"{pair.Key}: {pair.Value}"); } lines = StringUtils.refactorCodeShortcuts(lines, new [] { ('[', ']'), ('(', ')') });
/// <summary> /// Print a List<string>. One line per string /// </summary> /// <param name="list"> list of strings</param> /// <param name="print_index"> false by default. if true, index of line (starting 0) will be printed as prefix</param> public static void printStringList(IEnumerable <string> list, bool print_index = false) { short index = 1; foreach (string line in list) { if (print_index) { Global.stdoutWrite($"{index++} "); } Global.stdoutWriteLine(line); } }
/// <summary> /// Print the instruction and its <see cref="_sub_instr_list"/> if there are any. /// Indents the code according to the nested-depth to increase readability /// </summary> /// <param name="depth"> indentation level</param> public void prettyPrint(uint depth = 0) { for (uint i = 0; i < depth; i++) { Global.stdoutWrite("\t"); } Global.stdoutWriteLine(_instr); if (!_is_nested) { return; } foreach (RawInstruction sub_instr in _sub_instr_list) { sub_instr.prettyPrint(depth + 1); } }
/// <summary> /// Execute the input lines /// </summary> /// <param name="lines"> input lines</param> /// <param name="clear_lines"> clear the input lines at the end of execution</param> private static void executeLines(List <string> lines, bool clear_lines = true) { // execute line here try { int temp_i = 0; List <RawInstruction> raw_instructions = RawInstruction.code2RawInstructions(lines.ToDictionary(_ => temp_i++, x => x)); List <Instruction> instructions = RawInstruction.buildInstructions(raw_instructions); foreach (Instruction instr in instructions) { instr.execute(); } } catch (Exception e) { Global.stdoutWriteLine(e); } if (clear_lines) { lines.Clear(); } }
public void repr(int i = 0) { string prefix = new string('\t', i); // data if (data != null) { foreach (var pair in data) { Global.stdoutWriteLine(prefix + "\t - " + pair.Key); pair.Value.repr(i + 1); } } // endpoint if (endpoints != null) { foreach (string endpoint in endpoints) { Global.stdoutWriteLine(prefix + "\t * " + endpoint); } } // separation Global.stdoutWriteLine(); }
/// <summary> /// Process the input from the interpreter. /// If the input is one of the interactive-mode-only commands, the command should not /// be executed by the interpreter but will be executed by this function manually. /// </summary> /// <param name="input"> command line from the interactive-mode</param> /// <returns> should the command be executed ?</returns> internal static bool processInterpreterInput(string input) { switch (input) { case "help": { Global.stdoutWriteLine("All existing interactive-mode-only commands:"); // ReSharper disable once RedundantExplicitArrayCreation foreach (string command in new string[] { "help", "exit", "reset_env", "clear", // base interactive-mode "exec", "exec_info", // exec "debug", "trace_debug", "parse_debug", // debugging (enable/disable) "eval %expr", // expr "var %var_name", "vars", "$%var_name", // variables // ReSharper disable once StringLiteralTypo "funcs", "df_funcs", // functions "type", // ? "trace_info", "trace_uniq_stacks", "rewind %n %var_name", "peek_trace $%traced_value", // trace "get_context", "set_status", "set_info_null", "reset_context", // context "scope_info", // scope "show-settings", // settings }) { Global.stdoutWriteLine(" -> " + command); } return(false); } case "clear": if (!Global.getSetting("redirect debug stout & stderr")) { Console.Clear(); } return(false); case "vars": { Global.stdoutWriteLine("Global Variables:"); foreach (var pair in Global.getGlobalVariables()) { Global.stdoutWriteLine("\t" + pair.Key + " : " + pair.Value); } int i = 0; Global.stdoutWriteLine("Local Scope Variables:"); foreach (var dict in Global.getCurrentDictList()) { i++; foreach (var pair in dict) { Global.stdoutWrite(new string('\t', i)); Global.stdoutWrite(pair.Key + " : "); Global.stdoutWriteLine(pair.Value.ToString()); } } return(false); } // ReSharper disable once StringLiteralTypo case "funcs": { Global.stdoutWriteLine("User defined functions:"); foreach (var pair in Functions.user_functions) { Global.stdoutWriteLine(" * " + pair.Key + (pair.Value.isRec() ? " : [rec] " : " : ") + "(" + pair.Value.func_args.Count + ") -> " + pair.Value.getType()); } return(false); } case "df_funcs": Global.stdoutWriteLine("Default (predefined) functions:"); foreach (var pair in Functions.functions_dict) { MethodInfo method = pair.Value.GetMethodInfo(); Global.stdoutWriteLine(" * " + pair.Key + " [?] : (" + method.GetParameters().Length + ") -> " + method.ReturnType); } return(false); case "debug": Global.setSetting("debug", !Global.getSetting("debug")); return(false); case "trace_debug": Global.setSetting("trace debug", !Global.getSetting("trace debug")); return(false); case "parse_debug": Global.setSetting("parse debug", !Global.getSetting("parse debug")); return(false); case "trace_info": { Global.stdoutWriteLine("var tracers:"); foreach (VarTracer tracer in Global.var_tracers) { Global.stdoutWriteLine(" - var : " + (tracer.getTracedObject() as Variable).getName()); Global.stdoutWriteLine(" - stack : " + tracer.getStackCount()); Global.stdoutWriteLine(" - updated : " + tracer.last_stack_count); } Global.stdoutWriteLine("func tracers:"); foreach (FuncTracer tracer in Global.func_tracers) { Global.stdoutWriteLine(" - func : " + tracer.getTracedObject()); Global.stdoutWriteLine(" - stack : " + tracer.getStackCount()); } return(false); } case "trace_uniq_stacks": Global.var_tracers[0].printEventStack(); return(false); case "reset_env": Global.resetEnv(); Global.stdoutWriteLine(" [!] Global Environment reset"); return(false); case "get_context": { int status = Context.getStatus(); Context.StatusEnum status_quote = (Context.StatusEnum)status; object info = Context.getInfo(); bool blocked = Context.isFrozen(); bool enabled = Global.getSetting("fail on context assertions"); Global.stdoutWriteLine("status : " + status); Global.stdoutWriteLine("quote : " + status_quote); Global.stdoutWriteLine("info : " + info); Global.stdoutWriteLine("blocked : " + blocked); Global.stdoutWriteLine("asserts : " + enabled); return(false); } case "set_info_null": Context.setInfo(null); return(false); case "reset_context": Context.reset(); return(false); case "type": Global.stdoutWriteLine("type of NullVar: " + typeof(NullVar)); Global.stdoutWriteLine("type of Variable: " + typeof(Variable)); Global.stdoutWriteLine("type of Integer: " + typeof(Integer)); return(false); case "scope_info": Global.stdoutWriteLine("local scope depth: " + Global.getLocalScopeDepth()); Global.stdoutWriteLine("main scope depth: " + Global.getMainScopeDepth()); return(false); case "show-settings": foreach (var pair in Global.getSettings()) { Global.stdoutWriteLine($" - {pair.Key} : {pair.Value}"); } return(false); } if (input[0] == '$' && Global.variableExistsInCurrentScope(input.Substring(1))) { Global.stdoutWriteLine(Global.variableFromName(input.Substring(1)).ToString()); return(false); } if (input.StartsWith("set_status ")) { int status = int.Parse(input.Substring(11)); Context.setStatus((Context.StatusEnum)status); return(false); } if (input.StartsWith("eval ")) { Variable var_ = Expression.parse(input.Substring(5)); Global.stdoutWriteLine(var_.ToString()); return(false); } if (input.StartsWith("var ")) { string var_name = input.Substring(4); var_name = StringUtils.normalizeWhiteSpaces(var_name); if (var_name == "") { return(false); } Variable var_ = Global.variableFromName(var_name); Global.stdoutWriteLine("name : " + var_.getName()); Global.stdoutWriteLine("type : " + var_.getTypeString()); Global.stdoutWriteLine("const : " + var_.isConst()); Global.stdoutWriteLine("assigned : " + var_.assigned); Global.stdoutWriteLine("value : " + var_); Global.stdoutWriteLine("traced : " + var_.isTraced()); Global.stdoutWriteLine("^ mode : " + var_.trace_mode); if (var_ is NumericalValue value) { Global.stdoutWriteLine("*source : " + StringUtils.dynamic2Str(value.source_vars)); } return(false); } if (input.StartsWith("rewind")) { string[] splitted = input.Split(' '); if (splitted.Length == 3) { if (!int.TryParse(splitted[1], out int n)) { Global.stdoutWriteLine("cannot read n"); return(false); } string var_name = splitted[2]; Variable var_ = Expression.parse(var_name); if (!var_.isTraced()) { Global.stdoutWriteLine("Variable is not traced! Use the \"trace\" instruction to start tracing variables"); return(false); } var_.tracer.rewind(n); return(false); } Global.stdoutWriteLine("split count does not match 3"); return(false); } if (input.StartsWith("peek_trace")) { if (input.Length < 11) { return(false); } Variable var_ = Expression.parse(input.Substring(11)); if (!var_.isTraced()) { Global.stdoutWriteLine("Variable is not traced! Use the \"trace\" instruction to start tracing variables"); return(false); } Alteration alter = var_.tracer.peekEvent().alter; Global.stdoutWriteLine("name : " + alter.name); Global.stdoutWriteLine("variable : " + alter.affected.getName()); Global.stdoutWriteLine("main value : " + StringUtils.dynamic2Str(alter.main_value)); Global.stdoutWriteLine("num minor : " + alter.minor_values.Length); Global.stdoutWriteLine("minor values : " + StringUtils.dynamic2Str(alter.main_value)); Global.stdoutWriteLine("stack count : " + var_.tracer.getStackCount()); Global.stdoutWriteLine("updated : " + var_.tracer.last_stack_count); return(false); } if (input.StartsWith("#")) { Global.stdoutWriteLine("Handling macro parameter"); if (!input.Contains(' ')) { Parser.handleMacro(input.Substring(1), null); return(false); } int index = input.IndexOf(' '); // extract the key & value pair string value = input.Substring(index); input = input.Substring(1, index); // purge pair value = StringUtils.normalizeWhiteSpaces(value); input = StringUtils.normalizeWhiteSpaces(input); Parser.handleMacro(input, value); return(false); } return(true); }
/// <summary> /// The interactive mode gives you a shell-like environment in which /// you can code in Aquila. /// </summary> public static void interactiveMode(List <string> exec_lines = null, bool greeting = true, bool rescue_mode = false) { Global.setSetting("fail on context assertions", false); // disable context checks bool new_line = true; List <string> current_lines = new List <string>(); // exec mode bool exec_mode = exec_lines != null; if (greeting) { if (rescue_mode) { System.Console.WriteLine("interactive mode greeting"); } Global.stdoutWriteLine(" [ - Aquila Interactive Interpreter - ]"); Global.stdoutWriteLine(" [?] Type \"help\" to get a list of all the interactive-mode-only commands"); Global.stdoutWriteLine(" [?] See https://github.com/Nicolas-Reyland/Aquila/blob/main/Aquila_Documentation.pdf for some unfinished documentation about Aquila itself"); if (exec_mode) { Global.stdoutWriteLine(" [!] Exec mode enabled. There are executables lines saved. Use the \"exec\" command to run them"); } } Context.setStatus(Context.StatusEnum.instruction_main_loop); Context.setInfo("Interactive Mode"); while (true) { if (new_line) { Global.stdoutWrite(getInteractivePrefix() + " > "); } else { Global.stdoutWrite(getInteractivePrefix() + " - "); } if (rescue_mode) { System.Console.WriteLine("asking for input..."); } string input = Global.stdinReadLine(); if (rescue_mode) { System.Console.WriteLine("got input: " + input); Global.stdoutWriteLine(input); } if (StringUtils.normalizeWhiteSpaces(input) == "") { continue; } if (StringUtils.normalizeWhiteSpaces(input) == "") { continue; } input = StringUtils.removeComments(input); input = StringUtils.normalizeWhiteSpaces(input); if (input == "exit") { Global.stdoutWriteLine("Exiting."); return; } if (!processInterpreterInput(input)) { continue; // command should not be executed, then continue } if (input == "exec_info") { if (!exec_mode) { Global.stdoutWriteLine(" [X] Exec mode disabled. You have to have pre-defined executable lines to enable this mode"); } else { Global.stdoutWriteLine(" Executable lines:"); foreach (string line in exec_lines) { Global.stdoutWriteLine(" " + line); } } continue; } if (input == "exec") { if (!exec_mode) { Global.stdoutWriteLine(" [X] Exec mode disabled. You have to have pre-defined executable lines to enable this mode"); continue; } executeLines(exec_lines, false); } else { current_lines.Add(input); if (executableLines(current_lines)) { executeLines(current_lines); new_line = true; } else { new_line = false; } } } }