Вложенные лямбды

This commit is contained in:
RomanSaushkin 2015-06-11 09:20:31 +04:00
parent 1872434f19
commit 1b61879a42
14 changed files with 742 additions and 77 deletions

View file

@ -0,0 +1,18 @@
procedure p(f: Func<string, IEnumerable<string>>);
begin
end;
procedure p(f: Func<integer, IEnumerable<integer>>);
begin
var res := f(3).ToList();
assert(res.Count = 4);
assert(res[0] = 0);
assert(res[1] = 1);
assert(res[2] = 4);
assert(res[3] = 9);
end;
begin
p(x -> Range(0, x).Select(y -> y * y));
end.

View file

@ -0,0 +1,14 @@
procedure p(f: Func<integer, IEnumerable<integer>>);
begin
var res := f(5).ToList();
assert(res.Count = 5);
assert(res[0] = 2);
assert(res[1] = 3);
assert(res[2] = 4);
assert(res[3] = 5);
assert(res[4] = 6);
end;
begin
p(x -> Seq(1,2,3,4,5).Select(y -> Range(0, y).Select(z -> z).Count()));
end.

View file

@ -0,0 +1,27 @@
type cl = class
public
procedure p(f: Func<string, IEnumerable<string>>);
begin
end;
procedure p(f: Func<integer, IEnumerable<integer>>);
begin
var res := f(3).ToList();
assert(res.Count = 4);
assert(res[0] = 0);
assert(res[1] = 1);
assert(res[2] = 4);
assert(res[3] = 9);
end;
procedure tt();
begin
p(x -> Range(0, x).Select(y -> y * y));
end;
end;
begin
(new cl()).p(x -> Range(0, x).Select(y -> y * y));
(new cl()).tt();
end.

View file

@ -0,0 +1,22 @@
type cl = class
public
constructor(f: Func<string, IEnumerable<string>>);
begin
end;
constructor (f: Func<integer, IEnumerable<integer>>);
begin
var res := f(3).ToList();
assert(res.Count = 4);
assert(res[0] = 0);
assert(res[1] = 1);
assert(res[2] = 4);
assert(res[3] = 9);
end;
end;
begin
new cl(x -> Range(0, x).Select(y -> y * y));
end.

View file

@ -0,0 +1,12 @@
begin
var a := 3;
var ttt := Seq(1,2).Select(x -> begin
var t := 5;
result := Range(1,a+x).Select(y -> begin
var g := 5;
t += 5;
result := Range(1,2).Where(f -> f + a > 0).Select(z -> z + g + t);
end)
end).ToList();
assert(ttt[0].ToList()[0].ToList()[0] = 31);
end.

View file

@ -0,0 +1,20 @@
type cl = class
private gg := 9;
public
procedure h(k: integer);
begin
var a := 5;
Seq(1,2,3).Select(x -> begin
var t := 5;
result := Range(1,a).Select(y -> begin
var g := 5;
writeln(a);
result := Range(1,3).Where(f -> f + a > 0).Select(z -> z + g + t);
end)
end);
end;
end;
begin
(new cl).h(6);
end.

View file

@ -0,0 +1,20 @@
type cl = class
protected gg:integer := 9;
public
function h(k: integer):string;
begin
var a := 5;
foreach var tt in Seq(1,2,3) do
begin
var d := Seq(1,2,3).Select(x -> begin
var e := 65;
result := e + x + tt + self.gg + Range(1,2).Select(y -> gg + self.gg+y+a + tt).First()
end).ToList();
assert(d[0] = 100 + (tt * 2 - 1));
end;
end;
end;
begin
(new cl).h(5);
end.

View file

@ -0,0 +1,15 @@
begin
var yy := 5;
Range(1,1).Select(x -> begin
var l := x + yy; //6
begin
writeln(l);
begin
writeln(l);
end;
end;
writeln(yy);
result := Range(1, x).Select(y -> y + l + yy + Seq(1,2).Select(z -> l + yy).First())
end);
writeln(yy);
end.

View file

@ -0,0 +1,13 @@
procedure p<T>(aa: T); where T: class;
begin
var a := Seq(1,2,3).Select(x -> begin
var tt := new List<T>();
writeln(aa);
tt.Add(aa);
result := tt.Select(y -> begin result := aa; writeln(aa) end).ToList()
end).ToList();
end;
begin
p('sss');
end.

View file

