/* * Creates a modulo token */ private void ModuloToken(IteratorGroup current, string token) { // Removing "%" character token = token.Substring(1); // Making sure we're given a number if (!Utilities.IsNumber(token)) { throw new ExpressionException( Value, string.Format("Syntax error in modulo token '{0}', expected integer value, found string", token)); } current.AddIterator(new IteratorModulo(int.Parse(token))); }
/* * Creates a valued token */ private void ValueToken(ApplicationContext context, IteratorGroup current, string token) { token = token.Substring(1); // Removing equal sign (=) string type = null; // Defaulting to "no type", meaning "string" type basically // Might contain a type declaration, checking here if (token.StartsWith(":")) { // Yup, we've got a type declaration for our token ... type = token.Substring(1, token.IndexOf(":", 1, StringComparison.Ordinal) - 1); token = token.Substring(type.Length + 2); } current.AddIterator(new IteratorValued(token, type)); }
/* * Creates a sibling token */ private void SiblingToken(IteratorGroup current, string token) { var intValue = token.Substring(1); var oper = token[0]; var value = 1; if (intValue.Length > 0 && !Utilities.IsNumber(intValue)) { throw new ExpressionException( Value, string.Format("Syntax error in sibling token '{0}', expected integer value, found string", token)); } if (intValue.Length > 0) { value = int.Parse(intValue); } current.AddIterator(new IteratorSibling(value * (oper == '+' ? 1 : -1))); }
/* * Creates an elder relative token */ private void ElderRelativeToken(IteratorGroup current, string token) { var name = token.Substring(1); current.AddIterator(new IteratorNamedElderRelative(name)); }
/* * Creates a range token [x,y] */ private void RangeToken(IteratorGroup current, string token) { // Verifying token ends with "]" token = token.TrimEnd(); if (token [token.Length - 1] != ']') { throw new ExpressionException( Value, string.Format("Syntax error in range token '{0}', no ']' at end of token", token)); } token = token.Substring(1, token.Length - 2); // Removing [] square brackets if (token.IndexOf(',') == -1) { throw new ExpressionException( Value, string.Format("Syntax error in range token '{0}', range token must have at the very least a ',' character.", token)); } var values = token.Split(','); // Verifyies token has only two integer values, separated by "," if (values.Length != 2) { throw new ExpressionException( Value, string.Format("Syntax error in range token '[{0}]', ranged iterator takes two integer values, separated by ','", token)); } var start = -1; var end = -1; var startStr = values [0].Trim(); var endStr = values [1].Trim(); if (startStr.Length > 0) // start index was explicitly given { if (!Utilities.IsNumber(startStr)) { throw new ExpressionException( Value, string.Format("Syntax error in range token '[{0}]', expected number, found string", token)); } start = int.Parse(startStr, CultureInfo.InvariantCulture); } if (endStr.Length > 0) // end index was explicitly given { if (!Utilities.IsNumber(endStr)) { throw new ExpressionException( Value, string.Format("Syntax error in range token '[{0}]', expected number, found string", token)); } end = int.Parse(endStr, CultureInfo.InvariantCulture); if (end <= start) { throw new ExpressionException( Value, string.Format("Syntax error in range token '[{0}]', end must be larger than start", token)); } } current.AddIterator(new IteratorRange(start, end)); }
/* * Handles an expression iterator token */ private IteratorGroup AppendToken( ApplicationContext context, IteratorGroup current, string token, string previousToken) { switch (token) { case "(": // Opening new group, checking for empty name iterator first if (previousToken == "/") { current.AddIterator(new IteratorNamed("")); } return(new IteratorGroup(current)); case ")": // Closing group, checking for empty name iterator first and missing group opening first if (current.ParentGroup == null) // making sure there's actually an open group first { throw new ExpressionException( Value, "Closing parenthesis ')' has no matching '(' in expression."); } if (previousToken == "/") { current.AddIterator(new IteratorNamed("")); } return(current.ParentGroup); case "/": // New token iterator if (previousToken == "/") { // Two slashes "//" preceding each other, hence we're looking for a named value, // where its name is "" current.AddIterator(new IteratorNamed("")); } // Else, ignoring token, since it's simply declaring the beginning (or the end) of another token break; case "|": case "&": case "^": case "!": // Boolean algebraic operator, opening up a new sibling-expression, checking for empty name iterator first if (previousToken == "/") { current.AddIterator(new IteratorNamed("")); } LogicalToken(current, token, previousToken); break; case "..": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Root node token current.AddIterator(new IteratorRoot()); break; case "*": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // All children token current.AddIterator(new IteratorChildren()); break; case "**": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Flatten descendants token current.AddIterator(new IteratorDescendants()); break; case ".": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Parent node token current.AddIterator(new IteratorParent()); break; case "#": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Reference node token current.AddIterator(new IteratorReference()); break; case "<": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Left shift token current.AddIterator(new IteratorShiftLeft()); break; case ">": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Right shift token current.AddIterator(new IteratorShiftRight()); break; case "=$": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Right shift token current.AddIterator(new IteratorDistinctValue()); break; case "$": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Right shift token current.AddIterator(new IteratorDistinctName()); break; case "++": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Right shift token current.AddIterator(new IteratorSiblingsOlder()); break; case "--": // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Right shift token current.AddIterator(new IteratorSiblingsYounger()); break; default: // Sanity check! if (previousToken != "/") { throw new ExpressionException(Value, "Missing '/' before possible iterator"); } // Handles everything else if (token.StartsWith("=")) { // Some type of value token, either normal value, or regex value ValueToken(context, current, token); } else if (token.StartsWith("[")) { // Range iterator token RangeToken(current, token); } else if (token.StartsWith("..") && token.Length > 2) { // Named ancestor token current.AddIterator(new IteratorNamedAncestor(token.Substring(2))); } else if (token.StartsWith("%")) { // Modulo token ModuloToken(current, token); } else if (token.StartsWith("-") || token.StartsWith("+")) { // Sibling offset SiblingToken(current, token); } else if (token.StartsWith("@")) { // Sibling offset ElderRelativeToken(current, token); } else { if (Utilities.IsNumber(token)) { // Numbered child token current.AddIterator(new IteratorNumberedChild(int.Parse(token))); } else { // Defaulting to "named iterator" current.AddIterator(new IteratorNamed(token)); } } break; } // Defaulting to returning what we came in with return(current); }