/// <summary> /// Parses an object path expression from a string. /// </summary> /// <param name="expression">The expression text to parse</param> /// <returns>The parsed expression</returns> public static ObjectPathExpression Parse(string expression) { if (expression == null) { throw new ArgumentNullException("path cannot be null"); } if (expression.Length == 0) { throw new FormatException("Cannot parse empty string"); } Tokenizer <ObjectPathToken> tokenizer = new Tokenizer <ObjectPathToken>(); tokenizer.TokenFactory = ObjectPathToken.TokenFactoryImpl; tokenizer.WhitespaceBehavior = WhitespaceBehavior.DelimitAndInclude; tokenizer.DoubleQuoteBehavior = DoubleQuoteBehavior.IncludeQuotedTokensAsStringLiterals; tokenizer.Delimiters.Add("["); tokenizer.Delimiters.Add("]"); tokenizer.Delimiters.Add("."); List <ObjectPathToken> tokens = tokenizer.Tokenize(expression); TokenReader <ObjectPathToken> reader = new TokenReader <ObjectPathToken>(tokens); List <IObjectPathElement> pathElements = new List <IObjectPathElement>(); bool lastTokenWasNavigation = false; while (reader.CanAdvance(skipWhitespace: true)) { var currentToken = reader.Advance(skipWhitespace: true); if (lastTokenWasNavigation == true && currentToken.TokenType != ObjectPathTokenType.Identifier) { throw new FormatException("Expected property, got '" + currentToken.Value + "'" + " at " + currentToken.Position); } lastTokenWasNavigation = false; if (currentToken.TokenType == ObjectPathTokenType.IndexerOpen) { // read index value if (reader.TryAdvance(out currentToken, skipWhitespace: true) == false) { throw new FormatException("Expected index value, got end of string"); } if (currentToken.TokenType != ObjectPathTokenType.Identifier && currentToken.TokenType != ObjectPathTokenType.StringLiteral) { throw new ArgumentException("Unexpected token '" + currentToken.Value + "' at " + currentToken.Position); } string indexValueText = currentToken.Value; if (currentToken.TokenType == ObjectPathTokenType.StringLiteral) { indexValueText = indexValueText.Substring(1, indexValueText.Length - 2); } object indexValue; int indexValueInt; if (int.TryParse(indexValueText, out indexValueInt) == false) { indexValue = indexValueText; } else { indexValue = indexValueInt; } // read index close if (reader.TryAdvance(out currentToken, skipWhitespace: true) == false) { throw new FormatException("Expected ']', got end of string"); } if (currentToken.TokenType != ObjectPathTokenType.IndexerClose) { throw new FormatException("Expected ']', got '" + currentToken.Value + "' at " + currentToken.Position); } IndexerPathElement el = new IndexerPathElement(indexValue); pathElements.Add(el); } else if (currentToken.TokenType == ObjectPathTokenType.Identifier) { PropertyPathElement el = new PropertyPathElement(currentToken.Value); pathElements.Add(el); } else if (currentToken.TokenType == ObjectPathTokenType.NavigationElement) { lastTokenWasNavigation = true; } else { throw new ArgumentException("Expected property name or indexer, got '" + currentToken.Value + "' at " + currentToken.Position); } } return(new ObjectPathExpression(pathElements)); }