diff --git a/Codegen/src/Nodes/ParameterEntry.cs b/Codegen/src/Nodes/ParameterEntry.cs index a87d8dfc0..4a67f6d90 100644 --- a/Codegen/src/Nodes/ParameterEntry.cs +++ b/Codegen/src/Nodes/ParameterEntry.cs @@ -49,7 +49,7 @@ public override IEnumerable Lines { //Type exists from Cobol 2002 string typedef = null; if (this.CodeElement.DataType.CobolLanguageLevel >= TypeCobol.Compiler.CobolLanguageLevel.Cobol2002) { - var type = this.Description?.TypeDefinition ?? this.SymbolTable.GetType(this.CodeElement.DataType).FirstOrDefault(); + var type = this.Description?.TypeDefinition; if (type != null) { customtype = type; @@ -84,7 +84,9 @@ public override IEnumerable Lines { if (picture == null && this.CodeElement.Usage == null && this.CodeElement.DataType.CobolLanguageLevel == Compiler.CobolLanguageLevel.Cobol85) {//JCM humm... Type without picture lookup enclosing scope. - var type = this.Description?.TypeDefinition ?? this.SymbolTable.GetType(this.CodeElement.DataType).FirstOrDefault(); + + //TODO seems to be an impossible situation as we check if we are on Compiler.CobolLanguageLevel.Cobol85 + var type = this.Description?.TypeDefinition; if (type != null) { customtype = type; diff --git a/TypeCobol.Test/Parser/Programs/Cobol2002/ParserIntegration.rdzPGM.txt b/TypeCobol.Test/Parser/Programs/Cobol2002/ParserIntegration.rdzPGM.txt index 8f9902c43..ff6f1f988 100644 --- a/TypeCobol.Test/Parser/Programs/Cobol2002/ParserIntegration.rdzPGM.txt +++ b/TypeCobol.Test/Parser/Programs/Cobol2002/ParserIntegration.rdzPGM.txt @@ -1,6 +1,6 @@ --- Diagnostics --- -Line 19[44,48] <27, Error, Syntax> - Syntax error : PICTURE clause incompatible with TYPE clause OffendingSymbol=[44,48:X(21)] Line 19[18,59] <30, Error, Semantics> - Semantic error: TYPE 'rib' is not referenced +Line 19[44,48] <27, Error, Syntax> - Syntax error : PICTURE clause incompatible with TYPE clause OffendingSymbol=[44,48:X(21)] Line 23[44,48] <27, Error, Syntax> - Syntax error : PICTURE clause incompatible with TYPE clause OffendingSymbol=[44,48:X(08)] --- Program --- diff --git a/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdz.tcbl b/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdz.tcbl index c15616e6f..dfdd58562 100644 --- a/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdz.tcbl +++ b/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdz.tcbl @@ -35,19 +35,19 @@ *Complex USED Typedef - 01 Typedef1 TYPEDEF STRICT. + 01 Typedef1 TYPEDEF STRICT global. 05 td-var1 pic X. 05 td-var10. 10 td-var11 pic X. 10 td-var12 pic X. 10 td-var13 type Typedef2. - 01 Typedef2 TYPEDEF STRICT. + 01 Typedef2 TYPEDEF STRICT global. 05 td-var2 pic X. 05 td-var20. 10 td-var21 pic X. 10 td-var22 pic X. 10 td-var23 type MainProgram::Typedef3. - 01 Typedef3 TYPEDEF STRICT. + 01 Typedef3 TYPEDEF STRICT global. 05 td-var3 pic X. 05 td-var30. 10 td-var31 pic X. diff --git a/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdzMix.txt b/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdzMix.txt index 34d39434f..f42d1773a 100644 --- a/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdzMix.txt +++ b/TypeCobol.Test/Parser/Programs/Cobol2002/Typedef3-global.rdzMix.txt @@ -1,4 +1,4 @@ - IDENTIFICATION DIVISION. + IDENTIFICATION DIVISION. PROGRAM-ID. MainProgram. data division. working-storage section. @@ -35,19 +35,19 @@ *Complex USED Typedef - 01 Typedef1 TYPEDEF STRICT. + 01 Typedef1 TYPEDEF STRICT global. 05 td-var1 pic X. 05 td-var10. 10 td-var11 pic X. 10 td-var12 pic X. 10 td-var13 type Typedef2. - 01 Typedef2 TYPEDEF STRICT. + 01 Typedef2 TYPEDEF STRICT global. 05 td-var2 pic X. 05 td-var20. 10 td-var21 pic X. 10 td-var22 pic X. 10 td-var23 type MainProgram::Typedef3. - 01 Typedef3 TYPEDEF STRICT. + 01 Typedef3 TYPEDEF STRICT global. 05 td-var3 pic X. 05 td-var30. 10 td-var31 pic X. diff --git a/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzMix.txt b/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzMix.txt index 0cbf7907e..2b7ebd1c7 100644 --- a/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzMix.txt +++ b/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzMix.txt @@ -5,23 +5,13 @@ WORKING-STORAGE SECTION. 01 ThirdType TYPEDEF STRICT. -Line 8[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected +Line 8[13,35] <30, Error, Semantics> - Semantic error: Type circular reference detected : ThirdType -> myType 05 renjgrn TYPE myType. 01 myType TYPEDEF STRICT. 05 myVar PIC X(10). 05 secondGroup pic X. -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected 05 yhrtger TYPE ThirdType. -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected 05 ezgoerk TYPE MySendType. 01 MyGroup. @@ -33,7 +23,7 @@ Line 17[15,20] <30, Error, Semantics> - Semantic error: Variable 'MyVar1' has to 01 MySendType TYPEDEF STRICT. 05 MyVariable PIC X(10). 05 MySecVariable PIC X. -Line 24[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected +Line 24[13,38] <30, Error, Semantics> - Semantic error: Type circular reference detected : MySendType -> myType 05 SelfRef TYPE myType. diff --git a/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzPGM.txt b/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzPGM.txt index fded7aa4d..d9dff8f4a 100644 --- a/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzPGM.txt +++ b/TypeCobol.Test/Parser/Programs/TypeCobol/CircularReferenceType.rdzPGM.txt @@ -1,17 +1,7 @@ --- Diagnostics --- -Line 8[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:renjgrn] -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:yhrtger] -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:yhrtger] -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:yhrtger] -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:yhrtger] -Line 13[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:yhrtger] -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:ezgoerk] -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:ezgoerk] -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:ezgoerk] -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:ezgoerk] -Line 14[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:ezgoerk] +Line 8[13,35] <30, Error, Semantics> - Semantic error: Type circular reference detected : ThirdType -> myType Line 17[15,20] <30, Error, Semantics> - Semantic error: Variable 'MyVar1' has to be limited to level 47 because of 'myType' maximum estimated children level OffendingSymbol=[15,20:MyVar1] -Line 24[16,22] <30, Error, Semantics> - Semantic error: Type circular reference detected OffendingSymbol=[16,22:SelfRef] +Line 24[13,38] <30, Error, Semantics> - Semantic error: Type circular reference detected : MySendType -> myType --- Program --- PROGRAM: CircularRefCheck common:False initial:False recursive:False diff --git a/TypeCobol/Compiler/CodeModel/SymbolTable.cs b/TypeCobol/Compiler/CodeModel/SymbolTable.cs index aa1ca992f..38eec7008 100644 --- a/TypeCobol/Compiler/CodeModel/SymbolTable.cs +++ b/TypeCobol/Compiler/CodeModel/SymbolTable.cs @@ -195,11 +195,8 @@ void AddVariableUnderTypeDefinition([NotNull] DataDefinition data) //TypeDefinition must NOT be added to DataTypeEntries, only its children Debug.Assert(!(data is TypeDefinition)); - //Types are declared in the Declarations SymbolTable - var table = GetTableFromScope(Scope.Declarations); - //Add symbol to the dictionary - Add(table.DataTypeEntries, data); + Add(this.DataTypeEntries, data); } public IEnumerable GetVariables(SymbolReference symbolReference) @@ -686,6 +683,13 @@ private static void GetVariablesUnderTypeDefForPublicType(SymbolTable symbolTabl if (temp != null) { resultDataDefinitions.AddRange(temp); } + + //Stop when we reach the first Global scope, because otherwise a nested program can end up searching in it the global scope of its parent + //Global is the most upper scope that can contains Typedef (GlobalStorage cannot contains typedef) + if (currSymbolTable.CurrentScope == Scope.Global) + { + break; + } currSymbolTable = currSymbolTable.EnclosingScope; } @@ -867,7 +871,7 @@ public void AddDataDefinitionsUnderType([NotNull] DataDefinition data) } } - public IList EmptyTypeDefinitionList = new List(); + public List EmptyTypeDefinitionList = new List(); [NotNull] public IList GetType(DataDefinition symbol) { @@ -882,7 +886,7 @@ public List GetType(SymbolReference symbolReference) [NotNull] - public IList GetType(DataType dataType, string pgmName = null) + public List GetType(DataType dataType, string pgmName = null) { if (dataType.CobolLanguageLevel == CobolLanguageLevel.Cobol85) { diff --git a/TypeCobol/Compiler/CompilationUnit.cs b/TypeCobol/Compiler/CompilationUnit.cs index 793c15538..70cbe0b96 100644 --- a/TypeCobol/Compiler/CompilationUnit.cs +++ b/TypeCobol/Compiler/CompilationUnit.cs @@ -173,7 +173,7 @@ public void RefreshProgramClassDocumentSnapshot() SourceFile root = temporarySnapshot.Root; List diagnostics = new List(); Dictionary nodeCodeElementLinkers = temporarySnapshot.NodeCodeElementLinkers ?? new Dictionary(); - ProgramClassParserStep.CrossCheckPrograms(root); + ProgramClassParserStep.CrossCheckPrograms(root, temporarySnapshot); // Capture the result of the parse in a new snapshot ProgramClassDocumentSnapshot = new ProgramClassDocument( @@ -221,11 +221,17 @@ public void ProduceTemporarySemanticDocument() List newDiagnostics; Dictionary nodeCodeElementLinkers = new Dictionary(); + List typedVariablesOutsideTypedef = new List(); + List typeThatNeedTypeLinking = new List(); + //TODO cast to ImmutableList sometimes fails here - ProgramClassParserStep.CupParseProgramOrClass(TextSourceInfo, ((ImmutableList)codeElementsDocument.Lines), CompilerOptions, CustomSymbols, perfStatsForParserInvocation, out root, out newDiagnostics, out nodeCodeElementLinkers); + ProgramClassParserStep.CupParseProgramOrClass(TextSourceInfo, ((ImmutableList)codeElementsDocument.Lines), CompilerOptions, CustomSymbols, perfStatsForParserInvocation, out root, out newDiagnostics, out nodeCodeElementLinkers, + out typedVariablesOutsideTypedef, + out typeThatNeedTypeLinking); // Capture the produced results - TemporaryProgramClassDocumentSnapshot = new TemporarySemanticDocument(codeElementsDocument, new DocumentVersion(this), codeElementsDocument.Lines, root, newDiagnostics, nodeCodeElementLinkers); + TemporaryProgramClassDocumentSnapshot = new TemporarySemanticDocument(codeElementsDocument, new DocumentVersion(this), codeElementsDocument.Lines, root, newDiagnostics, nodeCodeElementLinkers, + typedVariablesOutsideTypedef, typeThatNeedTypeLinking); // Stop perf measurement PerfStatsForTemporarySemantic.OnStopRefreshParsingStep(); diff --git a/TypeCobol/Compiler/CupParser/NodeBuilder/ProgramClassBuilder.cs b/TypeCobol/Compiler/CupParser/NodeBuilder/ProgramClassBuilder.cs index 6d2799b7c..f5a49ea10 100644 --- a/TypeCobol/Compiler/CupParser/NodeBuilder/ProgramClassBuilder.cs +++ b/TypeCobol/Compiler/CupParser/NodeBuilder/ProgramClassBuilder.cs @@ -24,7 +24,19 @@ public class ProgramClassBuilder : IProgramClassBuilder private Program Program { get; set; } public SyntaxTree SyntaxTree { get; set; } - private TypeDefinition _CurrentTypeDefinition; + private TypeDefinition _CurrentTypeDefinition + { + get => _currentTypeDefinition; + set + { + _currentTypeDefinition = value; + //Reset that this type was already added to the list TypeThatNeedTypeLinking + typeAlreadyAddedToTypeToLink = false; + } + } + + private bool typeAlreadyAddedToTypeToLink = false; + private bool _IsInsideWorkingStorageContext; private bool _IsInsideLinkageSectionContext; private bool _IsInsideLocalStorageSectionContext; @@ -32,6 +44,9 @@ public class ProgramClassBuilder : IProgramClassBuilder private bool _IsInsideGlobalStorageSection; private FunctionDeclaration _ProcedureDeclaration; + public List TypedVariablesOutsideTypedef { get; } = new List(); + public List TypeThatNeedTypeLinking { get; } = new List(); + // Programs can be nested => track current programs being analyzed private Stack programsStack = null; @@ -181,25 +196,6 @@ private void ExitLastLevel1Definition() while (CurrentNode.CodeElement != null && CurrentNode.CodeElement is DataDefinitionEntry) Exit(); } - private void AddToSymbolTable(DataDescription node) - { - var table = node.SymbolTable; - if (node.CodeElement.IsGlobal && table.CurrentScope != SymbolTable.Scope.GlobalStorage) - table = table.GetTableFromScope(SymbolTable.Scope.Global); - else - { - var parent = node.Parent as DataDescription; - while (parent != null) - { - if (parent.CodeElement.IsGlobal && table.CurrentScope != SymbolTable.Scope.GlobalStorage) - table = table.GetTableFromScope(SymbolTable.Scope.Global); - parent = parent.Parent as DataDescription; - } - } - - table.AddVariable(node); - } - public virtual void StartCobolCompilationUnit() { if (TableOfNamespaces == null) @@ -415,36 +411,31 @@ public virtual void StartDataDescriptionEntry(DataDescriptionEntry entry) { SetCurrentNodeToTopLevelItem(entry.LevelNumber); + var symbolTable = SyntaxTree.CurrentNode.SymbolTable; + if (entry.IsGlobal) + symbolTable = symbolTable.GetTableFromScope(SymbolTable.Scope.Global); + //Update DataType of CodeElement by searching info on the declared Type into SymbolTable. //Note that the AST is not complete here, but you can only refer to a Type that has previously been defined. var node = new DataDescription(entry); if (_CurrentTypeDefinition != null) node.ParentTypeDefinition = _CurrentTypeDefinition; - Enter(node); + Enter(node, null, symbolTable); if (entry.Indexes != null && entry.Indexes.Any()) { - var table = node.SymbolTable; + foreach (var index in entry.Indexes) { - if (node.CodeElement.IsGlobal) - table = table.GetTableFromScope(SymbolTable.Scope.Global); - var indexNode = new IndexDefinition(index); - Enter(indexNode, null, table); + Enter(indexNode, null, symbolTable); if (_CurrentTypeDefinition != null) indexNode.ParentTypeDefinition = _CurrentTypeDefinition; - table.AddVariable(indexNode); + symbolTable.AddVariable(indexNode); Exit(); } } - var types = node.SymbolTable.GetType(node); - if (types.Count == 1) - { - entry.DataType.RestrictionLevel = types[0].DataType.RestrictionLevel; - } - //else do nothing, it's an error that will be handled by Cobol2002Checker if(_IsInsideWorkingStorageContext) node.SetFlag(Node.Flag.WorkingSectionNode, true); //Set flag to know that this node belongs to Working Storage Section @@ -457,18 +448,55 @@ public virtual void StartDataDescriptionEntry(DataDescriptionEntry entry) if (_IsInsideGlobalStorageSection) node.SetFlag(Node.Flag.GlobalStorageSection, true); //Set flag to know that this node belongs to Global Storage Section - AddToSymbolTable(node); + node.SymbolTable.AddVariable(node); + CheckIfItsTyped(node, node.CodeElement); } } + private void CheckIfItsTyped(DataDefinition dataDefinition, CommonDataDescriptionAndDataRedefines commonDataDescriptionAndDataRedefines) + { + //Is a type referenced + if (commonDataDescriptionAndDataRedefines.UserDefinedDataType != null) + { + if (_CurrentTypeDefinition != null) + { + _CurrentTypeDefinition.TypedChildren.Add(dataDefinition); + } + else + { + TypedVariablesOutsideTypedef.Add(dataDefinition); + } + } + + //Special case for Depending On. + //Depending on inside typedef can reference other variable declared in type referenced in this typedef + //To resolve variable after "depending on" we first have to resolve all types used in this typedef. + //This resolution must be recursive until all sub types have been resolved. + if (commonDataDescriptionAndDataRedefines.OccursDependingOn != null) + { + if (_CurrentTypeDefinition != null && !typeAlreadyAddedToTypeToLink) + { + TypeThatNeedTypeLinking.Add(_CurrentTypeDefinition); + typeAlreadyAddedToTypeToLink = true; + } + } + } + + public virtual void StartDataRedefinesEntry(DataRedefinesEntry entry) { SetCurrentNodeToTopLevelItem(entry.LevelNumber); + var symbolTable = SyntaxTree.CurrentNode.SymbolTable; + if (entry.IsGlobal) + symbolTable = symbolTable.GetTableFromScope(SymbolTable.Scope.Global); + var node = new DataRedefines(entry); if (_CurrentTypeDefinition != null) node.ParentTypeDefinition = _CurrentTypeDefinition; - Enter(node); + Enter(node, null, symbolTable); node.SymbolTable.AddVariable(node); + + CheckIfItsTyped(node, node.CodeElement); } public virtual void StartDataRenamesEntry(DataRenamesEntry entry) @@ -494,13 +522,17 @@ public virtual void StartDataConditionEntry(DataConditionEntry entry) public virtual void StartTypeDefinitionEntry(DataTypeDescriptionEntry typedef) { SetCurrentNodeToTopLevelItem(typedef.LevelNumber); - var node = new TypeDefinition(typedef); - Enter(node); + // TCTYPE_GLOBAL_TYPEDEF - var table = node.SymbolTable.GetTableFromScope(node.CodeElement.IsGlobal ? SymbolTable.Scope.Global : SymbolTable.Scope.Declarations); - table.AddType(node); + var symbolTable = SyntaxTree.CurrentNode.SymbolTable.GetTableFromScope(typedef.IsGlobal ? SymbolTable.Scope.Global : SymbolTable.Scope.Declarations); + + var node = new TypeDefinition(typedef); + Enter(node, null, symbolTable); + + symbolTable.AddType(node); _CurrentTypeDefinition = node; + CheckIfItsTyped(node, node.CodeElement); } public virtual void StartWorkingStorageSection(WorkingStorageSectionHeader header) @@ -586,6 +618,8 @@ public virtual void EnterUseStatement(UseStatement useStatement) } private Tools.UIDStore uidfactory = new Tools.UIDStore(); + private TypeDefinition _currentTypeDefinition; + public virtual void StartFunctionDeclaration(FunctionDeclarationHeader header) { header.SetLibrary(CurrentProgram.Identification.ProgramName.Name); @@ -617,6 +651,7 @@ public virtual void StartFunctionDeclaration(FunctionDeclarationHeader header) paramNode.SetParent(CurrentNode); CurrentNode.SymbolTable.AddVariable(paramNode); + CheckIfItsTyped(paramNode, paramNode.CodeElement); } foreach (var parameter in declaration.Profile.OutputParameters) //Set Output Parameters { @@ -628,6 +663,7 @@ public virtual void StartFunctionDeclaration(FunctionDeclarationHeader header) paramNode.SetParent(CurrentNode); CurrentNode.SymbolTable.AddVariable(paramNode); + CheckIfItsTyped(paramNode, paramNode.CodeElement); } foreach (var parameter in declaration.Profile.InoutParameters) //Set Inout Parameters { @@ -639,6 +675,7 @@ public virtual void StartFunctionDeclaration(FunctionDeclarationHeader header) paramNode.SetParent(CurrentNode); CurrentNode.SymbolTable.AddVariable(paramNode); + CheckIfItsTyped(paramNode, paramNode.CodeElement); } if (declaration.Profile.ReturningParameter != null) //Set Returning Parameters @@ -650,6 +687,7 @@ public virtual void StartFunctionDeclaration(FunctionDeclarationHeader header) paramNode.SetParent(CurrentNode); CurrentNode.SymbolTable.AddVariable(paramNode); + CheckIfItsTyped(paramNode, paramNode.CodeElement); } } diff --git a/TypeCobol/Compiler/Diagnostics/Cobol2002Checker.cs b/TypeCobol/Compiler/Diagnostics/Cobol2002Checker.cs index ab1a83f95..d0bebc3bf 100644 --- a/TypeCobol/Compiler/Diagnostics/Cobol2002Checker.cs +++ b/TypeCobol/Compiler/Diagnostics/Cobol2002Checker.cs @@ -113,6 +113,9 @@ public static void CheckTypeDefinition(TypeDefinition typeDefinition) token, code: MessageCode.Warning); } } + + //Check circular reference if not already done by TypeCobolLinker + TypeCobolLinker.CheckCircularReferences(typeDefinition); } private static void CheckForValueClause(Node node, string typedefName) @@ -233,8 +236,7 @@ public static void OnNode(Node node) } var type = dataDefinition.DataType; - TypeDefinition foundedType = null; - TypeDefinitionHelper.Check(node, type, out foundedType); //Check if the type exists and is not ambiguous + TypeDefinition foundedType = dataDefinition.TypeDefinition; if (foundedType == null || data == null || data.LevelNumber == null) return; @@ -277,7 +279,13 @@ public static void OnNode(Node node) private static long SimulatedTypeDefLevel(long startingLevel, DataDefinition node) { + if (node == null)//case where the type of variable is not found + { + return startingLevel; + } + var maximalLevelReached = startingLevel; + if (node is TypeDefinition) { @@ -291,22 +299,7 @@ private static long SimulatedTypeDefLevel(long startingLevel, DataDefinition nod var calculatedLevel = startingLevel; if (child.DataType.CobolLanguageLevel > CobolLanguageLevel.Cobol85) //If variable is typed { - /*----- This section should be removed when issue #1009 is fixed ----- */ - /*----- We'll only need child.TypeDefinition --------------------------*/ - TypeDefinition foundType; - if (child.TypeDefinition == null) - { - var foundedTypes = node.SymbolTable.GetType(child.DataType); - if (foundedTypes.Count != 1) - continue; //If none or multiple corresponding type, it's useless to check - - foundType = foundedTypes.First(); - } - else - foundType = child.TypeDefinition; - /* ----------------------------------------------------------------- */ - - calculatedLevel = SimulatedTypeDefLevel(++calculatedLevel, foundType); + calculatedLevel = SimulatedTypeDefLevel(++calculatedLevel, child.TypeDefinition); } else if (child.Children.Count > 0) //If variable is not typed, check if there is children { @@ -323,47 +316,5 @@ private static long SimulatedTypeDefLevel(long startingLevel, DataDefinition nod return maximalLevelReached; } } - - public static class TypeDefinitionHelper - { - /// - /// Generic method to check if a type is referenced or not or if it is ambiguous. - /// - /// - /// - /// - public static void Check(Node node, DataType type, out TypeDefinition foundedType) - { - foundedType = null; - if (type.CobolLanguageLevel == CobolLanguageLevel.Cobol85) - return; //nothing to do, Type exists from Cobol 2002 - var dataDefinition = node as DataDefinition; - if (dataDefinition?.TypeDefinition != null) - { - foundedType = dataDefinition.TypeDefinition; - return; - } - - var found = node.SymbolTable.GetType(type); - if (found.Count < 1) - { - string message = "TYPE \'" + type.Name + "\' is not referenced"; - DiagnosticUtils.AddError(node, message, MessageCode.SemanticTCErrorInParser); - } - else if (found.Count > 1) - { - string message = "Ambiguous reference to TYPE \'" + type.Name + "\'"; - DiagnosticUtils.AddError(node, message, MessageCode.SemanticTCErrorInParser); - } - else - { - //In case TypeDefinition is not already set, or it's not a DataDefinition Node - foundedType = found[0]; - if (dataDefinition != null) - dataDefinition.TypeDefinition = foundedType; - } - - } - - } + } \ No newline at end of file diff --git a/TypeCobol/Compiler/Diagnostics/TypeCobolChecker.cs b/TypeCobol/Compiler/Diagnostics/TypeCobolChecker.cs index 2e95df375..35e75a247 100644 --- a/TypeCobol/Compiler/Diagnostics/TypeCobolChecker.cs +++ b/TypeCobol/Compiler/Diagnostics/TypeCobolChecker.cs @@ -229,6 +229,16 @@ private static void Check(Node node, [NotNull] FunctionCall call, for (int c = 0; c < parameters.Count; c++) { var expected = parameters[c]; + + //Hack until we get a real concept of project to build all of the dependencies + if (expected.CodeElement.UserDefinedDataType != null && expected.TypeDefinition == null) + { + TypeCobolLinker.ResolveType(expected); + if (expected.TypeDefinition != null) + { + TypeCobolLinker.CheckCircularReferences(expected.TypeDefinition); + } + } if (c < callArgsCount) { //Omitted diff --git a/TypeCobol/Compiler/Diagnostics/TypeCobolLinker.cs b/TypeCobol/Compiler/Diagnostics/TypeCobolLinker.cs index ec9116646..34c2c0107 100644 --- a/TypeCobol/Compiler/Diagnostics/TypeCobolLinker.cs +++ b/TypeCobol/Compiler/Diagnostics/TypeCobolLinker.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using JetBrains.Annotations; using TypeCobol.Compiler.CodeElements; using TypeCobol.Compiler.CodeElements.Expressions; using TypeCobol.Compiler.CodeModel; @@ -11,142 +12,344 @@ namespace TypeCobol.Compiler.Diagnostics { - public class TypeCobolLinker : AbstractAstVisitor + /// + /// TypeCobolLinker is responsible for: + /// - Resolve TypeDefinition. + /// - It's the only class that can call SymbolTable.GetType() and set the property TypeDefinition on DataDefinition node + /// - Check circular reference between types + /// - Create a path between type reference and TypeDefinition in the SymbolTable (property SymbolTable.TypesReferences) + /// - It's the only class that can update SymbolTable.TypesReferences + /// - This path is not set for unused types + /// + /// + /// What is the "path" between type ? (SymbolTable.TypesReferences) + /// ---------------------------------------------------------- + /// The path between type is used to search variables which are located under a typedef + /// and then find if a variable outside reference this type (directly or indirectly). + /// The path will link a DataDefinition that use the syntax (type XXXX) to a TypeDefinition. + /// + /// + /// Group1 TypeA TypeB TypeC + /// var1 A11 type typeB B1 C1 + /// var11 type typeA B2 C2 + /// B3 type typeC C3 + /// + /// + /// Eg, with this SymbolReference: + /// var11::A11::B3::C3 + /// + /// We'll first find C3 under TypeC, then we need to know all DataDefinition that references TypeC. + /// So the path must start with: TypeC->B3 + /// Then again, after B3 is found under TypeB, we need to find DataDefinition that references TypeB. + /// The path must continue with: TypeB->A11 + /// ... + /// At the end, the full path path will be: TypeC->B3, TypeB->A11, TypeA->var11 + /// As var11 is a variable outside a TypeDef, the path ends here. + /// + /// With the same SymbolReference but fully qualified: + /// var11::A11::B1::B2::B3::C1::C2::C3 + /// The path will be exactly the same. + /// The path doesn't contains intermediate group-item. + /// + /// + /// Now when there are more Data/Definition/TypeDef + /// + /// Group1 TypeA TypeB TypeC + /// var1 A11 type typeB B1 C1 + /// var11 type typeA B2 C2 + /// B3 type typeC C3 + /// + /// Group2 TypeZ + /// var22 Z11 type typeB + /// var222 type typeZ + /// + /// With a SymbolReference with Group2 it's the same logic. + /// var222::Z11::B3::C3 + /// The path will be: + /// TypeC->B3, TypeB->Z11, TypeZ->var222 + /// + /// + /// + /// How the path is calculated/stored ? (SymbolTable.TypesReferences) + /// ------------------------------------------------------------------ + /// The path will always contains a DataDefinition outside a Type. + /// So we use the SymbolTable of this DataDefinition to store the full path. + /// + /// In the previous example, if Group1 and Group2 are in 2 different SymbolTable, it means the full path will be stored twice. + /// It takes more time to construct the path but it ensure that when we use a path we'll always be sure to find variables accessible/visible to our SymbolTable. + /// + /// + /// If all paths were common to all SymbolTable, then if Group1 and Group2 are in 2 different programs, there would be 2 downsides: + /// - We'll spend time using path that takes us outside our visibility scope. + /// - It's not a real problem on our unit test, but on big programs with a lot of dependencies this would be an issue. + /// - At the end we need to check if the variable is accessible to our scope + /// + /// + /// + /// Optimization on path storage (SymbolTable.TypesReferences) + /// ------------------------------------------------------------ + /// When 2 or more variable inside a typedef reference the same type, TypeCobolLinker will detect that and only store the path once. + /// + /// + /// + public class TypeCobolLinker { - public override bool BeginNode(Node node) - { - return base.BeginNode(node); - } - public override bool BeginCodeElement(CodeElement codeElement) - { - return false; //We don't want to check deeper than Node - } - public override bool Visit(DataDescription dataEntry) - { - TypeReferencer(dataEntry, dataEntry.SymbolTable); - return true; - } - public override bool Visit(Paragraph paragraph) + /// + /// This method will do the 3 actions: + /// - Resolve TypeDefinition + /// - Check circular references + /// - Create a path between type reference and TypeDefinition + /// + /// Variable outside that use the "type" syntax + /// Typedef that need all its typed children to be resolved (only use case for now is "Depending on") + public static void LinkedTypedVariables([NotNull][ItemNotNull] in List typedVariablesOutsideTypedef, + [NotNull][ItemNotNull] in List typeThatNeedTypeLinking) { - return false; - } + //Stack to detect circular reference between types + Stack currentlyCheckedTypedefStack = new Stack(); - public override bool Visit(Section section) - { - return false; - } + foreach (var dataDefinition in typedVariablesOutsideTypedef) + { + //Warning, when you ask to parse multiple input files with CLI, then TypeDefinition of typedVariablesOutsideTypedef can already be resolved - public override bool Visit(EnvironmentDivision environmentDivision) - { - return false; - } - public override bool IsStopVisitingChildren => false; + if (ResolveType(dataDefinition)) //If type has been found in SymbolTable + { + //Reference the path between the typedDataDefChild and its TypeDefinition on the SymbolTable on the original DataDefinition outside a typedef + if (dataDefinition.SymbolTable.TypesReferences.TryGetValue(dataDefinition.TypeDefinition, out var dataDefsThatReferencedThisType)) + { + //Link between the type and the dataDefinition cannot already be done + System.Diagnostics.Debug.Assert(!dataDefsThatReferencedThisType.Contains(dataDefinition)); - /// - /// Do not visit children of IF. - /// Just in case there are statements directly under the procedure division. - /// - public override bool Visit(If _) => false; + //Type already referenced in our SymbolTable, it means all further typed children of the type have already been linked into this SymbolTable + dataDefsThatReferencedThisType.Add(dataDefinition); + } + else + { + dataDefinition.SymbolTable.TypesReferences.Add(dataDefinition.TypeDefinition, new List { dataDefinition }); - /// - /// Do not visit children of Evaluate. - /// Just in case there are statements directly under the procedure division. - /// - public override bool Visit(Evaluate _) => false; + //First time this TypeDefinition is added to dataDefinition.SymbolTable, then link all children of the type + LinkTypedChildren(dataDefinition.TypeDefinition, currentlyCheckedTypedefStack, dataDefinition.SymbolTable); + } + } + } - /// - /// Do not visit children of Perform. - /// Just in case there are statements directly under the procedure division. - /// - public override bool Visit(Perform _) => false; - public override bool Visit(Declaratives declaratives) - { - return false; + //Now link type that use depending On + System.Diagnostics.Debug.Assert(currentlyCheckedTypedefStack.Count == 0, "Stack must be empty"); + foreach (var typeDefinition in typeThatNeedTypeLinking) + { + LinkTypedChildren(typeDefinition, currentlyCheckedTypedefStack, typeDefinition.SymbolTable); + } } - public override bool Visit(ProcedureDivision procedureDivision) - { - var parent = procedureDivision.Parent as Program; - return parent != null && base.Visit(procedureDivision); - } - public override bool Visit(FunctionDeclaration funcDeclare) + public static void CheckCircularReferences([NotNull] TypeDefinition typeDefinition) { - //Get Function declaration parameters - var parameters = funcDeclare.Profile.Parameters; - if(funcDeclare.Profile.ReturningParameter != null) - parameters.Add(funcDeclare.Profile.ReturningParameter); - - foreach (var dataEntry in parameters) + + if (typeDefinition.TypedChildren.Count == 0 //no typed children + || typeDefinition.TypedChildren[0] == null //TypeDefinition of first children could not be resolved + || typeDefinition.TypedChildren[0].TypeDefinition != null) //TypeDefinition of first children already resolved { - TypeReferencer(dataEntry, dataEntry.SymbolTable); + //In these case, nothing to do because no children or job has already be done + return; } - return base.Visit(funcDeclare); + //Stack to detect circular reference between types + Stack currentlyCheckedTypedefStack = new Stack(); + LinkTypedChildren(typeDefinition, currentlyCheckedTypedefStack); } - private void TypeReferencer(DataDescription dataEntry, SymbolTable symbolTable) + /// + /// This method will do the 3 actions: + /// - Resolve TypeDefinition + /// - Check circular references + /// - Create a path between type reference and TypeDefinition + /// + /// + /// + /// + /// + private static void LinkTypedChildren([NotNull] TypeDefinition typeDefinition, + [CanBeNull] Stack currentlyCheckedTypedefStack0, [CanBeNull] SymbolTable symbolTable = null) { - if (symbolTable == null) return; - var types = symbolTable.GetType(dataEntry.DataType); - if (types.Count != 1) + + if (typeDefinition.TypedChildren.Count == 0) { - //Check the existing children, if they use a type - foreach (var child in dataEntry.Children) - { - if (child is DataDescription childDataDesc) - TypeReferencer(childDataDesc, symbolTable); - } return; } - var type = types.First(); - dataEntry.TypeDefinition = type; //Set the TypeDefinition on DataDefinition Node so to avoid symbolTable access + currentlyCheckedTypedefStack0?.Push(typeDefinition); + LinkTypedChildren0(currentlyCheckedTypedefStack0); + currentlyCheckedTypedefStack0?.Pop(); + + - //Check circular type reference - if (dataEntry.IsPartOfATypeDef) + //Only reason to use private method here, is because there are multiple return path in LinkTypedChildren0. + //So we can easily handle currentlyCheckedTypedefStack push/pop just above + void LinkTypedChildren0(Stack currentlyCheckedTypedefStack) { - var circularRefInsideChildren = type.Children.Any(c => + //If all typed children of typedef are resolved it means this typedef has already been fully linked + if (typeDefinition.TypedChildren[typeDefinition.TypedChildren.Count - 1] == null || typeDefinition.TypedChildren[typeDefinition.TypedChildren.Count - 1]?.TypeDefinition != null) { - DataDefinition dataChild = (DataDefinition)c; - var childrenType = symbolTable.GetType(dataChild.DataType).FirstOrDefault(); - if (childrenType == null) return false; - return dataEntry.ParentTypeDefinition == childrenType; //Circular reference detected will return true - }); + //If symbolTable is null, it means we don't want to register link between TypeDefinition and DataDefinition that use it + //So we can stop here. + if (symbolTable == null) + { + return; + } + + currentlyCheckedTypedefStack = null; //As typedef has already been linked, then no need to check circular reference + } - if (type == dataEntry.ParentTypeDefinition || circularRefInsideChildren) + for (var i = 0; i < typeDefinition.TypedChildren.Count; i++) { - DiagnosticUtils.AddError(dataEntry, "Type circular reference detected", - dataEntry.CodeElement, code: MessageCode.SemanticTCErrorInParser); - return; //Do not continue to prevent further work/crash with circular references + var typedDataDefChild = typeDefinition.TypedChildren[i]; + //If a typedDataDefChild is null it means is TypeDefinition could not be resolved or is part of a circular reference. + //So let's continue to the next child. + if (typedDataDefChild == null) + { + continue; + } + + + //Resolve type of typedDataDefChild if not already done yet + if (typedDataDefChild.TypeDefinition == null) + { + if (!ResolveType(typedDataDefChild)) //Use the symbolTable of this typedDataDefChild to resolve the type + { + //No TypeDefinition found + typeDefinition.TypedChildren[i] = null; //set to null so we don't try to check its TypeDefinition another time. + continue; //Go to the next typed child + } + } + + + System.Diagnostics.Debug.Assert(typedDataDefChild.TypeDefinition != null); //type must be resolved now + + + //Detect circular reference + if (currentlyCheckedTypedefStack?.Contains(typedDataDefChild.TypeDefinition) == true) + { + typeDefinition.TypedChildren[i] = null; //set this typed child to null so we don't enter this infinite loop another time + DiagnosticUtils.AddError(typedDataDefChild, "Type circular reference detected : " + + string.Join(" -> ", currentlyCheckedTypedefStack.Select(t => t.Name)), code: MessageCode.SemanticTCErrorInParser); + + continue;//Go to the next typedChildren + //Do not make the link in symbolTable.TypesReferences with method ReferenceThisDataDefByThisType to avoid infinite loop in SymbolTable + } + + + if (symbolTable != null)//If we need to keep references between typed variable and type + { + //Reference the path between the typedDataDefChild and its TypeDefinition on the SymbolTable on the original DataDefinition outside a typedef + if (!ReferenceThisDataDefByThisType(symbolTable, typedDataDefChild)) + { + continue; //Type was already linked, so stop here + } + } + + + //Continue to link children of typedDataDefChild.TypeDefinition + LinkTypedChildren(typedDataDefChild.TypeDefinition, currentlyCheckedTypedefStack, symbolTable); } } + } - if (dataEntry.CodeElement.IsGlobal) - symbolTable = symbolTable.GetTableFromScope(SymbolTable.Scope.Global); + /// + /// Lookup the TypeDefinition from the DataType of this dataDefinition. + /// If no TypeDefinition can be found, then property TypeDefinition stay null. + /// + /// + /// true if type has been resolved + public static bool ResolveType([NotNull] in DataDefinition dataDefinition) + { + //Note : dataDefinition.CodeElement cannot be null, only Index have a null CodeElement and Index cannot be typed - - if (symbolTable.TypesReferences.ContainsKey(type)) //If datatype already exists, add ref to the list + + //Special hack until Visibility are fixed (#1081 and #938) + //As "Global" and "GlobalStorage" Scopes are above "Declarations" they cannot have access to "Declarations" scope. + //So types in "Declarations" scope cannot be reached from the SymbolTable of a variable declared as global or a variable inside global-storage. + + //But a variable NOT global and not in global-storage can access the SymbolTable "Declarations" and "Global". + //So if we are in scopes "Global" or "GlobalStorage" we first need to retrieve a SymbolTable under "Declarations" and resolve the type using this SymbolTable. + List types; + SymbolTable declarationsSymbolTable; + if (dataDefinition.SymbolTable.CurrentScope <= SymbolTable.Scope.Global) { - if (!symbolTable.TypesReferences[type].Contains(dataEntry)) - symbolTable.TypesReferences[type].Add(dataEntry); + //Retrieve the Scope Declarations by retrieving the SymbolTable of the program which is of Scope "Program". + //Then use the EnclosingScope which is of scope "Declarations" + declarationsSymbolTable = dataDefinition.GetProgramNode().SymbolTable.EnclosingScope; } else { - symbolTable.TypesReferences.Add(type, new List {dataEntry}); + declarationsSymbolTable = dataDefinition.SymbolTable; } + System.Diagnostics.Debug.Assert(declarationsSymbolTable.CurrentScope >= SymbolTable.Scope.Declarations, "Scope of SymbolTable must be under Declarations until (#1081 and #938) are fixed"); + + types = declarationsSymbolTable.GetType(dataDefinition.CodeElement.DataType); + //End special hack - //Also add all the typedChildren to reference list - foreach (var dataDescTypeChild in type.Children.Where(c => c is DataDescription)) + //When (#1081 and #938) are fixed, remove the hack above and simply use the following line: + //var types = dataDefinition.SymbolTable.GetType(dataDefinition.CodeElement.DataType); + + + + if (types.Count < 1) + { + string message = "TYPE \'" + dataDefinition.CodeElement.DataType + "\' is not referenced"; + DiagnosticUtils.AddError(dataDefinition, message, MessageCode.SemanticTCErrorInParser); + } + else if (types.Count > 1) { - TypeReferencer(dataDescTypeChild as DataDescription, symbolTable); + string message = "Ambiguous reference to TYPE \'" + dataDefinition.CodeElement.DataType + "\'"; + DiagnosticUtils.AddError(dataDefinition, message, MessageCode.SemanticTCErrorInParser); } + else + { + dataDefinition.TypeDefinition = types[0]; + dataDefinition.DataType.RestrictionLevel = types[0].DataType.RestrictionLevel; + return true; + } + + return false; } - + + /// + /// + /// + /// + /// Data definition that reference a Type. + /// true if reference has been set. False is reference was already made + private static bool ReferenceThisDataDefByThisType([NotNull] in SymbolTable symbolTable, [NotNull] in DataDefinition dataDefinition) + { + //Reminder on symbolTable.TypesReferences Dictionary + //Key is TypeDefinition, Value is List + // + //TypesReferences can be understood/read as: + //TypeDefinition is referenced by these DataDefinitions + + + //Do NOT use the SymbolTable of the DataDefinition because we are linking all types references to the first + //dataDefinition outside typedef (see explanation at top of the class). + if (symbolTable.TypesReferences.TryGetValue(dataDefinition.TypeDefinition, out var dataDefsThatReferencedThisType)) + { + if (dataDefsThatReferencedThisType.Contains(dataDefinition)) + { + return false; + } + dataDefsThatReferencedThisType.Add(dataDefinition); + } + else + { + //Same here, don't use the SymbolTable of the DataDefinition + symbolTable.TypesReferences.Add(dataDefinition.TypeDefinition, new List { dataDefinition }); + } + + return true; + } } } diff --git a/TypeCobol/Compiler/Nodes/Data.cs b/TypeCobol/Compiler/Nodes/Data.cs index 338b508f1..9ab361cce 100644 --- a/TypeCobol/Compiler/Nodes/Data.cs +++ b/TypeCobol/Compiler/Nodes/Data.cs @@ -261,6 +261,7 @@ public TypeDefinition TypeDefinition get { return _typeDefinition; } set { + //Implementation note : Only TypeCobolLinker should set this value if (_typeDefinition == null) _typeDefinition = value; } @@ -815,7 +816,10 @@ public override bool VisitNode(IASTVisitor astVisitor) // [COBOL 2002] public class TypeDefinition: DataDefinition, Parent, IDocumentable { - public TypeDefinition([NotNull] DataTypeDescriptionEntry entry) : base(entry) { } + public TypeDefinition([NotNull] DataTypeDescriptionEntry entry) : base(entry) + { + TypedChildren = new List(); + } [NotNull] public new DataTypeDescriptionEntry CodeElement => (DataTypeDescriptionEntry) base.CodeElement; @@ -826,6 +830,17 @@ public override bool VisitNode(IASTVisitor astVisitor) return base.VisitNode(astVisitor) && astVisitor.Visit(this); } + /// + /// List of all children that reference a type. + /// Element of this list can be null if : + /// - the child reference an unknown type, it'll be set to null in this list. + /// - We detect a circular reference between type. To avoid infinite loop one link of the circular reference will be set to null. + /// + /// ProgramClassBuilder to initialize this list. + /// Only TypeCobolLinker can check the link and set items to null. + /// + [NotNull][ItemCanBeNull] + public List TypedChildren { get; } public override bool IsPartOfATypeDef => true; diff --git a/TypeCobol/Compiler/Parser/ProgramClassParserStep.cs b/TypeCobol/Compiler/Parser/ProgramClassParserStep.cs index 9eb3d07bc..19405b3b5 100644 --- a/TypeCobol/Compiler/Parser/ProgramClassParserStep.cs +++ b/TypeCobol/Compiler/Parser/ProgramClassParserStep.cs @@ -48,7 +48,10 @@ public static void PrepareCupParser() } } } - public static void CupParseProgramOrClass(TextSourceInfo textSourceInfo, ISearchableReadOnlyList codeElementsLines, TypeCobolOptions compilerOptions, SymbolTable customSymbols, PerfStatsForParserInvocation perfStatsForParserInvocation, out SourceFile root, out List diagnostics, out Dictionary nodeCodeElementLinkers) + public static void CupParseProgramOrClass(TextSourceInfo textSourceInfo, ISearchableReadOnlyList codeElementsLines, TypeCobolOptions compilerOptions, SymbolTable customSymbols, PerfStatsForParserInvocation perfStatsForParserInvocation, out SourceFile root, out List diagnostics, + out Dictionary nodeCodeElementLinkers, + out List typedVariablesOutsideTypedef, + out List typeThatNeedTypeLinking) { PrepareCupParser(); #if DEBUG_ANTRL_CUP_TIME @@ -89,8 +92,6 @@ public static void CupParseProgramOrClass(TextSourceInfo textSourceInfo, ISearch perfStatsForParserInvocation.OnStartTreeBuilding(); - //Create link between data definition an Types, will be stored in SymbolTable - root.AcceptASTVisitor(new TypeCobolLinker()); //Stop measuring tree building performance perfStatsForParserInvocation.OnStopTreeBuilding(); @@ -98,6 +99,8 @@ public static void CupParseProgramOrClass(TextSourceInfo textSourceInfo, ISearch // Register compiler results diagnostics = diagReporter.Diagnostics ?? new List(); nodeCodeElementLinkers = builder.NodeCodeElementLinkers; + typedVariablesOutsideTypedef = builder.TypedVariablesOutsideTypedef; + typeThatNeedTypeLinking = builder.TypeThatNeedTypeLinking; if (programClassBuilderError != null) { @@ -105,8 +108,12 @@ public static void CupParseProgramOrClass(TextSourceInfo textSourceInfo, ISearch } } - public static void CrossCheckPrograms(SourceFile root) + public static void CrossCheckPrograms(SourceFile root, TemporarySemanticDocument temporarySemanticDocument) { + //Create link between data definition an Types, will be stored in SymbolTable + TypeCobolLinker.LinkedTypedVariables(temporarySemanticDocument.TypedVariablesOutsideTypedef, + temporarySemanticDocument.TypeThatNeedTypeLinking); + //Complete some information on Node and run checker that need a full AST root.AcceptASTVisitor(new CrossCompleteChecker()); } diff --git a/TypeCobol/Compiler/Parser/TemporarySemanticDocument.cs b/TypeCobol/Compiler/Parser/TemporarySemanticDocument.cs index 0d81b4e17..865b163cf 100644 --- a/TypeCobol/Compiler/Parser/TemporarySemanticDocument.cs +++ b/TypeCobol/Compiler/Parser/TemporarySemanticDocument.cs @@ -12,7 +12,11 @@ namespace TypeCobol.Compiler.Parser public class TemporarySemanticDocument : ICompilerStepDocumentSnapshot { - public TemporarySemanticDocument(CodeElementsDocument previousSnapShot, DocumentVersion codeElementsLinesVersion, ISearchableReadOnlyList codeElementsLines, SourceFile root, [NotNull] List diagnostics, Dictionary nodeCodeElementLinkers) + public TemporarySemanticDocument(CodeElementsDocument previousSnapShot, DocumentVersion codeElementsLinesVersion, + ISearchableReadOnlyList codeElementsLines, SourceFile root, [NotNull] List diagnostics, + Dictionary nodeCodeElementLinkers, + List typedVariablesOutsideTypedef, + List typeThatNeedTypeLinking) { PreviousStepSnapshot = previousSnapShot; Root = root; @@ -21,11 +25,21 @@ public TemporarySemanticDocument(CodeElementsDocument previousSnapShot, Document TextSourceInfo = previousSnapShot.TextSourceInfo; CurrentVersion = codeElementsLinesVersion; Lines = codeElementsLines; + TypedVariablesOutsideTypedef = typedVariablesOutsideTypedef; + TypeThatNeedTypeLinking = typeThatNeedTypeLinking; } public TextSourceInfo TextSourceInfo { get; set; } public SourceFile Root { get; private set; } public Dictionary NodeCodeElementLinkers { get; private set; } + + + [NotNull] [ItemNotNull] + public List TypedVariablesOutsideTypedef { get; } + + [NotNull][ItemNotNull] + public List TypeThatNeedTypeLinking { get; } + /// /// Errors found while parsing Program or Class ///