From f366046f707d5934fe5c164a5a479838aa3d91d9 Mon Sep 17 00:00:00 2001 From: Adithya Selvaprithiviraj Date: Mon, 29 Apr 2024 16:12:22 -0700 Subject: [PATCH] Introduce NamedTypes to INameResolver (#2350) Step 3 of allowing user defined types effort . * Introduces NamedTypes, LookupType in INameResolver. * Remove PrimitiveTypeSymbolTable usage, and use NamedTypes from Engine Symbols * Require INameResolver to create UDFs. * Removes `TypeSymbolTable`, `PrimitiveTypesSymbolTable` and `DefinedTypeSymbolTable` This will be followed with 1. Introduce parsing and adding user defined NamedTypes. 2. Optimize type graph to update incremental. --- .../Binding/INameResolver.cs | 8 + .../Functions/UserDefinedFunction.cs | 78 +++-- .../Config/ComposedReadOnlySymbolTable.cs | 33 +++ .../Public/Config/ReadOnlySymbolTable.cs | 50 +++- .../Public/Config/SymbolTable.cs | 71 ++++- .../Microsoft.PowerFx.Core/Public/Engine.cs | 270 +++++++++--------- .../Public/Types/FormulaType.cs | 41 +-- .../Syntax/Visitors/DTypeVisitor.cs | 49 ++-- .../TypeSymbolTable/DefinedTypeSymbolTable.cs | 56 ---- .../PrimitiveTypesSymbolTable.cs | 66 ----- .../Types/TypeSymbolTable/TypeSymbolTable.cs | 25 -- .../Utils/TokenUtils.cs | 26 -- .../RecalcEngine.cs | 26 +- .../FormulaTypeJsonConverter.cs | 6 +- .../FormulaTypeSchema.cs | 15 +- .../FormulaTypeToSchemaHelper.cs | 17 +- .../UserDefinedRecordType.cs | 9 +- .../ParseTests.cs | 6 +- .../UserDefinedFunctionTests.cs | 31 +- .../RecalcEngineTests.cs | 6 +- .../UserDefinedTests.cs | 16 +- .../FormulaTypeSerializerSnapshotTests.cs | 4 +- 22 files changed, 456 insertions(+), 453 deletions(-) delete mode 100644 src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/DefinedTypeSymbolTable.cs delete mode 100644 src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/PrimitiveTypesSymbolTable.cs delete mode 100644 src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/TypeSymbolTable.cs delete mode 100644 src/libraries/Microsoft.PowerFx.Core/Utils/TokenUtils.cs diff --git a/src/libraries/Microsoft.PowerFx.Core/Binding/INameResolver.cs b/src/libraries/Microsoft.PowerFx.Core/Binding/INameResolver.cs index a943a5572..3fa513fd0 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Binding/INameResolver.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Binding/INameResolver.cs @@ -10,6 +10,7 @@ using Microsoft.PowerFx.Core.Entities; using Microsoft.PowerFx.Core.Functions; using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Core.Utils; +using Microsoft.PowerFx.Types; namespace Microsoft.PowerFx.Core.Binding { @@ -41,6 +42,10 @@ namespace Microsoft.PowerFx.Core.Binding TexlFunctionSet Functions { get; } + // List of all valid named types in a given namespace + // Intellisense can use this when suggesting type options. + IEnumerable> NamedTypes { get; } + // This advertises whether the INameResolver instance will suggest unqualified enums ("Hours") // or only qualified enums ("TimeUnit.Hours"). // This must be consistent with how the other Lookup functions behave. @@ -82,6 +87,9 @@ namespace Microsoft.PowerFx.Core.Binding bool LookupGlobalEntity(DName name, out NameLookupInfo lookupInfo); bool TryLookupEnum(DName name, out NameLookupInfo lookupInfo); + + // Look up a type by name. + bool LookupType(DName name, out FormulaType fType); } internal static class NameResolverExtensions diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/UserDefinedFunction.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/UserDefinedFunction.cs index b4f4ec18f..2ef1a0b17 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/UserDefinedFunction.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/UserDefinedFunction.cs @@ -21,6 +21,7 @@ using Microsoft.PowerFx.Core.Texl; using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Syntax; +using Microsoft.PowerFx.Types; using static Microsoft.PowerFx.Core.Localization.TexlStrings; namespace Microsoft.PowerFx.Core.Functions @@ -52,8 +53,9 @@ namespace Microsoft.PowerFx.Core.Functions /// TexlNode for user defined function body. /// /// - public UserDefinedFunction(string functionName, DType returnType, TexlNode body, bool isImperative, ISet args) - : base(DPath.Root, functionName, functionName, SG(functionName), FunctionCategories.UserDefined, returnType, 0, args.Count, args.Count, args.Select(a => a.TypeIdent.GetFormulaType()._type).ToArray()) + /// Array of argTypes. + public UserDefinedFunction(string functionName, DType returnType, TexlNode body, bool isImperative, ISet args, DType[] argTypes) + : base(DPath.Root, functionName, functionName, SG(functionName), FunctionCategories.UserDefined, returnType, 0, args.Count, args.Count, argTypes) { this._args = args; this._isImperative = isImperative; @@ -116,7 +118,7 @@ namespace Microsoft.PowerFx.Core.Functions } bindingConfig = bindingConfig ?? new BindingConfig(this._isImperative); - _binding = TexlBinding.Run(documentBinderGlue, UdfBody, UserDefinitionsNameResolver.Create(nameResolver, _args), bindingConfig, features: features, rule: rule); + _binding = TexlBinding.Run(documentBinderGlue, UdfBody, UserDefinitionsNameResolver.Create(nameResolver, _args, ParamTypes), bindingConfig, features: features, rule: rule); CheckTypesOnDeclaration(_binding.CheckTypesContext, _binding.ResultType, _binding); @@ -176,7 +178,7 @@ namespace Microsoft.PowerFx.Core.Functions throw new ArgumentNullException(nameof(binderGlue)); } - var func = new UserDefinedFunction(Name, ReturnType, UdfBody, _isImperative, new HashSet(_args)); + var func = new UserDefinedFunction(Name, ReturnType, UdfBody, _isImperative, new HashSet(_args), ParamTypes); binding = func.BindBody(nameResolver, binderGlue, bindingConfig, features, rule); return func; @@ -188,9 +190,10 @@ namespace Microsoft.PowerFx.Core.Functions /// Helper to create IR UserDefinedFunctions. /// /// Valid Parsed UDFs to be converted into UserDefinedFunction. + /// NameResolver to resolve type names. /// Errors when creating functions. /// IEnumerable of UserDefinedFunction. - public static IEnumerable CreateFunctions(IEnumerable uDFs, out List errors) + public static IEnumerable CreateFunctions(IEnumerable uDFs, INameResolver nameResolver, out List errors) { Contracts.AssertValue(uDFs); Contracts.AssertAllValues(uDFs); @@ -210,14 +213,14 @@ namespace Microsoft.PowerFx.Core.Functions continue; } - var parametersOk = CheckParameters(udf.Args, errors); - var returnTypeOk = CheckReturnType(udf.ReturnType, errors); + var parametersOk = CheckParameters(udf.Args, errors, nameResolver, out var parameterTypes); + var returnTypeOk = CheckReturnType(udf.ReturnType, errors, nameResolver, out var returnType); if (!parametersOk || !returnTypeOk) { continue; } - var func = new UserDefinedFunction(udfName.Value, udf.ReturnType.GetFormulaType()._type, udf.Body, udf.IsImperative, udf.Args); + var func = new UserDefinedFunction(udfName.Value, returnType, udf.Body, udf.IsImperative, udf.Args, parameterTypes); texlFunctionSet.Add(func); userDefinedFunctions.Add(func); @@ -226,10 +229,17 @@ namespace Microsoft.PowerFx.Core.Functions return userDefinedFunctions; } - private static bool CheckParameters(ISet args, List errors) + private static bool CheckParameters(ISet args, List errors, INameResolver nameResolver, out DType[] parameterTypes) { + if (args.Count == 0) + { + parameterTypes = Array.Empty(); + return true; + } + var isParamCheckSuccessful = true; var argsAlreadySeen = new HashSet(); + parameterTypes = new DType[args.Count]; foreach (var arg in args) { @@ -242,30 +252,36 @@ namespace Microsoft.PowerFx.Core.Functions { argsAlreadySeen.Add(arg.NameIdent.Name); - var parameterType = arg.TypeIdent.GetFormulaType()._type; - if (parameterType.Kind.Equals(DType.Unknown.Kind) || UserDefinitions.RestrictedTypes.Contains(parameterType)) + if (!nameResolver.LookupType(arg.TypeIdent.Name, out var parameterType) || UserDefinitions.RestrictedTypes.Contains(parameterType._type)) { errors.Add(new TexlError(arg.TypeIdent, DocumentErrorSeverity.Severe, TexlStrings.ErrUDF_UnknownType, arg.TypeIdent.Name)); isParamCheckSuccessful = false; } + else + { + Contracts.Assert(arg.ArgIndex >= 0); + Contracts.Assert(arg.ArgIndex < args.Count); + parameterTypes[arg.ArgIndex] = parameterType._type; + } } } return isParamCheckSuccessful; } - private static bool CheckReturnType(IdentToken returnType, List errors) + private static bool CheckReturnType(IdentToken returnTypeToken, List errors, INameResolver nameResolver, out DType returnType) { - var returnTypeFormulaType = returnType.GetFormulaType()._type; - var isReturnTypeCheckSuccessful = true; - - if (returnTypeFormulaType.Kind.Equals(DType.Unknown.Kind) || UserDefinitions.RestrictedTypes.Contains(returnTypeFormulaType)) + if (!nameResolver.LookupType(returnTypeToken.Name, out var returnTypeFormulaType) || UserDefinitions.RestrictedTypes.Contains(returnTypeFormulaType._type)) { - errors.Add(new TexlError(returnType, DocumentErrorSeverity.Severe, TexlStrings.ErrUDF_UnknownType, returnType.Name)); - isReturnTypeCheckSuccessful = false; + errors.Add(new TexlError(returnTypeToken, DocumentErrorSeverity.Severe, TexlStrings.ErrUDF_UnknownType, returnTypeToken.Name)); + returnType = DType.Invalid; + return false; + } + else + { + returnType = returnTypeFormulaType._type; + return true; } - - return isReturnTypeCheckSuccessful; } /// @@ -275,16 +291,23 @@ namespace Microsoft.PowerFx.Core.Functions { private readonly INameResolver _globalNameResolver; private readonly IReadOnlyDictionary _args; + private readonly DType[] _argTypes; - public static INameResolver Create(INameResolver globalNameResolver, IEnumerable args) + public static INameResolver Create(INameResolver globalNameResolver, IEnumerable args, DType[] argTypes) { - return new UserDefinitionsNameResolver(globalNameResolver, args); + return new UserDefinitionsNameResolver(globalNameResolver, args, argTypes); } - private UserDefinitionsNameResolver(INameResolver globalNameResolver, IEnumerable args) + private UserDefinitionsNameResolver(INameResolver globalNameResolver, IEnumerable args, DType[] argTypes) { + Contracts.AssertValue(args); + Contracts.AssertValue(argTypes); + Contracts.AssertValue(globalNameResolver); + Contracts.Assert(args.Count() == argTypes.Length); + this._globalNameResolver = globalNameResolver; this._args = args.ToDictionary(arg => arg.NameIdent.Name.Value, arg => arg); + this._argTypes = argTypes; } public IExternalDocument Document => _globalNameResolver.Document; @@ -299,6 +322,8 @@ namespace Microsoft.PowerFx.Core.Functions public TexlFunctionSet Functions => _globalNameResolver.Functions; + public IEnumerable> NamedTypes => _globalNameResolver.NamedTypes; + public bool SuggestUnqualifiedEnums => _globalNameResolver.SuggestUnqualifiedEnums; public bool Lookup(DName name, out NameLookupInfo nameInfo, NameLookupPreferences preferences = NameLookupPreferences.None) @@ -306,7 +331,7 @@ namespace Microsoft.PowerFx.Core.Functions // lookup in the local scope i.e., function params & body and then look in global scope. if (_args.TryGetValue(name, out var value)) { - var type = value.TypeIdent.GetFormulaType()._type; + var type = _argTypes[value.ArgIndex]; nameInfo = new NameLookupInfo(BindKind.PowerFxResolvedObject, type, DPath.Root, 0, new UDFParameterInfo(type, value.ArgIndex, value.NameIdent.Name)); return true; @@ -331,6 +356,11 @@ namespace Microsoft.PowerFx.Core.Functions return _globalNameResolver.LookupFunctionsInNamespace(nameSpace); } + public bool LookupType(DName name, out FormulaType fType) + { + return _globalNameResolver.LookupType(name, out fType); + } + public bool LookupGlobalEntity(DName name, out NameLookupInfo lookupInfo) { return _globalNameResolver.LookupGlobalEntity(name, out lookupInfo); diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Config/ComposedReadOnlySymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Config/ComposedReadOnlySymbolTable.cs index fedbd91f9..790e1c28c 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Config/ComposedReadOnlySymbolTable.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Config/ComposedReadOnlySymbolTable.cs @@ -82,6 +82,25 @@ namespace Microsoft.PowerFx } } + // Expose the list to aide in intellisense suggestions. + IEnumerable> INameResolver.NamedTypes + { + get + { + var names = new HashSet(); + foreach (INameResolver table in _symbolTables) + { + foreach (var type in table.NamedTypes) + { + if (names.Add(type.Key)) + { + yield return type; + } + } + } + } + } + public IEnumerable> GlobalSymbols { get @@ -188,6 +207,20 @@ namespace Microsoft.PowerFx return false; } + public virtual bool LookupType(DName name, out FormulaType fType) + { + foreach (INameResolver table in _symbolTables) + { + if (table.LookupType(name, out fType)) + { + return true; + } + } + + fType = default; + return false; + } + internal override IExternalEntityScope InternalEntityScope { get diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Config/ReadOnlySymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Config/ReadOnlySymbolTable.cs index 6d9df14ce..e732342dd 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Config/ReadOnlySymbolTable.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Config/ReadOnlySymbolTable.cs @@ -291,7 +291,40 @@ namespace Microsoft.PowerFx } return NewDefault(tfs); - } + } + + // Helper to create a ReadOnly symbol table around a set of core types. + internal static ReadOnlySymbolTable NewDefaultTypes(IEnumerable> types) + { + Contracts.AssertValue(types); + + var s = new SymbolTable + { + DebugName = $"BuiltinTypes ({types?.Count()})" + }; + + s.AddTypes(types); + return s; + } + + // Overload Helper to create a ReadOnly symbol table around a set of core functions and types. + internal static ReadOnlySymbolTable NewDefault(TexlFunctionSet coreFunctions, IEnumerable> types) + { + Contracts.AssertValue(types); + Contracts.AssertValue(coreFunctions); + + var s = new SymbolTable + { + EnumStoreBuilder = new EnumStoreBuilder(), + DebugName = $"BuiltinFunctions ({coreFunctions.Count()}), BuiltinTypes ({types?.Count()})" + }; + + s.AddFunctions(coreFunctions); + s.AddTypes(types); + return s; + } + + internal static readonly ReadOnlySymbolTable PrimitiveTypesTableInstance = NewDefaultTypes(FormulaType.PrimitiveTypes); /// /// Helper to create a symbol table around a set of core functions. @@ -463,8 +496,10 @@ namespace Microsoft.PowerFx DPath INameResolver.CurrentEntityPath => default; - bool INameResolver.SuggestUnqualifiedEnums => false; - + bool INameResolver.SuggestUnqualifiedEnums => false; + + IEnumerable> INameResolver.NamedTypes => Enumerable.Empty>(); + bool INameResolver.LookupParent(out NameLookupInfo lookupInfo) { lookupInfo = default; @@ -505,7 +540,14 @@ namespace Microsoft.PowerFx bool INameResolver.LookupExpandedControlType(IExternalControl control, out DType controlType) { throw new NotImplementedException(); - } + } + + bool INameResolver.LookupType(DName name, out FormulaType fType) + { + fType = default; + return false; + } + #endregion } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Config/SymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Config/SymbolTable.cs index 589e7a2c0..b889c5487 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Config/SymbolTable.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Config/SymbolTable.cs @@ -36,10 +36,14 @@ namespace Microsoft.PowerFx private readonly SlotMap _slots = new SlotMap(); + private readonly IDictionary _namedTypes = new Dictionary(); + private DisplayNameProvider _environmentSymbolDisplayNameProvider = new SingleSourceDisplayNameProvider(); IEnumerable> IGlobalSymbolNameResolver.GlobalSymbols => _variables; + IEnumerable> INameResolver.NamedTypes => _namedTypes; + internal const string UserInfoSymbolName = "User"; /// @@ -216,7 +220,11 @@ namespace Microsoft.PowerFx var sb = new StringBuilder(); var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + + // Compose will handle null symbols + var composedSymbols = Compose(this, symbolTable, extraSymbolTable); + + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), composedSymbols, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); @@ -232,9 +240,6 @@ namespace Microsoft.PowerFx throw new InvalidOperationException(sb.ToString()); } - // Compose will handle null symbols - var composedSymbols = Compose(this, symbolTable, extraSymbolTable); - foreach (var udf in udfs) { AddFunction(udf); @@ -417,6 +422,62 @@ namespace Microsoft.PowerFx displayName: default); _variables.Add(hostDName, info); - } + } + + /// + /// Adds a named type that can be referenced in expression. + /// + /// Name of the type to be added into Symbol table. + /// Type associated with the name. + public void AddType(DName typeName, FormulaType type) + { + Contracts.AssertValue(typeName.Value); + Contracts.AssertValue(type); + Contracts.Assert(typeName.Value.Length > 0); + Contracts.AssertValid(typeName); + + using var guard = _guard.Enter(); // Region is single threaded. + Inc(); + + _namedTypes.Add(typeName, type); + } + + internal void AddTypes(IEnumerable> types) + { + Contracts.AssertValue(types); + + using var guard = _guard.Enter(); // Region is single threaded. + Inc(); + + foreach (var type in types) + { + _namedTypes.Add(type.Key, type.Value); + } + } + + /// + /// Helper to create a symbol table with primitive types. + /// + /// SymbolTable with primitive types. + public static SymbolTable WithPrimitiveTypes() + { + var s = new SymbolTable + { + DebugName = $"SymbolTable with PrimitiveTypes" + }; + + s.AddTypes(FormulaType.PrimitiveTypes); + return s; + } + + bool INameResolver.LookupType(DName name, out FormulaType fType) + { + if (_namedTypes.TryGetValue(name, out fType)) + { + return true; + } + + return false; + } } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs index 783894882..ce2635c1a 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Reflection; +using System.Reflection; using Microsoft.PowerFx.Core; using Microsoft.PowerFx.Core.App.Controls; using Microsoft.PowerFx.Core.Binding; @@ -30,30 +30,30 @@ namespace Microsoft.PowerFx /// Configuration symbols for this Power Fx engine. /// public PowerFxConfig Config { get; } - - // Volatile means it can be set by multiple threads. - // But all threads will produce the same value, so it's ok. - private static volatile string _assemblyVersion; - - /// - /// For diagnostics, get the assembly version of Power Fx Engine. - /// - public static string AssemblyVersion - { - get - { - if (_assemblyVersion == null) - { - var fxAttr = typeof(Engine).Assembly.GetCustomAttribute(); - var fullVerStr = fxAttr.InformationalVersion; - - var parts = fullVerStr.Split('+'); - _assemblyVersion = parts[0]; - } - - return _assemblyVersion; - } - } + + // Volatile means it can be set by multiple threads. + // But all threads will produce the same value, so it's ok. + private static volatile string _assemblyVersion; + + /// + /// For diagnostics, get the assembly version of Power Fx Engine. + /// + public static string AssemblyVersion + { + get + { + if (_assemblyVersion == null) + { + var fxAttr = typeof(Engine).Assembly.GetCustomAttribute(); + var fullVerStr = fxAttr.InformationalVersion; + + var parts = fullVerStr.Split('+'); + _assemblyVersion = parts[0]; + } + + return _assemblyVersion; + } + } /// /// Initializes a new instance of the class. @@ -82,6 +82,11 @@ namespace Microsoft.PowerFx /// public ReadOnlySymbolTable SupportedFunctions { get; protected internal set; } = _allBuiltinCoreFunctions; + /// + /// Builtin Types supported by this engine. + /// + public ReadOnlySymbolTable PrimitiveTypes { get; protected internal set; } = ReadOnlySymbolTable.PrimitiveTypesTableInstance; + // By default, we pull the core functions. // These can be overridden. internal TexlFunctionSet Functions => CreateResolverInternal().Functions; @@ -89,13 +94,13 @@ namespace Microsoft.PowerFx /// /// List of transforms to apply to an IR. /// - internal readonly List IRTransformList = new List(); - - /// - /// List of error processor that will add host specific custom errors at the end of the check. - /// - private readonly IList _postCheckErrorHandlers = new List(); - + internal readonly List IRTransformList = new List(); + + /// + /// List of error processor that will add host specific custom errors at the end of the check. + /// + private readonly IList _postCheckErrorHandlers = new List(); + public IList PostCheckErrorHandlers => _postCheckErrorHandlers; /// @@ -156,27 +161,27 @@ namespace Microsoft.PowerFx symbols = ReadOnlySymbolTable.Compose(localSymbols, GetCombinedEngineSymbols()); return symbols; - } - - /// - /// Get a combined engine symbol table, including builtins and config. - /// - /// - public ReadOnlySymbolTable GetCombinedEngineSymbols() - { - var symbols = ReadOnlySymbolTable.Compose(EngineSymbols, SupportedFunctions, Config.SymbolTable); - - return symbols; - } - - /// - /// Overriable method to be able to supply custom implementation of IExternalRuleScopeResolver. - /// Defaults to Null. - /// - /// Implementation of IExternalRuleScopeResolver. - // IExternalRuleScopeResolver is used in Canvas App backend when calling TexlBinding.Run(). - // There was no option to supply a custom implementation of this in Engine, - // so following the existing pattern in Engine, + } + + /// + /// Get a combined engine symbol table, including builtins and config. + /// + /// + public ReadOnlySymbolTable GetCombinedEngineSymbols() + { + var symbols = ReadOnlySymbolTable.Compose(EngineSymbols, SupportedFunctions, Config.SymbolTable, PrimitiveTypes); + + return symbols; + } + + /// + /// Overriable method to be able to supply custom implementation of IExternalRuleScopeResolver. + /// Defaults to Null. + /// + /// Implementation of IExternalRuleScopeResolver. + // IExternalRuleScopeResolver is used in Canvas App backend when calling TexlBinding.Run(). + // There was no option to supply a custom implementation of this in Engine, + // so following the existing pattern in Engine, // added this virtual function for the derived classes of Engine to override and supply custom implementation. private protected virtual IExternalRuleScopeResolver CreateExternalRuleScopeResolver() { @@ -191,9 +196,9 @@ namespace Microsoft.PowerFx public virtual ParserOptions GetDefaultParserOptionsCopy() { return new ParserOptions - { - Culture = null, - AllowsSideEffects = false, + { + Culture = null, + AllowsSideEffects = false, MaxExpressionLength = Config.MaximumExpressionLength, }; } @@ -226,9 +231,9 @@ namespace Microsoft.PowerFx if (expressionText == null) { throw new ArgumentNullException(nameof(expressionText)); - } - - options ??= new ParserOptions(); + } + + options ??= new ParserOptions(); var result = options.Parse(expressionText, features ?? Features.None); return result; } @@ -284,12 +289,12 @@ namespace Microsoft.PowerFx // Called after check result, can inject additional errors or constraints. protected virtual IEnumerable PostCheck(CheckResult check) - { - var hostErrors = new List(); - foreach (var postCheckErrorHandler in _postCheckErrorHandlers) - { - hostErrors.AddRange(postCheckErrorHandler.Process(check)); - } + { + var hostErrors = new List(); + foreach (var postCheckErrorHandler in _postCheckErrorHandlers) + { + hostErrors.AddRange(postCheckErrorHandler.Process(check)); + } return hostErrors; } @@ -304,12 +309,12 @@ namespace Microsoft.PowerFx private protected virtual RecordType GetRuleScope() { return null; - } - - internal bool TryGetRuleScope(out RecordType record) - { - record = this.GetRuleScope(); - return record != null; + } + + internal bool TryGetRuleScope(out RecordType record) + { + record = this.GetRuleScope(); + return record != null; } private BindingConfig GetDefaultBindingConfig() @@ -325,29 +330,29 @@ namespace Microsoft.PowerFx } return bindingConfig; - } - - /// - /// Creates and returns binding config from the given parser options. - /// - /// Parser Options. - /// Optional: Rule Scope. If not supplied, then rule scope from would be used. - /// Binding Config. - // Power Apps never set BindingConfig.UseThisRecordForRuleScope to true - // This virtual overload of GetDefaultBindingConfig allows us to supply custom binding config from PowerApps - // Default implementation is similar to how binding config is created in ComputeBinding - // Optional ruleScope is passed from ComputeBinding() so we don't have to call GetRuleScope twice + } + + /// + /// Creates and returns binding config from the given parser options. + /// + /// Parser Options. + /// Optional: Rule Scope. If not supplied, then rule scope from would be used. + /// Binding Config. + // Power Apps never set BindingConfig.UseThisRecordForRuleScope to true + // This virtual overload of GetDefaultBindingConfig allows us to supply custom binding config from PowerApps + // Default implementation is similar to how binding config is created in ComputeBinding + // Optional ruleScope is passed from ComputeBinding() so we don't have to call GetRuleScope twice private protected virtual BindingConfig GetDefaultBindingConfig(ParserOptions options, RecordType ruleScope = null) { - ruleScope ??= this.GetRuleScope(); - - // Canvas apps uses rule scope for lots of cases. - // But in general, we should only use rule scope for 'ThisRecord' binding. - // Anything else should be accomplished with SymbolTables. - bool useThisRecordForRuleScope = ruleScope != null; - + ruleScope ??= this.GetRuleScope(); + + // Canvas apps uses rule scope for lots of cases. + // But in general, we should only use rule scope for 'ThisRecord' binding. + // Anything else should be accomplished with SymbolTables. + bool useThisRecordForRuleScope = ruleScope != null; + return new BindingConfig(options.AllowsSideEffects, useThisRecordForRuleScope, options.NumberIsFloat); - } + } // Called by CheckResult.ApplyBinding to compute the binding. internal (TexlBinding, ReadOnlySymbolTable) ComputeBinding(CheckResult result) @@ -365,19 +370,19 @@ namespace Microsoft.PowerFx var glue = CreateBinderGlue(); var ruleScope = this.GetRuleScope(); - var bindingConfig = GetDefaultBindingConfig(result.Parse.Options, ruleScope); + var bindingConfig = GetDefaultBindingConfig(result.Parse.Options, ruleScope); - var binding = TexlBinding.Run( - glue, - externalRuleScopeResolver, - new DataSourceToQueryOptionsMap(), - parse.Root, - resolver, - bindingConfig, - false, - ruleScope?._type, - false, - null, + var binding = TexlBinding.Run( + glue, + externalRuleScopeResolver, + new DataSourceToQueryOptionsMap(), + parse.Root, + resolver, + bindingConfig, + false, + ruleScope?._type, + false, + null, Config.Features); return (binding, combinedSymbols); @@ -402,14 +407,14 @@ namespace Microsoft.PowerFx /// Get intellisense from the formula, with parser options. /// public IIntellisenseResult Suggest(CheckResult checkResult, int cursorPosition) - { - return this.Suggest(checkResult, cursorPosition, null); - } - - public IIntellisenseResult Suggest(CheckResult checkResult, int cursorPosition, IServiceProvider services) + { + return this.Suggest(checkResult, cursorPosition, null); + } + + public IIntellisenseResult Suggest(CheckResult checkResult, int cursorPosition, IServiceProvider services) { - // Note that for completions, we just need binding, - // but we don't need errors or dependency info. + // Note that for completions, we just need binding, + // but we don't need errors or dependency info. var binding = checkResult.ApplyBindingInternal(); var formula = checkResult.GetParseFormula(); @@ -417,10 +422,10 @@ namespace Microsoft.PowerFx // CheckResult has the binding, which has already captured both the INameResolver and any row scope parameters. // So these both become available to intellisense. - var context = new IntellisenseContext(expression, cursorPosition, checkResult.ExpectedReturnType) - { - Services = services - }; + var context = new IntellisenseContext(expression, cursorPosition, checkResult.ExpectedReturnType) + { + Services = services + }; var intellisense = this.CreateIntellisense(); var suggestions = intellisense.Suggest(context, binding, formula); @@ -440,8 +445,8 @@ namespace Microsoft.PowerFx public RenameDriver CreateFieldRenamer(RecordType parameters, DPath pathToRename, DName updatedName, CultureInfo culture) { return CreateFieldRenamer(parameters, pathToRename, updatedName, new ParserOptions() { Culture = culture }); - } - + } + /// /// Creates a renamer instance for updating a field reference from in expressions. /// @@ -449,7 +454,7 @@ namespace Microsoft.PowerFx /// be acecssed as top-level identifiers in the formula. Must be the names from before any rename operation is applied. /// Path to the field to rename. /// New name. Replaces the last segment of . - /// Parser option to support TextFirst (if necessary) and culture. + /// Parser option to support TextFirst (if necessary) and culture. public RenameDriver CreateFieldRenamer(RecordType parameters, DPath pathToRename, DName updatedName, ParserOptions options) { Contracts.CheckValue(parameters, nameof(parameters)); @@ -466,11 +471,11 @@ namespace Microsoft.PowerFx ** display name support and construct a resolver from that instead, which we use for the rewrite binding. */ return new RenameDriver(parameters, pathToRename, updatedName, this, CreateResolverInternal() as ReadOnlySymbolTable, CreateBinderGlue(), options, false); - } - - public RenameDriver CreateOptionSetRenamer(RecordType parameters, DPath pathToRename, DName updatedName, CultureInfo culture) - { - return new RenameDriver(parameters, pathToRename, updatedName, this, CreateResolverInternal() as ReadOnlySymbolTable, CreateBinderGlue(), culture, true); + } + + public RenameDriver CreateOptionSetRenamer(RecordType parameters, DPath pathToRename, DName updatedName, CultureInfo culture) + { + return new RenameDriver(parameters, pathToRename, updatedName, this, CreateResolverInternal() as ReadOnlySymbolTable, CreateBinderGlue(), culture, true); } /// @@ -488,10 +493,10 @@ namespace Microsoft.PowerFx var symbolTable = (parameters == null) ? null : SymbolTable.NewFromRecord(parameters); return GetInvariantExpressionWorker(expressionText, symbolTable, parseCulture); - } - + } + public string GetInvariantExpressionParserOption(string expressionText, RecordType parameters, ParserOptions options) - { + { var ruleScope = this.GetRuleScope(); var symbolTable = (parameters == null) ? null : SymbolTable.NewFromRecord(parameters); @@ -503,8 +508,8 @@ namespace Microsoft.PowerFx var ruleScope = this.GetRuleScope(); return ExpressionLocalizationHelper.ConvertExpression(expressionText, ruleScope, GetDefaultBindingConfig(), CreateResolverInternal(symbolTable), CreateBinderGlue(), parseCulture, Config.Features, toDisplay: false); - } - + } + internal string GetInvariantExpressionWorker(string expressionText, ReadOnlySymbolTable symbolTable, ParserOptions options) { var ruleScope = this.GetRuleScope(); @@ -531,11 +536,12 @@ namespace Microsoft.PowerFx { var ruleScope = this.GetRuleScope(); return ExpressionLocalizationHelper.ConvertExpression(expressionText, ruleScope, GetDefaultBindingConfig(), CreateResolverInternal(symbolTable), CreateBinderGlue(), culture, Config.Features, toDisplay: true); - } - - internal void AddUserDefinedFunction(string script, CultureInfo parseCulture = null, ReadOnlySymbolTable symbolTable = null, bool allowSideEffects = false) - { - Config.SymbolTable.AddUserDefinedFunction(script, parseCulture, SupportedFunctions, symbolTable, allowSideEffects); + } + + internal void AddUserDefinedFunction(string script, CultureInfo parseCulture = null, ReadOnlySymbolTable symbolTable = null, bool allowSideEffects = false) + { + var engineTypesAndFunctions = ReadOnlySymbolTable.Compose(PrimitiveTypes, SupportedFunctions); + Config.SymbolTable.AddUserDefinedFunction(script, parseCulture, engineTypesAndFunctions, symbolTable, allowSideEffects); } } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs index ddfe47582..8b6e51d98 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs @@ -2,6 +2,8 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Text; using Microsoft.PowerFx.Core.Entities; @@ -70,7 +72,25 @@ namespace Microsoft.PowerFx.Types internal FormulaType(DType type) { _type = type; - } + } + + // Primitive types - Keeping it same as PrimitiveTypeSymbolTable + internal static readonly IReadOnlyDictionary PrimitiveTypes = ImmutableDictionary.CreateRange(new Dictionary() + { + { new DName("Boolean"), Boolean }, + { new DName("Color"), Color }, + { new DName("Date"), Date }, + { new DName("Time"), Time }, + { new DName("DateTime"), DateTime }, + { new DName("DateTimeTZInd"), DateTimeNoTimeZone }, + { new DName("GUID"), Guid }, + { new DName("Number"), Number }, + { new DName("Decimal"), Decimal }, + { new DName("Text"), String }, + { new DName("Hyperlink"), Hyperlink }, + { new DName("None"), Blank }, + { new DName("UntypedObject"), UntypedObject }, + }); /// /// Initializes a new instance of the class. @@ -110,25 +130,6 @@ namespace Microsoft.PowerFx.Types return type; } - internal static FormulaType[] GetValidUDFPrimitiveTypes() - { - FormulaType[] validTypes = { Blank, Boolean, Number, Decimal, String, Time, Date, DateTime, DateTimeNoTimeZone, Hyperlink, Color, Guid }; - return validTypes; - } - - internal static FormulaType GetFromStringOrNull(string formula) - { - foreach (FormulaType formulaType in GetValidUDFPrimitiveTypes()) - { - if (string.Equals(formulaType.ToString(), formula, StringComparison.Ordinal)) - { - return formulaType; - } - } - - return null; - } - // Get the correct derived type internal static FormulaType Build(DType type) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Syntax/Visitors/DTypeVisitor.cs b/src/libraries/Microsoft.PowerFx.Core/Syntax/Visitors/DTypeVisitor.cs index 54211219b..b7cb4cab2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Syntax/Visitors/DTypeVisitor.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Syntax/Visitors/DTypeVisitor.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.PowerFx.Core.Binding; using Microsoft.PowerFx.Core.Binding.BindInfo; using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Core.Utils; @@ -13,104 +14,104 @@ using Microsoft.PowerFx.Types; namespace Microsoft.PowerFx.Core.Syntax.Visitors { - internal class DTypeVisitor : TexlFunctionalVisitor + internal class DTypeVisitor : TexlFunctionalVisitor { private DTypeVisitor() { } - public static DType Run(TexlNode node, DefinedTypeSymbolTable context) + public static DType Run(TexlNode node, INameResolver context) { return node.Accept(new DTypeVisitor(), context); } - public override DType Visit(ErrorNode node, DefinedTypeSymbolTable context) + public override DType Visit(ErrorNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(BlankNode node, DefinedTypeSymbolTable context) + public override DType Visit(BlankNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(BoolLitNode node, DefinedTypeSymbolTable context) + public override DType Visit(BoolLitNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(StrLitNode node, DefinedTypeSymbolTable context) + public override DType Visit(StrLitNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(NumLitNode node, DefinedTypeSymbolTable context) + public override DType Visit(NumLitNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(DecLitNode node, DefinedTypeSymbolTable context) + public override DType Visit(DecLitNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(FirstNameNode node, DefinedTypeSymbolTable context) + public override DType Visit(FirstNameNode node, INameResolver context) { var name = node.Ident.Name.Value; - if (context.TryLookup(new DName(name), out NameLookupInfo nameInfo)) + if (context.LookupType(new DName(name), out FormulaType ft)) { - return nameInfo.Type; + return ft._type; } - return FormulaType.GetFromStringOrNull(name)._type; + return DType.Invalid; } - public override DType Visit(ParentNode node, DefinedTypeSymbolTable context) + public override DType Visit(ParentNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(SelfNode node, DefinedTypeSymbolTable context) + public override DType Visit(SelfNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(StrInterpNode node, DefinedTypeSymbolTable context) + public override DType Visit(StrInterpNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(DottedNameNode node, DefinedTypeSymbolTable context) + public override DType Visit(DottedNameNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(UnaryOpNode node, DefinedTypeSymbolTable context) + public override DType Visit(UnaryOpNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(BinaryOpNode node, DefinedTypeSymbolTable context) + public override DType Visit(BinaryOpNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(VariadicOpNode node, DefinedTypeSymbolTable context) + public override DType Visit(VariadicOpNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(CallNode node, DefinedTypeSymbolTable context) + public override DType Visit(CallNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(ListNode node, DefinedTypeSymbolTable context) + public override DType Visit(ListNode node, INameResolver context) { throw new NotImplementedException(); } - public override DType Visit(RecordNode node, DefinedTypeSymbolTable context) + public override DType Visit(RecordNode node, INameResolver context) { var list = new List(); foreach (var (cNode, ident) in node.ChildNodes.Zip(node.Ids, (a, b) => (a, b))) @@ -127,7 +128,7 @@ namespace Microsoft.PowerFx.Core.Syntax.Visitors return DType.CreateRecord(list); } - public override DType Visit(TableNode node, DefinedTypeSymbolTable context) + public override DType Visit(TableNode node, INameResolver context) { var childNode = node.ChildNodes.First(); var ty = childNode.Accept(this, context); @@ -139,7 +140,7 @@ namespace Microsoft.PowerFx.Core.Syntax.Visitors return ty.ToTable(); } - public override DType Visit(AsNode node, DefinedTypeSymbolTable context) + public override DType Visit(AsNode node, INameResolver context) { throw new NotImplementedException(); } diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/DefinedTypeSymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/DefinedTypeSymbolTable.cs deleted file mode 100644 index 2a76a3e47..000000000 --- a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/DefinedTypeSymbolTable.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.PowerFx.Core.Binding; -using Microsoft.PowerFx.Core.Binding.BindInfo; -using Microsoft.PowerFx.Core.Types; -using Microsoft.PowerFx.Core.UtilityDataStructures; -using Microsoft.PowerFx.Core.Utils; -using Microsoft.PowerFx.Types; - -namespace Microsoft.PowerFx.Core -{ - [NotThreadSafe] - internal class DefinedTypeSymbolTable : TypeSymbolTable, IGlobalSymbolNameResolver - { - private readonly BidirectionalDictionary _definedTypes = new (); - - IEnumerable> IGlobalSymbolNameResolver.GlobalSymbols => _definedTypes.ToDictionary(kvp => kvp.Key, kvp => ToLookupInfo(kvp.Value)); - - internal void RegisterType(string typeName, FormulaType type) - { - Inc(); - - _definedTypes.Add(typeName, type); - } - - protected void ValidateName(string name) - { - if (!DName.IsValidDName(name)) - { - throw new ArgumentException("Invalid name: ${name}"); - } - } - - internal override bool TryLookup(DName name, out NameLookupInfo nameInfo) - { - if (!_definedTypes.TryGetFromFirst(name.Value, out var type)) - { - nameInfo = default; - return false; - } - - nameInfo = ToLookupInfo(type); - return true; - } - - internal override bool TryGetTypeName(FormulaType type, out string typeName) - { - return _definedTypes.TryGetFromSecond(type, out typeName); - } - } -} diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/PrimitiveTypesSymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/PrimitiveTypesSymbolTable.cs deleted file mode 100644 index d7ea9fdb6..000000000 --- a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/PrimitiveTypesSymbolTable.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.PowerFx.Core.Binding; -using Microsoft.PowerFx.Core.Binding.BindInfo; -using Microsoft.PowerFx.Core.Types; -using Microsoft.PowerFx.Core.UtilityDataStructures; -using Microsoft.PowerFx.Core.Utils; -using Microsoft.PowerFx.Types; - -namespace Microsoft.PowerFx.Core.Public.Types -{ - [ThreadSafeImmutable] - internal sealed class PrimitiveTypesSymbolTable : TypeSymbolTable, IGlobalSymbolNameResolver - { - private static readonly IReadOnlyDictionary _knownTypes = new Dictionary() - { - { "Boolean", FormulaType.Boolean }, - { "Color", FormulaType.Color }, - { "Date", FormulaType.Date }, - { "Time", FormulaType.Time }, - { "DateTime", FormulaType.DateTime }, - { "DateTimeTZInd", FormulaType.DateTimeNoTimeZone }, - { "GUID", FormulaType.Guid }, - { "Number", FormulaType.Number }, - { "Decimal", FormulaType.Decimal }, - { "Text", FormulaType.String }, - { "Hyperlink", FormulaType.Hyperlink }, - { "None", FormulaType.Blank }, - { "UntypedObject", FormulaType.UntypedObject }, - }; - - IEnumerable> IGlobalSymbolNameResolver.GlobalSymbols => _knownTypes.ToDictionary(kvp => kvp.Key, kvp => ToLookupInfo(kvp.Value)); - - internal override VersionHash VersionHash => base.VersionHash; - - private PrimitiveTypesSymbolTable() - { - } - - public static readonly PrimitiveTypesSymbolTable Instance = new PrimitiveTypesSymbolTable(); - - internal override bool TryLookup(DName name, out NameLookupInfo nameInfo) - { - if (!_knownTypes.TryGetValue(name.Value, out var type)) - { - nameInfo = default; - return false; - } - - nameInfo = ToLookupInfo(type); - return true; - } - - internal override bool TryGetTypeName(FormulaType type, out string typeName) - { - typeName = _knownTypes.Where(kvp => kvp.Value.Equals(type)).FirstOrDefault().Key; - - return typeName != null; - } - } -} diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/TypeSymbolTable.cs b/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/TypeSymbolTable.cs deleted file mode 100644 index 55234db0a..000000000 --- a/src/libraries/Microsoft.PowerFx.Core/Types/TypeSymbolTable/TypeSymbolTable.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.PowerFx.Core.Binding; -using Microsoft.PowerFx.Core.Binding.BindInfo; -using Microsoft.PowerFx.Core.Types; -using Microsoft.PowerFx.Core.UtilityDataStructures; -using Microsoft.PowerFx.Core.Utils; -using Microsoft.PowerFx.Types; - -namespace Microsoft.PowerFx.Core -{ - internal abstract class TypeSymbolTable : ReadOnlySymbolTable - { - internal abstract bool TryGetTypeName(FormulaType type, out string typeName); - - protected NameLookupInfo ToLookupInfo(FormulaType type) - { - return new NameLookupInfo(BindKind.TypeName, type._type, DPath.Root, 0, data: type); - } - } -} diff --git a/src/libraries/Microsoft.PowerFx.Core/Utils/TokenUtils.cs b/src/libraries/Microsoft.PowerFx.Core/Utils/TokenUtils.cs deleted file mode 100644 index c67e670f5..000000000 --- a/src/libraries/Microsoft.PowerFx.Core/Utils/TokenUtils.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.PowerFx.Core.Public.Types; -using Microsoft.PowerFx.Syntax; -using Microsoft.PowerFx.Types; - -namespace Microsoft.PowerFx.Core.Utils -{ - internal static class TokenUtils - { - internal static FormulaType GetFormulaType(this IdentToken token) - { - var formulaType = FormulaType.Unknown; - if (PrimitiveTypesSymbolTable.Instance.TryLookup(token.Name, out var info) && info.Data is FormulaType ft) - { - formulaType = ft; - } - - return formulaType; - } - } -} diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs index 13cb24557..b090509bd 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs @@ -33,7 +33,6 @@ namespace Microsoft.PowerFx internal readonly SymbolTable _symbolTable; internal readonly SymbolValues _symbolValues; - internal readonly DefinedTypeSymbolTable _definedTypeSymbolTable; /// /// Initializes a new instance of the class. @@ -49,7 +48,6 @@ namespace Microsoft.PowerFx { _symbolTable = new SymbolTable { DebugName = "Globals" }; _symbolValues = new SymbolValues(_symbolTable); - _definedTypeSymbolTable = new DefinedTypeSymbolTable(); _symbolValues.OnUpdate += OnSymbolValuesOnUpdate; base.EngineSymbols = _symbolTable; @@ -215,21 +213,6 @@ namespace Microsoft.PowerFx return result; } - internal FormulaType GetFormulaTypeFromName(string name) - { - return FormulaType.Build(GetTypeFromName(name)); - } - - internal DType GetTypeFromName(string name) - { - if (_definedTypeSymbolTable.TryLookup(new DName(name), out NameLookupInfo nameInfo)) - { - return nameInfo.Type; - } - - return FormulaType.GetFromStringOrNull(name)._type; - } - // Invoke onUpdate() each time this formula is changed, passing in the new value. public void SetFormula(string name, string expr, Action onUpdate) { @@ -404,7 +387,11 @@ namespace Microsoft.PowerFx var sb = new StringBuilder(); var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + + // Compose will handle null symbols + var composedSymbols = SymbolTable.Compose(Config.SymbolTable, SupportedFunctions, PrimitiveTypes); + + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), composedSymbols, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); if (errors.Any()) @@ -419,9 +406,6 @@ namespace Microsoft.PowerFx throw new InvalidOperationException(sb.ToString()); } - // Compose will handle null symbols - var composedSymbols = SymbolTable.Compose(Config.SymbolTable, SupportedFunctions); - foreach (var udf in udfs) { Config.SymbolTable.AddFunction(udf); diff --git a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeJsonConverter.cs b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeJsonConverter.cs index a080dc62c..09d45eed5 100644 --- a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeJsonConverter.cs +++ b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeJsonConverter.cs @@ -14,11 +14,11 @@ namespace Microsoft.PowerFx.Core { public class FormulaTypeJsonConverter : JsonConverter { - private readonly DefinedTypeSymbolTable _definedTypes; + private readonly SymbolTable _definedTypes; private readonly FormulaTypeSerializerSettings _settings; - internal FormulaTypeJsonConverter(DefinedTypeSymbolTable definedTypes) + internal FormulaTypeJsonConverter(SymbolTable definedTypes) { _definedTypes = definedTypes; _settings = new FormulaTypeSerializerSettings(null); @@ -37,7 +37,7 @@ namespace Microsoft.PowerFx.Core /// /// public FormulaTypeJsonConverter(FormulaTypeSerializerSettings settings) - : this(new DefinedTypeSymbolTable()) + : this(new SymbolTable()) { _settings = settings ?? _settings; } diff --git a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeSchema.cs b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeSchema.cs index 9ad3d92ca..96fe9ce60 100644 --- a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeSchema.cs +++ b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeSchema.cs @@ -41,7 +41,7 @@ namespace Microsoft.PowerFx.Core [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary Fields { get; set; } - public FormulaType ToFormulaType(DefinedTypeSymbolTable definedTypeSymbols, FormulaTypeSerializerSettings settings) + public FormulaType ToFormulaType(INameResolver definedTypeSymbols, FormulaTypeSerializerSettings settings) { var typeName = Type.Name; @@ -86,19 +86,14 @@ namespace Microsoft.PowerFx.Core return FormulaType.BindingError; } - private static bool TryLookupType(string typeName, DefinedTypeSymbolTable definedTypeSymbols, out FormulaType type) + private static bool TryLookupType(string typeName, INameResolver definedTypeSymbols, out FormulaType type) { - var lookupOrder = new List() { definedTypeSymbols, PrimitiveTypesSymbolTable.Instance }; + var lookupOrder = new List() { definedTypeSymbols, ReadOnlySymbolTable.PrimitiveTypesTableInstance }; foreach (var table in lookupOrder) { - if (table.TryLookup(new DName(typeName), out var lookupInfo)) + if (table.LookupType(new DName(typeName), out var ft)) { - if (lookupInfo.Kind != BindKind.TypeName || lookupInfo.Data is not FormulaType castType) - { - throw new InvalidOperationException("Resolved non-type name when constructing FormulaType definition"); - } - - type = castType; + type = ft; return true; } } diff --git a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeToSchemaHelper.cs b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeToSchemaHelper.cs index b9613f57e..8862faf0c 100644 --- a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeToSchemaHelper.cs +++ b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/FormulaTypeToSchemaHelper.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.PowerFx.Core.Binding; using Microsoft.PowerFx.Core.Public.Types; using Microsoft.PowerFx.Types; @@ -10,7 +12,7 @@ namespace Microsoft.PowerFx.Core { internal static class FormulaTypeToSchemaHelper { - public static FormulaTypeSchema ToSchema(this FormulaType type, DefinedTypeSymbolTable definedTypeSymbols, FormulaTypeSerializerSettings settings) + public static FormulaTypeSchema ToSchema(this FormulaType type, INameResolver definedTypeSymbols, FormulaTypeSerializerSettings settings) { // Converting a formulaType to a FormulaTypeSchema requires cutting off at a max depth // FormulaType may contain recurisve definitions that are not supported by FormulaTypeSchema @@ -18,7 +20,7 @@ namespace Microsoft.PowerFx.Core return ToSchema(type, definedTypeSymbols, settings, maxDepth: 5); } - private static FormulaTypeSchema ToSchema(FormulaType type, DefinedTypeSymbolTable definedTypeSymbols, FormulaTypeSerializerSettings settings, int maxDepth) + private static FormulaTypeSchema ToSchema(FormulaType type, INameResolver definedTypeSymbols, FormulaTypeSerializerSettings settings, int maxDepth) { if (TryLookupTypeName(type, definedTypeSymbols, out var typeName)) { @@ -84,13 +86,16 @@ namespace Microsoft.PowerFx.Core }; } - private static bool TryLookupTypeName(FormulaType type, DefinedTypeSymbolTable definedTypeSymbols, out string typeName) + private static bool TryLookupTypeName(FormulaType type, INameResolver definedTypeSymbols, out string typeName) { - var lookupOrder = new List() { definedTypeSymbols, PrimitiveTypesSymbolTable.Instance }; + var lookupOrder = new List() { definedTypeSymbols, ReadOnlySymbolTable.PrimitiveTypesTableInstance }; foreach (var table in lookupOrder) { - if (table.TryGetTypeName(type, out typeName)) + var typeNames = table.NamedTypes.Where(kvp => kvp.Value.Equals(type)); + + if (typeNames.Any()) { + typeName = typeNames.FirstOrDefault().Key.Value; return true; } } @@ -99,7 +104,7 @@ namespace Microsoft.PowerFx.Core return false; } - private static Dictionary GetChildren(AggregateType type, DefinedTypeSymbolTable definedTypeSymbols, FormulaTypeSerializerSettings settings, int maxDepth) + private static Dictionary GetChildren(AggregateType type, INameResolver definedTypeSymbols, FormulaTypeSerializerSettings settings, int maxDepth) { var fields = new Dictionary(StringComparer.Ordinal); foreach (var child in type.GetFieldTypes()) diff --git a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/UserDefinedRecordType.cs b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/UserDefinedRecordType.cs index 706297821..2e3f2c949 100644 --- a/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/UserDefinedRecordType.cs +++ b/src/libraries/Microsoft.PowerFx.Json/Public/Types/UserProvidedTypeDefinitions/UserDefinedRecordType.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.PowerFx.Core.Binding; using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Types; @@ -14,23 +15,23 @@ namespace Microsoft.PowerFx.Core /// Aggregate Type Definition derived from a .fx.yaml file /// This may recursively refer to itself or other types, and so we resolve /// the field types lazily using the DefinedTypeSymbolTable - /// passed to "/>. + /// passed to "/>. /// internal class UserDefinedRecordType : RecordType { private readonly FormulaTypeSchema _backingSchema; - private readonly DefinedTypeSymbolTable _symbolTable; + private readonly INameResolver _symbolTable; private readonly FormulaTypeSerializerSettings _settings; public override IEnumerable FieldNames => _backingSchema.Fields?.Keys ?? Enumerable.Empty(); - public UserDefinedRecordType(FormulaTypeSchema backingSchema, DefinedTypeSymbolTable definedTypes) + public UserDefinedRecordType(FormulaTypeSchema backingSchema, INameResolver definedTypes) { _backingSchema = backingSchema; _symbolTable = definedTypes; } - public UserDefinedRecordType(FormulaTypeSchema backingSchema, DefinedTypeSymbolTable definedTypes, FormulaTypeSerializerSettings settings) + public UserDefinedRecordType(FormulaTypeSchema backingSchema, INameResolver definedTypes, FormulaTypeSerializerSettings settings) { _backingSchema = backingSchema; _symbolTable = definedTypes; diff --git a/src/tests/Microsoft.PowerFx.Core.Tests/ParseTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests/ParseTests.cs index e303377f2..456b5b2e1 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests/ParseTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests/ParseTests.cs @@ -18,7 +18,9 @@ using Xunit; namespace Microsoft.PowerFx.Core.Tests { public class ParseTests : PowerFxTest - { + { + private static readonly ReadOnlySymbolTable _primitiveTypes = ReadOnlySymbolTable.PrimitiveTypesTableInstance; + [Theory] [InlineData("0")] [InlineData("-0")] @@ -901,7 +903,7 @@ namespace Microsoft.PowerFx.Core.Tests }; var parseResult = UserDefinitions.Parse(script, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.Equal(udfCount, udfs.Count()); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests/UserDefinedFunctionTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests/UserDefinedFunctionTests.cs index 63351d0aa..53341b24e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests/UserDefinedFunctionTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests/UserDefinedFunctionTests.cs @@ -21,6 +21,8 @@ namespace Microsoft.PowerFx.Core.Tests { public class UserDefinedFunctionTests : PowerFxTest { + private static readonly ReadOnlySymbolTable _primitiveTypes = ReadOnlySymbolTable.PrimitiveTypesTableInstance; + [Theory] [InlineData("Foo(x: Number): Number = Abs(x);", 1, 0, false)] [InlineData("IsType(x: Number): Number = Abs(x);", 0, 0, true)] @@ -56,10 +58,12 @@ namespace Microsoft.PowerFx.Core.Tests }; var parseResult = UserDefinitions.Parse(script, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + + var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library, FormulaType.PrimitiveTypes); + + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), nameResolver, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); - var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library); var glue = new Glue2DocumentBinderGlue(); var hasBinderErrors = false; @@ -87,7 +91,7 @@ namespace Microsoft.PowerFx.Core.Tests var glue = new Glue2DocumentBinderGlue(); var parseResult = UserDefinitions.Parse(udfScript, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); var texlFunctionSet = new TexlFunctionSet(udfs); @@ -135,11 +139,11 @@ namespace Microsoft.PowerFx.Core.Tests AllowsSideEffects = false }; - var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library); + var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library, FormulaType.PrimitiveTypes); var glue = new Glue2DocumentBinderGlue(); var parseResult = UserDefinitions.Parse(udfScript, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), nameResolver, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); var texlFunctionSet = new TexlFunctionSet(udfs); @@ -398,7 +402,7 @@ namespace Microsoft.PowerFx.Core.Tests [Fact] public void Basic() { - var st1 = new SymbolTable(); + var st1 = SymbolTable.WithPrimitiveTypes(); st1.AddUserDefinedFunction("Foo1(x: Number): Number = x*2;"); st1.AddUserDefinedFunction("Foo2(x: Number): Number = Foo1(x)+1;"); @@ -408,7 +412,7 @@ namespace Microsoft.PowerFx.Core.Tests Assert.Equal(FormulaType.Number, check.ReturnType); // A different symbol table can have same function name with different type. - var st2 = new SymbolTable(); + var st2 = SymbolTable.WithPrimitiveTypes(); st2.AddUserDefinedFunction("Foo2(x: Number): Text = x;"); check = engine.Check("Foo2(3)", symbolTable: st2); Assert.True(check.IsSuccess); @@ -419,8 +423,7 @@ namespace Microsoft.PowerFx.Core.Tests public void DefineEmpty() { // Empty symbol table doesn't get builtins. - var st = new SymbolTable(); - + var st = SymbolTable.WithPrimitiveTypes(); st.AddUserDefinedFunction("Foo1(x: Number): Number = x;"); // ok Assert.Throws(() => st.AddUserDefinedFunction("Foo2(x: Number): Number = Abs(x);")); } @@ -451,13 +454,15 @@ namespace Microsoft.PowerFx.Core.Tests var script = "Add(a: Number, b: Number):Number = a + b;"; var parseResult = UserDefinitions.Parse(script, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + + var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library, FormulaType.PrimitiveTypes); + + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), nameResolver, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); var func = udfs.FirstOrDefault(); Assert.NotNull(func); - var nameResolver = ReadOnlySymbolTable.NewDefault(BuiltinFunctionsCore._library); var glue = new Glue2DocumentBinderGlue(); var texlFunctionSet = new TexlFunctionSet(udfs); @@ -486,7 +491,7 @@ namespace Microsoft.PowerFx.Core.Tests }; var parseResult = UserDefinitions.Parse(formula, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.Equal(nfCount, parseResult.NamedFormulas.Count()); @@ -509,7 +514,7 @@ namespace Microsoft.PowerFx.Core.Tests }; var parseResult = UserDefinitions.Parse(script, parserOptions); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.Contains(errors, x => x.MessageKey == "ErrUDF_UnknownType"); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests/RecalcEngineTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests/RecalcEngineTests.cs index d7226662a..f70340ce5 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests/RecalcEngineTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests/RecalcEngineTests.cs @@ -553,7 +553,7 @@ namespace Microsoft.PowerFx.Tests engine.UpdateVariable("myArg", FormulaValue.New(10)); - symbolTable.AddUserDefinedFunction(script, CultureInfo.InvariantCulture, engine.SupportedFunctions); + symbolTable.AddUserDefinedFunction(script, CultureInfo.InvariantCulture, engine.SupportedFunctions, engine.PrimitiveTypes); var check = engine.Check(expression, symbolTable: symbolTable); var result = check.GetEvaluator().Eval(); @@ -640,10 +640,10 @@ namespace Microsoft.PowerFx.Tests public void FunctionInner() { // Inner table - SymbolTable stInner = new SymbolTable { DebugName = "Extras" }; + SymbolTable stInner = SymbolTable.WithPrimitiveTypes(); stInner.AddUserDefinedFunction("Func1() : Text = \"inner\";"); - SymbolTable st = new SymbolTable { DebugName = "Extras" }; + SymbolTable st = SymbolTable.WithPrimitiveTypes(); st.AddUserDefinedFunction("Func2() : Text = Func1() & \"2\";", symbolTable: stInner); var engine = new RecalcEngine(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests/UserDefinedTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests/UserDefinedTests.cs index acb201b35..7c9018adb 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests/UserDefinedTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests/UserDefinedTests.cs @@ -12,7 +12,9 @@ using Xunit; namespace Microsoft.PowerFx.Interpreter.Tests { public class UserDefinedTests - { + { + private static readonly ReadOnlySymbolTable _primitiveTypes = ReadOnlySymbolTable.PrimitiveTypesTableInstance; + [Theory] [InlineData("x=1;y=2;z=x+y;", "Float(Abs(-(x+y+z)))", 6d)] [InlineData("x=1;y=2;Foo(x: Number): Number = Abs(x);", "Foo(-(y*y)+x)", 3d)] @@ -42,7 +44,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests Culture = CultureInfo.InvariantCulture }; var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.False(errors.Any()); @@ -59,7 +61,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests Culture = CultureInfo.InvariantCulture }; var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.False(errors.Any()); @@ -75,7 +77,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests Culture = CultureInfo.InvariantCulture }; var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.True(errors.Any()); @@ -92,7 +94,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests Culture = CultureInfo.InvariantCulture }; var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.True(errors.Any()); @@ -111,7 +113,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests }; var parseResult = UserDefinitions.Parse(script, options); - var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out var errors); + var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.True(errors.Any()); @@ -122,7 +124,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests Culture = CultureInfo.InvariantCulture }; parseResult = UserDefinitions.Parse(script, options); - udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), out errors); + udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); Assert.False(errors.Any()); diff --git a/src/tests/Microsoft.PowerFx.Json.Tests/TypeSystemTests/FormulaTypeSerializerSnapshotTests.cs b/src/tests/Microsoft.PowerFx.Json.Tests/TypeSystemTests/FormulaTypeSerializerSnapshotTests.cs index 5b7374851..3ae1842d9 100644 --- a/src/tests/Microsoft.PowerFx.Json.Tests/TypeSystemTests/FormulaTypeSerializerSnapshotTests.cs +++ b/src/tests/Microsoft.PowerFx.Json.Tests/TypeSystemTests/FormulaTypeSerializerSnapshotTests.cs @@ -125,7 +125,7 @@ namespace Microsoft.PowerFx.Json.Tests Converters = { // Serialize types without accounting for any defined type names - new FormulaTypeJsonConverter(new DefinedTypeSymbolTable()) + new FormulaTypeJsonConverter(new SymbolTable()) } }); } @@ -139,7 +139,7 @@ namespace Microsoft.PowerFx.Json.Tests Converters = { // Serialize types without accounting for any defined type names - new FormulaTypeJsonConverter(new DefinedTypeSymbolTable()) + new FormulaTypeJsonConverter(new SymbolTable()) } }); }