FastLED 3.10.6
Loading...
Searching...
No Matches

◆ on_token()

ParseState fl::anonymous_namespace{json.cpp.hpp}::JsonBuilder::on_token ( JsonToken token,
const fl::span< const char > & value )
inlineoverridevirtual

Implements fl::anonymous_namespace{json.cpp.hpp}::JsonVisitor.

Definition at line 931 of file json.cpp.hpp.

931 {
932 // Recursion depth check
933 if (mDepth > MAX_JSON_DEPTH) {
934 FL_ERROR("JSON parser: FATAL - recursion depth exceeded %s", MAX_JSON_DEPTH);
935 return ParseState::ERROR;
936 }
937
938 switch (token) {
939 // Specialized array tokens - parse directly into typed vectors.
940 // Gated on Low-memory per #3224 Tier 2D: these packed-array tokens
941 // only fire when the tokenizer's `scan_array_lookahead` decides an
942 // array is uniformly-typed and small. LowMemory targets don't use
943 // the array-packing optimization (the integer-only RPC contract on
944 // LPC8xx never sends packed vectors), so dropping these cases
945 // collapses 3 large make_shared<json_value>(vector<T>) variant
946 // emplace instantiations + parse_int_array + parse_float_array.
947#if FL_PLATFORM_HAS_LARGE_MEMORY
949 fl::vector<u8> vec;
950 if (!parse_int_array(value, vec)) return ParseState::ERROR;
951 auto arr_val = fl::make_shared<json_value>(fl::move(vec));
952 push_value(arr_val);
954 }
955
957 fl::vector<i16> vec;
958 if (!parse_int_array(value, vec)) return ParseState::ERROR;
959 auto arr_val = fl::make_shared<json_value>(fl::move(vec));
960 push_value(arr_val);
962 }
963
965 fl::vector<float> vec;
966 if (!parse_float_array(value, vec)) return ParseState::ERROR;
967 auto arr_val = fl::make_shared<json_value>(fl::move(vec));
968 push_value(arr_val);
970 }
971#endif
972
973 case JsonToken::LBRACE: {
975 // Don't push to parent yet - will push in RBRACE
976 mStack.push_back({StackFrame::OBJECT, obj_val, ""});
977 mDepth++;
979 }
980
981 case JsonToken::RBRACE: {
982 if (!mStack.empty() && mStack.back().type == StackFrame::OBJECT) {
983 auto obj_val = mStack.back().value;
984 mStack.pop_back();
985 mDepth--;
986 // Push to parent after object is complete
987 push_value(obj_val);
988 }
990 }
991
992 case JsonToken::LBRACKET: {
993 auto arr_val = fl::make_shared<json_value>(json_array{});
994 // Don't push to parent yet - will push in RBRACKET after optimization
995 mStack.push_back({StackFrame::ARRAY, arr_val, ""});
996 mDepth++;
998 }
999
1000 case JsonToken::RBRACKET: {
1001 if (!mStack.empty() && mStack.back().type == StackFrame::ARRAY) {
1002 // Optimize array before pushing to parent (Milestone 9)
1003 auto arr_val = optimize_array(mStack.back().value);
1004 mStack.pop_back();
1005 mDepth--;
1006 // Push optimized array to parent
1007 push_value(arr_val);
1008 }
1010 }
1011
1012 case JsonToken::STRING: {
1013 // Check if this is an object key (next token should be COLON)
1014 if (!mStack.empty() && mStack.back().type == StackFrame::OBJECT &&
1015 mStack.back().pending_key.empty()) {
1016 // Key: handle escape sequences, then intern (StringInterner handles SSO internally)
1018 mStack.back().pending_key = mInterner.intern(unescape_string(value));
1019 } else {
1020 mStack.back().pending_key = mInterner.intern(value);
1021 }
1022 } else {
1023 // Value: handle escape sequences, then intern (StringInterner handles SSO internally)
1024 fl::string str;
1026 str = mInterner.intern(unescape_string(value));
1027 } else {
1028 str = mInterner.intern(value);
1029 }
1030 auto str_val = fl::make_shared<json_value>(str);
1031 push_value(str_val);
1032 }
1033
1035 }
1036
1037 case JsonToken::NUMBER: {
1038 // Determine if int or float by checking for decimal/exponent
1039 bool is_float = false;
1040 for (size_t i = 0; i < value.size(); i++) {
1041 if (value[i] == '.' || value[i] == 'e' || value[i] == 'E') {
1042 is_float = true;
1043 break;
1044 }
1045 }
1046
1047 fl::shared_ptr<json_value> num_val;
1048#if FL_PLATFORM_HAS_LARGE_MEMORY
1049 if (is_float) {
1050 // Bit-twiddling parse -> IEEE 754 bits -> store as float in the
1051 // variant. The `bit_cast<float>` is a `memcpy` -- no libgcc
1052 // soft-FP helper is reached on the parser hot path
1053 // (FastLED #3022 phase 2).
1054 const u32 bits = fl::ieee754_parse_decimal(value.data(), value.size());
1056 } else {
1057 int i = fl::parseInt(value.data(), value.size());
1058 i64 i64_val = static_cast<i64>(i);
1059 num_val = fl::make_shared<json_value>(i64_val);
1060 }
1061#else
1062 // Low-memory gate per FastLED #3224 Tier 2D: drop the float
1063 // store entirely. JSON float literals on LowMemory parse to
1064 // i64(0), avoiding the variant `float` emplace instantiation
1065 // that #3082's `0.0f` store used to anchor. Combined with
1066 // the ARRAY_FLOAT case gate above, LowMemory's JsonBuilder
1067 // never instantiates a `make_shared<json_value>(float)` or
1068 // `make_shared<json_value>(vector<float>)` path.
1069 (void)is_float;
1070 int i = fl::parseInt(value.data(), value.size());
1071 i64 i64_val = static_cast<i64>(i);
1072 num_val = fl::make_shared<json_value>(i64_val);
1073#endif
1074
1075 push_value(num_val);
1077 }
1078
1079 case JsonToken::TRUE:
1082
1083 case JsonToken::FALSE:
1086
1090
1091 case JsonToken::COLON:
1092 case JsonToken::COMMA:
1093 // Structural tokens - no action needed
1095
1098
1099 default:
1100 return ParseState::ERROR;
1101 }
1102 }
void push_value(const fl::shared_ptr< json_value > &val)
Definition json.cpp.hpp:905
bool parse_float_array(const fl::span< const char > &span, fl::vector< T > &out_vec)
Definition json.cpp.hpp:846
fl::vector_inlined< StackFrame, 8 > mStack
Definition json.cpp.hpp:809
bool parse_int_array(const fl::span< const char > &span, fl::vector< T > &out_vec)
Definition json.cpp.hpp:817
#define FL_ERROR(...)
Definition log.h:372
fl::string unescape_string(const fl::span< const char > &span)
Definition json.cpp.hpp:643
bool has_escape_sequences(const fl::span< const char > &span)
Definition json.cpp.hpp:633
fl::shared_ptr< json_value > optimize_array(fl::shared_ptr< json_value > array_val)
Definition json.cpp.hpp:745
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:28
constexpr int type_rank< T >::value
u32 ieee754_parse_decimal(const char *s, fl::size len, fl::size *consumed) FL_NO_EXCEPT
Parse a decimal floating-point number into IEEE 754 single-precision bits.
int parseInt(const char *str, fl::size len)
Parse an integer from a character buffer.
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:414
fl::vector< fl::shared_ptr< json_value > > json_array
Definition types.h:54
To bit_cast(const From &from) FL_NO_EXCEPT
Definition bit_cast.h:48
fl::flat_map< fl::string, fl::shared_ptr< json_value >, fl::StringFastLess > json_object
Definition types.h:55
fl::i64 i64
Definition stdint.h:221

