//////////////////// // PROCEDURE CALL // //////////////////// public override void EnterTcCallStatement(CodeElementsParser.TcCallStatementContext context) { var cbCallProc = context.procedurePointerOrFunctionPointerVariableOrfunctionNameReference; // Register call parameters (shared storage areas) information at the CodeElement level CallSite callSite = null; ProcedureStyleCallStatement statement = null; Context = context; //Incomplete CallStatement, create an empty CodeElement and return + Error due to issue #774 if (cbCallProc == null) { CodeElement = new ProcedureStyleCallStatement { Diagnostics = new List <Diagnostic> { new Diagnostic(MessageCode.SyntaxErrorInParser, context.Start.Column, context.Stop.Column, context.Start.Line, "Empty CALL is not authorized") } }; return; } //Here ambiguousSymbolReference with either CandidatesType: // - ProgramNameOrProgramEntry // - data, condition, UPSISwitch, TCFunctionName var ambiguousSymbolReference = CobolExpressionsBuilder.CreateProcedurePointerOrFunctionPointerVariableOrTCFunctionProcedure(cbCallProc); //If (inputs, inouts ou outputs).Count > 0, then it's a procedure call if (context.callOutputParameter().Length > 0 || context.callInputParameter().Length > 0 || context.callInoutParameter().Length > 0) { callSite = new CallSite(); #region Setup Input Output Inout CallSitesParameters var inputs = new List <CallSiteParameter>(); var inouts = new List <CallSiteParameter>(); var outputs = new List <CallSiteParameter>(); SyntaxProperty <ParameterSharingMode> mode = null; foreach (var p in context.callInputParameter()) { CreateSharingMode(p, ref mode); // TCRFUN_INPUT_BY var callSiteParameter = new CallSiteParameter { SharingMode = mode, }; if (p.sharedVariableOrFileName() != null) { callSiteParameter.StorageAreaOrValue = CobolExpressionsBuilder.CreateSharedVariableOrFileName(p.sharedVariableOrFileName()); } else if (p.OMITTED() != null) { callSiteParameter.Omitted = new SyntaxProperty <bool>(true, ParseTreeUtils.GetFirstToken(p.OMITTED())); } if (p.sharedVariableOrFileName() != null || p.OMITTED() != null) { inputs.Add(callSiteParameter); } } foreach (var p in context.callInoutParameter()) { var callSiteParameter = new CallSiteParameter { // TCRFUN_CALL_INOUT_AND_OUTPUT_BY_REFERENCE SharingMode = new SyntaxProperty <ParameterSharingMode>(ParameterSharingMode.ByReference, null), }; if (p.sharedStorageArea1() != null) { callSiteParameter.StorageAreaOrValue = new Variable(CobolExpressionsBuilder.CreateSharedStorageArea(p.sharedStorageArea1())); } else if (p.OMITTED() != null) { callSiteParameter.Omitted = new SyntaxProperty <bool>(true, ParseTreeUtils.GetFirstToken(p.OMITTED())); } if (p.sharedStorageArea1() != null || p.OMITTED() != null) { inouts.Add(callSiteParameter); } } foreach (var p in context.callOutputParameter()) { var callSiteParameter = new CallSiteParameter { // TCRFUN_CALL_INOUT_AND_OUTPUT_BY_REFERENCE SharingMode = new SyntaxProperty <ParameterSharingMode>(ParameterSharingMode.ByReference, null), }; if (p.sharedStorageArea1() != null) { callSiteParameter.StorageAreaOrValue = new Variable(CobolExpressionsBuilder.CreateSharedStorageArea(p.sharedStorageArea1())); } else if (p.OMITTED() != null) { callSiteParameter.Omitted = new SyntaxProperty <bool>(true, ParseTreeUtils.GetFirstToken(p.OMITTED())); } if (p.sharedStorageArea1() != null || p.OMITTED() != null) { outputs.Add(callSiteParameter); } } int parametersCount = inputs.Count + outputs.Count + inouts.Count; callSite.Parameters = new CallSiteParameter[parametersCount]; int i = 0; //Add inputs to global callsites parameters if (inputs.Count > 0) { foreach (var param in inputs) { callSite.Parameters[i] = param; i++; } } //Add outputs to global callsites parameters if (outputs.Count > 0) { foreach (var param in outputs) { callSite.Parameters[i] = param; i++; } } //Add inouts to global callsites parameters if (inouts.Count > 0) { foreach (var param in inouts) { callSite.Parameters[i] = param; i++; } } #endregion //Check Type or CandidatesTypes to see if a TCFunctionName is possible if (ambiguousSymbolReference.MainSymbolReference != null && ambiguousSymbolReference.MainSymbolReference.IsOrCanBeOfType(SymbolType.TCFunctionName)) { SymbolReferenceVariable TCFunctionNameRefVariable; if (ambiguousSymbolReference.MainSymbolReference.IsQualifiedReference) { var nonAmbiguousHead = new SymbolReference( (ambiguousSymbolReference.MainSymbolReference as TypeCobolQualifiedSymbolReference)?.Head .NameLiteral, SymbolType.TCFunctionName); var nonAmbiguousTail = new SymbolReference( (ambiguousSymbolReference.MainSymbolReference as TypeCobolQualifiedSymbolReference)?.Tail .NameLiteral, SymbolType.ProgramName); TypeCobolQualifiedSymbolReference newQualifiedSymbolReferece = new TypeCobolQualifiedSymbolReference(nonAmbiguousHead, nonAmbiguousTail); TCFunctionNameRefVariable = new SymbolReferenceVariable(StorageDataType.MethodName, newQualifiedSymbolReferece); } else { //If so, create ProcedureStyleCallStatement with a ProcedureCall and fix SymbolReference so it's not ambiguous var nonAmbiguousSymbolRef = new SymbolReference(ambiguousSymbolReference.MainSymbolReference.NameLiteral, SymbolType.TCFunctionName); TCFunctionNameRefVariable = new SymbolReferenceVariable(StorageDataType.MethodName, nonAmbiguousSymbolRef); } //CobolExpressionsBuilder store every StorageArea created into storageAreaReads and then after //storageAreaReads is set to the CodeElement //We must remove it as TCFunctionNameRefVariable doesn't contains a StorageArea if (ambiguousSymbolReference.StorageArea != null) { CobolExpressionsBuilder.storageAreaReads.Remove(ambiguousSymbolReference.StorageArea); } statement = new ProcedureStyleCallStatement(new ProcedureCall(TCFunctionNameRefVariable.MainSymbolReference, inputs, inouts, outputs)) { ProgramOrProgramEntryOrProcedureOrFunctionOrTCProcedureFunction = TCFunctionNameRefVariable.MainSymbolReference }; callSite.CallTarget = TCFunctionNameRefVariable.MainSymbolReference; } else { //else it's an error statement = new ProcedureStyleCallStatement(new ProcedureCall(ambiguousSymbolReference.MainSymbolReference, inputs, inouts, outputs)) { ProgramOrProgramEntryOrProcedureOrFunctionOrTCProcedureFunction = ambiguousSymbolReference.MainSymbolReference, Diagnostics = new List <Diagnostic> { new Diagnostic(MessageCode.ImplementationError, context.Start.Column, context.Stop.Column, context.Start.Line, "A call with arguments is not a TCFunctionName") }, }; callSite.CallTarget = ambiguousSymbolReference.MainSymbolReference; } } else { if (ambiguousSymbolReference.MainSymbolReference != null && ambiguousSymbolReference.MainSymbolReference.IsOrCanBeOfType(SymbolType.DataName, SymbolType.TCFunctionName)) { //TODO think about uniformity of CandidateTypes inside QualifiedReference. //Maybe just define CandidatesTypes for the Head... if (ambiguousSymbolReference.MainSymbolReference.IsQualifiedReference) { var qualifiedSymbolReference = (QualifiedSymbolReference)ambiguousSymbolReference.MainSymbolReference; AmbiguousSymbolReference.ApplyCandidatesTypes(qualifiedSymbolReference, new[] { SymbolType.DataName, SymbolType.ProgramName }); //Adjust candidate types only for the first element if (qualifiedSymbolReference.First.IsAmbiguous) { ((AmbiguousSymbolReference)qualifiedSymbolReference.First).CandidateTypes = new[] { SymbolType.DataName, SymbolType.TCFunctionName }; } } else { ((AmbiguousSymbolReference)ambiguousSymbolReference.MainSymbolReference).CandidateTypes = new[] { SymbolType.DataName, SymbolType.TCFunctionName }; } statement = new ProcedureStyleCallStatement(new ProcedureCall(ambiguousSymbolReference.MainSymbolReference, null, null, null)) { ProcdurePointerOrTCProcedureFunction = ambiguousSymbolReference.MainSymbolReference }; callSite = new CallSite(); callSite.CallTarget = statement.ProcdurePointerOrTCProcedureFunction; } else //else, it's an error { statement = new ProcedureStyleCallStatement(new ProcedureCall(ambiguousSymbolReference.MainSymbolReference, null, null, null)) { ProgramOrProgramEntryOrProcedureOrFunctionOrTCProcedureFunction = ambiguousSymbolReference.MainSymbolReference, }; statement.Diagnostics.Add(new Diagnostic(MessageCode.SyntaxErrorInParser, context.Start.Column, context.Stop.Column, context.Start.Line, "Error in detecting Procedure Call type")); callSite = new CallSite(); callSite.CallTarget = statement.ProgramOrProgramEntryOrProcedureOrFunctionOrTCProcedureFunction; } } if (callSite != null) { if (statement.CallSites == null) { statement.CallSites = new List <CallSite>(); } statement.CallSites.Add(callSite); } CodeElement = statement; }
/// <summary> /// Detecting call site parameter /// </summary> /// <param name="callSiteParameter"></param> /// <returns></returns> public override bool Visit(CallSiteParameter callSiteParameter) { return(false); }