fixed a major bug in the parser
This commit is contained in:
		
							parent
							
								
									3f8dc632e2
								
							
						
					
					
						commit
						89a1b0247b
					
				
					 3 changed files with 446 additions and 381 deletions
				
			
		
							
								
								
									
										763
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										763
									
								
								src/json.hpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -2524,7 +2524,7 @@ class basic_json
 | 
			
		|||
                '\000'         { return token_type::end_of_input; }
 | 
			
		||||
 | 
			
		||||
                // anything else is an error
 | 
			
		||||
                *              { return token_type::parse_error; }
 | 
			
		||||
                .              { return token_type::parse_error; }
 | 
			
		||||
             */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2612,7 +2612,19 @@ class basic_json
 | 
			
		|||
            get_token();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// public parser interface
 | 
			
		||||
        inline basic_json parse()
 | 
			
		||||
        {
 | 
			
		||||
            basic_json result = parse_internal();
 | 
			
		||||
 | 
			
		||||
            expect(lexer::token_type::end_of_input);
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// the actual parser
 | 
			
		||||
        inline basic_json parse_internal()
 | 
			
		||||
        {
 | 
			
		||||
            switch (last_token)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -2627,12 +2639,19 @@ class basic_json
 | 
			
		|||
                    // closing } -> we are done
 | 
			
		||||
                    if (last_token == lexer::token_type::end_object)
 | 
			
		||||
                    {
 | 
			
		||||
                        get_token();
 | 
			
		||||
                        return result;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // otherwise: parse key-value pairs
 | 
			
		||||
                    do
 | 
			
		||||
                    {
 | 
			
		||||
                        // ugly, but could be fixed with loop reorganization
 | 
			
		||||
                        if (last_token == lexer::token_type::value_separator)
 | 
			
		||||
                        {
 | 
			
		||||
                            get_token();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // store key
 | 
			
		||||
                        expect(lexer::token_type::value_string);
 | 
			
		||||
                        const auto key = m_lexer.get_string();
 | 
			
		||||
| 
						 | 
				
			
			@ -2643,16 +2662,13 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
                        // parse value
 | 
			
		||||
                        get_token();
 | 
			
		||||
                        result[key] = parse();
 | 
			
		||||
 | 
			
		||||
                        // read next character
 | 
			
		||||
                        get_token();
 | 
			
		||||
                        result[key] = parse_internal();
 | 
			
		||||
                    }
 | 
			
		||||
                    while (last_token == lexer::token_type::value_separator
 | 
			
		||||
                            and get_token() == last_token);
 | 
			
		||||
                    while (last_token == lexer::token_type::value_separator);
 | 
			
		||||
 | 
			
		||||
                    // closing }
 | 
			
		||||
                    expect(lexer::token_type::end_object);
 | 
			
		||||
                    get_token();
 | 
			
		||||
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -2668,44 +2684,53 @@ class basic_json
 | 
			
		|||
                    // closing ] -> we are done
 | 
			
		||||
                    if (last_token == lexer::token_type::end_array)
 | 
			
		||||
                    {
 | 
			
		||||
                        get_token();
 | 
			
		||||
                        return result;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // otherwise: parse values
 | 
			
		||||
                    do
 | 
			
		||||
                    {
 | 
			
		||||
                        // parse value
 | 
			
		||||
                        result.push_back(parse());
 | 
			
		||||
                        // ugly, but could be fixed with loop reorganization
 | 
			
		||||
                        if (last_token == lexer::token_type::value_separator)
 | 
			
		||||
                        {
 | 
			
		||||
                            get_token();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // read next character
 | 
			
		||||
                        get_token();
 | 
			
		||||
                        // parse value
 | 
			
		||||
                        result.push_back(parse_internal());
 | 
			
		||||
                    }
 | 
			
		||||
                    while (last_token == lexer::token_type::value_separator
 | 
			
		||||
                            and get_token() == last_token);
 | 
			
		||||
                    while (last_token == lexer::token_type::value_separator);
 | 
			
		||||
 | 
			
		||||
                    // closing ]
 | 
			
		||||
                    expect(lexer::token_type::end_array);
 | 
			
		||||
                    get_token();
 | 
			
		||||
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case (lexer::token_type::literal_null):
 | 
			
		||||
                {
 | 
			
		||||
                    get_token();
 | 
			
		||||
                    return basic_json(nullptr);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case (lexer::token_type::value_string):
 | 
			
		||||
                {
 | 
			
		||||
                    return basic_json(m_lexer.get_string());
 | 
			
		||||
                    const auto s = m_lexer.get_string();
 | 
			
		||||
                    get_token();
 | 
			
		||||
                    return basic_json(s);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case (lexer::token_type::literal_true):
 | 
			
		||||
                {
 | 
			
		||||
                    get_token();
 | 
			
		||||
                    return basic_json(true);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case (lexer::token_type::literal_false):
 | 
			
		||||
                {
 | 
			
		||||
                    get_token();
 | 
			
		||||
                    return basic_json(false);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2719,6 +2744,8 @@ class basic_json
 | 
			
		|||
                                                    m_lexer.get_string_value() + " is not a number");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    get_token();
 | 
			
		||||
 | 
			
		||||
                    // check if conversion loses precision
 | 
			
		||||
                    const auto int_val = static_cast<number_integer_t>(float_val);
 | 
			
		||||
                    if (float_val == int_val)
 | 
			
		||||
| 
						 | 
				
			
			@ -2744,7 +2771,6 @@ class basic_json
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// get next token from lexer
 | 
			
		||||
        inline typename lexer::token_type get_token()
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5052,7 +5052,15 @@ TEST_CASE("parser class")
 | 
			
		|||
        CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
 | 
			
		||||
 | 
			
		||||
        // unexpected end of null
 | 
			
		||||
        CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue