From 4c47339173d80cfe8406f7aa48b9dfe4bacfa988 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 11 Jul 2010 15:08:59 +0000 Subject: [PATCH] - reorganised some files of the VB Lexer - fixed a bug in the ILC detection - started with CC implementation based on new API git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/vbnet@6088 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/VBNetCodeCompletionDataProvider.cs | 51 ++++++ .../Project/Src/VBNetCompletionBinding.cs | 161 +++++++++++++++++- .../VBNetBinding/Project/VBNetBinding.addin | 8 +- .../VBNetBinding/Project/VBNetBinding.csproj | 1 + .../NRefactory/Project/NRefactory.csproj | 8 +- .../Project/Src/Lexer/AbstractLexer.cs | 8 +- .../NRefactory/Project/Src/Lexer/ILexer.cs | 4 +- ...{AbstractLexerState.cs => LexerMemento.cs} | 2 +- .../Project/Src/Lexer/SavepointEventArgs.cs | 24 +++ .../Project/Src/Lexer/VBNet/Block.cs | 55 ++++++ .../Src/Lexer/VBNet/ExpressionFinder.cs | 59 +------ .../Src/Lexer/VBNet/ExpressionFinderState.cs | 25 +++ .../Project/Src/Lexer/VBNet/Extensions.cs | 26 +++ .../Project/Src/Lexer/VBNet/Lexer.cs | 18 +- .../{VBLexerState.cs => VBLexerMemento.cs} | 2 +- .../NRefactory/Project/Src/ParserFactory.cs | 2 +- .../VBNet/ImplicitLineContinuationTests.cs | 46 +++++ .../NRefactoryResolver/NRefactoryResolver.cs | 9 - .../Src/VBNet/VBNetExpressionFinder.cs | 11 +- 19 files changed, 425 insertions(+), 95 deletions(-) create mode 100644 src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCodeCompletionDataProvider.cs rename src/Libraries/NRefactory/Project/Src/Lexer/{AbstractLexerState.cs => LexerMemento.cs} (90%) create mode 100644 src/Libraries/NRefactory/Project/Src/Lexer/SavepointEventArgs.cs create mode 100644 src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Block.cs create mode 100644 src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinderState.cs create mode 100644 src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Extensions.cs rename src/Libraries/NRefactory/Project/Src/Lexer/VBNet/{VBLexerState.cs => VBLexerMemento.cs} (92%) diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCodeCompletionDataProvider.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCodeCompletionDataProvider.cs new file mode 100644 index 0000000000..2af78c4881 --- /dev/null +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCodeCompletionDataProvider.cs @@ -0,0 +1,51 @@ +// +// +// +// +// $Revision: 6077 $ +// + +using System; +using System.Collections; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Parser.VB; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.VBNetBinding +{ + public class VBNetCodeCompletionDataProvider : NRefactoryCtrlSpaceCompletionItemProvider + { + ExpressionResult result; + + public VBNetCodeCompletionDataProvider(ExpressionResult result) + : base(LanguageProperties.VBNet, result.Context) + { + this.result = result; + } + + protected override List CtrlSpace(ITextEditor editor, ExpressionContext context) + { + var list = base.CtrlSpace(editor, context); + + BitArray expectedSet = result.Tag as BitArray; + + if (expectedSet != null) + AddVBNetKeywords(list, expectedSet); + + return list; + } + + static void AddVBNetKeywords(List ar, BitArray keywords) + { + for (int i = 0; i < keywords.Length; i++) { + if (keywords[i] && i >= Tokens.AddHandler) { + ar.Add(new KeywordEntry(Tokens.GetTokenString(i))); + } + } + } + } +} diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs index 965d9625e7..55a4f8ff4a 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs @@ -6,7 +6,16 @@ // using System; +using System.Collections; +using System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.NRefactory.Parser.VB; using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; +using ICSharpCode.SharpDevelop.Dom.VBNet; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; @@ -14,34 +23,176 @@ namespace ICSharpCode.VBNetBinding { public class VBNetCompletionBinding : ICodeCompletionBinding { + static VBNetCompletionBinding instance; + + public static VBNetCompletionBinding Instance { + get { + if (instance == null) + instance = new VBNetCompletionBinding(); + return instance; + } + } + public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) { + if (IsInComment(editor)) + return CodeCompletionKeyPressResult.None; + switch (ch) { + case '\n': + break; case ' ': if (CodeCompletionOptions.KeywordCompletionEnabled) { string word = editor.GetWordBeforeCaret(); if (!string.IsNullOrEmpty(word)) { - if (HandleKeyword(editor, word)) - return CodeCompletionKeyPressResult.Completed; + var list = HandleKeyword(editor, word); + editor.ShowCompletionWindow(list); + return CodeCompletionKeyPressResult.Completed; } } break; default: - + if (CodeCompletionOptions.CompleteWhenTyping) { + if (editor.SelectionLength > 0) { + // allow code completion when overwriting an identifier + int endOffset = editor.SelectionStart + editor.SelectionLength; + // but block code completion when overwriting only part of an identifier + if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset))) + return CodeCompletionKeyPressResult.None; + + editor.Document.Remove(editor.SelectionStart, editor.SelectionLength); + } + int cursor = editor.Caret.Offset; + char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' '; + bool afterUnderscore = prevChar == '_'; + if (afterUnderscore) { + cursor--; + prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' '; + } + if (!char.IsLetterOrDigit(prevChar) && prevChar != '.') { + VBNetExpressionFinder ef = new VBNetExpressionFinder(ParserService.GetParseInformation(editor.FileName)); + ExpressionResult result = ef.FindExpression(editor.Document.Text, cursor); + LoggingService.Debug("CC: Beginning to type a word, result=" + result + ", context=" + result.Context); + if (result.Context != ExpressionContext.IdentifierExpected) { + var provider = new VBNetCodeCompletionDataProvider(result); + provider.ShowTemplates = true; + provider.AllowCompleteExistingExpression = afterUnderscore; + provider.ShowCompletion(editor); + return CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion; + } + } + } break; } return CodeCompletionKeyPressResult.None; } + bool IsInComment(ITextEditor editor) + { + ILexer lexer = ParserFactory.CreateLexer(SupportedLanguage.VBNet, editor.Document.CreateReader()); + + Token t = lexer.NextToken(); + bool inXml = false; + + while (t.Location < editor.Caret.Position) { + t = lexer.NextToken(); + + if (inXml && (t.Kind != Tokens.Identifier && t.Kind != Tokens.LiteralString && !(t.Kind > Tokens.LiteralDate && t.Kind < Tokens.Colon))) { + inXml = false; + continue; + } + + if (t.Kind > Tokens.LiteralDate && t.Kind < Tokens.Assign) + inXml = true; + } + + if (inXml) { + return true; + } else { + string lineText = editor.Document.GetLine(t.Location.Line).Text; + + bool inString = false; + bool inComment = false; + + for (int i = 0; i < lineText.Length; i++) { + char ch = lineText[i]; + + if (!inComment && ch == '"') + inString = !inString; + if (!inString && ch == '\'') + inComment = true; + } + + return inComment; + } + } + public bool CtrlSpace(ITextEditor editor) { + if (IsInComment(editor)) + return false; + + if (editor.SelectionLength > 0) { + // allow code completion when overwriting an identifier + int endOffset = editor.SelectionStart + editor.SelectionLength; + // but block code completion when overwriting only part of an identifier + if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset))) + return false; + + editor.Document.Remove(editor.SelectionStart, editor.SelectionLength); + } + int cursor = editor.Caret.Offset; + char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' '; + bool afterUnderscore = prevChar == '_'; + if (afterUnderscore) { + cursor--; + prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' '; + } + if (!char.IsLetterOrDigit(prevChar) && prevChar != '.') { + VBNetExpressionFinder ef = new VBNetExpressionFinder(ParserService.GetParseInformation(editor.FileName)); + ExpressionResult result = ef.FindExpression(editor.Document.Text, cursor); + LoggingService.Debug("CC: Beginning to type a word, result=" + result + ", context=" + result.Context); + if (result.Context != ExpressionContext.IdentifierExpected) { + var provider = new VBNetCodeCompletionDataProvider(result); + provider.ShowTemplates = true; + provider.AllowCompleteExistingExpression = afterUnderscore; + provider.ShowCompletion(editor); + return true; + } + } + return false; } - bool HandleKeyword(ITextEditor editor, string word) + sealed class GlobalCompletionItemProvider : CodeCompletionItemProvider { - return false; + public override ExpressionResult GetExpression(ITextEditor editor) + { + return new ExpressionResult("Global", ExpressionContext.Importable); + } + } + + ICompletionItemList HandleKeyword(ITextEditor editor, string word) + { + DefaultCompletionItemList list = new DefaultCompletionItemList(); + + switch (word.ToLowerInvariant()) { + case "option": + return new TextCompletionItemProvider( + "Explicit On", "Explicit Off", + "Strict On", "Strict Off", + "Compare Binary", "Compare Text", + "Infer On", "Infer Off" + ).GenerateCompletionList(editor); + case "imports": + return new GlobalCompletionItemProvider().GenerateCompletionList(editor); + break; + } + + return list; } } + + } diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin index e68506c602..6af347b302 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin @@ -1,7 +1,7 @@ - @@ -96,7 +96,7 @@ - + diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj index ffff1cdd5d..28e9ef37a8 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj @@ -54,6 +54,7 @@ + diff --git a/src/Libraries/NRefactory/Project/NRefactory.csproj b/src/Libraries/NRefactory/Project/NRefactory.csproj index ea015e9367..9e9585c33b 100644 --- a/src/Libraries/NRefactory/Project/NRefactory.csproj +++ b/src/Libraries/NRefactory/Project/NRefactory.csproj @@ -61,8 +61,12 @@ - + + + + + ExpressionFinder.atg @@ -91,7 +95,7 @@ Configuration\GlobalAssemblyInfo.cs - + diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs index e0cb082431..1467132c16 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs @@ -196,7 +196,7 @@ namespace ICSharpCode.NRefactory.Parser this.reader = new LATextReader(reader); } - protected AbstractLexer(TextReader reader, AbstractLexerState state) + protected AbstractLexer(TextReader reader, LexerMemento state) : this(reader) { SetInitialLocation(new Location(state.Column, state.Line)); @@ -368,16 +368,16 @@ namespace ICSharpCode.NRefactory.Parser /// public abstract void SkipCurrentBlock(int targetToken); - public event EventHandler SavepointReached; + public event EventHandler SavepointReached; - protected virtual void OnSavepointReached(EventArgs e) + protected virtual void OnSavepointReached(SavepointEventArgs e) { if (SavepointReached != null) { SavepointReached(this, e); } } - public virtual AbstractLexerState Export() + public virtual LexerMemento Export() { throw new NotSupportedException(); } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs index a5f9378b13..a40f9e0d33 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs @@ -111,12 +111,12 @@ namespace ICSharpCode.NRefactory.Parser /// Used to export the current state of the lexer. The exported state should be /// complete, so that it is possible to reset the lexer to a previous state completely. /// - AbstractLexerState Export(); + LexerMemento Export(); /// /// Is fired by the lexer as soon as a savepoint is reached. /// The Export-method can be used to retrieve the current state. /// - event EventHandler SavepointReached; + event EventHandler SavepointReached; } } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexerState.cs b/src/Libraries/NRefactory/Project/Src/Lexer/LexerMemento.cs similarity index 90% rename from src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexerState.cs rename to src/Libraries/NRefactory/Project/Src/Lexer/LexerMemento.cs index 666954df76..abfcb7823d 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexerState.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/LexerMemento.cs @@ -8,7 +8,7 @@ using System; namespace ICSharpCode.NRefactory.Parser { - public abstract class AbstractLexerState + public abstract class LexerMemento { public int Line { get; set; } public int Column { get; set; } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/SavepointEventArgs.cs b/src/Libraries/NRefactory/Project/Src/Lexer/SavepointEventArgs.cs new file mode 100644 index 0000000000..1ac58392c5 --- /dev/null +++ b/src/Libraries/NRefactory/Project/Src/Lexer/SavepointEventArgs.cs @@ -0,0 +1,24 @@ +// +// +// +// +// $Revision: 6084 $ +// + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Parser +{ + public class SavepointEventArgs : EventArgs + { + public Location SavepointLocation { get; private set; } + public LexerMemento State { get; private set; } + + public SavepointEventArgs(Location savepointLocation, LexerMemento state) + { + this.SavepointLocation = savepointLocation; + this.State = state; + } + } +} diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Block.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Block.cs new file mode 100644 index 0000000000..1ed14b5aee --- /dev/null +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Block.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ICSharpCode.NRefactory.Parser.VB +{ + public enum Context + { + Global, + Type, + Member, + IdentifierExpected, + Body, + Xml, + Attribute, + Query, + Expression, + Debug, + Default + } + + public class Block : ICloneable + { + public static readonly Block Default = new Block() { + context = Context.Global, + lastExpressionStart = Location.Empty + }; + + public Context context; + public Location lastExpressionStart; + public bool isClosed; + + public override string ToString() + { + 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 + }; + } + } +} diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs index 2e8a78a9dc..88712c4cee 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.cs @@ -118,6 +118,13 @@ namespace ICSharpCode.NRefactory.Parser.VB } } + public bool InContext(Context expected) + { + return stack + .SkipWhile(f => f.context == Context.Expression) + .IsElement(fx => fx.context == expected); + } + public bool NextTokenIsPotentialStartOfExpression { get { return nextTokenIsPotentialStartOfExpression; } } @@ -152,56 +159,4 @@ namespace ICSharpCode.NRefactory.Parser.VB }; } } - - 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 StateStack { get; set; } - public Stack BlockStack { get; set; } - public int CurrentState { get; set; } - } - - public enum Context - { - Global, - Type, - Member, - IdentifierExpected, - Body, - Xml, - Attribute, - Query, - Expression, - Debug, - Default - } - - public class Block : ICloneable - { - public static readonly Block Default = new Block() { - context = Context.Global, - lastExpressionStart = Location.Empty - }; - - public Context context; - public Location lastExpressionStart; - public bool isClosed; - - public override string ToString() - { - 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 - }; - } - } } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinderState.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinderState.cs new file mode 100644 index 0000000000..cc8a069808 --- /dev/null +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinderState.cs @@ -0,0 +1,25 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ICSharpCode.NRefactory.Parser.VB +{ + 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 StateStack { get; set; } + public Stack BlockStack { get; set; } + public int CurrentState { get; set; } + } +} diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Extensions.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Extensions.cs new file mode 100644 index 0000000000..f1a19ea0e9 --- /dev/null +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Extensions.cs @@ -0,0 +1,26 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ICSharpCode.NRefactory.Parser.VB +{ + public static class Extensions + { + public static bool IsElement(this IEnumerable items, Func check) + { + T item = items.FirstOrDefault(); + + if (item != null) + return check(item); + return false; + } + } +} diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs index c5c860059a..1507aa0446 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs @@ -34,12 +34,12 @@ namespace ICSharpCode.NRefactory.Parser.VB ef = new ExpressionFinder(); } - public Lexer(TextReader reader, AbstractLexerState state) : base(reader, state) + public Lexer(TextReader reader, LexerMemento state) : base(reader, state) { - if (!(state is VBLexerState)) + if (!(state is VBLexerMemento)) throw new InvalidOperationException("state must be a VBLexerState"); - var vbState = state as VBLexerState; + var vbState = state as VBLexerMemento; ef = new ExpressionFinder(vbState.ExpressionFinder); lineEnd = vbState.LineEnd; isAtLineBegin = vbState.IsAtLineBegin; @@ -421,17 +421,17 @@ namespace ICSharpCode.NRefactory.Parser.VB // 4th rule // after a less-than (<) in an attribute context - if (prevTokenKind == Tokens.LessThan && ef.CurrentBlock.context == Context.Attribute) + if (prevTokenKind == Tokens.LessThan && ef.InContext(Context.Attribute)) return true; // 5th rule // before a greater-than (>) in an attribute context - if (nextTokenKind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute) + if (nextTokenKind == Tokens.GreaterThan && ef.InContext(Context.Attribute)) return true; // 6th rule // after a greater-than (>) in a non-file-level attribute context - if (prevTokenKind == Tokens.GreaterThan && ef.CurrentBlock.context == Context.Attribute) + if (prevTokenKind == Tokens.GreaterThan && ef.InContext(Context.Attribute)) return true; // 7th rule @@ -440,7 +440,7 @@ namespace ICSharpCode.NRefactory.Parser.VB 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 }; if ((queryOperators.Contains(prevTokenKind) || queryOperators.Contains(nextTokenKind)) - && ef.CurrentBlock.context == Context.Query) + && ef.InContext(Context.Query)) return true; // 8th rule @@ -1133,9 +1133,9 @@ namespace ICSharpCode.NRefactory.Parser.VB ef.SetContext(type); } - public override AbstractLexerState Export() + public override LexerMemento Export() { - return new VBLexerState() { + return new VBLexerMemento() { Column = Col, Line = Line, EncounteredLineContinuation = encounteredLineContinuation, diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerState.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerMemento.cs similarity index 92% rename from src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerState.cs rename to src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerMemento.cs index b6cd352cb7..cebe6a7a39 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerState.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/VBLexerMemento.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.Parser.VB { - public sealed class VBLexerState : AbstractLexerState + public sealed class VBLexerMemento : LexerMemento { public bool LineEnd { get; set; } public bool IsAtLineBegin { get; set; } diff --git a/src/Libraries/NRefactory/Project/Src/ParserFactory.cs b/src/Libraries/NRefactory/Project/Src/ParserFactory.cs index 7673a18fe6..1fa446c404 100644 --- a/src/Libraries/NRefactory/Project/Src/ParserFactory.cs +++ b/src/Libraries/NRefactory/Project/Src/ParserFactory.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.NRefactory throw new System.NotSupportedException(language + " not supported."); } - public static Parser.ILexer CreateLexer(SupportedLanguage language, TextReader textReader, AbstractLexerState state) + public static Parser.ILexer CreateLexer(SupportedLanguage language, TextReader textReader, LexerMemento state) { switch (language) { case SupportedLanguage.CSharp: diff --git a/src/Libraries/NRefactory/Test/Lexer/VBNet/ImplicitLineContinuationTests.cs b/src/Libraries/NRefactory/Test/Lexer/VBNet/ImplicitLineContinuationTests.cs index 34381eed63..e244e897b2 100644 --- a/src/Libraries/NRefactory/Test/Lexer/VBNet/ImplicitLineContinuationTests.cs +++ b/src/Libraries/NRefactory/Test/Lexer/VBNet/ImplicitLineContinuationTests.cs @@ -93,6 +93,52 @@ End Module"; Tokens.End, Tokens.Module); } + [Test] + public void Query() + { + string code = @"Module Test + Sub A + Dim q = From x In a + Select x + End Sub +End Module"; + + ILexer lexer = GenerateLexer(new StringReader(code)); + + CheckTokens(lexer, Tokens.Module, Tokens.Identifier, Tokens.EOL, + Tokens.Sub, Tokens.Identifier, Tokens.EOL, + Tokens.Dim, Tokens.Identifier, Tokens.Assign, Tokens.From, Tokens.Identifier, Tokens.In, Tokens.Identifier, + Tokens.Select, Tokens.Identifier, Tokens.EOL, + Tokens.End, Tokens.Sub, Tokens.EOL, + Tokens.End, Tokens.Module); + } + + [Test] + public void Query1() + { + string code = @"Module Test + Sub A + Dim actions = From a in b Select Sub() + Dim i = 1 + Select Case i + End Select + End Sub + End Sub +End Module"; + + ILexer lexer = GenerateLexer(new StringReader(code)); + + CheckTokens(lexer, Tokens.Module, Tokens.Identifier, Tokens.EOL, + Tokens.Sub, Tokens.Identifier, Tokens.EOL, + Tokens.Dim, Tokens.Identifier, Tokens.Assign, Tokens.From, Tokens.Identifier, Tokens.In, Tokens.Identifier, Tokens.Select, Tokens.Sub, Tokens.OpenParenthesis, Tokens.CloseParenthesis, Tokens.EOL, + Tokens.Dim, Tokens.Identifier, Tokens.Assign, Tokens.LiteralInteger, Tokens.EOL, + Tokens.Select, Tokens.Case, Tokens.Identifier, Tokens.EOL, + Tokens.End, Tokens.Select, Tokens.EOL, + Tokens.End, Tokens.Sub, Tokens.EOL, + Tokens.End, Tokens.Sub, Tokens.EOL, + Tokens.End, Tokens.Module); + } + #region Helpers ILexer GenerateLexer(StringReader sr) { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs index 5cd3241aab..ad17b92828 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs @@ -1122,15 +1122,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } } - static void AddVBNetKeywords(List ar, BitArray keywords) - { - for (int i = 0; i < keywords.Length; i++) { - if (keywords[i]) { - ar.Add(new KeywordEntry(NR.Parser.VB.Tokens.GetTokenString(i))); - } - } - } - /// /// Returns code completion entries for given context. /// diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs index 7c3bf873d1..0773f442e9 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs @@ -6,6 +6,7 @@ // using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -81,14 +82,14 @@ namespace ICSharpCode.SharpDevelop.Dom.VBNet if (lastExpressionStartOffset < 0) return new ExpressionResult(null, context); - return MakeResult(text, lastExpressionStartOffset, offset, context); + return MakeResult(text, lastExpressionStartOffset, offset, context, p.GetExpectedSet()); } - ExpressionResult MakeResult(string text, int startOffset, int endOffset, ExpressionContext context) + ExpressionResult MakeResult(string text, int startOffset, int endOffset, ExpressionContext context, BitArray expectedKeywords) { return new ExpressionResult(text.Substring(startOffset, endOffset - startOffset).Trim(), DomRegion.FromLocation(OffsetToLocation(startOffset), OffsetToLocation(endOffset)), - context, null); + context, expectedKeywords); } void Init(string text, int offset) @@ -160,10 +161,10 @@ namespace ICSharpCode.SharpDevelop.Dom.VBNet if (lastExpressionStartOffset >= 0) { if (offset < tokenOffset) { // offset is in front of this token - return MakeResult(text, lastExpressionStartOffset, tokenOffset, GetContext(block)); + return MakeResult(text, lastExpressionStartOffset, tokenOffset, GetContext(block), p.GetExpectedSet()); } else { // offset is IN this token - return MakeResult(text, lastExpressionStartOffset, offset, GetContext(block)); + return MakeResult(text, lastExpressionStartOffset, offset, GetContext(block), p.GetExpectedSet()); } } else { return new ExpressionResult(null, GetContext(block));