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;
			}
		}
Example #6
0
		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;
		}