diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj
index 4b373f7..b988ee1 100644
--- a/ASTPlayground/ASTPlayground.dproj
+++ b/ASTPlayground/ASTPlayground.dproj
@@ -4,7 +4,7 @@
20.3
FMX
True
- Debug
+ Release
Win64
ASTPlayground
2
diff --git a/Src/AST/Myc.Ast.Evaluator.pas b/Src/AST/Myc.Ast.Evaluator.pas
index cb4d533..8dd397b 100644
--- a/Src/AST/Myc.Ast.Evaluator.pas
+++ b/Src/AST/Myc.Ast.Evaluator.pas
@@ -395,7 +395,6 @@ end;
function TEvaluatorVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
var
leftValue, rightValue: TDataValue;
- leftScalar, rightScalar: TScalar;
begin
leftValue := Node.Left.Accept(Self);
rightValue := Node.Right.Accept(Self);
@@ -403,51 +402,30 @@ begin
if (leftValue.Kind <> vkScalar) or (rightValue.Kind <> vkScalar) then
raise ENotSupportedException.Create('Binary operations are only supported for scalar types.');
- leftScalar := leftValue.AsScalar;
- rightScalar := rightValue.AsScalar;
-
- if not TScalar.IsBinaryOperatorSupported(Node.Operator, leftScalar.Kind, rightScalar.Kind) then
- raise ENotSupportedException.Create('Binary operation not supported for scalar type.');
-
- case Node.Operator of
- boAdd: Result := leftScalar + rightScalar;
- boSubtract: Result := leftScalar - rightScalar;
- boMultiply: Result := leftScalar * rightScalar;
- boDivide: Result := leftScalar / rightScalar;
- boEqual: Result := TScalar.FromBoolean(leftScalar = rightScalar);
- boNotEqual: Result := TScalar.FromBoolean(leftScalar <> rightScalar);
- boLess: Result := TScalar.FromBoolean(leftScalar < rightScalar);
- boGreater: Result := TScalar.FromBoolean(leftScalar > rightScalar);
- boLessOrEqual: Result := TScalar.FromBoolean(leftScalar <= rightScalar);
- boGreaterOrEqual: Result := TScalar.FromBoolean(leftScalar >= rightScalar);
- else
- raise ENotSupportedException.Create('Unsupported binary operator.');
- end;
+ var res: TScalar;
+ if not TScalar.TryBinaryOperation(Node.Operator, leftValue.AsScalar, rightValue.AsScalar, res) then
+ raise ENotSupportedException.Create(
+ 'Binary operation not supported for scalar types '
+ + leftValue.AsScalar.Kind.ToString
+ + ' and '
+ + rightValue.AsScalar.Kind.ToString
+ + ' .');
+ Result := res;
end;
function TEvaluatorVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
var
rightValue: TDataValue;
- rightScalar: TScalar;
begin
rightValue := Node.Right.Accept(Self);
- if not TScalar.IsUnaryOperatorSupported(Node.Operator, rightScalar.Kind) then
- raise ENotSupportedException.Create('Unary operation not supported for scalar type.');
+ if rightValue.Kind <> vkScalar then
+ raise ENotSupportedException.Create('Unary operations are only supported for scalar types.');
- case Node.Operator of
- uoNegate:
- begin
- rightScalar := rightValue.AsScalar;
- Result := -rightScalar;
- end;
- uoNot:
- begin
- Result := TScalar.FromBoolean(not IsTruthy(rightValue));
- end;
- else
- raise ENotSupportedException.Create('Unary operator not supported');
- end;
+ var res: TScalar;
+ if not TScalar.TryUnaryOperation(Node.Operator, rightValue.AsScalar, res) then
+ raise ENotSupportedException.Create('Unary operation not supported for scalar type' + rightValue.AsScalar.Kind.ToString + '.');
+ Result := res;
end;
function TEvaluatorVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
diff --git a/Src/Data/Myc.Data.Scalar.pas b/Src/Data/Myc.Data.Scalar.pas
index 2cdb074..bd4fa3f 100644
--- a/Src/Data/Myc.Data.Scalar.pas
+++ b/Src/Data/Myc.Data.Scalar.pas
@@ -100,6 +100,9 @@ type
class function IsBinaryOperatorSupported(Op: TBinaryOperator; A, B: TScalarKind): Boolean; static;
class function IsUnaryOperatorSupported(Op: TUnaryOperator; A: TScalarKind): Boolean; static;
+ class function TryBinaryOperation(Op: TBinaryOperator; const A, B: TScalar; out Res: TScalar): Boolean; static;
+ class function TryUnaryOperation(Op: TUnaryOperator; const A: TScalar; out Res: TScalar): Boolean; static;
+
class operator Add(const A, B: TScalar): TScalar;
class operator Divide(const A, B: TScalar): TScalar;
class operator Equal(const A, B: TScalar): Boolean;
@@ -107,6 +110,7 @@ type
class operator GreaterThanOrEqual(const A, B: TScalar): Boolean;
class operator LessThan(const A, B: TScalar): Boolean;
class operator LessThanOrEqual(const A, B: TScalar): Boolean;
+ class operator LogicalNot(const A: TScalar): TScalar;
class operator Multiply(const A, B: TScalar): TScalar;
class operator Negative(const A: TScalar): TScalar;
class operator NotEqual(const A, B: TScalar): Boolean;
@@ -471,31 +475,31 @@ end;
class function TScalar.StringToKind(const AName: string): TScalarKind;
begin
- if SameText(AName, 'integer') then
+ if SameText(AName, 'Integer') then
Result := skInteger
- else if SameText(AName, 'int64') then
+ else if SameText(AName, 'Int64') then
Result := skInt64
- else if SameText(AName, 'uint64') then
+ else if SameText(AName, 'UInt64') then
Result := skUInt64
- else if SameText(AName, 'single') then
+ else if SameText(AName, 'Single') then
Result := skSingle
- else if SameText(AName, 'double') then
+ else if SameText(AName, 'Double') then
Result := skDouble
- else if SameText(AName, 'datetime') then
+ else if SameText(AName, 'DateTime') then
Result := skDateTime
- else if SameText(AName, 'timestamp') then
+ else if SameText(AName, 'Timestamp') then
Result := skTimestamp
- else if SameText(AName, 'boolean') then
+ else if SameText(AName, 'Boolean') then
Result := skBoolean
- else if SameText(AName, 'char') then
+ else if SameText(AName, 'Char') then
Result := skChar
- else if SameText(AName, 'pchar') then
+ else if SameText(AName, 'PChar') then
Result := skPChar
- else if SameText(AName, 'string') then
+ else if SameText(AName, 'String') then
Result := skString
- else if SameText(AName, 'bytes') then
+ else if SameText(AName, 'Bytes') then
Result := skBytes
- else if SameText(AName, 'decimal') then
+ else if SameText(AName, 'Decimal') then
Result := skDecimal
else
raise EArgumentException.CreateFmt('Unknown scalar type name: "%s"', [AName]);
@@ -522,6 +526,58 @@ begin
end;
end;
+class function TScalar.TryBinaryOperation(Op: TBinaryOperator; const A, B: TScalar; out Res: TScalar): Boolean;
+begin
+ if not IsBinaryOperatorSupported(Op, A.Kind, B.Kind) then
+ begin
+ Result := False;
+ exit;
+ end;
+
+ try
+ case Op of
+ boAdd: Res := A + B;
+ boSubtract: Res := A - B;
+ boMultiply: Res := A * B;
+ boDivide: Res := A / B;
+ boEqual: Res := TScalar.FromBoolean(A = B);
+ boNotEqual: Res := TScalar.FromBoolean(A <> B);
+ boLess: Res := TScalar.FromBoolean(A < B);
+ boGreater: Res := TScalar.FromBoolean(A > B);
+ boLessOrEqual: Res := TScalar.FromBoolean(A <= B);
+ boGreaterOrEqual: Res := TScalar.FromBoolean(A >= B);
+ else
+ Result := False;
+ exit;
+ end;
+ Result := True;
+ except
+ Result := False;
+ end;
+end;
+
+class function TScalar.TryUnaryOperation(Op: TUnaryOperator; const A: TScalar; out Res: TScalar): Boolean;
+begin
+ if not IsUnaryOperatorSupported(Op, A.Kind) then
+ begin
+ Result := False;
+ exit;
+ end;
+
+ try
+ case Op of
+ uoNegate: Res := -A;
+ uoNot: Res := not A;
+ else
+ Result := False;
+ exit;
+ end;
+ Result := True;
+ except
+ Result := False;
+ end;
+end;
+
class operator TScalar.Add(const A, B: TScalar): TScalar;
begin
// Fast path for identical types
@@ -916,6 +972,19 @@ begin
Result := (A < B) or (A = B);
end;
+class operator TScalar.LogicalNot(const A: TScalar): TScalar;
+begin
+ Result.Kind := A.Kind;
+ case A.Kind of
+ skBoolean: Result.Value.AsBoolean := not A.Value.AsBoolean;
+ skInteger: Result.Value.AsInteger := not A.Value.AsInteger;
+ skInt64: Result.Value.AsInt64 := not A.Value.AsInt64;
+ skUInt64: Result.Value.AsUInt64 := not A.Value.AsUInt64;
+ else
+ raise EArgumentException.CreateFmt('Operator Not not supported for type %s', [A.Kind.ToString]);
+ end;
+end;
+
class operator TScalar.Multiply(const A, B: TScalar): TScalar;
begin
// Fast path for identical types