Skip to content

Commit f87fa5b

Browse files
committed
allow MutableScripts to be directly executed
merges the shared logic into a base class to be inherited by Script and MutableScript; changed existing usages of Script to ExecutableScript. This change allows you more flexibility in setting up your own Starscript compilation pipeline, and even the ability to precompile scripts and then just load their files (compile, save, stop the program, load the file, works as if it was just compiled) if you want; since all the Hypervisor expects is an RO span of Value constants and bytes for code, with a few helpers that exist on the base class.
1 parent e548ee1 commit f87fa5b

File tree

5 files changed

+90
-48
lines changed

5 files changed

+90
-48
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace Starscript.Internal;
2+
3+
public abstract class ExecutableScript : IDisposable
4+
{
5+
public bool IsDisposed { get; protected set; }
6+
7+
public abstract ReadOnlySpan<byte> Code { get; }
8+
9+
public abstract ReadOnlySpan<Value> Constants { get; }
10+
11+
public virtual byte GetByteAt(int idx) => Code[idx];
12+
13+
public int GetMaskedByteAt(int idx) => GetByteAt(idx) & 0xFF;
14+
15+
public StringSegment Execute(StarscriptHypervisor hypervisor)
16+
{
17+
if (IsDisposed)
18+
throw new ObjectDisposedException(nameof(ExecutableScript), "Cannot execute a disposed Script.");
19+
20+
return hypervisor.Run(this);
21+
}
22+
23+
public StringSegment Execute(StarscriptHypervisor hypervisor, ValueMap locals)
24+
{
25+
if (IsDisposed)
26+
throw new ObjectDisposedException(nameof(ExecutableScript), "Cannot execute a disposed Script.");
27+
28+
return hypervisor.Run(this, locals);
29+
}
30+
31+
public StringSegment Execute(StarscriptHypervisor hypervisor, IStarscriptObject obj)
32+
{
33+
if (IsDisposed)
34+
throw new ObjectDisposedException(nameof(ExecutableScript), "Cannot execute a disposed Script.");
35+
36+
return hypervisor.Run(this, obj);
37+
}
38+
39+
public abstract void Dispose();
40+
}

src/Lib/Internal/MutableScript.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
using System.Runtime.CompilerServices;
2+
using System.Runtime.InteropServices;
23
using Starscript.Internal;
34
using Starscript.Util;
45

56
namespace Starscript;
67

7-
public class MutableScript
8+
public class MutableScript : ExecutableScript
89
{
9-
public List<Value> Constants { get; } = [];
10+
private readonly List<Value> _constants = [];
11+
12+
public override ReadOnlySpan<Value> Constants => CollectionsMarshal.AsSpan(_constants);
1013

1114
public ResizableBuffer<byte> CodeBuffer { get; } = new();
1215

16+
public override ReadOnlySpan<byte> Code => CodeBuffer.RoSpan;
17+
1318
public Script MoveToImmutable()
1419
{
1520
// Trim the excess (null) bytes before copying
@@ -20,7 +25,7 @@ public Script MoveToImmutable()
2025

2126
// Clear the current script's memory, potentially useful for a reusable script instance system in the future(?)
2227
CodeBuffer.ResetAndClear();
23-
Constants.Clear();
28+
_constants.Clear();
2429

2530
#if DEBUG
2631
Compiler.DebugLog($"Resulting immutable script size in bytes after move: {codeCopy.Length * Unsafe.SizeOf<byte>()}");
@@ -32,6 +37,8 @@ public Script MoveToImmutable()
3237
);
3338
}
3439

40+
#region Script writing
41+
3542
/// <summary>
3643
/// Write an <see cref="Instruction"/> to this <see cref="MutableScript"/>.
3744
/// </summary>
@@ -62,7 +69,7 @@ public void WriteConstant(Value constant)
6269
{
6370
var constIndex = -1;
6471

65-
foreach (var (idx, value) in Constants.Index())
72+
foreach (var (idx, value) in _constants.Index())
6673
{
6774
if (value == constant)
6875
{
@@ -73,10 +80,10 @@ public void WriteConstant(Value constant)
7380

7481
if (constIndex is -1)
7582
{
76-
constIndex = Constants.Count;
77-
Constants.Add(constant);
83+
constIndex = _constants.Count;
84+
_constants.Add(constant);
7885
}
79-
86+
8087
CodeBuffer.Write((byte)constIndex);
8188
}
8289

@@ -103,4 +110,24 @@ public void PatchJump(int offset)
103110
CodeBuffer.Span[offset] = (byte)((jump >> 8) & 0xFF);
104111
CodeBuffer.Span[offset + 1] = (byte)(jump & 0xFF);
105112
}
113+
114+
#endregion
115+
116+
public override void Dispose()
117+
{
118+
if (IsDisposed)
119+
throw new ObjectDisposedException(nameof(MutableScript), "Cannot dispose an already disposed Script.");
120+
121+
_constants.Clear();
122+
_constants.TrimExcess();
123+
CodeBuffer.ResetAndClear();
124+
125+
#if DEBUG
126+
Compiler.DebugLog("Destroyed mutable script");
127+
#endif
128+
129+
IsDisposed = true;
130+
131+
GC.SuppressFinalize(this);
132+
}
106133
}

