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 Apr 28, 2024
1 parent 2efdf8b commit 1e453c4
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
35 changes: 31 additions & 4 deletions src/Neon/Node/LiteralNode.php
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,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) {
Expand All @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions tests/Neon/Decoder.phpt
Expand Up @@ -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],
Expand Down

0 comments on commit 1e453c4

Please sign in to comment.