//
//
//
//
// $Revision$
//
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser;
namespace ICSharpCode.NRefactory
{
///
/// The snippet parser supports parsing code snippets that are not valid as a full compilation unit.
///
public class SnippetParser
{
readonly SupportedLanguage language;
public SnippetParser(SupportedLanguage language)
{
this.language = language;
}
Errors errors;
List specials;
///
/// Gets the errors of the last call to Parse(). Returns null if parse was not yet called.
///
public Errors Errors {
get { return errors; }
}
///
/// Gets the specials of the last call to Parse(). Returns null if parse was not yet called.
///
public List Specials {
get { return specials; }
}
///
/// 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)
{
IParser parser = ParserFactory.CreateParser(language, new StringReader(code));
parser.Parse();
errors = parser.Errors;
specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
INode result = parser.CompilationUnit;
if (errors.Count > 0) {
if (language == SupportedLanguage.CSharp) {
// SEMICOLON HACK : without a trailing semicolon, parsing expressions does not work correctly
parser = ParserFactory.CreateParser(language, new StringReader(code + ";"));
} else {
parser = ParserFactory.CreateParser(language, new StringReader(code));
}
Expression expression = parser.ParseExpression();
if (expression != null && parser.Errors.Count < errors.Count) {
errors = parser.Errors;
specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
result = expression;
}
}
if (errors.Count > 0) {
parser = ParserFactory.CreateParser(language, new StringReader(code));
BlockStatement block = parser.ParseBlock();
if (block != null && parser.Errors.Count < errors.Count) {
errors = parser.Errors;
specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
result = block;
}
}
if (errors.Count > 0) {
parser = ParserFactory.CreateParser(language, new StringReader(code));
List members = parser.ParseTypeMembers();
if (members != null && members.Count > 0 && parser.Errors.Count < errors.Count) {
errors = parser.Errors;
specials = parser.Lexer.SpecialTracker.RetrieveSpecials();
result = new NodeListNode(members);
}
}
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 { return Location.Empty; }
set { throw new NotSupportedException(); }
}
public Location EndLocation {
get { return Location.Empty; }
set { throw new NotSupportedException(); }
}
public object UserData { get; set; }
public object AcceptChildren(IAstVisitor visitor, object data)
{
foreach (INode n in nodes) {
n.AcceptVisitor(visitor, data);
}
return null;
}
public object AcceptVisitor(IAstVisitor visitor, object data)
{
return AcceptChildren(visitor, data);
}
}
}
}