@ -20,7 +20,8 @@ namespace TreeConverter.LambdaExpressions.Closure
private static int _generatedClassCounter;
private static int _generatedUpperClassCounter;
private readonly Dictionary<SubstitutionKey, dot_node> _substitutions;
private readonly List<LambdaReferencesSubstitutionInfo> _lambdaIdReferences = new List<LambdaReferencesSubstitutionInfo>();
private readonly List<RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo> _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo = new List<RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo>();
public static void Reset()
{
_generatedClassCounter = 0;
@ -58,6 +59,8 @@ namespace TreeConverter.LambdaExpressions.Closure
private const string GeneratedSubstitutingFieldPrefix = "<>local_variables_"; //это поле для того, чтобы заменять в текущем блоке, где захватывались переменные, левую часть dot_node
private static int _generatedSubstitutingFieldCounter;
public List<CapturedVariablesTreeNodeLambdaScope> NestedLambdas { get; set; }
public syntax_tree_node CorrespondingSyntaxTreeNode
{
get;
@ -129,9 +132,25 @@ namespace TreeConverter.LambdaExpressions.Closure
ClassDeclaration = classDeclaration;
_generatedSubstitutingFieldName = generatedSubstitutingFieldName;
CorrespondingTreeNode = correspondingTreeNode;
NestedLambdas = new List<CapturedVariablesTreeNodeLambdaScope>();
}
}
private class LambdaReferencesSubstitutionInfo
{
public CapturedVariablesTreeNodeLambdaScope LambdaScope { get; set; }
public string VarName { get; set; }
public syntax_tree_node SyntaxTreeNodeWithVarDeclaration { get; set; }
public dot_node DotNode { get; set; }
}
private class RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo
{
public CapturedVariablesTreeNode TreeNode { get; set; }
public string Varname { get; set; }
public syntax_tree_node NodeWithVarDecl { get; set; }
}
public CapturedVariablesSubstitutionClassGenerator(CapturedVariablesTreeNode capturedVariablesRootTreeNode)
{
_capturedVariablesRootTreeNode = capturedVariablesRootTreeNode;
@ -150,21 +169,27 @@ namespace TreeConverter.LambdaExpressions.Closure
private void VisitCapturedVar(CapturedVariablesTreeNode scope, CapturedVariablesTreeNode.CapturedSymbolInfo symbolInfo)
{
var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name.ToLower(); //TODO: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name.ToLower();
var isSelfWordInClass = scope is CapturedVariablesTreeNodeClassScope && varName == compiler_string_consts.self_word;
for (var k = 0; k < symbolInfo.ReferencingLambdas.Count; k++)
foreach (var referencingLambda in symbolInfo.ReferencingLambdas.OrderByDescending(rl => rl.ScopeIndex))
{
var referencingLambda = symbolInfo.ReferencingLambdas[k];
if (scope != referencingLambda.ParentNode)
{
var upperScopesStack = new Stack<CapturedVariablesTreeNode>();
var crawlUpScope = referencingLambda.ParentNode;
var anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope;
while (crawlUpScope != scope)
while (crawlUpScope != null && crawlUpScope != scope && !anotherLambdaIsOnTheWay)
{
upperScopesStack.Push(crawlUpScope);
crawlUpScope = crawlUpScope.ParentNode;
anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope;
}
if (anotherLambdaIsOnTheWay || crawlUpScope == null)
{
continue;
}
var upperScopeWhereVarsAreCaptured = scope;
@ -352,7 +377,6 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
//TODO: Nested Lambdas
if (!(upperScopeWhereVarsAreCaptured == scope &&
upperScopeWhereVarsAreCaptured is CapturedVariablesTreeNodeClassScope))
{
@ -403,8 +427,27 @@ namespace TreeConverter.LambdaExpressions.Closure
dotnode1 = new dot_node(dotnode1, new ident(varName));
}
}
AddReferencesToIdentInLambda(referencingLambda.ChildNodes[0], varName,
symbolInfo.SyntaxTreeNodeWithVarDeclaration, dotnode1);
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
}
else
{
var dotnode1 = new dot_node(
new ident(compiler_string_consts.self_word),
new ident(varName));
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
}
}
if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue ||
@ -454,6 +497,18 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
var dotnode1 = new dot_node(
new ident(compiler_string_consts.self_word),
new ident(varName));
_lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo
{
LambdaScope = referencingLambda,
VarName = varName,
SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration,
DotNode = dotnode1
});
if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue ||
scope.ScopeIndex > referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod)
{
@ -468,24 +523,93 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
private void AddReferencesToIdentInLambda(CapturedVariablesTreeNode scope, string varName, syntax_tree_node syntaxTreeNodeWithVarDeclaration, dot_node substDotNode)
private void AddReferencesToIdentInLambda(type_declaration upperScopeWhereVarsAreCapturedClass, CapturedVariablesTreeNode scope, string varName, syntax_tree_node syntaxTreeNodeWithVarDeclaration, dot_node substDotNode, bool nestedLambda)
{
//TODO: Nested Lambdas
for (var i = 0; i < scope.ChildNodes.Count; i++)
{
if (!(scope.ChildNodes[i] is CapturedVariablesTreeNodeLambdaScope)) // Вложенные лямбды пока не рассматриваем
if (!(scope.ChildNodes[i] is CapturedVariablesTreeNodeLambdaScope))
{
var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration,
scope.ChildNodes[i].CorrespondingSyntaxTreeNode);
if (_capturedVarsClassDefs.ContainsKey(scope.ChildNodes[i].ScopeIndex))
{
var cl = _capturedVarsClassDefs[scope.ChildNodes[i].ScopeIndex];
if (cl.AssignNodeForUpperClassFieldInitialization == null)
{
var fieldType =
SyntaxTreeBuilder.BuildSimpleType(upperScopeWhereVarsAreCapturedClass.type_name.name);
var field =
SyntaxTreeBuilder.BuildClassFieldsSection(
new List<ident>
{
new ident(cl.GeneratedUpperClassFieldName)
},
new List<type_definition> { fieldType });
var clClass = (class_definition) cl.ClassDeclaration.type_def;
clClass.body.Add(field);
cl.AssignNodeForUpperClassFieldInitialization =
new assign(
new dot_node(new ident(cl.GeneratedSubstitutingFieldName),new ident(cl.GeneratedUpperClassFieldName)),
new ident(compiler_string_consts.self_word));
}
}
if (!_substitutions.ContainsKey(substKey))
{
_substitutions.Add(substKey, substDotNode);
}
AddReferencesToIdentInLambda(scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration,
substDotNode);
AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda);
}
else
{
var scopeAsLambda = scope.ChildNodes[i] as CapturedVariablesTreeNodeLambdaScope;
if (scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue)
{
dot_node substDotNode1;
if (!nestedLambda)
{
substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), new ident(varName));
}
else
{
var parts = new Stack<ident>();
var dn = substDotNode;
parts.Push((ident)dn.right);
while (!(dn.left is ident && dn.right is ident))
{
dn = (dot_node)dn.left;
parts.Push((ident)dn.right);
}
parts.Push((ident)dn.left);
substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), parts.Pop());
while (parts.Count > 0)
{
substDotNode1 = new dot_node(substDotNode, parts.Pop());
}
}
var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration,
scope.ChildNodes[0].CorrespondingSyntaxTreeNode);
if (!_substitutions.ContainsKey(substKey))
{
_substitutions.Add(substKey, substDotNode1);
}
AddReferencesToIdentInLambda(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration, scopeAsLambda.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode1, true);
}
else
{
AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda);
}
}
}
}
@ -524,8 +648,7 @@ namespace TreeConverter.LambdaExpressions.Closure
currentNode));
}
// TODO: тут предусматривать разные случаи
var vars = variablesFromThisScopeWhichWereCaptured
.Select(field => field.SymbolInfo.sym_info as IVAriableDefinitionNode)
.ToList();
@ -571,7 +694,6 @@ namespace TreeConverter.LambdaExpressions.Closure
if (variablesFromThisScopeWhichWereCaptured.Count > 0)
{
// TODO: тут предусматривать разные случаи
var vars = variablesFromThisScopeWhichWereCaptured
.Select(x =>
new
@ -586,7 +708,13 @@ namespace TreeConverter.LambdaExpressions.Closure
{
foreach (CapturedVariablesTreeNode childNode in currentNode.ChildNodes)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(childNode, var.IVarDefinitionNode.name, var.VarDeclNode);
_rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo.Add(
new RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo
{
TreeNode = childNode,
Varname = var.IVarDefinitionNode.name,
NodeWithVarDecl = var.VarDeclNode
});
}
}
}
@ -594,9 +722,15 @@ namespace TreeConverter.LambdaExpressions.Closure
private void RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(CapturedVariablesTreeNode node, string varName, syntax_tree_node nodeWithVarDecl)
{
if (node is CapturedVariablesTreeNodeLambdaScope)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(node.ChildNodes[0], varName, nodeWithVarDecl);
return;
}
if (!(node is CapturedVariablesTreeNodeBlockScope ||
node is CapturedVariablesTreeNodeForScope ||
node is CapturedVariablesTreeNodeForEachScope)) // Добавляем ссылки только для скоупов-блоков и циклов, потому что остальные случаи должны были уже быть рассмотрены (когда эти случаи буду реализованы)
node is CapturedVariablesTreeNodeForEachScope))
{
return;
}
@ -637,6 +771,17 @@ namespace TreeConverter.LambdaExpressions.Closure
{
VisitTreeAndBuildClassDefinitions(_capturedVariablesRootTreeNode);
foreach (var ls in _lambdaIdReferences.Where(x => x.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue))
{
AddReferencesToIdentInLambda(_capturedVarsClassDefs[ls.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration,
ls.LambdaScope.ChildNodes[0], ls.VarName, ls.SyntaxTreeNodeWithVarDeclaration, ls.DotNode, false);
}
foreach (var r in _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo)
{
RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(r.TreeNode, r.Varname, r.NodeWithVarDecl);
}
return new VariableSubstitutionsInfo
{
GeneratedScopeClassesInfo = _capturedVarsClassDefs,

View file

@ -232,6 +232,34 @@ namespace TreeConverter.LambdaExpressions.Closure
SubstituteInNode(currentBlock, node);
}
private List<CapturedVariablesTreeNodeLambdaScope> GetNestedLambdasToBeAddedToThisClass(CapturedVariablesTreeNode scope)
{
var res = new List<CapturedVariablesTreeNodeLambdaScope>();
foreach (var child in scope.ChildNodes)
{
var childAsLambda = child as CapturedVariablesTreeNodeLambdaScope;
if (childAsLambda == null)
{
res.AddRange(GetNestedLambdasToBeAddedToThisClass(child));
}
else
{
if (childAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue)
{
continue;
}
else
{
res.Add(childAsLambda);
res.AddRange(GetNestedLambdasToBeAddedToThisClass(childAsLambda));
}
}
}
return res;
}
private void SubstituteLambdas()
{
for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++)
@ -239,21 +267,30 @@ namespace TreeConverter.LambdaExpressions.Closure
if (_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod != null)
{
var classDef = _generatedScopeClassesInfo[_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value];
if (classDef.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)
{
continue;
}
var otherLambdasToBeAddedAsMethods =
GetNestedLambdasToBeAddedToThisClass(_lambdasToBeAddedAsMethods[i]);
classDef.NestedLambdas.AddRange(otherLambdasToBeAddedAsMethods);
foreach (var oltaam in otherLambdasToBeAddedAsMethods)
{
oltaam.LambdaDefinition.substituting_node = new ident(oltaam.LambdaDefinition.lambda_name);
}
var left = new ident(classDef.GeneratedSubstitutingFieldName);
var lambdaDef = _lambdasToBeAddedAsMethods[i].LambdaDefinition;
lambdaDef.substituting_node = new dot_node(left, new ident(lambdaDef.lambda_name));
var classDecl = (class_definition)classDef.ClassDeclaration.type_def;
/*var classDecl = (class_definition)classDef.ClassDeclaration.type_def;
var procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDef);
classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl));
classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl));*/
}
}
}
@ -370,6 +407,44 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
private void SubstituteLambdaParameters()
{
var lambdaScopes =
_capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeLambdaScope)
.Select(n => (CapturedVariablesTreeNodeLambdaScope)n.Value)
.ToList();
foreach (var lambdaScope in lambdaScopes)
{
CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
if (_generatedScopeClassesInfo.TryGetValue(lambdaScope.ScopeIndex, out generatedClass))
{
var nodesToAdd = new List<statement>();
nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
{
nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
}
var variables = lambdaScope
.VariablesDefinedInScope
.Where(l => l.ReferencingLambdas.Count > 0)
.Select(var => ((IVAriableDefinitionNode) var.SymbolInfo.sym_info).name.ToLower())
.ToList();
foreach (var variable in variables)
{
var assignStmt = new assign(new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName),
new ident(variable)), new ident(variable));
nodesToAdd.Add(assignStmt);
}
((statement_list)lambdaScope.LambdaDefinition.proc_body).subnodes.InsertRange(0, nodesToAdd);
}
}
}
private void SubstituteVariablesDeclarations()
{
var classDefsTreeNodes = _generatedScopeClassesInfo.Join(_capturedVarsTreeNodesDictionary,
@ -489,16 +564,105 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
private void VisitClassDefinitions()
private Tuple<type_declaration, List<procedure_definition>> CreateTypeDeclarationWithForwardDeclaration(type_declaration cl)
{
var oldClDef = (class_definition) cl.type_def;
var classDef = SyntaxTreeBuilder.BuildClassDefinition(true);
var typeDeclaration = new type_declaration(cl.type_name, classDef);
classDef.where_section = oldClDef.where_section;
var procedures = new List<procedure_definition>();
var classMembers = new class_members(access_modifer.public_modifer);
classDef.body.class_def_blocks.Add(classMembers);
foreach (var member in oldClDef.body.class_def_blocks.SelectMany(x => x.members))
{
if (member is var_def_statement)
{
classMembers.Add(member);
}
else
{
var procDef = (procedure_definition) member;
if (procDef.proc_header is constructor)
{
classMembers.Add(procDef);
continue;
}
procedure_header procHeader;
if (procDef.proc_header is function_header)
{
var fh = (function_header) procDef.proc_header;
procHeader = new function_header
{
name = new method_name(fh.name.meth_name.name),
source_context = fh.source_context,
parameters = fh.parameters,
of_object = fh.of_object,
class_keyword = fh.class_keyword
};
((function_header)procHeader).return_type = fh.return_type;
}
else
{
procHeader = new procedure_header
{
name = new method_name(procDef.proc_header.name.meth_name.name),
source_context = procDef.proc_header.source_context,
parameters = procDef.proc_header.parameters,
of_object = procDef.proc_header.of_object,
class_keyword = procDef.proc_header.class_keyword
};
}
procDef.proc_header.name.class_name = cl.type_name;
procedures.Add(procDef);
classMembers.Add(procHeader);
}
}
return new Tuple<type_declaration, List<procedure_definition>>(typeDeclaration, procedures);
}
private List<procedure_definition> VisitClassDefinitions()
{
_visitor.context.SaveContextAndUpToGlobalLevel();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingVisitGeneratedClassesPhase;
foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)))
var procedures = new List<procedure_definition>();
var lambdaGroups =
_lambdasToBeAddedAsMethods.GroupBy(l => l.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod)
.ToDictionary(x => x.Key, x => x.ToList());
foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)).OrderBy(cd => cd.Key))
{
_visitor.visit(clDecl.Value.ClassDeclaration);
}
var lambdas = clDecl.Value.NestedLambdas;
List<CapturedVariablesTreeNodeLambdaScope> ls;
if (lambdaGroups.TryGetValue(clDecl.Key, out ls))
{
lambdas = lambdas.Concat(ls).ToList();
}
var classDecl = (class_definition)clDecl.Value.ClassDeclaration.type_def;
foreach (var lambdaDef in lambdas)
{
var procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDef.LambdaDefinition);
classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl));
}
var cl = CreateTypeDeclarationWithForwardDeclaration(clDecl.Value.ClassDeclaration);
procedures.AddRange(cl.Item2);
_visitor.visit(cl.Item1);
}
_visitor.context.RestoreCurrentContext();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingPhase;
return procedures;
}
private void VisitProceduresOfClasses(List<procedure_definition> procedures)
{
_visitor.context.SaveContextAndUpToGlobalLevel();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingVisitGeneratedClassesPhase;
procedures.ForEach(p => _visitor.visit(p));
_visitor.context.RestoreCurrentContext();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingPhase;
}
@ -581,9 +745,15 @@ namespace TreeConverter.LambdaExpressions.Closure
/* Предусмотреть случай, когда захвата переменных не происходит, но мы все равно находимся в лямбде - это нужно сделать на FinishPhase в syntax_tree_visitor
/* Не забыть про where секцию */
for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++)
var nestedLambdas = new List<CapturedVariablesTreeNodeLambdaScope>();
foreach (var cl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)))
{
var lambdaDef = _lambdasToBeAddedAsMethods[i].LambdaDefinition;
nestedLambdas.AddRange(cl.Value.NestedLambdas);
}
foreach (CapturedVariablesTreeNodeLambdaScope t in _lambdasToBeAddedAsMethods.Concat(nestedLambdas))
{
var lambdaDef = t.LambdaDefinition;
if (lambdaDef.formal_parameters != null && lambdaDef.formal_parameters.params_list.Count > 0)
{
for (var j = 0; j < lambdaDef.formal_parameters.params_list.Count; j++)
@ -716,8 +886,17 @@ namespace TreeConverter.LambdaExpressions.Closure
{
get
{
return _visitor.context.top_function != null && _visitor.context.top_function.generic_params != null ||
_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null;
var funcStackAsList = _visitor.context.func_stack == null
? null
: _visitor.context.func_stack.CloneInternalStack().ToList();
var funcIsGeneric = false;
if (funcStackAsList != null)
{
funcIsGeneric = funcStackAsList.FirstOrDefault(f => f.generic_params != null) != null;
}
return funcIsGeneric || _visitor.context._ctn != null && _visitor.context._ctn.generic_params != null;
}
}
@ -738,11 +917,19 @@ namespace TreeConverter.LambdaExpressions.Closure
res.AddRange(_visitor.context._ctn.generic_params.Select(par => new ident(par.name)));
}
if (_visitor.context.top_function != null && _visitor.context.top_function.generic_params != null)
{
res.AddRange(_visitor.context.top_function.generic_params.Select(par => new ident(par.name)));
}
var funcStackAsList = _visitor.context.func_stack == null
? null
: _visitor.context.func_stack.CloneInternalStack().ToList();
if (funcStackAsList != null)
{
var funcGeneric = funcStackAsList.FirstOrDefault(f => f.generic_params != null);
if (funcGeneric != null)
{
res.AddRange(funcGeneric.generic_params.Select(par => new ident(par.name)));
}
}
return res;
}
}
@ -856,14 +1043,16 @@ namespace TreeConverter.LambdaExpressions.Closure
{
OnLeave += OnNodeLeave;
ProcessNode(statementList);
SubstituteTypesInCaseOfGenerics();
SubstituteLambdas();
SubstituteTypesInCaseOfGenerics();
AddPropertiesToConvertingClass();
VisitClassDefinitions();
var procedures = VisitClassDefinitions();
SubstituteVariablesDeclarations();
SubstituteForLoopVariables();
SubstituteForEachLoopVariables();
SubstituteVarDefInProcedure(statementList);
//SubstituteLambdaParameters();
VisitProceduresOfClasses(procedures);
}
}
}

