diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs index 96a85a9911..eea76cb51a 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs @@ -15,27 +15,33 @@ namespace ICSharpCode.XamlBinding { var info = new MarkupExtensionInfo(); - var tokens = MarkupExtensionTokenizer.Tokenize(text); + var tokenizer = new MarkupExtensionTokenizer(text); string argumentName = null; - foreach (var token in tokens) { - switch (token.Kind) { - case MarkupExtensionTokenKind.TypeName: - info.Type = token.Value; - break; - case MarkupExtensionTokenKind.Membername: - argumentName = token.Value; - break; - case MarkupExtensionTokenKind.String: - if (argumentName != null) { - info.NamedArguments.Add(argumentName, ParseValue(token.Value)); - argumentName = null; - } else { - info.PositionalArguments.Add(ParseValue(token.Value)); - } - break; + try { + var token = tokenizer.NextToken(); + while (token.Kind != MarkupExtensionTokenKind.EOF) { + switch (token.Kind) { + case MarkupExtensionTokenKind.TypeName: + info.Type = token.Value; + break; + case MarkupExtensionTokenKind.Membername: + argumentName = token.Value; + break; + case MarkupExtensionTokenKind.String: + if (argumentName != null) { + info.NamedArguments.Add(argumentName, ParseValue(token.Value)); + argumentName = null; + } else { + info.PositionalArguments.Add(ParseValue(token.Value)); + } + break; + } + token = tokenizer.NextToken(); } + } catch (MarkupExtensionParseException) { + // ignore parser errors } return info; diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenKind.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenKind.cs index 5c6e3efe6a..7dba8f1fc3 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenKind.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenKind.cs @@ -11,6 +11,7 @@ namespace ICSharpCode.XamlBinding { public enum MarkupExtensionTokenKind { + EOF, OpenBrace, CloseBrace, Equals, diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs index 67dbdbfc7f..891f3fa0e9 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; namespace ICSharpCode.XamlBinding @@ -17,26 +18,43 @@ namespace ICSharpCode.XamlBinding /// public sealed class MarkupExtensionTokenizer { - private MarkupExtensionTokenizer() {} + public MarkupExtensionTokenizer(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + this.text = text; + + ParseBeginning(); + } string text; int pos; - List tokens = new List(); + Queue tokens = new Queue(); - public static List Tokenize(string text) + /// + /// Retrieves the next token. + /// + /// A parse error occurred. + public MarkupExtensionToken NextToken() { - MarkupExtensionTokenizer t = new MarkupExtensionTokenizer(); - t.text = text; - t.Parse(); - return t.tokens; + if (tokens.Count == 0) { + // produce new tokens on demand + ParseStep(); + // a parse step must produce tokens unless we're at EOF + Debug.Assert(tokens.Count > 0 || pos == text.Length); + } + if (tokens.Count > 0) + return tokens.Dequeue(); + else + return new MarkupExtensionToken(MarkupExtensionTokenKind.EOF, ""); } void AddToken(MarkupExtensionTokenKind kind, string val) { - tokens.Add(new MarkupExtensionToken(kind, val)); + tokens.Enqueue(new MarkupExtensionToken(kind, val)); } - void Parse() + void ParseBeginning() { AddToken(MarkupExtensionTokenKind.OpenBrace, "{"); Expect('{'); @@ -47,9 +65,12 @@ namespace ICSharpCode.XamlBinding while (pos < text.Length && !char.IsWhiteSpace(text, pos) && text[pos] != '}') b.Append(text[pos++]); AddToken(MarkupExtensionTokenKind.TypeName, b.ToString()); - + } + + void ParseStep() + { ConsumeWhitespace(); - while (pos < text.Length) { + if (pos < text.Length) { switch (text[pos]) { case '}': AddToken(MarkupExtensionTokenKind.CloseBrace, "}"); @@ -67,7 +88,6 @@ namespace ICSharpCode.XamlBinding MembernameOrString(); break; } - ConsumeWhitespace(); } } @@ -87,8 +107,7 @@ namespace ICSharpCode.XamlBinding ConsumeWhitespace(); } else { int braceTotal = 0; - while (true) { - CheckNotEOF(); + while (pos < text.Length) { switch (text[pos]) { case '\\': pos++; @@ -116,9 +135,8 @@ namespace ICSharpCode.XamlBinding } stop:; } - CheckNotEOF(); string valueText = b.ToString(); - if (text[pos] == '=') { + if (pos < text.Length && text[pos] == '=') { AddToken(MarkupExtensionTokenKind.Membername, valueText.Trim()); } else { AddToken(MarkupExtensionTokenKind.String, valueText);