forked from ZeraGmbH/Blockly.Net
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathValues.cs
More file actions
126 lines (108 loc) · 4.84 KB
/
Copy pathValues.cs
File metadata and controls
126 lines (108 loc) · 4.84 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
116
117
118
119
120
121
122
123
124
125
126
using Microsoft.Extensions.DependencyInjection;
namespace BlocklyNet.Core.Model;
/// <summary>
/// All values in a block.
/// </summary>
public class Values : Entities<Value>
{
/// <summary>
/// Retrieve the key to use for value identification.
/// </summary>
/// <param name="value">Some value.</param>
/// <returns>The name of the value.</returns>
protected override string GetKey(Value value) => value.Name;
/// <summary>
/// Evaluate a single value.
/// </summary>
/// <param name="name">Name of the value.</param>
/// <param name="context">Execution context.</param>
/// <param name="required">If set the indicated value must exist.</param>
/// <returns>Current result of the value.</returns>
/// <exception cref="ArgumentException">Value does not exist.</exception>
public Task<object?> EvaluateAsync(string name, Context context, bool required = true)
{
/* See if the value is known */
var value = TryGet(name);
if (value == null)
{
/* The value is optional so just indicate a null result. */
if (!required) return Task.FromResult((object?)null);
/* Value must exist so throw an exception. */
throw new ArgumentException($"value {name} not found");
}
/* Before executing see if the script should be cancelled. */
context.Cancellation.ThrowIfCancellationRequested();
/* Try to evaluate the value. */
return value.EvaluateAsync(context);
}
/// <summary>
/// Get a number - may be auto-converted from some other type.
/// </summary>
/// <param name="name">Name of the parameter.</param>
/// <param name="context">Operation context.</param>
/// <returns>Requested number.</returns>
public async Task<double> EvaluateDoubleAsync(string name, Context context)
=> (await EvaluateOptionalDoubleAsync(name, context)) ?? throw new ArgumentException($"value {name} not found");
/// <summary>
/// Get an optional number - may be auto-converted from some other type.
/// </summary>
/// <param name="name">Name of the parameter.</param>
/// <param name="context">Operation context.</param>
/// <returns>Requested number or null.</returns>
public async Task<double?> EvaluateOptionalDoubleAsync(string name, Context context)
{
/* Retrieve raw value. */
var raw = await EvaluateAsync(name, context, false);
/* Make it a double number. */
return raw == null ? null : TryConvertToDouble(raw, context, out var num) ? num : (double)raw;
}
/// <summary>
/// Try to convert a given value to double precision floating point number.
/// </summary>
/// <param name="raw">Raw value - can be anything.</param>
/// <param name="context">Current operating context.</param>
/// <param name="value">Raw value as number.</param>
/// <returns>Set if the value contains the requested number.</returns>
public static bool TryConvertToDouble(object raw, Context context, out double value)
{
/* Already a number - extend as needed, left out long because conversion is not always lossless. */
if (raw is double doubleNum) { value = doubleNum; return true; }
if (raw is float floatNum) { value = floatNum; return true; }
if (raw is uint uintNum) { value = uintNum; return true; }
if (raw is int intNum) { value = intNum; return true; }
if (raw is ushort ushortNum) { value = ushortNum; return true; }
if (raw is short shortNum) { value = shortNum; return true; }
if (raw is byte byteNum) { value = byteNum; return true; }
if (raw is sbyte sByteNum) { value = sByteNum; return true; }
value = default;
/* Check for converter. */
var cvt = context.ServiceProvider.GetService<IDoubleExtractor>();
if (cvt == null) return false;
/* Run converter - report cast error on mismatch. */
try
{
value = cvt.GetNumber(raw);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Evaluate a single value.
/// </summary>
/// <param name="name">Name of the value.</param>
/// <param name="context">Execution context.</param>
/// <param name="required">If set the indicated value must exist.</param>
/// <typeparam name="T">Expected result type.</typeparam>
/// <returns>Current result of the value.</returns>
/// <exception cref="ArgumentException">Value does not exist.</exception>
public async Task<T> EvaluateAsync<T>(string name, Context context, bool required = true)
{
/* Execute the script. */
var result = await EvaluateAsync(name, context, required);
/* Try to change type of result if possible. */
return result == null ? default! : (T)result;
}
}