/// <summary> /// Try to make a callback in a transactional way. /// </summary> /// <param name="delegate">The callback to perform the match.</param> /// <returns>true if the match could be made, false if not.</returns> protected bool TryMake(TryMakeDelegate @delegate) { var checkpoint = Enumerator.Checkpoint(); if (@delegate() == false) { checkpoint.Rollback(); return(false); } checkpoint.Dispose(); return(true); }
/// <summary> /// Try to make a callback in a transactional way. /// </summary> /// <param name="delegate">The callback to perform the match.</param> /// <param name="found">The parameter that was returned from the matching function.</param> /// <returns>true if the match could be made, false if not.</returns> protected bool TryMake <TOut>(TryMakeDelegate <TOut> @delegate, out TOut found) { var checkpoint = Enumerator.Checkpoint(); if (@delegate(out found) == false) { checkpoint.Rollback(); return(false); } checkpoint.Dispose(); return(true); }
/// <summary> /// Try to take the tokens in sequence. /// </summary> /// <param name="tokens">The list of tokens to take in sequence.</param> /// <returns>true if the given list of tokens could be made in sequence, false if not.</returns> protected bool TryTakeTokens(params Token[] tokens) { var checkpoint = Enumerator.Checkpoint(); foreach (var token in tokens) { if (Enumerator.Take() != token) { checkpoint.Rollback(); return(false); } } checkpoint.Dispose(); return(true); }
/// <summary> /// Try to extract IPv6 address. https://tools.ietf.org/html/rfc4291 section 2.2 used for specification. /// </summary> /// <param name="address">Extracted Ipv6 address</param> /// <returns>true if a valid Ipv6 address can be extracted</returns> public bool TryMakeIpv6AddressLiteral(out string address) { address = null; if ((TryMake(TryMakeIpVersion, out int ipVersion) == false) || ipVersion != 6) { return(false); } var hasDoubleColumn = false; var hexPartCount = 0; var hasIpv4Part = false; var wasColon = false; var token = Enumerator.Peek(); var builder = new System.Text.StringBuilder(); while (token.Kind == TokenKind.Number || token.Kind == TokenKind.Text || token == Tokens.Colon) { using (var cp = Enumerator.Checkpoint()) { Enumerator.Take(); // Alternate form with mixed IPv6 and IPv4 formats. See https://tools.ietf.org/html/rfc4291 section 2.2 item 3 if (token.Kind == TokenKind.Number && Enumerator.Peek() == Tokens.Period) { cp.Rollback(); if (TryMake(TryMakeIpv4AddressLiteral, out string ipv4)) { hasIpv4Part = true; builder.Append(ipv4); break; } else { return(false); } } else { cp.Rollback(); } } if (token == Tokens.Colon) { if (wasColon) { // Double column is allowed only once if (hasDoubleColumn) { return(false); } hasDoubleColumn = true; } builder.Append(token.Text); wasColon = true; Enumerator.Take(); } else { if (wasColon == false && builder.Length > 0) { return(false); } wasColon = false; if (TryMake(TryMake16BitsHexNumber, out string hexNumber)) { builder.Append(hexNumber); hexPartCount++; } else { return(false); } } token = Enumerator.Peek(); } address = builder.ToString(); var maxAllowedParts = (hasIpv4Part ? 6 : 8) - Math.Sign(hasDoubleColumn ? 1 : 0); if ((hasDoubleColumn && hexPartCount > maxAllowedParts) || (!hasDoubleColumn && hexPartCount != maxAllowedParts)) { return(false); } return(true); }