From f473c482477f9f6cee401668d8fa13f2647a4b9a Mon Sep 17 00:00:00 2001 From: Adithya Selvaprithiviraj Date: Tue, 22 Oct 2024 10:58:51 -0700 Subject: [PATCH] Clean up User-defined type related parser flag (#2697) * Remove `AllowParseAsTypeLiteral, AllowTypeLiteral` parser flag. * AsType, IsType and ParseJSON overloads are part of Builtin Functions * Add constant for Type Keyword. * Add type arg functions to Built-in * Refactor test --- releasenotes/releasenotes-1.3.0-rc.md | 5 +++ .../ExpressionLocalizationHelper.cs | 2 +- .../Parser/ParserOptions.cs | 6 ---- .../Parser/TexlParser.cs | 22 ++++++------ .../Public/DefinitionsCheckResult.cs | 12 +++++-- .../Microsoft.PowerFx.Core/Syntax/Formula.cs | 4 +-- .../Syntax/TexlPretty.cs | 8 ++--- .../Syntax/UserDefinitions.cs | 7 ++-- .../Texl/BuiltinFunctionsCore.cs | 12 +++---- .../Utils/LanguageConstants.cs | 5 +++ .../RecalcEngine.cs | 3 +- .../Modules/ModuleLoadContext.cs | 3 +- src/libraries/Microsoft.PowerFx.Repl/Repl.cs | 2 +- .../ExpressionTestCases/AsType_UO.txt | 30 +++------------- .../AsType_UO_TimeZone_Seattle.txt | 19 ++++++++++ .../ExpressionTestCases/IsType_UO.txt | 2 -- .../ExpressionTestCases/TypedParseJSON.txt | 18 ++-------- .../TypedParseJSON_TimeZone_Seattle.txt | 13 +++++++ .../NamedFormulasTests.cs | 12 +++---- .../UserDefinedTypeTests.cs | 28 +++------------ .../Helpers/ParserOptionsExtensions.cs | 5 --- .../RecalcEngineTests.cs | 4 +-- .../AsTypeIsTypeParseJSONTests.cs | 35 ++++++++----------- 23 files changed, 113 insertions(+), 144 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO_TimeZone_Seattle.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON_TimeZone_Seattle.txt diff --git a/releasenotes/releasenotes-1.3.0-rc.md b/releasenotes/releasenotes-1.3.0-rc.md index 5c9372391c..1aaf03c5c0 100644 --- a/releasenotes/releasenotes-1.3.0-rc.md +++ b/releasenotes/releasenotes-1.3.0-rc.md @@ -25,6 +25,11 @@ `Patch(DS, table_of_rows_with_updates)`\ `Patch(Record, Updates1, Updates2,…)` + - ParseJSON, IsType, AsType (https://github.com/microsoft/Power-Fx/pull/2569): ParseJSON, IsType, AsType functions now supports in-lined and user-defined types as argument.\ + `ParseJSON(Text, Type)`\ + `IsType(UntypedObject, Type)`\ + `AsType(UntypedObject, Type)` + ## Other: - Untyped object - Read a field from an untyped object by index (https://github.com/microsoft/Power-Fx/pull/2555): diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/ExpressionLocalizationHelper.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/ExpressionLocalizationHelper.cs index d3ce64e3e6..5ce236750a 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/ExpressionLocalizationHelper.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/ExpressionLocalizationHelper.cs @@ -22,7 +22,7 @@ internal static string ConvertExpression(string expressionText, RecordType param var formula = new Formula(expressionText, toDisplay ? CultureInfo.InvariantCulture : options?.Culture ?? CultureInfo.InvariantCulture); - formula.EnsureParsed(options.GetParserFlags()); + formula.EnsureParsed(options.GetParserFlags(), flags); var binding = TexlBinding.Run( binderGlue, diff --git a/src/libraries/Microsoft.PowerFx.Core/Parser/ParserOptions.cs b/src/libraries/Microsoft.PowerFx.Core/Parser/ParserOptions.cs index 839084dff6..f1c75de7d6 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Parser/ParserOptions.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Parser/ParserOptions.cs @@ -47,11 +47,6 @@ public class ParserOptions /// public int MaxExpressionLength { get; set; } - /// - /// Flag for parse type literals. - /// - internal bool AllowParseAsTypeLiteral { get; set; } - /// /// Allow parsing of attributes on user definitions /// This is an early prototype, and so is internal. @@ -88,7 +83,6 @@ internal ParseResult Parse(string script, Features features) (NumberIsFloat ? TexlParser.Flags.NumberIsFloat : 0) | (DisableReservedKeywords ? TexlParser.Flags.DisableReservedKeywords : 0) | (TextFirst ? TexlParser.Flags.TextFirst : 0) | - (AllowParseAsTypeLiteral ? TexlParser.Flags.AllowTypeLiteral : 0) | (features.PowerFxV1CompatibilityRules ? TexlParser.Flags.PFxV1 : 0); var result = TexlParser.ParseScript(script, features, Culture, flags); diff --git a/src/libraries/Microsoft.PowerFx.Core/Parser/TexlParser.cs b/src/libraries/Microsoft.PowerFx.Core/Parser/TexlParser.cs index 8f95c9a50f..0deba98569 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Parser/TexlParser.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Parser/TexlParser.cs @@ -34,9 +34,6 @@ public enum Flags // When specified, allows reserved keywords to be used as identifiers. DisableReservedKeywords = 1 << 3, - // When specified, allows type literals to be parsed. - AllowTypeLiteral = 1 << 4, - // Text first. Implemented entirely in the Lexer. TextFirst = 1 << 5, @@ -90,16 +87,16 @@ private TexlParser(IReadOnlyList tokens, Flags flags, Features features = /// /// Script to be parsed. /// Options for parsing an expression. + /// Power Fx feature flags. /// . - public static ParseUserDefinitionResult ParseUserDefinitionScript(string script, ParserOptions parserOptions) + public static ParseUserDefinitionResult ParseUserDefinitionScript(string script, ParserOptions parserOptions, Features features = null) { Contracts.AssertValue(parserOptions); var flags = Flags.NamedFormulas | (parserOptions.NumberIsFloat ? Flags.NumberIsFloat : 0) | - (parserOptions.AllowParseAsTypeLiteral ? Flags.AllowTypeLiteral : 0) | (parserOptions.AllowAttributes ? Flags.AllowAttributes : 0); var formulaTokens = TokenizeScript(script, parserOptions.Culture, flags); - var parser = new TexlParser(formulaTokens, flags); + var parser = new TexlParser(formulaTokens, flags, features); return parser.ParseUDFsAndNamedFormulas(script, parserOptions); } @@ -300,7 +297,7 @@ private ParseUserDefinitionResult ParseUDFsAndNamedFormulas(string script, Parse continue; } - if (_curs.TidCur == TokKind.ColonEqual && _flagsMode.Peek().HasFlag(Flags.AllowTypeLiteral)) + if (_curs.TidCur == TokKind.ColonEqual && _features.IsUserDefinedTypesEnabled) { var declaration = script.Substring(declarationStart, _curs.TokCur.Span.Min - declarationStart); _curs.TokMove(); @@ -1268,7 +1265,7 @@ private TexlNode ParseOperand() if (AfterSpaceTokenId() == TokKind.ParenOpen) { - if (ident.Token.As().Name.Value == "Type" && _flagsMode.Peek().HasFlag(Flags.AllowTypeLiteral)) + if (ident.Token.As().Name.Value == LanguageConstants.TypeLiteralInvariantName && _features.IsUserDefinedTypesEnabled) { var typeLiteralNode = ParseTypeLiteral(); @@ -2048,11 +2045,13 @@ internal static string GetTokString(TokKind kind) /// /// Expression text to format. /// Optional flags to customize the behavior of underlying lexer and parser. By default, expression chaining is enabled. + /// Power Fx features. /// Formatted expression text. - public static string Format(string text, Flags flags = Flags.EnableExpressionChaining) + public static string Format(string text, Flags flags = Flags.EnableExpressionChaining, Features features = null) { var result = ParseScript( text, + features ?? Features.None, flags: flags); // Can't pretty print a script with errors. @@ -2064,11 +2063,12 @@ public static string Format(string text, Flags flags = Flags.EnableExpressionCha return PrettyPrintVisitor.Format(result.Root, result.Before, result.After, text); } - public static string FormatUserDefinitions(string text, ParserOptions options) + public static string FormatUserDefinitions(string text, ParserOptions options, Features features = null) { var result = ParseUserDefinitionScript( text, - options); + options, + features ?? Features.None); // Can't pretty print a script with errors. if (result.HasErrors) diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/DefinitionsCheckResult.cs b/src/libraries/Microsoft.PowerFx.Core/Public/DefinitionsCheckResult.cs index 7b708f3c31..cb83794fd4 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/DefinitionsCheckResult.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/DefinitionsCheckResult.cs @@ -40,6 +40,8 @@ public class DefinitionsCheckResult : IOperationStatus private ParseUserDefinitionResult _parse; + private readonly Features _features; + // Local symboltable to store new symbols in a given script and use in binding. private readonly SymbolTable _localSymbolTable; @@ -49,9 +51,15 @@ public class DefinitionsCheckResult : IOperationStatus // All errors accumulated. private readonly List _errors = new List(); - public DefinitionsCheckResult() + public DefinitionsCheckResult() + : this(Features.PowerFxV1) + { + } + + public DefinitionsCheckResult(Features features = null) { _localSymbolTable = new SymbolTable { DebugName = "LocalUserDefinitions" }; + _features = features ?? Features.PowerFxV1; } internal DefinitionsCheckResult SetBindingInfo(ReadOnlySymbolTable symbols) @@ -93,7 +101,7 @@ internal ParseUserDefinitionResult ApplyParse() if (_parse == null) { - _parse = UserDefinitions.Parse(_definitions, _parserOptions); + _parse = UserDefinitions.Parse(_definitions, _parserOptions, _features); if (_parse.HasErrors) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Syntax/Formula.cs b/src/libraries/Microsoft.PowerFx.Core/Syntax/Formula.cs index 73ccbce5ca..7925a94d3d 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Syntax/Formula.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Syntax/Formula.cs @@ -70,13 +70,13 @@ private void AssertValid() // True if the formula has already been parsed. public bool IsParsed => ParseTree != null; - public bool EnsureParsed(TexlParser.Flags flags) + public bool EnsureParsed(TexlParser.Flags flags, Features features = null) { AssertValid(); if (ParseTree == null) { - var result = TexlParser.ParseScript(Script, loc: Loc, flags: flags); + var result = TexlParser.ParseScript(Script, features ?? Features.None, culture: Loc, flags: flags); ApplyParse(result); } diff --git a/src/libraries/Microsoft.PowerFx.Core/Syntax/TexlPretty.cs b/src/libraries/Microsoft.PowerFx.Core/Syntax/TexlPretty.cs index 50991cb40f..d8fc2d63cc 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Syntax/TexlPretty.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Syntax/TexlPretty.cs @@ -412,7 +412,7 @@ public override LazyList Visit(TypeLiteralNode node, Precedence parentPr result = result .With( - "Type", + LanguageConstants.TypeLiteralInvariantName, TexlLexer.PunctuatorParenOpen) .With(node.TypeRoot.Accept(this, Precedence.Atomic)) .With(TexlLexer.PunctuatorParenClose); @@ -466,9 +466,7 @@ private string SpacedOper(string op) internal sealed class PrettyPrintVisitor : TexlFunctionalVisitor, PrettyPrintVisitor.Context> { - private readonly string _script; - - public const string TypeInvariantFunctionName = "Type"; + private readonly string _script; private static readonly Dictionary BinaryPrecedence = new Dictionary() @@ -542,7 +540,7 @@ public static string FormatUserDefinitions(ParseUserDefinitionResult result, str case UserDefinitionType.DefinedType: var type = result.DefinedTypes.First(type => type.Ident == name); - definitions.Add(declaration + $" = {TypeInvariantFunctionName}(" + string.Concat(visitor.CommentsOf(before).With(type.Type.Accept(visitor, new Context(0)).With(visitor.CommentsOf(after)))) + ")"); + definitions.Add(declaration + $" = {LanguageConstants.TypeLiteralInvariantName}(" + string.Concat(visitor.CommentsOf(before).With(type.Type.Accept(visitor, new Context(0)).With(visitor.CommentsOf(after)))) + ")"); break; default: continue; diff --git a/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs b/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs index 147b7d735a..cdd8c791d1 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs @@ -44,14 +44,15 @@ private UserDefinitions(string script, ParserOptions parserOptions, Features fea /// /// Script with named formulas, user-defined functions and user-defined types. /// Options for parsing an expression. + /// Power Fx feature flags. /// . - public static ParseUserDefinitionResult Parse(string script, ParserOptions parserOptions) + public static ParseUserDefinitionResult Parse(string script, ParserOptions parserOptions, Features features = null) { - var parseResult = TexlParser.ParseUserDefinitionScript(script, parserOptions); + var parseResult = TexlParser.ParseUserDefinitionScript(script, parserOptions, features); if (parserOptions.AllowAttributes) { - var userDefinitions = new UserDefinitions(script, parserOptions); + var userDefinitions = new UserDefinitions(script, parserOptions, features); parseResult = userDefinitions.ProcessPartialAttributes(parseResult); } diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/BuiltinFunctionsCore.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/BuiltinFunctionsCore.cs index 240fd0d809..9679ce1de0 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/BuiltinFunctionsCore.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/BuiltinFunctionsCore.cs @@ -40,7 +40,8 @@ internal class BuiltinFunctionsCore public static readonly TexlFunction And = _library.Add(new VariadicLogicalFunction(isAnd: true)); public static readonly TexlFunction Asin = _library.Add(new AsinFunction()); public static readonly TexlFunction AsinT = _library.Add(new AsinTableFunction()); - public static readonly TexlFunction AsType = _library.Add(new AsTypeFunction()); + public static readonly TexlFunction AsType = _library.Add(new AsTypeFunction()); + public static readonly TexlFunction AsType_UO = _library.Add(new AsTypeFunction_UO()); public static readonly TexlFunction Atan = _library.Add(new AtanFunction()); public static readonly TexlFunction Atan2 = _library.Add(new Atan2Function()); public static readonly TexlFunction AtanT = _library.Add(new AtanTableFunction()); @@ -132,7 +133,8 @@ internal class BuiltinFunctionsCore public static readonly TexlFunction IsError = _library.Add(new IsErrorFunction()); public static readonly TexlFunction IsNumeric = _library.Add(new IsNumericFunction()); public static readonly TexlFunction ISOWeekNum = _library.Add(new ISOWeekNumFunction()); - public static readonly TexlFunction IsToday = _library.Add(new IsTodayFunction()); + public static readonly TexlFunction IsToday = _library.Add(new IsTodayFunction()); + public static readonly TexlFunction IsType_UO = _library.Add(new IsTypeFunction_UO()); public static readonly TexlFunction Language = _library.Add(new LanguageFunction()); public static readonly TexlFunction Last = _library.Add(new FirstLastFunction(isFirst: false)); public static readonly TexlFunction Last_UO = _library.Add(new FirstLastFunction_UO(isFirst: false)); @@ -231,6 +233,7 @@ internal class BuiltinFunctionsCore public static readonly TexlFunction TrimT = _library.Add(new TrimTFunction()); public static readonly TexlFunction Trunc = _library.Add(new TruncFunction()); public static readonly TexlFunction TruncT = _library.Add(new TruncTableFunction()); + public static readonly TexlFunction TypedParseJSON = _library.Add(new TypedParseJSONFunction()); public static readonly TexlFunction UniChar = _library.Add(new UniCharFunction()); public static readonly TexlFunction UniCharT = _library.Add(new UniCharTFunction()); public static readonly TexlFunction Upper = _library.Add(new LowerUpperFunction(isLower: false)); @@ -260,10 +263,7 @@ internal class BuiltinFunctionsCore public static readonly TexlFunction UTCToday = _featureGateFunctions.Add(new UTCTodayFunction()); public static readonly TexlFunction BooleanL = _featureGateFunctions.Add(new BooleanLFunction()); public static readonly TexlFunction BooleanL_T = _featureGateFunctions.Add(new BooleanLFunction_T()); - public static readonly TexlFunction Summarize = _featureGateFunctions.Add(new SummarizeFunction()); - public static readonly TexlFunction AsType_UO = _featureGateFunctions.Add(new AsTypeFunction_UO()); - public static readonly TexlFunction IsType_UO = _featureGateFunctions.Add(new IsTypeFunction_UO()); - public static readonly TexlFunction TypedParseJSON = _featureGateFunctions.Add(new TypedParseJSONFunction()); + public static readonly TexlFunction Summarize = _featureGateFunctions.Add(new SummarizeFunction()); // Slow API, only use for backward compatibility #pragma warning disable CS0618 // Type or member is obsolete diff --git a/src/libraries/Microsoft.PowerFx.Core/Utils/LanguageConstants.cs b/src/libraries/Microsoft.PowerFx.Core/Utils/LanguageConstants.cs index cfeb1ce077..1e91f2feef 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Utils/LanguageConstants.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Utils/LanguageConstants.cs @@ -75,5 +75,10 @@ internal class LanguageConstants /// The string value representing the JSON format. /// internal const string JSONFormatEnumString = "JSONFormat"; + + /// + /// The string value representing the Type literal keyword. + /// + public const string TypeLiteralInvariantName = "Type"; } } diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs index c384cfe3d9..0c1f4d2df4 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs @@ -397,13 +397,12 @@ public void AddUserDefinitions(string script, CultureInfo parseCulture = null, A var options = new ParserOptions() { AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, Culture = parseCulture ?? CultureInfo.InvariantCulture }; var sb = new StringBuilder(); - var checkResult = new DefinitionsCheckResult() + var checkResult = new DefinitionsCheckResult(this.Config.Features) .SetText(script, options); var parseResult = checkResult.ApplyParse(); diff --git a/src/libraries/Microsoft.PowerFx.Repl/Modules/ModuleLoadContext.cs b/src/libraries/Microsoft.PowerFx.Repl/Modules/ModuleLoadContext.cs index d788cad5ac..7b522052d6 100644 --- a/src/libraries/Microsoft.PowerFx.Repl/Modules/ModuleLoadContext.cs +++ b/src/libraries/Microsoft.PowerFx.Repl/Modules/ModuleLoadContext.cs @@ -142,11 +142,10 @@ private bool ResolveBody(ModulePoco poco, SymbolTable moduleExports, ReadOnlySym bool allowSideEffects = true; var options = new ParserOptions { - AllowParseAsTypeLiteral = true, AllowsSideEffects = true }; - var parseResult = UserDefinitions.Parse(str, options); + var parseResult = UserDefinitions.Parse(str, options, Features.PowerFxV1); var fragmentLocation = poco.Formulas.Location; diff --git a/src/libraries/Microsoft.PowerFx.Repl/Repl.cs b/src/libraries/Microsoft.PowerFx.Repl/Repl.cs index ef4d41d9e7..1a04efc2ee 100644 --- a/src/libraries/Microsoft.PowerFx.Repl/Repl.cs +++ b/src/libraries/Microsoft.PowerFx.Repl/Repl.cs @@ -503,7 +503,7 @@ await this.Output.WriteLineAsync($"Error: Can't set '{name}' to a Void value.", var errors = check.ApplyErrors(); if (!check.IsSuccess) { - var definitionsCheckResult = new DefinitionsCheckResult(); + var definitionsCheckResult = new DefinitionsCheckResult(this.Engine.Config.Features); definitionsCheckResult.SetText(expression, this.ParserOptions) .ApplyParseErrors(); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt index b294c06ac7..94fc8e2599 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt @@ -1,5 +1,3 @@ -#SETUP: AllowTypeLiteral, TimeZoneInfo("Pacific Standard Time") - // Primitives >> AsType(ParseJSON("987654321"), Number) 987654321 @@ -25,27 +23,18 @@ true >> AsType(ParseJSON("""1984-01-01"""), Date) Date(1984,1,1) ->> AsType(ParseJSON("""1900-12-31T23:59:59.999Z"""), DateTime) -DateTime(1900,12,31,15,59,59,999) - ->> AsType(ParseJSON("""1900-12-31T23:59:59.999"""), DateTime) -DateTime(1900,12,31,23,59,59,999) +>> AsType(ParseJSON("""1900-12-31T23:59:59.999"""), Date) +Date(1900,12,31) ->> AsType(ParseJSON("""1900-12-31T23:59:59.999+00:00"""), DateTime) -DateTime(1900,12,31,15,59,59,999) +>> AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), Date) +Date(1900,12,31) ->> AsType(ParseJSON("""1900-12-31T23:59:59.999-08:00"""), DateTime) +>> AsType(ParseJSON("""1900-12-31T23:59:59.999"""), DateTime) DateTime(1900,12,31,23,59,59,999) >> AsType(ParseJSON("""1900-12-31"""), DateTime) DateTime(1900,12,31,0,0,0,0) ->> AsType(ParseJSON("""1900-12-31T23:59:59.999"""), Date) -Date(1900,12,31) - ->> AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), Date) -Date(1900,12,31) - >> AsType(ParseJSON("""11:59:59.999"""), Time) Time(11,59,59,999) @@ -64,12 +53,6 @@ DateTime(1900,12,31,0,0,0,0) >> AsType(ParseJSON("""1900-12-31T00:00:00.000-08:00"""), DateTimeTZInd) DateTime(1900,12,31,8,0,0,0) ->> DateTimeValue(AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), UntypedObject)) -DateTime(1900,12,30,16,0,0,0) - ->> DateValue(AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), UntypedObject)) -Date(1900,12,30) - >> Value(AsType(ParseJSON("42"), UntypedObject)) 42 @@ -111,9 +94,6 @@ Error({Kind:ErrorKind.InvalidArgument}) >> AsType(ParseJSON("""42"""), Number) Error({Kind:ErrorKind.InvalidArgument}) ->> AsType(ParseJSON("""1900-12-31T24:59:59.1002Z"""), DateTime) -Error({Kind:ErrorKind.InvalidArgument}) - >> AsType(ParseJSON("""24:59:59.12345678"""), Time) Error({Kind:ErrorKind.InvalidArgument}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO_TimeZone_Seattle.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO_TimeZone_Seattle.txt new file mode 100644 index 0000000000..8364af22b2 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO_TimeZone_Seattle.txt @@ -0,0 +1,19 @@ +#SETUP: TimeZoneInfo("Pacific Standard Time") + +>> AsType(ParseJSON("""1900-12-31T23:59:59.999Z"""), DateTime) +DateTime(1900,12,31,15,59,59,999) + +>> AsType(ParseJSON("""1900-12-31T23:59:59.999+00:00"""), DateTime) +DateTime(1900,12,31,15,59,59,999) + +>> AsType(ParseJSON("""1900-12-31T23:59:59.999-08:00"""), DateTime) +DateTime(1900,12,31,23,59,59,999) + +>> DateTimeValue(AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), UntypedObject)) +DateTime(1900,12,30,16,0,0,0) + +>> DateValue(AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), UntypedObject)) +Date(1900,12,30) + +>> AsType(ParseJSON("""1900-12-31T24:59:59.1002Z"""), DateTime) +Error({Kind:ErrorKind.InvalidArgument}) \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt index f50e69da5d..3a576c1808 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt @@ -1,5 +1,3 @@ -#SETUP: AllowTypeLiteral, TimeZoneInfo("Pacific Standard Time") - // Primitives >> IsType(ParseJSON("987654321"), Number) true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt index abca5ad9ce..70193ae8cb 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt @@ -1,5 +1,3 @@ -#SETUP: AllowTypeLiteral, TimeZoneInfo("Pacific Standard Time") - // Primitives >> ParseJSON("5", Number) 5 @@ -28,21 +26,15 @@ >> ParseJSON("""1984-01-01""", Date) Date(1984,1,1) ->> ParseJSON("""2008-01-01T12:12:12.100Z""", DateTime) -DateTime(2008,1,1,4,12,12,100) +>> ParseJSON("""1900-12-31T23:59:59.999""", Date) +Date(1900,12,31) >> ParseJSON("""2008-01-01T12:12:12.100""", DateTime) DateTime(2008,1,1,12,12,12,100) ->> ParseJSON("""2008-01-01T12:12:12.100-08:00""", DateTime) -DateTime(2008,1,1,12,12,12,100) - >> ParseJSON("""1900-12-31""", DateTime) DateTime(1900,12,31,0,0,0,0) ->> ParseJSON("""1900-12-31T23:59:59.999""", Date) -Date(1900,12,31) - >> ParseJSON("""11:59:59.999""", Time) Time(11,59,59,999) @@ -61,12 +53,6 @@ DateTime(1900,12,31,0,0,0,0) >> ParseJSON("""1900-12-31T00:00:00.000-08:00""", DateTimeTZInd) DateTime(1900,12,31,8,0,0,0) ->> DateTimeValue(ParseJSON("""1900-12-31T00:00:00.000Z""", UntypedObject)) -DateTime(1900,12,30,16,0,0,0) - ->> DateValue(ParseJSON("""1900-12-31T00:00:00.000Z""", UntypedObject)) -Date(1900,12,30) - >> Value(ParseJSON("42", UntypedObject)) 42 diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON_TimeZone_Seattle.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON_TimeZone_Seattle.txt new file mode 100644 index 0000000000..e38c134bf3 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON_TimeZone_Seattle.txt @@ -0,0 +1,13 @@ +#SETUP: TimeZoneInfo("Pacific Standard Time") + +>> ParseJSON("""2008-01-01T12:12:12.100Z""", DateTime) +DateTime(2008,1,1,4,12,12,100) + +>> ParseJSON("""2008-01-01T12:12:12.100-08:00""", DateTime) +DateTime(2008,1,1,12,12,12,100) + +>> DateTimeValue(ParseJSON("""1900-12-31T00:00:00.000Z""", UntypedObject)) +DateTime(1900,12,30,16,0,0,0) + +>> DateValue(ParseJSON("""1900-12-31T00:00:00.000Z""", UntypedObject)) +Date(1900,12,30) \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/NamedFormulasTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/NamedFormulasTests.cs index 400377e58d..39aeb9343d 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/NamedFormulasTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/NamedFormulasTests.cs @@ -23,10 +23,9 @@ public void DefSimpleTypeTest(string script) var parserOptions = new ParserOptions() { AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, }; - var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions); + var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions, Features.PowerFxV1); Assert.False(parsedNamedFormulasAndUDFs.HasErrors); Assert.Equal("Number", parsedNamedFormulasAndUDFs.DefinedTypes.First().Type.TypeRoot.AsFirstName().Ident.Name.ToString()); Assert.Equal("Foo", parsedNamedFormulasAndUDFs.DefinedTypes.First().Ident.Name.ToString()); @@ -39,10 +38,9 @@ public void DefRecordTypeTest(string script) var parserOptions = new ParserOptions() { AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, }; - var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions); + var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions, Features.PowerFxV1); Assert.False(parsedNamedFormulasAndUDFs.HasErrors); var record = parsedNamedFormulasAndUDFs.DefinedTypes.First().Type.TypeRoot.AsRecord(); Assert.Equal("Age", record.Ids.First().Name.ToString()); @@ -56,9 +54,8 @@ public void AsTypeTest(string script) var parserOptions = new ParserOptions() { AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, }; - var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions); + var parsedNamedFormulasAndUDFs = UserDefinitions.Parse(script, parserOptions, Features.PowerFxV1); Assert.False(parsedNamedFormulasAndUDFs.HasErrors); } @@ -69,9 +66,8 @@ public void FailParsingTest(string script) var parserOptions = new ParserOptions() { AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, }; - var result = UserDefinitions.Parse(script, parserOptions); + var result = UserDefinitions.Parse(script, parserOptions, Features.PowerFxV1); Assert.True(result.HasErrors); var udf = result.UDFs.First(); Assert.Equal("Bar", udf.Ident.ToString()); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedTypeTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedTypeTests.cs index 163e732dc1..769c40e6a9 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedTypeTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedTypeTests.cs @@ -42,13 +42,8 @@ public class UserDefinedTypeTests : PowerFxTest [InlineData("A := Type({})", "", false)] public void TestUserDefinedType(string typeDefinition, string expectedDefinedTypeString, bool isValid) { - var parseOptions = new ParserOptions - { - AllowParseAsTypeLiteral = true - }; - var checkResult = new DefinitionsCheckResult() - .SetText(typeDefinition, parseOptions) + .SetText(typeDefinition) .SetBindingInfo(_primitiveTypes); checkResult.ApplyResolveTypes(); @@ -100,13 +95,8 @@ public void TestUserDefinedType(string typeDefinition, string expectedDefinedTyp [InlineData("NAlias := Type(Number);X := 5; ADDX(n:Number): Number = n + X; SomeType := Type(UntypedObject)", 2)] public void TestValidUDTCounts(string typeDefinition, int expectedDefinedTypesCount) { - var parseOptions = new ParserOptions - { - AllowParseAsTypeLiteral = true - }; - var checkResult = new DefinitionsCheckResult() - .SetText(typeDefinition, parseOptions) + .SetText(typeDefinition) .SetBindingInfo(_primitiveTypes); checkResult.ApplyResolveTypes(); @@ -127,13 +117,8 @@ public void TestValidUDTCounts(string typeDefinition, int expectedDefinedTypesCo [InlineData("C := 5; D := [1,2,3];", 2, "ErrNamedType_MissingTypeLiteral")] public void TestUDTErrors(string typeDefinition, int expectedErrorCount, string expectedMessageKey) { - var parseOptions = new ParserOptions - { - AllowParseAsTypeLiteral = true - }; - var checkResult = new DefinitionsCheckResult() - .SetText(typeDefinition, parseOptions) + .SetText(typeDefinition) .SetBindingInfo(_primitiveTypes); var errors = checkResult.ApplyErrors(); @@ -159,13 +144,8 @@ public void TestUDTErrors(string typeDefinition, int expectedErrorCount, string [InlineData("T := Type([{a: {b: {c: [{d: 10e+4}]}}}]);", 1)] public void TestUDTParseErrors(string typeDefinition, int expectedErrorCount) { - var parseOptions = new ParserOptions - { - AllowParseAsTypeLiteral = true - }; - var checkResult = new DefinitionsCheckResult() - .SetText(typeDefinition, parseOptions); + .SetText(typeDefinition); var parseResult = checkResult.ApplyParse(); Assert.True(parseResult.HasErrors); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/ParserOptionsExtensions.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/ParserOptionsExtensions.cs index a0375586d4..316a654f77 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/ParserOptionsExtensions.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/ParserOptionsExtensions.cs @@ -32,11 +32,6 @@ internal static ParserOptions ToParserOptions(this TexlParser.Flags flags, Cultu parserOptions.TextFirst = true; } - if (flags.HasFlag(TexlParser.Flags.AllowTypeLiteral)) - { - parserOptions.AllowParseAsTypeLiteral = true; - } - return parserOptions; } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs index 9f9a3b16b5..b71764da47 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs @@ -1877,8 +1877,7 @@ public void UserDefinedTypeTest(string userDefinitions, string evalExpression, b var recalcEngine = new RecalcEngine(config); var parserOptions = new ParserOptions() { - AllowsSideEffects = false, - AllowParseAsTypeLiteral = true, + AllowsSideEffects = false, }; if (isValid) @@ -1923,7 +1922,6 @@ public void UDFImperativeVsRecordAmbiguityTest(string udf, string evalExpression var parserOptions = new ParserOptions() { AllowsSideEffects = true, - AllowParseAsTypeLiteral = true }; var extraSymbols = new SymbolTable(); diff --git a/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs b/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs index 57a56ccdd0..21d84ba836 100644 --- a/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs +++ b/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs @@ -21,11 +21,6 @@ namespace Microsoft.PowerFx.Json.Tests { public class AsTypeIsTypeParseJSONTests { - private static readonly ParserOptions ParseType = new ParserOptions - { - AllowParseAsTypeLiteral = true, - }; - private RecalcEngine SetupEngine(bool udtFeaturedEnabled = true) { var config = new PowerFxConfig(); @@ -52,7 +47,7 @@ public void PrimitivesTest() CheckIsTypeAsTypeParseJSON(engine, "\"false\"", "Boolean", false); CheckIsTypeAsTypeParseJSON(engine, "\"1234.56789\"", "Decimal", 1234.56789m); CheckIsTypeAsTypeParseJSON(engine, "\"42\"", "T", 42D); - CheckIsTypeAsTypeParseJSON(engine, "\"\"\"Power Fx\"\"\"", "Type(Text)", "Power Fx", options: ParseType); + CheckIsTypeAsTypeParseJSON(engine, "\"\"\"Power Fx\"\"\"", "Type(Text)", "Power Fx"); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"2000-01-01T00:00:01.100Z\"\"\"", "DateTimeTZInd", new DateTime(2000, 1, 1, 0, 0, 1, 100)); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"11:59:59\"\"\"", "Time", new TimeSpan(11, 59, 59)); @@ -89,14 +84,14 @@ public void RecordsTest() obj3.a = new object[] { 1m, 2m, 3m, 4m }; CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5}\"", "T", obj1); - CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5}\"", "Type({a: Number})", obj1, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": { \"\"b\"\": {\"\"c\"\": false}}}\"", "Type({a: {b: {c: Boolean }}})", obj2, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": [1, 2, 3, 4]}\"", "Type({a: [Decimal]})", obj3, options: ParseType); + CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5}\"", "Type({a: Number})", obj1); + CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": { \"\"b\"\": {\"\"c\"\": false}}}\"", "Type({a: {b: {c: Boolean }}})", obj2); + CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": [1, 2, 3, 4]}\"", "Type({a: [Decimal]})", obj3); // Negative Tests - CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5}\"", "Type({a: Text})", obj1, isValid: false, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5, \"\"b\"\": 6}\"", "Type({a: Number})", obj1, false, options: ParseType); - CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"{\"\"a\"\": \"\"foo/bar/uri\"\"}\"", "Type({a: Void})", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key, options: ParseType); + CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5}\"", "Type({a: Text})", obj1, isValid: false); + CheckIsTypeAsTypeParseJSON(engine, "\"{\"\"a\"\": 5, \"\"b\"\": 6}\"", "Type({a: Number})", obj1, false); + CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"{\"\"a\"\": \"\"foo/bar/uri\"\"}\"", "Type({a: Void})", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key); } [Fact] @@ -112,14 +107,14 @@ public void TablesTest() var t3 = new object[] { t3a }; CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": 5}]\"", "T", t1); - CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": 5}]\"", "Type([{a: Number}])", t1, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": [true, true, false, true]}]\"", "Type([{a: [Boolean]}])", t3, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"[1, 2, 3, 4]\"", "Type([Decimal])", t2, options: ParseType); + CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": 5}]\"", "Type([{a: Number}])", t1); + CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": [true, true, false, true]}]\"", "Type([{a: [Boolean]}])", t3); + CheckIsTypeAsTypeParseJSON(engine, "\"[1, 2, 3, 4]\"", "Type([Decimal])", t2); // Negative tests - CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": 5, \"\"b\"\": 6}]\"", "Type([{a: Number}])", t1, false, options: ParseType); - CheckIsTypeAsTypeParseJSON(engine, "\"[1, 2, 3, 4]\"", "Type([Text])", t2, false, options: ParseType); - CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"[\"\"foo/bar/uri\"\"]\"", "Type([Color])", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key, options: ParseType); + CheckIsTypeAsTypeParseJSON(engine, "\"[{\"\"a\"\": 5, \"\"b\"\": 6}]\"", "Type([{a: Number}])", t1, false); + CheckIsTypeAsTypeParseJSON(engine, "\"[1, 2, 3, 4]\"", "Type([Text])", t2, false); + CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"[\"\"foo/bar/uri\"\"]\"", "Type([Color])", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key); } [Theory] @@ -139,11 +134,11 @@ public void TestCompileErrors(string expression, string type, bool testAllFuncti if (testAllFunctions) { - CheckIsTypeAsTypeParseJSONCompileErrors(engine, expression, type, expectedError, ParseType); + CheckIsTypeAsTypeParseJSONCompileErrors(engine, expression, type, expectedError); } else { - var result = engine.Check(expression, options: ParseType); + var result = engine.Check(expression); Assert.False(result.IsSuccess); Assert.Contains(result.Errors, e => e.MessageKey == expectedError); }