Skip to content
This repository has been archived by the owner on Jan 31, 2020. It is now read-only.

Commit

Permalink
made ints and floats more standard
Browse files Browse the repository at this point in the history
  • Loading branch information
ylixir committed Feb 20, 2019
1 parent 35dfd4c commit d85f167
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 41 deletions.
12 changes: 7 additions & 5 deletions docs/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ assert([1.0] === $parser("1.0")->parsed);
assert([0.1] === $parser(".1")->parsed);

assert([100.0] === $parser("10E1")->parsed);
assert([1.0] === $parser("10e-1")->parsed);
assert([1.0] === $parser("10e-001")->parsed);
assert([100.0] === $parser("10e+1")->parsed);

assert([100.0] === $parser("10.e1")->parsed);
assert([0.1] === $parser("1.0E-1")->parsed);
assert([1.0] === $parser(".1E+1")->parsed);
assert([100.0] === $parser("10.e001")->parsed);
assert([0.1] === $parser("1.00E-1")->parsed);
assert([1.0] === $parser(".1E+001")->parsed);

assert([1.0] === $parser("1e0")->parsed);
assert([1.0] === $parser("1e00")->parsed);

assert('a' === $parser("1.a")->unparsed);

Expand Down Expand Up @@ -133,6 +133,8 @@ assert('a' === $parser("123a")->unparsed);
assert(null === $parser("")->parsed);
//doesn't handle signs
assert(null === $parser("-123")->parsed);
//doesn't allow accidental octal collisions
assert(null === $parser("00")->parsed);
```

## `octal`
Expand Down
79 changes: 53 additions & 26 deletions src/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,27 @@ public static function eol(): callable
*/
public static function float(): callable
{
$decimal_part = self::map(function (int $q): float {
//mantissa and fractional integer's may have leading zeros
$zeros_integer = self::or(
self::and(self::drop(self::repeat(self::lit("0"))), self::int()),
self::and(self::int(), self::drop(self::repeat(self::lit("0"))))
);

$fractional_part = self::map(function (int $q): float {
for ($d = 1; $d <= $q; $d *= 10);
return $q / $d;
}, self::int());
}, $zeros_integer);
$integer_part = self::map('floatval', self::int());

// parse a non-scientific float into integer and decimal parts
$parts = self::or(
self::and($integer_part, self::drop(self::lit(".")), $decimal_part),
self::and(
$integer_part,
self::drop(self::lit(".")),
$fractional_part
),
self::and($integer_part, self::drop(self::lit("."))),
self::and(self::drop(self::lit(".")), $decimal_part)
self::and(self::drop(self::lit(".")), $fractional_part)
);
$float = self::fold(
/** @return array{0:float} */ function (float $p, float $i): array {
Expand All @@ -147,15 +157,19 @@ public static function float(): callable
);

$e = self::drop(self::or(self::lit("e"), self::lit("E")));

$negative_integer = self::map(function (int $i): int {
return -$i;
}, self::and(self::drop(self::lit("-")), self::int()));
$positive_integer = self::and(self::drop(self::lit("+")), self::int());
}, self::and(self::drop(self::lit("-")), $zeros_integer));
$positive_integer = self::and(
self::drop(self::lit("+")),
$zeros_integer
);
$mantissa = self::map(function (int $i): float {
return pow(10, $i);
}, self::and(
$e,
self::or(self::int(), $negative_integer, $positive_integer)
self::or($zeros_integer, $negative_integer, $positive_integer)
));
$scientific = self::fold(
/** @return array{0:float} */ function (float $a, float $b): array {
Expand Down Expand Up @@ -194,7 +208,7 @@ public static function fold(
function (array $a, $s) use ($f): array {
return $f($s, ...$a);
};
/** @var array<int, S> */ $reduced = array_reduce(
/** @var array<int, mixed> */ $reduced = array_reduce(
$r->parsed,
$ftransform,
$start
Expand Down Expand Up @@ -245,10 +259,15 @@ public static function int(): callable
/**
* @var array<int, callable(string):?r<string>>
*/
$digitLits = array_map(self::lit, range("0", "9"));
$digits = self::or(...$digitLits);

$intString = self::and($digits, self::repeat($digits));
$firstLits = array_map(self::lit, range("1", "9"));
$zeroLit = self::lit("0");
$firstDigits = self::or(...$firstLits);
$digits = self::or($zeroLit, ...$firstLits);

$intString = self::or(
self::and($firstDigits, self::repeat($digits)),
$zeroLit
);

$intVal = function (string $d, int $a): array {
return [$a * 10 + (int) $d];
Expand All @@ -258,7 +277,7 @@ public static function int(): callable
}

/**
* @return callable(string):?r
* @return callable(string):?r<string>
*/
public static function lit(string $c): callable
{
Expand All @@ -274,7 +293,9 @@ public static function lit(string $c): callable
$tail = mb_strcut($in, $cLen);

if ($head === $c) {
return r::make($tail, [$head]);
/** @var r<string> */
$result = r::make($tail, [$head]);
return $result;
} else {
return null;
}
Expand All @@ -285,20 +306,26 @@ public static function lit(string $c): callable
* @template S
* @template T
* @param callable(S):T $f
* @param callable(string):?r $p
* @return callable(string):?r
* @param callable(string):?r<S> $p
* @return callable(string):?r<T>
*/
public static function map(callable $f, callable $p): callable
{
return function (string $in) use ($f, $p): ?r {
$r = $p($in);
if (null === $r) {
return $r;
} else {
/** @var array<int, T> */ $mapped = array_map($f, $r->parsed);
return r::make($r->unparsed, $mapped);
}
};
return /**
* @return ?r<T>
*/
function (string $in) use ($f, $p): ?r {
$r = $p($in);
if (null === $r) {
return $r;
} else {
/** @var array<int, mixed> */ $mapped = array_map(
$f,
$r->parsed
);
return r::make($r->unparsed, $mapped);
}
};
}

/**
Expand All @@ -323,7 +350,7 @@ public static function octal(): callable

/**
* @param callable(string):?r $head
* @param array<int,callable(string):?r> $tail
* @param callable(string):?r ...$tail
* @return callable(string):?r
*/
public static function or(callable $head, callable ...$tail): callable
Expand Down
1 change: 1 addition & 0 deletions src/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ private function __construct(string $unparsed, array $parsed)

/**
* @param array<int, T> $parsed
* @return self<T>
*/
public static function make(string $unparsed, array $parsed): self
{
Expand Down
11 changes: 6 additions & 5 deletions test/Unit/FunctionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ public function float_provider(): array
[".1", r::make("", [0.1])],

["10E1", r::make("", [100.0])],
["10e-1", r::make("", [1.0])],
["10e-001", r::make("", [1.0])],
["10e+1", r::make("", [100.0])],

["10.e1", r::make("", [100.0])],
["1.0E-1", r::make("", [0.1])],
[".1E+1", r::make("", [1.0])],
["10.e001", r::make("", [100.0])],
["1.00E-1", r::make("", [0.1])],
[".1E+001", r::make("", [1.0])],

["1e0", r::make("", [1.0])],
["1e00", r::make("", [1.0])],

["1.a", r::make("a", [1.0])],

Expand Down Expand Up @@ -199,6 +199,7 @@ public function int_provider(): array
return [
["123", r::make("", [123])],
["0", r::make("", [0])],
["00", r::make("0", [0])],
["123a", r::make("a", [123])],
["", null],
["-123", null],
Expand Down
11 changes: 6 additions & 5 deletions test/Unit/OopTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@ public function floatProvider(): array
[".1", r::make("", [0.1])],

["10E1", r::make("", [100.0])],
["10e-1", r::make("", [1.0])],
["10e-001", r::make("", [1.0])],
["10e+1", r::make("", [100.0])],

["10.e1", r::make("", [100.0])],
["1.0E-1", r::make("", [0.1])],
[".1E+1", r::make("", [1.0])],
["10.e001", r::make("", [100.0])],
["1.00E-1", r::make("", [0.1])],
[".1E+001", r::make("", [1.0])],

["1e0", r::make("", [1.0])],
["1e00", r::make("", [1.0])],

["1.a", r::make("a", [1.0])],

Expand Down Expand Up @@ -192,6 +192,7 @@ public function intProvider(): array
return [
["123", r::make("", [123])],
["0", r::make("", [0])],
["00", r::make("0", [0])],
["123a", r::make("a", [123])],
["", null],
["-123", null],
Expand Down

0 comments on commit d85f167

Please sign in to comment.