internal DotNetScriptFunctions(ScriptReturnData srd, string dataFilesPath, string pluginsPath, ref SharedFunctionsHandler handler) { _srd = srd; _dataFiles = dataFilesPath; _plugins = pluginsPath; _handler = handler; }
internal static ScriptReturnData ExecuteScript(string script, string dataPath, string pluginsPath, IScriptFunctions scriptFunctions) { Utils.Info("Starting script execution..."); if (string.IsNullOrWhiteSpace(script)) { Utils.Error("Script is empty! Returning empty ScriptReturnData"); return(new ScriptReturnData()); } ScriptType type; if ((byte)script[0] >= (byte)ScriptType.Count) { type = ScriptType.OBMMScript; } else { type = (ScriptType)script[0]; script = script.Substring(1); } Utils.Debug($"ScriptType is {type.ToString()}"); var handler = new SharedFunctionsHandler(type, ref scriptFunctions); var srd = new ScriptReturnData(); var dotNetScriptFunctions = new Lazy <DotNetScriptFunctions>(() => new DotNetScriptFunctions(srd, dataPath, pluginsPath, ref handler)).Value; switch (type) { case ScriptType.OBMMScript: return(OBMMScriptHandler.Execute(script, dataPath, pluginsPath, ref handler)); case ScriptType.Python: //TODO break; case ScriptType.CSharp: DotNetScriptHandler.ExecuteCS(script, ref dotNetScriptFunctions); break; case ScriptType.VB: DotNetScriptHandler.ExecuteVB(script, ref dotNetScriptFunctions); break; case ScriptType.Count: //Impossible Utils.Error("Impossible switch case triggered, how dafuq did this happen?"); break; default: //Impossible Utils.Error("Impossible switch case triggered, how dafuq did this happen?"); return(srd); } return(srd); }
internal static ScriptReturnData Execute(string inputScript, string dataPath, string pluginsPath, ref SharedFunctionsHandler handler) { Handler = handler; Srd = new ScriptReturnData(); if (string.IsNullOrWhiteSpace(inputScript)) { return(Srd); } DataFiles = dataPath; Plugins = pluginsPath; Variables = new Dictionary <string, string>(); var flowControl = new Stack <FlowControlStruct>(); Variables["NewLine"] = Environment.NewLine; Variables["Tab"] = "\t"; var script = inputScript.Replace("\r", "").Split('\n'); string skipTo = null; bool allowRunOnLines = false; bool Break = false; for (var i = 0; i < script.Length || ExtraLines.Count > 0; i++) { string s; if (ExtraLines.Count > 0) { i--; s = ExtraLines.Dequeue().Replace('\t', ' ').Trim(); } else { s = script[i].Replace('\t', ' ').Trim(); } CLine = i.ToString(); if (allowRunOnLines) { while (s.EndsWith("\\")) { s = s.Remove(s.Length - 1); if (ExtraLines.Count > 0) { s += ExtraLines.Dequeue().Replace('\t', ' ').Trim(); } else { if (++i == script.Length) { Warn("Run-on line passed end of script"); } else { s += script[i].Replace('\t', ' ').Trim(); } } } } if (skipTo != null) { if (s == skipTo) { skipTo = null; } else { continue; } } IReadOnlyCollection <string> line = SplitLine(s); if (line.Count == 0) { continue; } if (flowControl.Count != 0 && !flowControl.Peek().Active) { switch (line.ElementAt(0)) { case "": Warn("Empty function"); break; case "If": case "IfNot": flowControl.Push(new FlowControlStruct(0)); break; case "Else": if (flowControl.Count != 0 && flowControl.Peek().Type == 0) { flowControl.Peek().Active = flowControl.Peek().Line != -1; } else { Warn("Unexpected Else"); } break; case "EndIf": if (flowControl.Count != 0 && flowControl.Peek().Type == 0) { flowControl.Pop(); } else { Warn("Unexpected EndIf"); } break; case "Select": case "SelectMany": case "SelectWithPreview": case "SelectManyWithPreview": case "SelectWithDescriptions": case "SelectManyWithDescriptions": case "SelectWithDescriptionsAndPreviews": case "SelectManyWithDescriptionsAndPreviews": case "SelectVar": case "SelectString": flowControl.Push(new FlowControlStruct(1)); break; case "Case": if (flowControl.Count != 0 && flowControl.Peek().Type == 1) { if (flowControl.Peek().Line != -1 && Array.IndexOf(flowControl.Peek().Values, s) != -1) { flowControl.Peek().Active = true; flowControl.Peek().HitCase = true; } } else { Warn("Unexpected Break"); } break; case "Default": if (flowControl.Count != 0 && flowControl.Peek().Type == 1) { if (flowControl.Peek().Line != -1 && !flowControl.Peek().HitCase) { flowControl.Peek().Active = true; } } else { Warn("Unexpected Default"); } break; case "EndSelect": if (flowControl.Count != 0 && flowControl.Peek().Type == 1) { flowControl.Pop(); } else { Warn("Unexpected EndSelect"); } break; case "For": flowControl.Push(new FlowControlStruct(2)); break; case "EndFor": if (flowControl.Count != 0 && flowControl.Peek().Type == 2) { flowControl.Pop(); } else { Warn("Unexpected EndFor"); } break; case "Break": case "Continue": case "Exit": break; } } else { var lineMsg = ""; line.Do(cur => lineMsg += "'" + cur + "' "); var registry = new SharedFunctionsRegistry(Handler); var function = registry.GetFunctionByName(line.ElementAt(0)); if (function != null) { if (line.Count < function.MinArgs) { Warn($"Missing arguments for '{function.FuncName}'"); break; } if (function.MaxArgs != 0 && line.Count > function.MaxArgs) { Warn($"Unexpected arguments for '{function.FuncName}'"); } Utils.Script($"\"{function.FuncName}\" called with line: {lineMsg}"); function.Run(ref line); } else { Utils.Script($"\"{line.ElementAt(0)}\" called with line: {lineMsg}"); } switch (line.ElementAt(0)) { case "Goto": if (line.Count < 2) { Warn("Not enough arguments to function 'Goto'!"); } else { if (line.Count > 2) { Warn("Unexpected extra arguments to function 'Goto'"); } skipTo = $"Label {line.ElementAt(1)}"; flowControl.Clear(); } break; case "Label": break; case "If": flowControl.Push(new FlowControlStruct(i, FunctionIf(line))); break; case "IfNot": flowControl.Push(new FlowControlStruct(i, !FunctionIf(line))); break; case "Else": if (flowControl.Count != 0 && flowControl.Peek().Type == 0) { flowControl.Peek().Active = false; } else { Warn("Unexpected Else"); } break; case "EndIf": if (flowControl.Count != 0 && flowControl.Peek().Type == 0) { flowControl.Pop(); } else { Warn("Unexpected EndIf"); } break; case "Select": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, false, false))); break; case "SelectMany": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, false, false))); break; case "SelectWithPreview": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, true, false))); break; case "SelectManyWithPreview": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, true, false))); break; case "SelectWithDescriptions": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, false, true))); break; case "SelectManyWithDescriptions": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, false, true))); break; case "SelectWithDescriptionsAndPreviews": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, true, true))); break; case "SelectManyWithDescriptionsAndPreviews": flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, true, true))); break; case "SelectVar": flowControl.Push(new FlowControlStruct(i, FunctionSelectVar(line, true))); break; case "SelectString": flowControl.Push(new FlowControlStruct(i, FunctionSelectVar(line, false))); break; case "Break": { bool found = false; var fcs = flowControl.ToArray(); for (int k = 0; k < fcs.Length; k++) { if (fcs[k].Type != 1) { continue; } for (int j = 0; j <= k; j++) { fcs[j].Active = false; } found = true; break; } if (!found) { Warn("Unexpected Break"); } break; } case "Case": if (flowControl.Count == 0 || flowControl.Peek().Type != 1) { Warn("Unexpected Case"); } break; case "Default": if (flowControl.Count == 0 || flowControl.Peek().Type != 1) { Warn("Unexpected Default"); } break; case "EndSelect": if (flowControl.Count != 0 && flowControl.Peek().Type == 1) { flowControl.Pop(); } else { Warn("Unexpected EndSelect"); } break; case "For": { var fc = FunctionFor(line, i); flowControl.Push(fc); if (fc.Line != -1 && fc.Values.Length > 0) { Variables[fc.Var] = fc.Values[0]; fc.Active = true; } break; } case "Continue": { var found = false; var fcs = flowControl.ToArray(); for (int k = 0; k < fcs.Length; k++) { if (fcs[k].Type != 2) { continue; } fcs[k].ForCount++; if (fcs[k].ForCount == fcs[k].Values.Length) { for (int j = 0; j <= k; j++) { fcs[j].Active = false; } } else { i = fcs[k].Line; Variables[fcs[k].Var] = fcs[k].Values[fcs[k].ForCount]; for (int j = 0; j < k; j++) { flowControl.Pop(); } } found = true; break; } if (!found) { Warn("Unexpected Continue"); } break; } case "Exit": { bool found = false; var fcs = flowControl.ToArray(); for (int k = 0; k < fcs.Length; k++) { if (fcs[k].Type != 2) { continue; } for (int j = 0; j <= k; j++) { flowControl.Peek().Active = false; } found = true; break; } if (!found) { Warn("Unexpected Exit"); } break; } case "EndFor": if (flowControl.Count != 0 && flowControl.Peek().Type == 2) { var fc = flowControl.Peek(); fc.ForCount++; if (fc.ForCount == fc.Values.Length) { flowControl.Pop(); } else { i = fc.Line; Variables[fc.Var] = fc.Values[fc.ForCount]; } } else { Warn("Unexpected EndFor"); } break; //Functions case "DontInstallAnyPlugins": Srd.InstallAllPlugins = false; break; case "DontInstallAnyDataFiles": Srd.InstallAllData = false; break; case "InstallAllPlugins": Srd.InstallAllPlugins = true; break; case "InstallAllDataFiles": Srd.InstallAllData = true; break; case "FatalError": Utils.Error("Script called FatalError!"); Srd.CancelInstall = true; break; case "Return": Break = true; break; case "AllowRunOnLines": allowRunOnLines = true; break; default: break; } } if (Break || Srd.CancelInstall) { break; } } if (skipTo != null) { Warn($"Expected: {skipTo}!"); } var temp = Srd; Srd = null; Variables = null; return(temp); }