diff --git a/src/Neon/Node/LiteralNode.php b/src/Neon/Node/LiteralNode.php index 2dd5990..4029526 100644 --- a/src/Neon/Node/LiteralNode.php +++ b/src/Neon/Node/LiteralNode.php @@ -46,16 +46,16 @@ public static function parse(string $value, bool $isKey = false): mixed return self::SimpleTypes[$value]; } elseif (is_numeric($value)) { - return $value * 1; + return is_int($num = $value * 1) || preg_match('#[.eE]#', $value) ? $num : $value; } elseif (preg_match(self::PatternHex, $value)) { - return hexdec($value); + return self::baseConvert(substr($value, 2), 16); } elseif (preg_match(self::PatternOctal, $value)) { - return octdec($value); + return self::baseConvert(substr($value, 2), 8); } elseif (preg_match(self::PatternBinary, $value)) { - return bindec($value); + return self::baseConvert(substr($value, 2), 2); } elseif (!$isKey && preg_match(self::PatternDatetime, $value)) { return new \DateTimeImmutable($value); @@ -66,6 +66,32 @@ public static function parse(string $value, bool $isKey = false): mixed } + public static function baseConvert(string $number, int $base): string|int + { + if (!extension_loaded('bcmath')) { + $res = base_convert($number, $base, 10); + if (is_float($res)) { + throw new Exception("The number '$number' is too large, enable 'bcmath' extension to handle it."); + } + return $res; + } + + $res = '0'; + for ($i = 0; $i < strlen($number); $i++) { + $char = $number[$i]; + $char = match (true) { + $char >= 'a' => ord($char) - 87, + $char >= 'A' => ord($char) - 55, + default => $char, + }; + $res = bcmul($res, (string) $base, 0); + $res = bcadd($res, (string) $char, 0); + } + + return is_int($num = $res * 1) ? $num : $res; + } + + public function toString(): string { if ($this->value instanceof \DateTimeInterface) { @@ -82,6 +108,7 @@ public function toString(): string return str_contains($res, '.') ? $res : $res . '.0'; } elseif (is_int($this->value) || is_bool($this->value) || $this->value === null) { + return json_encode($this->value); } else { diff --git a/tests/Neon/Decoder.phpt b/tests/Neon/Decoder.phpt index 8646904..c386a6c 100644 --- a/tests/Neon/Decoder.phpt +++ b/tests/Neon/Decoder.phpt @@ -35,6 +35,12 @@ $dataSet = [ ['1.1E1', 11.0], ['1.1E+1', 11.0], ['1.1E-1', 0.11], + ['2147483647', 2147483647], + + [(string) PHP_INT_MAX, PHP_INT_MAX], + ['12341234123412344564654657845465', '12341234123412344564654657845465'], + ['0x12341234123412344564654657845465', '24196472569643293506997087088694023269'], + ['12341234123412344564654657845465.0', 12341234123412344564654657845465.0], // literals ['null', null],