// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ICSharpCode.NRefactory.VB.Dom;
using ICSharpCode.NRefactory.VB.Parser;
namespace ICSharpCode.NRefactory.VB
{
public enum SnippetType
{
None,
CompilationUnit,
Expression,
Statements,
TypeMembers
}
///
/// The snippet parser supports parsing code snippets that are not valid as a full compilation unit.
///
public class SnippetParser
{
///
/// Gets the errors of the last call to Parse(). Returns null if parse was not yet called.
///
public Errors Errors { get; private set; }
///
/// Gets the specials of the last call to Parse(). Returns null if parse was not yet called.
///
public List Specials { get; private set; }
///
/// Gets the snippet type of the last call to Parse(). Returns None if parse was not yet called.
///
public SnippetType SnippetType { get; private set; }
///
/// Parse the code. The result may be a CompilationUnit, an Expression, a list of statements or a list of class
/// members.
///
public INode Parse(string code)
{
VBParser parser = ParserFactory.CreateParser(new StringReader(code));
parser.Parse();
this.Errors = parser.Errors;
this.Specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
this.SnippetType = SnippetType.CompilationUnit;
INode result = parser.CompilationUnit;
if (this.Errors.Count > 0) {
parser = ParserFactory.CreateParser(new StringReader(code));
Expression expression = parser.ParseExpression();
if (expression != null && parser.Errors.Count < this.Errors.Count) {
this.Errors = parser.Errors;
this.Specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
this.SnippetType = SnippetType.Expression;
result = expression;
}
}
if (this.Errors.Count > 0) {
parser = ParserFactory.CreateParser(new StringReader(code));
BlockStatement block = parser.ParseBlock();
if (block != null && parser.Errors.Count < this.Errors.Count) {
this.Errors = parser.Errors;
this.Specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
this.SnippetType = SnippetType.Statements;
result = block;
}
}
if (this.Errors.Count > 0) {
parser = ParserFactory.CreateParser(new StringReader(code));
List members = parser.ParseTypeMembers();
if (members != null && members.Count > 0 && parser.Errors.Count < this.Errors.Count) {
this.Errors = parser.Errors;
this.Specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
this.SnippetType = SnippetType.TypeMembers;
result = new NodeListNode(members);
result.StartLocation = members[0].StartLocation;
result.EndLocation = members[members.Count - 1].EndLocation;
}
}
Debug.Assert(result is CompilationUnit || !result.StartLocation.IsEmpty);
Debug.Assert(result is CompilationUnit || !result.EndLocation.IsEmpty);
return result;
}
sealed class NodeListNode : INode
{
List nodes;
public NodeListNode(List nodes)
{
this.nodes = nodes;
}
public INode Parent {
get { return null; }
set { throw new NotSupportedException(); }
}
public List Children {
get { return nodes; }
}
public Location StartLocation { get; set; }
public Location EndLocation { get; set; }
public object UserData { get; set; }
public object AcceptChildren(IDomVisitor visitor, object data)
{
foreach (INode n in nodes) {
n.AcceptVisitor(visitor, data);
}
return null;
}
public object AcceptVisitor(IDomVisitor visitor, object data)
{
return AcceptChildren(visitor, data);
}
}
}
}