/// <summary>
		/// Converts a Mono.CSharpPs syntax tree into an NRefactory syntax tree.
		/// </summary>
		public SyntaxTree Parse(CompilerCompilationUnit top, string fileName)
		{
			if (top == null) {
				return null;
			}
			PlayScriptParser.ConversionVisitor conversionVisitor = new ConversionVisitor (GenerateTypeSystemMode, top.LocationsBag);
			top.ModuleCompiled.Accept(conversionVisitor);
			conversionVisitor.Unit.FixOutOfOrderLocations(); // Reorder locations that are incorrect for PlayScript
			InsertComments(top, conversionVisitor);
			if (CompilationUnitCallback != null) {
				CompilationUnitCallback(top);
			}
			if (top.LastYYValue is Mono.CSharpPs.Expression) {
				conversionVisitor.Unit.TopExpression = ((Mono.CSharpPs.Expression)top.LastYYValue).Accept(conversionVisitor) as AstNode;
			}

			conversionVisitor.Unit.FileName = fileName;
			conversionVisitor.Unit.ConditionalSymbols = top.Conditionals.Concat (compilerSettings.ConditionalSymbols).ToArray ();
			return conversionVisitor.Unit;
		}
		SyntaxTree Parse(ITextSource program, string fileName, int initialLine, int initialColumn)
		{
			lock (parseLock) {
				errorReportPrinter = new ErrorReportPrinter ("");
				var ctx = new CompilerContext (compilerSettings.ToMono(), errorReportPrinter);
				ctx.Settings.TabSize = 1;
				var reader = new SeekableStreamReader (program);
				var file = new SourceFile (fileName, fileName, 0);
				Location.Initialize (new List<SourceFile> (new [] { file }));
				var module = new ModuleContainer (ctx);
				var session = new ParserSession ();
				session.LocationsBag = new LocationsBag ();
				var report = new Report (ctx, errorReportPrinter);
				CompilerCompilationUnit top;
				if (String.IsNullOrEmpty(fileName) || fileName.EndsWith(".play") || fileName.EndsWith(".as")) {
					if (String.IsNullOrEmpty(fileName) || fileName.EndsWith(".play"))
						file.PsExtended = true; // Assume playscript unless we have an actual file ext.
					var parser = (Mono.PlayScript.PlayScriptParser)Driver.Parse(reader, file, module, session, report, initialLine - 1, initialColumn - 1);
					top = new CompilerCompilationUnit() {
						ModuleCompiled = module,
						LocationsBag = session.LocationsBag,
						SpecialsBag = parser.Lexer.sbag,
						Conditionals = parser.Lexer.SourceFile.Conditionals
					};
				} else {
					var parser = (Mono.CSharpPs.CSharpParser)Driver.Parse(reader, file, module, session, report, initialLine - 1, initialColumn - 1);
					top = new CompilerCompilationUnit() {
						ModuleCompiled = module,
						LocationsBag = session.LocationsBag,
						SpecialsBag = parser.Lexer.sbag,
						Conditionals = parser.Lexer.SourceFile.Conditionals
					};
				}
				var unit = Parse (top, fileName);
				unit.Errors.AddRange (errorReportPrinter.Errors);
				CompilerCallableEntryPoint.Reset ();
				return unit;
			}
		}
		static void InsertComments (CompilerCompilationUnit top, ConversionVisitor conversionVisitor)
		{
			var leaf = GetOuterLeft (conversionVisitor.Unit);
			for (int i = 0; i < top.SpecialsBag.Specials.Count; i++) {
				var special = top.SpecialsBag.Specials [i];
				AstNode newLeaf = null;
				var comment = special as SpecialsBag.Comment;
				if (comment != null) {
					// HACK: multiline documentation comment detection; better move this logic into the mcs tokenizer
					bool isMultilineDocumentationComment = (
						comment.CommentType == SpecialsBag.CommentType.Multi
						&& comment.Content.StartsWith("*", StringComparison.Ordinal)
						&& !comment.Content.StartsWith("**", StringComparison.Ordinal)
					);
					if (conversionVisitor.convertTypeSystemMode && !(comment.CommentType == SpecialsBag.CommentType.Documentation || isMultilineDocumentationComment))
						continue;
					var type = isMultilineDocumentationComment ? CommentType.MultiLineDocumentation : (CommentType)comment.CommentType;
					var start = new TextLocation (comment.Line, comment.Col);
					var end = new TextLocation (comment.EndLine, comment.EndCol);
					newLeaf = new Comment (type, start, end) {
						StartsLine = comment.StartsLine,
						Content = isMultilineDocumentationComment ? comment.Content.Substring(1) : comment.Content
					};
				} else {
					var directive = special as SpecialsBag.PreProcessorDirective;
					if (directive != null) {
						newLeaf = new PreProcessorDirective ((ICSharpCode.NRefactory.PlayScript.PreProcessorDirectiveType)((int)directive.Cmd & 0xF), new TextLocation (directive.Line, directive.Col), new TextLocation (directive.EndLine, directive.EndCol)) {
							Argument = directive.Arg,
							Take = directive.Take
						};
					} else {
	/*					var newLine = special as SpecialsBag.NewLineToken;
						if (newLine != null) {
							if (newLine.NewLine == SpecialsBag.NewLine.Unix) {
								newLeaf = new UnixNewLine (new TextLocation (newLine.Line, newLine.Col));
							} else {
								newLeaf = new WindowsNewLine (new TextLocation (newLine.Line, newLine.Col));
							}
						}*/
					}
				}
				if (newLeaf == null)
					continue;
				
				while (true) {
					var nextLeaf = NextLeaf (leaf);
					// insert comment at begin
					if (newLeaf.StartLocation < leaf.StartLocation) {
						var node = leaf.Parent ?? conversionVisitor.Unit;
						while (node.Parent != null && node.FirstChild == leaf) {
							leaf = node;
							node = node.Parent;
						}
						if (newLeaf is NewLineNode) {
							node.InsertChildBefore (leaf, (NewLineNode)newLeaf, Roles.NewLine);
						} else if (newLeaf is Comment) {
							node.InsertChildBefore (leaf, (Comment)newLeaf, Roles.Comment);
						} else {
							node.InsertChildBefore (leaf, (PreProcessorDirective)newLeaf, Roles.PreProcessorDirective);
						}
						leaf = newLeaf;
						break;
					}
					
					// insert comment at the end
					if (nextLeaf == null) {
						var node = leaf.Parent ?? conversionVisitor.Unit;
						if (newLeaf is NewLineNode) {
							node.AddChild ((NewLineNode)newLeaf, Roles.NewLine);
						} else if (newLeaf is Comment) {
							node.AddChild ((Comment)newLeaf, Roles.Comment);
						} else {
							node.AddChild ((PreProcessorDirective)newLeaf, Roles.PreProcessorDirective);
						}
						leaf = newLeaf;
						break;
					}
					
					// comment is between 2 nodes
					if (leaf.EndLocation <= newLeaf.StartLocation && newLeaf.StartLocation <= nextLeaf.StartLocation) {
						var node = leaf.Parent ?? conversionVisitor.Unit;
						if (newLeaf is NewLineNode) {
							node.InsertChildAfter (leaf, (NewLineNode)newLeaf, Roles.NewLine);
						} else if (newLeaf is Comment) {
							node.InsertChildAfter (leaf, (Comment)newLeaf, Roles.Comment);
						} else {
							node.InsertChildAfter (leaf, (PreProcessorDirective)newLeaf, Roles.PreProcessorDirective);
						}
						leaf = newLeaf;
						break;
					}
					leaf = nextLeaf;
				}
			}
		}