Refactor Compiler Pipeline: Decouple Scope Layout from Runtime Descriptor
- **Architecture:** Split `IScopeDescriptor` into `IScopeLayout` (Binder/Structure) and immutable `IScopeDescriptor` (Runtime/Types). - **Binder:** Now produces `IScopeLayout` via `IScopeBuilder`. Restored Upvalue tracking and Lambda nesting detection. - **TypeChecker:** Introduced `TTypeContext` to track types during traversal. Now produces the final `IScopeDescriptor`. - **Evaluator:** Adapted to new `ILambdaExpressionNode` structure. - **Fixes:** Resolved `Scope depth mismatch` in TypeChecker and `AccessViolation` in Evaluator due to lost parent scopes.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -5,11 +5,9 @@ uses
|
||||
System.StartUpCopy,
|
||||
FMX.Forms,
|
||||
MainForm in 'MainForm.pas' {Form1},
|
||||
Myc.Ast.Evaluator in '..\Src\AST\Myc.Ast.Evaluator.pas',
|
||||
Myc.Ast.Nodes in '..\Src\AST\Myc.Ast.Nodes.pas',
|
||||
Myc.Ast.Scope in '..\Src\AST\Myc.Ast.Scope.pas',
|
||||
Myc.Data.Value in 'Myc.Data.Value.pas',
|
||||
Myc.Ast.Debugger in '..\Src\AST\Myc.Ast.Debugger.pas',
|
||||
Myc.Ast.Visitor in '..\Src\AST\Myc.Ast.Visitor.pas',
|
||||
Myc.Ast.RTL in '..\Src\AST\Myc.Ast.RTL.pas',
|
||||
Myc.Ast.Dumper in '..\Src\AST\Myc.Ast.Dumper.pas',
|
||||
@@ -26,8 +24,9 @@ uses
|
||||
Myc.Ast.Compiler.Lowering in '..\Src\AST\Myc.Ast.Compiler.Lowering.pas',
|
||||
Myc.Ast.Compiler.TypeChecker in '..\Src\AST\Myc.Ast.Compiler.TypeChecker.pas',
|
||||
Myc.Ast.Compiler.Macros in '..\Src\AST\Myc.Ast.Compiler.Macros.pas',
|
||||
Myc.Ast.Compiler.Specializer in '..\Src\AST\Myc.Ast.Compiler.Specializer.pas',
|
||||
Myc.Ast.Environment in '..\Src\AST\Myc.Ast.Environment.pas',
|
||||
Myc.Ast.Compiler.Specializer in '..\Src\AST\Myc.Ast.Compiler.Specializer.pas';
|
||||
Myc.Ast.Debugger in '..\Src\AST\Myc.Ast.Debugger.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
||||
@@ -135,11 +135,9 @@
|
||||
<DCCReference Include="MainForm.pas">
|
||||
<Form>Form1</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Evaluator.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Nodes.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Scope.pas"/>
|
||||
<DCCReference Include="Myc.Data.Value.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Debugger.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Visitor.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.RTL.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Dumper.pas"/>
|
||||
@@ -156,8 +154,9 @@
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Compiler.Lowering.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Compiler.TypeChecker.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Compiler.Macros.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Environment.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Compiler.Specializer.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Environment.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Debugger.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
@@ -213,12 +212,6 @@
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="Win64\Debug\ASTPlayground.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<Platform Name="Win64">
|
||||
<RemoteName>ASTPlayground.rsm</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="Win64\Release\ASTPlayground.exe" Configuration="Release" Class="ProjectOutput">
|
||||
<Platform Name="Win64">
|
||||
<RemoteName>ASTPlayground.exe</RemoteName>
|
||||
|
||||
+43
-24
@@ -115,6 +115,7 @@ type
|
||||
FWorkspace: TAuraWorkspace;
|
||||
FScriptUpdate: Boolean;
|
||||
FTriggerTest: TAstEnvironment;
|
||||
|
||||
procedure WorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||||
|
||||
// Helper function to encapsulate the Compile -> Evaluate pattern
|
||||
@@ -152,7 +153,15 @@ procedure TForm1.InnerLambdaButtonClick(Sender: TObject);
|
||||
var
|
||||
mainBlock: IAstNode;
|
||||
resultValue: TDataValue;
|
||||
resInt: Int64;
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- Nested Lambda & Upvalue Mutation Test ---');
|
||||
Memo1.Lines.Add('Scenario: outer() -> defines x=10');
|
||||
Memo1.Lines.Add(' inner() -> calls innermost()');
|
||||
Memo1.Lines.Add(' innermost() -> captures x, adds 5');
|
||||
Memo1.Lines.Add('Expected Result: 15');
|
||||
|
||||
mainBlock :=
|
||||
TAst.Block(
|
||||
[
|
||||
@@ -200,6 +209,19 @@ begin
|
||||
|
||||
resultValue := ExecuteAst(mainBlock);
|
||||
|
||||
if (resultValue.Kind = vkScalar) and (resultValue.AsScalar.Kind = TScalar.TKind.Ordinal) then
|
||||
begin
|
||||
resInt := resultValue.AsScalar.Value.AsInt64;
|
||||
Memo1.Lines.Add(Format('Actual Result: %d', [resInt]));
|
||||
|
||||
if resInt = 15 then
|
||||
Memo1.Lines.Add('SUCCESS: Deeply nested closure modified captured variable correctly.')
|
||||
else
|
||||
Memo1.Lines.Add(Format('FAILURE: Upvalue logic broken. Expected 15, got %d.', [resInt]));
|
||||
end
|
||||
else
|
||||
Memo1.Lines.Add('FAILURE: Result is not an integer scalar.');
|
||||
|
||||
Assert(TScalar.FromInt64(15) = resultValue.AsScalar, 'The final result should be 15, but is ' + resultValue.AsScalar.ToString);
|
||||
UpdateScript;
|
||||
end;
|
||||
@@ -220,11 +242,13 @@ begin
|
||||
|
||||
if CompilerStageBox.ItemIndex > 1 then
|
||||
begin
|
||||
var desc: IScopeDescriptor;
|
||||
Result := FEnvironment.Environment.Bind(Result, desc);
|
||||
var layout: IScopeLayout;
|
||||
// Bind now returns the bound AST and provides the layout
|
||||
Result := FEnvironment.Environment.Bind(Result, layout);
|
||||
|
||||
if CompilerStageBox.ItemIndex > 2 then
|
||||
Result := FEnvironment.Environment.Specialize(Result, desc);
|
||||
// Specialize no longer needs descriptor
|
||||
Result := FEnvironment.Environment.Specialize(Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@@ -247,6 +271,7 @@ begin
|
||||
FEnvironment.SetStandardMode;
|
||||
|
||||
try
|
||||
// Wrap in Lambda to compile
|
||||
var funcDef := TAst.LambdaExpr([], ANode);
|
||||
FCurrExec := FEnvironment.Compile(funcDef).Func;
|
||||
Result := FCurrExec([]);
|
||||
@@ -381,11 +406,11 @@ begin
|
||||
'''
|
||||
(defmacro stopwatch [body]
|
||||
`(do
|
||||
(def start-time (timestamp))
|
||||
(def result ~body)
|
||||
(print "(calculated in " (- (timestamp) start-time) " ms)" )
|
||||
result
|
||||
))
|
||||
(def start-time (timestamp))
|
||||
(def result ~body)
|
||||
(print "(calculated in " (- (timestamp) start-time) " ms)" )
|
||||
result
|
||||
))
|
||||
''')
|
||||
.AsMacroDefinition
|
||||
);
|
||||
@@ -402,6 +427,7 @@ var
|
||||
funcAst: IAstNode;
|
||||
funcValue: TDataValue;
|
||||
converter: IJsonAstConverter;
|
||||
addr: TResolvedAddress; // Variable für das Ergebnis von Resolve
|
||||
begin
|
||||
// Load definitions from JSON and populate the global scope.
|
||||
if not TFile.Exists(UserLibName) then
|
||||
@@ -419,7 +445,7 @@ begin
|
||||
|
||||
try
|
||||
Memo1.Lines.Add(Format('--- Loading User Library from %s ---', [ExtractFileName(UserLibName)]));
|
||||
var scopeDescr := FEnvironment.RootScope.Descriptor;
|
||||
|
||||
// Populate the list view with loaded functions and macros.
|
||||
RTLListView.Items.BeginUpdate;
|
||||
try
|
||||
@@ -431,8 +457,10 @@ begin
|
||||
// First, deserialize the AST node from JSON.
|
||||
funcAst := converter.Deserialize(pair.JsonValue as TJSONObject);
|
||||
|
||||
var sym := scopeDescr.FindSymbol(pair.JsonString.Value);
|
||||
if sym.Address.Kind = akUnresolved then
|
||||
// KORREKTUR: Statt Descriptor.FindSymbol nutzen wir Scope.Resolve
|
||||
addr := FEnvironment.RootScope.Resolve(pair.JsonString.Value);
|
||||
|
||||
if addr.Kind = akUnresolved then
|
||||
begin
|
||||
// Distinguish between loading a macro and loading a function.
|
||||
if funcAst.Kind = akMacroDefinition then
|
||||
@@ -451,6 +479,7 @@ begin
|
||||
end
|
||||
else
|
||||
Memo1.Lines.Add(Format('Symbol "%s" already defined', [pair.JsonString.Value]));
|
||||
|
||||
// Add the new function/macro to the RTL list view.
|
||||
RTLListView.Items.Add.Text := pair.JsonString.Value;
|
||||
end;
|
||||
@@ -615,7 +644,7 @@ begin
|
||||
try
|
||||
FCurrUnboundAst := converter.Deserialize(jsonObj);
|
||||
|
||||
// Run the full pipeline
|
||||
// Run the full pipeline via environment
|
||||
FCurrExec := FEnvironment.Compile(FCurrUnboundAst).Func;
|
||||
|
||||
Memo1.Lines.Add('AST deserialized and bound successfully from JSON.');
|
||||
@@ -674,13 +703,13 @@ begin
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- AST Dump ---');
|
||||
|
||||
if not Assigned(FCurrExec) then // Check FCurrExec
|
||||
if not Assigned(FCurrExec) then
|
||||
begin
|
||||
Memo1.Lines.Add('No *compiled* AST has been generated yet. Click a test button first.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Dump the compiled AST from the executable
|
||||
// Dump the compiled AST from the visualizer helper
|
||||
TAstDumper.Dump(CompileAstStage, Memo1.Lines);
|
||||
end;
|
||||
|
||||
@@ -688,7 +717,6 @@ procedure TForm1.FibonacciButtonClick(Sender: TObject);
|
||||
var
|
||||
result: TDataValue;
|
||||
sw: TStopwatch;
|
||||
fibDataValue: TDataValue;
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
|
||||
@@ -1319,15 +1347,6 @@ begin
|
||||
exit;
|
||||
|
||||
FWorkspace.Build(CompileAstStage, TPointF.Create(X, Y));
|
||||
//
|
||||
// if FCurrExec <> nil then
|
||||
// begin
|
||||
// FWorkspace.Build(FCurrExec.CompiledAst, TPointF.Create(X, Y));
|
||||
// end
|
||||
// else if FCurrUnboundAst <> nil then
|
||||
// begin
|
||||
// FWorkspace.Build(FCurrUnboundAst, TPointF.Create(X, Y));
|
||||
// end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user