diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index aa9549f..3ece1cc 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -288,7 +288,7 @@ begin CompilerStageBox.BringToFront; ClearButtonClick(Self); - Memo1.Lines.Text := TAstSchema.GenerateFullSystemPrompt; + Memo1.Lines.Add(TAstSchema.GenerateFullSystemPrompt); end; procedure TForm1.ShowVizualization; diff --git a/Src/AST/Myc.Ast.Json.Schema.pas b/Src/AST/Myc.Ast.Json.Schema.pas index 1c9ce18..91609d2 100644 --- a/Src/AST/Myc.Ast.Json.Schema.pas +++ b/Src/AST/Myc.Ast.Json.Schema.pas @@ -15,7 +15,7 @@ uses type TAstSchema = class public - // Generates the TypeScript definition by scanning classes via RTTI + // Generates the TypeScript definition by scanning INTERFACES via RTTI class function GenerateTypeScriptDefinition: string; // Static rules for the format @@ -29,7 +29,6 @@ implementation type // Helper structure to collect fields per type - // Moved here to avoid scope issues with generics TFieldInfo = record Idx: Integer; Def: string; @@ -42,6 +41,7 @@ var ctx: TRttiContext; types: TArray; typ: TRttiType; + prop: TRttiProperty; attr: TCustomAttribute; fieldAttr: AstFieldAttribute; nodeDefs: TDictionary>; @@ -50,7 +50,6 @@ var sb: TStringBuilder; tag: string; fieldInfo: TFieldInfo; - f: TRttiField; i: Integer; function GetTsType(Kind: TFieldKind): string; @@ -74,15 +73,16 @@ begin sb := TStringBuilder.Create; try - // 1. Scan all types in the application context + // 1. Scan all types (looking for INTERFACES now) types := ctx.GetTypes; for typ in types do begin - if not typ.IsInstance then + // CHANGE: We now look for Interfaces, not Classes + if typ.TypeKind <> tkInterface then Continue; - // Check for [AstTag] attribute on the class + // Check for [AstTag] attribute on the interface tag := ''; for attr in typ.GetAttributes do if attr is AstTagAttribute then @@ -102,10 +102,10 @@ begin fieldsList := nodeDefs[tag]; - // Scan Fields (Variables) of the class - for f in typ.AsInstance.GetFields do + // CHANGE: Scan Properties of the interface + for prop in typ.GetProperties do begin - for attr in f.GetAttributes do + for attr in prop.GetAttributes do if attr is AstFieldAttribute then begin fieldAttr := AstFieldAttribute(attr); @@ -119,7 +119,7 @@ begin end; // 2. Build the output - sb.AppendLine('// AST Schema Definition (Auto-Generated via RTTI)'); + sb.AppendLine('// AST Schema Definition (Auto-Generated via RTTI from Interfaces)'); sb.AppendLine('// Format: Compact JSON Arrays [Tag, Arg1, Arg2, ...]'); sb.AppendLine; @@ -136,13 +136,15 @@ begin sb.AppendLine(';'); sb.AppendLine; + // Special Handling for Tuple (it's recursive array structure) sb.AppendLine('type Tuple = ["Tuple", AstNode[]];'); sb.AppendLine; // Node Definitions for tag in unionTypes do begin - // Tuple is special base type + // Skip Tuple in automatic generation as we defined it manually above + // to represent the array structure correctly in TypeScript if tag = 'Tuple' then Continue; @@ -202,7 +204,7 @@ class function TAstSchema.GenerateFullSystemPrompt: string; begin // Combine everything Result := - 'You are a compiler frontend for the "Myc" scripting language.' + 'You are a compiler frontend for a scripting language.' + sLineBreak + 'Your task is to generate a valid Abstract Syntax Tree (AST) in a specific Compact JSON format.' + sLineBreak diff --git a/Src/AST/Myc.Ast.Nodes.pas b/Src/AST/Myc.Ast.Nodes.pas index d476668..74da128 100644 --- a/Src/AST/Myc.Ast.Nodes.pas +++ b/Src/AST/Myc.Ast.Nodes.pas @@ -1,6 +1,3 @@ -//================================================================================================== -//== FULL UNIT START: Myc.Ast.Nodes (from Myc.Ast.Nodes.pas) -//================================================================================================== unit Myc.Ast.Nodes; interface @@ -14,7 +11,7 @@ uses Myc.Ast.Scope, Myc.Ast.Types, Myc.Ast.Identities, - Myc.Ast.Attributes; // Hinzugefügt für [AstTag] und [AstField] + Myc.Ast.Attributes; type // --- Forward Declarations --- @@ -81,16 +78,12 @@ type IAstVisitor = interface; IAstTypedNode = interface; - // Core Nodes + // Forward Declarations of specific nodes IConstantNode = interface; IIdentifierNode = interface; IKeywordNode = interface; - - // Structure ITupleNode = interface; IRecordFieldNode = interface; - - // Control Flow & Structure IIfExpressionNode = interface; ICondExpressionNode = interface; ILambdaExpressionNode = interface; @@ -111,8 +104,6 @@ type ISeriesLengthNode = interface; IRecurNode = interface; INopNode = interface; - - // Pipes IPipeNode = interface; // Node Kinds & Helpers @@ -121,8 +112,8 @@ type akIdentifier, akKeyword, // Containers - akTuple, // The universal list (replaces ArgList, ParamList, ExprList, FieldList) - akRecordField, // Single key-value pair + akTuple, + akRecordField, // Control Flow akIfExpression, akCondExpression, @@ -153,7 +144,6 @@ type function ToString: string; end; - // Represents a single branch in a Cond expression (Condition -> Branch) TCondPair = record Condition: IAstNode; Branch: IAstNode; @@ -215,18 +205,21 @@ type property StaticType: IStaticType read GetStaticType; end; + [AstTag('Field')] IRecordFieldNode = interface(IAstNode) {$region 'private'} function GetKey: IKeywordNode; function GetValue: IAstNode; {$endregion} + [AstField(0, 'key', fkNode)] property Key: IKeywordNode read GetKey; + + [AstField(1, 'value', fkNode)] property Value: IAstNode read GetValue; end; // --- Node Interfaces (Definitions) --- - // Function Definition (Lambda) IFunctionDefinition = interface(IAstTypedNode) {$region 'private'} function GetBody: IAstNode; @@ -238,59 +231,80 @@ type property IsPure: Boolean read GetIsPure; end; + [AstTag('Nop')] INopNode = interface(IAstTypedNode) end; + [AstTag('Const')] IConstantNode = interface(IAstTypedNode) {$region 'private'} function GetValue: TDataValue; {$endregion} + [AstField(0, 'value', fkValue)] property Value: TDataValue read GetValue; end; + [AstTag('Id')] IIdentifierNode = interface(IAstTypedNode) {$region 'private'} function GetAddress: TResolvedAddress; function GetName: string; {$endregion} property Address: TResolvedAddress read GetAddress; + + [AstField(0, 'name', fkString)] property Name: string read GetName; end; + [AstTag('Key')] IKeywordNode = interface(IAstTypedNode) {$region 'private'} function GetValue: IKeyword; {$endregion} + [AstField(0, 'name', fkString)] property Value: IKeyword read GetValue; end; + [AstTag('Tuple')] ITupleNode = interface(IAstTypedNode) {$region 'private'} function GetElements: TArray; {$endregion} + [AstField(0, 'elements', fkNode)] property Elements: TArray read GetElements; end; + [AstTag('If')] IIfExpressionNode = interface(IAstTypedNode) {$region 'private'} function GetCondition: IAstNode; function GetThenBranch: IAstNode; function GetElseBranch: IAstNode; {$endregion} + [AstField(0, 'cond', fkNode)] property Condition: IAstNode read GetCondition; + + [AstField(1, 'then', fkNode)] property ThenBranch: IAstNode read GetThenBranch; + + [AstField(2, 'else', fkNullableNode)] property ElseBranch: IAstNode read GetElseBranch; end; + [AstTag('Cond')] ICondExpressionNode = interface(IAstTypedNode) {$region 'private'} function GetPairs: TArray; function GetElseBranch: IAstNode; {$endregion} + [AstField(0, 'pairs', fkArrayOfPairs)] property Pairs: TArray read GetPairs; + + [AstField(1, 'else', fkNullableNode)] property ElseBranch: IAstNode read GetElseBranch; end; + [AstTag('Fn')] ILambdaExpressionNode = interface(IFunctionDefinition) {$region 'private'} function GetLayout: IScopeLayout; @@ -302,8 +316,16 @@ type property Descriptor: IScopeDescriptor read GetDescriptor; property Upvalues: TArray read GetUpvalues; property HasNestedLambdas: Boolean read GetHasNestedLambdas; + + // Annotated properties from base interface (for schema generation) + [AstField(0, 'params', fkTuple)] + property Parameters: ITupleNode read GetParameters; + + [AstField(1, 'body', fkNode)] + property Body: IAstNode read GetBody; end; + [AstTag('Call')] IFunctionCallNode = interface(IAstTypedNode) {$region 'private'} function GetCallee: IAstNode; @@ -312,8 +334,12 @@ type function GetStaticTarget: TDataValue.TFunc; function GetIsTargetPure: Boolean; {$endregion} + [AstField(0, 'callee', fkNode)] property Callee: IAstNode read GetCallee; + + [AstField(1, 'args', fkTuple)] property Arguments: ITupleNode read GetArguments; + property IsTailCall: Boolean read GetIsTailCall; property StaticTarget: TDataValue.TFunc read GetStaticTarget; property IsTargetPure: Boolean read GetIsTargetPure; @@ -328,135 +354,186 @@ type property ExpandedBody: IAstNode read GetExpandedBody; end; + [AstTag('Recur')] IRecurNode = interface(IAstTypedNode) {$region 'private'} function GetArguments: ITupleNode; {$endregion} + [AstField(0, 'args', fkTuple)] property Arguments: ITupleNode read GetArguments; end; + [AstTag('Block')] IBlockExpressionNode = interface(IAstTypedNode) {$region 'private'} function GetExpressions: ITupleNode; {$endregion} + [AstField(0, 'expressions', fkTuple)] property Expressions: ITupleNode read GetExpressions; end; + [AstTag('Var')] IVariableDeclarationNode = interface(IAstTypedNode) {$region 'private'} function GetTarget: IAstNode; function GetInitializer: IAstNode; function GetIsBoxed: Boolean; {$endregion} + [AstField(0, 'target', fkNode)] property Target: IAstNode read GetTarget; + + [AstField(1, 'init', fkNullableNode)] property Initializer: IAstNode read GetInitializer; + property IsBoxed: Boolean read GetIsBoxed; end; + [AstTag('Assign')] IAssignmentNode = interface(IAstTypedNode) {$region 'private'} function GetTarget: IAstNode; function GetValue: IAstNode; {$endregion} + [AstField(0, 'target', fkNode)] property Target: IAstNode read GetTarget; + + [AstField(1, 'value', fkNode)] property Value: IAstNode read GetValue; end; + [AstTag('Macro')] IMacroDefinitionNode = interface(IAstTypedNode) {$region 'private'} function GetName: IIdentifierNode; function GetParameters: ITupleNode; function GetBody: IAstNode; {$endregion} + [AstField(0, 'name', fkNode)] property Name: IIdentifierNode read GetName; + + [AstField(1, 'params', fkTuple)] property Parameters: ITupleNode read GetParameters; + + [AstField(2, 'body', fkNode)] property Body: IAstNode read GetBody; end; + [AstTag('Quote')] IQuasiquoteNode = interface(IAstNode) {$region 'private'} function GetExpression: IAstNode; {$endregion} + [AstField(0, 'expr', fkNode)] property Expression: IAstNode read GetExpression; end; + [AstTag('Unquote')] IUnquoteNode = interface(IAstNode) {$region 'private'} function GetExpression: IAstNode; {$endregion} + [AstField(0, 'expr', fkNode)] property Expression: IAstNode read GetExpression; end; + [AstTag('Splice')] IUnquoteSplicingNode = interface(IAstNode) {$region 'private'} function GetExpression: IQuasiquoteNode; {$endregion} + [AstField(0, 'expr', fkNode)] property Expression: IQuasiquoteNode read GetExpression; end; + [AstTag('Index')] IIndexerNode = interface(IAstTypedNode) {$region 'private'} function GetBase: IAstNode; function GetIndex: IAstNode; {$endregion} + [AstField(0, 'base', fkNode)] property Base: IAstNode read GetBase; + + [AstField(1, 'index', fkNode)] property Index: IAstNode read GetIndex; end; + [AstTag('Member')] IMemberAccessNode = interface(IAstTypedNode) {$region 'private'} function GetBase: IAstNode; function GetMember: IKeywordNode; {$endregion} + [AstField(0, 'base', fkNode)] property Base: IAstNode read GetBase; + + [AstField(1, 'member', fkNode)] property Member: IKeywordNode read GetMember; end; + [AstTag('Record')] IRecordLiteralNode = interface(IAstTypedNode) {$region 'private'} function GetFields: ITupleNode; function GetGenericDefinition: IGenericRecordDefinition; function GetScalarDefinition: IScalarRecordDefinition; {$endregion} + [AstField(0, 'fields', fkTuple)] property Fields: ITupleNode read GetFields; + property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition; property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition; end; + [AstTag('Series')] ICreateSeriesNode = interface(IAstTypedNode) {$region 'private'} function GetDefinitionNode: IAstNode; function GetRecordDefinition: IScalarRecordDefinition; {$endregion} + [AstField(0, 'definition', fkNode)] property DefinitionNode: IAstNode read GetDefinitionNode; + property RecordDefinition: IScalarRecordDefinition read GetRecordDefinition; end; + [AstTag('Add')] IAddSeriesItemNode = interface(IAstTypedNode) {$region 'private'} function GetSeries: IIdentifierNode; function GetValue: IAstNode; function GetLookback: IAstNode; {$endregion} + [AstField(0, 'series', fkNode)] property Series: IIdentifierNode read GetSeries; + + [AstField(1, 'value', fkNode)] property Value: IAstNode read GetValue; + + [AstField(2, 'lookback', fkNullableNode)] property Lookback: IAstNode read GetLookback; end; + [AstTag('Count')] ISeriesLengthNode = interface(IAstTypedNode) {$region 'private'} function GetSeries: IIdentifierNode; {$endregion} + [AstField(0, 'series', fkNode)] property Series: IIdentifierNode read GetSeries; end; // The main pipe definition: (pipe [[source [:sel]]...] (fn ...)) + [AstTag('Pipe')] IPipeNode = interface(IAstTypedNode) {$region 'private'} function GetInputs: ITupleNode; function GetTransformation: ILambdaExpressionNode; {$endregion} + [AstField(0, 'inputs', fkTuple)] property Inputs: ITupleNode read GetInputs; + + [AstField(1, 'transform', fkNode)] property Transformation: ILambdaExpressionNode read GetTransformation; end; @@ -531,12 +608,9 @@ type property StaticType: IStaticType read GetStaticType; end; - [AstTag('Field')] TRecordFieldNode = class(TAstNode, IRecordFieldNode) private - [AstField(0, 'key', fkNode)] FKey: IKeywordNode; - [AstField(1, 'value', fkNode)] FValue: IAstNode; function GetKey: IKeywordNode; function GetValue: IAstNode; @@ -549,10 +623,8 @@ type // --- Core Nodes Implementations --- - [AstTag('Const')] TConstantNode = class(TAstTypedNode, IConstantNode) private - [AstField(0, 'value', fkValue)] FConstIdentity: IConstantIdentity; // Typed reference for fast access function GetValue: TDataValue; protected @@ -562,10 +634,8 @@ type function AsConstant: IConstantNode; override; end; - [AstTag('Id')] TIdentifierNode = class(TAstTypedNode, IIdentifierNode) private - [AstField(0, 'name', fkString)] FNamedIdentity: INamedIdentity; // Typed reference for fast access FAddress: TResolvedAddress; function GetAddress: TResolvedAddress; @@ -577,10 +647,8 @@ type function AsIdentifier: IIdentifierNode; override; end; - [AstTag('Key')] TKeywordNode = class(TAstTypedNode, IKeywordNode) private - [AstField(0, 'name', fkString)] FKeywordIdentity: IKeywordIdentity; function GetValue: IKeyword; protected @@ -590,10 +658,8 @@ type function AsKeyword: IKeywordNode; override; end; - [AstTag('Tuple')] TTupleNode = class(TAstTypedNode, ITupleNode) private - [AstField(0, 'elements', fkNode)] // Represents array FElements: TArray; function GetElements: TArray; protected @@ -603,10 +669,8 @@ type function AsTuple: ITupleNode; override; end; - [AstTag('Series')] TCreateSeriesNode = class(TAstTypedNode, ICreateSeriesNode) private - [AstField(0, 'definition', fkNode)] FDefinitionNode: IAstNode; FRecordDefinition: IScalarRecordDefinition; function GetDefinitionNode: IAstNode; @@ -623,17 +687,9 @@ type function AsCreateSeries: ICreateSeriesNode; override; end; - // --- Structural Nodes (Identity only for location) --- - - [AstTag('If')] TIfExpressionNode = class(TAstTypedNode, IIfExpressionNode) private - [AstField(0, 'cond', fkNode)] - FCondition: IAstNode; - [AstField(1, 'then', fkNode)] - FThenBranch: IAstNode; - [AstField(2, 'else', fkNullableNode)] - FElseBranch: IAstNode; + FCondition, FThenBranch, FElseBranch: IAstNode; function GetCondition: IAstNode; function GetThenBranch: IAstNode; function GetElseBranch: IAstNode; @@ -648,12 +704,9 @@ type function AsIfExpression: IIfExpressionNode; override; end; - [AstTag('Cond')] TCondExpressionNode = class(TAstTypedNode, ICondExpressionNode) private - [AstField(0, 'pairs', fkArrayOfPairs)] FPairs: TArray; - [AstField(1, 'else', fkNullableNode)] FElseBranch: IAstNode; function GetPairs: TArray; function GetElseBranch: IAstNode; @@ -669,12 +722,9 @@ type function AsCondExpression: ICondExpressionNode; override; end; - [AstTag('Fn')] TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition) private - [AstField(0, 'params', fkTuple)] FParameters: ITupleNode; - [AstField(1, 'body', fkNode)] FBody: IAstNode; FLayout: IScopeLayout; FDescriptor: IScopeDescriptor; @@ -703,12 +753,9 @@ type function AsLambdaExpression: ILambdaExpressionNode; override; end; - [AstTag('Call')] TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode) private - [AstField(0, 'callee', fkNode)] FCallee: IAstNode; - [AstField(1, 'args', fkTuple)] FArguments: ITupleNode; FIsTailCall: Boolean; FStaticTarget: TDataValue.TFunc; @@ -733,14 +780,10 @@ type function AsFunctionCall: IFunctionCallNode; override; end; - [AstTag('Macro')] TMacroDefinitionNode = class(TAstTypedNode, IMacroDefinitionNode) private - [AstField(0, 'name', fkNode)] FName: IIdentifierNode; - [AstField(1, 'params', fkTuple)] FParameters: ITupleNode; - [AstField(2, 'body', fkNode)] FBody: IAstNode; function GetName: IIdentifierNode; function GetParameters: ITupleNode; @@ -770,10 +813,8 @@ type function AsMacroExpansion: IMacroExpansionNode; override; end; - [AstTag('Quote')] TQuasiquoteNode = class(TAstNode, IQuasiquoteNode) private - [AstField(0, 'expr', fkNode)] FExpression: IAstNode; function GetExpression: IAstNode; protected @@ -783,10 +824,8 @@ type function AsQuasiquote: IQuasiquoteNode; override; end; - [AstTag('Unquote')] TUnquoteNode = class(TAstNode, IUnquoteNode) private - [AstField(0, 'expr', fkNode)] FExpression: IAstNode; function GetExpression: IAstNode; protected @@ -796,10 +835,8 @@ type function AsUnquote: IUnquoteNode; override; end; - [AstTag('Splice')] TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode) private - [AstField(0, 'expr', fkNode)] FExpression: IQuasiquoteNode; function GetExpression: IQuasiquoteNode; protected @@ -809,10 +846,8 @@ type function AsUnquoteSplicing: IUnquoteSplicingNode; override; end; - [AstTag('Recur')] TRecurNode = class(TAstTypedNode, IRecurNode) private - [AstField(0, 'args', fkTuple)] FArguments: ITupleNode; function GetArguments: ITupleNode; protected @@ -822,10 +857,8 @@ type function AsRecur: IRecurNode; override; end; - [AstTag('Block')] TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode) private - [AstField(0, 'expressions', fkTuple)] FExpressions: ITupleNode; function GetExpressions: ITupleNode; protected @@ -835,13 +868,9 @@ type function AsBlockExpression: IBlockExpressionNode; override; end; - [AstTag('Var')] TVariableDeclarationNode = class(TAstTypedNode, IVariableDeclarationNode) private - [AstField(0, 'target', fkNode)] - FTarget: IAstNode; - [AstField(1, 'init', fkNullableNode)] - FInitializer: IAstNode; + FTarget, FInitializer: IAstNode; FIsBoxed: Boolean; function GetTarget: IAstNode; function GetInitializer: IAstNode; @@ -859,13 +888,9 @@ type function AsVariableDeclaration: IVariableDeclarationNode; override; end; - [AstTag('Assign')] TAssignmentNode = class(TAstTypedNode, IAssignmentNode) private - [AstField(0, 'target', fkNode)] - FTarget: IAstNode; - [AstField(1, 'value', fkNode)] - FValue: IAstNode; + FTarget, FValue: IAstNode; function GetTarget: IAstNode; function GetValue: IAstNode; protected @@ -875,13 +900,9 @@ type function AsAssignment: IAssignmentNode; override; end; - [AstTag('Index')] TIndexerNode = class(TAstTypedNode, IIndexerNode) private - [AstField(0, 'base', fkNode)] - FBase: IAstNode; - [AstField(1, 'index', fkNode)] - FIndex: IAstNode; + FBase, FIndex: IAstNode; function GetBase: IAstNode; function GetIndex: IAstNode; protected @@ -891,12 +912,9 @@ type function AsIndexer: IIndexerNode; override; end; - [AstTag('Member')] TMemberAccessNode = class(TAstTypedNode, IMemberAccessNode) private - [AstField(0, 'base', fkNode)] FBase: IAstNode; - [AstField(1, 'member', fkNode)] FMember: IKeywordNode; function GetBase: IAstNode; function GetMember: IKeywordNode; @@ -912,10 +930,8 @@ type function AsMemberAccess: IMemberAccessNode; override; end; - [AstTag('Record')] TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode) private - [AstField(0, 'fields', fkTuple)] FFields: ITupleNode; FScalarDef: IScalarRecordDefinition; FGenericDef: IGenericRecordDefinition; @@ -935,15 +951,10 @@ type function AsRecordLiteral: IRecordLiteralNode; override; end; - [AstTag('Add')] TAddSeriesItemNode = class(TAstTypedNode, IAddSeriesItemNode) private - [AstField(0, 'series', fkNode)] FSeries: IIdentifierNode; - [AstField(1, 'value', fkNode)] - FValue: IAstNode; - [AstField(2, 'lookback', fkNullableNode)] - FLookback: IAstNode; + FValue, FLookback: IAstNode; function GetSeries: IIdentifierNode; function GetValue: IAstNode; function GetLookback: IAstNode; @@ -959,10 +970,8 @@ type function AsAddSeriesItem: IAddSeriesItemNode; override; end; - [AstTag('Count')] TSeriesLengthNode = class(TAstTypedNode, ISeriesLengthNode) private - [AstField(0, 'series', fkNode)] FSeries: IIdentifierNode; function GetSeries: IIdentifierNode; protected @@ -972,7 +981,6 @@ type function AsSeriesLength: ISeriesLengthNode; override; end; - [AstTag('Nop')] TNopNode = class(TAstTypedNode, INopNode) protected function GetKind: TAstNodeKind; override; @@ -981,12 +989,9 @@ type function AsNop: INopNode; override; end; - [AstTag('Pipe')] TPipeNode = class(TAstTypedNode, IPipeNode) private - [AstField(0, 'inputs', fkTuple)] FInputs: ITupleNode; - [AstField(1, 'transform', fkNode)] FTransformation: ILambdaExpressionNode; function GetInputs: ITupleNode; function GetTransformation: ILambdaExpressionNode; @@ -1006,9 +1011,9 @@ implementation uses System.Classes, - System.TypInfo, System.Rtti, - System.StrUtils; + System.StrUtils, + System.TypInfo; // Added for GetEnumName { TCompiledFunction } @@ -2129,6 +2134,3 @@ begin end; end. - //================================================================================================== -//== FULL UNIT END: Myc.Ast.Nodes -//================================================================================================== diff --git a/Src/AST/Myc.Fmx.AstEditor.pas b/Src/AST/Myc.Fmx.AstEditor.pas index 8439579..a6dbb3f 100644 --- a/Src/AST/Myc.Fmx.AstEditor.pas +++ b/Src/AST/Myc.Fmx.AstEditor.pas @@ -193,6 +193,8 @@ begin FWorkspace.SetFocus; var WorldP := FWorkspace.ScreenToWorld(FWorkspace.LocalToScreen(TPointF.Create(X, Y))); + if not Assigned(FWorkspace.RootNode) then + exit; var Hit := FWorkspace.RootNode.HitTest(WorldP); if (Button = TMouseButton.mbLeft) and (Hit is TAstViewNode) then