/// <summary>Parse the argument, reading any tags or other special data.</summary> /// <param name="error">What to invoke if there is an error.</param> /// <param name="runnable">The command runnable.</param> /// <returns>The parsed final text.</returns> public virtual TemplateObject Parse(Action <string> error, CompiledCommandRunnable runnable) { if (TrueForm == null) { throw new ErrorInducedException("Arguments must be compiled before usage!"); } return(TrueForm.Parse(error, runnable)); }
/// <summary>Constructs the tag information container.</summary> /// <param name="_system">The command system to use.</param> /// <param name="_vars">The variable argument pieces.</param> /// <param name="_bits">The tag bits.</param> /// <param name="_basecolor">The default color to use for output.</param> /// <param name="_mode">What debug mode to use.</param> /// <param name="_error">What to invoke if there is an error.</param> /// <param name="fallback">What to fall back to if the tag returns null.</param> /// <param name="_runnable">The relevant command runnable, if any.</param> public TagData(TagHandler _system, Argument[] _vars, TagBit[] _bits, string _basecolor, DebugMode _mode, Action <string> _error, Argument fallback, CompiledCommandRunnable _runnable) { TagSystem = _system; BaseColor = _basecolor ?? TextStyle.Simple; DBMode = _mode; ErrorHandler = _error; Fallback = fallback; Variables = _vars; Bits = _bits; Runnable = _runnable; ErrorAction = ErrorNoReturn; }
/// <summary>Handles an error as appropriate to the situation, in the current queue, from the current command.</summary> /// <param name="queue">The associated queue.</param> /// <param name="entry">The command entry that errored.</param> /// <param name="message">The error message.</param> public void HandleError(CommandQueue queue, CommandEntry entry, string message) { StringBuilder stacktrace = new(); stacktrace.Append("ERROR: " + message + "\n in script '" + entry.ScriptName + "' at line " + (entry.ScriptLine + 1) + ": (" + entry.Name + ")\n"); queue.WaitingOn = null; CompiledCommandRunnable runnable = queue.RunningStack.Count > 0 ? queue.RunningStack.Peek() : null; DebugMode dbmode = runnable == null ? DebugMode.FULL : runnable.Debug; while (runnable != null) { for (int i = runnable.Index; i < runnable.Entry.Entries.Length; i++) { CommandEntry entr = runnable.Entry.Entries[i]; if (entr.Command is TryCommand && entr.IsCallback) { entry.GoodOutput(queue, "Force-exiting try block."); // TODO: queue.SetVariable("stack_trace", new TextTag(stacktrace.ToString().Substring(0, stacktrace.Length - 1))); runnable.Index = i + 2; throw new ErrorInducedException(); } } runnable.Index = runnable.Entry.Entries.Length + 1; queue.RunningStack.Pop(); if (queue.RunningStack.Count > 0) { runnable = queue.RunningStack.Peek(); queue.CurrentRunnable = runnable; if (runnable.Index <= runnable.Entry.Entries.Length) { stacktrace.Append(" in script '" + runnable.Entry.Entries[runnable.Index - 1].ScriptName + "' at line " + (runnable.Entry.Entries[runnable.Index - 1].ScriptLine + 1) + ": (" + runnable.Entry.Entries[runnable.Index - 1].Name + ")\n"); } } else { runnable = null; break; } } message = stacktrace.ToString()[..(stacktrace.Length - 1)];
/// <summary>Executes the command.</summary> /// <param name="queue">The command queue involved.</param> /// <param name="entry">Entry to be executed.</param> public static void Execute(CommandQueue queue, CommandEntry entry) { int count = 1; if (entry.Arguments.Length > 0) { IntegerTag inter = IntegerTag.TryFor(entry.GetArgumentObject(queue, 0)); if (inter != null) { count = (int)inter.Internal; } } if (count <= 0) { ShowUsage(queue, entry); return; } for (int i = 0; i < count; i++) { CompiledCommandRunnable runnable = queue.CurrentRunnable; for (int ind = runnable.Index; ind < runnable.Entry.Entries.Length; ind++) { CommandEntry tentry = runnable.Entry.Entries[ind]; if (tentry.Command.Meta.IsBreakable && tentry.IsCallback) { runnable.Index = ind + 1; goto completed; } } if (queue.RunningStack.Count > 1) { queue.RunningStack.Pop(); } else { queue.HandleError(entry, "Not in that many blocks!"); return; } completed: continue; } entry.GoodOutput(queue, "Broke free successfully."); }
// TODO: Compile! /// <summary>Executes the command.</summary> /// <param name="queue">The command queue involved.</param> /// <param name="entry">Entry to be executed.</param> public static void Execute(CommandQueue queue, CommandEntry entry) { if (entry.IsCallback) { return; } if (entry.InnerCommandBlock == null) { queue.HandleError(entry, "No commands follow!"); return; } // TODO: FunctionTag input! if (entry.BlockScript != null) { if (entry.ShouldShowGood(queue)) { entry.GoodOutput(queue, "Re-running delay command..."); } } else { if (entry.ShouldShowGood(queue)) { entry.GoodOutput(queue, "Compiling and running delay command..."); } entry.BlockScript = new CommandScript("__delay__command__", "Special", entry.InnerCommandBlock, entry.System, entry.BlockStart); } CommandQueue nqueue = entry.BlockScript.ToQueue(entry.Command.Engine); nqueue.RunningStack.Peek().Debug = queue.RunningStack.Peek().Debug; nqueue.Outputsystem = queue.Outputsystem; nqueue.Execute(); CompiledCommandRunnable runnable = queue.CurrentRunnable; runnable.Index = entry.BlockEnd + 2; }
/// <summary>Run this command stack.</summary> /// <param name="queue">The queue to run under.</param> /// <param name="runnable">The runnable to run.</param> /// <returns>Whether to continue looping.</returns> public CommandStackRetVal Run(CommandQueue queue, CompiledCommandRunnable runnable) { runnable.CurrentQueue = queue; try { runnable.Run(queue); runnable.Index++; if (queue.Delayable && ((queue.Wait > 0f) || queue.WaitingOn != null)) { return(CommandStackRetVal.BREAK); } runnable.Callback?.Invoke(); if (queue.RunningStack.Count == 0) { return(CommandStackRetVal.BREAK); } if (queue.RunningStack.Peek() != runnable) { return(CommandStackRetVal.CONTINUE); } if (runnable.Index >= Entries.Length) { queue.RunningStack.Pop(); } if (queue.RunningStack.Count == 0) { return(CommandStackRetVal.STOP); } return(CommandStackRetVal.CONTINUE); } catch (Exception ex) { FreneticScriptUtilities.CheckException(ex); if (!(ex is ErrorInducedException eie && string.IsNullOrEmpty(eie.Message))) { try { if (ex is ErrorInducedException) { queue.HandleError(Entries[runnable.Index], ex.Message); } else { queue.HandleError(Entries[runnable.Index], "Internal exception:\n------\n" + ex.ToString() + "\n------"); } } catch (Exception ex2) { if (ex2 is ThreadAbortException) { throw; } if (ex2 is not ErrorInducedException) { string message = ex2.ToString(); if (runnable.Debug <= DebugMode.MINIMAL) { queue.Engine.Context.BadOutput(message); if (queue.Outputsystem != null) { queue.Outputsystem.Invoke(message, MessageType.BAD); } runnable.Index = Entries.Length + 1; queue.RunningStack.Clear(); } } } } if (queue.RunningStack.Count > 0) { if (queue.RunningStack.Peek() == runnable) { queue.RunningStack.Pop(); } return(CommandStackRetVal.CONTINUE); } return(CommandStackRetVal.STOP); } finally { runnable.CurrentQueue = null; } }
/// <summary>Parse the argument part, reading any tags or other special data.</summary> /// <param name="error">What to invoke if there is an error.</param> /// <param name="runnable">The command runnable.</param> /// <returns>The parsed final text.</returns> public abstract TemplateObject Parse(Action <string> error, CompiledCommandRunnable runnable);
/// <summary>Executes the command.</summary> /// <param name="queue">The command queue involved.</param> /// <param name="entry">Entry to be executed.</param> public static void Execute(CommandQueue queue, CommandEntry entry) { TemplateObject obj = entry.GetArgumentObject(queue, 0); FunctionTag function = FunctionTag.CreateFor(obj, queue.GetTagData()); if (function == null) { queue.HandleError(entry, "Cannot call function '" + TextStyle.Separate + obj.ToString() + TextStyle.Base + "': it does not exist!"); return; } CommandScript script = function.Internal; if (entry.ShouldShowGood(queue)) { entry.GoodOutput(queue, "Calling '" + function.GetDebugString() + TextStyle.Base + "'..."); } CompiledCommandRunnable runnable = script.Compiled.ReferenceCompiledRunnable.Duplicate(); if (runnable.Entry.Entries.Length > 0) { Dictionary <string, SingleCILVariable> varlookup = runnable.Entry.Entries[0].VarLookup; foreach (string var in entry.NamedArguments.Keys) { if (!var.StartsWithNull()) { if (varlookup.TryGetValue(var, out SingleCILVariable varx)) { // TODO: Type verification! runnable.Entry.GetSetter(varx.Index).Invoke(runnable, entry.GetNamedArgumentObject(queue, var)); } } } } if (entry.NamedArguments.ContainsKey(CommandEntry.SAVE_NAME_ARG_ID)) { bool sgood = entry.ShouldShowGood(queue); string vname = entry.NamedArguments[CommandEntry.SAVE_NAME_ARG_ID].ToString(); if (sgood) { entry.GoodOutput(queue, "Noticing variable track for " + vname + "."); } CompiledCommandRunnable curRunnable = queue.CurrentRunnable; if (!entry.VarLookup.TryGetValue(vname, out SingleCILVariable locVar)) { queue.HandleError(entry, "Invalid save-to variable: " + vname + "!"); return; } runnable.Callback = () => { // TODO: Fix! /*if (runnable.Entry.Entries.Length > 0) * { * MapTag mt = new MapTag(); * Dictionary<string, SingleCILVariable> varlookup = runnable.Entry.Entries[0].VarLookup; * foreach (SingleCILVariable vara in varlookup.Values) * { * if (runnable.LocalVariables[vara.Index].Internal != null) * { * mt.Internal.Add(vara.Name, runnable.LocalVariables[vara.Index].Internal); * } * } * curRunnable.LocalVariables[locVar.Index].Internal = mt; * }*/ if (sgood) { entry.GoodOutput(queue, "Call complete."); } }; } queue.RunningStack.Push(runnable); }
public sealed override TemplateObject Parse(Action <string> error, CompiledCommandRunnable runnable) { return(InputValue); }