1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2007-2011 Baptiste Lepilleur
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Distributed under MIT license, or public domain if desired and
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// recognized in your jurisdiction.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if !defined(JSON_IS_AMALGAMATION)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# include <json/assertions.h>
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# include <json/reader.h>
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# include <json/value.h>
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# include "json_tool.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif // if !defined(JSON_IS_AMALGAMATION)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <utility>
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <cstdio>
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <cassert>
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <cstring>
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <stdexcept>
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <string>
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <istream>
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if _MSC_VER >= 1400 // VC++ 8.0
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace Json {
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Implementation of class Features
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// ////////////////////////////////
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Features::Features()
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   : allowComments_( true )
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   , strictRoot_( false )
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Features
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Features::all()
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return Features();
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Features
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Features::strictMode()
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Features features;
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   features.allowComments_ = false;
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   features.strictRoot_ = true;
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return features;
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Implementation of class Reader
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// ////////////////////////////////
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static inline bool
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static inline bool
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static bool
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)containsNewLine( Reader::Location begin,
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 Reader::Location end )
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for ( ;begin < end; ++begin )
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( *begin == '\n'  ||  *begin == '\r' )
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return true;
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return false;
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Class Reader
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// //////////////////////////////////////////////////////////////////
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::Reader()
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : errors_(),
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      document_(),
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      begin_(),
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      end_(),
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      current_(),
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValueEnd_(),
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValue_(),
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      commentsBefore_(),
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      features_( Features::all() ),
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      collectComments_()
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::Reader( const Features &features )
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : errors_(),
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      document_(),
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      begin_(),
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      end_(),
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      current_(),
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValueEnd_(),
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValue_(),
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      commentsBefore_(),
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      features_( features ),
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      collectComments_()
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::parse( const std::string &document,
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               Value &root,
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               bool collectComments )
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   document_ = document;
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   const char *begin = document_.c_str();
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   const char *end = begin + document_.length();
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return parse( begin, end, root, collectComments );
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::parse( std::istream& sin,
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               Value &root,
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               bool collectComments )
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   //std::istream_iterator<char> begin(sin);
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   //std::istream_iterator<char> end;
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // Those would allow streamed input from a file, if parse() were a
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // template function.
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // Since std::string is reference-counted, this at least does not
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // create an extra copy.
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   std::string doc;
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   std::getline(sin, doc, (char)EOF);
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return parse( doc, root, collectComments );
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::parse( const char *beginDoc, const char *endDoc,
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               Value &root,
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               bool collectComments )
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( !features_.allowComments_ )
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      collectComments = false;
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   begin_ = beginDoc;
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   end_ = endDoc;
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   collectComments_ = collectComments;
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   current_ = begin_;
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   lastValueEnd_ = 0;
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   lastValue_ = 0;
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   commentsBefore_ = "";
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   errors_.clear();
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( !nodes_.empty() )
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      nodes_.pop();
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   nodes_.push( &root );
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool successful = readValue();
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Token token;
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   skipCommentTokens( token );
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( collectComments_  &&  !commentsBefore_.empty() )
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      root.setComment( commentsBefore_, commentAfter );
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( features_.strictRoot_ )
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !root.isArray()  &&  !root.isObject() )
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         // Set error location to start of doc, ideally should be first token found in doc
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         token.type_ = tokenError;
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         token.start_ = beginDoc;
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         token.end_ = endDoc;
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         addError( "A valid JSON document must be either an array or an object value.",
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   token );
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return false;
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return successful;
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readValue()
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Token token;
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   skipCommentTokens( token );
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool successful = true;
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( collectComments_  &&  !commentsBefore_.empty() )
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue().setComment( commentsBefore_, commentBefore );
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      commentsBefore_ = "";
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   switch ( token.type_ )
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenObjectBegin:
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = readObject( token );
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenArrayBegin:
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = readArray( token );
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenNumber:
209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = decodeNumber( token );
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenString:
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = decodeString( token );
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenTrue:
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = true;
216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenFalse:
218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = false;
219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case tokenNull:
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = Value();
222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   default:
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return addError( "Syntax error: value, object or array expected.", token );
225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
227a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( collectComments_ )
228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValueEnd_ = current_;
230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValue_ = &currentValue();
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return successful;
234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::skipCommentTokens( Token &token )
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( features_.allowComments_ )
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      do
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         readToken( token );
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      while ( token.type_ == tokenComment );
247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else
249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      readToken( token );
251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::expectToken( TokenType type, Token &token, const char *message )
257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   readToken( token );
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( token.type_ != type )
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return addError( message, token );
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readToken( Token &token )
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   skipSpaces();
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   token.start_ = current_;
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Char c = getNextChar();
271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool ok = true;
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   switch ( c )
273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '{':
275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenObjectBegin;
276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '}':
278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenObjectEnd;
279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '[':
281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenArrayBegin;
282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case ']':
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenArrayEnd;
285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '"':
287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenString;
288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = readString();
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '/':
291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenComment;
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = readComment();
293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '0':
295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '1':
296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '2':
297a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '3':
298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '4':
299a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '5':
300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '6':
301a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '7':
302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '8':
303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '9':
304a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case '-':
305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenNumber;
306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      readNumber();
307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case 't':
309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenTrue;
310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = match( "rue", 3 );
311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case 'f':
313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenFalse;
314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = match( "alse", 4 );
315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case 'n':
317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenNull;
318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = match( "ull", 3 );
319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case ',':
321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenArraySeparator;
322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case ':':
324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenMemberSeparator;
325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   case 0:
327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenEndOfStream;
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   default:
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = false;
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( !ok )
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      token.type_ = tokenError;
335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   token.end_ = current_;
336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void
341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::skipSpaces()
342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current_ != end_ )
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = *current_;
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' )
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ++current_;
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else
349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::match( Location pattern,
356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               int patternLength )
357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( end_ - current_ < patternLength )
359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return false;
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int index = patternLength;
361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( index-- )
362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( current_[index] != pattern[index] )
363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return false;
364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   current_ += patternLength;
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readComment()
371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location commentBegin = current_ - 1;
373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Char c = getNextChar();
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool successful = false;
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( c == '*' )
376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = readCStyleComment();
377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else if ( c == '/' )
378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      successful = readCppStyleComment();
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( !successful )
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return false;
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( collectComments_ )
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      CommentPlacement placement = commentBefore;
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )
386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            placement = commentAfterOnSameLine;
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      addComment( commentBegin, current_, placement );
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::addComment( Location begin,
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    Location end,
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    CommentPlacement placement )
401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   assert( collectComments_ );
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( placement == commentAfterOnSameLine )
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      assert( lastValue_ != 0 );
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      lastValue_->setComment( std::string( begin, end ), placement );
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else
409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !commentsBefore_.empty() )
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         commentsBefore_ += "\n";
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      commentsBefore_ += std::string( begin, end );
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readCStyleComment()
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current_ != end_ )
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = getNextChar();
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c == '*'  &&  *current_ == '/' )
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return getNextChar() == '/';
427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readCppStyleComment()
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current_ != end_ )
434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
435a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = getNextChar();
436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (  c == '\r'  ||  c == '\n' )
437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
442a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readNumber()
445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current_ != end_ )
447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)           !in( *current_, '.', 'e', 'E', '+', '-' ) )
450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ++current_;
452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readString()
457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Char c = 0;
459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current_ != end_ )
460a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      c = getNextChar();
462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c == '\\' )
463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         getNextChar();
464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if ( c == '"' )
465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return c == '"';
468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readObject( Token &/*tokenStart*/ )
473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Token tokenName;
475a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   std::string name;
476a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   currentValue() = Value( objectValue );
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( readToken( tokenName ) )
478a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool initialTokenOk = true;
480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      while ( tokenName.type_ == tokenComment  &&  initialTokenOk )
481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         initialTokenOk = readToken( tokenName );
482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if  ( !initialTokenOk )
483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object
485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return true;
486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( tokenName.type_ != tokenString )
487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      name = "";
490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !decodeString( tokenName, name ) )
491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return recoverFromError( tokenObjectEnd );
492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Token colon;
494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )
495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addErrorAndRecover( "Missing ':' after object member name",
497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    colon,
498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    tokenObjectEnd );
499a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Value &value = currentValue()[ name ];
501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      nodes_.push( &value );
502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool ok = readValue();
503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      nodes_.pop();
504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !ok ) // error already set
505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return recoverFromError( tokenObjectEnd );
506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Token comma;
508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !readToken( comma )
509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            ||  ( comma.type_ != tokenObjectEnd  &&
510a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  comma.type_ != tokenArraySeparator &&
511a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  comma.type_ != tokenComment ) )
512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addErrorAndRecover( "Missing ',' or '}' in object declaration",
514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    comma,
515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    tokenObjectEnd );
516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool finalizeTokenOk = true;
518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      while ( comma.type_ == tokenComment &&
519a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)              finalizeTokenOk )
520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         finalizeTokenOk = readToken( comma );
521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( comma.type_ == tokenObjectEnd )
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return true;
523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
524a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return addErrorAndRecover( "Missing '}' or object member name",
525a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              tokenName,
526a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              tokenObjectEnd );
527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
528a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
529a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
530a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::readArray( Token &/*tokenStart*/ )
532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   currentValue() = Value( arrayValue );
534a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   skipSpaces();
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( *current_ == ']' ) // empty array
536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Token endArray;
538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      readToken( endArray );
539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return true;
540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
541a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int index = 0;
542a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for (;;)
543a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
544a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Value &value = currentValue()[ index++ ];
545a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      nodes_.push( &value );
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool ok = readValue();
547a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      nodes_.pop();
548a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !ok ) // error already set
549a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return recoverFromError( tokenArrayEnd );
550a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
551a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Token token;
552a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Accept Comment after last item in the array.
553a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ok = readToken( token );
554a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      while ( token.type_ == tokenComment  &&  ok )
555a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
556a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ok = readToken( token );
557a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool badTokenType = ( token.type_ != tokenArraySeparator  &&
559a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            token.type_ != tokenArrayEnd );
560a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !ok  ||  badTokenType )
561a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
562a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addErrorAndRecover( "Missing ',' or ']' in array declaration",
563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    token,
564a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    tokenArrayEnd );
565a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
566a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( token.type_ == tokenArrayEnd )
567a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
568a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
569a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
570a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
571a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
572a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
573a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
574a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeNumber( Token &token )
575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool isDouble = false;
577a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      isDouble = isDouble
580a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 ||  in( *inspect, '.', 'e', 'E', '+' )
581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 ||  ( *inspect == '-'  &&  inspect != token.start_ );
582a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
583a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( isDouble )
584a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return decodeDouble( token );
585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // Attempts to parse the number as an integer. If the number is
586a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // larger than the maximum supported value of an integer then
587a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // we decode the number as a double.
588a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location current = token.start_;
589a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   bool isNegative = *current == '-';
590a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( isNegative )
591a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ++current;
592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt)
593a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                   : Value::maxLargestUInt;
594a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Value::LargestUInt threshold = maxIntegerValue / 10;
595a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Value::LargestUInt value = 0;
596a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current < token.end_ )
597a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
598a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = *current++;
599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c < '0'  ||  c > '9' )
600a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
601a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Value::UInt digit(c - '0');
602a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( value >= threshold )
603a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
604a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         // We've hit or exceeded the max value divided by 10 (rounded down). If
605a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         // a) we've only just touched the limit, b) this is the last digit, and
606a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         // c) it's small enough to fit in that rounding delta, we're okay.
607a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         // Otherwise treat this number as a double to avoid overflow.
608a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         if (value > threshold ||
609a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)             current != token.end_ ||
610a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)             digit > maxIntegerValue % 10)
611a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         {
612a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return decodeDouble( token );
613a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         }
614a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
615a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      value = value * 10 + digit;
616a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
617a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( isNegative )
618a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = -Value::LargestInt( value );
619a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else if ( value <= Value::LargestUInt(Value::maxInt) )
620a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = Value::LargestInt( value );
621a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else
622a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      currentValue() = value;
623a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
624a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
625a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
626a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
627a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
628a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeDouble( Token &token )
629a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
630a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   double value = 0;
631a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   const int bufferSize = 32;
632a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int count;
633a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int length = int(token.end_ - token.start_);
634a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
635a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // Sanity check to avoid buffer overflow exploits.
636a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if (length < 0) {
637a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return addError( "Unable to parse token length", token );
638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
639a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
640a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // Avoid using a string constant for the format control string given to
641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // sscanf, as this can cause hard to debug crashes on OS X. See here for more
642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // info:
643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   //
644a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
645a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   char format[] = "%lf";
646a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
647a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( length <= bufferSize )
648a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
649a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char buffer[bufferSize+1];
650a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      memcpy( buffer, token.start_, length );
651a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      buffer[length] = 0;
652a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      count = sscanf( buffer, format, &value );
653a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
654a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   else
655a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
656a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      std::string buffer( token.start_, token.end_ );
657a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      count = sscanf( buffer.c_str(), format, &value );
658a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
659a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
660a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( count != 1 )
661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
662a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   currentValue() = value;
663a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
664a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
665a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
666a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
667a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
668a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeString( Token &token )
669a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
670a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   std::string decoded;
671a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( !decodeString( token, decoded ) )
672a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return false;
673a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   currentValue() = decoded;
674a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
675a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
677a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
678a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
679a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeString( Token &token, std::string &decoded )
680a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
681a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   decoded.reserve( token.end_ - token.start_ - 2 );
682a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location current = token.start_ + 1; // skip '"'
683a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location end = token.end_ - 1;      // do not include '"'
684a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current != end )
685a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
686a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = *current++;
687a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c == '"' )
688a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if ( c == '\\' )
690a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
691a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         if ( current == end )
692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return addError( "Empty escape sequence in string", token, current );
693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         Char escape = *current++;
694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         switch ( escape )
695a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         {
696a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case '"': decoded += '"'; break;
697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case '/': decoded += '/'; break;
698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case '\\': decoded += '\\'; break;
699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 'b': decoded += '\b'; break;
700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 'f': decoded += '\f'; break;
701a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 'n': decoded += '\n'; break;
702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 'r': decoded += '\r'; break;
703a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 't': decoded += '\t'; break;
704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         case 'u':
705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            {
706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               unsigned int unicode;
707a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
708a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  return false;
709a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               decoded += codePointToUTF8(unicode);
710a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            break;
712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         default:
713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return addError( "Bad escape sequence in string", token, current );
714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         }
715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else
717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         decoded += c;
719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
724a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
725a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeUnicodeCodePoint( Token &token,
726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     Location &current,
727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     Location end,
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     unsigned int &unicode )
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return false;
733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if (unicode >= 0xD800 && unicode <= 0xDBFF)
734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // surrogate pairs
736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (end - current < 6)
737a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
738a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      unsigned int surrogatePair;
739a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (*(current++) == '\\' && *(current++)== 'u')
740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
741a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
742a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         {
743a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
744a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         }
745a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         else
746a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return false;
747a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
748a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else
749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
750a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
751a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
752a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
755a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::decodeUnicodeEscapeSequence( Token &token,
756a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     Location &current,
757a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     Location end,
758a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     unsigned int &unicode )
759a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
760a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( end - current < 4 )
761a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
762a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   unicode = 0;
763a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for ( int index =0; index < 4; ++index )
764a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
765a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = *current++;
766a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      unicode *= 16;
767a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c >= '0'  &&  c <= '9' )
768a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         unicode += c - '0';
769a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if ( c >= 'a'  &&  c <= 'f' )
770a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         unicode += c - 'a' + 10;
771a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if ( c >= 'A'  &&  c <= 'F' )
772a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         unicode += c - 'A' + 10;
773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else
774a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
775a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
776a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return true;
777a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
778a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
779a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
780a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
781a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::addError( const std::string &message,
782a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  Token &token,
783a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  Location extra )
784a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
785a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   ErrorInfo info;
786a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   info.token_ = token;
787a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   info.message_ = message;
788a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   info.extra_ = extra;
789a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   errors_.push_back( info );
790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return false;
791a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
792a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
793a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
794a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
795a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::recoverFromError( TokenType skipUntilToken )
796a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
797a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int errorCount = int(errors_.size());
798a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Token skip;
799a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for (;;)
800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
801a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( !readToken(skip) )
802a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         errors_.resize( errorCount ); // discard errors caused by recovery
803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )
804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         break;
805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   errors_.resize( errorCount );
807a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return false;
808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
809a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
810a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
811a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool
812a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::addErrorAndRecover( const std::string &message,
813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            Token &token,
814a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            TokenType skipUntilToken )
815a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
816a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   addError( message, token );
817a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return recoverFromError( skipUntilToken );
818a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
819a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
820a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
821a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Value &
822a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::currentValue()
823a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
824a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return *(nodes_.top());
825a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
826a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
828a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::Char
829a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::getNextChar()
830a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   if ( current_ == end_ )
832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return 0;
833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return *current_++;
834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void
838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::getLocationLineAndColumn( Location location,
839a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  int &line,
840a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  int &column ) const
841a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location current = begin_;
843a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   Location lastLineStart = current;
844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   line = 0;
845a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   while ( current < location  &&  current != end_ )
846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
847a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Char c = *current++;
848a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( c == '\r' )
849a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
850a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         if ( *current == '\n' )
851a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            ++current;
852a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         lastLineStart = current;
853a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ++line;
854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if ( c == '\n' )
856a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      {
857a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         lastLineStart = current;
858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ++line;
859a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
860a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
861a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   // column & line start at 1
862a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   column = int(location - lastLineStart) + 1;
863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   ++line;
864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
865a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
866a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
867a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string
868a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::getLocationLineAndColumn( Location location ) const
869a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
870a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   int line, column;
871a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   getLocationLineAndColumn( location, line, column );
872a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   char buffer[18+16+16+1];
873a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   sprintf( buffer, "Line %d, Column %d", line, column );
874a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return buffer;
875a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
876a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
877a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
878a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Deprecated. Preserved for backward compatibility
879a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string
880a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::getFormatedErrorMessages() const
881a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
882a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return getFormattedErrorMessages();
883a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
884a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
885a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
886a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string
887a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Reader::getFormattedErrorMessages() const
888a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
889a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   std::string formattedMessage;
890a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   for ( Errors::const_iterator itError = errors_.begin();
891a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         itError != errors_.end();
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ++itError )
893a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   {
894a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const ErrorInfo &error = *itError;
895a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
896a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      formattedMessage += "  " + error.message_ + "\n";
897a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if ( error.extra_ )
898a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
899a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   }
900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   return formattedMessage;
901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::istream& operator>>( std::istream &sin, Value &root )
905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles){
906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Json::Reader reader;
907a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool ok = reader.parse(sin, root, true);
908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!ok) {
909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      fprintf(
910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          stderr,
911a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          "Error from reader: %s",
912a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          reader.getFormattedErrorMessages().c_str());
913a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
914a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      JSON_FAIL_MESSAGE("reader error");
915a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
916a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return sin;
917a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
918a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
919a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
920a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace Json
921