mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-22 18:26:30 +00:00
Berry change number parser for json to reuse same parser as lexer (#23505)
This commit is contained in:
parent
de0d88514a
commit
d94d7c8972
@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- ESP32 Platform from 2025.05.40 to 2025.05.30, Framework (Arduino Core) from v3.2.0.250504 to v3.1.3.250504 and IDF from v5.4.1.250501 to v5.3.3.250501 (#23404)
|
- ESP32 Platform from 2025.05.40 to 2025.05.30, Framework (Arduino Core) from v3.2.0.250504 to v3.1.3.250504 and IDF from v5.4.1.250501 to v5.3.3.250501 (#23404)
|
||||||
- ESP8266 platform update from 2024.09.00 to 2025.05.00 (#23448)
|
- ESP8266 platform update from 2024.09.00 to 2025.05.00 (#23448)
|
||||||
- Increase number of supported LoRaWan nodes from 4 to 16
|
- Increase number of supported LoRaWan nodes from 4 to 16
|
||||||
|
- Berry change number parser for json to reuse same parser as lexer
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Haspmota `haspmota.parse()` page parsing (#23403)
|
- Haspmota `haspmota.parse()` page parsing (#23403)
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
#if BE_USE_JSON_MODULE
|
#if BE_USE_JSON_MODULE
|
||||||
|
|
||||||
|
#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
|
||||||
|
#define is_digit(c) ((c) >= '0' && (c) <= '9')
|
||||||
|
|
||||||
#define MAX_INDENT 24
|
#define MAX_INDENT 24
|
||||||
#define INDENT_WIDTH 2
|
#define INDENT_WIDTH 2
|
||||||
#define INDENT_CHAR ' '
|
#define INDENT_CHAR ' '
|
||||||
@ -30,11 +33,6 @@ static const char* skip_space(const char *s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_digit(int c)
|
|
||||||
{
|
|
||||||
return c >= '0' && c <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* match_char(const char *json, int ch)
|
static const char* match_char(const char *json, int ch)
|
||||||
{
|
{
|
||||||
json = skip_space(json);
|
json = skip_space(json);
|
||||||
@ -249,90 +247,114 @@ static const char* parser_array(bvm *vm, const char *json)
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
JSON_NUMBER_INVALID = 0,
|
||||||
|
JSON_NUMBER_INTEGER = 1,
|
||||||
|
JSON_NUMBER_REAL = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
int check_json_number(const char *json) {
|
||||||
|
if (!json || *json == '\0') {
|
||||||
|
return JSON_NUMBER_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *p = json;
|
||||||
|
bbool has_fraction = bfalse;
|
||||||
|
bbool has_exponent = bfalse;
|
||||||
|
|
||||||
|
// Skip leading whitespace
|
||||||
|
while (is_space(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p == '\0') {
|
||||||
|
return JSON_NUMBER_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle optional minus sign
|
||||||
|
if (*p == '-') {
|
||||||
|
p++;
|
||||||
|
if (*p == '\0') {
|
||||||
|
return JSON_NUMBER_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer part
|
||||||
|
if (*p == '0') {
|
||||||
|
// If starts with 0, next char must not be a digit (unless it's decimal point or exponent)
|
||||||
|
p++;
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
return JSON_NUMBER_INVALID; // Leading zeros not allowed (except standalone 0)
|
||||||
|
}
|
||||||
|
} else if (is_digit(*p)) {
|
||||||
|
// First digit must be 1-9, then any digits
|
||||||
|
p++;
|
||||||
|
while (is_digit(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return JSON_NUMBER_INVALID; // Must start with digit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional fractional part
|
||||||
|
if (*p == '.') {
|
||||||
|
has_fraction = btrue;
|
||||||
|
p++;
|
||||||
|
if (!is_digit(*p)) {
|
||||||
|
return JSON_NUMBER_INVALID; // Must have at least one digit after decimal point
|
||||||
|
}
|
||||||
|
while (is_digit(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional exponent part
|
||||||
|
if (*p == 'e' || *p == 'E') {
|
||||||
|
has_exponent = btrue;
|
||||||
|
p++;
|
||||||
|
// Optional sign in exponent
|
||||||
|
if (*p == '+' || *p == '-') {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (!is_digit(*p)) {
|
||||||
|
return JSON_NUMBER_INVALID; // Must have at least one digit in exponent
|
||||||
|
}
|
||||||
|
while (is_digit(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number ends here - check that next char is not a continuation
|
||||||
|
// Valid JSON number termination: whitespace, null, or JSON delimiters
|
||||||
|
if (*p != '\0' && !is_space(*p) && *p != ',' && *p != ']' && *p != '}' && *p != ':') {
|
||||||
|
return JSON_NUMBER_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine return value based on what was found
|
||||||
|
// Any number with exponent (e/E) is always real, regardless of fractional part
|
||||||
|
if (has_exponent || has_fraction) {
|
||||||
|
return JSON_NUMBER_REAL; // real number
|
||||||
|
} else {
|
||||||
|
return JSON_NUMBER_INTEGER; // integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char* parser_number(bvm *vm, const char *json)
|
static const char* parser_number(bvm *vm, const char *json)
|
||||||
{
|
{
|
||||||
char c = *json++;
|
const char *endstr = NULL;
|
||||||
bbool is_neg = c == '-';
|
int number_type = check_json_number(json);
|
||||||
if(is_neg) {
|
|
||||||
c = *json++;
|
switch (number_type) {
|
||||||
if(!is_digit(c)) {
|
case JSON_NUMBER_INTEGER:
|
||||||
/* minus must be followed by digit */
|
be_pushint(vm, be_str2int(json, &endstr));
|
||||||
return NULL;
|
break;
|
||||||
}
|
case JSON_NUMBER_REAL:
|
||||||
|
be_pushreal(vm, be_str2real(json, &endstr));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
endstr = NULL;
|
||||||
}
|
}
|
||||||
bint intv = 0;
|
return endstr;
|
||||||
if(c != '0') {
|
|
||||||
/* parse integer part */
|
|
||||||
while(is_digit(c)) {
|
|
||||||
intv = intv * 10 + c - '0';
|
|
||||||
c = *json++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
Number starts with zero, this is only allowed
|
|
||||||
if the number is just '0' or
|
|
||||||
it has a fractional part or exponent.
|
|
||||||
*/
|
|
||||||
c = *json++;
|
|
||||||
|
|
||||||
}
|
|
||||||
if(c != '.' && c != 'e' && c != 'E') {
|
|
||||||
/*
|
|
||||||
No fractional part or exponent follows, this is an integer.
|
|
||||||
If digits follow after it (for example due to a leading zero)
|
|
||||||
this will cause an error in the calling function.
|
|
||||||
*/
|
|
||||||
be_pushint(vm, intv * (is_neg ? -1 : 1));
|
|
||||||
json--;
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
breal realval = (breal) intv;
|
|
||||||
if(c == '.') {
|
|
||||||
|
|
||||||
breal deci = 0.0, point = 0.1;
|
|
||||||
/* fractional part */
|
|
||||||
c = *json++;
|
|
||||||
if(!is_digit(c)) {
|
|
||||||
/* decimal point must be followed by digit */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
while (is_digit(c)) {
|
|
||||||
deci = deci + ((breal)c - '0') * point;
|
|
||||||
point *= (breal)0.1;
|
|
||||||
c = *json++;
|
|
||||||
}
|
|
||||||
|
|
||||||
realval += deci;
|
|
||||||
}
|
|
||||||
if(c == 'e' || c == 'E') {
|
|
||||||
c = *json++;
|
|
||||||
/* exponent part */
|
|
||||||
breal ratio = c == '-' ? (breal)0.1 : 10;
|
|
||||||
if (c == '+' || c == '-') {
|
|
||||||
c = *json++;
|
|
||||||
if(!is_digit(c)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!is_digit(c)) {
|
|
||||||
/* e and sign must be followed by digit */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
unsigned int e = 0;
|
|
||||||
while (is_digit(c)) {
|
|
||||||
e = e * 10 + c - '0';
|
|
||||||
c = *json++;
|
|
||||||
}
|
|
||||||
/* e > 0 must be here to prevent infinite loops when e overflows */
|
|
||||||
while (e--) {
|
|
||||||
realval *= ratio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
be_pushreal(vm, realval * (is_neg ? -1.0 : 1.0));
|
|
||||||
json--;
|
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parser json value */
|
/* parser json value */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user