RECUR keyword added
This commit is contained in:
@@ -12,14 +12,14 @@ uses
|
||||
Myc.Ast.ViewModel in '..\Src\AST\Myc.Ast.ViewModel.pas',
|
||||
Myc.Data.Value in 'Myc.Data.Value.pas',
|
||||
Myc.Ast.Debugger in '..\Src\AST\Myc.Ast.Debugger.pas',
|
||||
Myc.Fmx.AstEditor.Node in 'Myc.Fmx.AstEditor.Node.pas',
|
||||
Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas',
|
||||
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
|
||||
Myc.Ast.Traverser in '..\Src\AST\Myc.Ast.Traverser.pas',
|
||||
Myc.Ast.Binding in '..\Src\AST\Myc.Ast.Binding.pas',
|
||||
Myc.Ast.RTL in '..\Src\AST\Myc.Ast.RTL.pas',
|
||||
Myc.Ast.Dumper in '..\Src\AST\Myc.Ast.Dumper.pas',
|
||||
Myc.Ast.RTL.Core in '..\Src\AST\Myc.Ast.RTL.Core.pas',
|
||||
Myc.Fmx.AstEditor.Node in 'Myc.Fmx.AstEditor.Node.pas',
|
||||
Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas',
|
||||
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
|
||||
Myc.Utils in '..\Src\Myc.Utils.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
@@ -143,14 +143,14 @@
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.ViewModel.pas"/>
|
||||
<DCCReference Include="Myc.Data.Value.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Debugger.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Node.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Workspace.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Traverser.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Binding.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.RTL.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Dumper.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.RTL.Core.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Node.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Workspace.pas"/>
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/>
|
||||
<DCCReference Include="..\Src\Myc.Utils.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
|
||||
+59
-90
@@ -21,9 +21,6 @@ uses
|
||||
FMX.ScrollBox,
|
||||
FMX.Memo,
|
||||
FMX.Controls.Presentation,
|
||||
Myc.Fmx.AstEditor,
|
||||
Myc.Fmx.AstEditor.Node,
|
||||
Myc.Fmx.AstEditor.Workspace,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast.Nodes,
|
||||
@@ -36,7 +33,10 @@ uses
|
||||
Myc.Ast.RTL,
|
||||
FMX.Layouts,
|
||||
FMX.Objects,
|
||||
Myc.Ast.Debugger;
|
||||
Myc.Ast.Debugger,
|
||||
Myc.Fmx.AstEditor,
|
||||
Myc.Fmx.AstEditor.Node,
|
||||
Myc.Fmx.AstEditor.Workspace;
|
||||
|
||||
type
|
||||
// A test record
|
||||
@@ -281,31 +281,42 @@ var
|
||||
sw: TStopwatch;
|
||||
begin
|
||||
// Create a setup script to define a memoize-compatible 'fib' function globally.
|
||||
// This is rewritten to be tail-recursive using the 'recur' keyword.
|
||||
var fibAst :=
|
||||
TAst.Block(
|
||||
[
|
||||
// 1. var fib; (Declare the name so it can be captured by the lambda. Initializer is nil)
|
||||
// 1. var fib_iter = lambda(n, a, b) { ... }; (The tail-recursive part)
|
||||
TAst.VarDecl(
|
||||
TAst.Identifier('fib_iter'),
|
||||
TAst.LambdaExpr(
|
||||
[TAst.Identifier('n'), TAst.Identifier('a'), TAst.Identifier('b')],
|
||||
TAst.TernaryExpr(
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boEqual, TAst.Constant(TScalar.FromInt64(0))),
|
||||
TAst.Identifier('a'), // Base case 1
|
||||
TAst.TernaryExpr(
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boEqual, TAst.Constant(TScalar.FromInt64(1))),
|
||||
TAst.Identifier('b'), // Base case 2
|
||||
TAst.Recur( // Tail-recursive step
|
||||
[
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1))),
|
||||
TAst.Identifier('b'),
|
||||
TAst.BinaryExpr(TAst.Identifier('a'), boAdd, TAst.Identifier('b'))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
// 2. var fib;
|
||||
TAst.VarDecl(TAst.Identifier('fib')),
|
||||
// 2. var fib_impl = lambda(n) { ... fib(n-1) + fib(n-2) ... };
|
||||
// 3. fib = lambda(n) { fib_iter(n, 0, 1) }; (The public-facing function)
|
||||
TAst.Assign(
|
||||
TAst.Identifier('fib'),
|
||||
TAst.LambdaExpr(
|
||||
[TAst.Identifier('n')],
|
||||
TAst.TernaryExpr(
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boLess, TAst.Constant(TScalar.FromInt64(2))),
|
||||
TAst.Identifier('n'),
|
||||
TAst.BinaryExpr(
|
||||
// Recursive calls now use the re-bindable name 'fib' instead of 'Self'
|
||||
TAst.FunctionCall(
|
||||
TAst.Identifier('Self'),
|
||||
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
|
||||
),
|
||||
boAdd,
|
||||
TAst.FunctionCall(
|
||||
TAst.Identifier('Self'),
|
||||
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(2)))]
|
||||
)
|
||||
)
|
||||
TAst.FunctionCall(
|
||||
TAst.Identifier('fib_iter'),
|
||||
[TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(0)), TAst.Constant(TScalar.FromInt64(1))]
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -314,10 +325,10 @@ begin
|
||||
|
||||
var fibScope := TAstBinder.Bind(fibAst, FGScope).CreateScope(FGScope);
|
||||
var visitor := CreateVisitor(fibScope);
|
||||
Result := visitor.Execute(fibAst);
|
||||
visitor.Execute(fibAst);
|
||||
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- Recursive fib with AST---');
|
||||
Memo1.Lines.Add('--- Tail-Recursive fib with AST---');
|
||||
sw := TStopwatch.StartNew;
|
||||
|
||||
root := TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(30))]);
|
||||
@@ -330,7 +341,7 @@ begin
|
||||
Memo1.Lines.Add(Format('Result: fib(30) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
||||
|
||||
Memo1.Lines.Add('');
|
||||
Memo1.Lines.Add('--- Memoized recursive fib with AST (using global fib)---');
|
||||
Memo1.Lines.Add('--- Memoized tail-recursive fib with AST (using global fib)---');
|
||||
sw := TStopwatch.StartNew;
|
||||
|
||||
root :=
|
||||
@@ -375,30 +386,39 @@ var
|
||||
sw: TStopwatch;
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- Recursive factorial(20) ---');
|
||||
Memo1.Lines.Add('--- Tail-Recursive factorial(20) ---');
|
||||
sw := TStopwatch.StartNew;
|
||||
|
||||
// Rewritten to be tail-recursive to use 'recur'
|
||||
root :=
|
||||
TAst.Block(
|
||||
[
|
||||
// Define the tail-recursive helper function
|
||||
TAst.VarDecl(
|
||||
TAst.Identifier('factorial'),
|
||||
TAst.Identifier('fact_iter'),
|
||||
TAst.LambdaExpr(
|
||||
[TAst.Identifier('n')],
|
||||
[TAst.Identifier('n'), TAst.Identifier('acc')],
|
||||
TAst.TernaryExpr(
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boLess, TAst.Constant(TScalar.FromInt64(2))),
|
||||
TAst.Constant(TScalar.FromInt64(1)),
|
||||
TAst.BinaryExpr(
|
||||
TAst.Identifier('n'),
|
||||
boMultiply,
|
||||
TAst.FunctionCall(
|
||||
TAst.Identifier('Self'),
|
||||
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
|
||||
)
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boLessOrEqual, TAst.Constant(TScalar.FromInt64(1))),
|
||||
TAst.Identifier('acc'), // Base case: return the accumulator
|
||||
TAst.Recur( // Tail-recursive step
|
||||
[
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1))),
|
||||
TAst.BinaryExpr(TAst.Identifier('acc'), boMultiply, TAst.Identifier('n'))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
// Define the public-facing factorial function
|
||||
TAst.VarDecl(
|
||||
TAst.Identifier('factorial'),
|
||||
TAst.LambdaExpr(
|
||||
[TAst.Identifier('n')],
|
||||
TAst.FunctionCall(TAst.Identifier('fact_iter'), [TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(1))])
|
||||
)
|
||||
),
|
||||
// Call the main function
|
||||
TAst.FunctionCall(TAst.Identifier('factorial'), [TAst.Constant(TScalar.FromInt64(20))])
|
||||
]
|
||||
);
|
||||
@@ -566,54 +586,6 @@ begin
|
||||
var setupAst :=
|
||||
TAst.Block(
|
||||
[
|
||||
// TAst.VarDecl(
|
||||
// TAst.Identifier('CreateSMA'),
|
||||
// TAst.LambdaExpr(
|
||||
// [TAst.Identifier('len')],
|
||||
// TAst.Block(
|
||||
// [
|
||||
// TAst.VarDecl(TAst.Identifier('sum'), TAst.Constant(TScalar.FromDouble(0.0))),
|
||||
// TAst.VarDecl(TAst.Identifier('count'), TAst.Constant(TScalar.FromInt64(0))),
|
||||
// TAst.LambdaExpr(
|
||||
// [TAst.Identifier('series'), TAst.Identifier('val')],
|
||||
// TAst.Block(
|
||||
// [
|
||||
// TAst.Assign(
|
||||
// TAst.Identifier('sum'),
|
||||
// TAst.BinaryExpr(TAst.Identifier('sum'), boAdd, TAst.Identifier('val'))
|
||||
// ),
|
||||
// TAst.Assign(
|
||||
// TAst.Identifier('count'),
|
||||
// TAst.BinaryExpr(TAst.Identifier('count'), boAdd, TAst.Constant(TScalar.FromInt64(1)))
|
||||
// ),
|
||||
// TAst.IfExpr(
|
||||
// TAst.BinaryExpr(TAst.Identifier('count'), boGreater, TAst.Identifier('len')),
|
||||
// TAst.Assign(
|
||||
// TAst.Identifier('sum'),
|
||||
// TAst.BinaryExpr(
|
||||
// TAst.Identifier('sum'),
|
||||
// boSubtract,
|
||||
// TAst.Indexer(TAst.Identifier('series'), TAst.Identifier('len'))
|
||||
// )
|
||||
// ),
|
||||
// nil
|
||||
// ),
|
||||
// TAst.BinaryExpr(
|
||||
// TAst.Identifier('sum'),
|
||||
// boDivide,
|
||||
// TAst.TernaryExpr(
|
||||
// TAst.BinaryExpr(TAst.Identifier('count'), boLess, TAst.Identifier('len')),
|
||||
// TAst.Identifier('count'),
|
||||
// TAst.Identifier('len')
|
||||
// )
|
||||
// )
|
||||
// ]
|
||||
// )
|
||||
// )
|
||||
// ]
|
||||
// )
|
||||
// )
|
||||
// ),
|
||||
TAst.VarDecl(
|
||||
TAst.Identifier('smaFast'),
|
||||
TAst.FunctionCall(TAst.Identifier('CreateSMA'), [TAst.Constant(TScalar.FromInt64(smaFastLength))])
|
||||
@@ -961,14 +933,11 @@ begin
|
||||
TAst.Identifier('countDown'),
|
||||
TAst.LambdaExpr(
|
||||
[TAst.Identifier('n')],
|
||||
// if (n > 0) then Self(n-1) else 'done'
|
||||
// if (n > 0) then recur(n-1) else 'done'
|
||||
TAst.IfExpr(
|
||||
TAst.BinaryExpr(TAst.Identifier('n'), boGreater, TAst.Constant(TScalar.FromInt64(0))),
|
||||
// This is the tail call position.
|
||||
TAst.FunctionCall(
|
||||
TAst.Identifier('Self'),
|
||||
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
|
||||
),
|
||||
// This is the tail call position, now using recur.
|
||||
TAst.Recur([TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]),
|
||||
// Base case of the recursion
|
||||
TAst.Constant(TScalar.FromString('done'))
|
||||
)
|
||||
|
||||
@@ -30,6 +30,7 @@ type
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -105,6 +106,27 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstToTextVisitor.VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
var
|
||||
i: Integer;
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('recur(');
|
||||
for i := 0 to High(Node.Arguments) do
|
||||
begin
|
||||
sb.Append(Node.Arguments[i].Accept(Self).AsText);
|
||||
if i < High(Node.Arguments) then
|
||||
sb.Append(', ');
|
||||
end;
|
||||
sb.Append(')');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstToTextVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
begin
|
||||
Result := Node.Name;
|
||||
|
||||
@@ -118,6 +118,7 @@ type
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -567,6 +568,46 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstToAuraNodeVisitor.VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
var
|
||||
details: string;
|
||||
begin
|
||||
if (FMode = vmControlFlow) and TryGetDescr(Node, details) then
|
||||
begin
|
||||
var recurNode := CreateNodeControl('Recur', details);
|
||||
CreateEntry(recurNode);
|
||||
CreateExit(recurNode, '');
|
||||
FinalizeNodeLayout(recurNode);
|
||||
FLastResult.OutputPin := nil;
|
||||
end
|
||||
else
|
||||
begin
|
||||
VisitOperatorNode(
|
||||
Node.Arguments,
|
||||
function(const InputResults: TAuraNodeResultList): TAuraNodeResult
|
||||
var
|
||||
recurNode: TAuraNode;
|
||||
argPin: array of TControl;
|
||||
i: Integer;
|
||||
begin
|
||||
recurNode := BuildNodeControl('Recur', '');
|
||||
CreateEntry(recurNode);
|
||||
SetLength(argPin, Length(Node.Arguments));
|
||||
for i := 0 to High(argPin) do
|
||||
argPin[i] := CreateInput(recurNode, 'Arg' + i.ToString);
|
||||
CreateExit(recurNode, '');
|
||||
for i := 0 to High(Node.Arguments) do
|
||||
if Assigned(InputResults[i].OutputPin) then
|
||||
FConnections.Add(TPinConnection.Create(InputResults[i].OutputPin, argPin[i]));
|
||||
FinalizeNodeLayout(recurNode);
|
||||
Result.LayoutNode := recurNode;
|
||||
Result.OutputPin := nil;
|
||||
end
|
||||
);
|
||||
end;
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstToAuraNodeVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
var
|
||||
existingResult: TAuraNodeResult;
|
||||
|
||||
Reference in New Issue
Block a user