Browse Source

added the memento pattern to VB Lexer (Import/Export of state)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/vbnet@6083 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Siegfried Pammer 16 years ago
parent
commit
7b5949bb2e
  1. 35
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs
  2. 114
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs
  3. 16
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Parser.cs
  4. 12
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/PushParser.frame

35
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs

@ -138,6 +138,30 @@ namespace ICSharpCode.NRefactory.Parser.VB
public List<Token> Errors { public List<Token> Errors {
get { return errors; } get { return errors; }
} }
public ExpressionFinderState Export()
{
return new ExpressionFinderState() {
WasQualifierTokenAtStart = wasQualifierTokenAtStart,
NextTokenIsPotentialStartOfExpression = nextTokenIsPotentialStartOfExpression,
NextTokenIsStartOfImportsOrAccessExpression = nextTokenIsStartOfImportsOrAccessExpression,
ReadXmlIdentifier = readXmlIdentifier,
StateStack = new Stack<int>(stateStack.Reverse()),
BlockStack = new Stack<Block>(stack.Select(x => (Block)x.Clone()).Reverse()),
CurrentState = currentState
};
}
}
public class ExpressionFinderState
{
public bool WasQualifierTokenAtStart { get; set; }
public bool NextTokenIsPotentialStartOfExpression { get; set; }
public bool ReadXmlIdentifier { get; set; }
public bool NextTokenIsStartOfImportsOrAccessExpression { get; set; }
public Stack<int> StateStack { get; set; }
public Stack<Block> BlockStack { get; set; }
public int CurrentState { get; set; }
} }
public enum Context public enum Context
@ -155,7 +179,7 @@ namespace ICSharpCode.NRefactory.Parser.VB
Default Default
} }
public class Block public class Block : ICloneable
{ {
public static readonly Block Default = new Block() { public static readonly Block Default = new Block() {
context = Context.Global, context = Context.Global,
@ -170,5 +194,14 @@ namespace ICSharpCode.NRefactory.Parser.VB
{ {
return string.Format("[Block Context={0}, LastExpressionStart={1}, IsClosed={2}]", context, lastExpressionStart, isClosed); return string.Format("[Block Context={0}, LastExpressionStart={1}, IsClosed={2}]", context, lastExpressionStart, isClosed);
} }
public object Clone()
{
return new Block() {
context = this.context,
lastExpressionStart = this.lastExpressionStart,
isClosed = this.isClosed
};
}
} }
} }

114
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs

