public override ParsedDocument Parse(bool storeAst, string file, TextReader content, Project prj = null)
{
if (!storeAst)
return null;
ProjectFile pf = null;
if (prj == null)
{
var sln = Ide.IdeApp.ProjectOperations.CurrentSelectedSolution;
if (sln != null)
foreach (var proj in sln.GetAllProjects())
if (proj.IsFileInProject(file))
{
prj = proj;
pf = proj.GetProjectFile(file);
break;
}
}
else if(prj.IsFileInProject(file))
{
pf = prj.GetProjectFile(file);
}
// HACK(?) The folds are parsed before the document gets loaded
// - so reuse the last parsed document to save time
// -- What if multiple docs are opened?
var d = LastParsedMod as ParsedDModule;
if (d != null && d.FileName == file)
{
LastParsedMod = null;
return d;
}
else
LastParsedMod = null;
var dprj = prj as AbstractDProject;
// Remove obsolete ast from cache
if(file != null)
GlobalParseCache.RemoveModule (file);
DModule ast;
var doc = new ParsedDModule(file);
var parser = DParser.Create(content);
// Also put attention on non-ddoc comments; These will be used to generate foldable comment regions then
parser.Lexer.OnlyEnlistDDocComments = false;
// Parse the code
try
{
ast = parser.Parse();
}
catch (TooManyErrorsException)
{
ast = parser.Document;
}
catch(System.Exception ex) {
doc.ErrorList.Add(new Error(ErrorType.Error, ex.Message));
return doc;
}
if(ast == null)
return doc;
// Update project owner information / Build appropriate module name
if(string.IsNullOrEmpty(ast.ModuleName))
{
if(pf == null)
ast.ModuleName = file != null ? Path.GetFileNameWithoutExtension(file) : string.Empty;
else
ast.ModuleName = BuildModuleName(pf);
}
ast.FileName = file;
// Assign new ast to the ParsedDDocument object
doc.DDom = ast;
// Add parser errors to the parser output
foreach (var parserError in parser.ParseErrors)
doc.ErrorList.Add(new Error(
ErrorType.Error,
parserError.Message,
parserError.Location.Line,
parserError.Location.Column));
#region Provide comment fold support by addin them to the IDE document object
foreach (var cm in parser.Comments)
{
var c = new MonoDevelop.Ide.TypeSystem.Comment(cm.CommentText){
CommentStartsLine = cm.CommentStartsLine,
CommentType = (cm.CommentType & D_Parser.Parser.Comment.Type.Block) != 0 ? CommentType.Block : CommentType.SingleLine,
IsDocumentation = cm.CommentType.HasFlag(D_Parser.Parser.Comment.Type.Documentation),
};
if (c.CommentType == CommentType.SingleLine)
{
if (c.IsDocumentation)
c.OpenTag = "///";
else
c.OpenTag = "//";
}
else
{
if (c.IsDocumentation)
{
c.OpenTag = "/**";
c.ClosingTag = "*/";
}
else
{
c.OpenTag = "/*";
c.ClosingTag = "*/";
}
}
c.Region = new DomRegion(cm.StartPosition.Line, cm.StartPosition.Column, cm.EndPosition.Line, cm.EndPosition.Column);
doc.Comments.Add(c);
// Enlist TODO/FIXME/HACK etc. stuff in the IDE's project task list
for (int i = CommentTag.SpecialCommentTags.Count-1; i >= 0 ; i--)
if (c.Text.StartsWith(CommentTag.SpecialCommentTags[i].Tag))
{
doc.Add(new Tag(CommentTag.SpecialCommentTags[i].Tag, c.Text, c.Region));
break;
}
}
#endregion
#region Serialize to NRefactory Dom structure
/*
var cu = new CompilationUnit(file);
doc.CompilationUnit = cu;
var global = new DomType(cu, ClassType.Class,
Modifiers.Public | Modifiers.Partial,
"(global)",
new DomLocation(),
ast.ModuleName,
new DomRegion());
cu.Add(global);
foreach (var n in ast)
{
var ch = ConvertDParserToDomNode(n, doc);
if (ch is DomField || ch is DomMethod)
global.Add(ch as IMember);
else
cu.Add(ch as IType);
}
*/
#endregion
if (prj != null)
{
// Workaround for tags not being displayed
var ctnt = TypeSystemService.GetProjectContentWrapper(prj);
if (ctnt != null)
{
var tags = ctnt.GetExtensionObject<ProjectCommentTags>();
if (tags != null)
tags.UpdateTags(prj, file, doc.TagComments);
}
}
return doc;
}