View file

@ -16,7 +16,7 @@ namespace TreeConverter.LambdaExpressions.Closure
private readonly syntax_tree_visitor _visitor;
private CapturedVariablesTreeNode _currentTreeNode;
private readonly Dictionary<int, CapturedVariablesTreeNode> _scopesCapturedVarsNodesDictionary;
private CapturedVariablesTreeNodeLambdaScope _currentLambdaScopeNode; //TODO Пересмотреть для вложенных лямбд
private Stack<CapturedVariablesTreeNodeLambdaScope> _currentLambdaScopeNodeStack = new Stack<CapturedVariablesTreeNodeLambdaScope>();
private readonly Dictionary<SubstitutionKey, List<ident>> _identsReferences;
private CapturedVariablesTreeNode _rootNode;
private CapturedVariablesTreeNodeClassScope _classScope;
@ -49,6 +49,13 @@ namespace TreeConverter.LambdaExpressions.Closure
}
}
private bool InLambdaContext
{
get
{
return _currentLambdaScopeNodeStack.Count > 0;
}
}
public CapturedVariablesTreeBuilder(syntax_tree_visitor visitor)
{
_visitor = visitor;
@ -125,7 +132,7 @@ namespace TreeConverter.LambdaExpressions.Closure
if (si == null)
{
if (_currentLambdaScopeNode != null)
if (InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
@ -154,13 +161,13 @@ namespace TreeConverter.LambdaExpressions.Closure
si.sym_info.semantic_node_type == semantic_node_type.common_parameter ||
si.sym_info.semantic_node_type == semantic_node_type.class_field;
if (!(acceptableVarType) && _currentLambdaScopeNode != null)
if (!(acceptableVarType) && InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}
if (si.sym_info.semantic_node_type == semantic_node_type.class_field && _currentLambdaScopeNode != null)
if (si.sym_info.semantic_node_type == semantic_node_type.class_field && InLambdaContext)
{
var semClassField = (class_field)si.sym_info;
if (semClassField.polymorphic_state != polymorphic_state.ps_common)
@ -186,12 +193,12 @@ namespace TreeConverter.LambdaExpressions.Closure
{
if (si.sym_info.semantic_node_type == semantic_node_type.local_variable)
{
if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && _currentLambdaScopeNode != null)
if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
}
}
if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && _currentLambdaScopeNode != null)
if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && InLambdaContext)
{
_visitor.AddError(new CannotCaptureNonValueParameters(_visitor.get_location(id)));
}
@ -268,19 +275,43 @@ namespace TreeConverter.LambdaExpressions.Closure
_identsReferences[substKey].Add(id);
}
if (_currentLambdaScopeNode == null ||
scopeIndex >= _currentLambdaScopeNode.ScopeIndex)
if (InLambdaContext && scope is CapturedVariablesTreeNodeLambdaScope &&
scopeIndex < _currentLambdaScopeNodeStack.Peek().ScopeIndex) //TODO: Захват параметров лямбды в другой лямбде
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}
if (!InLambdaContext ||
scopeIndex >= _currentLambdaScopeNodeStack.Peek().ScopeIndex)
{
return;
}
if (!_currentLambdaScopeNode.CapturedVarsSymbolInfo.Contains(si))
var stackAsList = _currentLambdaScopeNodeStack.ToList();
stackAsList.RemoveAt(0);
if (!_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Contains(si))
{
_currentLambdaScopeNode.CapturedVarsSymbolInfo.Add(si);
_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Add(si);
foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
{
if (!capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Contains(si))
{
capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Add(si);
}
}
}
if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNode))
if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNodeStack.Peek()))
{
idRef.ReferencingLambdas.Add(_currentLambdaScopeNode);
idRef.ReferencingLambdas.Add(_currentLambdaScopeNodeStack.Peek());
foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
{
if (!idRef.ReferencingLambdas.Contains(capturedVariablesTreeNodeLambdaScope))
{
idRef.ReferencingLambdas.Add(capturedVariablesTreeNodeLambdaScope);
}
}
}
}
}
@ -529,14 +560,14 @@ namespace TreeConverter.LambdaExpressions.Closure
_visitor.context.func_stack.top().scope.ScopeNum, lambdaDefinition);
_currentTreeNode.LambdasDefinedInScope.Add(newTreeNode);
_currentLambdaScopeNode = newTreeNode;
_currentLambdaScopeNodeStack.Push(newTreeNode);
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(_currentTreeNode.ScopeIndex, _currentTreeNode);
VisitProcParameters(procDecl.proc_header.parameters);
ProcessNode(procDecl.proc_body);
@ -545,7 +576,7 @@ namespace TreeConverter.LambdaExpressions.Closure
_visitor.context.remove_lambda_function(procDecl.proc_header.name.meth_name.name, false);
_currentTreeNode = _currentTreeNode.ParentNode;
_currentLambdaScopeNode = null; //TODO: Вложенные лямбды - изменить это
_currentLambdaScopeNodeStack.Pop();
LambdaHelper.RemoveLambdaInfoFromCompilationContext(_visitor.context, lambdaDefinition);
}

