public void Visit(ParsedPrototype pars) { pars.ReturnType = ConvertStringToParsedPrimitiveType(pars.TempReturnType, false); // only visit IN prototypes (not FORWARD) if (pars.SimpleForward) { return; } // to code explorer PushToCodeExplorer( GetExplorerListNode("Function prototypes", CodeExplorerIconType.Prototype), new PrototypeCodeItem { 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, Flags = pars.Flags, SubText = pars.ReturnType.ToString() }, pars); }
/* Function: BuildPrototype * * Builds the HTML for the passed prototype. * * In order to have type links, links must be specified and contain any links that appear in the prototype. * linkTargets must also be specified and contain the target topics of all links. If you do not need type * links, set both to null. * * Requirements: * * - The <Context>'s topic must be set. * - If type links are being generated, the <Context>'s page must also be set. */ public string BuildPrototype(ParsedPrototype parsedPrototype, Context context, IList <Link> links = null, IList <Topics.Topic> linkTargets = null) { StringBuilder output = new StringBuilder(); AppendPrototype(parsedPrototype, context, output, links, linkTargets); return(output.ToString()); }
private bool DeletePrototypes(ref StringBuilder outputMessage, ParsedPrototype function) { DeleteCode(function); outputMessage.Append("<br> - " + function.Name); return(true); }
void AppendPostPrototypeLines(ParsedPrototype prototype, StringBuilder output) { int numberOfLines = prototype.NumberOfPostPrototypeLines; TokenIterator start, end; for (int i = 0; i < numberOfLines; i++) { prototype.GetPostPrototypeLine(i, out start, out end); output.Append(" - Post-Prototype Line: "); prototype.Tokenizer.AppendTextBetweenTo(start, end, output); output.AppendLine(); } }
/* Function: ParsePrototype * Converts a raw text prototype into a <ParsedPrototype>. */ override public ParsedPrototype ParsePrototype(string stringPrototype, int commentTypeID) { Tokenizer tokenizedPrototype = new Tokenizer(stringPrototype, tabWidth: EngineInstance.Config.TabWidth); ParsedPrototype parsedPrototype; // Mark any leading annotations. TokenIterator iterator = tokenizedPrototype.FirstToken; TryToSkipWhitespace(ref iterator, true, ParseMode.ParsePrototype); if (TryToSkipAnnotations(ref iterator, ParseMode.ParsePrototype)) { TryToSkipWhitespace(ref iterator, true, ParseMode.ParsePrototype); } // Search for the first opening bracket or brace. char closingBracket = '\0'; while (iterator.IsInBounds) { if (iterator.Character == '(') { closingBracket = ')'; break; } else if (iterator.Character == '[') { // Only treat brackets as parameters if it's following "this", meaning it's an iterator. Ignore all others so we // don't get tripped up on metadata or array brackets on return values. TokenIterator lookbehind = iterator; lookbehind.Previous(); lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.Iterator); if (lookbehind.MatchesToken("this")) { closingBracket = ']'; break; } else { iterator.Next(); } } else if (iterator.Character == '{') { closingBracket = '}'; break; } else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator)) { } else { iterator.Next(); } } // If we found brackets, it's either a function prototype or a class prototype that includes members. // Mark the delimiters. if (closingBracket != '\0') { iterator.PrototypeParsingType = PrototypeParsingType.StartOfParams; iterator.Next(); while (iterator.IsInBounds) { if (iterator.Character == ',') { iterator.PrototypeParsingType = PrototypeParsingType.ParamSeparator; iterator.Next(); } else if (iterator.Character == closingBracket) { iterator.PrototypeParsingType = PrototypeParsingType.EndOfParams; break; } // Unlike prototype detection, here we treat < as an opening bracket. Since we're already in the parameter list // we shouldn't run into it as part of an operator overload, and we need it to not treat the comma in "template<a,b>" // as a parameter divider. else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator) || TryToSkipBlock(ref iterator, true)) { } else { iterator.Next(); } } // We have enough tokens marked to create the parsed prototype. This will also let us iterate through the parameters // easily. parsedPrototype = new ParsedPrototype(tokenizedPrototype); // Set the main section to the last one, since any annotations present will each be in their own section. Some can have // parameter lists and we don't want those confused for the actual parameter list. parsedPrototype.MainSectionIndex = parsedPrototype.Sections.Count - 1; // Mark the part before the parameters, which includes the name and return value. TokenIterator start, end; parsedPrototype.GetBeforeParameters(out start, out end); // Exclude the opening bracket end.Previous(); end.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); if (start < end) { MarkCParameter(start, end); } // If there are any parameters, mark the tokens in them. if (parsedPrototype.NumberOfParameters > 0) { for (int i = 0; i < parsedPrototype.NumberOfParameters; i++) { parsedPrototype.GetParameter(i, out start, out end); MarkCParameter(start, end); } } } // If there's no brackets, it's a variable, property, or class. else { parsedPrototype = new ParsedPrototype(tokenizedPrototype); TokenIterator start = tokenizedPrototype.FirstToken; TokenIterator end = tokenizedPrototype.LastToken; MarkCParameter(start, end); } return(parsedPrototype); }
/* Function: AppendPrototype * * Builds the HTML for the passed prototype and appends it to the passed StringBuilder. * * In order to have type links, links must be specified and contain any links that appear in the prototype. * linkTargets must also be specified and contain the target topics of all links. If you do not need type * links, set both to null. * * Requirements: * * - The <Context>'s topic must be set. * - If type links are being generated, the <Context>'s page must also be set. */ public void AppendPrototype(ParsedPrototype parsedPrototype, Context context, StringBuilder output, IList <Link> links = null, IList <Topics.Topic> linkTargets = null) { this.parsedPrototype = parsedPrototype; this.context = context; #if DEBUG if (context.Topic == null) { throw new Exception("Tried to generate a prototype when the context's topic was not set."); } #endif this.links = links; this.linkTargets = linkTargets; this.addLinks = (links != null && linkTargets != null); #if DEBUG if (this.addLinks && context.Page.IsNull) { throw new Exception("Tried to generate a prototype with type links when the context's page was not set."); } #endif if (parsedPrototype.Tokenizer.HasSyntaxHighlighting == false) { var language = EngineInstance.Languages.FromID(Context.Topic.LanguageID); language.SyntaxHighlight(parsedPrototype); } // Determine if there's parameters anywhere. It's possible for parsedPrototype.NumberOfParameters to be zero and // there still be a parameters section present somewhere such as for SQL's return table definitions. bool hasParameters = false; foreach (var section in parsedPrototype.Sections) { if (section is Prototypes.ParameterSection && (section as Prototypes.ParameterSection).NumberOfParameters > 0) { hasParameters = true; break; } } // We always build the wide form by default, but only include the attribute if there's parameters. The JavaScript assumes // there will be a parameters section in any prototype that has it. output.Append("<div id=\"NDPrototype" + Context.Topic.TopicID + "\" class=\"NDPrototype" + (hasParameters ? " WideForm" : "") + "\">"); foreach (var section in parsedPrototype.Sections) { if (section is Prototypes.ParameterSection && (section as Prototypes.ParameterSection).NumberOfParameters > 0) { AppendParameterSection((Prototypes.ParameterSection)section, output); } else { AppendPlainSection(section, output); } } output.Append("</div>"); }
public void Visit(ParsedPrototype pars) { AppendEverything(pars); }
/// <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); }
/* Function: ScoreParameter * Returns a two bit value representing how well the parameters match, or -1 if they match so poorly that the link and * the target shouldn't be considered a match at all. */ private long ScoreParameter(ParsedPrototype prototype, ParameterString linkParameters, int index, bool ignoreCase) { // -1 - The link has a parameter but the prototype does not. // 00 - The prototype has a parameter but the link does not. This allows links on partial parameters. // 00 - They both have parameters but do not match at all. // 01 - The link doesn't have a parameter but the prototype has one with a default value set. // 10 - The parameters match except for qualifiers or modifiers like "unsigned". // 11 - The parameters match completely, by type or by name, or both don't exist. SimpleTokenIterator linkParamStart, linkParamEnd; TokenIterator prototypeParamStart, prototypeParamEnd; bool hasLinkParam = linkParameters.GetParameter(index, out linkParamStart, out linkParamEnd); bool hasPrototypeParam; if (prototype == null) { hasPrototypeParam = false; // To shut the compiler up. prototypeParamStart = new TokenIterator(); prototypeParamEnd = new TokenIterator(); } else { hasPrototypeParam = prototype.GetParameter(index, out prototypeParamStart, out prototypeParamEnd); } if (!hasLinkParam) { if (!hasPrototypeParam) { return(3); } else { // There is a prototype parameter but not a link parameter. This will be 0 or 1 depending on whether the // prototype parameter has a default value. while (prototypeParamStart < prototypeParamEnd) { if (prototypeParamStart.PrototypeParsingType == PrototypeParsingType.DefaultValue) { return(1); } prototypeParamStart.Next(); } return(0); } } else // hasLinkParam == true { if (hasPrototypeParam == false) { return(-1); } // Both the link and the prototype have parameters at index. bool typeMatch = false; bool typeMismatch = false; bool typeModifierMismatch = false; bool nameMatch = false; bool nameMismatch = false; int modifierBlockLevel = 0; while (prototypeParamStart < prototypeParamEnd) { var type = prototypeParamStart.PrototypeParsingType; // We want any mismatches that occur nested in type modifier blocks to be scored as a modifier mismatch. if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { modifierBlockLevel++; } else if (type == PrototypeParsingType.ClosingTypeModifier || type == PrototypeParsingType.ClosingParamModifier) { modifierBlockLevel--; } else if (modifierBlockLevel > 0) { type = PrototypeParsingType.TypeModifier; } switch (type) { case PrototypeParsingType.TypeModifier: case PrototypeParsingType.TypeQualifier: case PrototypeParsingType.OpeningTypeModifier: case PrototypeParsingType.ClosingTypeModifier: case PrototypeParsingType.ParamModifier: case PrototypeParsingType.OpeningParamModifier: case PrototypeParsingType.ClosingParamModifier: if (linkParamStart < linkParamEnd && linkParamStart.MatchesToken(prototypeParamStart, ignoreCase)) { linkParamStart.Next(); linkParamStart.NextPastWhitespace(); } else { typeModifierMismatch = true; } break; case PrototypeParsingType.Type: if (linkParamStart < linkParamEnd && linkParamStart.MatchesToken(prototypeParamStart, ignoreCase)) { typeMatch = true; linkParamStart.Next(); linkParamStart.NextPastWhitespace(); } else { typeMismatch = true; } break; case PrototypeParsingType.Name: if (linkParamStart < linkParamEnd && linkParamStart.MatchesToken(prototypeParamStart, ignoreCase)) { nameMatch = true; linkParamStart.Next(); linkParamStart.NextPastWhitespace(); } else { nameMismatch = true; } break; } prototypeParamStart.Next(); prototypeParamStart.NextPastWhitespace(); } if (linkParamStart < linkParamEnd) { return(0); } if (nameMatch && !nameMismatch) { return(3); } if (typeMatch && !typeMismatch) { if (!typeModifierMismatch) { return(3); } else { return(2); } } return(0); } }
/* Function: ParsePrototype * Converts a raw text prototype into a <ParsedPrototype>. */ override public ParsedPrototype ParsePrototype(string stringPrototype, int commentTypeID) { Tokenizer tokenizedPrototype = new Tokenizer(stringPrototype, tabWidth: EngineInstance.Config.TabWidth); TokenIterator iterator = tokenizedPrototype.FirstToken; ParsedPrototype parsedPrototype; // Search for the first opening parenthesis. while (iterator.IsInBounds) { if (iterator.Character == '(') { break; } else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator)) { } else { iterator.Next(); } } // If we found parentheses, it's a function prototype. Mark the delimiters. if (iterator.Character == '(') { iterator.PrototypeParsingType = PrototypeParsingType.StartOfParams; iterator.Next(); while (iterator.IsInBounds) { if (iterator.Character == ',') { iterator.PrototypeParsingType = PrototypeParsingType.ParamSeparator; iterator.Next(); } else if (iterator.Character == ')') { iterator.PrototypeParsingType = PrototypeParsingType.EndOfParams; break; } // Unlike prototype detection, here we treat < as an opening bracket. Since we're already in the parameter list // we shouldn't run into it as part of an operator overload, and we need it to not treat the comma in "template<a,b>" // as a parameter divider. else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator) || TryToSkipBlock(ref iterator, true)) { } else { iterator.Next(); } } // We have enough tokens marked to create the parsed prototype. This will also let us iterate through the parameters // easily. parsedPrototype = new ParsedPrototype(tokenizedPrototype, supportsImpliedTypes: false); // Mark the part before the parameters, which includes the name and return value. TokenIterator start, end; parsedPrototype.GetBeforeParameters(out start, out end); // Exclude the opening bracket end.Previous(); end.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); if (start < end) { MarkParameter(start, end); } // If there are any parameters, mark the tokens in them. if (parsedPrototype.NumberOfParameters > 0) { for (int i = 0; i < parsedPrototype.NumberOfParameters; i++) { parsedPrototype.GetParameter(i, out start, out end); MarkParameter(start, end); } } } // If there's no brackets, it's a variable, property, or class. else { parsedPrototype = new ParsedPrototype(tokenizedPrototype, supportsImpliedTypes: false); TokenIterator start = tokenizedPrototype.FirstToken; TokenIterator end = tokenizedPrototype.LastToken; MarkParameter(start, end); } return(parsedPrototype); }