@ -25,28 +25,28 @@ namespace ICSharpCode.NRefactory.Parser.VB
ExpressionFinder ef; ExpressionFinder ef;
#region XmlModeStackInfo
bool inXmlMode; bool inXmlMode;
class XmlModeStackInfo { Stack<XmlModeInfo> xmlModeStack = new Stack<XmlModeInfo>();
public bool inXmlTag, inXmlCloseTag, isDocumentStart;
public int level;
public XmlModeStackInfo(bool isSpecial)
{
level = isSpecial ? -1 : 0;
inXmlTag = inXmlCloseTag = isDocumentStart = false;
}
}
Stack<XmlModeStackInfo> xmlModeStack = new Stack<XmlModeStackInfo>();
#endregion
public Lexer(TextReader reader) : base(reader) public Lexer(TextReader reader) : base(reader)
{ {
ef = new ExpressionFinder(); ef = new ExpressionFinder();
} }
public Lexer(TextReader reader, LexerState state) : base(reader)
{
ef = new ExpressionFinder(state.ExpressionFinder);
SetInitialLocation(new Location(state.Column, state.Line));
lineEnd = state.LineEnd;
isAtLineBegin = state.IsAtLineBegin;
lastToken = new Token(state.PrevTokenKind, 0, 0);
encounteredLineContinuation = state.EncounteredLineContinuation;
misreadExclamationMarkAsTypeCharacter = state.MisreadExclamationMarkAsTypeCharacter;
xmlModeStack = new Stack<XmlModeInfo>(state.XmlModeInfoStack.Select(i => (XmlModeInfo)i.Clone()).Reverse());
inXmlMode = state.InXmlMode;
}
Token NextInternal() Token NextInternal()
{ {
if (misreadExclamationMarkAsTypeCharacter) { if (misreadExclamationMarkAsTypeCharacter) {
@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.Parser.VB
char ch = (char)nextChar; char ch = (char)nextChar;
#region XML mode #region XML mode
if (inXmlMode && xmlModeStack.Peek().level <= 0 && !xmlModeStack.Peek().isDocumentStart && !xmlModeStack.Peek().inXmlTag) { if (inXmlMode && xmlModeStack.Peek().level <= 0 && !xmlModeStack.Peek().isDocumentStart && !xmlModeStack.Peek().inXmlTag) {
XmlModeStackInfo info = xmlModeStack.Peek(); XmlModeInfo info = xmlModeStack.Peek();
int peek = nextChar; int peek = nextChar;
while (true) { while (true) {
int step = -1; int step = -1;
@ -89,7 +89,7 @@ namespace ICSharpCode.NRefactory.Parser.VB
xmlModeStack.Pop(); xmlModeStack.Pop();
} }
if (inXmlMode) { if (inXmlMode) {
XmlModeStackInfo info = xmlModeStack.Peek(); XmlModeInfo info = xmlModeStack.Peek();
int x = Col - 1; int x = Col - 1;
int y = Line; int y = Line;
switch (ch) { switch (ch) {
@ -319,8 +319,8 @@ namespace ICSharpCode.NRefactory.Parser.VB
} }
#endregion #endregion
if (ch == '<' && (ef.NextTokenIsPotentialStartOfExpression || ef.NextTokenIsStartOfImportsOrAccessExpression)) { if (ch == '<' && (ef.NextTokenIsPotentialStartOfExpression || ef.NextTokenIsStartOfImportsOrAccessExpression)) {
xmlModeStack.Push(new XmlModeStackInfo(ef.NextTokenIsStartOfImportsOrAccessExpression)); xmlModeStack.Push(new XmlModeInfo(ef.NextTokenIsStartOfImportsOrAccessExpression));
XmlModeStackInfo info = xmlModeStack.Peek(); XmlModeInfo info = xmlModeStack.Peek();
int x = Col - 1; int x = Col - 1;
int y = Line; int y = Line;
inXmlMode = true; inXmlMode = true;
@ -371,7 +371,7 @@ namespace ICSharpCode.NRefactory.Parser.VB
Debug.Assert(t.next == null); // NextInternal() must return only 1 token Debug.Assert(t.next == null); // NextInternal() must return only 1 token
t.next = NextInternal(); t.next = NextInternal();
Debug.Assert(t.next.next == null); Debug.Assert(t.next.next == null);
if (SkipEOL(prevToken, t.next)) { if (SkipEOL(prevToken.kind, t.next.kind)) {
t = t.next; t = t.next;
} }
} }
@ -391,7 +391,7 @@ namespace ICSharpCode.NRefactory.Parser.VB
} }
/// <remarks>see VB language specification 10; pg. 6</remarks> /// <remarks>see VB language specification 10; pg. 6</remarks>
bool SkipEOL(Token prevToken, Token nextToken) bool SkipEOL(int prevTokenKind, int nextTokenKind)
{ {
// exception directly after _ // exception directly after _
if (encounteredLineContinuation) { if (encounteredLineContinuation) {
@ -401,35 +401,35 @@ namespace ICSharpCode.NRefactory.Parser.VB
// 1st rule // 1st rule
// after a comma (,), open parenthesis ((), open curly brace ({), or open embedded expression (<%=) // after a comma (,), open parenthesis ((), open curly brace ({), or open embedded expression (<%=)
if (new[] { Tokens.Comma, Tokens.OpenParenthesis, Tokens.OpenCurlyBrace, Tokens.XmlStartInlineVB } if (new[] { Tokens.Comma, Tokens.OpenParenthesis, Tokens.OpenCurlyBrace, Tokens.XmlStartInlineVB }
.Contains(prevToken.kind)) .Contains(prevTokenKind))
return true; return true;
// 2nd rule // 2nd rule
// after a member qualifier (. or .@ or ...), provided that something is being qualified (i.e. is not // after a member qualifier (. or .@ or ...), provided that something is being qualified (i.e. is not
// using an implicit With context) // using an implicit With context)
if (new[] { Tokens.Dot, Tokens.DotAt, Tokens.TripleDot }.Contains(prevToken.kind) if (new[] { Tokens.Dot, Tokens.DotAt, Tokens.TripleDot }.Contains(prevTokenKind)
&& !ef.WasQualifierTokenAtStart) && !ef.WasQualifierTokenAtStart)
return true; return true;
// 3rd rule // 3rd rule
// before a close parenthesis ()), close curly brace (}), or close embedded expression (%>) // before a close parenthesis ()), close curly brace (}), or close embedded expression (%>)
if (new[] { Tokens.CloseParenthesis, Tokens.CloseCurlyBrace, Tokens.XmlEndInlineVB } if (new[] { Tokens.CloseParenthesis, Tokens.CloseCurlyBrace, Tokens.XmlEndInlineVB }
.Contains(nextToken.kind)) .Contains(nextTokenKind))
return true; return true;
// 4th rule // 4th rule
// after a less-than (<) in an attribute context // after a less-than (<) in an attribute context
if (prevToken.kind == Tokens.LessThan && ef.CurrentBlock.context == Context.Attribute) if (prevTokenKind == Tokens.LessThan && ef.CurrentBlock.context == Context.Attribute)
return true; return true;
// 5th rule // 5th rule
// before a greater-than (>) in an attribute context // before a greater-than (>) in an attribute context
if (nextToken.kind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute) if (nextTokenKind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute)
return true; return true;
// 6th rule // 6th rule
// after a greater-than (>) in a non-file-level attribute context // after a greater-than (>) in a non-file-level attribute context
if (prevToken.kind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute) if (prevTokenKind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute)
return true; return true;
// 7th rule // 7th rule
@ -437,23 +437,23 @@ namespace ICSharpCode.NRefactory.Parser.VB
var queryOperators = new int[] { Tokens.From, Tokens.Aggregate, Tokens.Select, Tokens.Distinct, var queryOperators = new int[] { Tokens.From, Tokens.Aggregate, Tokens.Select, Tokens.Distinct,
Tokens.Where, Tokens.Order, Tokens.By, Tokens.Ascending, Tokens.Descending, Tokens.Take, Tokens.Where, Tokens.Order, Tokens.By, Tokens.Ascending, Tokens.Descending, Tokens.Take,
Tokens.Skip, Tokens.Let, Tokens.Group, Tokens.Into, Tokens.On, Tokens.While, Tokens.Join }; Tokens.Skip, Tokens.Let, Tokens.Group, Tokens.Into, Tokens.On, Tokens.While, Tokens.Join };
if ((queryOperators.Contains(prevToken.kind) || queryOperators.Contains(nextToken.kind)) if ((queryOperators.Contains(prevTokenKind) || queryOperators.Contains(nextTokenKind))
&& ef.CurrentBlock.context == Context.Query) && ef.CurrentBlock.context == Context.Query)
return true; return true;
// 8th rule // 8th rule
// after binary operators (+, -, /, *, etc.) in an expression context // after binary operators (+, -, /, *, etc.) in an expression context
if (new[] { Tokens.Plus, Tokens.Minus, Tokens.Div, Tokens.DivInteger, Tokens.Times, Tokens.Mod, Tokens.Power, if (new[] { Tokens.Plus, Tokens.Minus, Tokens.Div, Tokens.DivInteger, Tokens.Times, Tokens.Mod, Tokens.Power,
Tokens.Assign, Tokens.NotEqual, Tokens.LessThan, Tokens.LessEqual, Tokens.GreaterThan, Tokens.GreaterEqual, Tokens.Assign, Tokens.NotEqual, Tokens.LessThan, Tokens.LessEqual, Tokens.GreaterThan, Tokens.GreaterEqual,
Tokens.Like, Tokens.ConcatString, Tokens.AndAlso, Tokens.OrElse, Tokens.And, Tokens.Or, Tokens.Xor, Tokens.Like, Tokens.ConcatString, Tokens.AndAlso, Tokens.OrElse, Tokens.And, Tokens.Or, Tokens.Xor,
Tokens.ShiftLeft, Tokens.ShiftRight }.Contains(prevToken.kind) && ef.CurrentBlock.context == Context.Expression) Tokens.ShiftLeft, Tokens.ShiftRight }.Contains(prevTokenKind) && ef.CurrentBlock.context == Context.Expression)
return true; return true;
// 9th rule // 9th rule
// after assignment operators (=, :=, +=, -=, etc.) in any context. // after assignment operators (=, :=, +=, -=, etc.) in any context.
if (new[] { Tokens.Assign, Tokens.ColonAssign, Tokens.ConcatStringAssign, Tokens.DivAssign, if (new[] { Tokens.Assign, Tokens.ColonAssign, Tokens.ConcatStringAssign, Tokens.DivAssign,
Tokens.DivIntegerAssign, Tokens.MinusAssign, Tokens.PlusAssign, Tokens.PowerAssign, Tokens.DivIntegerAssign, Tokens.MinusAssign, Tokens.PlusAssign, Tokens.PowerAssign,
Tokens.ShiftLeftAssign, Tokens.ShiftRightAssign, Tokens.TimesAssign }.Contains(prevToken.kind)) Tokens.ShiftLeftAssign, Tokens.ShiftRightAssign, Tokens.TimesAssign }.Contains(prevTokenKind))
return true; return true;
return false; return false;
@ -1130,5 +1130,57 @@ namespace ICSharpCode.NRefactory.Parser.VB
{ {
ef.SetContext(type); ef.SetContext(type);
} }
public LexerState Export()
{
return new LexerState() {
Column = Col,
Line = Line,
EncounteredLineContinuation = encounteredLineContinuation,
ExpressionFinder = ef.Export(),
InXmlMode = inXmlMode,
IsAtLineBegin = isAtLineBegin,
LineEnd = lineEnd,
PrevTokenKind = prevToken.kind,
MisreadExclamationMarkAsTypeCharacter = misreadExclamationMarkAsTypeCharacter,
XmlModeInfoStack = new Stack<XmlModeInfo>(xmlModeStack.Select(i => (XmlModeInfo)i.Clone()).Reverse())
};
}
}
public class XmlModeInfo : ICloneable
{
public bool inXmlTag, inXmlCloseTag, isDocumentStart;
public int level;
public XmlModeInfo(bool isSpecial)
{
level = isSpecial ? -1 : 0;
inXmlTag = inXmlCloseTag = isDocumentStart = false;
}
public object Clone()
{
return new XmlModeInfo(false) {
inXmlCloseTag = this.inXmlCloseTag,
inXmlTag = this.inXmlTag,
isDocumentStart = this.isDocumentStart,
level = this.level
};
}
}
public class LexerState
{
public bool LineEnd { get; set; }
public bool IsAtLineBegin { get; set; }
public bool MisreadExclamationMarkAsTypeCharacter { get; set; }
public bool EncounteredLineContinuation { get; set; }
public ExpressionFinderState ExpressionFinder { get; set; }
public Stack<XmlModeInfo> XmlModeInfoStack { get; set; }
public bool InXmlMode { get; set; }
public int Line { get; set; }
public int Column { get; set; }
public int PrevTokenKind { get; set; }
} }
} }

16
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Parser.cs

@ -2,13 +2,13 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
using System.Text; using System.Text;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser.VB; using ICSharpCode.NRefactory.Parser.VB;
using ASTAttribute = ICSharpCode.NRefactory.Ast.Attribute; using ASTAttribute = ICSharpCode.NRefactory.Ast.Attribute;
namespace ICSharpCode.NRefactory.Parser.VB { namespace ICSharpCode.NRefactory.Parser.VB {
@ -1189,6 +1189,18 @@ partial class ExpressionFinder {
{ {
stateStack.Push(-1); // required so that we don't crash when leaving the root production stateStack.Push(-1); // required so that we don't crash when leaving the root production
} }
public ExpressionFinder(ExpressionFinderState state)
{
wasQualifierTokenAtStart = state.WasQualifierTokenAtStart;
nextTokenIsPotentialStartOfExpression = state.NextTokenIsPotentialStartOfExpression;
nextTokenIsStartOfImportsOrAccessExpression = state.NextTokenIsStartOfImportsOrAccessExpression;
readXmlIdentifier = state.ReadXmlIdentifier;
stateStack = new Stack<int>(state.StateStack.Reverse());
stack = new Stack<Block>(state.BlockStack.Select(x => (Block)x.Clone()).Reverse());
currentState = state.CurrentState;
output = new StringBuilder();
}
void Expect(int expectedKind, Token la) void Expect(int expectedKind, Token la)
{ {

12
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/PushParser.frame

@ -44,6 +44,18 @@ partial class ExpressionFinder {
{ {
stateStack.Push(-1); // required so that we don't crash when leaving the root production stateStack.Push(-1); // required so that we don't crash when leaving the root production
} }
public ExpressionFinder(ExpressionFinderState state)
{
wasQualifierTokenAtStart = state.WasQualifierTokenAtStart;
nextTokenIsPotentialStartOfExpression = state.NextTokenIsPotentialStartOfExpression;
nextTokenIsStartOfImportsOrAccessExpression = state.NextTokenIsStartOfImportsOrAccessExpression;
readXmlIdentifier = state.ReadXmlIdentifier;
stateStack = new Stack<int>(state.StateStack.Reverse());
stack = new Stack<Block>(state.BlockStack.Select(x => (Block)x.Clone()).Reverse());
currentState = state.CurrentState;
output = new StringBuilder();
}
void Expect(int expectedKind, Token la) void Expect(int expectedKind, Token la)
{ {

Loading…
Cancel
Save