View file

@ -1048,12 +1048,6 @@ namespace PascalABCCompiler.TreeConverter
{
var func_stack_as_array = _func_stack.CloneInternalStack().ToList();
var upperLambda = func_stack_as_array.FirstOrDefault(func => LambdaHelper.IsLambdaName(func.name));
if (upperLambda != null)
{
syntax_tree_visitor.AddError(new NestedLambdasAreNotSupportedInThisVersionOfCompiler(def_loc));
}
var nestedFunc = func_stack_as_array.FirstOrDefault(func => func is common_in_function_function_node);
if (nestedFunc != null)
{

View file

@ -5082,26 +5082,159 @@ namespace PascalABCCompiler.TreeConverter
if (lambdas_are_in_parameters)
{
LambdaHelper.processingLambdaParametersForTypeInference++;
function_node ffn = convertion_data_and_alghoritms.select_function(exprs, si, subloc, syntax_nodes_parameters);
int exprCounter = 0;
if (skip_first_parameter)
// SSM 21.05.14 - попытка обработать перегруженные функции с параметрами-лямбдами с различными возвращаемыми значениями
function_node_list spf = null;
try
{
exprCounter++;
}
foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
if (!(en is SyntaxTree.function_lambda_definition))
function_node ffn = convertion_data_and_alghoritms.select_function(exprs, si, subloc, syntax_nodes_parameters);
int exprCounter = 0;
if (skip_first_parameter)
{
exprCounter++;
continue;
}
else
foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
LambdaHelper.InferTypesFromVarStmt(ffn.parameters[exprCounter].type, en as SyntaxTree.function_lambda_definition, this);
exprs[exprCounter] = convert_strong(en);
exprCounter++;
if (!(en is SyntaxTree.function_lambda_definition))
{
exprCounter++;
continue;
}
else
{
var enLambda = (SyntaxTree.function_lambda_definition)en;
LambdaHelper.InferTypesFromVarStmt(ffn.parameters[exprCounter].type, enLambda, this);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing;
exprs[exprCounter] = convert_strong(en);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing;
exprCounter++;
}
}
}
catch (SeveralFunctionsCanBeCalled sf)
{
spf = sf.set_of_possible_functions; // Возможны несколько перегруженных версий - надо выводить дальше в надежде что какие-то уйдут и останется одна
}
Exception lastmultex = null;
if (spf != null) // пытаемся инстанцировать одну за другой и ошибки гасим try
{ // exprs - глобальная, поэтому надо копировать
int spfnum = -1; // первый номер правильно инстанцированной. Если потом встретился второй, то тоже ошибка
for (int i = 0; i < spf.Count; i++)
{
function_node fnn = spf[i];
try
{
int exprCounter = 0;
expressions_list exprs1 = new expressions_list();
exprs1.AddRange(exprs); // сделали копию
foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
if (!(en is SyntaxTree.function_lambda_definition))
{
exprCounter++;
continue;
}
else
{
var fld = en as SyntaxTree.function_lambda_definition;
var lambdaName = fld.lambda_name; //lroman Сохранять имя необходимо
var fl = fld.lambda_visit_mode;
// запомнили типы параметров лямбды - SSM
object[] realparamstype = new object[fld.formal_parameters.params_list.Count]; // здесь хранятся выведенные типы лямбд или null если типы явно заданы
for (var k = 0; k < fld.formal_parameters.params_list.Count; k++)
{
var laminftypeK = fld.formal_parameters.params_list[k].vars_type as SyntaxTree.lambda_inferred_type;
if (laminftypeK == null)
realparamstype[k] = null;
else realparamstype[k] = laminftypeK.real_type;
}
// запоминаем реальный тип возвращаемого значения если он не указан явно (это должен быть any_type или null если он указан явно) - он может измениться при следующем вызове, поэтому мы его восстановим
var restype = fld.return_type as SyntaxTree.lambda_inferred_type;
object realrestype = null;
if (restype != null)
realrestype = restype.real_type;
LambdaHelper.InferTypesFromVarStmt(fnn.parameters[exprCounter].type, fld, this);
fld.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing; //lroman
fld.lambda_name = LambdaHelper.GetAuxiliaryLambdaName(lambdaName); // поправляю имя. Думаю, назад возвращать не надо. ПРОВЕРИТЬ!
//contextChanger.SaveContextAndUpToNearestDefSect();
try
{
exprs1[exprCounter] = convert_strong(en);
}
catch
{
throw;
}
finally
{
LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition);
// восстанавливаем сохраненный тип возвращаемого значения
if (restype != null)
restype.real_type = realrestype;
// восстанавливаем сохраненные типы параметров лямбды, которые не были заданы явно
for (var k = 0; k < fld.formal_parameters.params_list.Count; k++)
{
var laminftypeK = fld.formal_parameters.params_list[k].vars_type as SyntaxTree.lambda_inferred_type;
if (laminftypeK != null)
laminftypeK.real_type = realparamstype[k];
}
fld.lambda_name = lambdaName; //lroman Восстанавливаем имена
fld.lambda_visit_mode = fl;
}
//contextChanger.RestoreCurrentContext();
exprCounter++;
}
}
if (spfnum >= 0) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так
{
spfnum = -2;
break;
}
spfnum = i;
for (int j = 0; j < exprs.Count; j++) // копируем назад если всё хорошо
exprs[j] = exprs1[j];
}
catch (Exception e)
{
// если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать
//contextChanger.RestoreCurrentContext();
lastmultex = e;
}
}
if (spfnum == -2) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так
throw new SeveralFunctionsCanBeCalled(subloc, spf);
if (spfnum == -1) // было много, но ни одна не подошла из-за лямбд
{
throw lastmultex;
//throw new NoFunctionWithSameArguments(subloc2, false);
}
var kk = 0;
foreach (SyntaxTree.expression en in _method_call.parameters.expressions) //lroman окончательно подставить типы в лямбды
{
if (!(en is SyntaxTree.function_lambda_definition))
{
kk++;
continue;
}
else
{
LambdaHelper.InferTypesFromVarStmt(spf[spfnum].parameters[kk].type, en as SyntaxTree.function_lambda_definition, this);
exprs[kk] = convert_strong(en);
kk++;
}
}
}
// SSM 21.05.14 end
LambdaHelper.processingLambdaParametersForTypeInference--;
}
//lroman//
@ -6022,8 +6155,11 @@ namespace PascalABCCompiler.TreeConverter
}
else
{
LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, en as SyntaxTree.function_lambda_definition, this);
var enLambda = (SyntaxTree.function_lambda_definition) en;
LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, enLambda, this);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing;
exprs[exprCounter] = convert_strong(en);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing;
exprCounter++;
}
}
@ -6085,8 +6221,13 @@ namespace PascalABCCompiler.TreeConverter
{
exprs1[exprCounter] = convert_strong(en);
}
catch
{
throw;
}
finally
{
LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition);
// восстанавливаем сохраненный тип возвращаемого значения
if (restype != null)
restype.real_type = realrestype;
@ -6121,7 +6262,6 @@ namespace PascalABCCompiler.TreeConverter
// если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать
//contextChanger.RestoreCurrentContext();
lastmultex = e;
context.converted_namespace.functions.remove_at(context.converted_namespace.functions.Count - 1);
}
}
if (spfnum == -2) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так
@ -10565,7 +10705,7 @@ namespace PascalABCCompiler.TreeConverter
if ((context.top_function.semantic_node_type == semantic_node_type.common_method_node)
|| ((context.func_stack_size_is_one()) && (_is_interface_part)))
{
context.leave_block();
//context.leave_block();
}
}
body_exists = false;
@ -16154,9 +16294,11 @@ namespace PascalABCCompiler.TreeConverter
}
else
{
LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type,
en as SyntaxTree.function_lambda_definition, this);
var enLambda = (SyntaxTree.function_lambda_definition)en;
LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, enLambda, this);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing;
exprs[exprCounter] = convert_strong(en);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing;
exprCounter++;
}
}
@ -16226,8 +16368,13 @@ namespace PascalABCCompiler.TreeConverter
{
exprs1[exprCounter] = convert_strong(en);
}
catch
{
throw;
}
finally
{
LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition);
// восстанавливаем сохраненный тип возвращаемого значения
if (restype != null)
restype.real_type = realrestype;
@ -16265,8 +16412,6 @@ namespace PascalABCCompiler.TreeConverter
// если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать
//contextChanger.RestoreCurrentContext();
lastmultex = e;
context.converted_namespace.functions.remove_at(
context.converted_namespace.functions.Count - 1);
}
}
if (spfnum == -2)