/// <summary> /// Initializes a new instance of the <see cref="SimpleKey"/> class. /// </summary> public SimpleKey(bool isPossible, bool isRequired, int tokenNumber, Mark mark) { this.isPossible = isPossible; this.isRequired = isRequired; this.tokenNumber = tokenNumber; this.mark = mark; }
/// <summary> /// Initializes a new instance of the <see cref="SyntaxErrorException"/> class. /// </summary> public SyntaxErrorException(Mark start, Mark end, string message) : base(start, end, message) { }
/// <summary> /// Initializes a new instance of the <see cref="YamlException"/> class. /// </summary> public YamlException(Mark start, Mark end, string message) : this(start, end, message, null) { }
/// <summary> /// Initializes a new instance of the <see cref="YamlException"/> class. /// </summary> public YamlException(Mark start, Mark end, string message, Exception innerException) : base(string.Format("({0}) - ({1}): {2}", start, end, message), innerException) { Start = start; End = end; }
/// <summary> /// Loads the specified event. /// </summary> /// <param name="yamlEvent">The event.</param> /// <param name="state">The state of the document.</param> internal void Load(NodeEvent yamlEvent, DocumentLoadingState state) { Tag = yamlEvent.Tag; if (yamlEvent.Anchor != null) { Anchor = yamlEvent.Anchor; state.AddAnchor(this); } Start = yamlEvent.Start; End = yamlEvent.End; }
/// <summary> /// Gets the node with the specified anchor. /// </summary> /// <param name="anchor">The anchor.</param> /// <param name="throwException">if set to <c>true</c>, the method should throw an exception if there is no node with that anchor.</param> /// <param name="start">The start position.</param> /// <param name="end">The end position.</param> /// <returns></returns> public YamlNode GetNode(string anchor, bool throwException, Mark start, Mark end) { YamlNode target; if (anchors.TryGetValue(anchor, out target)) { return target; } else if (throwException) { throw new AnchorNotFoundException(anchor, start, end, string.Format(CultureInfo.InvariantCulture, "The anchor '{0}' does not exists", anchor)); } else { return null; } }
/// <summary> /// Scan a tag handle. /// </summary> private string ScanTagHandle(bool isDirective, Mark start) { // Check the initial '!' character. if (!analyzer.Check('!')) { throw new SyntaxErrorException(start, mark, "While scanning a tag, did not find expected '!'."); } // Copy the '!' character. StringBuilder tagHandle = new StringBuilder(); tagHandle.Append(ReadCurrentCharacter()); // Copy all subsequent alphabetical and numerical characters. while (analyzer.IsAlpha()) { tagHandle.Append(ReadCurrentCharacter()); } // Check if the trailing character is '!' and copy it. if (analyzer.Check('!')) { tagHandle.Append(ReadCurrentCharacter()); } else { // It's either the '!' tag or not really a tag handle. If it's a %TAG // directive, it's an error. If it's a tag token, it must be a part of // URI. if (isDirective && (tagHandle.Length != 1 || tagHandle[0] != '!')) { throw new SyntaxErrorException(start, mark, "While parsing a tag directive, did not find expected '!'."); } } return tagHandle.ToString(); }
/// <summary> /// Scan intendation spaces and line breaks for a block scalar. Determine the /// intendation level if needed. /// </summary> private int ScanBlockScalarBreaks(int currentIndent, StringBuilder breaks, Mark start, ref Mark end) { int maxIndent = 0; end = mark; // Eat the intendation spaces and line breaks. for (; ;) { // Eat the intendation spaces. while ((currentIndent == 0 || mark.Column < currentIndent) && analyzer.IsSpace()) { Skip(); } if (mark.Column > maxIndent) { maxIndent = mark.Column; } // Check for a tab character messing the intendation. if ((currentIndent == 0 || mark.Column < currentIndent) && analyzer.IsTab()) { throw new SyntaxErrorException(start, mark, "While scanning a block scalar, find a tab character where an intendation space is expected."); } // Have we find a non-empty line? if (!analyzer.IsBreak()) { break; } // Consume the line break. breaks.Append(ReadLine()); end = mark; } // Determine the indentation level if needed. if (currentIndent == 0) { currentIndent = Math.Max(maxIndent, Math.Max(indent + 1, 1)); } return currentIndent; }
/// <summary> /// Scan a tag. /// </summary> private string ScanTagUri(string head, Mark start) { StringBuilder tag = new StringBuilder(); if (head != null && head.Length > 1) { tag.Append(head.Substring(1)); } // Scan the tag. // The set of characters that may appear in URI is as follows: // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', // '%'. while (analyzer.IsAlpha() || analyzer.Check(";/?:@&=+$,.!~*'()[]%")) { // Check if it is a URI-escape sequence. if (analyzer.Check('%')) { tag.Append(ScanUriEscapes(start)); } else { tag.Append(ReadCurrentCharacter()); } } // Check if the tag is non-empty. if (tag.Length == 0) { throw new SyntaxErrorException(start, mark, "While parsing a tag, did not find expected tag URI."); } return tag.ToString(); }
/// <summary> /// Decode an URI-escape sequence corresponding to a single UTF-8 character. /// </summary> private char ScanUriEscapes(Mark start) { // Decode the required number of characters. List<byte> charBytes = new List<byte>(); int width = 0; do { // Check for a URI-escaped octet. if (!(analyzer.Check('%') && analyzer.IsHex(1) && analyzer.IsHex(2))) { throw new SyntaxErrorException(start, mark, "While parsing a tag, did not find URI escaped octet."); } // Get the octet. int octet = (analyzer.AsHex(1) << 4) + analyzer.AsHex(2); // If it is the leading octet, determine the length of the UTF-8 sequence. if (width == 0) { width = (octet & 0x80) == 0x00 ? 1 : (octet & 0xE0) == 0xC0 ? 2 : (octet & 0xF0) == 0xE0 ? 3 : (octet & 0xF8) == 0xF0 ? 4 : 0; if (width == 0) { throw new SyntaxErrorException(start, mark, "While parsing a tag, find an incorrect leading UTF-8 octet."); } } else { // Check if the trailing octet is correct. if ((octet & 0xC0) != 0x80) { throw new SyntaxErrorException(start, mark, "While parsing a tag, find an incorrect trailing UTF-8 octet."); } } // Copy the octet and move the pointers. charBytes.Add((byte)octet); Skip(); Skip(); Skip(); } while (--width > 0); char[] characters = Encoding.UTF8.GetChars(charBytes.ToArray()); if (characters.Length != 1) { throw new SyntaxErrorException(start, mark, "While parsing a tag, find an incorrect UTF-8 sequence."); } return characters[0]; }
/// <summary> /// Scan the value of a TAG-DIRECTIVE token. /// /// Scope: /// %TAG !yaml! tag:yaml.org,2002: \n /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// </summary> private Token ScanTagDirectiveValue(Mark start) { SkipWhitespaces(); // Scan a handle. string handle = ScanTagHandle(true, start); // Expect a whitespace. if (!analyzer.IsBlank()) { throw new SyntaxErrorException(start, mark, "While scanning a %TAG directive, did not find expected whitespace."); } SkipWhitespaces(); // Scan a prefix. string prefix = ScanTagUri(null, start); // Expect a whitespace or line break. if (!analyzer.IsBlankOrBreakOrZero()) { throw new SyntaxErrorException(start, mark, "While scanning a %TAG directive, did not find expected whitespace or line break."); } return new TagDirective(handle, prefix, start, start); }
/// <summary> /// Scan the value of VERSION-DIRECTIVE. /// /// Scope: /// %YAML 1.1 # a comment \n /// ^^^^^^ /// </summary> private Token ScanVersionDirectiveValue(Mark start) { SkipWhitespaces(); // Consume the major version number. int major = ScanVersionDirectiveNumber(start); // Eat '.'. if (!analyzer.Check('.')) { throw new SyntaxErrorException(start, mark, "While scanning a %YAML directive, did not find expected digit or '.' character."); } Skip(); // Consume the minor version number. int minor = ScanVersionDirectiveNumber(start); return new VersionDirective(new Version(major, minor), start, start); }
/// <summary> /// Scan the directive name. /// /// Scope: /// %YAML 1.1 # a comment \n /// ^^^^ /// %TAG !yaml! tag:yaml.org,2002: \n /// ^^^ /// </summary> private string ScanDirectiveName(Mark start) { StringBuilder name = new StringBuilder(); // Consume the directive name. while (analyzer.IsAlpha()) { name.Append(ReadCurrentCharacter()); } // Check if the name is empty. if (name.Length == 0) { throw new SyntaxErrorException(start, mark, "While scanning a directive, could not find expected directive name."); } // Check for an blank character after the name. if (!analyzer.IsBlankOrBreakOrZero()) { throw new SyntaxErrorException(start, mark, "While scanning a directive, find unexpected non-alphabetical character."); } return name.ToString(); }
/// <summary> /// Initializes a new instance of the <see cref="SemanticErrorException"/> class. /// </summary> public SemanticErrorException(Mark start, Mark end, string message) : base(start, end, message) { }
/// <summary> /// Scan the version number of VERSION-DIRECTIVE. /// /// Scope: /// %YAML 1.1 # a comment \n /// ^ /// %YAML 1.1 # a comment \n /// ^ /// </summary> private int ScanVersionDirectiveNumber(Mark start) { int value = 0; int length = 0; // Repeat while the next character is digit. while (analyzer.IsDigit()) { // Check if the number is too long. if (++length > MaxVersionNumberLength) { throw new SyntaxErrorException(start, mark, "While scanning a %YAML directive, find extremely long version number."); } value = value * 10 + analyzer.AsDigit(); Skip(); } // Check if the number was present. if (length == 0) { throw new SyntaxErrorException(start, mark, "While scanning a %YAML directive, did not find expected version number."); } return value; }
/// <summary> /// Generate an empty scalar event. /// </summary> private static Event ProcessEmptyScalar(Mark position) { return new Events.Scalar(null, null, string.Empty, ScalarStyle.Plain, true, false, position, position); }
/// <summary> /// Push the current indentation level to the stack and set the new level /// the current column is greater than the indentation level. In this case, /// append or insert the specified token into the token queue. /// </summary> private void RollIndent(int column, int number, bool isSequence, Mark position) { // In the flow context, do nothing. if (flowLevel > 0) { return; } if (indent < column) { // Push the current indentation level to the stack and set the new // indentation level. indents.Push(indent); indent = column; // Create a token and insert it into the queue. Token token; if (isSequence) { token = new BlockSequenceStart(position, position); } else { token = new BlockMappingStart(position, position); } if (number == -1) { tokens.Enqueue(token); } else { tokens.Insert(number - tokensParsed, token); } } }