#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

447 lines
14 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krueger" email="mike@icsharpcode.net"/>
// <version value="$version"/>
// </file>
using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Xml;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Dom;
namespace ICSharpCode.Core
{
public static class ParserService
{
static ParserDescriptor[] parser;
static Dictionary<IProject, IProjectContent> projectContents = new Dictionary<IProject, IProjectContent>();
static Dictionary<string, ParseInformation> parsings = new Dictionary<string, ParseInformation>();
public static IProjectContent CurrentProjectContent {
[DebuggerStepThrough]
get {
if (forcedContent != null) return forcedContent;
if (ProjectService.CurrentProject == null || !projectContents.ContainsKey(ProjectService.CurrentProject)) {
return defaultProjectContent;
}
return projectContents[ProjectService.CurrentProject];
}
}
static IProjectContent forcedContent;
/// <summary>
/// Used for unit tests ONLY!!
/// </summary>
public static void ForceProjectContent(IProjectContent content)
{
forcedContent = content;
}
public static IEnumerable<IProjectContent> AllProjectContents {
get {
return projectContents.Values;
}
}
static ParserService()
{
try {
parser = (ParserDescriptor[])(AddInTree.GetTreeNode("/Workspace/Parser").BuildChildItems(null)).ToArray(typeof(ParserDescriptor));
} catch (TreePathNotFoundException) {
parser = new ParserDescriptor[] {};
}
ProjectService.SolutionLoaded += new SolutionEventHandler(OpenCombine);
ProjectService.SolutionClosed += new EventHandler(ProjectServiceSolutionClosed);
}
static void ProjectServiceSolutionClosed(object sender, EventArgs e)
{
abortLoadSolutionProjectsThread = true;
lock (projectContents) {
foreach (IProjectContent content in projectContents.Values) {
content.Dispose();
}
projectContents.Clear();
}
}
static Thread loadSolutionProjectsThread;
static bool abortLoadSolutionProjectsThread;
static void OpenCombine(object sender, SolutionEventArgs e)
{
if (loadSolutionProjectsThread != null) {
if (!abortLoadSolutionProjectsThread)
throw new InvalidOperationException("Cannot open new combine without closing old combine!");
loadSolutionProjectsThread.Join();
}
loadSolutionProjectsThread = new Thread(new ThreadStart(LoadSolutionProjects));
loadSolutionProjectsThread.Priority = ThreadPriority.Lowest;
loadSolutionProjectsThread.IsBackground = true;
loadSolutionProjectsThread.Start();
}
public static bool LoadSolutionProjectsThreadRunning {
get {
return loadSolutionProjectsThread != null;
}
}
static void LoadSolutionProjects()
{
try {
abortLoadSolutionProjectsThread = false;
LoadSolutionProjectsInternal();
} finally {
loadSolutionProjectsThread = null;
}
}
static void LoadSolutionProjectsInternal()
{
List<ParseProjectContent> createdContents = new List<ParseProjectContent>();
foreach (IProject project in ProjectService.OpenSolution.Projects) {
try {
ParseProjectContent newContent = project.CreateProjectContent();
lock (projectContents) {
projectContents[project] = newContent;
}
createdContents.Add(newContent);
} catch (Exception e) {
Console.WriteLine("Error while retrieving project contents from {0}:", project);
ICSharpCode.Core.MessageService.ShowError(e);
}
}
int workAmount = 0;
foreach (ParseProjectContent newContent in createdContents) {
if (abortLoadSolutionProjectsThread) return;
try {
newContent.Initialize1();
workAmount += newContent.GetInitializationWorkAmount();
} catch (Exception e) {
Console.WriteLine("Error while initializing project references:" + newContent);
ICSharpCode.Core.MessageService.ShowError(e);
}
}
StatusBarService.ProgressMonitor.BeginTask("Parsing...", workAmount);
foreach (ParseProjectContent newContent in createdContents) {
if (abortLoadSolutionProjectsThread) return;
try {
newContent.Initialize2();
} catch (Exception e) {
Console.WriteLine("Error while initializing project contents:" + newContent);
ICSharpCode.Core.MessageService.ShowError(e);
}
}
StatusBarService.ProgressMonitor.Done();
}
public static IProjectContent GetProjectContent(IProject project)
{
if (projectContents.ContainsKey(project)) {
return projectContents[project];
}
return null;
}
public static void StartParserThread()
{
abortParserUpdateThread = false;
Thread parserThread = new Thread(new ThreadStart(ParserUpdateThread));
parserThread.Priority = ThreadPriority.Lowest;
parserThread.IsBackground = true;
parserThread.Start();
}
public static void StopParserThread()
{
abortParserUpdateThread = true;
}
static bool abortParserUpdateThread = false;
static Dictionary<string, int> lastUpdateSize = new Dictionary<string, int>();
static void ParserUpdateThread()
{
// preload mscorlib, we're going to need it anyway
ProjectContentRegistry.GetMscorlibContent();
while (!abortParserUpdateThread) {
try {
ParserUpdateStep();
} catch (Exception e) {
ICSharpCode.Core.MessageService.ShowError(e);
// don't fire an exception every 2 seconds at the user, give him at least
// time to read the first :-)
Thread.Sleep(10000);
}
Thread.Sleep(2000);
}
}
static void ParserUpdateStep()
{
if (WorkbenchSingleton.Workbench.ActiveWorkbenchWindow != null && WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent != null) {
IEditable editable = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IEditable;
if (editable != null) {
string fileName = null;
IViewContent viewContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ViewContent;
IParseableContent parseableContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IParseableContent;
//ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it.
string text = null;
if (parseableContent != null) {
fileName = parseableContent.ParseableContentName;
text = parseableContent.ParseableText;
} else {
fileName = viewContent.IsUntitled ? viewContent.UntitledName : viewContent.FileName;
}
if (!(fileName == null || fileName.Length == 0)) {
ParseInformation parseInformation = null;
bool updated = false;
if (text == null) {
text = editable.Text;
if (text == null) return;
}
int hash = text.Length;
if (!lastUpdateSize.ContainsKey(fileName) || (int)lastUpdateSize[fileName] != hash) {
parseInformation = ParseFile(fileName, text, !viewContent.IsUntitled, true);
lastUpdateSize[fileName] = hash;
updated = true;
}
if (updated) {
if (parseInformation != null && editable is IParseInformationListener) {
((IParseInformationListener)editable).ParseInformationUpdated(parseInformation);
}
}
OnParserUpdateStepFinished(new ParserUpdateStepEventArgs(fileName, text, updated));
}
}
}
}
public static void ParseViewContent(IViewContent viewContent)
{
string text = ((IEditable)viewContent).Text;
ParseInformation parseInformation = ParseFile(viewContent.FileName, text, !viewContent.IsUntitled, true);
if (parseInformation != null && viewContent is IParseInformationListener) {
((IParseInformationListener)viewContent).ParseInformationUpdated(parseInformation);
}
}
public static event ParserUpdateStepEventHandler ParserUpdateStepFinished;
static void OnParserUpdateStepFinished(ParserUpdateStepEventArgs e)
{
if (ParserUpdateStepFinished != null) {
ParserUpdateStepFinished(typeof(ParserService), e);
}
}
public static ParseInformation ParseFile(string fileName)
{
return ParseFile(fileName, null);
}
public static ParseInformation ParseFile(string fileName, string fileContent)
{
return ParseFile(fileName, fileContent, true, true);
}
static IProjectContent GetProjectContent(string fileName)
{
lock (projectContents) {
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) {
if (projectContent.Key.IsFileInProject(fileName)) {
return projectContent.Value;
}
}
}
return null;
}
static IProjectContent defaultProjectContent = new DefaultProjectContent();
public static ParseInformation ParseFile(string fileName, string fileContent, bool updateCommentTags, bool fireUpdate)
{
return ParseFile(null, fileName, fileContent, updateCommentTags, fireUpdate);
}
public static ParseInformation ParseFile(IProjectContent fileProjectContent, string fileName, string fileContent, bool updateCommentTags, bool fireUpdate)
{
IParser parser = GetParser(fileName);
if (parser == null) {
return null;
}
ICompilationUnit parserOutput = null;
if (fileContent == null) {
if (ProjectService.OpenSolution != null) {
foreach (IProject project in ProjectService.OpenSolution.Projects) {
if (project.IsFileInProject(fileName)) {
fileContent = project.GetParseableFileContent(fileName);
break;
}
}
}
}
try {
if (fileProjectContent == null) {
// GetProjectContent is expensive because it compares all file names, so
// we accept the project content as optional parameter.
fileProjectContent = GetProjectContent(fileName);
if (fileProjectContent == null) {
fileProjectContent = defaultProjectContent;
}
}
if (fileContent != null) {
parserOutput = parser.Parse(fileProjectContent, fileName, fileContent);
} else {
if (!File.Exists(fileName)) {
return null;
}
parserOutput = parser.Parse(fileProjectContent, fileName);
}
if (parsings.ContainsKey(fileName)) {
ParseInformation parseInformation = parsings[fileName];
fileProjectContent.UpdateCompilationUnit(parseInformation.MostRecentCompilationUnit, parserOutput as ICompilationUnit, fileName, updateCommentTags);
} else {
fileProjectContent.UpdateCompilationUnit(null, parserOutput, fileName, updateCommentTags);
}
return UpdateParseInformation(parserOutput as ICompilationUnit, fileName, updateCommentTags, fireUpdate);
} catch (Exception e) {
MessageService.ShowError(e);
}
return null;
}
public static ParseInformation UpdateParseInformation(ICompilationUnit parserOutput, string fileName, bool updateCommentTags, bool fireEvent)
{
if (!parsings.ContainsKey(fileName)) {
parsings[fileName] = new ParseInformation();
}
ParseInformation parseInformation = parsings[fileName];
if (fireEvent) {
try {
OnParseInformationUpdated(new ParseInformationEventArgs(fileName, parseInformation, parserOutput));
} catch (Exception e) {
Console.WriteLine(e);
}
}
if (parserOutput.ErrorsDuringCompile) {
parseInformation.DirtyCompilationUnit = parserOutput;
} else {
parseInformation.ValidCompilationUnit = parserOutput;
parseInformation.DirtyCompilationUnit = null;
}
return parseInformation;
}
public static ParseInformation GetParseInformation(string fileName)
{
if (fileName == null || fileName.Length == 0) {
return null;
}
if (!parsings.ContainsKey(fileName)) {
return ParseFile(fileName);
}
return parsings[fileName];
}
public static IExpressionFinder GetExpressionFinder(string fileName)
{
IParser parser = GetParser(fileName);
if (parser != null) {
return parser.ExpressionFinder;
}
return null;
}
public static readonly string[] DefaultTaskListTokens = {"HACK", "TODO", "UNDONE", "FIXME"};
public static IParser GetParser(string fileName)
{
IParser curParser = null;
foreach (ParserDescriptor descriptor in parser) {
if (descriptor.CanParse(fileName)) {
curParser = descriptor.Parser;
break;
}
}
if (curParser != null) {
curParser.LexerTags = PropertyService.Get("SharpDevelop.TaskListTokens", DefaultTaskListTokens);
}
return curParser;
}
////////////////////////////////////
public static ArrayList CtrlSpace(int caretLine, int caretColumn, string fileName, string fileContent)
{
IParser parser = GetParser(fileName);
if (parser != null) {
return parser.CreateResolver().CtrlSpace(caretLine, caretColumn, fileName, fileContent);
}
return null;
}
public static ResolveResult Resolve(string expression,
int caretLineNumber,
int caretColumn,
string fileName,
string fileContent)
{
IParser parser = GetParser(fileName);
if (parser != null) {
return parser.CreateResolver().Resolve(expression, caretLineNumber, caretColumn, fileName, fileContent);
}
return null;
}
static void OnParseInformationUpdated(ParseInformationEventArgs e)
{
if (ParseInformationUpdated != null) {
ParseInformationUpdated(null, e);
}
}
public static event ParseInformationEventHandler ParseInformationUpdated;
}
}