aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/src/Godosa.Core/Runs/Scripts/ScriptProgram.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Godosa.Core/Runs/Scripts/ScriptProgram.cs')
-rw-r--r--src/Godosa.Core/Runs/Scripts/ScriptProgram.cs57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/Godosa.Core/Runs/Scripts/ScriptProgram.cs b/src/Godosa.Core/Runs/Scripts/ScriptProgram.cs
new file mode 100644
index 0000000..502e24c
--- /dev/null
+++ b/src/Godosa.Core/Runs/Scripts/ScriptProgram.cs
@@ -0,0 +1,57 @@
+// Provenance: own design — shared run scripts
+namespace Godosa.Core.Runs.Scripts;
+
+public enum Op { Verb, Wait, Expect, Set, Checkpoint, LabelBegin, LabelEnd, ScopeBegin, ScopeEnd, TryBegin, TryEnd, SetupBegin, SetupEnd }
+
+/// <summary>One flattened instruction. <see cref="Chain"/> = include / call sites, outermost first.</summary>
+public sealed record Instr(Op Op, SourceRef At, string Text, IReadOnlyList<SourceRef> Chain, int Format)
+{
+ public string A { get; init; } = "";
+ public string B { get; init; } = "";
+ public int Timeout { get; init; }
+ public IReadOnlyList<KeyValuePair<string, string>> Bindings { get; init; } = [];
+ public bool LocalVars { get; init; }
+ public int Jump { get; init; } = -1;
+}
+
+public sealed record ScriptProgram(string Entry, RunMode Mode, ulong? Seed, IReadOnlyDictionary<string, string> Vars,
+ IReadOnlySet<string> Locked, IReadOnlyList<Instr> Code, IReadOnlyList<ScriptError> Errors);
+
+public interface IScriptSource
+{
+ string? Read(string path);
+}
+
+public sealed class MemoryScriptSource(IReadOnlyDictionary<string, string> files) : IScriptSource
+{
+ public string? Read(string path) => files.GetValueOrDefault(path);
+}
+
+/// <summary>Files under <paramref name="root"/>; paths are '/'-separated and relative to it.</summary>
+public sealed class FileScriptSource(string root) : IScriptSource
+{
+ public string? Read(string path)
+ {
+ var full = Path.GetFullPath(Path.Combine(root, path));
+ return File.Exists(full) ? File.ReadAllText(full) : null;
+ }
+}
+
+public static class ScriptPaths
+{
+ public static string Resolve(string fromFile, string relative)
+ {
+ var dir = fromFile.Contains('/') ? fromFile[..fromFile.LastIndexOf('/')] : "";
+ var parts = new List<string>(dir.Length == 0 ? [] : dir.Split('/'));
+ foreach (var part in relative.Replace('\\', '/').Split('/'))
+ {
+ if (part is "" or ".")
+ continue;
+ if (part == ".." && parts.Count > 0)
+ parts.RemoveAt(parts.Count - 1);
+ else if (part != "..")
+ parts.Add(part);
+ }
+ return string.Join('/', parts);
+ }
+}