#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.
 
 
 
 
 
 

500 lines
11 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
// <license see="prj:///doc/license.txt">GNU General Public License</license>
// <owner name="Markus Palme" email="MarkusPalme@gmx.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Text;
using ICSharpCode.SharpDevelop.Dom;
namespace VBNetBinding.Parser
{
/// <summary>
/// Description of ExpressionFinder.
/// </summary>
public class ExpressionFinder : IExpressionFinder
{
ExpressionResult CreateResult(string expression)
{
if (expression == null)
return new ExpressionResult(null);
if (expression.Length > 8 && expression.Substring(0, 8).Equals("Imports ", StringComparison.InvariantCultureIgnoreCase))
return new ExpressionResult(expression.Substring(8).TrimStart(), ExpressionContext.Namespace, null);
if (expression.Length > 4 && expression.Substring(0, 4).Equals("New ", StringComparison.InvariantCultureIgnoreCase))
return new ExpressionResult(expression.Substring(4).TrimStart(), ExpressionContext.ObjectCreation, null);
return new ExpressionResult(expression);
}
public ExpressionResult FindExpression(string inText, int offset)
{
return CreateResult(FindExpressionInternal(inText, offset));
}
public string FindExpressionInternal(string inText, int offset)
{
this.text = FilterComments(inText, ref offset);
this.offset = this.lastAccept = offset;
this.state = START;
if (this.text == null)
{
return null;
}
while (state != ERROR)
{
ReadNextToken();
//Console.WriteLine("cur state {0} got token {1}/{3} going to {2}", GetStateName(state), GetTokenName(curTokenType), GetStateName(stateTable[state, curTokenType]), curTokenType);
state = stateTable[state, curTokenType];
if (state == ACCEPT || state == ACCEPT2)
{
lastAccept = this.offset;
}
if (state == ACCEPTNOMORE)
{
return this.text.Substring(this.offset + 1, offset - this.offset);
}
}
return this.text.Substring(this.lastAccept + 1, offset - this.lastAccept);
}
internal int LastExpressionStartPosition {
get {
return ((state == ACCEPTNOMORE) ? offset : lastAccept) + 1;
}
}
public ExpressionResult FindFullExpression(string inText, int offset)
{
string expressionBeforeOffset = FindExpressionInternal(inText, offset);
if (expressionBeforeOffset == null || expressionBeforeOffset.Length == 0)
return CreateResult(null);
StringBuilder b = new StringBuilder(expressionBeforeOffset);
// append characters after expression
for (int i = offset + 1; i < inText.Length; ++i) {
char c = inText[i];
if (Char.IsLetterOrDigit(c)) {
if (Char.IsWhiteSpace(inText, i - 1))
break;
b.Append(c);
} else if (c == ' ') {
b.Append(c);
} else if (c == '(') {
int otherBracket = SearchBracketForward(inText, i + 1, '(', ')');
if (otherBracket < 0)
break;
b.Append(inText, i, otherBracket - i + 1);
break;
} else {
break;
}
}
return CreateResult(b.ToString());
}
// Like VBNetFormattingStrategy.SearchBracketForward, but operates on a string.
private int SearchBracketForward(string text, int offset, char openBracket, char closingBracket)
{
bool inString = false;
bool inComment = false;
int brackets = 1;
for (int i = offset; i < text.Length; ++i) {
char ch = text[i];
if (ch == '\n') {
inString = false;
inComment = false;
}
if (inComment) continue;
if (ch == '"') inString = !inString;
if (inString) continue;
if (ch == '\'') {
inComment = true;
} else if (ch == openBracket) {
++brackets;
} else if (ch == closingBracket) {
--brackets;
if (brackets == 0) return i;
}
}
return -1;
}
#region Comment Filter and 'inside string watcher'
int initialOffset;
public string FilterComments(string text, ref int offset)
{
this.initialOffset = offset;
StringBuilder outText = new StringBuilder();
int curOffset = 0;
while (curOffset <= initialOffset)
{
char ch = text[curOffset];
switch (ch)
{
case '@':
if (curOffset + 1 < text.Length && text[curOffset + 1] == '"')
{
outText.Append(text[curOffset++]); // @
outText.Append(text[curOffset++]); // "
if (!ReadVerbatimString(outText, text, ref curOffset))
{
return null;
}
}
else
{
outText.Append(ch);
++curOffset;
}
break;
case '"':
outText.Append(ch);
curOffset++;
if (!ReadString(outText, text, ref curOffset))
{
return null;
}
break;
case '\'':
offset -= 1;
curOffset += 1;
if (!ReadToEOL(text, ref curOffset, ref offset))
{
return null;
}
break;
default:
outText.Append(ch);
++curOffset;
break;
}
}
return outText.ToString();
}
bool ReadToEOL(string text, ref int curOffset, ref int offset)
{
while (curOffset <= initialOffset)
{
char ch = text[curOffset++];
--offset;
if (ch == '\n')
{
return true;
}
}
return false;
}
bool ReadString(StringBuilder outText, string text, ref int curOffset)
{
while (curOffset <= initialOffset)
{
char ch = text[curOffset++];
outText.Append(ch);
if (ch == '"')
{
return true;
}
}
return false;
}
bool ReadVerbatimString(StringBuilder outText, string text, ref int curOffset)
{
while (curOffset <= initialOffset)
{
char ch = text[curOffset++];
outText.Append(ch);
if (ch == '"')
{
if (curOffset < text.Length && text[curOffset] == '"')
{
outText.Append(text[curOffset++]);
}
else
{
return true;
}
}
}
return false;
}
bool ReadMultiLineComment(string text, ref int curOffset, ref int offset)
{
while (curOffset <= initialOffset)
{
char ch = text[curOffset++];
--offset;
if (ch == '*')
{
if (curOffset < text.Length && text[curOffset] == '/')
{
++curOffset;
--offset;
return true;
}
}
}
return false;
}
#endregion
#region mini backward lexer
string text;
int offset;
char GetNext()
{
if (offset >= 0)
{
return text[offset--];
}
return '\0';
}
char Peek()
{
if (offset >= 0)
{
return text[offset];
}
return '\0';
}
void UnGet()
{
++offset;
}
// tokens for our lexer
static int Err = 0;
static int Dot = 1;
static int StrLit = 2;
static int Ident = 3;
static int New = 4;
// static int Bracket = 5;
static int Parent = 6;
static int Curly = 7;
static int Using = 8;
int curTokenType;
readonly static string[] tokenStateName = new string[] {
"Err", "Dot", "StrLit", "Ident", "New", "Bracket", "Paren", "Curly", "Using"
};
string GetTokenName(int state)
{
return tokenStateName[state];
}
void ReadNextToken()
{
char ch = GetNext();
curTokenType = Err;
if (ch == '\0' || ch == '\n' || ch == '\r')
{
return;
}
while (Char.IsWhiteSpace(ch))
{
ch = GetNext();
if (ch == '\n' || ch == '\r')
{
return;
}
}
switch (ch)
{
case '}':
if (ReadBracket('{', '}'))
{
curTokenType = Curly;
}
break;
case ')':
if (ReadBracket('(', ')'))
{
curTokenType = Parent;
}
break;
case ']':
if (ReadBracket('[', ']'))
{
curTokenType = Ident;
}
break;
case '.':
curTokenType = Dot;
break;
case '\'':
case '"':
if (ReadStringLiteral(ch))
{
curTokenType = StrLit;
}
break;
default:
if (IsIdentifierPart(ch))
{
string ident = ReadIdentifier(ch);
if (ident != null)
{
switch (ident.ToLower())
{
case "new":
curTokenType = New;
break;
case "imports":
curTokenType = Using;
break;
default:
curTokenType = Ident;
break;
}
}
}
break;
}
}
bool ReadStringLiteral(char litStart)
{
while (true)
{
char ch = GetNext();
if (ch == '\0')
{
return false;
}
if (ch == litStart)
{
if (Peek() == '@' && litStart == '"')
{
GetNext();
}
return true;
}
}
}
bool ReadBracket(char openBracket, char closingBracket)
{
int curlyBraceLevel = 0;
int squareBracketLevel = 0;
int parenthesisLevel = 0;
switch (openBracket)
{
case '(':
parenthesisLevel++;
break;
case '[':
squareBracketLevel++;
break;
case '{':
curlyBraceLevel++;
break;
}
while (parenthesisLevel != 0 || squareBracketLevel != 0 || curlyBraceLevel != 0)
{
char ch = GetNext();
if (ch == '\0')
{
return false;
}
switch (ch)
{
case '(':
parenthesisLevel--;
break;
case '[':
squareBracketLevel--;
break;
case '{':
curlyBraceLevel--;
break;
case ')':
parenthesisLevel++;
break;
case ']':
squareBracketLevel++;
break;
case '}':
curlyBraceLevel++;
break;
}
}
return true;
}
string ReadIdentifier(char ch)
{
string identifier = ch.ToString();
while (IsIdentifierPart(Peek()))
{
identifier = GetNext() + identifier;
}
return identifier;
}
bool IsIdentifierPart(char ch)
{
return Char.IsLetterOrDigit(ch) || ch == '_';
}
#endregion
#region finite state machine
readonly static int ERROR = 0;
readonly static int START = 1;
readonly static int DOT = 2;
readonly static int MORE = 3;
readonly static int CURLY = 4;
readonly static int CURLY2 = 5;
readonly static int CURLY3 = 6;
readonly static int ACCEPT = 7;
readonly static int ACCEPTNOMORE = 8;
readonly static int ACCEPT2 = 9;
readonly static string[] stateName = new string[] {
"ERROR",
"START",
"DOT",
"MORE",
"CURLY",
"CURLY2",
"CURLY3",
"ACCEPT",
"ACCEPTNOMORE",
"ACCEPT2"
};
string GetStateName(int state)
{
return stateName[state];
}
int state = 0;
int lastAccept = 0;
static int[,] stateTable = new int[,] {
// Err, Dot, Str, ID, New, Brk, Par, Cur, Using
/*ERROR*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR},
/*START*/ { ERROR, DOT, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ACCEPTNOMORE},
/*DOT*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT, CURLY, ERROR},
/*MORE*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ERROR},
/*CURLY*/ { ERROR, ERROR, ERROR, ERROR, ERROR, CURLY2, ERROR, ERROR, ERROR},
/*CURLY2*/ { ERROR, ERROR, ERROR, CURLY3, ERROR, ERROR, ERROR, ERROR, ERROR},
/*CURLY3*/ { ERROR, ERROR, ERROR, ERROR, ACCEPTNOMORE, ERROR, ERROR, ERROR, ERROR},
/*ACCEPT*/ { ERROR, MORE, ERROR, ERROR, ACCEPT, ERROR, ERROR, ERROR, ACCEPTNOMORE},
/*ACCEPTNOMORE*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR},
/*ACCEPT2*/ { ERROR, MORE, ERROR, ACCEPT, ACCEPT, ERROR, ERROR, ERROR, ERROR},
};
#endregion
}
}