src/Lib/Public/Entities/Script.cs

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,33 @@
1-
namespace Starscript;
1+
using Starscript.Internal;
22

3-
public class Script : IDisposable
3+
namespace Starscript;
4+
5+
public class Script : ExecutableScript
46
{
5-
private bool _disposed;
6-
77
private byte[] _code;
88
private Value[] _constants;
99

10-
public ReadOnlySpan<byte> Code => _code;
10+
public override ReadOnlySpan<byte> Code => _code;
1111

12-
public ReadOnlySpan<Value> Constants => _constants;
12+
public override ReadOnlySpan<Value> Constants => _constants;
1313

1414
public Script(byte[] codeBuffer, Value[] constants)
1515
{
1616
_code = codeBuffer;
1717
_constants = constants;
1818
}
1919

20-
public byte GetByteAt(int idx)
20+
public override byte GetByteAt(int idx)
2121
{
22-
if (_disposed)
22+
if (IsDisposed)
2323
throw new ObjectDisposedException(nameof(Script), "Cannot access bytecode of a disposed Script.");
2424

2525
return _code[idx];
2626
}
2727

28-
public int GetMaskedByteAt(int idx) => GetByteAt(idx) & 0xFF;
29-
30-
public StringSegment Execute(StarscriptHypervisor hypervisor)
31-
{
32-
if (_disposed)
33-
throw new ObjectDisposedException(nameof(Script), "Cannot execute a disposed Script.");
34-
35-
return hypervisor.Run(this);
36-
}
37-
38-
public StringSegment Execute(StarscriptHypervisor hypervisor, ValueMap locals)
39-
{
40-
if (_disposed)
41-
throw new ObjectDisposedException(nameof(Script), "Cannot execute a disposed Script.");
42-
43-
return hypervisor.Run(this, locals);
44-
}
45-
46-
public StringSegment Execute(StarscriptHypervisor hypervisor, IStarscriptObject obj)
47-
{
48-
if (_disposed)
49-
throw new ObjectDisposedException(nameof(Script), "Cannot execute a disposed Script.");
50-
51-
return hypervisor.Run(this, obj);
52-
}
53-
54-
public void Dispose()
28+
public override void Dispose()
5529
{
56-
if (_disposed)
30+
if (IsDisposed)
5731
throw new ObjectDisposedException(nameof(Script), "Cannot dispose an already disposed Script.");
5832

5933
Array.Resize(ref _code, 0);
@@ -63,7 +37,7 @@ public void Dispose()
6337
Compiler.DebugLog("Destroyed script");
6438
#endif
6539

66-
_disposed = true;
40+
IsDisposed = true;
6741

6842
GC.SuppressFinalize(this);
6943
}

src/Lib/Public/Hypervisor/Starscript.HV.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Starscript;
66

77
public partial class StarscriptHypervisor
88
{
9-
internal StringSegment RunImpl(Script script, StringBuilder sb)
9+
internal StringSegment RunImpl(ExecutableScript script, StringBuilder sb)
1010
{
1111
_stack.Clear();
1212

src/Lib/Public/Starscript.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Diagnostics.CodeAnalysis;
22
using System.Runtime.CompilerServices;
33
using System.Text;
4+
using Starscript.Internal;
45
using Starscript.Util;
56

67
namespace Starscript;
@@ -59,20 +60,20 @@ public StarscriptHypervisor ReplaceLocals(ValueMap locals)
5960
public StarscriptHypervisor ReplaceLocals(IStarscriptObject locals)
6061
=> ReplaceLocals(locals.ToStarscript());
6162

62-
public StringSegment Run(Script script) => RunImpl(script, new StringBuilder());
63+
public StringSegment Run(ExecutableScript script) => RunImpl(script, new StringBuilder());
6364

6465
/// <summary>
6566
/// Calls <see cref="Run(Script)"/> after calling <see cref="ReplaceLocals(Starscript.ValueMap)"/>.
6667
/// </summary>
6768
/// <remarks>The internal locals map has been reset by the time this method returns, if persistent locals is disabled.</remarks>
68-
public StringSegment Run(Script script, ValueMap locals)
69+
public StringSegment Run(ExecutableScript script, ValueMap locals)
6970
=> ReplaceLocals(locals).Run(script);
7071

7172
/// <summary>
7273
/// Calls <see cref="Run(Script)"/> after calling <see cref="ReplaceLocals(Starscript.IStarscriptObject)"/>.
7374
/// </summary>
7475
/// <remarks>The internal locals map has been reset by the time this method returns, if persistent locals is disabled.</remarks>
75-
public StringSegment Run(Script script, IStarscriptObject locals)
76+
public StringSegment Run(ExecutableScript script, IStarscriptObject locals)
7677
=> ReplaceLocals(locals).Run(script);
7778

7879
#if DEBUG

0 commit comments

Comments
 (0)