Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Diff of /branches/vis15/src/debugger/engine/json.cxx
ViewVC logotype

Diff of /branches/vis15/src/debugger/engine/json.cxx

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 5125, Wed Jul 19 18:32:51 2017 UTC revision 5126, Wed Jul 19 21:04:31 2017 UTC
# Line 14  Line 14 
14   */   */
15    
16  #include "json.hxx"  #include "json.hxx"
 #include <iostream>  
 #include <fstream>  
 #include <cctype>  
 #include "strings.h"  
17    
18  namespace JSON {  namespace JSON {
19    
20  /***** class Value member functions *****/  /***** class value member functions *****/
21    
22  Value::~Value () { }  value::~value () { }
23    
24  const Object *Value::asObject () const  const object *value::asObject () const
25  {  {
26      return dynamic_cast<const Object *>(this);      return dynamic_cast<const object *>(this);
27  }  }
28    
29  const Array *Value::asArray () const  const array *value::asArray () const
30  {  {
31      return dynamic_cast<const Array *>(this);      return dynamic_cast<const array *>(this);
32  }  }
33    
34  const Number *Value::asNumber () const  const Number *value::asNumber () const
35  {  {
36      return dynamic_cast<const Number *>(this);      return dynamic_cast<const Number *>(this);
37  }  }
38    
39  const String *Value::asString () const  const string *value::asString () const
40  {  {
41      return dynamic_cast<const String *>(this);      return dynamic_cast<const string *>(this);
42  }  }
43    
44  const Bool *Value::asBool () const  const boolean *value::asBool () const
45  {  {
46      return dynamic_cast<const Bool *>(this);      return dynamic_cast<const boolean *>(this);
47  }  }
48    
49  /***** class Object member functions *****/  /***** class object member functions *****/
50    
51  Object::Object () : Value(T_OBJECT), _value() { }  object::object () : value(T_OBJECT), _value() { }
52    
53  Object::~Object ()  object::~object ()
54  {  {
55    // need to delete contents    // need to delete contents
56  }  }
57    
58  void Object::insert (std::string key, Value *val)  void object::insert (std::string key, value *val)
59  {  {
60      this->_value.insert (std::pair<std::string, Value *>(key, val));      this->_value.insert (std::pair<std::string, value *>(key, val));
61  }  }
62    
63  Value *Object::operator[] (std::string key) const  value *object::operator[] (std::string key) const
64  {  {
65      std::map<std::string, Value *>::const_iterator got = this->_value.find(key);      std::map<std::string, value *>::const_iterator got = this->_value.find(key);
66      if (got == this->_value.end())      if (got == this->_value.end())
67          return nullptr;          return nullptr;
68      else      else
69          return got->second;          return got->second;
70  }  }
71    
72  std::string Object::toString() { return std::string("<object>"); }  std::string object::toString() { return std::string("<object>"); }
73    
74  /***** class Array member functions *****/  /***** class array member functions *****/
75    
76  Array::Array () : Value(T_ARRAY), _value() { }  array::array () : value(T_ARRAY), _value() { }
77    
78  Array::~Array ()  array::~array ()
79  {  {
80    // need to delete contents    // need to delete contents
81  }  }
82    
83  std::string Array::toString() { return std::string("<array>"); }  std::string array::toString() { return std::string("<array>"); }
84    
85  /***** class Number member functions *****/  /***** class Number member functions *****/
86    
87  Number::Number (double v) : Value(T_NUMBER), _value(v) { }  integer::integer (int64_t v) : value(T_INTEGER), _value(v) { }
88    
89  Number::~Number () { }  integer::~integer () { }
90    
91  std::string Number::toString() { return std::string("<number>"); }  std::string integer::toString() { return std::string("<integer>"); }
92    
93  /***** class String member functions *****/  /***** class Number member functions *****/
   
 String::String (std::string v) : Value(T_STRING), _value(v) { }  
   
 String::~String () { }  
   
 std::string String::toString () { return this->_value; }  
   
 /***** class Bool member functions *****/  
   
 Bool::Bool (bool v) : Value(T_BOOL), _value(v) { }  
   
 Bool::~Bool () { }  
   
 std::string Bool::toString() { if (this->_value) return std::string("true"); else return std::string("false"); }  
   
 /***** class Null member functions *****/  
   
 Null::Null () : Value(T_NULL) { }  
   
 Null::~Null () { }  
   
 std::string Null::toString() { return std::string("null"); }  
   
   
 /***** JSON parsing *****/  
   
 class Input {  
   public:  
     Input (std::string filename);  
     ~Input () { delete this->_buffer; }  
   
   
     Input const &operator++ (int _unused) {  
         if (this->_buffer[this->_i++] == '\n') this->_lnum++;  
         return *this;  
     }  
     Input const &operator += (int n) { this->_i += n;  return *this; }  
     const char *operator() () const { return &(this->_buffer[this->_i]); }  
     char operator[] (int j) const { return this->_buffer[this->_i + j]; }  
     char operator* () const { return this->_buffer[this->_i]; }  
     int avail () const { return this->_len - this->_i; }  
     bool eof () const { return this->_i >= this->_len; }  
   
     void error (std::string msg)  
     {  
 #ifndef NDEBUG  
         std::cerr << "JSON::ParseFile(" << this->_file << "): " << msg  
             << " at line " << this->_lnum << std::endl;  
         std::cerr << "    input = \"";  
         int n = this->avail();  
         if (20 < n) n = 20;  
         for (int i = 0;  (i < 20);  i++) {  
             if (isprint(this->_buffer[this->_i+i]))  
                 std::cerr << this->_buffer[this->_i+i];  
             else  
                 std::cerr << ".";  
         }  
         std::cerr << " ...\n" << std::endl;  
 #endif  
     }  
   
   private:  
     std::string _file;  
     char        *_buffer;  
     int         _i;     // character index  
     int         _lnum;  // current line number  
     int         _len;   // buffer size  
   
 };  
   
 Input::Input (std::string filename)  
     : _file(filename), _buffer(nullptr), _i(0), _lnum(0), _len(0)  
 {  
   // open the JSON file for reading  
     std::ifstream inS(filename, std::ios::in);  
     if (inS.fail())  
         return;  
   
   // figure out the size of the file  
     inS.seekg (0, inS.end);  
     int length = inS.tellg();  
     inS.seekg (0, inS.beg);  
   
   // read length bytes  
     this->_lnum = 1;  
     this->_buffer = new char[length];  
     inS.read (this->_buffer, length);  
   
     if (inS.fail()) {  
         delete this->_buffer;  
         this->_buffer = nullptr;  
         return;  
     }  
   
     this->_len = length;  
 }  
   
 // forward decls  
 static bool SkipWhitespace (Input &datap);  
 static Value *Parse (Input &datap);  
   
 // parse a JSON file; this returns nullptr if there is a parsing error  
 Value *ParseFile (std::string filename)  
 {  
   // open the JSON file for reading  
     Input datap(filename);  
     if (datap.eof()) {  
 #ifndef NDEBUG  
         std::cerr << "JSON::ParseFile: unable to read \"" << filename << "\"" << std::endl;  
 #endif  
         return nullptr;  
     }  
94    
95      if (! SkipWhitespace (datap)) {  number::number (double v) : value(T_NUMBER), _value(v) { }
         return nullptr;  
     }  
96    
97      Value *value = Parse (datap);  number::~number () { }
98    
99      return value;  std::string number::toString() { return std::string("<number>"); }
100    
101  }  /***** class string member functions *****/
102    
103  static bool SkipWhitespace (Input &datap)  string::string (std::string v) : value(T_STRING), _value(v) { }
 {  
     while ((! datap.eof()) && isspace(*datap))  
         datap++;  
104    
105      if (datap.eof()) {  string::~string () { }
         datap.error("unexpected eof");  
         return false;  
     }  
     else  
         return true;  
 }  
106    
107  static bool ExtractString (Input &datap, std::string &str)  std::string string::toString () { return this->_value; }
 {  
     str = "";  
108    
109      if (*datap != '\"')  /***** class boolean member functions *****/
         return false;  
     datap++;  
   
     while (! datap.eof()) {  
         // Save the char so we can change it if need be  
         char nextChar = *datap;  
   
         // Escaping something?  
         if (nextChar == '\\') {  
             // Move over the escape char  
             datap++;  
             // Deal with the escaped char  
             switch (*datap) {  
                 case '"': nextChar = '"'; break;  
                 case '\\': nextChar = '\\'; break;  
                 case '/': nextChar = '/'; break;  
                 case 'b': nextChar = '\b'; break;  
                 case 'f': nextChar = '\f'; break;  
                 case 'n': nextChar = '\n'; break;  
                 case 'r': nextChar = '\r'; break;  
                 case 't': nextChar = '\t'; break;  
                 case 'u': /* no UNICODE support */  
                 // By the spec, only the above cases are allowed  
                 default:  
                     datap.error("invalid escape sequence in string");  
                     return false;  
             }  
         }  
       // End of the string?  
         else if (nextChar == '"') {  
             datap++;  
             str.reserve(); // Remove unused capacity  
             return true;  
         }  
       // Disallowed char?  
         else if (! isprint(nextChar) && (nextChar != '\t')) {  
           // SPEC Violation: Allow tabs due to real world cases  
             datap.error("invalid character in string");  
             return false;  
         }  
       // Add the next char  
         str += nextChar;  
       // Move on  
         datap++;  
     }  
110    
111    // If we're here, the string ended incorrectly  boolean::boolean (bool v) : value(T_BOOL), _value(v) { }
     return false;  
 }  
112    
113  static double ParseInt (Input &datap)  boolean::~boolean () { }
 {  
     double integer = 0;  
     while (*datap != 0 && isdigit(*datap)) {  
         integer = integer * 10 + (*datap - '0');  
         datap++;  
     }  
114    
115      return integer;  std::string boolean::toString() {
116        if (this->_value) {
117            return std::string("true");
118  }  }
   
 static double ParseDecimal (Input &datap)  
 {  
     double decimal = 0.0;  
     double factor = 0.1;  
   
     while ((! datap.eof()) && isdigit(*datap)) {  
         int digit = (*datap - '0');  
         decimal = decimal + digit * factor;  
         factor *= 0.1;  
         datap++;  
     }  
     return decimal;  
 }  
   
 static Value *Parse (Input &datap)  
 {  
     if (datap.eof()) {  
         datap.error("unexpected end of file");  
         return nullptr;  
     }  
   
   // Is it a string?  
     if (*datap == '"') {  
         std::string str;  
         if (! ExtractString(datap, str))  
             return nullptr;  
         else  
             return new String(str);  
     }  
   // Is it a boolean?  
     else if ((datap.avail() >= 4) && strncasecmp(datap(), "true", 4) == 0) {  
         datap += 4;  
         return new Bool(true);  
     }  
     else if ((datap.avail() >=  5) && strncasecmp(datap(), "false", 5) == 0) {  
         datap += 5;  
         return new Bool(false);  
     }  
   // Is it a null?  
     else if ((datap.avail() >=  4) && strncasecmp(datap(), "null", 4) == 0) {  
         datap += 4;  
         return new Null();  
     }  
   // Is it a number?  
     else if (*datap == '-' || isdigit(*datap)) {  
       // Negative?  
         bool neg = *datap == '-';  
         if (neg) datap++;  
   
         double number = 0.0;  
   
       // Parse the whole part of the number - only if it wasn't 0  
         if (*datap == '0')  
             datap++;  
         else if (isdigit(*datap))  
             number = ParseInt(datap);  
119          else {          else {
120              datap.error("invalid number");          return std::string("false");
             return nullptr;  
         }  
   
       // Could be a decimal now...  
         if (*datap == '.') {  
             datap++;  
   
             // Not get any digits?  
             if (! isdigit(*datap)) {  
                 datap.error("invalid number");  
                 return nullptr;  
             }  
   
             // Find the decimal and sort the decimal place out  
             // Use ParseDecimal as ParseInt won't work with decimals less than 0.1  
             // thanks to Javier Abadia for the report & fix  
             double decimal = ParseDecimal(datap);  
   
             // Save the number  
             number += decimal;  
         }  
   
         // Could be an exponent now...  
         if (*datap == 'E' || *datap == 'e') {  
             datap++;  
   
             // Check signage of expo  
             bool neg_expo = false;  
             if (*datap == '-' || *datap == '+') {  
                 neg_expo = *datap == '-';  
                 datap++;  
             }  
   
             // Not get any digits?  
             if (! isdigit(*datap)) {  
                 datap.error("invalid number");  
                 return nullptr;  
             }  
   
             // Sort the expo out  
             double expo = ParseInt(datap);  
             for (double i = 0.0; i < expo; i++)  
                 number = neg_expo ? (number / 10.0) : (number * 10.0);  
         }  
   
         // Was it neg?  
         if (neg) number *= -1;  
   
         return new Number(number);  
     }  
   // An object?  
     else if (*datap == '{') {  
         Object *object = new Object();  
   
         datap++;  
   
         while (!datap.eof()) {  
           // Whitespace at the start?  
             if (! SkipWhitespace(datap)) {  
                 delete object;  
                 return nullptr;  
             }  
   
           // Special case: empty object  
             if ((object->size() == 0) && (*datap == '}')) {  
                 datap++;  
                 return object;  
121              }              }
   
           // We want a string now...  
             std::string name;  
 // CHECK: do we need to look for "?  
             if (! ExtractString(datap, name)) {  
                 datap.error("expected label");  
                 delete object;  
                 return nullptr;  
122              }              }
123    
124            // More whitespace?  /***** class null member functions *****/
             if (! SkipWhitespace(datap)) {  
                 delete object;  
                 return nullptr;  
             }  
125    
126            // Need a : now  null::null () : value(T_NULL) { }
             if (*datap != ':') {  
                 datap.error("expected ':'");  
                 delete object;  
                 return nullptr;  
             }  
             datap++;  
127    
128            // More whitespace?  null::~null () { }
             if (! SkipWhitespace(datap)) {  
                 delete object;  
                 return nullptr;  
             }  
129    
130            // The value is here  std::string null::toString() { return std::string("null"); }
             Value *value = Parse(datap);  
             if (value == nullptr) {  
                 delete object;  
                 return nullptr;  
             }  
   
           // Add the name:value  
             object->insert(name, value);  
   
           // More whitespace?  
             if (! SkipWhitespace(datap)) {  
                 delete object;  
                 return nullptr;  
             }  
131    
             // End of object?  
             if (*datap == '}') {  
                 datap++;  
                 return object;  
             }  
132    
133              // Want a , now  /***** JSON parsing *****/
             if (*datap != ',') {  
                 datap.error("expected ','");  
                 delete object;  
                 return nullptr;  
             }  
   
             datap++;  
         }  
   
       // Only here if we ran out of data  
         datap.error("unexpected eof");  
         delete object;  
         return nullptr;  
     }  
   
     // An array?  
     else if (*datap == '[') {  
         Array *array = new Array();  
   
         datap++;  
   
         while (! datap.eof()) {  
           // Whitespace at the start?  
             if (! SkipWhitespace(datap)) {  
                 delete array;  
                 return nullptr;  
             }  
   
           // Special case - empty array  
             if ((array->length() == 0) && (*datap == ']')) {  
                 datap++;  
                 return array;  
             }  
   
           // Get the value  
             Value *value = Parse(datap);  
             if (value == nullptr) {  
                 delete array;  
                 return nullptr;  
             }  
   
           // Add the value  
             array->add(value);  
   
           // More whitespace?  
             if (! SkipWhitespace(datap)) {  
                 delete array;  
                 return nullptr;  
             }  
   
           // End of array?  
             if (*datap == ']') {  
                 datap++;  
                 return array;  
             }  
   
           // Want a , now  
             if (*datap != ',') {  
                 datap.error("expected ','");  
                 delete array;  
                 return nullptr;  
             }  
   
             datap++;  
         }  
   
       // Only here if we ran out of data  
         datap.error("unexpected eof");  
         delete array;  
         return nullptr;  
     }  
   // Ran out of possibilites, it's bad!  
     else {  
         datap.error("bogus input");  
         return nullptr;  
     }  
 }  
134    
135  } // namespace JSON  } // namespace JSON

Legend:
Removed from v.5125  
changed lines
  Added in v.5126

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0