/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2017 Danny Robson */ #include "./jsonish.hpp" #include "./base.hpp" #include "../event.hpp" #include "../except.hpp" #include "../../debug.hpp" using util::json2::personality::jsonish; /////////////////////////////////////////////////////////////////////////////// const char* jsonish::consume_whitespace (const char *first, const char *last) noexcept { auto cursor = base::consume_whitespace (first, last); // consume a comment if (cursor != last && *cursor == '#') { while (cursor != last && *cursor != '\n') ++cursor; return consume_whitespace (cursor, last); } return cursor; } /////////////////////////////////////////////////////////////////////////////// // format is: // int: '0x' hex+ | '0' oct+ | '0b' bit+ // // float: significand exp? // significand: digit+ ('.' digit*)? // exp: [eE] sign? digit+ // // number: [+-] (int | float) const char* jsonish::parse_number (const std::function &cb, const char *first, const char *last) { auto cursor = first; if (cursor != last && (*cursor == '+' || *cursor == '-')) ++cursor; if (cursor != last && *cursor == '0') { ++cursor; if (cursor == last) throw parse_error {cursor}; char max = '9'; switch (*cursor) { case 'x': { // parse the hex integer here because we can simplify the // remaining cases somewhat if we don't need to care about the // multiple ranges of valid digits. ++cursor; auto digit_start = cursor; while (cursor != last && ((('0' <= *cursor) && (*cursor <= '9')) || (('a' <= *cursor) && (*cursor <= 'f')) || (('A' <= *cursor) && (*cursor <= 'F')))) ++cursor; if (digit_start == cursor) throw parse_error {cursor}; cb ({first, cursor}); return cursor; }; case 'b': max = '1'; break; case '0'...'7': max = '7'; break; case '.': goto frac; } auto digit_start = ++cursor; while (cursor != last && '0' <= *cursor && *cursor <= max) ++cursor; if (digit_start == cursor) throw parse_error {cursor}; cb ({first, cursor}); return cursor; } while (cursor != last && '0' <= *cursor && *cursor <= '9') ++cursor; if (cursor == last) goto done; if (*cursor != '.') goto exp; frac: ++cursor; while (cursor != last && *cursor >= '0' && *cursor <= '9') ++cursor; if (cursor == last) goto done; exp: if (cursor != last && (*cursor == 'e' || *cursor == 'E')) { ++cursor; if (cursor != last && (*cursor == '+' || *cursor == '-')) ++cursor; auto digit_start = cursor; while (cursor != last && '0' <= *cursor && *cursor <= '9') ++cursor; if (digit_start == cursor) throw parse_error {cursor}; } if (first == cursor) throw parse_error {cursor}; done: cb ({first, cursor}); return cursor; } /////////////////////////////////////////////////////////////////////////////// const char* jsonish::parse_key (const std::function &cb, const char *first, const char *last) { auto cursor = first; if (cursor == last) throw parse_error {cursor}; // must start with alpha or underscore switch (*cursor) { case 'a'...'z': case 'A'...'Z': case '_': ++cursor; break; default: throw parse_error {cursor}; } while (cursor != last) { switch (*cursor) { case 'a'...'z': case 'A'...'Z': case '_': case '0'...'9': ++cursor; break; default: cb ({first, cursor}); return cursor; } } cb ({first, cursor}); return cursor; } /////////////////////////////////////////////////////////////////////////////// const char* jsonish::parse_string (const std::function &cb, const char *first, const char *last) { if (first == last) throw parse_error {first}; if (*first == '"') return base::parse_string (cb, first, last); else return parse_key (cb, first, last); }