Anderson Silva 2024-07-15 23:07:30 -05:00 коммит произвёл GitHub
Родитель 07a17a998f
Коммит d193162359
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
13 изменённых файлов: 482 добавлений и 180 удалений

Просмотреть файл

@ -122,6 +122,13 @@ namespace Microsoft.PowerFx.Types
public static ErrorValue NewError(IEnumerable<ExpressionError> error, FormulaType type)
{
return new ErrorValue(IRContext.NotInSource(type), error.ToList());
}
public static UntypedObjectValue New(UntypedObjectBase untypedObject)
{
return new UntypedObjectValue(
IRContext.NotInSource(new UntypedObjectType()),
untypedObject);
}
public static UntypedObjectValue New(IUntypedObject untypedObject)

Просмотреть файл

@ -79,5 +79,39 @@ namespace Microsoft.PowerFx.Types
// Not supported for the time being.
throw new NotImplementedException("UntypedObjectValue cannot be serialized.");
}
}
}
public abstract class UntypedObjectBase : IUntypedObject
{
public abstract IUntypedObject this[int index] { get; }
public abstract FormulaType Type { get; }
public abstract int GetArrayLength();
public abstract bool GetBoolean();
public abstract decimal GetDecimal();
public abstract double GetDouble();
public abstract string GetString();
public abstract string GetUntypedNumber();
public abstract bool TryGetProperty(string value, out IUntypedObject result);
public abstract bool TryGetPropertyNames(out IEnumerable<string> propertyNames);
/// <summary>
/// Set a property on the object.
/// </summary>
/// <param name="propertyName">Property name.</param>
/// <param name="value">FormulaValue to be set.</param>
public virtual void SetProperty(string propertyName, FormulaValue value)
{
// In case of unwanted behavior, throw an CustomFunctionErrorException exception.
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -1,9 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.Localization;
using Microsoft.PowerFx.Core.Types;
@ -35,6 +33,8 @@ namespace Microsoft.PowerFx.Core.Texl.Builtins
public override bool IsSelfContained => true;
public override bool PropagatesMutability => true;
public IndexFunction_UO()
: base(IndexInvariantFunctionName, TexlStrings.AboutIndex, FunctionCategories.Table, DType.UntypedObject, 0, 2, 2, DType.UntypedObject, DType.Number)
{

Просмотреть файл

@ -19,6 +19,7 @@ using Microsoft.PowerFx.Interpreter;
using Microsoft.PowerFx.Interpreter.Exceptions;
using Microsoft.PowerFx.Types;
using static Microsoft.PowerFx.Functions.Library;
using static Microsoft.PowerFx.Syntax.PrettyPrintVisitor;
namespace Microsoft.PowerFx
{
@ -154,28 +155,58 @@ namespace Microsoft.PowerFx
// Set is unique because it has an l-value for the first arg.
// Async params can't have out-params.
// Return null if not handled. Else non-null if handled.
private async Task<FormulaValue> TryHandleSet(CallNode node, EvalVisitorContext context)
{
// Special case Set() calls because they take an LValue.
if (node.Function.GetType() != typeof(RecalcEngineSetFunction))
{
return null;
}
var arg0 = node.Args[0];
var arg1 = node.Args[1];
private async Task<FormulaValue> TryHandleSet(CallNode node, EvalVisitorContext context)
{
// Special case Set() calls because they take an LValue.
if (node.Function.GetType() != typeof(RecalcEngineSetFunction))
{
return null;
}
var arg0 = node.Args[0];
var arg1 = node.Args[1];
var newValue = await arg1.Accept(this, context).ConfigureAwait(false);
if (arg0.IRContext.IsMutation && arg0 is RecordFieldAccessNode rfan)
if (arg0.IRContext.IsMutation)
{
var arg0value = await rfan.From.Accept(this, context).ConfigureAwait(false);
if (arg0value is RecordValue rv)
if (arg0 is RecordFieldAccessNode rfan)
{
rv.ShallowCopyFieldInPlace(rfan.Field);
rv.UpdateField(rfan.Field, newValue);
return node.IRContext.ResultType._type.Kind == DKind.Boolean ? FormulaValue.New(true) : FormulaValue.NewVoid();
var arg0value = await rfan.From.Accept(this, context).ConfigureAwait(false);
if (arg0value is RecordValue rv)
{
rv.ShallowCopyFieldInPlace(rfan.Field);
rv.UpdateField(rfan.Field, newValue);
return node.IRContext.ResultType._type.Kind == DKind.Boolean ? FormulaValue.New(true) : FormulaValue.NewVoid();
}
else
{
return CommonErrors.UnreachableCodeError(node.IRContext);
}
}
else if (arg0 is BinaryOpNode bon && bon.Op == BinaryOpKind.DynamicGetField)
{
var arg0value = await bon.Left.Accept(this, context).ConfigureAwait(false);
if (arg0value is UntypedObjectValue uov && uov.Impl is UntypedObjectBase impl)
{
TextLiteralNode textLiteralNode = (TextLiteralNode)bon.Right;
try
{
impl.SetProperty(textLiteralNode.LiteralValue, newValue);
return node.IRContext.ResultType._type.Kind == DKind.Boolean ? FormulaValue.New(true) : FormulaValue.NewVoid();
}
catch (CustomFunctionErrorException ex)
{
return new ErrorValue(node.IRContext, new ExpressionError() { Message = ex.Message, Span = node.IRContext.SourceContext, Kind = ex.ErrorKind });
}
catch (NotImplementedException)
{
return CommonErrors.NotYetImplementedError(node.IRContext, $"Class {impl.GetType()} does not implement 'SetProperty'.");
}
}
}
else
{
@ -184,9 +215,9 @@ namespace Microsoft.PowerFx
}
// Binder has already ensured this is a first name node as well as mutable symbol.
if (arg0 is ResolvedObjectNode obj)
{
if (obj.Value is ISymbolSlot sym)
if (arg0 is ResolvedObjectNode obj)
{
if (obj.Value is ISymbolSlot sym)
{
if (_symbolValues != null)
{
@ -197,9 +228,9 @@ namespace Microsoft.PowerFx
// This may happen if the runtime symbols are missing a value and we failed to update.
}
}
// Fail?
return CommonErrors.UnreachableCodeError(node.IRContext);
// Fail?
return CommonErrors.UnreachableCodeError(node.IRContext);
}
// Handle invoke SetProperty(source.Prop, newValue)

Просмотреть файл

@ -55,6 +55,12 @@ namespace Microsoft.PowerFx.Interpreter
nodeToCoercedTypeMap = null;
returnType = context.Features.PowerFxV1CompatibilityRules ? DType.Void : DType.Boolean;
if (argTypes[0].IsUntypedObject)
{
// if arg0 is untyped object, the host implementation will handle arg1.
return true;
}
var isValid = CheckType(context, args[1], argTypes[1], argTypes[0], errors, ref nodeToCoercedTypeMap);
return isValid;
@ -64,43 +70,63 @@ namespace Microsoft.PowerFx.Interpreter
public override void CheckSemantics(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors)
{
base.CheckSemantics(binding, args, argTypes, errors);
Contracts.AssertValue(args);
Contracts.AssertAllValues(args);
Contracts.AssertValue(argTypes);
Contracts.AssertAllValid(argTypes);
Contracts.Assert(args.Length == argTypes.Length);
Contracts.AssertValue(errors);
Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);
Contracts.AssertValue(args);
Contracts.AssertAllValues(args);
Contracts.AssertValue(argTypes);
Contracts.AssertAllValid(argTypes);
Contracts.Assert(args.Length == argTypes.Length);
Contracts.AssertValue(errors);
Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);
var arg0 = argTypes[0];
var arg1 = argTypes[1];
// Type check
if (!(arg0.Accepts(arg1, exact: true, useLegacyDateTimeAccepts: false, usePowerFxV1CompatibilityRules: binding.Features.PowerFxV1CompatibilityRules) ||
(arg0.IsNumeric && arg1.IsNumeric)))
if (arg0.IsUntypedObject)
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrBadType_ExpectedType_ProvidedType, arg0.GetKindString(), arg1.GetKindString());
return;
if (CheckMutability(binding, args, argTypes, errors))
{
return;
}
}
else
{
if (!(arg0.Accepts(arg1, exact: true, useLegacyDateTimeAccepts: false, usePowerFxV1CompatibilityRules: binding.Features.PowerFxV1CompatibilityRules) ||
(arg0.IsNumeric && arg1.IsNumeric)))
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrBadType_ExpectedType_ProvidedType, arg0.GetKindString(), arg1.GetKindString());
return;
}
if (arg1.AggregateHasExpandedType())
{
if (arg1.IsTable)
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrSetVariableWithRelationshipNotAllowTable);
return;
}
if (arg1.IsRecord)
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrSetVariableWithRelationshipNotAllowRecord);
return;
}
}
if (CheckMutability(binding, args, argTypes, errors))
{
return;
}
}
if (arg1.AggregateHasExpandedType())
{
if (arg1.IsTable)
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrSetVariableWithRelationshipNotAllowTable);
return;
}
if (arg1.IsRecord)
{
errors.EnsureError(DocumentErrorSeverity.Critical, args[1], ErrSetVariableWithRelationshipNotAllowRecord);
return;
}
}
var firstName = args[0].AsFirstName();
errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedValidVariableName_Arg, Name, args[0]);
return;
}
private bool CheckMutability(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors)
{
var firstName = args[0].AsFirstName();
if (firstName != null)
{
// Variable reference assignment, for example Set( x, 3 )
@ -108,18 +134,17 @@ namespace Microsoft.PowerFx.Interpreter
if (info.Data is NameSymbol nameSymbol && nameSymbol.Props.CanSet)
{
// We have a variable, success
return;
return true;
}
}
else if (binding.Features.PowerFxV1CompatibilityRules)
{
// Deep mutation, for example Set( x.a, 4 )
base.ValidateArgumentIsSetMutable(binding, args[0], errors);
return;
return true;
}
errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedValidVariableName_Arg, Name, args[0]);
return;
return false;
}
}
}

