private static bool AddPrototypes(ref StringBuilder outputMessage, ParsedImplementation function) { var protoStr = Npp.GetTextByRange(function.Position, function.EndPosition); // ensure that the file was correctly parsed if (ParserHandler.AblParser.ParserErrors.Count == 0) { // get the best position to insert the prototype bool insertBefore; int insertPos = GetCaretPositionForInsertion <ParsedPrototype>(function.Name, ProInsertPosition.Last, out insertBefore); // if we didn't find a good position, then let's assume the user doesn't need one if (insertPos > 0) { // replace the end ":" or "." by a " FOWARD." protoStr = FormatInsertion(protoStr.Substring(0, protoStr.Length - 1).TrimEnd(' ') + " FORWARD.", "_FUNCTION-FORWARD " + function.Name + " Procedure", insertBefore); Npp.SetTextByRange(insertPos, insertPos, protoStr); //outputMessage.Append("<br> - <a href='" + function.FilePath + "#" + insertPos + "'>" + function.Name + "</a>"); outputMessage.Append("<br> - " + function.Name); return(true); } } return(false); }
/// <summary> /// This method checks if the current document contains function prototypes that are not updated /// and correct them if needed /// </summary> private bool UpdatePrototypes(ref StringBuilder outputMessage, ParsedImplementation function) { var protoStr = Sci.GetTextByRange(function.Position, function.EndPosition); // replace the end ":" or "." by a " FOWARD." protoStr = protoStr.Substring(0, protoStr.Length - 1).TrimEnd(' ') + " FORWARD."; Sci.SetTextByRange(function.PrototypePosition, function.PrototypeEndPosition, protoStr); outputMessage.Append("<br> - <a href='" + function.FilePath + "#" + (function.PrototypePosition) + "'>" + function.Name + "</a>"); return(true); }
public void Visit(ParsedImplementation pars) { pars.ReturnType = ConvertStringToParsedPrimitiveType(pars.TempReturnType, false); // to code explorer PushToCodeExplorer( GetExplorerListNode("Functions", CodeExplorerIconType.Function), new FunctionCodeItem { DisplayText = pars.Name, Flags = pars.Flags, SubText = null, DocumentOwner = pars.FilePath, GoToLine = pars.Line, GoToColumn = pars.Column }); // to completion data PushToAutoCompletion(new FunctionCompletionItem { DisplayText = pars.Name, SubText = pars.ReturnType.ToString(), Flags = pars.Flags, }, pars); }
public void Visit(ParsedImplementation pars) { AppendEverything(pars); }
/// <summary> /// returns the best caret position for inserting a new IProNew /// </summary> private int GetCaretPositionForInsertion <T>(string codeName, ProInsertPosition insertPos, out bool insertBefore) where T : ParsedScopeBlock { insertBefore = false; // at caret position if (insertPos == ProInsertPosition.CaretPosition) { return(Sci.GetPosFromLineColumn(Sci.Line.CurrentLine, 0)); } T refItem = null; #region set insertBefore and refItem // the following is a little annoying to code and understand... // the idea is to get (or dont get if it doesn't exist) the previous or the next item // of type T in the existing list of said types so we can "anchor" on it to insert // our new stuff... if (typeof(ParsedPrototype) == typeof(T)) { // find the previous/next function implementation with a prototype bool found = false; ParsedImplementation foundImplement = null; foreach (var impl in _parsedItems.Where(item => item is ParsedImplementation).Cast <ParsedImplementation>()) { if (impl != null) { // we didn't match our current function implementation yet if (!found) { // we just did if (impl.Name.Equals(codeName)) { found = true; continue; } // set previous item if (impl.HasPrototype) { foundImplement = impl; } } else { // match first item after we found our implementation if (impl.HasPrototype) { insertBefore = true; foundImplement = impl; break; } } } } // now we need its proto if (foundImplement != null) { refItem = _parsedItems.FirstOrDefault(fun => { var proto = fun as ParsedPrototype; return(proto != null && proto.Name.Equals(foundImplement.Name) && proto.SimpleForward); }) as T; } } else { // list of existing items of the same type var existingList = _parsedItems.Where(item => item.GetType() == typeof(T)).Select(item => (T)item).ToList(); if (existingList.Count > 0) { // alphabetical order if (insertPos == ProInsertPosition.AlphabeticalOrder) { // find the position that would take our new code int index = existingList.Select(item => item.Name).ToList().BinarySearch(codeName); if (index < 0) { index = ~index - 1; // we get the index in which it should be inserted - 1 if (index == -1) { insertBefore = true; refItem = existingList[0]; } else { refItem = existingList[index]; } } // first of its kind } else if (insertPos == ProInsertPosition.First) { refItem = existingList.FirstOrDefault(); insertBefore = true; } else if (insertPos == ProInsertPosition.Last) { refItem = existingList.LastOrDefault(); } } } #endregion string preProcBlockType = null; string typeComment = null; if (typeof(ParsedImplementation) == typeof(T)) { preProcBlockType = @"_FUNCTION"; typeComment = @"Function\s+Implementations"; } else if (typeof(ParsedPrototype) == typeof(T)) { preProcBlockType = @"_FUNCTION-FORWARD"; typeComment = @"Function\s+Prototypes"; } else if (typeof(ParsedProcedure) == typeof(T)) { preProcBlockType = @"_PROCEDURE"; typeComment = @"Internal\s+Procedures"; } // is there already an item existing? if (refItem != null && preProcBlockType != null) { // try to find a &IF DEFINED(EXCLUDE- block or a _UIB_BLOCK that surrounds the prototype var surroundingScope = GetPreProcBlock(refItem, preProcBlockType); if (surroundingScope != null) { return(insertBefore ? surroundingScope.Position : surroundingScope.EndBlockPosition); } // otherwise return the position of the function itself return(insertBefore ? refItem.Position : refItem.EndBlockPosition); } // can we find a comment indicating where the proc should be inserted? if (typeComment != null) { Sci.TargetWholeDocument(); var previousFlags = Sci.SearchFlags; Sci.SearchFlags = SearchFlags.Regex; var streg = @"\/\*\s+[\*]+\s+" + typeComment + @"\s+[\*]+"; var foundPos = Sci.SearchInTarget(streg); Sci.SearchFlags = previousFlags; if (foundPos == -1) { foundPos = new Regex(@"\/\*\s+[\*]+\s+" + typeComment + @"\s+[\*]+").Match(Sci.Text).Index; if (foundPos == 0) { foundPos = -1; } } if (foundPos > -1) { return(Sci.GetPosFromLineColumn(Sci.LineFromPosition(foundPos) + 1, 0)); } } // At last, we find the best position considering the appbuilder blocks if (typeof(ParsedImplementation) == typeof(T)) { // function implementation goes all the way bottom return(Sci.TextLength); } if (typeof(ParsedPrototype) == typeof(T)) { // prototypes go after &ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK var preprocessorBlock = _parsedItems.FirstOrDefault(item => item is ParsedScopePreProcBlock && ((ParsedScopePreProcBlock)item).Type == ParsedPreProcBlockType.UibPreprocessorBlock); if (preprocessorBlock != null) { insertBefore = false; return(((ParsedScopePreProcBlock)preprocessorBlock).EndBlockPosition); } } if (typeof(ParsedProcedure) == typeof(T)) { // new procedure goes before the first function implementation of last var firstFunc = _parsedItems.FirstOrDefault(item => item is ParsedImplementation) as ParsedImplementation; if (firstFunc != null) { insertBefore = true; // try to find a &IF DEFINED(EXCLUDE- block that surrounds the func var surroundingScope = GetPreProcBlock(firstFunc, @"_FUNCTION"); if (surroundingScope != null) { return(surroundingScope.Position); } return(firstFunc.Position); } // otherwise it goes at the end return(Sci.TextLength); } return(-1); }
/// <summary> /// Matches a function definition (not the FORWARD prototype) /// </summary> private ParsedFunction CreateParsedFunction(Token functionToken) { // info we will extract from the current statement : string name = null; string parsedReturnType = null; int extent = 0; ParseFlag flags = 0; StringBuilder parameters = new StringBuilder(); List <ParsedDefine> parametersList = null; ParsedImplementation createdImp = null; _lastTokenWasSpace = true; Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // matching name if (!(token is TokenWord)) { break; } name = token.Value; state++; break; case 1: // matching return type if (!(token is TokenWord)) { break; } if (token.Value.EqualsCi("returns") || token.Value.EqualsCi("class")) { continue; } parsedReturnType = token.Value; state++; break; case 2: // matching parameters (start) if (token is TokenWord) { if (token.Value.EqualsCi("private")) { flags |= ParseFlag.Private; } if (token.Value.EqualsCi("extent")) { extent = GetExtentNumber(2); } // we didn't match any opening (, but we found a forward if (token.Value.EqualsCi("forward")) { state = 99; } else if (token.Value.EqualsCi("in")) { state = 100; } } else if (token is TokenSymbol && token.Value.Equals("(")) { state = 3; } break; case 3: // read parameters, define a ParsedDefineItem for each parametersList = GetParsedParameters(functionToken, parameters); state = 10; break; case 10: // matching prototype, we dont want to create a ParsedItem for prototype if (token is TokenWord) { if (token.Value.EqualsCi("forward")) { state = 99; } else if (token.Value.EqualsCi("in")) { state = 100; } } break; } } while (MoveNext()); if (name == null || parsedReturnType == null) { return(null); } // otherwise it needs to ends with : or . if (!(token is TokenEos)) { return(null); } // New prototype, we matched a forward or a IN if (state >= 99) { ParsedPrototype createdProto = new ParsedPrototype(name, functionToken, parsedReturnType) { Scope = GetCurrentBlock <ParsedScopeBlock>(), FilePath = FilePathBeingParsed, SimpleForward = state == 99, // allows us to know if we expect an implementation in this .p or not EndPosition = token.EndPosition, EndBlockLine = token.Line, EndBlockPosition = token.EndPosition, Flags = flags, Extent = extent, ParametersString = parameters.ToString() }; if (!_functionPrototype.ContainsKey(name)) { _functionPrototype.Add(name, createdProto); } AddParsedItem(createdProto, functionToken.OwnerNumber); // case of a IN if (!createdProto.SimpleForward) { // add the parameters to the list if (parametersList != null) { createdProto.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { createdProto.Parameters.Add(parsedItem); } } } } else { // New function createdImp = new ParsedImplementation(name, functionToken, parsedReturnType) { EndPosition = token.EndPosition, Flags = flags, Extent = extent, ParametersString = parameters.ToString() }; // it has a prototype? if (_functionPrototype.ContainsKey(name)) { // make sure it was a prototype! var proto = _functionPrototype[name] as ParsedPrototype; if (proto != null && proto.SimpleForward) { createdImp.HasPrototype = true; createdImp.PrototypeLine = proto.Line; createdImp.PrototypeColumn = proto.Column; createdImp.PrototypePosition = proto.Position; createdImp.PrototypeEndPosition = proto.EndPosition; // boolean to know if the implementation matches the prototype createdImp.PrototypeUpdated = ( createdImp.Flags == proto.Flags && createdImp.Extent.Equals(proto.Extent) && createdImp.TempReturnType.EqualsCi(proto.TempReturnType) && createdImp.ParametersString.EqualsCi(proto.ParametersString)); } } else { _functionPrototype.Add(name, createdImp); } // add the parameters to the list if (parametersList != null) { createdImp.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { createdImp.Parameters.Add(parsedItem); } } AddParsedItem(createdImp, functionToken.OwnerNumber); } return(createdImp); }