Skip to content

Commit

Permalink
Decoder: big integers are decoded as strings [Closes #9]
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Jun 26, 2024
1 parent dad6890 commit b2b28ae
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
33 changes: 29 additions & 4 deletions src/Neon/Node/LiteralNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -66,6 +66,30 @@ public static function parse(string $value, bool $isKey = false): mixed
}


public static function baseConvert(string $number, int $base): string|int
{
if (strlen($number) < 16) {
$res = base_convert($number, $base, 10);
} elseif (!extension_loaded('bcmath')) {
throw new Exception("The number '$number' is too large, enable 'bcmath' extension to handle it.");
} else {
$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) {
Expand All @@ -82,6 +106,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 {
Expand Down
6 changes: 6 additions & 0 deletions tests/Neon/Decoder.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ $dataSet = [
['1.1E1', 11.0],
['1.1E+1', 11.0],
['1.1E-1', 0.11],
['2147483647', 2_147_483_647],

[(string) PHP_INT_MAX, PHP_INT_MAX],
['12341234123412344564654657845465', '12341234123412344564654657845465'],
['0x12341234123412344564654657845465', '24196472569643293506997087088694023269'],
['12341234123412344564654657845465.0', 12_341_234_123_412_344_564_654_657_845_465.0],

// literals
['null', null],
Expand Down

0 comments on commit b2b28ae

Please sign in to comment.