Advertisement
Rochet2

smallfolk_cpp std::move

Sep 25th, 2015
282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 23.22 KB | None | 0 0
  1. #ifndef SMALLFOLK_H
  2. #define SMALLFOLK_H
  3.  
  4. #include <string>
  5. #include <iostream>
  6. #include <iomanip>
  7. #include <sstream>
  8. #include <map>
  9. #include <unordered_map>
  10. #include <cmath>
  11. #include <memory>
  12. #include <cassert>
  13. #include <functional>
  14. #include <exception>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17.  
  18. class smallfolk_exception : public std::exception
  19. {
  20. public:
  21.     static size_t const size = 2048;
  22.  
  23.     smallfolk_exception(const char * format, ...) : std::exception()
  24.     {
  25.         char buffer[size];
  26.         va_list args;
  27.         va_start(args, format);
  28.         vsnprintf_s(buffer, size, format, args);
  29.         errmsg = buffer;
  30.         va_end(args);
  31.     }
  32.  
  33.     virtual const char* what() const throw()
  34.     {
  35.         return errmsg.c_str();
  36.     }
  37.  
  38.     std::string errmsg;
  39. };
  40.  
  41. enum LuaTypeTag
  42. {
  43.     TNIL,
  44.     TSTRING,
  45.     TNUMBER,
  46.     TTABLE,
  47.     TBOOL,
  48. };
  49.  
  50. class LuaVal
  51. {
  52. public:
  53.  
  54.     // static nil value, same as LuaVal();
  55.     static LuaVal const & nil()
  56.     {
  57.         static LuaVal const nil;
  58.         return nil;
  59.     }
  60.  
  61.     // returns the string representation of the value info similar to lua tostring
  62.     std::string tostring() const
  63.     {
  64.         switch (tag)
  65.         {
  66.         case TBOOL:
  67.             if (b)
  68.                 return "true";
  69.             else
  70.                 return "false";
  71.         case TNIL:
  72.             return "nil";
  73.         case TSTRING:
  74.             return s;
  75.         case TNUMBER:
  76.             return tostring(d);
  77.         case TTABLE:
  78.             return tostring(tbl_ptr);
  79.         default:
  80.             break;
  81.         }
  82.         throw smallfolk_exception("tostring invalid or unhandled tag %i", tag);
  83.         return std::string();
  84.     }
  85.  
  86.     struct LuaValHasher
  87.     {
  88.         size_t operator()(LuaVal const & v) const
  89.         {
  90.             switch (v.tag)
  91.             {
  92.             case TBOOL:
  93.                 return std::hash<bool>()(v.b);
  94.             case TNIL:
  95.                 return std::hash<int>()(0);
  96.             case TSTRING:
  97.                 return std::hash<std::string>()(v.s);
  98.             case TNUMBER:
  99.                 return std::hash<double>()(v.d);
  100.             case TTABLE:
  101.                 return std::hash<TblPtr>()(v.tbl_ptr);
  102.             default:
  103.                 return std::hash<std::string>()(v.tostring());
  104.             }
  105.         }
  106.     };
  107.  
  108.     typedef std::unordered_map< LuaVal, LuaVal, LuaValHasher> LuaTable;
  109.     typedef std::unique_ptr< LuaTable > TblPtr; // circular reference memleak if insert self to self
  110.  
  111.     LuaVal(const LuaTypeTag tag) : tag(tag), tbl_ptr(tag == TTABLE ? new LuaTable() : nullptr), d(0), b(false)
  112.     {
  113.         if (istable() && !tbl_ptr)
  114.             throw smallfolk_exception("creating table LuaVal with nullptr table");
  115.     }
  116.     LuaVal() : tag(TNIL), tbl_ptr(nullptr), d(0), b(false)
  117.     {
  118.     }
  119.     LuaVal(const long d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  120.     {
  121.     }
  122.     LuaVal(const unsigned long d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  123.     {
  124.     }
  125.     LuaVal(const int d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  126.     {
  127.     }
  128.     LuaVal(const unsigned int d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  129.     {
  130.     }
  131.     LuaVal(const float d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  132.     {
  133.     }
  134.     LuaVal(const double d) : tag(TNUMBER), tbl_ptr(nullptr), d(d), b(false)
  135.     {
  136.     }
  137.     LuaVal(const std::string& s) : tag(TSTRING), tbl_ptr(nullptr), s(s), d(0), b(false)
  138.     {
  139.     }
  140.     LuaVal(const char* s) : tag(TSTRING), tbl_ptr(nullptr), s(s), d(0), b(false)
  141.     {
  142.     }
  143.     LuaVal(const bool b) : tag(TBOOL), tbl_ptr(nullptr), d(0), b(b)
  144.     {
  145.     }
  146.     LuaVal(LuaTable const & luatable) : tag(TTABLE), tbl_ptr(new LuaTable(luatable)), d(0), b(false)
  147.     {
  148.         if (!tbl_ptr)
  149.             throw smallfolk_exception("creating table LuaVal with nullptr table");
  150.     }
  151.     LuaVal(LuaVal const & val) : tag(val.tag), tbl_ptr(val.tag == TTABLE ? new LuaTable(*val.tbl_ptr.get()) : nullptr), s(val.s), d(val.d), b(val.b)
  152.     {
  153.         if (istable())
  154.         {
  155.             if (!tbl_ptr)
  156.                 throw smallfolk_exception("creating table LuaVal with nullptr table");
  157.         }
  158.     }
  159.     LuaVal(LuaVal && val) : tag(val.tag), tbl_ptr(std::move(val.tbl_ptr)), s(std::move(val.s)), d(val.d), b(val.b)
  160.     {
  161.     }
  162.     LuaVal(std::initializer_list<LuaVal const> l) : tag(TTABLE), tbl_ptr(new LuaTable()), d(0), b(false)
  163.     {
  164.         if (!tbl_ptr)
  165.             throw smallfolk_exception("creating table LuaVal with nullptr table");
  166.         LuaTable & tbl = *tbl_ptr;
  167.         unsigned int i = 0;
  168.         for (auto&& v : l)
  169.             tbl[++i] = v;
  170.     }
  171.  
  172.     bool isstring() const { return tag == TSTRING; }
  173.     bool isnumber() const { return tag == TNUMBER; }
  174.     bool istable() const { return tag == TTABLE; }
  175.     bool isbool() const { return tag == TBOOL; }
  176.     bool isnil() const { return tag == TNIL; }
  177.  
  178.     // create a table (same as LuaVal(TTABLE);)
  179.     static LuaVal table(LuaTable arr = LuaTable())
  180.     {
  181.         return LuaVal(arr);
  182.     }
  183.  
  184.     // gettable
  185.     LuaVal get(LuaVal const & k) const
  186.     {
  187.         if (!istable())
  188.             throw smallfolk_exception("using get on non table object");
  189.         if (k.isnil()) // on nil key do nothing
  190.             return nil();
  191.         LuaTable & tbl = (*tbl_ptr);
  192.         auto it = tbl.find(k);
  193.         if (it != tbl.end())
  194.             return it->second;
  195.         return nil();
  196.     }
  197.  
  198.     // settable, return self
  199.     LuaVal & set(LuaVal const & k, LuaVal const & v)
  200.     {
  201.         if (!istable())
  202.             throw smallfolk_exception("using set on non table object");
  203.         if (k.isnil()) // on nil key do nothing
  204.             return *this;
  205.         LuaTable & tbl = (*tbl_ptr);
  206.         if (v.isnil()) // on nil value erase key
  207.             tbl.erase(k);
  208.         else
  209.             tbl[k] = v; // normally set pair
  210.         return *this;
  211.     }
  212.  
  213.     // erase, return self
  214.     LuaVal & rem(LuaVal const & k)
  215.     {
  216.         if (!istable())
  217.             throw smallfolk_exception("using rem on non table object");
  218.         LuaTable & tbl = (*tbl_ptr);
  219.         tbl.erase(k);
  220.         return *this;
  221.     }
  222.  
  223.     // table array size, not actual element count
  224.     unsigned int len() const
  225.     {
  226.         if (!istable())
  227.             throw smallfolk_exception("using len on non table object");
  228.         LuaTable & tbl = (*tbl_ptr);
  229.         unsigned int i = 0;
  230.         while (++i)
  231.         {
  232.             auto it = tbl.find(i);
  233.             if (it == tbl.end() || it->second.isnil())
  234.                 break;
  235.         }
  236.         return i - 1;
  237.     }
  238.  
  239.     // table.insert, return self
  240.     LuaVal & insert(LuaVal const & v, LuaVal const & pos = nil())
  241.     {
  242.         if (!istable())
  243.             throw smallfolk_exception("using insert on non table object");
  244.         LuaTable & tbl = (*tbl_ptr);
  245.         if (pos.isnil())
  246.         {
  247.             if (!v.isnil())
  248.                 tbl[len() + 1] = v;
  249.             return *this;
  250.         }
  251.         if (!pos.isnumber())
  252.             throw smallfolk_exception("using insert with non number pos");
  253.         if (std::floor(pos.num()) != pos.num())
  254.             throw smallfolk_exception("using insert with invalid number key");
  255.         unsigned int max = len() + 1;
  256.         unsigned int val = static_cast<unsigned int>(pos.num());
  257.         if (val <= 0 || val > max)
  258.             throw smallfolk_exception("using insert with out of bounds key");
  259.         for (unsigned int i = max; i > val; --i)
  260.             tbl[i] = tbl[i - 1];
  261.         if (v.isnil())
  262.             tbl.erase(val);
  263.         else
  264.             tbl[val] = v;
  265.         return *this;
  266.     }
  267.  
  268.     // table.remove, return self
  269.     LuaVal & remove(LuaVal const & pos = nil())
  270.     {
  271.         if (!istable())
  272.             throw smallfolk_exception("using remove on non table object");
  273.         LuaTable & tbl = (*tbl_ptr);
  274.         if (pos.isnil())
  275.         {
  276.             if (unsigned int i = len())
  277.                 tbl.erase(i);
  278.             return *this;
  279.         }
  280.         if (!pos.isnumber())
  281.             throw smallfolk_exception("using remove with non number key");
  282.         if (std::floor(pos.num()) != pos.num())
  283.             throw smallfolk_exception("using remove with invalid number key");
  284.         unsigned int max = len();
  285.         unsigned int val = static_cast<unsigned int>(pos.num());
  286.         if (val <= 0 || val > max + 1)
  287.             throw smallfolk_exception("using remove with out of bounds key");
  288.         for (unsigned int i = val; i < max; ++i)
  289.             tbl[i] = tbl[i + 1];
  290.         tbl.erase(max);
  291.         return *this;
  292.     }
  293.  
  294.     // gettable - note, adds key-nil pair if not existing
  295.     // nil key throws error
  296.     LuaVal operator [](LuaVal const & k) const
  297.     {
  298.         if (!istable())
  299.             throw smallfolk_exception("using [] on non table object");
  300.         if (k.isnil())
  301.             throw smallfolk_exception("using [] with nil key");
  302.         LuaTable & tbl = (*tbl_ptr);
  303.         return tbl[k];
  304.     }
  305.  
  306.     // get-set-table - note, adds key-nil pair if not existing
  307.     // nil key throws error
  308.     LuaVal & operator [](LuaVal const & k)
  309.     {
  310.         if (!istable())
  311.             throw smallfolk_exception("using [] on non table object");
  312.         if (k.isnil())
  313.             throw smallfolk_exception("using [] with nil key");
  314.         LuaTable & tbl = (*tbl_ptr);
  315.         return tbl[k];
  316.     }
  317.  
  318.     // get a number value
  319.     double num() const
  320.     {
  321.         if (!isnumber())
  322.             throw smallfolk_exception("using num on non number object");
  323.         return d;
  324.     }
  325.     // get a boolean value
  326.     bool boolean() const
  327.     {
  328.         if (!isbool())
  329.             throw smallfolk_exception("using boolean on non bool object");
  330.         return b;
  331.     }
  332.     // get a string value
  333.     std::string const & str() const
  334.     {
  335.         if (!isstring())
  336.             throw smallfolk_exception("using str on non string object");
  337.         return s;
  338.     }
  339.     // get a table value
  340.     LuaTable const & tbl() const
  341.     {
  342.         if (!istable())
  343.             throw smallfolk_exception("using tbl on non table object");
  344.         return *tbl_ptr;
  345.     }
  346.     LuaTypeTag GetTypeTag() const
  347.     {
  348.         return tag;
  349.     }
  350.  
  351.     // serializes the value into string
  352.     // errmsg is optional value to output error message to on failure
  353.     // returns empty string on error
  354.     std::string dumps(std::string* errmsg = nullptr) const
  355.     {
  356.         try
  357.         {
  358.             ACC acc;
  359.             acc << std::setprecision(17); // min lua percision
  360.             unsigned int nmemo = 0;
  361.             MEMO memo;
  362.             dump_object(*this, nmemo, memo, acc);
  363.             return acc.str();
  364.         }
  365.         catch (std::exception& e)
  366.         {
  367.             if (errmsg)
  368.             {
  369.                 *errmsg += "Smallfolk_cpp error: ";
  370.                 *errmsg += e.what();
  371.             }
  372.         }
  373.         catch (...)
  374.         {
  375.             if (errmsg)
  376.                 *errmsg += "Smallfolk_cpp error";
  377.         }
  378.         return std::string();
  379.     }
  380.  
  381.     // deserialize a string into a LuaVal
  382.     // string param is deserialized string
  383.     // errmsg is optional value to output error message to on failure
  384.     static LuaVal loads(std::string const & string, std::string* errmsg = nullptr)
  385.     {
  386.         try
  387.         {
  388.             TABLES tables;
  389.             size_t i = 0;
  390.             return std::move(expect_object(string, i, tables));
  391.         }
  392.         catch (std::exception& e)
  393.         {
  394.             if (errmsg)
  395.             {
  396.                 *errmsg += "Smallfolk_cpp error: ";
  397.                 *errmsg += e.what();
  398.             }
  399.         }
  400.         catch (...)
  401.         {
  402.             if (errmsg)
  403.                 *errmsg += "Smallfolk_cpp error";
  404.         }
  405.         return nil();
  406.     }
  407.  
  408.     bool operator==(LuaVal const& rhs) const
  409.     {
  410.         if (tag != rhs.tag)
  411.             return false;
  412.         switch (tag)
  413.         {
  414.         case TBOOL:
  415.             return b == rhs.b;
  416.         case TNIL:
  417.             return true;
  418.         case TSTRING:
  419.             return s == rhs.s;
  420.         case TNUMBER:
  421.             return d == rhs.d;
  422.         case TTABLE:
  423.             return tbl_ptr == rhs.tbl_ptr;
  424.         default:
  425.             throw smallfolk_exception("operator== invalid or unhandled tag %i", tag);
  426.         }
  427.         return false;
  428.     }
  429.  
  430.     bool operator!=(LuaVal const& rhs) const
  431.     {
  432.         return !(*this == rhs);
  433.     }
  434.  
  435.     // You can use !val to check for nil or false
  436.     explicit operator bool()
  437.     {
  438.         return !isnil() && (!isbool() || boolean());
  439.     }
  440.  
  441.     LuaVal& operator=(LuaVal const& val)
  442.     {
  443.         tag = val.tag;
  444.         if (istable())
  445.         {
  446.             tbl_ptr = (std::make_unique<LuaTable>());
  447.             *tbl_ptr = *val.tbl_ptr.get();
  448.         }
  449.         else
  450.             tbl_ptr = nullptr;
  451.         s = val.s;
  452.         d = val.d;
  453.         b = val.b;
  454.  
  455.         if (istable())
  456.         {
  457.             if (!tbl_ptr)
  458.                 throw smallfolk_exception("creating table LuaVal with nullptr table");
  459.         }
  460.         return *this;
  461.     }
  462.  
  463. private:
  464.     typedef std::vector<LuaVal> TABLES;
  465.     typedef std::unordered_map<LuaVal, unsigned int, LuaValHasher> MEMO;
  466.     typedef std::stringstream ACC;
  467.  
  468.     LuaTypeTag tag;
  469.  
  470.     TblPtr tbl_ptr;
  471.     std::string s;
  472.     // int64_t i; // lua 5.3 support?
  473.     double d;
  474.     bool b;
  475.  
  476.     // sprintf is ~50% faster than other solutions
  477.     static std::string tostring(const double d)
  478.     {
  479.         char arr[128];
  480.         sprintf_s(arr, "%.17g", d);
  481.         return arr;
  482.     }
  483.     static std::string tostring(TblPtr const & ptr)
  484.     {
  485.         char arr[128];
  486.         sprintf_s(arr, "table: %p", static_cast<const void*>(ptr.get()));
  487.         return arr;
  488.     }
  489.  
  490.     static size_t dump_type_table(LuaVal const & object, unsigned int nmemo, MEMO& memo, ACC& acc)
  491.     {
  492.         if (!object.istable())
  493.             throw smallfolk_exception("using dump_type_table on non table object");
  494.  
  495.         /*
  496.         auto it = memo.find(object);
  497.         if (it != memo.end())
  498.         {
  499.         acc << '@' << it->second;
  500.         return nmemo;
  501.         }
  502.         memo[object] = ++nmemo;
  503.         */
  504.         acc << '{';
  505.         std::map<unsigned int, const LuaVal*> arr;
  506.         std::unordered_map<const LuaVal*, const LuaVal*> hash;
  507.         for (auto&& v : *object.tbl_ptr)
  508.         {
  509.             if (v.first.isnumber() && v.first.num() >= 1 && std::floor(v.first.num()) == v.first.num())
  510.                 arr[static_cast<unsigned int>(v.first.num())] = &v.second;
  511.             else
  512.                 hash[&v.first] = &v.second;
  513.         }
  514.         unsigned int i = 1;
  515.         for (auto&& v : arr)
  516.         {
  517.             if (v.first != i)
  518.             {
  519.                 nmemo = dump_object(v.first, nmemo, memo, acc);
  520.                 acc << ':';
  521.             }
  522.             else
  523.                 ++i;
  524.             nmemo = dump_object(*v.second, nmemo, memo, acc);
  525.             acc << ',';
  526.         }
  527.         for (auto&& v : hash)
  528.         {
  529.             nmemo = dump_object(*v.first, nmemo, memo, acc);
  530.             acc << ':';
  531.             nmemo = dump_object(*v.second, nmemo, memo, acc);
  532.             acc << ',';
  533.         }
  534.         std::string l = acc.str();
  535.         char c = strat(l, l.length() - 1);
  536.         if (c != '{')
  537.         {
  538.             // remove last char
  539.             l.pop_back();
  540.             acc.clear();
  541.             acc.str(std::string());
  542.             acc << l;
  543.         }
  544.         acc << '}';
  545.         return std::move(nmemo);
  546.     }
  547.  
  548.     static size_t dump_object(LuaVal const & object, unsigned int nmemo, MEMO& memo, ACC& acc)
  549.     {
  550.         switch (object.tag)
  551.         {
  552.         case TBOOL:
  553.             acc << (object.b ? 't' : 'f');
  554.             break;
  555.         case TNIL:
  556.             acc << 'n';
  557.             break;
  558.         case TSTRING:
  559.             acc << '"';
  560.             acc << escape_quotes(object.s); // change to std::quote() in c++14?
  561.             acc << '"';
  562.             break;
  563.         case TNUMBER:
  564.             if (!isfinite(object.d))
  565.             {
  566.                 // slightly ugly :(
  567.                 std::string nn = tostring(object.d);
  568.                 if (nn == "1.#INF")
  569.                     acc << 'I';
  570.                 else if (nn == "-1.#INF")
  571.                     acc << 'i';
  572.                 else if (nn == "1.#IND")
  573.                     acc << 'i';
  574.                 else if (nn == "-1.#IND")
  575.                     acc << 'N';
  576.                 else
  577.                     acc << 'Q';
  578.             }
  579.             else
  580.                 acc << object.d;
  581.             break;
  582.         case TTABLE:
  583.             return dump_type_table(object, nmemo, memo, acc);
  584.             break;
  585.         default:
  586.             throw smallfolk_exception("dump_object invalid or unhandled tag %i", object.tag);
  587.             break;
  588.         }
  589.         return std::move(nmemo);
  590.     }
  591.  
  592.     static std::string escape_quotes(const std::string &before)
  593.     {
  594.         std::string after;
  595.         after.reserve(before.length() + 4);
  596.  
  597.         for (std::string::size_type i = 0; i < before.length(); ++i)
  598.         {
  599.             switch (before[i])
  600.             {
  601.             case '"':
  602.                 after += '"'; // no break
  603.             default:
  604.                 after += before[i];
  605.             }
  606.         }
  607.  
  608.         return std::move(after);
  609.     }
  610.  
  611.     static std::string unescape_quotes(const std::string &before)
  612.     {
  613.         std::string after;
  614.         after.reserve(before.length());
  615.  
  616.         for (std::string::size_type i = 0; i < before.length(); ++i)
  617.         {
  618.             switch (before[i])
  619.             {
  620.             case '"':
  621.                 if (i + 1 < before.length() && before[i + 1] == '"')
  622.                     ++i;
  623.             default:
  624.                 after += before[i];
  625.             }
  626.         }
  627.  
  628.         return std::move(after);
  629.     }
  630.  
  631.     static bool nonzero_digit(char c)
  632.     {
  633.         switch (c)
  634.         {
  635.         case '1':
  636.         case '2':
  637.         case '3':
  638.         case '4':
  639.         case '5':
  640.         case '6':
  641.         case '7':
  642.         case '8':
  643.         case '9':
  644.             return true;
  645.         }
  646.         return false;
  647.     }
  648.  
  649.     static bool is_digit(char c)
  650.     {
  651.         switch (c)
  652.         {
  653.         case '0':
  654.         case '1':
  655.         case '2':
  656.         case '3':
  657.         case '4':
  658.         case '5':
  659.         case '6':
  660.         case '7':
  661.         case '8':
  662.         case '9':
  663.             return true;
  664.         }
  665.         return false;
  666.     }
  667.  
  668.     static char strat(std::string const & string, std::string::size_type i)
  669.     {
  670.         if (i != std::string::npos &&
  671.             i < string.length() &&
  672.             i >= 0)
  673.             return string.at(i);
  674.         return '\0'; // bad?
  675.     }
  676.  
  677.     static LuaVal expect_number(std::string const & string, size_t& start)
  678.     {
  679.         size_t i = start;
  680.         char head = strat(string, i);
  681.         if (head == '-')
  682.             head = strat(string, ++i);
  683.         if (nonzero_digit(head))
  684.         {
  685.             do
  686.             {
  687.                 head = strat(string, ++i);
  688.             } while (is_digit(head));
  689.         }
  690.         else if (head == '0')
  691.             head = strat(string, ++i);
  692.         else
  693.             throw smallfolk_exception("expect_number at %u unexpected character %c", i, head);
  694.         if (head == '.')
  695.         {
  696.             size_t oldi = i;
  697.             do
  698.             {
  699.                 head = strat(string, ++i);
  700.             } while (is_digit(head));
  701.             if (i == oldi + 1)
  702.                 throw smallfolk_exception("expect_number at %u no numbers after decimal", i);
  703.         }
  704.         if (head == 'e' || head == 'E')
  705.         {
  706.             head = strat(string, ++i);
  707.             if (head == '+' || head == '-')
  708.                 head = strat(string, ++i);
  709.             if (!is_digit(head))
  710.                 throw smallfolk_exception("expect_number at %u not a digit part %c", i, head);
  711.             do
  712.             {
  713.                 head = strat(string, ++i);
  714.             } while (is_digit(head));
  715.         }
  716.         size_t temp = start;
  717.         start = i;
  718.         return std::atof(string.substr(temp, i).c_str());
  719.     }
  720.  
  721.     static LuaVal expect_object(std::string const & string, size_t& i, TABLES& tables)
  722.     {
  723.         static double _zero = 0.0;
  724.  
  725.         char cc = strat(string, i++);
  726.         switch (cc)
  727.         {
  728.         case 't':
  729.             return true;
  730.         case 'f':
  731.             return false;
  732.         case 'n':
  733.             return nil();
  734.         case 'Q':
  735.             return -(0 / _zero);
  736.         case 'N':
  737.             return (0 / _zero);
  738.         case 'I':
  739.             return (1 / _zero);
  740.         case 'i':
  741.             return -(1 / _zero);
  742.         case '"':
  743.         {
  744.             size_t nexti = i - 1;
  745.             do
  746.             {
  747.                 nexti = string.find('"', nexti + 1);
  748.                 if (nexti == std::string::npos)
  749.                 {
  750.                     throw smallfolk_exception("expect_object at %u was %c eof before string ends", i, cc);
  751.                 }
  752.                 ++nexti;
  753.             } while (strat(string, nexti) == '"');
  754.             size_t temp = i;
  755.             i = nexti;
  756.             return unescape_quotes(string.substr(temp, nexti - temp - 1));
  757.         }
  758.         case '0':
  759.         case '1':
  760.         case '2':
  761.         case '3':
  762.         case '4':
  763.         case '5':
  764.         case '6':
  765.         case '7':
  766.         case '8':
  767.         case '9':
  768.         case '-':
  769.         case '.':
  770.             return expect_number(string, --i);
  771.         case '{':
  772.         {
  773.             LuaVal nt(TTABLE);
  774.             unsigned int j = 1;
  775.             tables.push_back(nt);
  776.             if (strat(string, i) == '}')
  777.             {
  778.                 ++i;
  779.                 return std::move(nt);
  780.             }
  781.             while (true)
  782.             {
  783.                 LuaVal k = expect_object(string, i, tables);
  784.                 if (strat(string, i) == ':')
  785.                 {
  786.                     nt.set(k, expect_object(string, ++i, tables));
  787.                 }
  788.                 else
  789.                 {
  790.                     nt.set(j, k);
  791.                     ++j;
  792.                 }
  793.                 char head = strat(string, i);
  794.                 if (head == ',')
  795.                     ++i;
  796.                 else if (head == '}')
  797.                 {
  798.                     ++i;
  799.                     return std::move(nt);
  800.                 }
  801.                 else
  802.                 {
  803.                     throw smallfolk_exception("expect_object at %u was %c unexpected character %c", i, cc, head);
  804.                 }
  805.             }
  806.             break;
  807.         }
  808.         /*
  809.         case '@':
  810.         {
  811.         std::string::size_type x = i;
  812.         for (; x < string.length(); ++x)
  813.         {
  814.         if (!isdigit(string[x]))
  815.         break;
  816.         }
  817.         std::string substr = string.substr(i, x - i);
  818.         size_t index = std::stoul(substr.c_str());
  819.         if (index >= 1 && index <= tables.size())
  820.         {
  821.         i += substr.length();
  822.         return tables[index - 1];
  823.         }
  824.  
  825.         throw smallfolk_exception("expect_object at %u was %c invalid index %u", i, cc, index);
  826.         break;
  827.         }
  828.         */
  829.         default:
  830.         {
  831.             throw smallfolk_exception("expect_object at %u was %c", i, cc);
  832.             break;
  833.         }
  834.         }
  835.         return nil();
  836.     }
  837. };
  838.  
  839. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement