Kirill Simonov avatar Kirill Simonov committed 62e4dce

Fix numerous bugs in the Scanner.

Comments (0)

Files changed (1)

     /* Move the queue head. */
 
     parser->tokens[parser->tokens_head++] = NULL;
-    if (parser->tokens_head == parser->tokens_size)
-        parser->tokens_head = 0;
 
     parser->tokens_parsed++;
 
+    if (token->type == YAML_STREAM_END_TOKEN) {
+        parser->stream_end_produced = 1;
+    }
+
     return token;
 }
 
 
     memset(new_buffer+string->size, 0, string->size);
 
-    string->pointer = new_buffer + (string->buffer-string->pointer);
+    string->pointer = new_buffer + (string->pointer-string->buffer);
     string->buffer = new_buffer;
     string->size *= 2;
 
     }
 
     memcpy(string1->pointer, string2->buffer, string2->pointer-string2->buffer);
+    string1->pointer += string2->pointer-string2->buffer;
 
     return 1;
 }
         return 0;
     }
 
-    memset(new_buffer+(*size), 0, item_size*(*size));
+    memset(new_buffer+item_size*(*size), 0, item_size*(*size));
 
     *buffer = new_buffer;
     *size *= 2;
     parser->context_mark = context_mark;
     parser->problem = problem;
     parser->problem_mark = yaml_parser_get_mark(parser);
+
+    return 0;
 }
 
 /*
         {
             /* Check if any potential simple key may occupy the head position. */
 
+            if (!yaml_parser_stale_simple_keys(parser))
+                return 0;
+
             for (k = 0; k <= parser->flow_level; k++) {
                 yaml_simple_key_t *simple_key = parser->simple_keys[k];
                 if (simple_key
     if (!yaml_parser_scan_to_next_token(parser))
         return 0;
 
+    /* Remove obsolete potential simple keys. */
+
+    if (!yaml_parser_stale_simple_keys(parser))
+        return 0;
+
     /* Check the indentation level against the current column. */
 
     if (!yaml_parser_unroll_indent(parser, parser->column))
 
     /* Is it the key indicator? */
 
-    if (CHECK(parser, '?') && (!parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+    if (CHECK(parser, '?') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_key(parser);
 
     /* Is it the value indicator? */
 
-    if (CHECK(parser, ':') && (!parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+    if (CHECK(parser, ':') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_value(parser);
 
     /* Is it an alias? */
      *      '#', '&', '*', '!', '|', '>', '\'', '\"',
      *      '%', '@', '`'.
      *
-     * In the block context, it may also start with the characters
+     * In the block context (and, for the '-' indicator, in the flow context
+     * too), it may also start with the characters
      *
      *      '-', '?', ':'
      *
                 || CHECK(parser, '!') || CHECK(parser, '|') || CHECK(parser, '>')
                 || CHECK(parser, '\'') || CHECK(parser, '"') || CHECK(parser, '%')
                 || CHECK(parser, '@') || CHECK(parser, '`')) ||
+            (CHECK(parser, '-') && !IS_BLANK_AT(parser, 1)) ||
             (!parser->flow_level &&
-             (CHECK(parser, '-') || CHECK(parser, '?') || CHECK(parser, ':')) &&
-             IS_BLANKZ_AT(parser, 1)))
+             (CHECK(parser, '?') || CHECK(parser, ':')) && !IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_plain_scalar(parser);
 
     /*
          */
 
         if (simple_key && (simple_key->line < parser->line ||
-                    simple_key->index < parser->index+1024)) {
+                    simple_key->index+1024 < parser->index)) {
 
             /* Check if the potential simple key to be removed is required. */
 
     if (!yaml_parser_unroll_indent(parser, -1))
         return 0;
 
-    /* We have finished. */
-
-    parser->stream_end_produced = 1;
+    /* Reset simple keys. */
+
+    if (!yaml_parser_remove_simple_key(parser))
+        return 0;
+
+    parser->simple_key_allowed = 0;
 
     /* Create the STREAM-END token. */
 
 
         /* In the block context, we may need to add the BLOCK-MAPPING-START token. */
 
-        if (!yaml_parser_roll_indent(parser, parser->column,
+        if (!yaml_parser_roll_indent(parser, simple_key->column,
                     simple_key->token_number,
                     YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
             return 0;
             if (!handle) goto error;
             handle[0] = '!';
             handle[1] = '\0';
+
+            /*
+             * A special case: the '!' tag.
+             */
+
+            if (suffix[0] == '\0') {
+                yaml_char_t *tmp = handle;
+                handle = suffix;
+                suffix = tmp;
+            }
         }
     }
 
     else
     {
         /*
-         * It's 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.
+         * 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 (directive) {
-            yaml_parser_set_scanner_error(parser, "while parsing a directive",
+        if (directive && !(string.buffer[0] == '!' && string.buffer[1] == '\0')) {
+            yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
                     start_mark, "did not find expected '!'");
             goto error;
         }
         if (!yaml_parser_resize_string(parser, &string)) goto error;
     }
 
-    /* Copy the head if needed. */
-
-    if (length) {
-        memcpy(string.buffer, head, length);
-        string.pointer += length;
+    /*
+     * Copy the head if needed.
+     *
+     * Note that we don't copy the leading '!' character.
+     */
+
+    if (length > 1) {
+        memcpy(string.buffer, head+1, length-1);
+        string.pointer += length-1;
     }
 
     /* Scan the tag. */
                         *(string.pointer++) = '\'';
                         break;
 
+                    case '\\':
+                        *(string.pointer++) = '\\';
+                        break;
+
                     case 'N':   /* NEL (#x85) */
                         *(string.pointer++) = '\xC2';
                         *(string.pointer++) = '\x85';
                     case 'P':   /* PS (#x2029) */
                         *(string.pointer++) = '\xE2';
                         *(string.pointer++) = '\x80';
-                        *(string.pointer++) = '\xA8';
+                        *(string.pointer++) = '\xA9';
                         break;
 
                     case 'x':
                     if (!RESIZE(parser, whitespaces)) goto error;
                     COPY(parser, whitespaces);
                 }
+                else {
+                    FORWARD(parser);
+                }
             }
             else
             {
 
         while (!IS_BLANKZ(parser))
         {
-            /* Check for 'x:x' in the flow context. */
+            /* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */
 
             if (parser->flow_level && CHECK(parser, ':') && !IS_BLANKZ_AT(parser, 1)) {
                 yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
                 if (leading_blanks && parser->column < indent && IS_TAB(parser)) {
                     yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
                             start_mark, "found a tab character that violate intendation");
-                    break;
+                    goto error;
                 }
 
                 /* Consume a space or a tab character. */
                     if (!RESIZE(parser, whitespaces)) goto error;
                     COPY(parser, whitespaces);
                 }
+                else {
+                    FORWARD(parser);
+                }
             }
             else
             {
 
         /* Check intendation level. */
 
-        if (parser->column < indent)
+        if (!parser->flow_level && parser->column < indent)
             break;
     }
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.