180 lines
6.3 KiB
C#
180 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using Upsilon.BaseTypes;
|
|
using Upsilon.BaseTypes.UserData;
|
|
using Upsilon.Binder;
|
|
using Upsilon.Parser;
|
|
using Upsilon.StandardLibraries;
|
|
using Upsilon.Text;
|
|
using Upsilon.Utilities;
|
|
|
|
namespace Upsilon.Evaluator
|
|
{
|
|
public class Script : IDisposable
|
|
{
|
|
public string FileName { get; }
|
|
public ScriptOptions Options { get; }
|
|
private readonly string _scriptString;
|
|
public SourceText ScriptString { get; }
|
|
private Evaluator Evaluator { get; }
|
|
private BlockStatementSyntax _parsed;
|
|
private BoundScript _bound;
|
|
public Diagnostics Diagnostics { get; }
|
|
private Binder.Binder Binder { get; }
|
|
private EvaluationScope Scope { get; }
|
|
public List<string> ModuleDependencies { get; } = new List<string>();
|
|
|
|
internal Script(string scriptString, string fileName, ScriptOptions options )
|
|
{
|
|
FileName = fileName;
|
|
Options = options;
|
|
_scriptString = scriptString;
|
|
ScriptString = new SourceText(scriptString);
|
|
Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError, fileName);
|
|
|
|
var staticBoundScope = options.OverrideStaticBoundScope ?? StaticScope.BoundScope;
|
|
var boundScope = BoundScope.WithReadOnlyScope(staticBoundScope);
|
|
Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, boundScope, this);
|
|
|
|
var staticScope = options.OverrideStaticScope ?? StaticScope.Scope;
|
|
Scope = EvaluationScope.CreateWithGetOnlyParent(staticScope);
|
|
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope, this);
|
|
}
|
|
|
|
public Script(BoundScript s, ScriptOptions options )
|
|
{
|
|
FileName = s.FileName;
|
|
Options = options;
|
|
Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError, s.FileName);
|
|
|
|
_bound = s;
|
|
Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, s.Scope, this);
|
|
|
|
var staticScope = options.OverrideStaticScope ?? StaticScope.Scope;
|
|
Scope = EvaluationScope.CreateWithGetOnlyParent(staticScope);
|
|
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope, this);
|
|
}
|
|
|
|
private Script(string fileName, string scriptString, Binder.Binder binder, Evaluator evaluator, ScriptOptions options)
|
|
{
|
|
ScriptString = new SourceText(scriptString);
|
|
Options = options;
|
|
_scriptString = scriptString;
|
|
Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError, fileName);
|
|
|
|
Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope, this);
|
|
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, evaluator.Scope, this);
|
|
Scope = Evaluator.Scope;
|
|
}
|
|
|
|
private Script(BoundScript boundScript, Binder.Binder binder, Evaluator evaluator, ScriptOptions options)
|
|
{
|
|
Options = options;
|
|
_bound = boundScript;
|
|
Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError, boundScript.FileName);
|
|
|
|
Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope, this);
|
|
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, evaluator.Scope, this);
|
|
Scope = Evaluator.Scope;
|
|
}
|
|
|
|
|
|
internal static Script ContinueWith(Script previousScript, string fileName, string scriptString)
|
|
{
|
|
var s = new Script(fileName, scriptString, previousScript.Binder, previousScript.Evaluator, previousScript.Options);
|
|
return s;
|
|
}
|
|
|
|
internal static Script ContinueWith(Script previousScript, BoundScript boundScript)
|
|
{
|
|
var s = new Script(boundScript, previousScript.Binder, previousScript.Evaluator, previousScript.Options);
|
|
return s;
|
|
}
|
|
|
|
|
|
internal void Parse()
|
|
{
|
|
_parsed = Parser.Parser.Parse(_scriptString, Diagnostics, Options.SaveDataComments);
|
|
|
|
}
|
|
|
|
public BoundScript Bind()
|
|
{
|
|
return _bound ?? (_bound = Binder.BindScript(FileName, _parsed));
|
|
}
|
|
|
|
public object Evaluate()
|
|
{
|
|
return Convert(Evaluator.Evaluate(Bind()));
|
|
}
|
|
|
|
public object EvaluateFunction(string functionName, object[] parameters = null)
|
|
{
|
|
return Convert(Evaluator.Evaluate(Bind(), functionName, parameters));
|
|
}
|
|
|
|
private static T Convert<T>(ScriptType t)
|
|
{
|
|
var result = UpsilonBinder.Default.ChangeType(t, typeof(T), CultureInfo.InvariantCulture);
|
|
if (result == null) return default(T);
|
|
return (T)result;
|
|
}
|
|
|
|
private static object Convert(System.Type type, ScriptType t)
|
|
{
|
|
return UpsilonBinder.Default.ChangeType(t, type, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
private static object Convert(ScriptType t)
|
|
{
|
|
return t?.ToCSharpObject();
|
|
}
|
|
|
|
public T Evaluate<T>()
|
|
{
|
|
var bound = Bind();
|
|
var evaluate = Evaluator.Evaluate(bound);
|
|
return Convert<T>(evaluate);
|
|
}
|
|
|
|
public T EvaluateFunction<T>(string functionName, object[] parameters = null)
|
|
{
|
|
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, parameters));
|
|
}
|
|
|
|
public Dictionary<string, ScriptType> GetVariables()
|
|
{
|
|
return Evaluator.Scope.Variables;
|
|
}
|
|
|
|
public T GetVariable<T>(string variableName)
|
|
{
|
|
if (!Scope.TryGet(variableName, out var variable))
|
|
{
|
|
throw new NullReferenceException();
|
|
}
|
|
|
|
return Convert<T>(variable);
|
|
}
|
|
|
|
public bool HasVariable(string variableName)
|
|
{
|
|
return Scope.TryGet(variableName, out _);
|
|
}
|
|
|
|
public string PrettyPrintSyntaxTree()
|
|
{
|
|
return _parsed.Print();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Binder?.Dispose();
|
|
Evaluator?.Dispose();
|
|
Scope?.Dispose();
|
|
_parsed = null;
|
|
_bound = null;
|
|
}
|
|
}
|
|
} |