Просмотреть файл

@ -9,27 +9,27 @@ using Microsoft.PowerFx.Types;
namespace Microsoft.PowerFx.Functions
{
internal class JsonUntypedObject : IUntypedObject
{
internal readonly JsonElement _element;
public JsonUntypedObject(JsonElement element)
{
_element = element;
}
public FormulaType Type
{
get
{
switch (_element.ValueKind)
{
case JsonValueKind.Object:
return ExternalType.ObjectType;
case JsonValueKind.Array:
return ExternalType.ArrayType;
case JsonValueKind.String:
return FormulaType.String;
internal class JsonUntypedObject : UntypedObjectBase
{
internal readonly JsonElement _element;
public JsonUntypedObject(JsonElement element)
{
_element = element;
}
public override FormulaType Type
{
get
{
switch (_element.ValueKind)
{
case JsonValueKind.Object:
return ExternalType.ObjectType;
case JsonValueKind.Array:
return ExternalType.ArrayType;
case JsonValueKind.String:
return FormulaType.String;
case JsonValueKind.Number:
// Do not be tempted to use FormulaType.Number here. JSON numbers can be interpreted as either
// a float or a decimal and connectors take advantage of this to interop with decimals in databases.
@ -41,45 +41,45 @@ namespace Microsoft.PowerFx.Functions
// number types of various capacities and complements, fixed or floating, binary or decimal.That can make
// interchange between different programming languages difficult. JSON instead offers only the representation of
// numbers that humans use: a sequence of digits. All programming languages know how to make sense of digit
// sequences even if they disagree on internal representations. That is enough to allow interchange
// sequences even if they disagree on internal representations. That is enough to allow interchange
return ExternalType.UntypedNumber;
case JsonValueKind.True:
case JsonValueKind.False:
return FormulaType.Boolean;
}
return FormulaType.Blank;
}
}
public IUntypedObject this[int index] => new JsonUntypedObject(_element[index]);
public int GetArrayLength()
{
return _element.GetArrayLength();
}
public double GetDouble()
{
return _element.GetDouble();
}
public string GetString()
{
return _element.GetString();
}
public bool GetBoolean()
{
return _element.GetBoolean();
case JsonValueKind.True:
case JsonValueKind.False:
return FormulaType.Boolean;
}
return FormulaType.Blank;
}
}
public decimal GetDecimal()
public override IUntypedObject this[int index] => new JsonUntypedObject(_element[index]);
public override int GetArrayLength()
{
return _element.GetArrayLength();
}
public override double GetDouble()
{
return _element.GetDouble();
}
public override string GetString()
{
return _element.GetString();
}
public override bool GetBoolean()
{
return _element.GetBoolean();
}
public override decimal GetDecimal()
{
return _element.GetDecimal();
}
public string GetUntypedNumber()
public override string GetUntypedNumber()
{
if (Type == ExternalType.UntypedNumber)
{
@ -89,25 +89,25 @@ namespace Microsoft.PowerFx.Functions
{
throw new FormatException();
}
}
public bool TryGetProperty(string value, out IUntypedObject result)
{
var res = _element.TryGetProperty(value, out var je);
result = new JsonUntypedObject(je);
return res;
}
public bool TryGetPropertyNames(out IEnumerable<string> result)
public override bool TryGetProperty(string value, out IUntypedObject result)
{
var res = _element.TryGetProperty(value, out var je);
result = new JsonUntypedObject(je);
return res;
}
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
if (_element.ValueKind != JsonValueKind.Object)
{
result = null;
return false;
}
result = _element.EnumerateObject().Select(x => x.Name);
return true;
}
}
}
}

Просмотреть файл

@ -141,6 +141,7 @@ namespace Microsoft.PowerFx.Core.Tests
"Microsoft.PowerFx.Types.IDelegatableTableValue",
"Microsoft.PowerFx.Types.ITypeVisitor",
"Microsoft.PowerFx.Types.IUntypedObject",
"Microsoft.PowerFx.Types.UntypedObjectBase",
"Microsoft.PowerFx.Types.IValueVisitor",
"Microsoft.PowerFx.Types.NamedFormulaType",
"Microsoft.PowerFx.Types.NamedValue",

Просмотреть файл

@ -294,7 +294,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
}
}
private class SimpleObject : IUntypedObject
private class SimpleObject : UntypedObjectBase
{
private readonly FormulaValue _value;
@ -303,46 +303,46 @@ namespace Microsoft.PowerFx.Interpreter.Tests
_value = value;
}
public IUntypedObject this[int index] => throw new NotImplementedException();
public override IUntypedObject this[int index] => throw new NotImplementedException();
public FormulaType Type => _value.Type;
public override FormulaType Type => _value.Type;
public int GetArrayLength()
public override int GetArrayLength()
{
throw new NotImplementedException();
}
public bool GetBoolean()
public override bool GetBoolean()
{
return ((BooleanValue)_value).Value;
}
public double GetDouble()
public override double GetDouble()
{
return ((NumberValue)_value).Value;
}
public decimal GetDecimal()
public override decimal GetDecimal()
{
return ((DecimalValue)_value).Value;
}
public string GetUntypedNumber()
public override string GetUntypedNumber()
{
return ((StringValue)_value).Value;
}
public string GetString()
public override string GetString()
{
return ((StringValue)_value).Value;
}
public bool TryGetProperty(string value, out IUntypedObject result)
public override bool TryGetProperty(string value, out IUntypedObject result)
{
throw new NotImplementedException();
}
public bool TryGetPropertyNames(out IEnumerable<string> result)
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
result = null;
return false;

