diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index 42f9c60..7743030 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -312,7 +312,7 @@ begin result := root.Accept(visitor); sw.Stop; - if not result.IsUndefined then + if not result.IsVoid then Memo1.Lines.Add(Format('Result: %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds])) else Memo1.Lines.Add(Format(' (calculated in %d ms)', [sw.ElapsedMilliseconds])); diff --git a/Src/AST/Myc.Ast.Evaluator.pas b/Src/AST/Myc.Ast.Evaluator.pas index 5386475..ec362cf 100644 --- a/Src/AST/Myc.Ast.Evaluator.pas +++ b/Src/AST/Myc.Ast.Evaluator.pas @@ -176,9 +176,9 @@ begin if Assigned(Node.Initializer) then initValue := Node.Initializer.Accept(Self) else - initValue := TAstValue.Undefined; + initValue := TAstValue.Void; FScope.SetValue(varName, initValue); - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; @@ -202,16 +202,13 @@ begin calleeValue := Node.Callee.Accept(Self); arguments := Node.Arguments; - if not calleeValue.IsClosure then - begin + if calleeValue.Kind <> avkClosure then raise EArgumentException.Create('Expression is not a callable closure.'); - end; + closure := calleeValue.AsClosure; if (arguments.Count <> Length(closure.Parameters)) then - begin raise EArgumentException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(closure.Parameters), arguments.Count]); - end; callScope := T_ExecutionScope.Create(closure.ClosureScope); @@ -236,7 +233,10 @@ begin leftValue := Node.Left.Accept(Self); rightValue := Node.Right.Accept(Self); - if not leftValue.IsScalar or not rightValue.IsScalar then + if leftValue.Kind <> rightValue.Kind then + raise ENotSupportedException.Create('Binary operations are only supported for compatible types.'); + + if leftValue.Kind <> avkScalar then begin raise ENotSupportedException.Create('Binary operations are only supported for scalar types.'); end; @@ -284,10 +284,8 @@ var rightScalar: TScalar; begin rightValue := Node.Right.Accept(Self); - if not rightValue.IsScalar then - begin + if rightValue.Kind <> avkScalar then raise ENotSupportedException.Create('Unary operations are only supported for scalar types.'); - end; rightScalar := rightValue.AsScalar; @@ -321,7 +319,7 @@ var expression: IExpressionNode; lastValue: TAstValue; begin - lastValue := TAstValue.Undefined; + lastValue := TAstValue.Void; for expression in Node.Expressions do begin lastValue := expression.Accept(Self); diff --git a/Src/AST/Myc.Ast.Nodes.pas b/Src/AST/Myc.Ast.Nodes.pas index a31e763..957cd8c 100644 --- a/Src/AST/Myc.Ast.Nodes.pas +++ b/Src/AST/Myc.Ast.Nodes.pas @@ -20,7 +20,8 @@ type function ToString: string; end; - TAstValueKind = (avkUndefined, avkScalar, avkClosure); + // Added avkText to represent a string value. + TAstValueKind = (avkUndefined, avkScalar, avkClosure, avkText); // --- Forward Declarations to break cycles --- IExecutionScope = interface; @@ -56,23 +57,21 @@ type private FKind: TAstValueKind; FScalar: TScalar; - FClosure: IEvaluatorClosure; + FInterface: IInterface; function GetKind: TAstValueKind; inline; - function GetIsScalar: Boolean; inline; - function GetIsClosure: Boolean; inline; - function GetIsUndefined: Boolean; inline; + function GetIsVoid: Boolean; inline; public class operator Initialize(out Dest: TAstValue); - class function Undefined: TAstValue; static; + class function Void: TAstValue; static; class function FromScalar(const AValue: TScalar): TAstValue; static; class function FromClosure(const AValue: IEvaluatorClosure): TAstValue; static; + class function FromText(const AValue: String): TAstValue; static; function AsScalar: TScalar; function AsClosure: IEvaluatorClosure; + function AsText: String; function ToString: String; + property IsVoid: Boolean read GetIsVoid; property Kind: TAstValueKind read GetKind; - property IsScalar: Boolean read GetIsScalar; - property IsClosure: Boolean read GetIsClosure; - property IsUndefined: Boolean read GetIsUndefined; end; IExecutionScope = interface(IInterface) @@ -198,19 +197,51 @@ type implementation +uses + System.Classes; + +type + // Private interface to encapsulate a string value for reference counting. + IAstTextValue = interface(IInterface) + function GetValue: string; + property Value: string read GetValue; + end; + + // Implementation of the text value interface. + TAstTextValue = class(TInterfacedObject, IAstTextValue) + private + FValue: string; + function GetValue: string; + public + constructor Create(const AValue: string); + end; + +{ TAstTextValue } + +constructor TAstTextValue.Create(const AValue: string); +begin + inherited Create; + FValue := AValue; +end; + +function TAstTextValue.GetValue: string; +begin + Result := FValue; +end; + { TAstValue } class operator TAstValue.Initialize(out Dest: TAstValue); begin Dest.FKind := avkUndefined; - Dest.FClosure := nil; + Dest.FInterface := nil; end; function TAstValue.AsClosure: IEvaluatorClosure; begin if (FKind <> avkClosure) then raise EInvalidCast.Create('Cannot read value as a Closure.'); - Result := FClosure; + Result := IEvaluatorClosure(FInterface); end; function TAstValue.AsScalar: TScalar; @@ -220,10 +251,17 @@ begin Result := FScalar; end; +function TAstValue.AsText: String; +begin + if (FKind <> avkText) then + raise EInvalidCast.Create('Cannot read value as Text.'); + Result := IAstTextValue(FInterface).Value; +end; + class function TAstValue.FromClosure(const AValue: IEvaluatorClosure): TAstValue; begin Result.FKind := avkClosure; - Result.FClosure := AValue; + Result.FInterface := AValue; Result.FScalar := Default(TScalar); end; @@ -231,20 +269,17 @@ class function TAstValue.FromScalar(const AValue: TScalar): TAstValue; begin Result.FKind := avkScalar; Result.FScalar := AValue; - Result.FClosure := nil; + Result.FInterface := nil; end; -function TAstValue.GetIsClosure: Boolean; +class function TAstValue.FromText(const AValue: String): TAstValue; begin - Result := FKind = avkClosure; + Result.FKind := avkText; + Result.FInterface := TAstTextValue.Create(AValue); + Result.FScalar := Default(TScalar); end; -function TAstValue.GetIsScalar: Boolean; -begin - Result := FKind = avkScalar; -end; - -function TAstValue.GetIsUndefined: Boolean; +function TAstValue.GetIsVoid: Boolean; begin Result := FKind = avkUndefined; end; @@ -259,13 +294,14 @@ begin case FKind of avkScalar: Result := FScalar.ToString; avkClosure: Result := ''; + avkText: Result := AsText; avkUndefined: Result := ''; else Result := '[Unknown AstValue]'; end; end; -class function TAstValue.Undefined: TAstValue; +class function TAstValue.Void: TAstValue; begin Result := Default(TAstValue); end; diff --git a/Src/AST/Myc.Ast.Printer.pas b/Src/AST/Myc.Ast.Printer.pas index fde1f28..89c5c6c 100644 --- a/Src/AST/Myc.Ast.Printer.pas +++ b/Src/AST/Myc.Ast.Printer.pas @@ -80,13 +80,13 @@ end; function TPrettyPrintVisitor.VisitConstant(const Node: IConstantNode): TAstValue; begin AppendLine(Format('Constant (%s)', [Node.Value.ToString])); - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitIdentifier(const Node: IIdentifierNode): TAstValue; begin AppendLine(Format('Identifier (%s)', [Node.Name])); - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; @@ -96,7 +96,7 @@ begin Node.Left.Accept(Self); Node.Right.Accept(Self); Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; @@ -105,7 +105,7 @@ begin Indent; Node.Right.Accept(Self); Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode): TAstValue; @@ -125,7 +125,7 @@ begin Node.ElseBranch.Accept(Self); Unindent; Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; @@ -148,7 +148,7 @@ begin Node.Body.Accept(Self); Unindent; Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; @@ -167,7 +167,7 @@ begin arg.Accept(Self); Unindent; Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; @@ -179,7 +179,7 @@ begin for expr in Node.Expressions do expr.Accept(Self); Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue; @@ -191,7 +191,7 @@ begin Node.Initializer.Accept(Self); Unindent; end; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitAssignment(const Node: IAssignmentNode): TAstValue; @@ -201,7 +201,7 @@ begin Indent; Node.Value.Accept(Self); Unindent; - Result := TAstValue.Undefined; + Result := TAstValue.Void; end; end.