BadScript 2
Loading...
Searching...
No Matches
BadRuntimeApi.cs
Go to the documentation of this file.
1using System.Globalization;
2using System.Reflection;
3using System.Runtime.InteropServices;
6using BadScript2.IO;
24
26
30[BadInteropApi("Runtime")]
31internal partial class BadRuntimeApi
32{
36 public static IEnumerable<string>? StartupArguments { get; set; }
37
38 protected override void AdditionalData(BadTable target)
39 {
40 target.SetProperty("Native", MakeNative());
41 }
42
48 {
49 BadTable table = new BadTable();
50
51 new BadNativeApi().LoadRawApi(table);
52
53 return table;
54 }
55
56 [BadMethod(description: "Creates a default scope based off of the root scope of the caller")]
57 [return: BadReturn("The created scope")]
59 {
60 return ctx.Scope.GetRootScope()
61 .CreateChild("<customscope>", ctx.Scope, null);
62 }
63
64 [BadMethod(description: "Evaluates a BadScript Source String")]
65 [return: BadReturn("An Awaitable Task")]
67 [BadParameter(description: "The Source of the Script")]
68 string source,
69 [BadParameter(description:
70 "An (optional but recommended) file path, it will be used to determine the working directory of the script."
71 )]
72 string? file = null,
73 [BadParameter(description:
74 "If true, any optimizations that are activated in the settings will be applied."
75 )]
76 bool optimize = true,
77 [BadParameter(description:
78 "An (optional) scope that the execution takes place in, if not specified, an Instance of BadRuntime will get searched and a scope will be created from it, if its not found, a scope will be created from the root scope of the caller."
79 )]
80 BadScope? scope = null,
81 [BadParameter(description:
82 "If true, the last element that was returned from the enumeration will be the result of the task. Otherwise the result will be the exported objects of the script."
83 )]
84 bool setLastAsReturn = false)
85 {
86 file = BadFileSystem.Instance.GetFullPath(file ?? "<eval>");
87
88 bool optimizeConstantFolding =
89 BadNativeOptimizationSettings.Instance.UseConstantFoldingOptimization && optimize;
90
91 bool optimizeConstantSubstitution =
92 BadNativeOptimizationSettings.Instance.UseConstantSubstitutionOptimization && optimize;
93
95 BadRuntime? runtime = caller.Scope.GetSingleton<BadRuntime>();
96
97 if (runtime != null && scope == null)
98 {
99 // If the runtime is available, we can use the context builder to create a new context.
100 // This is cleaner and also works better with the use of the Export Expressions.
101 ctx = runtime.CreateContext(Path.GetDirectoryName(file) ?? "/");
102 }
103 else
104 {
105 // The Old way of doing it. This was a hack initially to ensure the configured interop apis are available in the scope,
106 // even if we dont have a way to access the context builder.
107 ctx =
108 scope == null
109 ? new BadExecutionContext(caller.Scope.GetRootScope()
110 .CreateChild("<EvaluateAsync>",
111 caller.Scope,
112 null,
113 BadScopeFlags.CaptureThrow
114 )
115 )
116 : new BadExecutionContext(scope);
117 }
118
119 IEnumerable<BadExpression> exprs = BadSourceParser.Create(file, source)
120 .Parse();
121
122 if (optimizeConstantFolding)
123 {
125 }
126
127 if (optimizeConstantSubstitution)
128 {
130 }
131
132 BadTask task = null!;
133
134 IEnumerable<BadObject> executor;
135
136 if (setLastAsReturn) //If we want the last object as the return value, we just execute
137 {
138 executor = ctx.Execute(exprs);
139 }
140 else //Otherwise we return the exported variables of the script
141 {
142 executor = ExecuteScriptWithExports(ctx, exprs);
143 }
144
145 task = new BadTask(new BadInteropRunnable(
146 // ReSharper disable once AccessToModifiedClosure
147 SafeExecute(executor, ctx, () => task)
148 .GetEnumerator(),
149 true
150 ),
151 "EvaluateAsync"
152 );
153
154 return task;
155 }
156
157 [BadMethod(description: "Returns the Stack Trace of the current Execution Context")]
158 [return: BadReturn("The Stack Trace")]
160 {
161 return ctx.Scope.GetStackTrace();
162 }
163
164
165 [BadMethod]
167 {
168 return ctx.Scope.GetRootScope();
169 }
170
171
172 [BadMethod(description: "Returns all Native Types")]
173 [return: BadReturn("An Array containing all Native Types")]
175 {
177 .ToList()
178 );
179 }
180
181 [BadMethod(description: "Returns the Assembly Path of the current Runtime")]
182 [return: BadReturn("The Assembly Path")]
183 private string GetRuntimeAssemblyPath()
184 {
185 string path = Path.ChangeExtension(Assembly.GetEntryAssembly()!.Location,
186 RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "exe" : ""
187 );
188
189 return path;
190 }
191
192 [BadMethod(description: "Returns a new Guid")]
193 [return: BadReturn("A new Guid")]
194 private string NewGuid()
195 {
196 return Guid.NewGuid()
197 .ToString();
198 }
199
200 [BadMethod(description: "Returns true if an api with that name is registered")]
201 [return: BadReturn("True if the api is registered")]
202 private BadObject IsApiRegistered(BadExecutionContext ctx, [BadParameter(description: "The Api Name")] string api)
203 {
204 return ctx.Scope.RegisteredApis.Contains(api);
205 }
206
207 [BadMethod(description: "Creates a new Reference Object")]
208 [return: BadReturn("The Reference Object")]
210 [BadParameter(description: "The Text for the Reference")]
211 string refText,
212 [BadParameter(description: "The getter Function")]
213 BadFunction get,
214 [BadParameter(description: "The setter Function")]
215 BadFunction? set = null,
216 [BadParameter(description: "The delete Function")]
217 BadFunction? delete = null)
218 {
219 if (set == null && delete == null)
220 {
221 return BadObjectReference.Make(refText, (p) => GetReferenceValue(ctx, get));
222 }
223
224 if (delete == null && set != null)
225 {
226 return BadObjectReference.Make(refText,
227 (p) => GetReferenceValue(ctx, get),
228 (value, _, _) => SetReferenceValue(ctx, set, value)
229 );
230 }
231
232 if (delete != null && set == null)
233 {
234 return BadObjectReference.Make(refText,
235 (p) => GetReferenceValue(ctx, get),
236 (Action<BadObject, BadSourcePosition?, BadPropertyInfo?>?)null,
237 (p) => SetReferenceValue(ctx, delete, BadObject.Null)
238 );
239 }
240
241 return BadObjectReference.Make(refText,
242 (p) => GetReferenceValue(ctx, get),
243 (value, _, _) => SetReferenceValue(ctx, set!, value),
244 (p) => DeleteReference(ctx, delete!)
245 );
246 }
247
249 {
250 foreach (BadObject? o in func.Invoke(Array.Empty<BadObject>(), ctx)) { }
251 }
252
254 {
255 BadObject? result = BadObject.Null;
256
257 foreach (BadObject? o in func.Invoke(Array.Empty<BadObject>(), ctx))
258 {
259 result = o;
260 }
261
262 return result.Dereference(null);
263 }
264
266 {
267 foreach (BadObject? o in func.Invoke(new[] { value },
268 ctx
269 )) { }
270 }
271
272 [BadMethod(description: "Returns all registered apis")]
273 [return: BadReturn("An Array containing all registered apis")]
275 {
276 return new BadArray(ctx.Scope.RegisteredApis.Select(x => (BadObject)x)
277 .ToList()
278 );
279 }
280
288 [BadMethod(description: "Registers an Import Handler")]
290 [BadParameter(description:
291 "An Import handler implementing the IImportHandler Interface",
292 nativeType: "IImportHandler"
293 )]
294 BadClass cls)
295 {
296 BadClassPrototype proto = cls.GetPrototype();
297
298 if (!BadNativeClassBuilder.ImportHandler.IsSuperClassOf(proto))
299 {
300 throw BadRuntimeException.Create(ctx.Scope, "Invalid Import Handler");
301 }
302
303 BadModuleImporter? importer = ctx.Scope.GetSingleton<BadModuleImporter>();
304
305 if (importer == null)
306 {
307 throw BadRuntimeException.Create(ctx.Scope, "Module Importer not found");
308 }
309
310 BadInteropImportHandler handler = new BadInteropImportHandler(ctx, cls);
311 importer.AddHandler(handler);
312 }
313
320 [BadMethod("Validate", "Validates a source string")]
321 [return: BadReturn("Validation Result")]
322 private static BadTable ValidateSource([BadParameter(description: "The Source to Validate")] string source,
323 [BadParameter(description: "The File Name")] string file)
324 {
327 BadTable ret = new BadTable();
328 ret.SetProperty("IsError", result.IsError);
329
330 ret.SetProperty("Messages",
331 new BadArray(result.Messages.Select(x =>
332 {
333 BadTable msg = new BadTable();
334 msg.SetProperty("Message", x.Message);
335 msg.SetProperty("Validator", x.Validator.ToString());
336 msg.SetProperty("Type", x.Type.ToString());
337
338 msg.SetProperty("Position",
339 x.Expression.Position.ToString()
340 );
341
342 return (BadObject)msg;
343 }
344 )
345 .ToList()
346 )
347 );
348 ret.SetFunction("GetMessageString", () => result.ToString(), BadNativeClassBuilder.GetNative("string"));
349
350 return ret;
351 }
352
358 [BadMethod(description: "Parses a date string")]
359 [return: BadReturn("Bad Table with the parsed date")]
360 private static BadObject ParseDate([BadParameter(description: "The date string")] string date)
361 {
362 DateTimeOffset d = DateTimeOffset.Parse(date);
363
364 return new BadDate(d);
365 }
366
371 [BadMethod(description: "Returns the Current Time")]
372 [return: BadReturn("The Current Time")]
373 private static BadObject GetTimeNow()
374 {
375 return BadDate.Now;
376 }
377
384 [BadMethod(description: "Lists all extension names of the given object")]
385 [return: BadReturn("An Array containing all Extension Names")]
387 [BadParameter(description: "Object")] BadObject o)
388 {
389 return new BadArray(ctx.Scope.Provider.GetExtensionNames(o)
390 .ToList()
391 );
392 }
399 [BadMethod(description: "Returns all Extensions of the given object(will create the objects based on the supplied object)")]
400 [return: BadReturn("A Table containing all Extensions")]
402 [BadParameter(description: "Object")] BadObject o)
403 {
404 return ctx.Scope.Provider.GetExtensions(o);
405 }
406
411 [BadMethod(description: "Lists all global extension names")]
412 [return: BadReturn("An Array containing all Extension Names")]
414 {
415 return new BadArray(ctx.Scope.Provider.GetExtensionNames()
416 .ToList()
417 );
418 }
419
424 [BadMethod(description: "Gets the Commandline Arguments")]
425 [return: BadReturn("An Array containing all Commandline Arguments")]
426 private static BadArray GetArguments()
427 {
428 return StartupArguments == null
429 ? new BadArray()
430 : new BadArray(StartupArguments.Select(x => (BadObject)x)
431 .ToList()
432 );
433 }
434
435
436 [BadMethod(description: "Gets the Attributes of the given objects members")]
437 [return: BadReturn("A Table containing the Attributes of the given objects members.")]
438 private static BadArray GetMembers(BadObject obj)
439 {
440 if (obj is BadClass cls)
441 {
442 return cls.Scope.GetMemberInfos();
443 }
444
445 return new BadArray();
446 }
447
454 private IEnumerable<BadObject> ExecuteScriptWithExports(BadExecutionContext ctx, IEnumerable<BadExpression> exprs)
455 {
456 foreach (BadObject o in ctx.Execute(exprs))
457 {
458 yield return o;
459 }
460
461 yield return ctx.Scope.GetExports();
462 }
463
471 private static IEnumerable<BadObject> SafeExecute(IEnumerable<BadObject> script,
473 Func<BadTask> getTask)
474 {
475 using IEnumerator<BadObject>? enumerator = script.GetEnumerator();
476
477 while (true)
478 {
479 try
480 {
481 if (!enumerator.MoveNext())
482 {
483 break;
484 }
485 }
487 {
488 getTask()
489 .Runnable.SetError(e.Error);
490
491 break;
492 }
493 catch (Exception e)
494 {
495 getTask()
496 .Runnable.SetError(BadRuntimeError.FromException(e, ctx.Scope.GetStackTrace()));
497
498 break;
499 }
500
501 yield return enumerator.Current ?? BadObject.Null;
502 }
503 }
504}
Exposes the BadScript Runtime Functionality to Consumers.
Definition BadRuntime.cs:30
BadExecutionContext CreateContext(string workingDirectory)
Creates a new Context with the configured Options.
Public interface for the filesystem abstraction of the BadScript Engine.
static IFileSystem Instance
File System implementation.
static BadArray GetMembers(BadObject obj)
BadScope GetRootScope(BadExecutionContext ctx)
static IEnumerable< BadObject > SafeExecute(IEnumerable< BadObject > script, BadExecutionContext ctx, Func< BadTask > getTask)
Wrapper that will execute a script and catch any errors that occur.
static BadObject ParseDate([BadParameter(description:"The date string")] string date)
Parses a date string.
BadArray GetRegisteredApis(BadExecutionContext ctx)
IEnumerable< BadObject > ExecuteScriptWithExports(BadExecutionContext ctx, IEnumerable< BadExpression > exprs)
Executes a script and returns the exported variables.
static BadTable ValidateSource([BadParameter(description:"The Source to Validate")] string source, [BadParameter(description:"The File Name")] string file)
Validates a source string.
BadObject IsApiRegistered(BadExecutionContext ctx, [BadParameter(description:"The Api Name")] string api)
void DeleteReference(BadExecutionContext ctx, BadFunction func)
static ? IEnumerable< string > StartupArguments
The Startup Arguments that were passed to the Runtime.
string GetStackTrace(BadExecutionContext ctx)
void SetReferenceValue(BadExecutionContext ctx, BadFunction func, BadObject value)
static BadTable GetExtensions(BadExecutionContext ctx, [BadParameter(description:"Object")] BadObject o)
Returns all Extensions of the given object(will create the objects based on the supplied object)
BadObject MakeReference(BadExecutionContext ctx, [BadParameter(description:"The Text for the Reference")] string refText, [BadParameter(description:"The getter Function")] BadFunction get, [BadParameter(description:"The setter Function")] BadFunction? set=null, [BadParameter(description:"The delete Function")] BadFunction? delete=null)
BadObject GetReferenceValue(BadExecutionContext ctx, BadFunction func)
override void AdditionalData(BadTable target)
BadScope CreateDefaultScope(BadExecutionContext ctx)
static void RegisterImportHandler(BadExecutionContext ctx, [BadParameter(description:"An Import handler implementing the IImportHandler Interface", nativeType:"IImportHandler")] BadClass cls)
Registers an Import Handler.
BadTask EvaluateAsync(BadExecutionContext caller, [BadParameter(description:"The Source of the Script")] string source, [BadParameter(description:"An (optional but recommended) file path, it will be used to determine the working directory of the script.")] string? file=null, [BadParameter(description:"If true, any optimizations that are activated in the settings will be applied.")] bool optimize=true, [BadParameter(description:"An (optional) scope that the execution takes place in, if not specified, an Instance of BadRuntime will get searched and a scope will be created from it, if its not found, a scope will be created from the root scope of the caller.")] BadScope? scope=null, [BadParameter(description:"If true, the last element that was returned from the enumeration will be the result of the task. Otherwise the result will be the exported objects of the script.")] bool setLastAsReturn=false)
static BadArray GetExtensionNames(BadExecutionContext ctx, [BadParameter(description:"Object")] BadObject o)
Returns all Extension Names of the given object.
static BadArray GetArguments()
Returns the arguments passed to the script.
BadTable MakeNative()
Creates the "Native" Table.
static BadObject GetTimeNow()
Returns the Current Time.
static BadObject GetGlobalExtensionNames(BadExecutionContext ctx)
Lists all global extension names.
Implements a Runnable that can return a value.
Implements a Task Object.
Definition BadTask.cs:17
static BadExpression Optimize(BadExpression expr)
Optimizes the given expression.
Contains the Implementation of the Constant Substitution Optimization This optimization replaces expr...
static IEnumerable< BadExpression > Optimize(BadConstantSubstitutionOptimizerScope scope, IEnumerable< BadExpression > expressions)
Substitutes all variables in the expressions with their constant value.
The Parser of the Language. It turns Source Code into an Expression Tree.
static BadSourceParser Create(string fileName, string source)
Creates a BadSourceParser Instance based on the source and filename provided.
static IEnumerable< BadExpression > Parse(string fileName, string source)
Parses a BadExpression from the Source Reader.
The Execution Context. Every execution of a script needs a context the script is running in....
IEnumerable< BadObject > Execute(IEnumerable< BadExpression > expressions)
Executes an enumeration of expressions.
BadScope Scope
The Root Scope of the Context.
Implements the Scope for the Script Engine.
Definition BadScope.cs:16
BadScope GetRootScope()
Returns the Root Scope of the Scope.
Definition BadScope.cs:304
BadScope CreateChild(string name, BadScope? caller, bool? useVisibility, BadScopeFlags flags=BadScopeFlags.RootScope)
Creates a subscope of the current scope.
Definition BadScope.cs:597
string GetStackTrace()
Returns the Stack Trace of the Current scope.
Definition BadScope.cs:419
Gets thrown if the runtime encounters an error.
Implements the Error Object Type.
static BadRuntimeError FromException(Exception e, string? scriptStackTrace=null)
Creates a BadRuntimeError from an Exception.
static BadRuntimeException Create(BadScope? scope, string message)
Creates a new BadScriptException.
Implements an Interop API for the BS2 Language.
The Class that manages the importing of modules.
BadModuleImporter AddHandler(BadImportHandler handler)
Adds a new Import Handler to the Importer.
Implements a Dynamic List/Array for the BadScript Language.
Definition BadArray.cs:17
The Base Class for all BadScript Objects.
Definition BadObject.cs:14
static readonly BadObject Null
The Null Value for the BadScript Language.
Definition BadObject.cs:28
Implements the base functionality for a BadScript Reference.
static BadObjectReference Make(string refText, Func< BadSourcePosition?, BadObject > getter, Action< BadObject, BadSourcePosition?, BadPropertyInfo?>? setter=null, Action< BadSourcePosition?>? delete=null)
Creates a new Reference Object.
Implements a Table Structure for the BadScript Language.
Definition BadTable.cs:14
Implements a function that can be called from the script.
Implements a Type Instance in the BadScript Language.
Definition BadClass.cs:11
Implements a Class Prototype for the BadScript Language.
Helper Class that Builds a Native Class from a Prototype.
static BadClassPrototype GetNative(string name)
Returns a Native Class Prototype for the given Native Type.
static IEnumerable< BadClassPrototype > NativeTypes
Enumeration of all Native Class Prototypes.
string GetFullPath(string path)
Returns the full path of the given path.
Contains Shared Data Structures and Functionality.
Contains IO Implementation for the BadScript2 Runtime.
Contains Common Interop APIs for the BadScript2 Runtime.
Contains task/async Extensions and Integrations for the BadScript2 Runtime.
Contains the BadScript2 Constant Folding Optimizations.
Contains the BadScript2 Constant Substitution Optimizations.
Contains the Expressions for the BadScript2 Language.
Contains the Comparison Operators for the BadScript2 Language.
Contains the Parser for the BadScript2 Language.
Contains the Error Objects for the BadScript2 Language.
Contains the Extension Classes for Functions.
Contains the Interop Function Classes for the BadScript2 Language.
Contains the Interop Abstractions and Implementations for the BadScript2 Language.
Contains Runtime Function Objects.
Contains the Native Runtime Objects.
Definition BadBoolean.cs:6
Contains the Runtime Objects.
Definition BadArray.cs:10
Contains Runtime Settings Objects.
Contains the Runtime Implementation.
BadScopeFlags
Defines Different Behaviours for the Current Scope.
bool IsError
Indicates whether there are any messages of type Error.
static BadExpressionValidatorContext Validate(IEnumerable< BadExpression > expressions)
Validates the given expressions.
override string ToString()
Returns a string representation of the validation results.
IReadOnlyList< BadExpressionValidatorMessage > Messages
The messages generated by the validators.