References fl::anonymous_namespace{json.cpp.hpp}::JsonBuilder::StackFrame::ARRAY, fl::anonymous_namespace{json.cpp.hpp}::ARRAY_FLOAT, fl::anonymous_namespace{json.cpp.hpp}::ARRAY_INT16, fl::anonymous_namespace{json.cpp.hpp}::ARRAY_UINT8, fl::bit_cast(), fl::anonymous_namespace{json.cpp.hpp}::COLON, fl::anonymous_namespace{json.cpp.hpp}::COMMA, fl::anonymous_namespace{json.cpp.hpp}::END_OF_INPUT, fl::anonymous_namespace{json.cpp.hpp}::ERROR, fl::anonymous_namespace{json.cpp.hpp}::FALSE, FL_ERROR, fl::anonymous_namespace{json.cpp.hpp}::has_escape_sequences(), fl::ieee754_parse_decimal(), fl::anonymous_namespace{json.cpp.hpp}::KEEP_GOING, fl::anonymous_namespace{json.cpp.hpp}::LBRACE, fl::anonymous_namespace{json.cpp.hpp}::LBRACKET, fl::make_shared(), fl::anonymous_namespace{json.cpp.hpp}::MAX_JSON_DEPTH, mDepth, mInterner, fl::move(), mStack, fl::anonymous_namespace{json.cpp.hpp}::NULL_VALUE, fl::anonymous_namespace{json.cpp.hpp}::NUMBER, fl::anonymous_namespace{json.cpp.hpp}::JsonBuilder::StackFrame::OBJECT, fl::anonymous_namespace{json.cpp.hpp}::optimize_array(), parse_float_array(), parse_int_array(), fl::parseInt(), push_value(), fl::anonymous_namespace{json.cpp.hpp}::RBRACE, fl::anonymous_namespace{json.cpp.hpp}::RBRACKET, fl::anonymous_namespace{json.cpp.hpp}::STRING, fl::anonymous_namespace{json.cpp.hpp}::TRUE, fl::type_rank< T >::value, and fl::anonymous_namespace{json.cpp.hpp}::unescape_string().

+ Here is the call graph for this function: