-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathBlock.cs
More file actions
115 lines (94 loc) · 3.61 KB
/
Copy pathBlock.cs
File metadata and controls
115 lines (94 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using BlocklyNet.Scripting.Debugger;
namespace BlocklyNet.Core.Model;
/// <summary>
/// Describes a single block in the script. A block may produce
/// a result and may execute the next block in chain.
/// </summary>
public abstract class Block
{
/// <summary>
/// Unique identifier of the block.
/// </summary>
public string Id { get; set; } = null!;
/// <summary>
/// Unset to exclude this block from execution.
/// </summary>
public bool Enabled { get; set; } = true;
/// <summary>
/// All fields (constant values) of the block.
/// </summary>
public Fields Fields { get; } = new();
/// <summary>
/// All (dynamic) values of the block - actually other
/// blocks producing the value.
/// </summary>
public Values Values { get; } = new();
/// <summary>
/// All statements of the block - more or less variant
/// of (dynamic) values.
/// </summary>
public Statements Statements { get; } = new();
/// <summary>
/// The type of the block.
/// </summary>
public string Type { get; set; } = null!;
/// <summary>
/// Next block in chain.
/// </summary>
public Block? Next { get; set; }
/// <summary>
/// All mutation (extra settings) of the block.
/// </summary>
public IList<Mutation> Mutations { get; } = [];
/// <summary>
/// All comments for the block.
/// </summary>
public IList<Comment> Comments { get; } = [];
/// <inheritdoc/>
protected virtual async Task<object?> EvaluateAsync(Context context)
{
/* Always check for cancel before proceeding with the execution of the next block in chain. */
context.Cancellation.ThrowIfCancellationRequested();
/* Check for early stop. */
if (context.Engine.CurrentScript?.Options?.ShouldStopNow?.Invoke() == true)
throw new ScriptStoppedEarlyException();
/* Run the next block if we are not forcefully exiting a loop. */
if (context.EscapeMode == EscapeMode.None)
for (var next = Next; next != null; next = next.Next)
if (next.Enabled)
return await next.EnterBlockAsync(context);
return null;
}
/// <summary>
/// Start a brand new block execution chain.
/// </summary>
/// <param name="context">Current operation context.</param>
/// <param name="isScript">Set when we are executing the full script.</param>
/// <returns>Result of the block if any.</returns>
public async Task<object?> EnterBlockAsync(Context context, bool isScript = false)
{
/* Wait for debugger to allow execution - we enter a new chain of execution, e.g. calculating a value or control block. */
await context.Engine.SingleStepAsync(this, context, ScriptDebuggerStopReason.Enter);
/* Execute the block itself. */
object? result = null;
try
{
result = await EvaluateAsync(context);
}
catch (Exception e)
{
/* Run exception throw debugger. */
var exception = await context.Engine.CatchExceptionAsync(this, context, e);
if (exception != null)
if (exception == e)
throw;
else
throw exception;
}
/* Wait for debugger to allow execution - the current block as finished its work. */
await context.Engine.SingleStepAsync(this, context, ScriptDebuggerStopReason.Leave);
/* Script is done. */
if (isScript) await context.Engine.SingleStepAsync(this, context, ScriptDebuggerStopReason.ScriptDone);
return result;
}
}