Просмотреть файл

@ -339,4 +339,8 @@ Errors: Error 45-52: The value passed to the 'Set' function cannot be changed.
>> rwt1_copy3
{Field1:3,Field2:{Field2_1:321,Field2_2:"2_2",Field2_4:Table({Field1:1,Field2:"earth",Field3:DateTime(2022,1,1,0,0,0,0),Field4:true})}}
// Untyped object
>> IsError(Set(ParseJSON("{""x"":5}").x, 99))
Errors: Error 34-36: The value passed to the 'Set' function cannot be changed.

Просмотреть файл

@ -45,9 +45,59 @@ namespace Microsoft.PowerFx.Interpreter.Tests
Assert.Equal(FormulaType.UntypedObject, fv3.Type);
Assert.True(fv3 is BlankValue);
}
[Fact]
public void PadUntypedObjectMutationTest()
{
DataTable dt = new DataTable("someTable");
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Column1", typeof(string));
dt.Columns.Add("Column2", typeof(string));
dt.Rows.Add(1, "data1", "data2");
dt.Rows.Add(2, "data3", "data4");
PadUntypedObject uo = new PadUntypedObject(dt);
PadUntypedObject uoCell = new PadUntypedObject(99);
NotImplementedUntypedObject notImplementedUO = new NotImplementedUntypedObject(dt);
UntypedObjectValue uov = new UntypedObjectValue(IRContext.NotInSource(FormulaType.UntypedObject), uo);
UntypedObjectValue uovCell = new UntypedObjectValue(IRContext.NotInSource(FormulaType.UntypedObject), uoCell);
UntypedObjectValue notImplementedValue = new UntypedObjectValue(IRContext.NotInSource(FormulaType.UntypedObject), notImplementedUO);
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
RecalcEngine engine = new RecalcEngine(config);
engine.Config.SymbolTable.EnableMutationFunctions();
engine.UpdateVariable("padTable", uov, new SymbolProperties() { CanMutate = true, CanSetMutate = true });
engine.UpdateVariable("notImplementedUO", notImplementedValue, new SymbolProperties() { CanMutate = true, CanSetMutate = true });
engine.UpdateVariable("padCell", uovCell);
// Setting an untyped object (padCell).
DecimalValue result = (DecimalValue)engine.Eval(@"Set(Index(padTable, 1).Id, padCell);Index(padTable, 1).Id+1", options: new ParserOptions() { AllowsSideEffects = true });
Assert.Equal(100m, result.ToObject());
// Setting a strongly typed object (99).
result = (DecimalValue)engine.Eval(@"Set(Index(padTable, 1).Id, 99);Index(padTable, 1).Id+1", options: new ParserOptions() { AllowsSideEffects = true });
Assert.Equal(100m, result.ToObject());
// Property does not exist.
ErrorValue errorValue = (ErrorValue)engine.Eval(@"Set(Index(padTable, 1).DoesNotExist, 99)", options: new ParserOptions() { AllowsSideEffects = true });
Assert.IsType<ErrorValue>(errorValue);
Assert.Equal(ErrorKind.InvalidArgument, errorValue.Errors.First().Kind);
// Type not supported.
errorValue = (ErrorValue)engine.Eval(@"Set(Index(padTable, 1).Column2, GUID())", options: new ParserOptions() { AllowsSideEffects = true });
Assert.IsType<ErrorValue>(errorValue);
Assert.Equal(ErrorKind.InvalidArgument, errorValue.Errors.First().Kind);
// 'SetProperty' not implemented.
errorValue = (ErrorValue)engine.Eval(@"Set(Index(notImplementedUO, 1).Id, 1)", options: new ParserOptions() { AllowsSideEffects = true });
Assert.IsType<ErrorValue>(errorValue);
Assert.Equal(ErrorKind.NotSupported, errorValue.Errors.First().Kind);
}
}
public class PadUntypedObject : IUntypedObject
public class PadUntypedObject : UntypedObjectBase
{
public DataTable DataTable;
public DataRow DataRow;
@ -74,8 +124,6 @@ namespace Microsoft.PowerFx.Interpreter.Tests
Cell = cell;
}
public IUntypedObject this[int index] => Index(index);
private IUntypedObject Index(int index)
{
return (DataTable != null)
@ -85,7 +133,9 @@ namespace Microsoft.PowerFx.Interpreter.Tests
: throw new NotImplementedException();
}
public FormulaType Type => GetFormulaType();
public override FormulaType Type => GetFormulaType();
public override IUntypedObject this[int index] => Index(index);
private FormulaType GetFormulaType()
{
@ -102,7 +152,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
: ExternalType.ArrayAndObject;
}
public int GetArrayLength()
public override int GetArrayLength()
{
return (DataTable != null)
? DataTable.Rows.Count
@ -111,12 +161,12 @@ namespace Microsoft.PowerFx.Interpreter.Tests
: throw new NotImplementedException();
}
public bool GetBoolean()
public override bool GetBoolean()
{
throw new NotImplementedException();
}
public double GetDouble()
public override double GetDouble()
{
return Cell switch
{
@ -127,12 +177,12 @@ namespace Microsoft.PowerFx.Interpreter.Tests
};
}
public decimal GetDecimal()
public override decimal GetDecimal()
{
throw new NotImplementedException();
}
public string GetUntypedNumber()
public override string GetUntypedNumber()
{
throw new NotImplementedException();
}
@ -142,12 +192,12 @@ namespace Microsoft.PowerFx.Interpreter.Tests
throw new NotImplementedException();
}
public string GetString()
public override string GetString()
{
return Cell.ToString();
}
public bool TryGetProperty(string propertyName, out IUntypedObject result)
public override bool TryGetProperty(string propertyName, out IUntypedObject result)
{
if (DataTable != null)
{
@ -165,7 +215,154 @@ namespace Microsoft.PowerFx.Interpreter.Tests
return true;
}
public bool TryGetPropertyNames(out IEnumerable<string> result)
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
result = null;
return false;
}
public override void SetProperty(string propertyName, FormulaValue value)
{
if (DataTable != null)
{
throw new NotImplementedException();
}
if (!DataRow.Table.Columns.Contains(propertyName))
{
value = default;
throw new CustomFunctionErrorException($"Property '{propertyName}' does not exist.", ErrorKind.InvalidArgument);
}
if (value is DecimalValue dv)
{
DataRow[propertyName] = dv.Value;
}
else if (value is GuidValue)
{
throw new CustomFunctionErrorException($"Type '{value.Type.ToString()}' is not supported.", ErrorKind.InvalidArgument);
}
else if (value is UntypedObjectValue uov)
{
if (DataRow[propertyName].GetType() == typeof(string))
{
DataRow[propertyName] = uov.Impl.GetString();
}
else if (DataRow[propertyName].GetType() == typeof(int))
{
DataRow[propertyName] = uov.Impl.GetDouble();
}
else if (DataRow[propertyName].GetType() == typeof(bool))
{
DataRow[propertyName] = uov.Impl.GetBoolean();
}
else if (DataRow[propertyName].GetType() == typeof(decimal))
{
DataRow[propertyName] = uov.Impl.GetDecimal();
}
else
{
throw new CustomFunctionErrorException($"Type '{DataRow[propertyName].GetType()}' is not supported.", ErrorKind.InvalidArgument);
}
}
}
}
public class NotImplementedUntypedObject : UntypedObjectBase
{
public DataTable DataTable;
public DataRow DataRow;
public object Cell;
public NotImplementedUntypedObject(DataTable dt)
{
DataTable = dt;
DataRow = null;
Cell = null;
}
public NotImplementedUntypedObject(DataRow dr)
{
DataTable = null;
DataRow = dr;
Cell = null;
}
public NotImplementedUntypedObject(object cell)
{
DataTable = null;
DataRow = null;
Cell = cell;
}
private IUntypedObject Index(int index)
{
return new NotImplementedUntypedObject(DataTable.Rows[index]);
}
public override FormulaType Type => GetFormulaType();
public override IUntypedObject this[int index] => Index(index);
private FormulaType GetFormulaType()
{
return ExternalType.ArrayAndObject;
}
public override int GetArrayLength()
{
return 1;
}
public override bool GetBoolean()
{
throw new NotImplementedException();
}
public override double GetDouble()
{
throw new NotImplementedException();
}
public override decimal GetDecimal()
{
throw new NotImplementedException();
}
public override string GetUntypedNumber()
{
throw new NotImplementedException();
}
public string[] GetPropertyNames()
{
throw new NotImplementedException();
}
public override string GetString()
{
return Cell.ToString();
}
public override bool TryGetProperty(string propertyName, out IUntypedObject result)
{
if (DataTable != null)
{
throw new NotImplementedException();
}
if (!DataRow.Table.Columns.Contains(propertyName))
{
result = default;
return false;
}
var cell = DataRow[propertyName];
result = new NotImplementedUntypedObject(cell);
return true;
}
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
result = null;
return false;

Просмотреть файл

@ -799,6 +799,8 @@ namespace Microsoft.PowerFx.Interpreter.Tests
var t_bsType = TableType.Empty().Add("b", FormulaType.String);
engine.UpdateVariable("t_bs1", FormulaValue.NewTable(t_bsType.ToRecord()));
engine.UpdateVariable("t_bs2", FormulaValue.NewTable(t_bsType.ToRecord()));
engine.Config.EnableJsonFunctions();
}
private static void TraceSetup(RecalcEngine engine, bool numberIsFloat)

Просмотреть файл

@ -14,7 +14,8 @@ namespace Microsoft.PowerFx.Tests
// Wrap a .net object as an UntypedObject.
// This will lazily marshal through the object as it's accessed.
[DebuggerDisplay("{_source}")]
public class PrimitiveWrapperAsUnknownObject : IUntypedObject
[DebuggerDisplay("{_source}")]
public class PrimitiveWrapperAsUnknownObject : UntypedObjectBase
{
public readonly object _source;
@ -28,7 +29,7 @@ namespace Microsoft.PowerFx.Tests
return FormulaValue.New(new PrimitiveWrapperAsUnknownObject(source));
}
public FormulaType Type
public override FormulaType Type
{
get
{
@ -61,7 +62,7 @@ namespace Microsoft.PowerFx.Tests
}
}
public IUntypedObject this[int index]
public override IUntypedObject this[int index]
{
get
{
@ -81,13 +82,13 @@ namespace Microsoft.PowerFx.Tests
}
}
public int GetArrayLength()
public override int GetArrayLength()
{
var a = (Array)_source;
return a.Length;
}
public bool GetBoolean()
public override bool GetBoolean()
{
Assert.True(Type == FormulaType.Boolean);
@ -99,7 +100,7 @@ namespace Microsoft.PowerFx.Tests
throw new InvalidOperationException($"Not a boolean type");
}
public double GetDouble()
public override double GetDouble()
{
// Fx will only call this helper for numbers.
Assert.True(Type == FormulaType.Number);
@ -122,7 +123,7 @@ namespace Microsoft.PowerFx.Tests
throw new InvalidOperationException($"Not a number type");
}
public decimal GetDecimal()
public override decimal GetDecimal()
{
// Fx will only call this helper for decimals.
Assert.True(Type == FormulaType.Decimal);
@ -145,12 +146,12 @@ namespace Microsoft.PowerFx.Tests
throw new InvalidOperationException($"Not a decimal type");
}
public string GetUntypedNumber()
public override string GetUntypedNumber()
{
throw new NotImplementedException();
}
public string GetString()
public override string GetString()
{
Assert.True(Type == FormulaType.String);
@ -162,7 +163,7 @@ namespace Microsoft.PowerFx.Tests
throw new InvalidOperationException($"Not a string type");
}
public bool TryGetProperty(string value, out IUntypedObject result)
public override bool TryGetProperty(string value, out IUntypedObject result)
{
Assert.True(Type == ExternalType.ObjectType);
@ -191,7 +192,7 @@ namespace Microsoft.PowerFx.Tests
return true;
}
public bool TryGetPropertyNames(out IEnumerable<string> result)
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
result = null;
return false;

