267 lines
8.7 KiB
C#
267 lines
8.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using Flee.CalcEngine.InternalTypes;
|
|
using Flee.CalcEngine.PublicTypes;
|
|
using Flee.ExpressionElements.Base;
|
|
using Flee.InternalTypes;
|
|
using Flee.Parsing;
|
|
|
|
namespace Flee.PublicTypes
|
|
{
|
|
/// <summary>
|
|
/// 表达式上下文类,提供表达式编译和执行的环境
|
|
/// </summary>
|
|
public sealed class ExpressionContext
|
|
{
|
|
|
|
#region "Fields"
|
|
|
|
private PropertyDictionary _myProperties;
|
|
|
|
private readonly object _mySyncRoot = new object();
|
|
|
|
private VariableCollection _myVariables;
|
|
#endregion
|
|
|
|
#region "Constructor"
|
|
|
|
public ExpressionContext() : this(DefaultExpressionOwner.Instance)
|
|
{
|
|
}
|
|
|
|
public ExpressionContext(object expressionOwner)
|
|
{
|
|
Utility.AssertNotNull(expressionOwner, "expressionOwner");
|
|
_myProperties = new PropertyDictionary();
|
|
|
|
_myProperties.SetValue("CalculationEngine", null);
|
|
_myProperties.SetValue("CalcEngineExpressionName", null);
|
|
_myProperties.SetValue("IdentifierParser", null);
|
|
|
|
_myProperties.SetValue("ExpressionOwner", expressionOwner);
|
|
|
|
_myProperties.SetValue("ParserOptions", new ExpressionParserOptions(this));
|
|
|
|
_myProperties.SetValue("Options", new ExpressionOptions(this));
|
|
_myProperties.SetValue("Imports", new ExpressionImports());
|
|
this.Imports.SetContext(this);
|
|
_myVariables = new VariableCollection(this);
|
|
|
|
_myProperties.SetToDefault<bool>("NoClone");
|
|
|
|
this.RecreateParser();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region "Methods - Private"
|
|
|
|
private void AssertTypeIsAccessibleInternal(Type t)
|
|
{
|
|
bool isPublic = t.IsPublic;
|
|
|
|
if (t.IsNested == true)
|
|
{
|
|
isPublic = t.IsNestedPublic;
|
|
}
|
|
|
|
bool isSameModuleAsOwner = object.ReferenceEquals(t.Module, this.ExpressionOwner.GetType().Module);
|
|
|
|
// Public types are always accessible. Otherwise they have to be in the same module as the owner
|
|
bool isAccessible = isPublic | isSameModuleAsOwner;
|
|
|
|
if (isAccessible == false)
|
|
{
|
|
string msg = Utility.GetGeneralErrorMessage("TypeNotAccessibleToExpression", t.Name);
|
|
throw new ArgumentException(msg);
|
|
}
|
|
}
|
|
|
|
private void AssertNestedTypeIsAccessible(Type t)
|
|
{
|
|
while ((t != null))
|
|
{
|
|
AssertTypeIsAccessibleInternal(t);
|
|
t = t.DeclaringType;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region "Methods - Internal"
|
|
internal ExpressionContext CloneInternal(bool cloneVariables)
|
|
{
|
|
ExpressionContext context = (ExpressionContext)this.MemberwiseClone();
|
|
context._myProperties = _myProperties.Clone();
|
|
context._myProperties.SetValue("Options", context.Options.Clone());
|
|
context._myProperties.SetValue("ParserOptions", context.ParserOptions.Clone());
|
|
context._myProperties.SetValue("Imports", context.Imports.Clone());
|
|
context.Imports.SetContext(context);
|
|
|
|
if (cloneVariables == true)
|
|
{
|
|
context._myVariables = new VariableCollection(context);
|
|
this.Variables.Copy(context._myVariables);
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
internal void AssertTypeIsAccessible(Type t)
|
|
{
|
|
if (t.IsNested == true)
|
|
{
|
|
AssertNestedTypeIsAccessible(t);
|
|
}
|
|
else
|
|
{
|
|
AssertTypeIsAccessibleInternal(t);
|
|
}
|
|
}
|
|
|
|
internal ExpressionElement Parse(string expression, IServiceProvider services)
|
|
{
|
|
lock (_mySyncRoot)
|
|
{
|
|
System.IO.StringReader sr = new System.IO.StringReader(expression);
|
|
ExpressionParser parser = this.Parser;
|
|
parser.Reset(sr);
|
|
parser.Tokenizer.Reset(sr);
|
|
FleeExpressionAnalyzer analyzer = (FleeExpressionAnalyzer)parser.Analyzer;
|
|
|
|
analyzer.SetServices(services);
|
|
|
|
Node rootNode = DoParse();
|
|
analyzer.Reset();
|
|
ExpressionElement topElement = (ExpressionElement)rootNode.Values[0];
|
|
return topElement;
|
|
}
|
|
}
|
|
|
|
internal void RecreateParser()
|
|
{
|
|
lock (_mySyncRoot)
|
|
{
|
|
FleeExpressionAnalyzer analyzer = new FleeExpressionAnalyzer();
|
|
ExpressionParser parser = new ExpressionParser(TextReader.Null, analyzer, this);
|
|
_myProperties.SetValue("ExpressionParser", parser);
|
|
}
|
|
}
|
|
|
|
internal Node DoParse()
|
|
{
|
|
try
|
|
{
|
|
return this.Parser.Parse();
|
|
}
|
|
catch (ParserLogException ex)
|
|
{
|
|
// Syntax error; wrap it in our exception and rethrow
|
|
throw new ExpressionCompileException(ex);
|
|
}
|
|
}
|
|
|
|
internal void SetCalcEngine(CalculationEngine engine, string calcEngineExpressionName)
|
|
{
|
|
_myProperties.SetValue("CalculationEngine", engine);
|
|
_myProperties.SetValue("CalcEngineExpressionName", calcEngineExpressionName);
|
|
}
|
|
|
|
internal IdentifierAnalyzer ParseIdentifiers(string expression)
|
|
{
|
|
ExpressionParser parser = this.IdentifierParser;
|
|
StringReader sr = new StringReader(expression);
|
|
parser.Reset(sr);
|
|
parser.Tokenizer.Reset(sr);
|
|
|
|
IdentifierAnalyzer analyzer = (IdentifierAnalyzer)parser.Analyzer;
|
|
analyzer.Reset();
|
|
|
|
parser.Parse();
|
|
|
|
return (IdentifierAnalyzer)parser.Analyzer;
|
|
}
|
|
#endregion
|
|
|
|
#region "Methods - Public"
|
|
|
|
public ExpressionContext Clone()
|
|
{
|
|
return this.CloneInternal(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 编译动态表达式,返回类型在运行时确定
|
|
/// </summary>
|
|
/// <param name="expression">要编译的表达式字符串</param>
|
|
/// <returns>编译后的动态表达式</returns>
|
|
public IDynamicExpression CompileDynamic(string expression)
|
|
{
|
|
return new Flee.InternalTypes.Expression<object>(expression, this, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 编译泛型表达式,返回指定类型的结果
|
|
/// </summary>
|
|
/// <typeparam name="TResultType">表达式结果的类型</typeparam>
|
|
/// <param name="expression">要编译的表达式字符串</param>
|
|
/// <returns>编译后的泛型表达式</returns>
|
|
public IGenericExpression<TResultType> CompileGeneric<TResultType>(string expression)
|
|
{
|
|
return new Flee.InternalTypes.Expression<TResultType>(expression, this, true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region "Properties - Private"
|
|
|
|
private ExpressionParser IdentifierParser
|
|
{
|
|
get
|
|
{
|
|
ExpressionParser parser = _myProperties.GetValue<ExpressionParser>("IdentifierParser");
|
|
|
|
if (parser == null)
|
|
{
|
|
IdentifierAnalyzer analyzer = new IdentifierAnalyzer();
|
|
parser = new ExpressionParser(System.IO.TextReader.Null, analyzer, this);
|
|
//parser = new ExpressionParser(System.IO.StringReader.Null, analyzer, this);
|
|
_myProperties.SetValue("IdentifierParser", parser);
|
|
}
|
|
|
|
return parser;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region "Properties - Internal"
|
|
|
|
internal bool NoClone
|
|
{
|
|
get { return _myProperties.GetValue<bool>("NoClone"); }
|
|
set { _myProperties.SetValue("NoClone", value); }
|
|
}
|
|
|
|
internal object ExpressionOwner => _myProperties.GetValue<object>("ExpressionOwner");
|
|
|
|
internal string CalcEngineExpressionName => _myProperties.GetValue<string>("CalcEngineExpressionName");
|
|
|
|
internal ExpressionParser Parser => _myProperties.GetValue<ExpressionParser>("ExpressionParser");
|
|
|
|
#endregion
|
|
|
|
#region "Properties - Public"
|
|
public ExpressionOptions Options => _myProperties.GetValue<ExpressionOptions>("Options");
|
|
|
|
public ExpressionImports Imports => _myProperties.GetValue<ExpressionImports>("Imports");
|
|
|
|
public VariableCollection Variables => _myVariables;
|
|
|
|
public CalculationEngine CalculationEngine => _myProperties.GetValue<CalculationEngine>("CalculationEngine");
|
|
|
|
public ExpressionParserOptions ParserOptions => _myProperties.GetValue<ExpressionParserOptions>("ParserOptions");
|
|
|
|
#endregion
|
|
}
|
|
}
|