public unsafe ParsedDocument Parse (string fileName, string content) { var regionStack = new Stack<Tuple<string, DomLocation>> (); var result = new ParsedDocument (fileName); bool inSingleComment = false, inMultiLineComment = false; bool inString = false, inVerbatimString = false; bool inChar = false; bool inLineStart = true, hasStartedAtLine = false; int line = 1, column = 1; var startLoc = DomLocation.Empty; fixed (char* startPtr = content) { char* endPtr = startPtr + content.Length; char* ptr = startPtr; char* beginPtr = ptr; while (ptr < endPtr) { switch (*ptr) { case '#': if (!inLineStart) break; ptr++; if (StartsIdentifier (ptr, endPtr, "region")) { var regionLocation = new DomLocation (line, column); column++; ptr += "region".Length; column += "region".Length; SkipWhitespaces (ref ptr, endPtr, ref column); regionStack.Push (Tuple.Create (ReadToEol (content, ref ptr, endPtr, ref line, ref column), regionLocation)); continue; } else if (StartsIdentifier (ptr, endPtr, "endregion")) { column++; ptr += "endregion".Length; column += "endregion".Length; if (regionStack.Count > 0) { var beginRegion = regionStack.Pop (); result.Add (new FoldingRegion ( beginRegion.Item1, new DomRegion (beginRegion.Item2.Line, beginRegion.Item2.Column, line, column), FoldType.UserRegion, true)); } continue; } else { column++; } break; case '/': if (inString || inChar || inVerbatimString || inMultiLineComment || inSingleComment) break; if (ptr + 1 < endPtr) { char nextCh = *(ptr + 1); if (nextCh == '/') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; startLoc = new DomLocation (line, column); ptr++; column++; inSingleComment = true; } else if (nextCh == '*') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; startLoc = new DomLocation (line, column); ptr++; column++; inMultiLineComment = true; } } break; case '*': if (inString || inChar || inVerbatimString || inSingleComment) break; if (inMultiLineComment && ptr + 1 < endPtr) { if (ptr + 1 < endPtr && *(ptr + 1) == '/') { ptr += 2; column += 2; inMultiLineComment = false; result.Add (new Comment () { Region = new DomRegion (startLoc, new DomLocation (line, column)), CommentType = CommentType.MultiLine, Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), CommentStartsLine = hasStartedAtLine }); continue; } } break; case '@': if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) break; if (ptr + 1 < endPtr && *(ptr + 1) == '"') { ptr++; column++; inVerbatimString = true; } break; case '\n': if (inSingleComment) { bool isDocumentation = *beginPtr == '/'; if (isDocumentation) beginPtr++; result.Add (new Comment () { Region = new DomRegion (startLoc, new DomLocation (line, column)), CommentType = CommentType.SingleLine, Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), CommentStartsLine = hasStartedAtLine, IsDocumentation = isDocumentation }); inSingleComment = false; } inString = false; inChar = false; inLineStart = true; line++; column = 1; ptr++; continue; case '\r': if (ptr + 1 < endPtr && *(ptr + 1) == '\n') ptr++; goto case '\n'; case '\\': if (inString || inChar) ptr++; break; case '"': if (inSingleComment || inMultiLineComment || inChar) break; if (inVerbatimString) { if (ptr + 1 < endPtr && *(ptr + 1) == '"') { ptr++; column++; break; } inVerbatimString = false; break; } inString = !inString; break; case '\'': if (inSingleComment || inMultiLineComment || inString || inVerbatimString) break; inChar = !inChar; break; } column++; ptr++; } } return result; }
void VisitPreprocessorDirective (ParsedDocument result, SpecialsBag.PreProcessorDirective directive) { DomLocation loc = new DomLocation (directive.Line, directive.Col); switch (directive.Cmd) { case Tokenizer.PreprocessorDirective.If: conditionalRegions.Push (new ConditionalRegion (visitor.Text)); ifBlocks.Push (directive); ConditionalRegion.Start = loc; break; case Tokenizer.PreprocessorDirective.Elif: CloseConditionBlock (new DomLocation (directive.EndLine, directive.EndCol)); if (ConditionalRegion != null) ConditionalRegion.ConditionBlocks.Add (new ConditionBlock (visitor.Text, loc)); break; case Tokenizer.PreprocessorDirective.Else: CloseConditionBlock (new DomLocation (directive.EndLine, directive.EndCol)); if (ConditionalRegion != null) ConditionalRegion.ElseBlock = new DomRegion (loc, DomLocation.Empty); break; case Tokenizer.PreprocessorDirective.Endif: DomLocation endLoc = new DomLocation (directive.EndLine, directive.EndCol); CloseConditionBlock (endLoc); if (ConditionalRegion != null && !ConditionalRegion.ElseBlock.Start.IsEmpty) ConditionalRegion.ElseBlock = new DomRegion (ConditionalRegion.ElseBlock.Start, endLoc); AddCurRegion (result, directive.EndLine, directive.EndCol); if (ifBlocks.Count > 0) { var ifBlock = ifBlocks.Pop (); DomRegion dr = new DomRegion (ifBlock.Line, ifBlock.Col, directive.EndLine, directive.EndCol); result.Add (new FoldingRegion ("#if " + ifBlock.Arg.Trim (), dr, FoldType.UserRegion, false)); foreach (var d in elifBlocks) { dr.Start = new DomLocation (d.Line, d.Col); result.Add (new FoldingRegion ("#elif " + ifBlock.Arg.Trim (), dr, FoldType.UserRegion, false)); } if (elseBlock != null) { dr.Start = new DomLocation (elseBlock.Line, elseBlock.Col); result.Add (new FoldingRegion ("#else", dr, FoldType.UserRegion, false)); } } elseBlock = null; break; case Tokenizer.PreprocessorDirective.Define: result.Add (new PreProcessorDefine (directive.Arg, loc)); break; case Tokenizer.PreprocessorDirective.Region: regions.Push (directive); break; case Tokenizer.PreprocessorDirective.Endregion: if (regions.Count > 0) { var start = regions.Pop (); DomRegion dr = new DomRegion (start.Line, start.Col, directive.EndLine, directive.EndCol); result.Add (new FoldingRegion (start.Arg, dr, FoldType.UserRegion, true)); } break; } }
void AddCurRegion (ParsedDocument result, int line, int col) { if (ConditionalRegion == null) return; ConditionalRegion.End = new DomLocation (line, col); result.Add (ConditionalRegion); conditionalRegions.Pop (); }
void VisitComment (ParsedDocument result, SpecialsBag.Comment comment, string[] tagComments) { var cmt = new MonoDevelop.Projects.Dom.Comment (comment.Content); cmt.CommentStartsLine = comment.StartsLine; switch (comment.CommentType) { case SpecialsBag.CommentType.Multi: cmt.CommentType = MonoDevelop.Projects.Dom.CommentType.MultiLine; cmt.OpenTag = "/*"; cmt.ClosingTag = "*/"; break; case SpecialsBag.CommentType.Single: cmt.CommentType = MonoDevelop.Projects.Dom.CommentType.SingleLine; cmt.OpenTag = "//"; break; case SpecialsBag.CommentType.Documentation: cmt.CommentType = MonoDevelop.Projects.Dom.CommentType.SingleLine; cmt.IsDocumentation = true; cmt.OpenTag = "///"; break; } cmt.Region = new DomRegion (comment.Line, comment.Col, comment.EndLine, comment.EndCol); result.Comments.Add (cmt); foreach (string tag in tagComments) { int idx = comment.Content.IndexOf (tag); if (idx < 0) continue; result.Add (new Tag (tag, comment.Content, cmt.Region)); } }
public override ParsedDocument Parse (ProjectDom dom, string fileName, string content) { using (ICSharpCode.NRefactory.IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser (ICSharpCode.NRefactory.SupportedLanguage.CSharp, new StringReader (content))) { ParsedDocument result = new ParsedDocument (fileName); result.CompilationUnit = new MonoDevelop.Projects.Dom.CompilationUnit (fileName); parser.ParseMethodBodies = false; parser.Errors.Error += delegate(int line, int col, string message) { result.Add (new Error (ErrorType.Error, line, col, message)); }; parser.Lexer.SpecialCommentTags = ProjectDomService.SpecialCommentTags.GetNames (); parser.Lexer.EvaluateConditionalCompilation = true; if (dom != null && dom.Project != null && MonoDevelop.Ide.IdeApp.Workspace != null) { DotNetProjectConfiguration configuration = dom.Project.GetConfiguration (MonoDevelop.Ide.IdeApp.Workspace.ActiveConfiguration) as DotNetProjectConfiguration; CSharpCompilerParameters par = configuration != null ? configuration.CompilationParameters as CSharpCompilerParameters : null; if (par != null) parser.Lexer.SetConditionalCompilationSymbols (par.DefineSymbols); } parser.Parse (); SpecialTracker tracker = new SpecialTracker (result); foreach (ICSharpCode.NRefactory.ISpecial special in parser.Lexer.SpecialTracker.CurrentSpecials) { special.AcceptVisitor (tracker, null); } foreach (ICSharpCode.NRefactory.Parser.TagComment tagComment in parser.Lexer.TagComments) { result.Add (new Tag (tagComment.Tag, tagComment.CommentText, new DomRegion (tagComment.StartPosition.Y, tagComment.StartPosition.X, tagComment.EndPosition.Y, tagComment.EndPosition.X))); } ConversionVisitior visitor = new ConversionVisitior (dom, result, parser.Lexer.SpecialTracker.CurrentSpecials); visitor.VisitCompilationUnit (parser.CompilationUnit, null); result.CompilationUnit.Tag = parser.CompilationUnit; LastUnit = parser.CompilationUnit; return result; } }
public unsafe ParsedDocument Parse (string fileName, string content) { var result = new ParsedDocument (fileName); bool inSingleComment = false, inMultiLineComment = false; bool inString = false, inVerbatimString = false; bool inChar = false; bool inLineStart = true, hasStartedAtLine = false; int line = 1, column = 1; var startLoc = DomLocation.Empty; fixed (char* startPtr = content) { char* endPtr = startPtr + content.Length; char* ptr = startPtr; char* beginPtr = ptr; while (ptr < endPtr) { switch (*ptr) { case '/': if (inString || inChar || inVerbatimString || inMultiLineComment || inSingleComment) break; if (ptr + 1 < endPtr) { char nextCh = *(ptr + 1); if (nextCh == '/') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; startLoc = new DomLocation (line, column); ptr++; column++; inSingleComment = true; } else if (nextCh == '*') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; startLoc = new DomLocation (line, column); ptr++; column++; inMultiLineComment = true; } } break; case '*': if (inString || inChar || inVerbatimString || inSingleComment) break; if (inMultiLineComment && ptr + 1 < endPtr) { if (ptr + 1 < endPtr && *(ptr + 1) == '/') { ptr += 2; column += 2; inMultiLineComment = false; result.Add (new Comment () { Region = new DomRegion (startLoc, new DomLocation (line, column)), CommentType = CommentType.MultiLine, Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), CommentStartsLine = hasStartedAtLine }); continue; } } break; case '@': if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) break; if (ptr + 1 < endPtr && *(ptr + 1) == '"') { ptr++; column++; inVerbatimString = true; } break; case '\n': if (inSingleComment) { bool isDocumentation = *beginPtr == '/'; if (isDocumentation) beginPtr++; result.Add (new Comment () { Region = new DomRegion (startLoc, new DomLocation (line, column)), CommentType = CommentType.SingleLine, Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), CommentStartsLine = hasStartedAtLine, IsDocumentation = isDocumentation }); inSingleComment = false; } inString = false; inChar = false; inLineStart = true; line++; column = 1; ptr++; continue; case '\r': if (ptr + 1 < endPtr && *(ptr + 1) == '\n') ptr++; goto case '\n'; case '\\': if (inString || inChar) ptr++; break; case '"': if (inSingleComment || inMultiLineComment || inChar) break; if (inVerbatimString) { if (ptr + 1 < endPtr && *(ptr + 1) == '"') { ptr++; column++; break; } inVerbatimString = false; break; } inString = !inString; break; case '\'': if (inSingleComment || inMultiLineComment || inString || inVerbatimString) break; inChar = !inChar; break; } column++; ptr++; } } return result; }