зеркало из https://github.com/microsoft/Power-Fx.git
Fixes enum store when SymbolTable is replaced while setting up config (#2729)
This PR fixes the issue where inbuilt enums are no longer part of the config if the config's symbol table is replaced after initialization. After initializing the config if SymbolTable was replaced, we were loosing the enums attached to the previous default symbol table. This PR will adds a default symbol table(seprate from existing table) to handle that.
This commit is contained in:
Родитель
7b70dd927c
Коммит
c5a3aeadb5
|
@ -23,20 +23,41 @@ namespace Microsoft.PowerFx
|
|||
internal static readonly int DefaultMaxCallDepth = 20;
|
||||
internal static readonly int DefaultMaximumExpressionLength = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Global symbols. Additional symbols beyond default function set and primitive types.
|
||||
/// </summary>
|
||||
public SymbolTable SymbolTable { get; set; } = new SymbolTable
|
||||
private SymbolTable _symbolTable = new SymbolTable
|
||||
{
|
||||
DebugName = "DefaultConfig"
|
||||
DebugName = "Host Symbols"
|
||||
};
|
||||
|
||||
private readonly SymbolTable _internalConfigSymbols = new SymbolTable
|
||||
{
|
||||
DebugName = "InternalConfigSymbols"
|
||||
};
|
||||
|
||||
internal SymbolTable InternalConfigSymbols => _internalConfigSymbols;
|
||||
|
||||
/// <summary>
|
||||
/// We shouldn't cache it as SymbolTable is mutable.
|
||||
/// </summary>
|
||||
internal ReadOnlySymbolTable ComposedConfigSymbols => ReadOnlySymbolTable.Compose(InternalConfigSymbols, SymbolTable);
|
||||
|
||||
private static EnumStoreBuilder BuiltInEnumStoreBuilder => new EnumStoreBuilder().WithRequiredEnums(BuiltinFunctionsCore._library);
|
||||
|
||||
/// <summary>
|
||||
/// Global symbols. Additional symbols beyond default function set and primitive types defined by host.
|
||||
/// </summary>
|
||||
///
|
||||
public SymbolTable SymbolTable
|
||||
{
|
||||
get => _symbolTable;
|
||||
set => _symbolTable = value;
|
||||
}
|
||||
|
||||
internal readonly Dictionary<TexlFunction, IAsyncTexlFunction> AdditionalFunctions = new ();
|
||||
|
||||
[Obsolete("Use Config.EnumStore or symboltable directly")]
|
||||
internal EnumStoreBuilder EnumStoreBuilder => SymbolTable.EnumStoreBuilder;
|
||||
internal EnumStoreBuilder EnumStoreBuilder => InternalConfigSymbols.EnumStoreBuilder;
|
||||
|
||||
internal IEnumStore EnumStore => ReadOnlySymbolTable.Compose(SymbolTable);
|
||||
internal IEnumStore EnumStore => ComposedConfigSymbols;
|
||||
|
||||
public Features Features { get; }
|
||||
|
||||
|
@ -47,7 +68,7 @@ namespace Microsoft.PowerFx
|
|||
private PowerFxConfig(EnumStoreBuilder enumStoreBuilder, Features features = null)
|
||||
{
|
||||
Features = features ?? Features.None;
|
||||
SymbolTable.EnumStoreBuilder = enumStoreBuilder;
|
||||
InternalConfigSymbols.EnumStoreBuilder = enumStoreBuilder;
|
||||
MaxCallDepth = DefaultMaxCallDepth;
|
||||
MaximumExpressionLength = DefaultMaximumExpressionLength;
|
||||
}
|
||||
|
@ -66,7 +87,7 @@ namespace Microsoft.PowerFx
|
|||
[Obsolete("Migrate to SymbolTables")]
|
||||
public IEnumerable<FunctionInfo> FunctionInfos =>
|
||||
new Engine(this).SupportedFunctions.Functions.Functions
|
||||
.Concat(SymbolTable.Functions.Functions)
|
||||
.Concat(ComposedConfigSymbols.Functions.Functions)
|
||||
.Select(f => new FunctionInfo(f));
|
||||
|
||||
/// <summary>
|
||||
|
@ -74,7 +95,7 @@ namespace Microsoft.PowerFx
|
|||
/// </summary>
|
||||
/// <param name="features">Features to use.</param>
|
||||
public PowerFxConfig(Features features)
|
||||
: this(new EnumStoreBuilder().WithRequiredEnums(BuiltinFunctionsCore._library), features)
|
||||
: this(BuiltInEnumStoreBuilder, features)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -115,12 +136,12 @@ namespace Microsoft.PowerFx
|
|||
}
|
||||
}
|
||||
|
||||
internal bool GetSymbols(string name, out NameLookupInfo symbol) => SymbolTable._variables.TryGetValue(name, out symbol);
|
||||
internal bool GetSymbols(string name, out NameLookupInfo symbol) => InternalConfigSymbols._variables.TryGetValue(name, out symbol) || SymbolTable._variables.TryGetValue(name, out symbol);
|
||||
|
||||
internal IEnumerable<string> GetSuggestableSymbolName() => SymbolTable._variables.Keys;
|
||||
internal IEnumerable<string> GetSuggestableSymbolName() => InternalConfigSymbols._variables.Keys.Concat(SymbolTable._variables.Keys);
|
||||
|
||||
internal void AddEntity(IExternalEntity entity, DName displayName = default)
|
||||
=> SymbolTable.AddEntity(entity, displayName);
|
||||
=> SymbolTable.AddEntity(entity, displayName);
|
||||
|
||||
internal void AddFunction(TexlFunction function)
|
||||
{
|
||||
|
@ -137,7 +158,7 @@ namespace Microsoft.PowerFx
|
|||
}
|
||||
}
|
||||
|
||||
var overloads = SymbolTable.Functions.WithName(function.Name).Where(tf => tf.HasLambdas || tf.HasColumnIdentifiers);
|
||||
var overloads = ComposedConfigSymbols.Functions.WithName(function.Name).Where(tf => tf.HasLambdas || tf.HasColumnIdentifiers);
|
||||
|
||||
if (overloads.Any())
|
||||
{
|
||||
|
@ -153,20 +174,25 @@ namespace Microsoft.PowerFx
|
|||
}
|
||||
}
|
||||
|
||||
SymbolTable.AddFunction(function);
|
||||
InternalConfigSymbols.AddFunction(function);
|
||||
}
|
||||
|
||||
internal void AddFunctions(TexlFunctionSet functionSet)
|
||||
{
|
||||
SymbolTable.AddFunctions(functionSet);
|
||||
InternalConfigSymbols.AddFunctions(functionSet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds optionset to <see cref="SymbolTable"/>.
|
||||
/// </summary>
|
||||
/// <param name="optionSet"></param>
|
||||
/// <param name="optionalDisplayName"></param>
|
||||
public void AddOptionSet(OptionSet optionSet, DName optionalDisplayName = default)
|
||||
{
|
||||
SymbolTable.AddOptionSet(optionSet, optionalDisplayName);
|
||||
}
|
||||
|
||||
internal bool TryGetVariable(DName name, out DName displayName)
|
||||
=> SymbolTable.TryGetVariable(name, out _, out displayName);
|
||||
=> ComposedConfigSymbols.TryGetVariable(name, out _, out displayName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,7 +353,8 @@ namespace Microsoft.PowerFx
|
|||
// Which enums are available.
|
||||
// These do not compose - only bottom one wins.
|
||||
// ComposedReadOnlySymbolTable will handle composition by looking up in each symbol table.
|
||||
private protected EnumStoreBuilder _enumStoreBuilder;
|
||||
private protected EnumStoreBuilder _enumStoreBuilder;
|
||||
|
||||
private EnumSymbol[] _enumSymbolCache;
|
||||
|
||||
private EnumSymbol[] GetEnumSymbolSnapshot
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace Microsoft.PowerFx
|
|||
// Compose all the symbol tables most likely to have functions into a single
|
||||
// symbol table and then cache that.
|
||||
// That will cache unifying into a single TexlFunctionSet - which is the most expensive part.
|
||||
var functionList = _functionListCache.GetComposedCached(SupportedFunctions, Config.SymbolTable);
|
||||
var functionList = _functionListCache.GetComposedCached(SupportedFunctions, Config.ComposedConfigSymbols);
|
||||
|
||||
var symbols = ReadOnlySymbolTable.Compose(EngineSymbols, functionList, PrimitiveTypes);
|
||||
|
||||
|
@ -548,7 +548,7 @@ namespace Microsoft.PowerFx
|
|||
|
||||
public DefinitionsCheckResult AddUserDefinedFunction(string script, CultureInfo parseCulture = null, ReadOnlySymbolTable symbolTable = null, bool allowSideEffects = false)
|
||||
{
|
||||
var engineTypesAndFunctions = ReadOnlySymbolTable.Compose(PrimitiveTypes, SupportedFunctions);
|
||||
var engineTypesAndFunctions = ReadOnlySymbolTable.Compose(PrimitiveTypes, SupportedFunctions, Config.InternalConfigSymbols);
|
||||
return Config.SymbolTable.AddUserDefinedFunction(script, parseCulture, engineTypesAndFunctions, symbolTable, allowSideEffects);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,12 +70,12 @@ namespace Microsoft.PowerFx
|
|||
|
||||
foreach (KeyValuePair<TexlFunction, IAsyncTexlFunction> func in Library.RegexFunctions(regExTimeout, regexTypeCache))
|
||||
{
|
||||
if (config.SymbolTable.Functions.AnyWithName(func.Key.Name))
|
||||
if (config.ComposedConfigSymbols.Functions.AnyWithName(func.Key.Name))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot add RegEx functions more than once.");
|
||||
}
|
||||
|
||||
config.SymbolTable.AddFunction(func.Key);
|
||||
config.InternalConfigSymbols.AddFunction(func.Key);
|
||||
config.AdditionalFunctions.Add(func.Key, func.Value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -420,7 +420,7 @@ namespace Microsoft.PowerFx
|
|||
}
|
||||
|
||||
// Compose will handle null symbols
|
||||
var composedSymbols = SymbolTable.Compose(Config.SymbolTable, SupportedFunctions, PrimitiveTypes, _symbolTable);
|
||||
var composedSymbols = SymbolTable.Compose(Config.ComposedConfigSymbols, SupportedFunctions, PrimitiveTypes, _symbolTable);
|
||||
|
||||
if (parseResult.DefinedTypes.Any())
|
||||
{
|
||||
|
|
|
@ -487,12 +487,12 @@ namespace Microsoft.PowerFx.Core.Tests
|
|||
|
||||
PowerFxConfig config = new PowerFxConfig();
|
||||
|
||||
bool fOk = config.SymbolTable.TryGetSymbolType("os1", out var type);
|
||||
bool fOk = config.ComposedConfigSymbols.TryGetSymbolType("os1", out var type);
|
||||
Assert.False(fOk);
|
||||
|
||||
config.AddOptionSet(os);
|
||||
|
||||
fOk = config.SymbolTable.TryGetSymbolType("os1", out type);
|
||||
fOk = config.ComposedConfigSymbols.TryGetSymbolType("os1", out type);
|
||||
Assert.True(fOk);
|
||||
|
||||
AssertOptionSetType(type, os);
|
||||
|
|
|
@ -397,8 +397,8 @@ namespace Microsoft.PowerFx.Tests
|
|||
// After (A,B) = 3,6
|
||||
var result = engine.Eval("With({x:A, y:B}, Set(A,3); x & y & A & B)", options: _opts);
|
||||
Assert.Equal("102036", result.ToObject());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BasicEval()
|
||||
{
|
||||
|
@ -409,6 +409,24 @@ namespace Microsoft.PowerFx.Tests
|
|||
Assert.Equal(14.0, ((NumberValue)result).Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuiltInEnumConfigCheck()
|
||||
{
|
||||
var config = new PowerFxConfig()
|
||||
{
|
||||
SymbolTable = null
|
||||
};
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
config.EnableRegExFunctions();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
var expression = "Match(\"test\", \"t\", MatchOptions.Contains)";
|
||||
|
||||
var engine = new RecalcEngine(config);
|
||||
var check = engine.Check(expression);
|
||||
Assert.True(check.IsSuccess);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormulaErrorUndefined()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче