Separate out BinaryOp IR Matrix to be sharable with JS Translator (#479)

This commit is contained in:
McCall Saltzman 2022-07-18 16:40:19 -07:00 коммит произвёл GitHub
Родитель 9e7b6f6a82
Коммит 74a063ea39
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 459 добавлений и 390 удалений

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

@ -0,0 +1,393 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using Microsoft.PowerFx.Core.Binding;
using Microsoft.PowerFx.Core.IR.Nodes;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;
using Microsoft.PowerFx.Syntax;
namespace Microsoft.PowerFx.Core.IR
{
internal class BinaryOpMatrix
{
public static BinaryOpKind GetBinaryOpKind(Syntax.BinaryOpNode node, TexlBinding binding)
{
var parsedBinaryOp = node.Op;
var leftType = binding.GetType(node.Left);
var rightType = binding.GetType(node.Right);
return parsedBinaryOp switch
{
BinaryOp.In or BinaryOp.Exactin => GetInOp(parsedBinaryOp, leftType, rightType),
BinaryOp.Power => BinaryOpKind.Power,
BinaryOp.Concat => BinaryOpKind.Concatenate,
BinaryOp.And => BinaryOpKind.And,
BinaryOp.Or => BinaryOpKind.Or,
BinaryOp.Add => GetAddOp(node, leftType, rightType),
BinaryOp.Mul => BinaryOpKind.MulNumbers,
BinaryOp.Div => BinaryOpKind.DivNumbers,
BinaryOp.Equal or
BinaryOp.NotEqual or
BinaryOp.Less or
BinaryOp.Greater or
BinaryOp.LessEqual or
BinaryOp.GreaterEqual => GetBooleanBinaryOp(node, binding, leftType, rightType),
BinaryOp.Error => BinaryOpKind.Invalid,
_ => throw new NotSupportedException(),
};
}
private static BinaryOpKind GetBooleanBinaryOp(Syntax.BinaryOpNode node, TexlBinding binding, DType leftType, DType rightType)
{
var kindToUse = leftType.Accepts(rightType) ? leftType.Kind : rightType.Kind;
if (!leftType.Accepts(rightType) && !rightType.Accepts(leftType))
{
// There is coercion involved, pick the coerced type.
if (binding.TryGetCoercedType(node.Left, out var leftCoerced))
{
kindToUse = leftCoerced.Kind;
}
else if (binding.TryGetCoercedType(node.Right, out var rightCoerced))
{
kindToUse = rightCoerced.Kind;
}
else
{
return BinaryOpKind.Invalid;
}
}
switch (kindToUse)
{
case DKind.Number:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqNumbers;
case BinaryOp.Equal:
return BinaryOpKind.EqNumbers;
case BinaryOp.Less:
return BinaryOpKind.LtNumbers;
case BinaryOp.LessEqual:
return BinaryOpKind.LeqNumbers;
case BinaryOp.Greater:
return BinaryOpKind.GtNumbers;
case BinaryOp.GreaterEqual:
return BinaryOpKind.GeqNumbers;
default:
throw new NotSupportedException();
}
case DKind.Date:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqDate;
case BinaryOp.Equal:
return BinaryOpKind.EqDate;
case BinaryOp.Less:
return BinaryOpKind.LtDate;
case BinaryOp.LessEqual:
return BinaryOpKind.LeqDate;
case BinaryOp.Greater:
return BinaryOpKind.GtDate;
case BinaryOp.GreaterEqual:
return BinaryOpKind.GeqDate;
default:
throw new NotSupportedException();
}
case DKind.DateTime:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqDateTime;
case BinaryOp.Equal:
return BinaryOpKind.EqDateTime;
case BinaryOp.Less:
return BinaryOpKind.LtDateTime;
case BinaryOp.LessEqual:
return BinaryOpKind.LeqDateTime;
case BinaryOp.Greater:
return BinaryOpKind.GtDateTime;
case BinaryOp.GreaterEqual:
return BinaryOpKind.GeqDateTime;
default:
throw new NotSupportedException();
}
case DKind.Time:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqTime;
case BinaryOp.Equal:
return BinaryOpKind.EqTime;
case BinaryOp.Less:
return BinaryOpKind.LtTime;
case BinaryOp.LessEqual:
return BinaryOpKind.LeqTime;
case BinaryOp.Greater:
return BinaryOpKind.GtTime;
case BinaryOp.GreaterEqual:
return BinaryOpKind.GeqTime;
default:
throw new NotSupportedException();
}
case DKind.Boolean:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqBoolean;
case BinaryOp.Equal:
return BinaryOpKind.EqBoolean;
default:
throw new NotSupportedException();
}
case DKind.String:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqText;
case BinaryOp.Equal:
return BinaryOpKind.EqText;
default:
throw new NotSupportedException();
}
case DKind.Hyperlink:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqHyperlink;
case BinaryOp.Equal:
return BinaryOpKind.EqHyperlink;
default:
throw new NotSupportedException();
}
case DKind.Currency:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqCurrency;
case BinaryOp.Equal:
return BinaryOpKind.EqCurrency;
default:
throw new NotSupportedException();
}
case DKind.Image:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqImage;
case BinaryOp.Equal:
return BinaryOpKind.EqImage;
default:
throw new NotSupportedException();
}
case DKind.Color:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqColor;
case BinaryOp.Equal:
return BinaryOpKind.EqColor;
default:
throw new NotSupportedException();
}
case DKind.Media:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqMedia;
case BinaryOp.Equal:
return BinaryOpKind.EqMedia;
default:
throw new NotSupportedException();
}
case DKind.Blob:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqBlob;
case BinaryOp.Equal:
return BinaryOpKind.EqBlob;
default:
throw new NotSupportedException();
}
case DKind.Guid:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqGuid;
case BinaryOp.Equal:
return BinaryOpKind.EqGuid;
default:
throw new NotSupportedException();
}
case DKind.ObjNull:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqNull;
case BinaryOp.Equal:
return BinaryOpKind.EqNull;
default:
throw new NotSupportedException();
}
case DKind.OptionSetValue:
switch (node.Op)
{
case BinaryOp.NotEqual:
return BinaryOpKind.NeqOptionSetValue;
case BinaryOp.Equal:
return BinaryOpKind.EqOptionSetValue;
default:
throw new NotSupportedException();
}
default:
throw new NotSupportedException("Not supported comparison op on type " + kindToUse.ToString());
}
}
private static BinaryOpKind GetAddOp(Syntax.BinaryOpNode node, DType leftType, DType rightType)
{
switch (leftType.Kind)
{
case DKind.Date:
if (rightType == DType.DateTime || rightType == DType.Date)
{
// Date + '-DateTime' => in days
// Date + '-Date' => in days
// Binding produces this as '-Date'. This should be cleaned up when we switch to a proper sub op.
if (node.Right is not Syntax.UnaryOpNode { Op: UnaryOp.Minus })
{
throw new NotSupportedException();
}
return BinaryOpKind.DateDifference;
}
else if (rightType == DType.Time)
{
return BinaryOpKind.AddDateAndTime;
}
else
{
return BinaryOpKind.AddDateAndDay;
}
case DKind.Time:
if (rightType == DType.Date)
{
// Time + Date => DateTime
return BinaryOpKind.AddTimeAndDate;
}
else if (rightType == DType.Time)
{
// Time + '-Time' => in ms
// Ensure that this is really '-Time' - Binding should always catch this, but let's make sure...
Contracts.Assert(node.Right.AsUnaryOpLit().VerifyValue().Op == UnaryOp.Minus);
return BinaryOpKind.AddNumbers;
}
else
{
// Time + Number
return BinaryOpKind.AddTimeAndMilliseconds;
}
case DKind.DateTime:
if (rightType == DType.DateTime || rightType == DType.Date)
{
// DateTime + '-DateTime' => in days
// DateTime + '-Date' => in days
// Ensure that this is really '-Date' - Binding should always catch this, but let's make sure...
Contracts.Assert(node.Right.AsUnaryOpLit().VerifyValue().Op == UnaryOp.Minus);
return BinaryOpKind.DateDifference;
}
else
{
return BinaryOpKind.AddDateTimeAndDay;
}
default:
switch (rightType.Kind)
{
case DKind.Date:
// Number + Date
return BinaryOpKind.AddDayAndDate;
case DKind.Time:
// Number + Date
return BinaryOpKind.AddMillisecondsAndTime;
case DKind.DateTime:
return BinaryOpKind.AddDayAndDateTime;
default:
// Number + Number
return BinaryOpKind.AddNumbers;
}
}
}
private static BinaryOpKind GetInOp(BinaryOp parsedBinaryOp, DType leftType, DType rightType)
{
if (!rightType.IsAggregate)
{
if ((DType.String.Accepts(rightType) && (DType.String.Accepts(leftType) || leftType.CoercesTo(DType.String))) ||
(rightType.CoercesTo(DType.String) && DType.String.Accepts(leftType)))
{
return parsedBinaryOp == BinaryOp.In ? BinaryOpKind.InText : BinaryOpKind.ExactInText;
}
return BinaryOpKind.Invalid;
}
if (!leftType.IsAggregate)
{
if (rightType.IsTable)
{
// scalar in table: in_ST(left, right)
// scalar exactin table: exactin_ST(left, right)
return parsedBinaryOp == BinaryOp.In ? BinaryOpKind.InScalarTable : BinaryOpKind.ExactInScalarTable;
}
// scalar in record: not supported
// scalar exactin record: not supported
return BinaryOpKind.Invalid;
}
if (leftType.IsRecord)
{
if (rightType.IsTable)
{
// record in table: in_RT(left, right)
// record exactin table: in_RT(left, right)
// This is done regardless of "exactness".
return BinaryOpKind.InRecordTable;
}
// record in record: not supported
// record exactin record: not supported
return BinaryOpKind.Invalid;
}
// table in anything: not supported
// table exactin anything: not supported
return BinaryOpKind.Invalid;
}
}
}

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

@ -156,97 +156,73 @@ namespace Microsoft.PowerFx.Core.IR
var left = node.Left.Accept(this, context);
var right = node.Right.Accept(this, context);
var leftType = context.Binding.GetType(node.Left);
var rightType = context.Binding.GetType(node.Right);
var kind = BinaryOpMatrix.GetBinaryOpKind(node, context.Binding);
IntermediateNode binaryOpResult;
switch (node.Op)
switch (kind)
{
case BinaryOp.In:
case BinaryOp.Exactin:
if (!rightType.IsAggregate)
{
if ((DType.String.Accepts(rightType) && (DType.String.Accepts(leftType) || leftType.CoercesTo(DType.String))) ||
(rightType.CoercesTo(DType.String) && DType.String.Accepts(leftType)))
{
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), node.Op == BinaryOp.In ? BinaryOpKind.InText : BinaryOpKind.ExactInText, left, right);
break;
}
// anything else in scalar: not supported.
Contracts.Assert(context.Binding.ErrorContainer.HasErrors(node.Left) || context.Binding.ErrorContainer.HasErrors(node.Right));
return new ErrorNode(context.GetIRContext(node), node.ToString());
}
if (!leftType.IsAggregate)
{
if (rightType.IsTable)
{
// scalar in table: in_ST(left, right)
// scalar exactin table: exactin_ST(left, right)
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), node.Op == BinaryOp.In ? BinaryOpKind.InScalarTable : BinaryOpKind.ExactInScalarTable, left, right);
break;
}
// scalar in record: not supported
// scalar exactin record: not supported
Contracts.Assert(context.Binding.ErrorContainer.HasErrors(node.Left) || context.Binding.ErrorContainer.HasErrors(node.Right));
return new ErrorNode(context.GetIRContext(node), node.ToString());
}
if (leftType.IsRecord)
{
if (rightType.IsTable)
{
// record in table: in_RT(left, right)
// record exactin table: in_RT(left, right)
// This is done regardless of "exactness".
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.InRecordTable, left, right);
break;
}
// record in record: not supported
// record exactin record: not supported
Contracts.Assert(context.Binding.ErrorContainer.HasErrors(node.Left) || context.Binding.ErrorContainer.HasErrors(node.Right));
return new ErrorNode(context.GetIRContext(node), node.ToString());
}
// table in anything: not supported
// table exactin anything: not supported
Contracts.Assert(context.Binding.ErrorContainer.HasErrors(node.Left));
return new ErrorNode(context.GetIRContext(node), node.ToString());
case BinaryOp.Power:
// Call Node Replacements:
case BinaryOpKind.Power:
binaryOpResult = new CallNode(context.GetIRContext(node), BuiltinFunctionsCore.Power, left, right);
break;
case BinaryOp.Concat:
case BinaryOpKind.Concatenate:
binaryOpResult = new CallNode(context.GetIRContext(node), BuiltinFunctionsCore.Concatenate, left, right);
break;
case BinaryOp.Or:
case BinaryOp.And:
case BinaryOpKind.Or:
case BinaryOpKind.And:
binaryOpResult = new CallNode(context.GetIRContext(node), node.Op == BinaryOp.And ? BuiltinFunctionsCore.And : BuiltinFunctionsCore.Or, left, new LazyEvalNode(context.GetIRContext(node), right));
break;
case BinaryOp.Add:
binaryOpResult = GetAddBinaryOp(context, node, left, right, leftType, rightType);
// Reversed Args:
case BinaryOpKind.AddTimeAndDate:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndTime, right, left);
break;
case BinaryOp.Mul:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.MulNumbers, left, right);
case BinaryOpKind.AddDayAndDate:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndDay, right, left);
break;
case BinaryOp.Div:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.DivNumbers, left, right);
case BinaryOpKind.AddMillisecondsAndTime:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddTimeAndMilliseconds, right, left);
break;
case BinaryOp.Equal:
case BinaryOp.NotEqual:
case BinaryOp.Less:
case BinaryOp.LessEqual:
case BinaryOp.Greater:
case BinaryOp.GreaterEqual:
binaryOpResult = GetBooleanBinaryOp(context, node, left, right, leftType, rightType);
case BinaryOpKind.AddDayAndDateTime:
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateTimeAndDay, right, left);
break;
case BinaryOp.Error:
return new ErrorNode(context.GetIRContext(node), node.ToString());
case BinaryOpKind.Invalid:
if (node.Op == BinaryOp.NotEqual)
{
binaryOpResult = new BooleanLiteralNode(context.GetIRContext(node), true);
}
else if (node.Op == BinaryOp.Equal)
{
binaryOpResult = new BooleanLiteralNode(context.GetIRContext(node), false);
}
else if (node.Op == BinaryOp.Error || context.Binding.ErrorContainer.HasErrors(node.Left) || context.Binding.ErrorContainer.HasErrors(node.Right))
{
return new ErrorNode(context.GetIRContext(node), node.ToString());
}
else
{
throw new NotSupportedException();
}
break;
// Date Diff pulls from nested unary op
case BinaryOpKind.DateDifference:
// Validated in Matrix + Binder
if (right is not UnaryOpNode { Op: UnaryOpKind.Negate } unaryNegate)
{
throw new NotSupportedException();
}
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.DateDifference, left, unaryNegate.Child);
break;
// All others used directly
default:
throw new NotSupportedException();
binaryOpResult = new BinaryOpNode(context.GetIRContext(node), kind, left, right);
break;
}
return MaybeInjectCoercion(node, binaryOpResult, context);
@ -754,319 +730,6 @@ namespace Microsoft.PowerFx.Core.IR
return new UnaryOpNode(IRContext.NotInSource(FormulaType.Build(toType)), unaryOpKind, child);
}
private static IntermediateNode GetAddBinaryOp(IRTranslatorContext context, TexlBinaryOpNode node, IntermediateNode left, IntermediateNode right, DType leftType, DType rightType)
{
Contracts.AssertValue(node);
Contracts.Assert(node.Op == BinaryOp.Add);
switch (leftType.Kind)
{
case DKind.Date:
if (rightType == DType.DateTime || rightType == DType.Date)
{
// Date + '-DateTime' => in days
// Date + '-Date' => in days
// Binding produces this as '-Date'. This should be cleaned up when we switch to a proper sub op.
if (right is not UnaryOpNode unaryNode || unaryNode.Op != UnaryOpKind.Negate)
{
throw new NotSupportedException();
}
// Use the child of the negate as the rhs for datediff
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.DateDifference, left, unaryNode.Child);
}
else if (rightType == DType.Time)
{
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndTime, left, right);
}
else
{
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndDay, left, right);
}
case DKind.Time:
if (rightType == DType.Date)
{
// Time + Date => DateTime
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndTime, right, left);
}
else if (rightType == DType.Time)
{
// Time + '-Time' => in ms
// Ensure that this is really '-Time' - Binding should always catch this, but let's make sure...
Contracts.Assert(node.Right.AsUnaryOpLit().VerifyValue().Op == UnaryOp.Minus);
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddNumbers, left, right);
}
else
{
// Time + Number
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddTimeAndMilliseconds, left, right);
}
case DKind.DateTime:
if (rightType == DType.DateTime || rightType == DType.Date)
{
// DateTime + '-DateTime' => in days
// DateTime + '-Date' => in days
// Ensure that this is really '-Date' - Binding should always catch this, but let's make sure...
Contracts.Assert(node.Right.AsUnaryOpLit().VerifyValue().Op == UnaryOp.Minus);
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.DateDifference, left, right);
}
else
{
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateTimeAndDay, left, right);
}
default:
switch (rightType.Kind)
{
case DKind.Date:
// Number + Date
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateAndDay, right, left);
case DKind.Time:
// Number + Date
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddTimeAndMilliseconds, right, left);
case DKind.DateTime:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddDateTimeAndDay, right, left);
default:
// Number + Number
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.AddNumbers, left, right);
}
}
}
private static IntermediateNode GetBooleanBinaryOp(IRTranslatorContext context, TexlBinaryOpNode node, IntermediateNode left, IntermediateNode right, DType leftType, DType rightType)
{
var kindToUse = leftType.Accepts(rightType) ? leftType.Kind : rightType.Kind;
if (!leftType.Accepts(rightType) && !rightType.Accepts(leftType))
{
// There is coercion involved, pick the coerced type.
if (context.Binding.TryGetCoercedType(node.Left, out var leftCoerced))
{
kindToUse = leftCoerced.Kind;
}
else if (context.Binding.TryGetCoercedType(node.Right, out var rightCoerced))
{
kindToUse = rightCoerced.Kind;
}
else
{
// In this particular case, we issue a warning
// We only manage = and <> cases here as other comparison operators are more complex to handle
// See https://stackoverflow.com/questions/35050151/excel-if-statement-comparing-text-with-number
return (node.Op == BinaryOp.NotEqual) ? new BooleanLiteralNode(context.GetIRContext(node), true)
: (node.Op == BinaryOp.Equal) ? new BooleanLiteralNode(context.GetIRContext(node), false)
: throw new NotSupportedException();
}
}
switch (kindToUse)
{
case DKind.Number:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqNumbers, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqNumbers, left, right);
case BinaryOp.Less:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LtNumbers, left, right);
case BinaryOp.LessEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LeqNumbers, left, right);
case BinaryOp.Greater:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GtNumbers, left, right);
case BinaryOp.GreaterEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GeqNumbers, left, right);
default:
throw new NotSupportedException();
}
case DKind.Date:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqDate, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqDate, left, right);
case BinaryOp.Less:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LtDate, left, right);
case BinaryOp.LessEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LeqDate, left, right);
case BinaryOp.Greater:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GtDate, left, right);
case BinaryOp.GreaterEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GeqDate, left, right);
default:
throw new NotSupportedException();
}
case DKind.DateTime:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqDateTime, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqDateTime, left, right);
case BinaryOp.Less:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LtDateTime, left, right);
case BinaryOp.LessEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LeqDateTime, left, right);
case BinaryOp.Greater:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GtDateTime, left, right);
case BinaryOp.GreaterEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GeqDateTime, left, right);
default:
throw new NotSupportedException();
}
case DKind.Time:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqTime, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqTime, left, right);
case BinaryOp.Less:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LtTime, left, right);
case BinaryOp.LessEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.LeqTime, left, right);
case BinaryOp.Greater:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GtTime, left, right);
case BinaryOp.GreaterEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.GeqTime, left, right);
default:
throw new NotSupportedException();
}
case DKind.Boolean:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqBoolean, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqBoolean, left, right);
default:
throw new NotSupportedException();
}
case DKind.String:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqText, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqText, left, right);
default:
throw new NotSupportedException();
}
case DKind.Hyperlink:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqHyperlink, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqHyperlink, left, right);
default:
throw new NotSupportedException();
}
case DKind.Currency:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqCurrency, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqCurrency, left, right);
default:
throw new NotSupportedException();
}
case DKind.Image:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqImage, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqImage, left, right);
default:
throw new NotSupportedException();
}
case DKind.Color:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqColor, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqColor, left, right);
default:
throw new NotSupportedException();
}
case DKind.Media:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqMedia, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqMedia, left, right);
default:
throw new NotSupportedException();
}
case DKind.Blob:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqBlob, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqBlob, left, right);
default:
throw new NotSupportedException();
}
case DKind.Guid:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqGuid, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqGuid, left, right);
default:
throw new NotSupportedException();
}
case DKind.ObjNull:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqNull, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqNull, left, right);
default:
throw new NotSupportedException();
}
case DKind.OptionSetValue:
switch (node.Op)
{
case BinaryOp.NotEqual:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.NeqOptionSetValue, left, right);
case BinaryOp.Equal:
return new BinaryOpNode(context.GetIRContext(node), BinaryOpKind.EqOptionSetValue, left, right);
default:
throw new NotSupportedException();
}
default:
throw new NotSupportedException("Not supported comparison op on type " + kindToUse.ToString());
}
}
}
internal class IRTranslatorContext

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

@ -5,6 +5,8 @@ namespace Microsoft.PowerFx.Core.IR.Nodes
{
internal enum BinaryOpKind
{
Invalid,
InText,
ExactInText,
InScalarTable,
@ -78,5 +80,16 @@ namespace Microsoft.PowerFx.Core.IR.Nodes
DynamicGetField,
// And, Or, Pow, Concatenate get represented as FunctionNodes with lambdas to handle short-circuiting
// Included here to make the matrix cleaner, should not be generated in IR.
Power,
Concatenate,
And,
Or,
// These are reversed versions of earlier ops, added to make the matrix cleaner
AddTimeAndDate,
AddDayAndDate,
AddMillisecondsAndTime,
AddDayAndDateTime,
}
}