Просмотреть файл

@ -13,7 +13,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
{
// Demonstrate mutation example using IUntypedObject
public class ScenarioMutation : PowerFxTest
{
{
[Fact]
public void MutabilityTest()
{
@ -26,7 +26,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
{
["prop"] = FormulaValue.New(123)
};
var obj = MutableObject.New(d);
engine.UpdateVariable("obj", obj);
@ -45,15 +45,15 @@ namespace Microsoft.PowerFx.Interpreter.Tests
[Theory]
[InlineData("Assert2(obj.prop, 123); Set2(obj, \"prop\", 456); Assert2(obj.prop, 456)")]
[InlineData("Assert2(obj.prop, 123); Set3(obj, \"prop\", \"prop2\"); Assert2(obj.prop, 456)")]
[InlineData("Assert2(obj.prop, 123); Set3(obj, \"prop\", \"prop2\"); Assert2(obj.prop, 456)")]
public void MutabilityTest_Chain(string expr)
{
var config = new PowerFxConfig();
var config = new PowerFxConfig();
config.AddFunction(new Assert2Function());
config.AddFunction(new Set2Function());
config.AddFunction(new Set3Function());
var engine = new RecalcEngine(config);
var engine = new RecalcEngine(config);
var d = new Dictionary<string, FormulaValue>
{
["prop"] = FormulaValue.New(123),
@ -72,7 +72,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
Assert.IsType<DecimalValue>(x);
Assert.Equal(456, ((DecimalValue)x).Value);
Assert.Equal(456, ((DecimalValue)d["prop"]).Value);
Assert.Equal(456, ((DecimalValue)d["prop"]).Value);
}
[Fact]
@ -133,7 +133,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
{
var impl = (MutableObject)obj.Impl;
impl.TryGetProperty(propName2.Value, out var propValue);
var val = propValue.GetDecimal();
var val = propValue.GetDecimal();
impl.Set(propName.Value, new DecimalValue(IRContext.NotInSource(FormulaType.Decimal), val));
}
}
@ -193,7 +193,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
}
}
private class MutableObject : IUntypedObject
private class MutableObject : UntypedObjectBase
{
private Dictionary<string, FormulaValue> _values = new Dictionary<string, FormulaValue>();
@ -212,41 +212,41 @@ namespace Microsoft.PowerFx.Interpreter.Tests
return FormulaValue.New(x);
}
public IUntypedObject this[int index] => throw new NotImplementedException();
public override IUntypedObject this[int index] => throw new NotImplementedException();
public FormulaType Type => ExternalType.ObjectType;
public override FormulaType Type => ExternalType.ObjectType;
public int GetArrayLength()
public override int GetArrayLength()
{
throw new NotImplementedException();
}
public bool GetBoolean()
public override bool GetBoolean()
{
throw new NotImplementedException();
}
public double GetDouble()
{
throw new NotImplementedException();
}
public decimal GetDecimal()
public override double GetDouble()
{
throw new NotImplementedException();
}
public string GetUntypedNumber()
public override decimal GetDecimal()
{
throw new NotImplementedException();
}
public string GetString()
public override string GetUntypedNumber()
{
throw new NotImplementedException();
}
public bool TryGetProperty(string value, out IUntypedObject result)
public override string GetString()
{
throw new NotImplementedException();
}
public override bool TryGetProperty(string value, out IUntypedObject result)
{
if (_values.TryGetValue(value, out var x))
{
@ -258,7 +258,7 @@ namespace Microsoft.PowerFx.Interpreter.Tests
return false;
}
public bool TryGetPropertyNames(out IEnumerable<string> result)
public override bool TryGetPropertyNames(out IEnumerable<string> result)
{
result = null;
return false;