pascalabcnet/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutor.cs

867 lines
43 KiB
C#
Raw Normal View History

2015-05-14 22:35:07 +03:00
using System;
using System.Collections.Generic;
using System.Linq;
using PascalABCCompiler.SemanticTree;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.SystemLibrary;
using PascalABCCompiler.TreeConverter;
using PascalABCCompiler.TreeRealization;
using array_const = PascalABCCompiler.SyntaxTree.array_const;
using for_node = PascalABCCompiler.SyntaxTree.for_node;
namespace TreeConverter.LambdaExpressions.Closure
{
internal class SubstitutionKey
{
private readonly string _variableName;
private readonly syntax_tree_node _syntaxTreeNodeWhereVaribleIsDeclared;
private readonly syntax_tree_node _syntaxTreeUnderSubstitution;
public SubstitutionKey(string varName, syntax_tree_node varDefLocation, syntax_tree_node block)
{
_variableName = varName.ToLower();
_syntaxTreeNodeWhereVaribleIsDeclared = varDefLocation;
_syntaxTreeUnderSubstitution = block;
}
public bool IsPartialKeyEquals(syntax_tree_node block)
{
return block == _syntaxTreeUnderSubstitution;
}
public override bool Equals(object obj)
{
var other = obj as SubstitutionKey;
if (other == null)
{
return false;
}
return _variableName == other._variableName &&
_syntaxTreeNodeWhereVaribleIsDeclared == other._syntaxTreeNodeWhereVaribleIsDeclared &&
_syntaxTreeUnderSubstitution == other._syntaxTreeUnderSubstitution;
}
public override int GetHashCode()
{
Func<syntax_tree_node, int> getHashCodeOfSyntaxTreeNode = stn =>
{
if (stn == null || stn.source_context == null)
{
return 0;
}
var begin = stn.source_context.begin_position;
var end = stn.source_context.end_position;
return (begin == null ? 0 : begin.column_num.GetHashCode() ^ begin.line_num.GetHashCode()) ^
(end == null ? 0 : end.column_num.GetHashCode() ^ end.line_num.GetHashCode());
};
return _variableName.ToLower().GetHashCode() ^
(_syntaxTreeNodeWhereVaribleIsDeclared == null ? 0 : _syntaxTreeNodeWhereVaribleIsDeclared.GetHashCode()) ^
(_syntaxTreeUnderSubstitution == null ? 0 : _syntaxTreeUnderSubstitution.GetHashCode());
}
}
internal class CapturedVariablesSubstitutor : WalkingVisitor
{
private readonly Dictionary<SubstitutionKey, List<ident>> _identsReferences;
private readonly Dictionary<int, CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition> _generatedScopeClassesInfo;
private readonly Dictionary<SubstitutionKey, dot_node> _substitutionsInfo;
private readonly syntax_tree_visitor _visitor;
private readonly Stack<syntax_tree_node> _syntaxTreeNodeStack = new Stack<syntax_tree_node>();
private readonly Dictionary<int, CapturedVariablesTreeNode> _capturedVarsTreeNodesDictionary;
private readonly List<CapturedVariablesTreeNodeLambdaScope> _lambdasToBeAddedAsMethods;
private readonly Dictionary<string, Tuple<string, class_field, semantic_node>> _mappingForNonPublicFieldsOfClass;
public CapturedVariablesSubstitutor(Dictionary<SubstitutionKey, List<ident>> identsReferences,
Dictionary<int, CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition> generatedScopeClassesInfo,
List<CapturedVariablesTreeNodeLambdaScope> lambdasToBeAddedAsMethods,
Dictionary<SubstitutionKey, dot_node> substitutionsInfo,
Dictionary<int, CapturedVariablesTreeNode> capturedVarsTreeNodesDictionary,
Dictionary<string, Tuple<string, class_field, semantic_node>> mappingForNonPublicFieldsOfClass,
syntax_tree_visitor visitor)
{
_identsReferences = identsReferences;
_generatedScopeClassesInfo = generatedScopeClassesInfo;
_substitutionsInfo = substitutionsInfo;
_capturedVarsTreeNodesDictionary = capturedVarsTreeNodesDictionary;
_lambdasToBeAddedAsMethods = lambdasToBeAddedAsMethods;
_mappingForNonPublicFieldsOfClass = mappingForNonPublicFieldsOfClass;
_visitor = visitor;
}
public override void visit(statement_list stmtList)
{
_syntaxTreeNodeStack.Push(stmtList);
base.visit(stmtList);
_syntaxTreeNodeStack.Pop();
}
public override void visit(for_node fn)
{
SubstituteInNode(fn, fn); //Здесь обработаются замены поверхностного уровня, то есть, если в initial_value и т.д. содержатся ident
_syntaxTreeNodeStack.Push(fn); //Здесь обработаются случаи, если initial_value и т.д. представляют собой более сложные случаи, такие как indexer и т.д.
ProcessNode(fn.initial_value);
ProcessNode(fn.finish_value);
ProcessNode(fn.increment_value);
_syntaxTreeNodeStack.Pop();
ProcessNode(fn.statements);
}
public override void visit(foreach_stmt fn)
{
SubstituteInNode(fn, fn); //Здесь обработаются замены поверхностного уровня, то есть, если в initial_value и т.д. содержатся ident
_syntaxTreeNodeStack.Push(fn); //Здесь обработаются случаи, если in_what представляет собой более сложные случаи, такие как indexer и т.д.
ProcessNode(fn.in_what);
_syntaxTreeNodeStack.Pop();
ProcessNode(fn.stmt);
}
private void AddPropertiesToConvertingClass()
{
if (_visitor.context._ctn != null)
{
if (_mappingForNonPublicFieldsOfClass != null)
{
var pairs = _mappingForNonPublicFieldsOfClass.Where(pair => pair.Value.Item3 is common_property_node);
foreach (var pair in pairs)
{
var name = pair.Value.Item1;
var semClassField = pair.Value.Item2;
var pn = (common_property_node)pair.Value.Item3;
var readFunction = _visitor.GenerateGetMethodForField(pn, compiler_string_consts.GetGetAccessorName(pn.name), semClassField, null);
var writeFunction = _visitor.GenerateSetMethodForField(pn, compiler_string_consts.GetSetAccessorName(pn.name), semClassField, null);
pn.internal_get_function = readFunction;
pn.internal_set_function = writeFunction;
_visitor.context._ctn.Scope.AddSymbol(name, new SymbolInfo(pn));
_visitor.context._ctn.properties.AddElement(pn);
}
}
}
}
private void SubstituteInNode(syntax_tree_node currentNode, syntax_tree_node nodeWhereSubstitute)
{
var identSubnodesIndexes = Enumerable
.Range(0, nodeWhereSubstitute.subnodes_count)
.Where(index => nodeWhereSubstitute[index] is ident)
.ToList();
if (nodeWhereSubstitute is for_node) //нужно исключить переменную цикла, так как она оброабатывается отдельно в SubstituteForLoopVariables
{
var fn = (for_node) nodeWhereSubstitute;
var indexWithLoopIdent = identSubnodesIndexes.First(ind =>
{
var id = nodeWhereSubstitute[ind] as ident;
if (id == null)
{
return false;
}
return id == fn.loop_variable;
});
identSubnodesIndexes.Remove(indexWithLoopIdent);
}
if (nodeWhereSubstitute is foreach_stmt) //нужно исключить переменную цикла, так как она оброабатывается отдельно в SubstituteForEachLoopVariables
{
var fn = (foreach_stmt)nodeWhereSubstitute;
var indexWithLoopIdent = identSubnodesIndexes.First(ind =>
{
var id = nodeWhereSubstitute[ind] as ident;
if (id == null)
{
return false;
}
return id == fn.identifier;
});
identSubnodesIndexes.Remove(indexWithLoopIdent);
}
if (identSubnodesIndexes.Count == 0)
{
return;
}
var keys = _substitutionsInfo
.Keys
.Where(k => k.IsPartialKeyEquals(currentNode))
.Where(k => _identsReferences.ContainsKey(k));
foreach (var key in keys)
{
var subst = _substitutionsInfo[key];
foreach (var id in _identsReferences[key])
{
for (var i = 0; i < identSubnodesIndexes.Count; i++)
{
if (nodeWhereSubstitute[identSubnodesIndexes[i]] == id)
{
nodeWhereSubstitute[identSubnodesIndexes[i]] = new closure_substituting_node(subst);
}
}
}
}
}
private void OnNodeLeave(syntax_tree_node node)
{
if (_syntaxTreeNodeStack.Count == 0)
{
return;
}
if (node is for_node || node is foreach_stmt) // заголовки циклов обрабатываются отдельно
{
return;
}
var currentBlock = _syntaxTreeNodeStack.Peek();
SubstituteInNode(currentBlock, node);
}
private void SubstituteLambdas()
{
for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++)
{
if (_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod != null)
{
var classDef = _generatedScopeClassesInfo[_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value];
if (classDef.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)
{
continue;
}
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 procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDef);
classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl));
}
}
}
private void SubstituteForLoopVariables()
{
var forScopes =
_capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeForScope)
.Select(n => (CapturedVariablesTreeNodeForScope) n.Value)
.ToList();
foreach (var forScope in forScopes)
{
var forNode = forScope.CorrespondingSyntaxTreeNode as for_node;
if (forNode != null)
{
CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
if (_generatedScopeClassesInfo.TryGetValue(forScope.ScopeIndex, out generatedClass))
{
var nodesToAdd = new List<statement>();
var enclosedStatementList = (statement_list) forScope.EnclosedUpperBlockScope.CorrespondingSyntaxTreeNode;
nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
{
nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
}
var forNodeIndex = enclosedStatementList.subnodes.FindIndex(stmt => stmt == forNode);
enclosedStatementList.subnodes.InsertRange(forNodeIndex, nodesToAdd);
var substDotNode = new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName), new ident(forNode.loop_variable.name));
var assignNode = new assign(substDotNode, new ident(forNode.loop_variable.name)); // TODO: SourceContexts!!!!!
((statement_list)forNode.statements).subnodes.Insert(0, assignNode);
}
else
{
var si = forScope.SymbolInfoLoopVar;
var scopeWhereVarDefined = _capturedVarsTreeNodesDictionary[si.scope.ScopeNum];
var idRef = scopeWhereVarDefined
.VariablesDefinedInScope
.Find(var => var.SymbolInfo == si); //TODO: !!!!!!!!!!!!!!!!!!!!!!
var substKey = new SubstitutionKey(forNode.loop_variable.name, idRef.SyntaxTreeNodeWithVarDeclaration, forNode);
if (_substitutionsInfo.ContainsKey(substKey)) // Если нашли замену, то переменная где-то захватывалась
{
forNode.create_loop_variable = true;
var substDotNode = _substitutionsInfo[substKey];
var assignNode = new assign(substDotNode, new ident(forNode.loop_variable.name)); // TODO: SourceContexts!!!!!
(((statement_list)forNode.statements).subnodes).Insert(0, assignNode);
}
}
}
}
}
private void SubstituteForEachLoopVariables()
{
var forEachScopes =
_capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeForEachScope)
.Select(n => (CapturedVariablesTreeNodeForEachScope)n.Value)
.ToList();
foreach (var forEachScope in forEachScopes)
{
var forEachNode = forEachScope.CorrespondingSyntaxTreeNode as foreach_stmt;
if (forEachNode != null)
{
CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
if (_generatedScopeClassesInfo.TryGetValue(forEachScope.ScopeIndex, out generatedClass))
{
var nodesToAdd = new List<statement>();
var bodyStmtList = (statement_list)forEachNode.stmt;
nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
{
nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
}
var substDotNode = new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName), new ident(forEachNode.identifier.name));
var assignNode = new assign(substDotNode, new ident(forEachNode.identifier.name)); // TODO: SourceContexts!!!!!
nodesToAdd.Add(assignNode);
bodyStmtList.subnodes.InsertRange(0, nodesToAdd);
}
else
{
var si = forEachScope.SymbolInfoLoopVar;
var scopeWhereVarDefined = _capturedVarsTreeNodesDictionary[si.scope.ScopeNum];
var idRef = scopeWhereVarDefined
.VariablesDefinedInScope
.Find(var => var.SymbolInfo == si); //TODO: !!!!!!!!!!!!!!!!!!!!!!
var substKey = new SubstitutionKey(forEachNode.identifier.name, idRef.SyntaxTreeNodeWithVarDeclaration, forEachNode);
if (_substitutionsInfo.ContainsKey(substKey)) // Если нашли замену, то переменная где-то захватывалась
{
if (forEachNode.type_name == null) //Нужно, чтобы переменная цикла создалась в этом случае в контескте с этим же именем что и была
{
forEachNode.type_name = new no_type_foreach();
}
var substDotNode = _substitutionsInfo[substKey];
var assignNode = new assign(substDotNode, new ident(forEachNode.identifier.name)); // TODO: SourceContexts!!!!!
(((statement_list)forEachNode.stmt).subnodes).Insert(0, assignNode);
}
}
}
}
}
private void SubstituteVariablesDeclarations()
{
var classDefsTreeNodes = _generatedScopeClassesInfo.Join(_capturedVarsTreeNodesDictionary,
outer => outer.Key,
inner => inner.Key,
(outer, inner) => new
{
ClassDeclaration = outer.Value,
TreeNode = inner.Value
})
.Where(p => p.TreeNode is CapturedVariablesTreeNodeBlockScope)
.Select(p => new
{
p.ClassDeclaration,
TreeNode = (CapturedVariablesTreeNodeBlockScope) p.TreeNode
}); //TODO: Сейчас рассматриваются только захватываемые переменные, определенные внутри какого-либо блока. Рассмотреть остальные случаи.
foreach (var classDefTreeNode in classDefsTreeNodes)
{
var statementListNode = classDefTreeNode.TreeNode.CorrespondingSyntaxTreeNode as statement_list; //TODO: Сейчас рассматриваются только захватываемые переменные, определенные внутри какого-либо блока. Рассмотреть остальные случаи.
if (statementListNode != null)
{
var variables = classDefTreeNode
.TreeNode
.VariablesDefinedInScope
.Where(var => var.ReferencingLambdas.Count > 0)
.GroupBy(var => var.SyntaxTreeNodeWithVarDeclaration)
.Select(gr => new
{
SyntaxTreeNodeWithVarDeclaration = gr.Key,
Vars = gr.ToList()
})
.ToList();
if (variables.Count == 0)
{
return;
}
var newStmtList = new statement_list();
newStmtList.Add(classDefTreeNode.ClassDeclaration.GeneratedVarStatementForScope);
if (classDefTreeNode.ClassDeclaration.AssignNodeForUpperClassFieldInitialization != null)
{
newStmtList.Add(classDefTreeNode.ClassDeclaration.AssignNodeForUpperClassFieldInitialization);
}
var stmtListQueue = new Queue<statement>(statementListNode.subnodes);
while (stmtListQueue.Count > 0)
{
var currentStatement = stmtListQueue.Dequeue();
var varStatement = currentStatement as var_statement; //TODO: пока что только локальные переменные, определенные внутри var_def_statement!!!!!!!!
if (varStatement != null &&
varStatement.var_def != null)
{
var varDefKey =
variables.FirstOrDefault(gr => gr.SyntaxTreeNodeWithVarDeclaration == varStatement.var_def);
if (varDefKey != null)
{
var varsToExclude =
varDefKey.Vars.Select(var => ((IVAriableDefinitionNode) var.SymbolInfo.sym_info).name.ToLower()); //TODO: пока что только локальные переменные!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var newVarList = varStatement.var_def.vars.idents
.Where(id => !varsToExclude.Contains(id.name.ToLower()))
.ToList();
if (newVarList.Count > 0)
{
var newVarDefStmt = new var_def_statement(new ident_list(newVarList), varStatement.var_def.vars_type)
{
inital_value = varStatement.var_def.inital_value
};
var newVarStmt = new var_statement(newVarDefStmt);
newStmtList.Add(newVarStmt);
}
if (varStatement.var_def.inital_value != null)
{
var initVal = varStatement.var_def.inital_value;
string auxVarName = null;
if (initVal is array_const)
{
auxVarName = LambdaHelper.GetAuxVarName();
var newVarDefStmt = new var_def_statement(new ident_list(new ident(auxVarName)), varStatement.var_def.vars_type)
{
inital_value = initVal
};
var newVarStmt = new var_statement(newVarDefStmt);
newStmtList.Add(newVarStmt);
}
foreach (var variable in varsToExclude)
{
var assignStmt =
new assign(new dot_node(new ident(classDefTreeNode.ClassDeclaration.GeneratedSubstitutingFieldName),
new ident(variable)),
auxVarName == null ? varStatement.var_def.inital_value : new ident(auxVarName));
newStmtList.Add(assignStmt);
}
}
}
else
{
newStmtList.Add(currentStatement);
}
}
else
{
newStmtList.Add(currentStatement);
}
}
statementListNode.subnodes.Clear();
statementListNode.subnodes.AddRange(newStmtList.subnodes);
}
}
}
private void VisitClassDefinitions()
{
_visitor.context.SaveContextAndUpToGlobalLevel();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingVisitGeneratedClassesPhase;
foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)))
{
_visitor.visit(clDecl.Value.ClassDeclaration);
}
_visitor.context.RestoreCurrentContext();
_visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingPhase;
}
private void SubstituteVarDefInProcedure(statement_list statementList) //TODO: сейчас обрабатывается так, как будто блока объявлений declarations в функции нет. Нужно будет предусмотреть, но не только для функций, а еще для всех узлов где есть block, который содержит declarations
{
var classDefsTreeNode = _generatedScopeClassesInfo.Join(_capturedVarsTreeNodesDictionary,
outer => outer.Key,
inner => inner.Key,
(outer, inner) => new
{
ClassDeclaration = outer.Value,
TreeNode = inner.Value
})
.Where(p => p.TreeNode is CapturedVariablesTreeNodeProcedureScope)
.Select(p => new
{
p.ClassDeclaration,
TreeNode = (CapturedVariablesTreeNodeProcedureScope)p.TreeNode
})
.FirstOrDefault();
if (classDefsTreeNode == null)
{
return;
}
var variables = classDefsTreeNode
.TreeNode
.VariablesDefinedInScope
.Where(l => l.ReferencingLambdas.Count > 0)
.ToList();
if (variables.Count == 0)
{
return;
}
CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass;
if (_generatedScopeClassesInfo.TryGetValue(classDefsTreeNode.TreeNode.ScopeIndex, out generatedClass))
{
var exprList = variables.Select(v => (expression)new ident(((IVAriableDefinitionNode) v.SymbolInfo.sym_info).name)).ToList();
if (IsInGenerics)
{
var newVarDefSyntaxTreeNode = new var_def_statement(generatedClass.GeneratedSubstitutingFieldName, new template_type_reference(new named_type_reference(generatedClass.ClassDeclaration.type_name.name), new template_param_list(AllGenericParameters.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList())));
newVarDefSyntaxTreeNode.inital_value =
new new_expr(new template_type_reference(new named_type_reference(generatedClass.ClassDeclaration.type_name.name), new template_param_list(AllGenericParameters.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList())),
new expression_list(exprList), null);
generatedClass.GeneratedVarStatementForScope.var_def = newVarDefSyntaxTreeNode;
}
else
{
generatedClass.GeneratedVarStatementForScope.var_def.inital_value =
new new_expr(SyntaxTreeBuilder.BuildSimpleType(generatedClass.ClassDeclaration.type_name.name),
new expression_list(exprList), null);
}
var nodesToAdd = new List<statement>();
nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope);
if (generatedClass.AssignNodeForUpperClassFieldInitialization != null)
{
nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization);
}
statementList.subnodes.InsertRange(0, nodesToAdd);
}
}
private void SubstituteTypesInCaseOfGenerics()
{
if (!IsInGenerics)
{
return;
}
/* TODO: нужно заменить в полях сгенерированных классов, параметрах и возвращаемом значении лямбд - у всех, с учетом того как чистятся все дженерики...
/* Предусмотреть случай, когда захвата переменных не происходит, но мы все равно находимся в лямбде - это нужно сделать на FinishPhase в syntax_tree_visitor
/* Не забыть про where секцию */
for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++)
{
var lambdaDef = _lambdasToBeAddedAsMethods[i].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++)
{
if (lambdaDef.formal_parameters.params_list[j].vars_type is lambda_inferred_type)
{
if ((lambdaDef.formal_parameters.params_list[j].vars_type as lambda_inferred_type).real_type is type_node)
{
lambdaDef.formal_parameters.params_list[j].vars_type =
LambdaHelper.ConvertSemanticTypeToSyntaxType((type_node)(lambdaDef.formal_parameters.params_list[j].vars_type as lambda_inferred_type).real_type);
}
}
}
}
if (lambdaDef.return_type is lambda_inferred_type)
{
if ((lambdaDef.return_type as lambda_inferred_type).real_type is type_node)
{
lambdaDef.return_type = LambdaHelper.ConvertSemanticTypeToSyntaxType((type_node)(lambdaDef.return_type as lambda_inferred_type).real_type);
}
}
}
foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)))
{
var fields =
((class_definition) clDecl.Value.ClassDeclaration.type_def).body.class_def_blocks
.SelectMany(d => d.members)
.OfType<var_def_statement>();
foreach (var field in fields)
{
var semTypeNode = field.vars_type as semantic_type_node;
if (semTypeNode != null)
{
if (semTypeNode.type is type_node)
{
field.vars_type = LambdaHelper.ConvertSemanticTypeToSyntaxType((type_node) semTypeNode.type);
}
}
}
var constructors =
((class_definition)clDecl.Value.ClassDeclaration.type_def).body.class_def_blocks
.SelectMany(d => d.members)
.OfType<procedure_definition>()
.Where(pr => pr.proc_header is constructor);
foreach (var constructor in constructors)
{
if (constructor.proc_header != null && constructor.proc_header.parameters != null && constructor.proc_header.parameters.params_list != null)
{
var pars = constructor.proc_header.parameters.params_list;
foreach (var p in pars)
{
var semTypeNode = p.vars_type as semantic_type_node;
if (semTypeNode != null)
{
if (semTypeNode.type is type_node)
{
p.vars_type = LambdaHelper.ConvertSemanticTypeToSyntaxType((type_node)semTypeNode.type);
}
}
}
}
}
var upperField =
((class_definition)clDecl.Value.ClassDeclaration.type_def).body.class_def_blocks
.SelectMany(d => d.members)
.OfType<var_def_statement>()
.FirstOrDefault(vds =>
{
if (vds.vars != null && vds.vars.idents != null)
{
if (vds.vars.idents.FirstOrDefault(id => id.name == clDecl.Value.GeneratedUpperClassFieldName) != null)
{
return true;
}
}
return false;
});
if (upperField != null)
{
var genericParameters = AllGenericParameters;
if (_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null)
{
var tr = upperField.vars_type as named_type_reference;
if (tr != null && tr.names != null && tr.names.Count == 1)
{
if (tr.names[0].name == _visitor.context._ctn.name)
{
genericParameters = ClassGenericParameters;
}
}
}
upperField.vars_type =
new template_type_reference(
(named_type_reference)upperField.vars_type,
new template_param_list(genericParameters.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList()));
}
if (clDecl.Value.GeneratedVarStatementForScope != null)
{
var oldInitialValueExpressions =
((new_expr) clDecl.Value.GeneratedVarStatementForScope.var_def.inital_value).params_list;
var newVarDefSyntaxTreeNode = new var_def_statement(clDecl.Value.GeneratedSubstitutingFieldName, new template_type_reference(new named_type_reference(clDecl.Value.ClassDeclaration.type_name.name), new template_param_list(AllGenericParameters.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList())));
newVarDefSyntaxTreeNode.inital_value =
new new_expr(new template_type_reference(new named_type_reference(clDecl.Value.ClassDeclaration.type_name.name), new template_param_list(AllGenericParameters.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList())),
oldInitialValueExpressions, null);
clDecl.Value.GeneratedVarStatementForScope.var_def = newVarDefSyntaxTreeNode;
}
clDecl.Value.ClassDeclaration.type_name = new template_type_name(clDecl.Value.ClassDeclaration.type_name.name, new ident_list(AllGenericParameters));
if (WhereSection != null && WhereSection.defs != null && WhereSection.defs.Count != 0)
{
((class_definition) clDecl.Value.ClassDeclaration.type_def).where_section = WhereSection;
}
}
}
private bool IsInGenerics
{
get
{
return _visitor.context.top_function != null && _visitor.context.top_function.generic_params != null ||
_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null;
}
}
private List<ident> AllGenericParameters
{
get
{
if (!IsInGenerics)
{
return null;
}
var res = new List<ident>();
if (_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null)
{
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)));
}
return res;
}
}
private List<ident> ClassGenericParameters
{
get
{
if (!IsInGenerics)
{
return null;
}
var res = new List<ident>();
if (_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null)
{
res.AddRange(_visitor.context._ctn.generic_params.Select(par => new ident(par.name)));
}
return res;
}
}
public static where_definition_list GetWhereSection(List<generic_parameter_eliminations> genericParameterEliminations, List<ident> pars)
{
var list = new List<where_definition>();
for (var i = 0; i < pars.Count; i++)
{
var el = genericParameterEliminations[i];
var par = pars[i];
var whereDef = new where_definition
{
names = new ident_list(par),
types = new type_definition_list()
};
if (el.is_class)
{
var d = new declaration_specificator(DeclarationSpecificator.WhereDefClass, "class");
whereDef.types.Add(d);
}
if (el.is_value)
{
var d = new declaration_specificator(DeclarationSpecificator.WhereDefValueType, "record");
whereDef.types.Add(d);
}
if (el.base_class != null && el.base_class != SystemLibrary.object_type)
{
var d = LambdaHelper.ConvertSemanticTypeToSyntaxType(el.base_class);
whereDef.types.Add(d);
}
foreach (var interf in el.implementing_interfaces)
{
var d = LambdaHelper.ConvertSemanticTypeToSyntaxType(interf);
whereDef.types.Add(d);
}
if (el.has_default_ctor)
{
var d = new declaration_specificator(DeclarationSpecificator.WhereDefConstructor, "constructor");
whereDef.types.Add(d);
}
if (whereDef.types.defs.Count != 0)
{
list.Add(whereDef);
}
}
return new where_definition_list(list);
}
private where_definition_list _whereSection = null;
private where_definition_list WhereSection
{
get
{
if (!IsInGenerics)
{
return null;
}
if (_whereSection != null)
{
return _whereSection;
}
var genericParameterEliminations = new List<generic_parameter_eliminations>();
if (_visitor.context._ctn != null && _visitor.context._ctn.generic_params != null)
{
genericParameterEliminations.AddRange(generic_parameter_eliminations.make_eliminations_common(_visitor.context._ctn.generic_params));
}
if (_visitor.context.top_function != null && _visitor.context.top_function.generic_params != null)
{
genericParameterEliminations.AddRange(generic_parameter_eliminations.make_eliminations_common(_visitor.context.top_function.generic_params));
}
_whereSection = GetWhereSection(genericParameterEliminations, AllGenericParameters);
return _whereSection;
}
}
public void Substitute(statement_list statementList)
{
OnLeave += OnNodeLeave;
ProcessNode(statementList);
SubstituteTypesInCaseOfGenerics();
SubstituteLambdas();
AddPropertiesToConvertingClass();
VisitClassDefinitions();
SubstituteVariablesDeclarations();
SubstituteForLoopVariables();
SubstituteForEachLoopVariables();
SubstituteVarDefInProcedure(statementList);
}
}
}