refactor: Cleanup git state - commit all staged changes
Major refactoring cleanup: - Add new controller architecture (class-controller-*.php) - Add new settings-v2 UI (views/settings-v2/) - Add new CSS architecture (agentic-sidebar.css, tokens) - Add esbuild build pipeline (scripts/build.js, package.json) - Add composer dependencies (vendor/) - Add frontend src directory (assets/js/src/index.jsx) - Add documentation files - Remove old/obsolete files (class-settings.php, old CSS) This commits all pending changes from previous refactoring efforts.
This commit is contained in:
290
vendor/parsica-php/parsica/tests/Curry/CurryTest.php
vendored
Normal file
290
vendor/parsica-php/parsica/tests/Curry/CurryTest.php
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This code is forked from https://github.com/matteosister/php-curry, which is abandoned. It could be integrated into
|
||||
* the rest of Parsica.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Curry;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function Parsica\Parsica\Curry\__;
|
||||
use function Parsica\Parsica\Curry\_is_fullfilled;
|
||||
use function Parsica\Parsica\Curry\_rest;
|
||||
use function Parsica\Parsica\Curry\curry;
|
||||
use function Parsica\Parsica\Curry\curry_args;
|
||||
use function Parsica\Parsica\Curry\curry_right;
|
||||
use function Parsica\Parsica\Curry\curry_right_args;
|
||||
|
||||
final class CurryTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_without_params()
|
||||
{
|
||||
$simpleFunction = curry(function () {
|
||||
return 1;
|
||||
});
|
||||
$this->assertEquals(1, $simpleFunction());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_identity()
|
||||
{
|
||||
$identity = curry([new TestSubject(), 'identity'], 1);
|
||||
$this->assertEquals(1, $identity(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_identity_function()
|
||||
{
|
||||
$func = curry(function ($v) {
|
||||
return $v;
|
||||
}, 'test string');
|
||||
$this->assertEquals('test string', $func());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_with_one_later_param()
|
||||
{
|
||||
$curriedOne = curry([new TestSubject(), 'add2'], 1);
|
||||
$this->assertInstanceOf('Closure', $curriedOne);
|
||||
$this->assertEquals(2, $curriedOne(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_with_two_later_param()
|
||||
{
|
||||
$curriedTwo = curry([new TestSubject(), 'add4'], 1, 1);
|
||||
$this->assertInstanceOf('Closure', $curriedTwo);
|
||||
$this->assertEquals(4, $curriedTwo(1, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_with_successive_calls()
|
||||
{
|
||||
$curriedTwo = curry([new TestSubject(), 'add4'], 1, 1);
|
||||
$curriedThree = $curriedTwo(1);
|
||||
$this->assertEquals(4, $curriedThree(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_right()
|
||||
{
|
||||
$divideBy10 = curry_right([new TestSubject(), 'divide2'], 10);
|
||||
$this->assertInstanceOf('Closure', $divideBy10);
|
||||
$this->assertEquals(10, $divideBy10(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_right_immediate()
|
||||
{
|
||||
$divide3 = curry_right([new TestSubject(), 'divide3'], 5, 2, 20);
|
||||
$this->assertEquals(2, $divide3());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_left_immediate()
|
||||
{
|
||||
$divide3 = curry([new TestSubject(), 'divide3'], 20, 2, 4);
|
||||
$this->assertEquals(2.5, $divide3());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_three_times()
|
||||
{
|
||||
$divideBy5 = curry([new TestSubject(), 'divide3'], 100);
|
||||
$divideBy10And5 = $divideBy5(10);
|
||||
$this->assertEquals(2, $divideBy10And5(5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_right_three_times()
|
||||
{
|
||||
$divideBy5 = curry_right([new TestSubject(), 'divide3'], 5);
|
||||
$divideBy10And5 = $divideBy5(10);
|
||||
$this->assertEquals(2, $divideBy10And5(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_using_func_get_args()
|
||||
{
|
||||
|
||||
$fnNoArgs = function () {
|
||||
return func_get_args();
|
||||
};
|
||||
$curried = curry($fnNoArgs);
|
||||
$curriedRight = curry_right($fnNoArgs);
|
||||
|
||||
$this->assertEquals([], $fnNoArgs());
|
||||
$this->assertEquals([], $curried());
|
||||
$this->assertEquals([], $curriedRight());
|
||||
|
||||
$this->assertEquals([1], $fnNoArgs(1));
|
||||
$this->assertEquals([1], $curried(1));
|
||||
$this->assertEquals([1], $curriedRight(1));
|
||||
|
||||
$this->assertEquals([1, 2, 'three'], $fnNoArgs(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curried(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curriedRight(1, 2, 'three'));
|
||||
|
||||
$fnOneArg = function ($x) {
|
||||
return func_get_args();
|
||||
};
|
||||
$curried = curry($fnOneArg);
|
||||
$curriedRight = curry_right($fnOneArg);
|
||||
|
||||
$this->assertEquals([1], $fnOneArg(1));
|
||||
$this->assertEquals([1], $curried(1));
|
||||
$this->assertEquals([1], $curriedRight(1));
|
||||
|
||||
$this->assertEquals([1, 2, 'three'], $fnOneArg(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curried(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curriedRight(1, 2, 'three'));
|
||||
|
||||
$fnTwoArgs = function ($x, $y) {
|
||||
return func_get_args();
|
||||
};
|
||||
$curried = curry($fnTwoArgs);
|
||||
$curriedRight = curry_right($fnTwoArgs);
|
||||
|
||||
$curriedOne = $curried(1);
|
||||
$curriedRightOne = $curriedRight(2);
|
||||
$curriedRightTwo = $curriedRight('three');
|
||||
|
||||
$this->assertEquals([1, 2], $fnTwoArgs(1, 2));
|
||||
$this->assertEquals([1, 2], $curried(1, 2));
|
||||
$this->assertEquals([1, 2], $curriedRight(2, 1));
|
||||
|
||||
$this->assertEquals([1, 2, 'three'], $fnTwoArgs(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curried(1, 2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curriedRight('three', 2, 1));
|
||||
|
||||
$this->assertEquals([1, 2], $curriedOne(2));
|
||||
$this->assertEquals([1, 2], $curriedRightOne(1));
|
||||
|
||||
$this->assertEquals([1, 2, 'three'], $curriedOne(2, 'three'));
|
||||
$this->assertEquals([1, 2, 'three'], $curriedRightTwo(2, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function curry_with_placeholders()
|
||||
{
|
||||
$minus = curry(function ($x, $y) {
|
||||
return $x - $y;
|
||||
});
|
||||
$decrement = $minus(__(), 1);
|
||||
|
||||
$this->assertEquals(9, $decrement(10));
|
||||
|
||||
$introduce = curry(function ($name, $age, $job, $details = '') {
|
||||
return "{$name}, {$age} years old, is a {$job} {$details}";
|
||||
});
|
||||
|
||||
$introduceDeveloper = $introduce(__(), __(), 'Developer');
|
||||
$this->assertEquals("Foo, 20 years old, is a Developer ", $introduceDeveloper('Foo', 20));
|
||||
|
||||
$introduceOld = $introduce(__(), 99, __());
|
||||
$this->assertEquals("Foo, 99 years old, is a Developer and Cooker as well", $introduceOld('Foo', 'Developer', 'and Cooker as well'));
|
||||
|
||||
$introduceSkipName = $introduce(__());
|
||||
$introduceSkipJob = $introduceSkipName(99, __());
|
||||
|
||||
$this->assertEquals("Foo, 99 years old, is a Cooker ", $introduceSkipJob('Foo', 'Cooker'));
|
||||
$this->assertEquals("Foo, 99 years old, is a Cooker yumm !", $introduceSkipJob('Foo', 'Cooker', 'yumm !'));
|
||||
|
||||
$reduce = curry('array_reduce');
|
||||
$add = function ($x, $y) {
|
||||
return $x + $y;
|
||||
};
|
||||
$sum = $reduce(__(), $add);
|
||||
|
||||
$this->assertEquals(10, $sum([1, 2, 3, 4], 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function rest()
|
||||
{
|
||||
$this->assertEquals([1], _rest([1, 1]));
|
||||
$this->assertEquals(['a', 'b'], _rest([1, 'a', 'b']));
|
||||
$this->assertEquals([], _rest([1]));
|
||||
$this->assertEquals([], _rest([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider provider_is_fullfilled
|
||||
*/
|
||||
public function is_fullfilled($isFullfilled, $args, $callable)
|
||||
{
|
||||
$this->assertSame($isFullfilled, _is_fullfilled($callable, $args));
|
||||
}
|
||||
|
||||
public function provider_is_fullfilled()
|
||||
{
|
||||
return [[false, [], function ($a) {
|
||||
}], [true, [], function () {
|
||||
}], [true, [1], function ($a) {
|
||||
}], [false, [1], function ($a, $b) {
|
||||
}], [false, [1], [new TestSubject(), 'add2']], [true, [1, 2], [new TestSubject(), 'add2']], [true, ['aaa', 'a'], 'strpos'],];
|
||||
}
|
||||
}
|
||||
|
||||
final class TestSubject
|
||||
{
|
||||
public function identity($a)
|
||||
{
|
||||
return $a;
|
||||
}
|
||||
|
||||
public function add2($a, $b)
|
||||
{
|
||||
return $a + $b;
|
||||
}
|
||||
|
||||
public function divide2($a, $b)
|
||||
{
|
||||
return $a / $b;
|
||||
}
|
||||
|
||||
public function divide3($a, $b, $c)
|
||||
{
|
||||
return $a / $b / $c;
|
||||
}
|
||||
|
||||
public function add3($a, $b, $c)
|
||||
{
|
||||
return $a + $b + $c;
|
||||
}
|
||||
|
||||
public function add4($a, $b, $c, $d)
|
||||
{
|
||||
return $a + $b + $c + $d;
|
||||
}
|
||||
}
|
||||
130
vendor/parsica-php/parsica/tests/Examples/BooleanExpressionsTest.php
vendored
Normal file
130
vendor/parsica-php/parsica/tests/Examples/BooleanExpressionsTest.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Examples;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{between, char, choice, keepFirst, recursive, skipHSpace, string};
|
||||
use function Parsica\Parsica\Expression\{binaryOperator, expression, leftAssoc, prefix, unaryOperator};
|
||||
|
||||
final class BooleanExpressionsTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function booleanExpressions()
|
||||
{
|
||||
$token = fn(Parser $parser) : Parser => keepFirst($parser, skipHSpace());
|
||||
$parens = fn (Parser $parser): Parser => $token(between($token(char('(')), $token(char(')')), $parser));
|
||||
$term = fn(): Parser => $token(choice(
|
||||
string("TRUE")->map(fn($v) => new True_),
|
||||
string("FALSE")->map(fn($v) => new False_),
|
||||
));
|
||||
$NOT = unaryOperator($token(string("NOT")), fn($v) => new Not_($v));
|
||||
$AND = binaryOperator($token(string("AND")), fn($l, $r) => new And_($l, $r));
|
||||
$OR = binaryOperator($token(string("OR")), fn($l, $r) => new Or_($l, $r));
|
||||
|
||||
$expr = recursive();
|
||||
$expr->recurse(expression(
|
||||
$parens($expr)->or($term()),
|
||||
[
|
||||
prefix($NOT),
|
||||
leftAssoc($AND),
|
||||
leftAssoc($OR),
|
||||
]
|
||||
));
|
||||
|
||||
|
||||
$parser = $expr->thenEof();
|
||||
$input = "TRUE AND NOT (FALSE AND FALSE)";
|
||||
$expected =
|
||||
new And_(
|
||||
new True_(),
|
||||
new Not_(
|
||||
new And_(
|
||||
new False_(),
|
||||
new False_()
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
|
||||
$parser = $expr->thenEof();
|
||||
$input = "TRUE AND NOT (FALSE OR TRUE AND FALSE)";
|
||||
$expected =
|
||||
new And_(
|
||||
new True_,
|
||||
new Not_(
|
||||
new Or_(
|
||||
new False_,
|
||||
new And_(
|
||||
new True_,
|
||||
new False_
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
// Now swapping precedence of AND and OR
|
||||
$expr = recursive();
|
||||
$expr->recurse(expression(
|
||||
$parens($expr)->or($term()),
|
||||
[
|
||||
prefix($NOT),
|
||||
leftAssoc($OR),
|
||||
leftAssoc($AND),
|
||||
]
|
||||
));
|
||||
|
||||
$parser = $expr->thenEof();
|
||||
$input = "TRUE AND NOT (FALSE OR TRUE AND FALSE)";
|
||||
$expected =
|
||||
new And_(
|
||||
new True_,
|
||||
new Not_(
|
||||
new And_(
|
||||
new Or_(
|
||||
new False_,
|
||||
new True_
|
||||
),
|
||||
new False_
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface Boolean_ {}
|
||||
class True_ implements Boolean_ {}
|
||||
class False_ implements Boolean_ {}
|
||||
class Not_ implements Boolean_ {
|
||||
private Boolean_ $boolean;
|
||||
function __construct(Boolean_ $boolean){$this->boolean = $boolean;}
|
||||
}
|
||||
class And_ implements Boolean_ {
|
||||
private Boolean_ $l, $r;
|
||||
function __construct(Boolean_ $l, Boolean_ $r){
|
||||
$this->l = $l;
|
||||
$this->r = $r;
|
||||
}
|
||||
}
|
||||
class Or_ implements Boolean_ {
|
||||
private Boolean_ $l, $r;
|
||||
function __construct(Boolean_ $l, Boolean_ $r){
|
||||
$this->l = $l;
|
||||
$this->r = $r;
|
||||
}
|
||||
}
|
||||
63
vendor/parsica-php/parsica/tests/Examples/CalculatorTest.php
vendored
Normal file
63
vendor/parsica-php/parsica/tests/Examples/CalculatorTest.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Examples;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use function Parsica\Parsica\{atLeastOne, between, char, digitChar, keepFirst, recursive, skipHSpace, string};
|
||||
use function Parsica\Parsica\Expression\{binaryOperator,
|
||||
expression,
|
||||
leftAssoc,
|
||||
postfix,
|
||||
prefix,
|
||||
unaryOperator};
|
||||
|
||||
/**
|
||||
* Parse expressions and calculate the result
|
||||
*/
|
||||
final class CalculatorTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function calculator()
|
||||
{
|
||||
$token = fn(Parser $parser) => keepFirst($parser, skipHSpace());
|
||||
$parens = fn (Parser $parser): Parser => $token(between($token(char('(')), $token(char(')')), $parser));
|
||||
$term = fn(): Parser => $token(atLeastOne(digitChar()));
|
||||
|
||||
$expr = recursive();
|
||||
$expr->recurse(expression(
|
||||
$parens($expr)->or($term()),
|
||||
[
|
||||
prefix(
|
||||
unaryOperator(char('-'), fn($v) => -$v),
|
||||
unaryOperator(char('+'), fn($v) => $v),
|
||||
),
|
||||
postfix(
|
||||
unaryOperator($token(string('--')), fn($v) => $v - 1),
|
||||
unaryOperator($token(string('++')), fn($v) => $v + 1),
|
||||
),
|
||||
leftAssoc(
|
||||
binaryOperator($token(char('*')), fn($l, $r) => $l * $r),
|
||||
binaryOperator($token(char('/')), fn($l, $r) => $l / $r),
|
||||
),
|
||||
leftAssoc(
|
||||
binaryOperator($token(char('+')), fn($l, $r) => $l + $r),
|
||||
binaryOperator($token(char('-')), fn($l, $r) => $l - $r),
|
||||
),
|
||||
]
|
||||
));
|
||||
|
||||
|
||||
$parser = $expr->thenEof();
|
||||
$result = $parser->tryString("(3 - 2) + -1 - 3 * (1 + 1) / 6");
|
||||
$this->assertEquals(-1, (string)$result->output());
|
||||
}
|
||||
}
|
||||
131
vendor/parsica-php/parsica/tests/Examples/ExcelTest.php
vendored
Normal file
131
vendor/parsica-php/parsica/tests/Examples/ExcelTest.php
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Examples;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{alphaChar, between, char, collect, digitChar, skipHSpace1, space, string};
|
||||
|
||||
final class ExcelTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function spaceOrOperatorDependingOnContext()
|
||||
{
|
||||
// https://twitter.com/Mark_Baker/status/1309919606887374849?s=20
|
||||
// and https://twitter.com/Mark_Baker/status/1309960902482026498?s=20
|
||||
// `=SUM(B7:D7 C6:C8)` where space is the intersection operator for the
|
||||
// intersection between the two ranges B7:D7 and C6:C8 (ie. C7),
|
||||
// and `=A1 & B1` where the space is simply whitespace and should be ignored
|
||||
|
||||
$parser = $this->excelParser();
|
||||
|
||||
|
||||
$input = "=SUM(B7:D7 C6:C8)";
|
||||
$expected = new Sum(
|
||||
new Intersection(
|
||||
new Range(new Cell("B", "7"), new Cell("D", "7")),
|
||||
new Range(new Cell("C", "6"), new Cell("C", "8")),
|
||||
)
|
||||
);
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
|
||||
$input = "=A1 & B1";
|
||||
$expected = new Ampersand(
|
||||
new Cell("A", "1"),
|
||||
new Cell("B", "1"),
|
||||
);
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
private function excelParser(): Parser
|
||||
{
|
||||
$parens = fn(Parser $p): Parser => between(char('('), char(')'), $p);
|
||||
$cell = collect(alphaChar(), digitChar())
|
||||
->map(fn($o) => new Cell($o[0], $o[1]));
|
||||
$range = collect($cell, char(':'), $cell)
|
||||
->map(fn($o) => new Range($o[0], $o[2]));
|
||||
$intersection = collect($range, space(), $range)
|
||||
->map(fn($o) => new Intersection($o[0], $o[2]));
|
||||
$sum = (string('=SUM')->followedBy($parens($intersection)))
|
||||
->map(fn($o) => new Sum($o));
|
||||
|
||||
|
||||
// consumes space before and after Parser $p
|
||||
$token = fn(Parser $p): Parser => between(skipHSpace1(), skipHSpace1(), $p);
|
||||
$ampersand = char('=')->followedBy(collect(
|
||||
$cell,
|
||||
$token(char('&')),
|
||||
$cell
|
||||
))->map(fn($o) => new Ampersand($o[0], $o[2]));
|
||||
|
||||
|
||||
return $sum->or($ampersand);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Cell
|
||||
{
|
||||
private $col;
|
||||
private $row;
|
||||
|
||||
function __construct($col, $row)
|
||||
{
|
||||
$this->col = $col;
|
||||
$this->row = $row;
|
||||
}
|
||||
}
|
||||
class Range
|
||||
{
|
||||
private Cell $from;
|
||||
private Cell $to;
|
||||
|
||||
function __construct(Cell $from, Cell $to)
|
||||
{
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
}
|
||||
}
|
||||
class Intersection
|
||||
{
|
||||
private Range $l;
|
||||
private Range $r;
|
||||
|
||||
function __construct(Range $l, Range $r)
|
||||
{
|
||||
$this->l = $l;
|
||||
$this->r = $r;
|
||||
}
|
||||
}
|
||||
class Sum
|
||||
{
|
||||
private Intersection $intersection;
|
||||
|
||||
function __construct(Intersection $intersection)
|
||||
{
|
||||
$this->intersection = $intersection;
|
||||
}
|
||||
}
|
||||
class Ampersand
|
||||
{
|
||||
private Cell $l;
|
||||
private Cell $r;
|
||||
|
||||
function __construct(Cell $l, Cell $r)
|
||||
{
|
||||
$this->l = $l;
|
||||
$this->r = $r;
|
||||
}
|
||||
}
|
||||
47
vendor/parsica-php/parsica/tests/Examples/SimpleDateTest.php
vendored
Normal file
47
vendor/parsica-php/parsica/tests/Examples/SimpleDateTest.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Examples;
|
||||
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function Parsica\Parsica\any;
|
||||
use function Parsica\Parsica\collect;
|
||||
use function Parsica\Parsica\digitChar;
|
||||
use function Parsica\Parsica\repeat;
|
||||
use function Parsica\Parsica\skipSpace;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class SimpleDateTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function simple_date()
|
||||
{
|
||||
$jan = (string("January")->or(string("Jan")))->map(fn($v) => 1);
|
||||
$feb = (string("February")->or(string("Feb")))->map(fn($v) => 2);
|
||||
$mar = (string("March")->or(string("Mar")))->map(fn($v) => 3);
|
||||
// ... you get the gist
|
||||
|
||||
$month = any($jan, $feb, $mar);
|
||||
$day = repeat(2, digitChar())->map('intval');
|
||||
$p1 = collect(
|
||||
$month->thenIgnore(skipSpace()),
|
||||
$day
|
||||
);
|
||||
|
||||
$this->assertParses("January 28", $p1, [1, 28]);
|
||||
$this->assertParses("Jan 28", $p1, [1, 28]);
|
||||
$this->assertParses("February 28", $p1, [2, 28]);
|
||||
$this->assertParses("Feb 28", $p1, [2, 28]);
|
||||
}
|
||||
|
||||
}
|
||||
172
vendor/parsica-php/parsica/tests/Expression/ExpressionsTest.php
vendored
Normal file
172
vendor/parsica-php/parsica/tests/Expression/ExpressionsTest.php
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Expression;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Expression\{LeftAssoc, NonAssoc, Operator, Postfix, Prefix, RightAssoc};
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\atLeastOne;
|
||||
use function Parsica\Parsica\between;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\collect;
|
||||
use function Parsica\Parsica\digitChar;
|
||||
use function Parsica\Parsica\eof;
|
||||
use function Parsica\Parsica\Expression\binaryOperator;
|
||||
use function Parsica\Parsica\Expression\expression;
|
||||
use function Parsica\Parsica\Expression\leftAssoc;
|
||||
use function Parsica\Parsica\Expression\nonAssoc;
|
||||
use function Parsica\Parsica\Expression\operator;
|
||||
use function Parsica\Parsica\Expression\postfix;
|
||||
use function Parsica\Parsica\Expression\prefix;
|
||||
use function Parsica\Parsica\Expression\rightAssoc;
|
||||
use function Parsica\Parsica\Expression\unaryOperator;
|
||||
use function Parsica\Parsica\keepFirst;
|
||||
use function Parsica\Parsica\recursive;
|
||||
use function Parsica\Parsica\skipHSpace;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
|
||||
final class ExpressionsTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
private Parser $expression;
|
||||
|
||||
protected function setUp() : void
|
||||
{
|
||||
/** Consumes whitespace */
|
||||
$token = fn(Parser $parser) => keepFirst($parser, skipHSpace());
|
||||
$parens = fn (Parser $parser): Parser => $token(between($token(char('(')), $token(char(')')), $parser));
|
||||
$term = fn(): Parser => $token(atLeastOne(digitChar()));
|
||||
|
||||
$expr = recursive();
|
||||
$primaryTermParser = $parens($expr)->or($term());
|
||||
|
||||
$expr->recurse(expression(
|
||||
$primaryTermParser,
|
||||
[
|
||||
prefix(
|
||||
unaryOperator(char('-'), fn($v) => "(-$v)"),
|
||||
unaryOperator(char('+'), fn($v) => "(+$v)"),
|
||||
),
|
||||
postfix(
|
||||
unaryOperator($token(string('--')), fn($v) => "($v--)"),
|
||||
unaryOperator($token(string('++')), fn($v) => "($v++)"),
|
||||
),
|
||||
leftAssoc(
|
||||
binaryOperator($token(char('*')), fn($l, $r) => "($l * $r)"),
|
||||
binaryOperator($token(char('/')), fn($l, $r) => "($l / $r)"),
|
||||
|
||||
),
|
||||
rightAssoc(
|
||||
// imaginary right associative operator
|
||||
binaryOperator($token(char('R')), fn($l, $r) => "($l R $r)"),
|
||||
binaryOperator($token(string('R2')), fn($l, $r) => "($l R2 $r)"),
|
||||
),
|
||||
leftAssoc(
|
||||
binaryOperator($token(char('-')), fn($l, $r) => "($l - $r)"),
|
||||
binaryOperator($token(char('+')), fn($l, $r) => "($l + $r)"),
|
||||
),
|
||||
nonAssoc(
|
||||
// imaginary non-associative operator
|
||||
binaryOperator($token(char('§')), fn($l, $r) => "($l § $r)"),
|
||||
)
|
||||
]
|
||||
));
|
||||
$this->expression = $expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider examples
|
||||
*/
|
||||
public function expression(string $input, string $expected)
|
||||
{
|
||||
$parser = $this->expression->thenEof();
|
||||
$result = $parser->tryString($input);
|
||||
$this->assertEquals($expected, (string)$result->output());
|
||||
}
|
||||
|
||||
|
||||
public function examples()
|
||||
{
|
||||
$examples = [
|
||||
["1", "1"],
|
||||
["1 + 1", "(1 + 1)"],
|
||||
["1 * 1", "(1 * 1)"],
|
||||
["(1 + 1) + 1", "((1 + 1) + 1)"],
|
||||
["1 + (1 + 1)", "(1 + (1 + 1))"],
|
||||
["1 * (1 + 1)", "(1 * (1 + 1))"],
|
||||
["1 + (1 * 1)", "(1 + (1 * 1))"],
|
||||
["(1 * 2) + (1 * 1)", "((1 * 2) + (1 * 1))"],
|
||||
["1 + 2 + 3", "((1 + 2) + 3)"],
|
||||
["1 * 2 * 3", "((1 * 2) * 3)"],
|
||||
["1 * 2 + 3", "((1 * 2) + 3)"],
|
||||
["1 + 2 * 3", "(1 + (2 * 3))"],
|
||||
["4 + 5 + 2 * 3", "((4 + 5) + (2 * 3))"],
|
||||
["4 + 5 * 2 * 3", "(4 + ((5 * 2) * 3))"],
|
||||
["1 * 2 * 3 / 4 * 5", "((((1 * 2) * 3) / 4) * 5)"],
|
||||
["1 / 2 / 3 * 4", "(((1 / 2) / 3) * 4)"],
|
||||
["1 - 2 + 3", "((1 - 2) + 3)"],
|
||||
["1 - 2 * 3", "(1 - (2 * 3))"],
|
||||
["1 + 5 - 2 * 3 - 6", "(((1 + 5) - (2 * 3)) - 6)"],
|
||||
["-1", "(-1)"],
|
||||
["-1 + -2", "((-1) + (-2))"],
|
||||
["-(-1)", "(-(-1))"],
|
||||
["-(-(1))", "(-(-1))"],
|
||||
// @todo crazy slow for some reason
|
||||
// ["(-(-(1)))", "(-(-1))"],
|
||||
["-1 * +1", "((-1) * (+1))"],
|
||||
["1 § 2", "(1 § 2)"],
|
||||
["1 + 5 § 2 * 3 - 6", "((1 + 5) § ((2 * 3) - 6))"],
|
||||
["1 R 2 R 3", "(1 R (2 R 3))"],
|
||||
["1 R 2 R 3 R 4", "(1 R (2 R (3 R 4)))"],
|
||||
["1 - 2 * 3 R 4", "(1 - ((2 * 3) R 4))"],
|
||||
["1 - 2 * 3 R 4 R 5", "(1 - ((2 * 3) R (4 R 5)))"],
|
||||
["1++", "(1++)"],
|
||||
["1++ + 2++", "((1++) + (2++))"],
|
||||
["1--", "(1--)"],
|
||||
["1-- + 2--", "((1--) + (2--))"],
|
||||
["1++ + 2--", "((1++) + (2--))"],
|
||||
["1-- + 2++", "((1--) + (2++))"],
|
||||
];
|
||||
|
||||
return array_combine(array_column($examples, 0), $examples);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider unparsableExamples
|
||||
*/
|
||||
public function unparsableExpressions(string $input)
|
||||
{
|
||||
$parser = $this->expression->thenEof();
|
||||
$this->assertParseFails($input, $parser);
|
||||
}
|
||||
|
||||
public function unparsableExamples()
|
||||
{
|
||||
$examples = [
|
||||
["--1"],
|
||||
["1--++"],
|
||||
["1++--"],
|
||||
["1 § 2 § 3"],
|
||||
["1 § 2 * 3 § 4"],
|
||||
["1 § 2 * 3 § 4 § 5"],
|
||||
];
|
||||
return array_combine(array_column($examples, 0), $examples);
|
||||
}
|
||||
}
|
||||
|
||||
47
vendor/parsica-php/parsica/tests/Internal/FP/CurryTest.php
vendored
Normal file
47
vendor/parsica-php/parsica/tests/Internal/FP/CurryTest.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Internal\FP;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function Parsica\Parsica\Curry\curry;
|
||||
|
||||
final class CurryTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function curry()
|
||||
{
|
||||
$f = fn($a, $b, $c) => $a + $b + $c;
|
||||
$curried = curry($f);
|
||||
|
||||
$this->assertIsCallable($curried);
|
||||
$this->assertIsCallable($curried(1));
|
||||
$this->assertIsCallable($curried(1)(2));
|
||||
$this->assertIsCallable($curried(1)(2));
|
||||
|
||||
$this->assertEquals(6, $curried(1)(2)(3));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function partial_application()
|
||||
{
|
||||
$f = fn($a, $b, $c) => $a + $b + $c;
|
||||
|
||||
$this->assertIsCallable(curry($f, 1));
|
||||
$this->assertIsCallable(curry($f, 1, 2));
|
||||
|
||||
// I would expect this:
|
||||
// $this->assertEquals(6, curry($f, 1, 2, 3));
|
||||
|
||||
// But we must add a () at the end, which I feel is a bug:
|
||||
$this->assertIsCallable(curry($f, 1, 2, 3));
|
||||
$this->assertEquals(6, curry($f, 1, 2, 3)());
|
||||
}
|
||||
}
|
||||
59
vendor/parsica-php/parsica/tests/Internal/FP/FoldrTest.php
vendored
Normal file
59
vendor/parsica-php/parsica/tests/Internal/FP/FoldrTest.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Internal\FP;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function Parsica\Parsica\Internal\FP\foldr;
|
||||
|
||||
final class FoldrTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function sum_implemented_as_foldr()
|
||||
{
|
||||
$actual = foldr([1, 2, 3], fn ($x, $y) => $x + $y, 0);
|
||||
$this->assertSame(6, $actual);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function associativity_is_correct()
|
||||
{
|
||||
$minus = fn($x, $y) => $x - $y;
|
||||
$input = [1, 2, 3, 4, 5];
|
||||
$init = 0;
|
||||
|
||||
// foldl: ((((0 - 1) - 2) - 3) - 4) - 5) = -15
|
||||
// foldr: (1 - (2 - (3 - (4 - (5 - 0))))) = 3
|
||||
|
||||
$actual = array_reduce($input, $minus, $init);
|
||||
$this->assertSame(-15, $actual);
|
||||
|
||||
$actual = foldr($input, $minus, $init);
|
||||
$this->assertSame(3, $actual);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function x()
|
||||
{
|
||||
$concat = fn($x, $y) => "$x$y";
|
||||
$input = [1, 2, 3, 4, 5];
|
||||
$init = "0";
|
||||
|
||||
// foldl: 012345
|
||||
// foldr: 123450
|
||||
|
||||
$actual = array_reduce($input, $concat, $init);
|
||||
$this->assertSame("012345", $actual);
|
||||
|
||||
$actual = foldr($input, $concat, $init);
|
||||
$this->assertSame("123450", $actual);
|
||||
}
|
||||
|
||||
}
|
||||
65
vendor/parsica-php/parsica/tests/Internal/PositionTest.php
vendored
Normal file
65
vendor/parsica-php/parsica/tests/Internal/PositionTest.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Internal;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Internal\Position;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
|
||||
final class PositionTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function update()
|
||||
{
|
||||
$position = Position::initial();
|
||||
$this->assertEquals(1, $position->line());
|
||||
$this->assertEquals(1, $position->column());
|
||||
$position = $position->advance("a");
|
||||
$this->assertEquals(1, $position->line());
|
||||
$this->assertEquals(2, $position->column());
|
||||
$position = $position->advance("\n");
|
||||
$this->assertEquals(2, $position->line());
|
||||
$this->assertEquals(1, $position->column());
|
||||
$position = $position->advance("\n\n\nabc");
|
||||
$this->assertEquals(5, $position->line());
|
||||
$this->assertEquals(4, $position->column());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function position_in_sequence()
|
||||
{
|
||||
$parser = char('a')->followedBy(char('b'));
|
||||
$input = new StringStream("abc", Position::initial());
|
||||
$result = $parser->run($input);
|
||||
|
||||
$expectedColumn = 3;
|
||||
$actualColumn = $result->remainder()->position()->column();
|
||||
$this->assertEquals($expectedColumn, $actualColumn);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function position_with_tabs()
|
||||
{
|
||||
$expected = 10;
|
||||
// All of these move the column position to 10
|
||||
$position = Position::initial()->advance("123456789");
|
||||
$this->assertEquals($expected, $position->column());
|
||||
$position = Position::initial()->advance("\t56789");
|
||||
$this->assertEquals($expected, $position->column());
|
||||
$position = Position::initial()->advance("\t\t9");
|
||||
$this->assertEquals($expected, $position->column());
|
||||
$position = Position::initial()->advance("1\t56789");
|
||||
$this->assertEquals($expected, $position->column());
|
||||
$position = Position::initial()->advance("123\t56789");
|
||||
$this->assertEquals($expected, $position->column());
|
||||
}
|
||||
}
|
||||
52
vendor/parsica-php/parsica/tests/Internal/StringStreamTest.php
vendored
Normal file
52
vendor/parsica-php/parsica/tests/Internal/StringStreamTest.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Internal;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Internal\Position;
|
||||
use Parsica\Parsica\StringStream;
|
||||
|
||||
final class StringStreamTest extends TestCase
|
||||
{
|
||||
|
||||
/** @test */
|
||||
public function take1()
|
||||
{
|
||||
$s = new StringStream("abc");
|
||||
$t = $s->take1();
|
||||
$this->assertEquals("a", $t->chunk());
|
||||
$expectedPosition = new Position("<input>", 1, 2);
|
||||
$expectedStream = new StringStream("bc", $expectedPosition);
|
||||
$this->assertEquals($expectedStream, $t->stream());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeN()
|
||||
{
|
||||
$s = new StringStream("abcde");
|
||||
$t = $s->takeN(3);
|
||||
$this->assertEquals("abc", $t->chunk());
|
||||
$expectedPosition = new Position("<input>", 1, 4);
|
||||
$expectedStream = new StringStream("de", $expectedPosition);
|
||||
$this->assertEquals($expectedStream, $t->stream());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeWhile()
|
||||
{
|
||||
$s = new StringStream("abc\nde");
|
||||
$t = $s->takeWhile(fn($c) => $c !== "\n");
|
||||
$this->assertEquals("abc", $t->chunk());
|
||||
$expectedPosition = new Position("<input>", 1, 4);
|
||||
$expectedStream = new StringStream("\nde", $expectedPosition);
|
||||
$this->assertEquals($expectedStream, $t->stream());
|
||||
}
|
||||
}
|
||||
161
vendor/parsica-php/parsica/tests/Issues/GH26_Test.php
vendored
Normal file
161
vendor/parsica-php/parsica/tests/Issues/GH26_Test.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Issues;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\alphaNumChar;
|
||||
use function Parsica\Parsica\any;
|
||||
use function Parsica\Parsica\atLeastOne;
|
||||
use function Parsica\Parsica\between;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\either;
|
||||
use function Parsica\Parsica\emit;
|
||||
use function Parsica\Parsica\eof;
|
||||
use function Parsica\Parsica\fail;
|
||||
use function Parsica\Parsica\many;
|
||||
use function Parsica\Parsica\succeed;
|
||||
|
||||
/**
|
||||
* https://github.com/mathiasverraes/parsica/issues/6
|
||||
*/
|
||||
final class GH26_Test extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
private static function pathParser(): Parser
|
||||
{
|
||||
$sep = char('/')
|
||||
->label('directory separator');
|
||||
// unix supports other characters, such as space, so adapt if needed
|
||||
$name = atLeastOne(char('.')->or(char('_'))->or(alphaNumChar()))
|
||||
->label("directory or filename");
|
||||
$parser = many($sep->followedBy($name));
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function parsing_a_simple_path()
|
||||
{
|
||||
$parser = self::pathParser();
|
||||
|
||||
$input = "/a/b/c/file1";
|
||||
$expected = ["a", "b", "c", "file1"];
|
||||
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/mathiasverraes/parsica/issues/6#issuecomment-653772920
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function only_the_first_successful_parser_in_an_either_should_call_emit()
|
||||
{
|
||||
$x = new class {
|
||||
public bool $first = false;
|
||||
public bool $second = false;
|
||||
};
|
||||
|
||||
$parser = either(
|
||||
emit(
|
||||
succeed(),
|
||||
function ($output) use ($x) {
|
||||
$x->first = true; // is called
|
||||
}
|
||||
),
|
||||
emit(
|
||||
succeed(),
|
||||
function ($output) use ($x) {
|
||||
$x->second = true; // is not called
|
||||
}
|
||||
)
|
||||
);
|
||||
$result = $parser->tryString('test');
|
||||
|
||||
$this->assertEquals(true, $x->first);
|
||||
$this->assertEquals(false, $x->second, "Either should only call emit on the first successful parser");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO Set $repeatParser at 500 and fix the performance issues.
|
||||
*
|
||||
* https://github.com/mathiasverraes/parsica/issues/6#issuecomment-653772920
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function it_should_parse_500_times_in_under_100_ms()
|
||||
{
|
||||
// Number of times we run the parser
|
||||
$repeatParser = 1;//500;
|
||||
|
||||
$propertyName = atLeastOne(alphaNumChar());
|
||||
|
||||
$type = emit(
|
||||
either(
|
||||
eof(),
|
||||
char('@')
|
||||
->followedBy($propertyName)
|
||||
->thenIgnore(eof()),
|
||||
),
|
||||
function () {}
|
||||
);
|
||||
|
||||
$map = emit(
|
||||
char('.')->followedBy($propertyName),
|
||||
function () {}
|
||||
);
|
||||
|
||||
$list = emit(
|
||||
between(
|
||||
char('['),
|
||||
char(']'),
|
||||
either(
|
||||
char('@')
|
||||
->followedBy($propertyName)
|
||||
->map(fn($value) => [
|
||||
'discriminatorName' => $value,
|
||||
'keepKeys' => true
|
||||
]),
|
||||
$propertyName
|
||||
->map(fn($value) => [
|
||||
'discriminatorName' => $value,
|
||||
'keepKeys' => false
|
||||
]),
|
||||
)
|
||||
),
|
||||
function () {}
|
||||
);
|
||||
|
||||
$root = emit(
|
||||
char('$'),
|
||||
function () {}
|
||||
);
|
||||
|
||||
$rest = many(any($map, $list))->followedBy($type);
|
||||
|
||||
$parser = either(
|
||||
fail("message"), // $context->preflightCacheParser(),
|
||||
$root
|
||||
)->followedBy($rest);
|
||||
|
||||
$start = microtime(true);
|
||||
for ($i = 0; $i < $repeatParser; $i++) {
|
||||
$parser->tryString('$.q.w[@1].e[2]@int');
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
$this->assertLessThan(0.1, $end - $start);
|
||||
}
|
||||
|
||||
}
|
||||
46
vendor/parsica-php/parsica/tests/JSON/ArrayTest.php
vendored
Normal file
46
vendor/parsica-php/parsica/tests/JSON/ArrayTest.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\JSON\key_value;
|
||||
|
||||
final class ArrayTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider examples
|
||||
*/
|
||||
public function array(string $input, $expected)
|
||||
{
|
||||
$parser = JSON::array();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
public function examples()
|
||||
{
|
||||
return [
|
||||
['[]', []],
|
||||
['[ ] ', []],
|
||||
['[ 1 ] ', [1.0]],
|
||||
['[ true ] ', [true]],
|
||||
['[ 1.23, "abc", null, false ] ', [ 1.23, "abc", null, false]],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
64
vendor/parsica-php/parsica/tests/JSON/JSONTest.php
vendored
Normal file
64
vendor/parsica-php/parsica/tests/JSON/JSONTest.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
|
||||
final class JSONTest extends TestCase
|
||||
{
|
||||
public static function examples(): array
|
||||
{
|
||||
return [
|
||||
['true'],
|
||||
['false'],
|
||||
['null'],
|
||||
['"abc"'],
|
||||
['{"a b":"c d"}'],
|
||||
[' { " a b " : " c d " } '],
|
||||
[' [ { " a b " : " c d " } ] '],
|
||||
[' [ { " a b " : " c d " } , { "ef" : "gh" } ] '],
|
||||
['"some weird chars \\n in \\t strings \\u9999 should do it"'],
|
||||
['"this \\\\ is just a backslash"'],
|
||||
[<<<JSON
|
||||
[
|
||||
-1.23,
|
||||
null,
|
||||
true,
|
||||
[
|
||||
[
|
||||
{
|
||||
"a": true
|
||||
},
|
||||
{
|
||||
"b": false,
|
||||
"c": -1.23456789E+123
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
JSON,
|
||||
],
|
||||
[file_get_contents(__DIR__ . '/../../composer.json')],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider examples
|
||||
*/
|
||||
public function compare_to_json_decode(string $input)
|
||||
{
|
||||
$native = json_decode($input);
|
||||
$parsica = JSON::json()->tryString($input)->output();
|
||||
$this->assertEquals($native, $parsica);
|
||||
}
|
||||
}
|
||||
38
vendor/parsica-php/parsica/tests/JSON/NumberTest.php
vendored
Normal file
38
vendor/parsica-php/parsica/tests/JSON/NumberTest.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
|
||||
final class NumberTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function number()
|
||||
{
|
||||
$this->assertParses("0", JSON::number(), 0.0);
|
||||
$this->assertParses("0.1", JSON::number(), 0.1);
|
||||
$this->assertParses("0.15", JSON::number(), 0.15);
|
||||
$this->assertParses("0.10", JSON::number(), 0.1);
|
||||
$this->assertParses("-0.1", JSON::number(), -0.1);
|
||||
$this->assertParses("1.2345678", JSON::number(), 1.2345678);
|
||||
$this->assertParses("-1.2345678", JSON::number(), -1.2345678);
|
||||
$this->assertParses("-1.23456789E+123", JSON::number(), -1.23456789E+123);
|
||||
$this->assertParses("-1.23456789e-123", JSON::number(), -1.23456789E-123);
|
||||
$this->assertParses("-1E-123", JSON::number(), -1E-123);
|
||||
$this->assertParses("-1E-123 ", JSON::number(), -1E-123);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
45
vendor/parsica-php/parsica/tests/JSON/ObjectTest.php
vendored
Normal file
45
vendor/parsica-php/parsica/tests/JSON/ObjectTest.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
|
||||
final class ObjectTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function member()
|
||||
{
|
||||
$input = '"foo":"bar"';
|
||||
$parser = JSON::member();
|
||||
|
||||
$this->assertParses($input, $parser, ["foo" => "bar"]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function object()
|
||||
{
|
||||
$input = '{"foo":"bar","bar":"foo"}';
|
||||
$parser = JSON::object();
|
||||
|
||||
$result = $parser->run(new StringStream($input));
|
||||
|
||||
$this->assertParses($input, $parser, (object)["foo" => "bar", "bar" => "foo"]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
61
vendor/parsica-php/parsica/tests/JSON/StringLiteralTest.php
vendored
Normal file
61
vendor/parsica-php/parsica/tests/JSON/StringLiteralTest.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
|
||||
final class StringLiteralTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
public static function escapedChars(): array
|
||||
{
|
||||
return [
|
||||
// label => [literal that will appear in json, expected character it results in]
|
||||
"quotation mark" => ["\\\"", '"'],
|
||||
"reverse solidus" => ['\\\\', '\\'],
|
||||
"solidus" => ["\\/", '/'],
|
||||
"backspace" => ["\\b", mb_chr(8)],
|
||||
"formfeed" => ["\\f", mb_chr(12)],
|
||||
"linefeed" => ["\\n", "\n"],
|
||||
"carriage return" => ["\\r", "\r"],
|
||||
"horizontal tab" => ["\\t", "\t"],
|
||||
];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function empty()
|
||||
{
|
||||
$this->assertParses('""', JSON::stringLiteral(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider escapedChars
|
||||
*/
|
||||
public function escapes(string $input, string $expected)
|
||||
{
|
||||
$this->assertParses('"' . $input . '"', JSON::stringLiteral(), $expected);
|
||||
$this->assertParses('"a' . $input . '"', JSON::stringLiteral(), "a" . $expected);
|
||||
$this->assertParses('"' . $input . 'a"', JSON::stringLiteral(), $expected . "a");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function escape_hex()
|
||||
{
|
||||
$input = '"\\u0BB9\\u0BB2\\u0BCB\\u0020\\u0B89\\u0BB2\\u0B95\\u0BAE\\u0BCD"';
|
||||
$this->assertParses($input, JSON::stringLiteral(), "ஹலோ உலகம்");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
32
vendor/parsica-php/parsica/tests/JSON/TokenTest.php
vendored
Normal file
32
vendor/parsica-php/parsica/tests/JSON/TokenTest.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\JSON\token;
|
||||
|
||||
final class TokenTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function token()
|
||||
{
|
||||
$parser = JSON::token(char('a'));
|
||||
$input = "a \n \tb";
|
||||
$this->assertRemainder($input, $parser, "b");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
79
vendor/parsica-php/parsica/tests/JSON/WhitespaceTest.php
vendored
Normal file
79
vendor/parsica-php/parsica/tests/JSON/WhitespaceTest.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\JSON;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\JSON\JSON;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\JSON\ws;
|
||||
|
||||
final class WhitespaceTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function ws_empty()
|
||||
{
|
||||
$expected = null;
|
||||
$input = "";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ws_space()
|
||||
{
|
||||
$expected = null;
|
||||
$input = " ";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ws_tab()
|
||||
{
|
||||
$expected = null;
|
||||
$input = "\t";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ws_newline()
|
||||
{
|
||||
$expected = null;
|
||||
$input = "\n";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ws_carriage_return()
|
||||
{
|
||||
$expected = null;
|
||||
$input = "\r";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_bunch_of_whitespace()
|
||||
{
|
||||
$expected = null;
|
||||
$input = " \n \r \t a";
|
||||
$parser = JSON::ws();
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "a");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
80
vendor/parsica-php/parsica/tests/PHPUnit/ParserTestCaseTest.php
vendored
Normal file
80
vendor/parsica-php/parsica/tests/PHPUnit/ParserTestCaseTest.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\PHPUnit;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
|
||||
final class ParserTestCaseTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function strict_equality()
|
||||
{
|
||||
$this->assertEquals(1.23, "1.23",
|
||||
"A string and a float are equal in php");
|
||||
$this->assertNotSame(1.23, "1.23",
|
||||
"A string and a float are not the same in php");
|
||||
$this->assertSame(1.23, 1.23,
|
||||
"Primitives are compared by value");
|
||||
$this->assertEquals(new MyType(1.23), new MyType(1.23),
|
||||
"Weak equality works for objects");
|
||||
$this->assertNotSame(new MyType(1.23), new MyType(1.23),
|
||||
"...but value object instances with the same value do not have equality");
|
||||
$this->assertTrue((new MyType(1.23))->equals(new MyType(1.23)),
|
||||
"We can solve it with an equals() method, but the user doesn't always have "
|
||||
. "control of the types.");
|
||||
|
||||
$this->assertTrue(true,
|
||||
"Therefore, we need something that will behave like assertSame for primitives, "
|
||||
. "like assertEquals for objects of the same type,"
|
||||
. "and fail for everything else.");
|
||||
|
||||
$this->assertStrictlyEquals(1.23, 1.23);
|
||||
$this->assertStrictlyEquals(new MyType(1.23), new MyType(1.23));
|
||||
|
||||
/*
|
||||
$this->assertStrictlyEquals(1.23, "1.23",
|
||||
"should fail");
|
||||
$this->assertStrictlyEquals("1.23", 1.23,
|
||||
"should fail");
|
||||
$this->assertStrictlyEquals(new MyType(1.23), new MyType(7.89),
|
||||
"should fail");
|
||||
*/
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function strictlyEquals_for_arrays()
|
||||
{
|
||||
$this->assertStrictlyEquals(
|
||||
[1, new MyType(5.0)],
|
||||
[1, new MyType(5.0)]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final class MyType
|
||||
{
|
||||
private float $x;
|
||||
|
||||
public function __construct(float $x)
|
||||
{
|
||||
$this->x = $x;
|
||||
}
|
||||
|
||||
public function equals(MyType $other): bool
|
||||
{
|
||||
return $this->x === $other->x;
|
||||
}
|
||||
|
||||
}
|
||||
53
vendor/parsica-php/parsica/tests/ParseResult/AppendTest.php
vendored
Normal file
53
vendor/parsica-php/parsica/tests/ParseResult/AppendTest.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\ParseResult;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Internal\Fail;
|
||||
use Parsica\Parsica\Internal\Succeed;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
|
||||
final class AppendTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function append_strings()
|
||||
{
|
||||
$remainder = new StringStream("");
|
||||
$succeed1 = new Succeed("Parsed1", new StringStream("Remain1"));
|
||||
$succeed2 = new Succeed("Parsed2", new StringStream("Remain2"));
|
||||
$fail1 = new Fail("Expected1", new StringStream("Got1"));
|
||||
$fail2 = new Fail("Expected2", new StringStream("Got2"));
|
||||
|
||||
$this->assertStrictlyEquals(new Succeed("Parsed1Parsed2", new StringStream("Remain2")), $succeed1->append($succeed2));
|
||||
$this->assertStrictlyEquals(new Fail("Expected1", new StringStream("Got1")), $succeed1->append($fail1));
|
||||
$this->assertStrictlyEquals(new Fail("Expected1", new StringStream("Got1")), $fail1->append($succeed2));
|
||||
$this->assertStrictlyEquals(new Fail("Expected1", new StringStream("Got1")), $fail1->append($fail2));
|
||||
}
|
||||
/** @test */
|
||||
public function append_with_null()
|
||||
{
|
||||
$null1 = new Succeed(null, new StringStream("Remain Null 1"));
|
||||
$null2 = new Succeed(null, new StringStream("Remain Null 2"));
|
||||
$string = new Succeed("String", new StringStream("Remain String"));
|
||||
|
||||
$first = $string->append($null1);
|
||||
$this->assertStrictlyEquals(new Succeed("String", new StringStream("Remain Null 1")), $first);
|
||||
|
||||
$second = $null1->append($string);
|
||||
$this->assertStrictlyEquals(new Succeed("String", new StringStream("Remain String")), $second);
|
||||
|
||||
$both = $null1->append($null2);
|
||||
$this->assertStrictlyEquals(new Succeed(null, new StringStream("Remain Null 2")), $both);
|
||||
}
|
||||
}
|
||||
277
vendor/parsica-php/parsica/tests/ParseResult/ErrorReportingTest.php
vendored
Normal file
277
vendor/parsica-php/parsica/tests/ParseResult/ErrorReportingTest.php
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\ParseResult;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Internal\Position;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\many;
|
||||
use function Parsica\Parsica\newline;
|
||||
use function Parsica\Parsica\repeat;
|
||||
use function Parsica\Parsica\skipSpace;
|
||||
use function Parsica\Parsica\string;
|
||||
use function Parsica\Parsica\whitespace;
|
||||
|
||||
final class ErrorReportingTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function failing_on_the_first_token()
|
||||
{
|
||||
$parser = char('a');
|
||||
$input = new StringStream("bcd");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:1
|
||||
|
|
||||
1 | bcd
|
||||
| ^— column 1
|
||||
Unexpected 'b'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function failing_with_an_advanced_position()
|
||||
{
|
||||
$parser = char('a');
|
||||
$input = new StringStream("bcd", new Position("/path/to/file", 5, 10));
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
/path/to/file:5:10
|
||||
|
|
||||
5 | ...bcd
|
||||
| ^— column 10
|
||||
Unexpected 'b'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function works_for_parsers_with_more_than_one_character()
|
||||
{
|
||||
$parser = string("abc");
|
||||
$input = new StringStream("xyz", Position::initial("/path/to/file"));
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
/path/to/file:1:1
|
||||
|
|
||||
1 | xyz
|
||||
| ^— column 1
|
||||
Unexpected 'x'
|
||||
Expecting 'abc'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function advance_the_column_with_followedBy()
|
||||
{
|
||||
$parser = char('a')->sequence(char('b'));
|
||||
$input = new StringStream("axy");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:2
|
||||
|
|
||||
1 | ...xy
|
||||
| ^— column 2
|
||||
Unexpected 'x'
|
||||
Expecting 'b'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function works_with_custom_labels()
|
||||
{
|
||||
$parser = char('a')->sequence(char('b'))->label("a followed by b");
|
||||
$input = new StringStream("axy");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:2
|
||||
|
|
||||
1 | ...xy
|
||||
| ^— column 2
|
||||
Unexpected 'x'
|
||||
Expecting a followed by b
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tabs_move_column_position()
|
||||
{
|
||||
$parser = skipSpace()->sequence(char('a'));
|
||||
$input = new StringStream("\t\tbcdefgh");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:9
|
||||
|
|
||||
1 | ...bcdefgh
|
||||
| ^— column 9
|
||||
Unexpected 'b'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function line_numbers_space_out()
|
||||
{
|
||||
$parser = skipSpace()->sequence(char('a'));
|
||||
$input = new StringStream(str_repeat("\n", 99) . "b");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:100:1
|
||||
|
|
||||
100 | b
|
||||
| ^— column 1
|
||||
Unexpected 'b'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function multiline_input()
|
||||
{
|
||||
$parser = many(newline())->sequence(char('a'));
|
||||
$input = new StringStream("\n\n\nbcd\nxyz", Position::initial("/path/to/file"));
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
/path/to/file:4:1
|
||||
|
|
||||
4 | bcd
|
||||
| ^— column 1
|
||||
Unexpected 'b'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function indicate_position()
|
||||
{
|
||||
$parser = repeat(5, char('a'))->sequence(char('b'));
|
||||
$input = new StringStream("aaaaaXYZ");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:6
|
||||
|
|
||||
1 | ...XYZ
|
||||
| ^— column 6
|
||||
Unexpected 'X'
|
||||
Expecting 'b'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function repeatN()
|
||||
{
|
||||
$parser = repeat(5, char('a'))->sequence(char('b'));
|
||||
$input = new StringStream("aaaaXYZ");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:5
|
||||
|
|
||||
1 | ...XYZ
|
||||
| ^— column 5
|
||||
Unexpected 'X'
|
||||
Expecting 5 times 'a'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function indicate_shorter_position()
|
||||
{
|
||||
$parser = string("aa")->sequence(char('b'));
|
||||
$input = new StringStream("aaXYZ");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:3
|
||||
|
|
||||
1 | ...XYZ
|
||||
| ^— column 3
|
||||
Unexpected 'X'
|
||||
Expecting 'b'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function truncate_long_lines()
|
||||
{
|
||||
$parser = skipSpace()->sequence(string("Hello"))->sequence(char(','))->sequence(whitespace())->sequence(string("World"));
|
||||
$input = new StringStream("\n\n\n\n\n\n\n\n\nHello World! This is a really long line of more than 80 characters, if you count the spaces.");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:10:6
|
||||
|
|
||||
10 | ... World! This is a really long line of more than 80 characters, if you...
|
||||
| ^— column 6
|
||||
Unexpected <space>
|
||||
Expecting ','
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function dont_truncate_short_enough_lines()
|
||||
{
|
||||
$parser = char('a');
|
||||
$input = new StringStream("1234567890123456789012345678901234567890123456789012345678901234567890123456");
|
||||
$result = $parser->run($input);
|
||||
$expected =
|
||||
<<<ERROR
|
||||
<input>:1:1
|
||||
|
|
||||
1 | 1234567890123456789012345678901234567890123456789012345678901234567890123456
|
||||
| ^— column 1
|
||||
Unexpected '1'
|
||||
Expecting 'a'
|
||||
ERROR;
|
||||
|
||||
$this->assertEquals($expected, $result->errorMessage());
|
||||
}
|
||||
|
||||
}
|
||||
40
vendor/parsica-php/parsica/tests/ParseResult/FunctorTest.php
vendored
Normal file
40
vendor/parsica-php/parsica/tests/ParseResult/FunctorTest.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\ParseResult;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Internal\Fail;
|
||||
use Parsica\Parsica\Internal\Succeed;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
|
||||
final class FunctorTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function map_over_ParseSuccess()
|
||||
{
|
||||
$succeed = new Succeed("parsed", new StringStream("remainder"));
|
||||
$expected = new Succeed("PARSED", new StringStream("remainder"));
|
||||
$this->assertEquals($expected, $succeed->map('strtoupper'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function map_over_ParseFailure()
|
||||
{
|
||||
$remainder = new StringStream("");
|
||||
$fail = new Fail("expected", new StringStream("got"));
|
||||
$expected = new Fail("expected", new StringStream("got"));
|
||||
$this->assertEquals($expected, $fail->map('strtoupper'));
|
||||
}
|
||||
|
||||
}
|
||||
39
vendor/parsica-php/parsica/tests/ParseResult/ParseResultTest.php
vendored
Normal file
39
vendor/parsica-php/parsica/tests/ParseResult/ParseResultTest.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\ParseResult;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
|
||||
final class ParseResultTest extends TestCase
|
||||
{
|
||||
|
||||
/** @test */
|
||||
public function ParseSuccess_continueWith()
|
||||
{
|
||||
$input = new StringStream("abc");
|
||||
$success = char('a')->run($input);
|
||||
$result = $success->continueWith(char('b'));
|
||||
$this->assertTrue($result->isSuccess());
|
||||
$this->assertEquals("c", $result->remainder());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ParseFailure_continueWith()
|
||||
{
|
||||
$input = new StringStream("abc");
|
||||
$fail = char('x')->run($input);
|
||||
$result = $fail->continueWith(char('a'));
|
||||
$this->assertTrue($result->isFail());
|
||||
}
|
||||
|
||||
}
|
||||
128
vendor/parsica-php/parsica/tests/Parser/AlternativeTest.php
vendored
Normal file
128
vendor/parsica-php/parsica/tests/Parser/AlternativeTest.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\alphaChar;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\digitChar;
|
||||
use function Parsica\Parsica\either;
|
||||
use function Parsica\Parsica\eof;
|
||||
use function Parsica\Parsica\ignore;
|
||||
use function Parsica\Parsica\keepFirst;
|
||||
use function Parsica\Parsica\many;
|
||||
use function Parsica\Parsica\punctuationChar;
|
||||
use function Parsica\Parsica\some;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class AlternativeTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function or()
|
||||
{
|
||||
$parser = char('a')->or(char('b'));
|
||||
$this->assertParses("a123", $parser, "a");
|
||||
$this->assertParses("b123", $parser, "b");
|
||||
$this->assertParseFails("123", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function alternatives_for_strings_with_similar_starts()
|
||||
{
|
||||
$jan =
|
||||
either(
|
||||
string("Jan")->thenIgnore(eof()),
|
||||
string("January")->thenIgnore(eof()),
|
||||
);
|
||||
$this->assertParses("Jan", $jan, "Jan");
|
||||
$this->assertParses("January", $jan, "January");
|
||||
|
||||
// Reverse order
|
||||
$jan =
|
||||
either(
|
||||
string("January")->thenIgnore(eof()),
|
||||
string("Jan")->thenIgnore(eof()),
|
||||
);
|
||||
$this->assertParses("Jan", $jan, "Jan");
|
||||
$this->assertParses("January", $jan, "January");
|
||||
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function or_order_matters()
|
||||
{
|
||||
// The order of clauses in an or() matters. If we do the following parser definition, the parser will consume
|
||||
// "http", even if the strings starts with "https", leaving "s://..." as the remainder.
|
||||
$parser = string('http')->or(string('https'));
|
||||
$input = "https://verraes.net";
|
||||
$this->assertRemainder($input, $parser, "s://verraes.net");
|
||||
|
||||
// The solution is to consider the order of or clauses:
|
||||
$parser = string('https')->or(string('http'));
|
||||
$input = "https://verraes.net";
|
||||
$this->assertParses($input, $parser, "https");
|
||||
$this->assertRemainder($input, $parser, "://verraes.net");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function optional()
|
||||
{
|
||||
$parser = char('a')->optional();
|
||||
$this->assertParses("", $parser, null, "EOF");
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertRemainder("abc", $parser, "bc");
|
||||
|
||||
$this->assertParses("bc", $parser, null);
|
||||
$this->assertRemainder("bc", $parser, "bc");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function many()
|
||||
{
|
||||
$parser = many(alphaChar());
|
||||
$this->assertParses("123", $parser, []);
|
||||
$this->assertParses("Hello", $parser, ["H", "e", "l", "l", "o"]);
|
||||
|
||||
$parser = many(alphaChar()->append(digitChar()));
|
||||
$this->assertParses("1a2b3c", $parser, []);
|
||||
$this->assertParses("a1b2c3", $parser, ["a1", "b2", "c3"]);
|
||||
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function some()
|
||||
{
|
||||
$parser = many(
|
||||
keepFirst(
|
||||
some(alphaChar())->map(fn($a) => implode('', $a)),
|
||||
punctuationChar()->optional()
|
||||
)
|
||||
);
|
||||
$input = "abc,def,ghi";
|
||||
$expected = ["abc","def","ghi"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function some_2()
|
||||
{
|
||||
$parser = some(string("foo"));
|
||||
$this->assertParseFails("bla", $parser);
|
||||
$this->assertParses("foo", $parser, ["foo"]);
|
||||
$this->assertParses("foobar", $parser, ["foo"]);
|
||||
$this->assertParses("foofoo", $parser, ["foo", "foo"]);
|
||||
$this->assertParses("foofoobar", $parser, ["foo", "foo"]);
|
||||
}
|
||||
|
||||
}
|
||||
55
vendor/parsica-php/parsica/tests/Parser/AppendTest.php
vendored
Normal file
55
vendor/parsica-php/parsica/tests/Parser/AppendTest.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
|
||||
final class AppendTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function append_strings()
|
||||
{
|
||||
$parser = char('a')->append(char('b'));
|
||||
$this->assertParses("abc", $parser, "ab");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function append_array()
|
||||
{
|
||||
$a = char('a')->map(fn($x) => [$x]);
|
||||
$b = char('b')->map(fn($x) => [$x]);
|
||||
$this->assertParses("abc", $a->append($b), ['a', 'b']);
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function append_non_semigroup()
|
||||
{
|
||||
$a = char('a')->map(fn($v)=> new NotASemigroup($v));
|
||||
$b = char('b')->map(fn($v)=> new NotASemigroup($v));
|
||||
$this->expectException(Exception::class);
|
||||
$a->append($b)->run(new StringStream('abc'));
|
||||
}
|
||||
}
|
||||
|
||||
final class NotASemigroup
|
||||
{
|
||||
|
||||
public function __construct($_)
|
||||
{
|
||||
}
|
||||
}
|
||||
261
vendor/parsica-php/parsica/tests/Parser/ApplicativeTest.php
vendored
Normal file
261
vendor/parsica-php/parsica/tests/Parser/ApplicativeTest.php
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use \InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{alphaChar,
|
||||
anything,
|
||||
atLeastOne,
|
||||
char,
|
||||
Curry\curry,
|
||||
digitChar,
|
||||
keepFirst,
|
||||
keepSecond,
|
||||
pure,
|
||||
repeat,
|
||||
repeatList,
|
||||
sepBy,
|
||||
sepBy1,
|
||||
sepBy2,
|
||||
skipSpace,
|
||||
string};
|
||||
|
||||
final class ApplicativeTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function pure()
|
||||
{
|
||||
$parser = pure("<3");
|
||||
$this->assertParses("(╯°□°)╯", $parser, "<3");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequential_application()
|
||||
{
|
||||
$upper = pure(fn(string $v) => strtoupper($v));
|
||||
$hello = string('hello');
|
||||
|
||||
// Parser<callable(a):b> -> Parser<a> -> Parser<b>
|
||||
$parser = $upper->apply($hello);
|
||||
$this->assertParses("hello", $parser, "HELLO");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequential_application_2()
|
||||
{
|
||||
$multiply = curry(fn($x, $y) => $x * $y);
|
||||
$number = digitChar()->map(fn($s) => intval($s));
|
||||
|
||||
// Parser<callable(a, b):c> -> Parser<a> -> Parser<b> -> Parser<c>
|
||||
$parser = pure($multiply)->apply($number)->apply($number);
|
||||
$input = "35";
|
||||
$this->assertParses($input, $parser, 15);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequential_application_3()
|
||||
{
|
||||
$sort3 = curry(function($x, $y, $z) {
|
||||
$arr = [$x, $y, $z];
|
||||
sort($arr);
|
||||
return implode('', $arr);
|
||||
});
|
||||
|
||||
$parser = pure($sort3)->apply(anything())->apply(anything())->apply(anything());
|
||||
$this->assertParses("735", $parser, "357");
|
||||
$this->assertParses("cba", $parser, "abc");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequential_application_throws_when_not_a_callable()
|
||||
{
|
||||
$parser = pure("ceci n'est pas un callable")->apply(anything());
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$parser->tryString("foo");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function keepFirst()
|
||||
{
|
||||
$parser = keepFirst(char('a'), char('b'));
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertRemainder("abc", $parser, "c");
|
||||
$this->assertParseFails("ac", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function keepFirst_with_ignore()
|
||||
{
|
||||
$parser = keepFirst(char('a'), skipSpace());
|
||||
$this->assertParses("a ", $parser, "a");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function keepSecond()
|
||||
{
|
||||
$parser = keepSecond(char('a'), char('b'));
|
||||
$this->assertParses("abc", $parser, "b");
|
||||
$this->assertRemainder("abc", $parser, "c");
|
||||
$this->assertParseFails("ac", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sepBy()
|
||||
{
|
||||
$parser = sepBy(string('||'), atLeastOne(alphaChar()));
|
||||
|
||||
$input = "";
|
||||
$expected = [];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||bar||";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar||baz";
|
||||
$expected = ["foo", "bar", "baz"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "||";
|
||||
$this->assertParses($input, $parser, [], "The sepBy parser always succeed, even if it doesn't find anything");
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar||baz";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar||";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function sepBy1()
|
||||
{
|
||||
$parser = sepBy1(string('||'), atLeastOne(alphaChar()));
|
||||
|
||||
$input = "";
|
||||
$this->assertParseFails($input, $parser, "at least one A-Z or a-z, separated by '||'");
|
||||
|
||||
$input = "||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||baz";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
|
||||
$input = "foo";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||bar||";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar||baz";
|
||||
$expected = ["foo", "bar", "baz"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sepBy2()
|
||||
{
|
||||
$parser = sepBy2(string('||'), atLeastOne(alphaChar()));
|
||||
|
||||
$input = "";
|
||||
$this->assertParseFails($input, $parser, "at least two of (at least one A-Z or a-z), separated by '||'");
|
||||
|
||||
$input = "||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||baz";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
|
||||
$input = "foo";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "foo||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "foo||bar";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||bar||";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar||baz";
|
||||
$expected = ["foo", "bar", "baz"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function repeat_vs_repeatList()
|
||||
{
|
||||
$parser = repeat(5, alphaChar());
|
||||
$this->assertParses("hello", $parser, "hello");
|
||||
$parser = repeatList(5, alphaChar());
|
||||
$this->assertParses("hello", $parser, ["h", "e", "l", "l", "o"]);
|
||||
|
||||
$parser = repeatList(3, repeat(3, alphaChar()));
|
||||
$this->assertParses("EURUSDGBP", $parser, ["EUR", "USD", "GBP"]);
|
||||
}
|
||||
}
|
||||
|
||||
67
vendor/parsica-php/parsica/tests/Parser/FunctorTest.php
vendored
Normal file
67
vendor/parsica-php/parsica/tests/Parser/FunctorTest.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\float;
|
||||
use function Parsica\Parsica\sequence;
|
||||
|
||||
final class FunctorTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function map()
|
||||
{
|
||||
$parser =
|
||||
char('a')->followedBy(char('b'))
|
||||
->map('strtoupper');
|
||||
|
||||
$expected = "B";
|
||||
|
||||
$this->assertParses("abca", $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function simple_eur()
|
||||
{
|
||||
$parser = sequence(
|
||||
char('€'),
|
||||
float()->map(fn($v)=>new SimpleEur((float) $v))
|
||||
);
|
||||
$this->assertParses("€1.25", $parser, new SimpleEur(1.25));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class MyType1
|
||||
{
|
||||
private $val;
|
||||
|
||||
public function __construct($val)
|
||||
{
|
||||
$this->val = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class SimpleEur
|
||||
{
|
||||
private float $val;
|
||||
|
||||
public function __construct(float $val)
|
||||
{
|
||||
$this->val = $val;
|
||||
}
|
||||
|
||||
}
|
||||
56
vendor/parsica-php/parsica/tests/Parser/LabelTest.php
vendored
Normal file
56
vendor/parsica-php/parsica/tests/Parser/LabelTest.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\any;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\fail;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class LabelTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function or_label()
|
||||
{
|
||||
$parser = char('a')->or(char('b'));
|
||||
$input = "c";
|
||||
$result = $parser->run(new StringStream($input));
|
||||
$this->assertEquals("'a' or 'b'", $result->expected());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function or_label2()
|
||||
{
|
||||
$parser = string('hello')->or(string('world'));
|
||||
$input = "foo";
|
||||
$result = $parser->run(new StringStream($input));
|
||||
$this->assertEquals("'hello' or 'world'", $result->expected());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function any_label()
|
||||
{
|
||||
$parser = any(char('a'), char('b'), string("hello"));
|
||||
$input = "foo";
|
||||
$result = $parser->run(new StringStream($input));
|
||||
$this->assertEquals("'a' or 'b' or 'hello'", $result->expected());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function failure_label()
|
||||
{
|
||||
$parser = fail("reason");
|
||||
$result = $parser->run(new StringStream("foo"));
|
||||
$this->assertEquals("reason", $result->expected());
|
||||
}
|
||||
}
|
||||
80
vendor/parsica-php/parsica/tests/Parser/MonadTest.php
vendored
Normal file
80
vendor/parsica-php/parsica/tests/Parser/MonadTest.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\anySingle;
|
||||
use function Parsica\Parsica\bind;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\pure;
|
||||
use function Parsica\Parsica\sequence;
|
||||
|
||||
final class MonadTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function bind()
|
||||
{
|
||||
// This parser checks if the second character is the same as the first, by taking the output of the first
|
||||
// parser and binding it to a function that produces the second parser from that output.
|
||||
$parser = anySingle()->bind(fn(string $c) => char($c));
|
||||
$this->assertParses("aa", $parser, "a");
|
||||
$this->assertParses("bb", $parser, "b");
|
||||
$this->assertParseFails("ab", $parser);
|
||||
|
||||
$parser = bind(anySingle(), fn(string $c) => char($c));
|
||||
$this->assertParses("aa", $parser, "a");
|
||||
$this->assertParses("bb", $parser, "b");
|
||||
$this->assertParseFails("ab", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function bind_fails()
|
||||
{
|
||||
// If the first parser fails, bind() returns the first one.
|
||||
$parser = char('x')->bind(fn(string $c) => char($c));
|
||||
$this->assertParses("xx", $parser, "x");
|
||||
$this->assertParseFails("yx", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequence()
|
||||
{
|
||||
$parser = char('a')->sequence(char('b'));
|
||||
$this->assertParses("ab", $parser, "b");
|
||||
$this->assertParseFails("aa", $parser);
|
||||
|
||||
$parser = sequence(char('a'), char('b'));
|
||||
$this->assertParses("ab", $parser, "b");
|
||||
$this->assertParseFails("aa", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequence_error_should_show_the_label_of_the_failing_parser()
|
||||
{
|
||||
$parser = char('a')->sequence(char('b'));
|
||||
$this->assertParseFails("X", $parser, "'a'");
|
||||
$this->assertParseFails("aX", $parser, "'b'");
|
||||
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function pure()
|
||||
{
|
||||
$parser = pure("hi");
|
||||
$this->assertParses("something else", $parser, "hi");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
38
vendor/parsica-php/parsica/tests/Parser/ParserTest.php
vendored
Normal file
38
vendor/parsica-php/parsica/tests/Parser/ParserTest.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class ParserTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function label()
|
||||
{
|
||||
$parser = string(":-)");
|
||||
$this->assertParseFails("x", $parser, "':-)'");
|
||||
|
||||
$labeled = $parser->label("smiley");
|
||||
$this->assertParseFails("x", $labeled, "smiley");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function followedBy()
|
||||
{
|
||||
$parser = char('a')->followedBy(char('b'));
|
||||
$this->assertParses("abc", $parser, "b");
|
||||
}
|
||||
}
|
||||
43
vendor/parsica-php/parsica/tests/Parser/RunningParsersTest.php
vendored
Normal file
43
vendor/parsica-php/parsica/tests/Parser/RunningParsersTest.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\ParserHasFailed;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\skipSpace;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class RunningParsersTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function try_throws()
|
||||
{
|
||||
$parser = char('a');
|
||||
$result = $parser->try(new StringStream("a"));
|
||||
$this->assertSame("a", $result->output());
|
||||
|
||||
$this->expectException(ParserHasFailed::class);
|
||||
$result = $parser->try(new StringStream("b"));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function continueFrom()
|
||||
{
|
||||
$parser = string('hello')->sequence(skipSpace());
|
||||
$result = $parser->try(new StringStream("hello world!"));
|
||||
$parser2 = string("world");
|
||||
$result2 = $parser2->continueFrom($result);
|
||||
$this->assertEquals("world", $result2->output());
|
||||
$this->assertEquals("!", $result2->remainder());
|
||||
}
|
||||
}
|
||||
33
vendor/parsica-php/parsica/tests/Parser/unicodeTest.php
vendored
Normal file
33
vendor/parsica-php/parsica/tests/Parser/unicodeTest.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica\Parser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\char;
|
||||
|
||||
final class unicodeTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function mbstring_must_be_installed()
|
||||
{
|
||||
$this->assertTrue(function_exists('mb_detect_encoding'), "ext-mbstring must be installed.");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function parses_unicode()
|
||||
{
|
||||
$parser = char("🥰");
|
||||
$this->assertParses("🥰 hello", $parser, "🥰");
|
||||
}
|
||||
}
|
||||
114
vendor/parsica-php/parsica/tests/PolishNotationTest.php
vendored
Normal file
114
vendor/parsica-php/parsica/tests/PolishNotationTest.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\between;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\collect;
|
||||
use function Parsica\Parsica\digitChar;
|
||||
use function Parsica\Parsica\eof;
|
||||
use function Parsica\Parsica\keepFirst;
|
||||
use function Parsica\Parsica\recursive;
|
||||
use function Parsica\Parsica\skipHSpace;
|
||||
|
||||
final class PolishNotationTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/**
|
||||
* @var Parser
|
||||
*/
|
||||
private Parser $expr;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$token = fn(Parser $parser) => keepFirst($parser, skipHSpace());
|
||||
$term = digitChar();
|
||||
$parens = fn(Parser $parser)
|
||||
: Parser => $token(between($token(char('(')), $token(char(')')), $parser));
|
||||
|
||||
|
||||
$expr = recursive();
|
||||
|
||||
|
||||
$plus = collect(
|
||||
$token(char('+')),
|
||||
$token($expr),
|
||||
$token($expr)
|
||||
)->map(fn($o) => "(+ {$o[1]} {$o[2]})");
|
||||
|
||||
$times = collect(
|
||||
$token(char('*')),
|
||||
$token($expr),
|
||||
$token($expr)
|
||||
)->map(fn($o) => "(* {$o[1]} {$o[2]})");
|
||||
|
||||
$expr->recurse($term->or($plus)->or($times)->or($parens($expr)));
|
||||
|
||||
$this->expr = $expr->thenEof();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider polishExamples
|
||||
*/
|
||||
public function polishNotation(string $input, $output)
|
||||
{
|
||||
$this->assertParses($input, $this->expr, $output);
|
||||
}
|
||||
|
||||
public function polishExamples()
|
||||
{
|
||||
$examples = [
|
||||
['1', '1'],
|
||||
['+ 1 2', '(+ 1 2)'],
|
||||
['+ 1 + 2 3', '(+ 1 (+ 2 3))'],
|
||||
['+ + 1 2 + 3 4', '(+ (+ 1 2) (+ 3 4))'],
|
||||
['+ 1 (+ 2 3)', '(+ 1 (+ 2 3))'],
|
||||
['((+ 1 + 2 (+ 3 4)))', '(+ 1 (+ 2 (+ 3 4)))'],
|
||||
['(1)', '1'],
|
||||
['((1))', '1'],
|
||||
['(((1)))', '1'],
|
||||
['* 1 2', '(* 1 2)'],
|
||||
['+ 1 * 2 3', '(+ 1 (* 2 3))'],
|
||||
['* 1 + 2 3', '(* 1 (+ 2 3))'],
|
||||
['* 1 * 2 3', '(* 1 (* 2 3))'],
|
||||
['((+ 1 * 2 (+ 3 4)))', '(+ 1 (* 2 (+ 3 4)))'],
|
||||
];
|
||||
|
||||
return array_combine(array_column($examples, 0), $examples);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider badExamples
|
||||
*/
|
||||
public function theseAreNotPolishNotation(string $input)
|
||||
{
|
||||
$this->assertParseFails($input, $this->expr);
|
||||
}
|
||||
|
||||
public function badExamples()
|
||||
{
|
||||
$examples = [
|
||||
[''],
|
||||
['()'],
|
||||
['1 2'],
|
||||
['(1 2'],
|
||||
['1 2)'],
|
||||
['(1 2)'],
|
||||
['(+ 2)'],
|
||||
['+ 1 2)'],
|
||||
['(1 + 2)'],
|
||||
['1 + 2)'],
|
||||
['(1 2 +)'],
|
||||
];
|
||||
|
||||
return array_combine(array_column($examples, 0), $examples);
|
||||
}
|
||||
}
|
||||
|
||||
93
vendor/parsica-php/parsica/tests/assembleTest.php
vendored
Normal file
93
vendor/parsica-php/parsica/tests/assembleTest.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\assemble;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\string;
|
||||
|
||||
final class assembleTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function assemble_string()
|
||||
{
|
||||
$parser = assemble(
|
||||
string('first'),
|
||||
string('second'),
|
||||
);
|
||||
$this->assertParses("firstsecond", $parser, "firstsecond");
|
||||
$this->assertRemainder("firstsecond", $parser, "");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function assemble_string_ignore()
|
||||
{
|
||||
$parser = assemble(
|
||||
string('first')->thenIgnore(char('-')),
|
||||
string('second'),
|
||||
);
|
||||
$this->assertParses("first-second", $parser, "firstsecond");
|
||||
$this->assertRemainder("first-second", $parser, "");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function assemble_arrays()
|
||||
{
|
||||
$toArray = fn($v) => [$v];
|
||||
|
||||
$parser = assemble(
|
||||
string('first')->map($toArray),
|
||||
string('second')->map($toArray),
|
||||
);
|
||||
|
||||
$input = "firstsecond";
|
||||
$expected = ["first", "second"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function assemble_different_types_but_the_others_are_ignored()
|
||||
{
|
||||
// @todo this could be more elegant
|
||||
$toArray = fn($v) => [$v];
|
||||
$parser = assemble(
|
||||
char('[')->sequence(
|
||||
string('first')->map($toArray)
|
||||
),
|
||||
char(',')->sequence(
|
||||
string('second')->map($toArray)
|
||||
)->thenIgnore(char(']')),
|
||||
);
|
||||
|
||||
$input = "[first,second]";
|
||||
$expected = ["first", "second"];
|
||||
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function label()
|
||||
{
|
||||
$parser = assemble(
|
||||
string('first'),
|
||||
string('second'),
|
||||
);
|
||||
$this->assertParseFails("X", $parser, "'first'");
|
||||
$this->assertParseFails("firsX", $parser, "'first'");
|
||||
$this->assertParseFails("firstX", $parser, "'second'");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
125
vendor/parsica-php/parsica/tests/charactersTest.php
vendored
Normal file
125
vendor/parsica-php/parsica/tests/charactersTest.php
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\Parser;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{alphaChar,
|
||||
alphaNumChar,
|
||||
binDigitChar,
|
||||
blank,
|
||||
char,
|
||||
charI,
|
||||
controlChar,
|
||||
digitChar,
|
||||
hexDigitChar,
|
||||
lowerChar,
|
||||
octDigitChar,
|
||||
printChar,
|
||||
punctuationChar,
|
||||
space,
|
||||
string,
|
||||
stringI,
|
||||
tab,
|
||||
upperChar,
|
||||
whitespace};
|
||||
|
||||
final class charactersTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function char()
|
||||
{
|
||||
$this->assertParses("abc", char('a'), "a");
|
||||
$this->assertRemainder("abc", char('a'), "bc");
|
||||
$this->assertParseFails("bc", char('a'), "'a'");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function charI()
|
||||
{
|
||||
$this->assertParses("abc", charI('a'), "a");
|
||||
$this->assertParses("ABC", charI('a'), "A");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function charI_label()
|
||||
{
|
||||
$this->assertParseFails("foo", charI('a'), "'a' or 'A'");
|
||||
$this->assertParseFails("foo", charI('%'), "'%'");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function string()
|
||||
{
|
||||
$this->assertParses("abcde", string('abc'), "abc");
|
||||
$this->assertParseFails("babc", string('abc'), "'abc'");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function stringI()
|
||||
{
|
||||
$parser = stringI('hello world');
|
||||
$input = "hElLO WoRlD!!1!";
|
||||
$expected = "hElLO WoRlD";
|
||||
$this->assertParses($input, $parser, $expected, "stringI() should be case-preserving");
|
||||
$this->assertRemainder($input, $parser, "!!1!");
|
||||
}
|
||||
|
||||
public function characterParsers(): array
|
||||
{
|
||||
$tests = [
|
||||
// dataSet => [Parser, example character]
|
||||
'controlChar' => [controlChar(), mb_chr(0x05)],
|
||||
'printChar_a' => [printChar(), "a"],
|
||||
'printChar_%' => [printChar(), "%"],
|
||||
];
|
||||
|
||||
|
||||
$types = [
|
||||
// dataSet => [Parser, [example character]]
|
||||
'upperChar' => [upperChar(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"],
|
||||
'lowerChar' => [lowerChar(), "abcdefghijklmnopqrstuvwxyz"],
|
||||
'alphaChar' => [alphaChar(), "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"],
|
||||
'alphaNumChar' => [alphaNumChar(), "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"],
|
||||
'digitChar' => [digitChar(), "0123456789"],
|
||||
'binDigitChar' => [binDigitChar(), "01"],
|
||||
'octDigitChar' => [octDigitChar(), "01234567"],
|
||||
'hexDigitChar' => [hexDigitChar(), "0123456789abcdefABCDEF"],
|
||||
'punctuationChar' => [punctuationChar(), "!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"],
|
||||
'whitespace' => [whitespace(), " \t\n\r\f\v"],
|
||||
'space' => [space(), " "],
|
||||
'tab' => [tab(), "\t"],
|
||||
'blank' => [blank(), "\t "],
|
||||
];
|
||||
|
||||
foreach ($types as $name => [$parser, $chars]) {
|
||||
foreach (mb_str_split($chars) as $char) {
|
||||
$tests["{$name}: {$char}"] = [$parser, $char];
|
||||
}
|
||||
}
|
||||
|
||||
return $tests;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider characterParsers
|
||||
*/
|
||||
public function character_parsers(Parser $parser, string $example)
|
||||
{
|
||||
$this->assertParses($example, $parser, $example);
|
||||
}
|
||||
}
|
||||
|
||||
462
vendor/parsica-php/parsica/tests/combinatorsTest.php
vendored
Normal file
462
vendor/parsica-php/parsica/tests/combinatorsTest.php
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{alphaChar,
|
||||
alphaNumChar,
|
||||
any,
|
||||
anySingle,
|
||||
anySingleBut,
|
||||
atLeastOne,
|
||||
between,
|
||||
char,
|
||||
choice,
|
||||
collect,
|
||||
digitChar,
|
||||
either,
|
||||
float,
|
||||
identity,
|
||||
keepFirst,
|
||||
lookAhead,
|
||||
many,
|
||||
noneOf,
|
||||
noneOfS,
|
||||
notFollowedBy,
|
||||
oneOf,
|
||||
oneOfS,
|
||||
optional,
|
||||
punctuationChar,
|
||||
repeat,
|
||||
repeatList,
|
||||
sepBy,
|
||||
sepBy1,
|
||||
sequence,
|
||||
skipSpace,
|
||||
string,
|
||||
stringI,
|
||||
takeRest,
|
||||
whitespace};
|
||||
|
||||
final class combinatorsTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function identity()
|
||||
{
|
||||
$parser = identity(char('a'));
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertRemainder("abc", $parser, "bc");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function identity_does_not_show_up_in_error_messages()
|
||||
{
|
||||
$parser = identity(char('a'));
|
||||
$this->assertParseFails("bc", $parser, "'a'");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function thenIgnore()
|
||||
{
|
||||
$parser = string('abcd')
|
||||
->thenIgnore(char('-'))
|
||||
->append(string('efgh'));
|
||||
$this->assertParses("abcd-efgh", $parser, "abcdefgh");
|
||||
$this->assertParseFails("abcdefgh", $parser);
|
||||
|
||||
// smae with optional dash
|
||||
$parser = string('abcd')
|
||||
->thenIgnore(optional(char('-')))
|
||||
->append(string('efgh'));
|
||||
$this->assertParses("abcdefgh", $parser, "abcdefgh");
|
||||
$this->assertParses("abcd-efgh", $parser, "abcdefgh");
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function anySingle()
|
||||
{
|
||||
$parser = anySingle();
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("a", $parser, "a");
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertParses(":", $parser, ":");
|
||||
$this->assertParses(":-)", $parser, ":");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function anySingleBut()
|
||||
{
|
||||
$parser = anySingleBut("x");
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("a", $parser, "a");
|
||||
$this->assertRemainder("a", $parser, "");
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertRemainder("abc", $parser, "bc");
|
||||
$this->assertParseFails("x", $parser);
|
||||
$this->assertParseFails("xxx", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function oneOf()
|
||||
{
|
||||
$parser = oneOf(['a', 'b', 'c']);
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("a", $parser, "a");
|
||||
$this->assertParses("ax", $parser, "a");
|
||||
$this->assertParses("b", $parser, "b");
|
||||
$this->assertParses("c", $parser, "c");
|
||||
$this->assertParseFails("xyz", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function oneOf_expects_single_chars()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$parser = oneOf(['a', "long", "c"]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function oneOfS()
|
||||
{
|
||||
$parser = oneOfS("abc");
|
||||
$this->assertParses("ax", $parser, "a");
|
||||
$this->assertParseFails("xyz", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function noneOf()
|
||||
{
|
||||
$parser = noneOf(['a', 'b', 'c']);
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParseFails("a", $parser);
|
||||
$this->assertParseFails("ax", $parser);
|
||||
$this->assertParseFails("b", $parser);
|
||||
$this->assertParses("xyz", $parser, "x");
|
||||
$this->assertRemainder("xyz", $parser, "yz");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function noneOfS()
|
||||
{
|
||||
$parser = noneOfS("abc");
|
||||
$this->assertParseFails("ax", $parser);
|
||||
$this->assertParses("xyz", $parser, "x");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeRest()
|
||||
{
|
||||
$parser = takeRest();
|
||||
$this->assertSucceedOnEOF($parser);
|
||||
$this->assertParses("xyz", $parser, "xyz");
|
||||
$this->assertRemainder("xyz", $parser, "");
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function either()
|
||||
{
|
||||
$parser = either(char('a'), char('b'));
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("abc", $parser, "a");
|
||||
$this->assertRemainder("abc", $parser, "bc");
|
||||
$this->assertParses("bc", $parser, "b");
|
||||
$this->assertRemainder("bc", $parser, "c");
|
||||
$this->assertParseFails("cd", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function either_with_mixed_type()
|
||||
{
|
||||
$parser = either(
|
||||
atLeastOne(digitChar())->map(fn(string $o)=> intval($o))->thenEof(),
|
||||
atLeastOne(alphaNumChar())->thenEof(),
|
||||
);
|
||||
|
||||
$actual = $parser->tryString("123")->output();
|
||||
$this->assertIsInt($actual);
|
||||
$this->assertEquals("123", $actual);
|
||||
|
||||
$actual = $parser->tryString("123a")->output();
|
||||
$this->assertIsString($actual);
|
||||
$this->assertEquals("123a", $actual);
|
||||
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sequence()
|
||||
{
|
||||
$parser = sequence(char('a'), char('b'));
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("abc", $parser, "b");
|
||||
$this->assertRemainder("abc", $parser, "c");
|
||||
$this->assertParseFails("acc", $parser);
|
||||
$this->assertParseFails("cab", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function collect()
|
||||
{
|
||||
$parser =
|
||||
collect(
|
||||
string("Hello")
|
||||
->append(skipSpace())->thenIgnore(char(','))
|
||||
->append(skipSpace()),
|
||||
string("world")
|
||||
->thenIgnore(char('!'))
|
||||
);
|
||||
|
||||
$expected = ["Hello", "world"];
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("Hello , world!", $parser, $expected);
|
||||
$this->assertParses("Hello,world!", $parser, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function collectFails()
|
||||
{
|
||||
$parser =
|
||||
collect(
|
||||
string("Hello"),
|
||||
string("World")
|
||||
);
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParseFails("HiWorld", $parser, "'Hello'");
|
||||
$this->assertParseFails("HelloPlanet", $parser, "'World'");
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function atLeastOne()
|
||||
{
|
||||
$parser = atLeastOne(char('a'));
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParses("a", $parser, "a");
|
||||
$this->assertParses("aa", $parser, "aa");
|
||||
$this->assertParses("aaaaa", $parser, "aaaaa");
|
||||
$this->assertParses("aaabb", $parser, "aaa");
|
||||
$this->assertParseFails("bb", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function any_()
|
||||
{
|
||||
$symbol = any(string("€"), string("$"));
|
||||
$amount = float()->map('floatval');
|
||||
$money = collect($symbol, $amount);
|
||||
|
||||
$this->assertFailOnEOF($money);
|
||||
$this->assertParses("€", $symbol, "€");
|
||||
$this->assertParses("15.23", $amount, 15.23);
|
||||
$this->assertParses("€15.23", $money, ["€", 15.23]);
|
||||
$this->assertParses("$15", $money, ["$", 15.0]);
|
||||
$this->assertParseFails("£12.13", $money);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function choice()
|
||||
{
|
||||
$symbol = choice(string("€"), string("$"));
|
||||
$amount = float()->map('floatval');
|
||||
$money = collect($symbol, $amount);
|
||||
|
||||
$this->assertFailOnEOF($money);
|
||||
$this->assertParses("€", $symbol, "€");
|
||||
$this->assertParses("15.23", $amount, 15.23);
|
||||
$this->assertParses("€15.23", $money, ["€", 15.23]);
|
||||
$this->assertParses("$15", $money, ["$", 15.0]);
|
||||
$this->assertParseFails("£12.13", $money);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipMany()
|
||||
{
|
||||
//skipMany p applies the parser p zero or more times, skipping its result.
|
||||
self::markTestIncomplete();
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function keepFirst__inside_a_nested_parser()
|
||||
{
|
||||
$movies = any(stringI('movie'), stringI('movies'), stringI('film'), stringI('films'))->followedBy(skipSpace());
|
||||
$number = atLeastOne(digitChar())->map('intval');
|
||||
$words = many(any(alphaChar(), punctuationChar(), whitespace()));
|
||||
$parser = $words->followedBy(keepFirst($number, skipSpace()->followedBy($movies)));
|
||||
|
||||
$input = "I watched 23 MOVIES this week ";
|
||||
$this->assertParses($input, $parser, 23);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function between()
|
||||
{
|
||||
$parser = between(char('{'), char('}'), atLeastOne(alphaNumChar()));
|
||||
$input = "{foo}";
|
||||
$this->assertParses($input, $parser, "foo");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function between_failure()
|
||||
{
|
||||
$parser = between(char('{'), char('}'), atLeastOne(alphaNumChar()));
|
||||
$this->assertParseFails("foo}", $parser, "'{'");
|
||||
$this->assertParseFails("{foo", $parser, "'}'");
|
||||
$this->assertParseFails("{}", $parser, "A-Z or a-z or 0-9");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function notFollowedBy()
|
||||
{
|
||||
$print = string("print");
|
||||
$this->assertParses("print('Hello World');", $print, "print");
|
||||
// This also outputs "print", but it wasn't our intention, because "printXYZ" is not a valid keyword:
|
||||
$this->assertParses("printXYZ('Hello World');", $print, "print");
|
||||
|
||||
// with notFollowedBy:
|
||||
$print = keepFirst(string("print"), notFollowedBy(alphaNumChar()));
|
||||
$this->assertParses("print('Hello World');", $print, "print");
|
||||
$this->assertParseFails("printXYZ('Hello World');", $print);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function notFollowedBy_fluent()
|
||||
{
|
||||
$print = string("print")->notFollowedBy(alphaNumChar());
|
||||
$this->assertParses("print('Hello World');", $print, "print");
|
||||
$this->assertParseFails("printXYZ('Hello World');", $print);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function lookAhead()
|
||||
{
|
||||
$parser = lookAhead(stringI("hello"));
|
||||
|
||||
// On success, lookAhead succeeds without consuming input
|
||||
$this->assertParses("Hello, world!", $parser, "Hello");
|
||||
$this->assertRemainder("Hello, world!", $parser, "Hello, world!");
|
||||
|
||||
// On fail, lookAhead fails without consuming input
|
||||
$this->assertParseFails("Hi, world!", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function sepBy()
|
||||
{
|
||||
$parser = sepBy(string('||'), atLeastOne(alphaChar()));
|
||||
|
||||
$input = "";
|
||||
$expected = [];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||bar||";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar||baz";
|
||||
$expected = ["foo", "bar", "baz"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "||";
|
||||
$this->assertParses($input, $parser, [], "The sepBy parser always succeed, even if it doesn't find anything");
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar||baz";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar||";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
|
||||
$input = "||bar";
|
||||
$this->assertParses($input, $parser, []);
|
||||
$this->assertRemainder($input, $parser, $input);
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function sepBy1()
|
||||
{
|
||||
$parser = sepBy1(string('||'), atLeastOne(alphaChar()));
|
||||
|
||||
$input = "";
|
||||
$this->assertParseFails($input, $parser, "at least one A-Z or a-z, separated by '||'");
|
||||
|
||||
$input = "||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||baz";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar||";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
$input = "||bar";
|
||||
$this->assertParseFails($input, $parser);
|
||||
|
||||
|
||||
$input = "foo";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||";
|
||||
$expected = ["foo"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
|
||||
$input = "foo||bar||";
|
||||
$expected = ["foo", "bar"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
$this->assertRemainder($input, $parser, "||");
|
||||
|
||||
$input = "foo||bar||baz";
|
||||
$expected = ["foo", "bar", "baz"];
|
||||
$this->assertParses($input, $parser, $expected);
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function repeat_vs_repeatList()
|
||||
{
|
||||
$parser = repeat(5, alphaChar());
|
||||
$this->assertParses("hello", $parser, "hello");
|
||||
$parser = repeatList(5, alphaChar());
|
||||
$this->assertParses("hello", $parser, ["h", "e", "l", "l", "o"]);
|
||||
|
||||
$parser = repeatList(3, repeat(3, alphaChar()));
|
||||
$this->assertParses("EURUSDGBP", $parser, ["EUR", "USD", "GBP"]);
|
||||
}
|
||||
}
|
||||
105
vendor/parsica-php/parsica/tests/numericTest.php
vendored
Normal file
105
vendor/parsica-php/parsica/tests/numericTest.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\float;
|
||||
use function Parsica\Parsica\integer;
|
||||
use function Parsica\Parsica\keepFirst;
|
||||
use function Parsica\Parsica\skipSpace1;
|
||||
|
||||
final class numericTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function integer()
|
||||
{
|
||||
$parser = integer();
|
||||
$this->assertParses("0", $parser, "0");
|
||||
$this->assertParses("1", $parser, "1");
|
||||
$this->assertParses("10", $parser, "10");
|
||||
$this->assertParses("972115541", $parser, "972115541");
|
||||
$this->assertParses("-0", $parser, "-0");
|
||||
$this->assertParses("-1", $parser, "-1");
|
||||
$this->assertParses("-10", $parser, "-10");
|
||||
$this->assertParses("-972115541", $parser, "-972115541");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function integer_maps_to_int()
|
||||
{
|
||||
$parser = integer()->map('intval');
|
||||
$this->assertParses("0", $parser, 0);
|
||||
$this->assertParses("1", $parser, 1);
|
||||
$this->assertParses("10", $parser, 10);
|
||||
$this->assertParses("972115541", $parser, 972115541);
|
||||
$this->assertParses("-0", $parser, 0);
|
||||
$this->assertParses("-1", $parser, -1);
|
||||
$this->assertParses("-10", $parser, -10);
|
||||
$this->assertParses("-972115541", $parser, -972115541);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function integer_fails()
|
||||
{
|
||||
$parser = keepFirst(integer(), skipSpace1());
|
||||
$this->assertParseFails("00", $parser);
|
||||
$this->assertParseFails("01", $parser);
|
||||
$this->assertParseFails("+1", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function float()
|
||||
{
|
||||
$parser = float();
|
||||
$this->assertParses("0", $parser, "0");
|
||||
$this->assertParses("0.1", $parser, "0.1");
|
||||
$this->assertParses("0.15", $parser, "0.15");
|
||||
$this->assertParses("0.10", $parser, "0.10");
|
||||
$this->assertParses("123.456", $parser, "123.456");
|
||||
$this->assertParses("1.2345678", $parser, "1.2345678");
|
||||
$this->assertParses("-1.2345678", $parser, "-1.2345678");
|
||||
$this->assertParses("-1.23456789E+123", $parser, "-1.23456789E+123");
|
||||
$this->assertParses("-1.23456789e-123", $parser, "-1.23456789E-123");
|
||||
$this->assertParses("-1E-123", $parser, "-1E-123");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function float_fails()
|
||||
{
|
||||
$parser = keepFirst(float(), skipSpace1()); // avoid false positives
|
||||
$this->assertParseFails("00", $parser);
|
||||
$this->assertParseFails("0. 15", $parser);
|
||||
$this->assertParseFails("00.10", $parser);
|
||||
$this->assertParseFails(" + 00.10", $parser);
|
||||
$this->assertParseFails(" + 123.456", $parser);
|
||||
$this->assertParseFails("1.234.5678", $parser);
|
||||
$this->assertParseFails(" - 1,2345678", $parser);
|
||||
$this->assertParseFails("--1.234E123", $parser);
|
||||
$this->assertParseFails(" - 1.234e", $parser);
|
||||
$this->assertParseFails(" - 1E-123E - 456", $parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function float_maps_correctly()
|
||||
{
|
||||
$parser = float()->map('floatval');
|
||||
$this->assertParses("123.456", $parser, 123.456);
|
||||
$this->assertParses("-0.1", $parser, -0.1);
|
||||
$this->assertParses("1.2345678", $parser, 1.2345678);
|
||||
$this->assertParses("-1.2345678", $parser, -1.2345678);
|
||||
$this->assertParses("-1.23456789E+123", $parser, -1.23456789E+123);
|
||||
$this->assertParses("-1.23456789e-123", $parser, -1.23456789E-123);
|
||||
$this->assertParses("-1E-123", $parser, -1E-123);
|
||||
}
|
||||
}
|
||||
57
vendor/parsica-php/parsica/tests/predicatesTest.php
vendored
Normal file
57
vendor/parsica-php/parsica/tests/predicatesTest.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{andPred, isEqual, notPred, orPred, satisfy};
|
||||
|
||||
final class predicatesTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function isEqual()
|
||||
{
|
||||
$this->assertTrue(isEqual('x')('x'));
|
||||
$this->assertFalse(isEqual('x')('y'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function notPred()
|
||||
{
|
||||
$this->assertFalse(notPred(isEqual('x'))('x'));
|
||||
$this->assertTrue(notPred(isEqual('x'))('y'));
|
||||
|
||||
$parser = satisfy(notPred(isEqual('x')));
|
||||
$this->assertParseFails("xyz", $parser);
|
||||
$this->assertParses("yz", $parser, "y");
|
||||
$this->assertParseFails("", $parser, "satisfy(predicate)");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function orPred()
|
||||
{
|
||||
$predicate = orPred(isEqual('x'), isEqual('y'));
|
||||
$this->assertTrue($predicate('x'));
|
||||
$this->assertTrue($predicate('y'));
|
||||
$this->assertFalse($predicate('z'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function andPred()
|
||||
{
|
||||
$predicate = andPred(isEqual('x'), isEqual('x'));
|
||||
$this->assertTrue($predicate('x'));
|
||||
$this->assertFalse($predicate('y'));
|
||||
}
|
||||
}
|
||||
|
||||
185
vendor/parsica-php/parsica/tests/primitivesTest.php
vendored
Normal file
185
vendor/parsica-php/parsica/tests/primitivesTest.php
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{anything,
|
||||
eof,
|
||||
everything,
|
||||
fail,
|
||||
nothing,
|
||||
satisfy,
|
||||
skipWhile,
|
||||
skipWhile1,
|
||||
succeed,
|
||||
takeWhile,
|
||||
takeWhile1};
|
||||
use function Parsica\Parsica\{isEqual, notPred};
|
||||
|
||||
|
||||
final class primitivesTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function satisfy()
|
||||
{
|
||||
$parser = satisfy(isEqual('x'));
|
||||
$this->assertParses("xyz", $parser, "x");
|
||||
$this->assertRemainder("xyz", $parser, "yz");
|
||||
$this->assertParseFails("yz", $parser, "satisfy(predicate)");
|
||||
$this->assertParseFails("", $parser, "satisfy(predicate)");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function anything_()
|
||||
{
|
||||
$this->assertParses("xyz", anything(), "x");
|
||||
$this->assertRemainder("xyz", anything(), "yz");
|
||||
$this->assertParses(":-)", anything(), ":");
|
||||
$this->assertRemainder(":-)", anything(), "-)");
|
||||
$this->assertParseFails("", anything(), "anything");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function nothing()
|
||||
{
|
||||
$this->assertRemainder("xyz", nothing(), "xyz");
|
||||
$this->assertRemainder(":-)", nothing(), ":-)");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function everything()
|
||||
{
|
||||
$this->assertParses("xyz", everything(), "xyz");
|
||||
$this->assertRemainder("xyz", everything(), "");
|
||||
$this->assertParses(":-)", everything(), ":-)");
|
||||
$this->assertRemainder(":-)", everything(), "");
|
||||
$this->assertParses("", everything(), "");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function eof()
|
||||
{
|
||||
$this->assertParses("", eof(), "");
|
||||
$this->assertParseFails("xyz", eof(), "<EOF>");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeWhile()
|
||||
{
|
||||
$parser = takeWhile(isEqual('a'));
|
||||
$this->assertParses("xyz", $parser, "");
|
||||
$this->assertParses("xaaa", $parser, "");
|
||||
$this->assertParses("axyz", $parser, "a");
|
||||
$this->assertParses("aaaxyz", $parser, "aaa");
|
||||
$this->assertParses("aaa", $parser, "aaa");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeWhile_using_not()
|
||||
{
|
||||
$parser = takeWhile(notPred(isEqual('a')));
|
||||
|
||||
$this->assertParses("xyza", $parser, "xyz");
|
||||
$this->assertParses("xyz", $parser, "xyz");
|
||||
$this->assertParses("xaaa", $parser, "x");
|
||||
$this->assertParses("axyz", $parser, "");
|
||||
$this->assertParses("aaaxyz", $parser, "");
|
||||
$this->assertParses("aaa", $parser, "");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeWile_succeeds_on_EOF()
|
||||
{
|
||||
$parser = takeWhile(isEqual('a'));
|
||||
$this->assertSucceedOnEOF($parser);
|
||||
|
||||
$parser = takeWhile(notPred(isEqual('a')));
|
||||
$this->assertSucceedOnEOF($parser);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function takeWhile1()
|
||||
{
|
||||
$parser = takeWhile1(isEqual('a'));
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParseFails("xyz", $parser, "takeWhile1(predicate)");
|
||||
$this->assertParseFails("takeWhile1(predicate)", $parser);
|
||||
$this->assertParses("axyz", $parser, "a");
|
||||
$this->assertParses("aaaxyz", $parser, "aaa");
|
||||
$this->assertParses("aaa", $parser, "aaa");
|
||||
$this->assertParseFails("", $parser, "takeWhile1(predicate)");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function success_and_failure()
|
||||
{
|
||||
$this->assertParses("doesn't matter what we put in here", succeed(), null);
|
||||
$this->assertRemainder("no input is consumed", succeed(), "no input is consumed");
|
||||
$this->assertParseFails("doesn't matter what we put in here", fail("reason for failure"));
|
||||
|
||||
$or = fail("")->or(succeed());
|
||||
$this->assertParses("failure or success is success", $or, null);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipWhile()
|
||||
{
|
||||
$parser = skipWhile(isEqual('a'));
|
||||
|
||||
$this->assertParses("xyz", $parser, null);
|
||||
$this->assertRemainder("xyz", $parser, "xyz");
|
||||
$this->assertParses("xaaa", $parser, null);
|
||||
$this->assertRemainder("xaaa", $parser, "xaaa");
|
||||
$this->assertParses("axyz", $parser, null);
|
||||
$this->assertRemainder("axyz", $parser, "xyz");
|
||||
$this->assertParses("aaaxyz", $parser, null);
|
||||
$this->assertRemainder("aaaxyz", $parser, "xyz");
|
||||
$this->assertParses("aaa", $parser, null);
|
||||
$this->assertRemainder("aaa", $parser, "");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipWhile_using_not()
|
||||
{
|
||||
$parser = skipWhile(notPred(isEqual('a')));
|
||||
|
||||
$this->assertParses("xyz", $parser, null);
|
||||
$this->assertRemainder("xyz", $parser, "");
|
||||
$this->assertParses("xaaa", $parser, null);
|
||||
$this->assertRemainder("xaaa", $parser, "aaa");
|
||||
$this->assertParses("axyz", $parser, null);
|
||||
$this->assertRemainder("axyz", $parser, "axyz");
|
||||
$this->assertParses("aaaxyz", $parser, null);
|
||||
$this->assertRemainder("aaaxyz", $parser, "aaaxyz");
|
||||
$this->assertParses("aaa", $parser, null);
|
||||
$this->assertRemainder("aaa", $parser, "aaa");
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function skipWhile1()
|
||||
{
|
||||
$parser = skipWhile1(isEqual('a'));
|
||||
|
||||
$this->assertFailOnEOF($parser);
|
||||
$this->assertParseFails("xyz", $parser);
|
||||
$this->assertParses("axyz", $parser, null);
|
||||
$this->assertRemainder("axyz", $parser, "xyz");
|
||||
$this->assertParses("aaaxyz", $parser, null);
|
||||
$this->assertRemainder("aaaxyz", $parser, "xyz");
|
||||
$this->assertParses("aaa", $parser, null);
|
||||
$this->assertRemainder("aaa", $parser, "");
|
||||
$this->assertParseFails("", $parser);
|
||||
}
|
||||
}
|
||||
126
vendor/parsica-php/parsica/tests/recursionTest.php
vendored
Normal file
126
vendor/parsica-php/parsica/tests/recursionTest.php
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\{between, char, collect, digitChar, recursive};
|
||||
|
||||
final class recursionTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function recursion_on_nested_structures()
|
||||
{
|
||||
$opening = char('[');
|
||||
$closing = char(']');
|
||||
$comma = char(',');
|
||||
$digit = digitChar()->map('intval');
|
||||
|
||||
$pair = recursive();
|
||||
$pair->recurse(
|
||||
between(
|
||||
$opening, $closing, collect(
|
||||
$digit->or($pair)->thenIgnore($comma),
|
||||
$digit->or($pair)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$input = "[1,2]";
|
||||
$this->assertParses($input, $pair, [1, 2]);
|
||||
|
||||
$input = "[1,[2,[3,4]]]";
|
||||
$this->assertParses($input, $pair, [1, [2, [3, 4]]]);
|
||||
|
||||
$input = "[[[4,3],2],1]";
|
||||
$this->assertParses($input, $pair, [[[4, 3], 2], 1]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function nesting_multiple_recursive_parsers()
|
||||
{
|
||||
$openingSquare = char('[');
|
||||
$closingSquare = char(']');
|
||||
$openingCurly = char('{');
|
||||
$closingCurly = char('}');
|
||||
$comma = char(',');
|
||||
$digit = digitChar()->map('intval');
|
||||
|
||||
$curlyPair = recursive();
|
||||
$squarePair = recursive();
|
||||
$anyPair = $curlyPair->or($squarePair);
|
||||
|
||||
$expr = $digit->or($anyPair);
|
||||
$inner = collect($expr->thenIgnore($comma), $expr);
|
||||
|
||||
$curlyPair->recurse(
|
||||
between($openingCurly, $closingCurly, $inner)
|
||||
);
|
||||
|
||||
$squarePair->recurse(
|
||||
between($openingSquare, $closingSquare, $inner)
|
||||
);
|
||||
|
||||
$input = "[1,{2,[{3,4},{5,6}]}]";
|
||||
$this->assertParses($input, $anyPair, [1, [2, [[3, 4], [5, 6]]]]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function throw_on_multiple_calls_to_recurse()
|
||||
{
|
||||
$parser = recursive();
|
||||
$parser->recurse(char('a'));
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$parser->recurse(char('b'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function throw_when_recursing_non_recursive_parsers()
|
||||
{
|
||||
$parser = char('a');
|
||||
$this->expectException(Exception::class);
|
||||
$parser->recurse(char('b'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function throw_for_nested_recursive_parsers_that_arent_completely_setup()
|
||||
{
|
||||
$p1 = recursive();
|
||||
$p2 = recursive();
|
||||
$p1->recurse($p2);
|
||||
$this->expectException(Exception::class);
|
||||
$p1->run(new StringStream("test"));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function using_a_recursive_parser_like_a_regular_one_after_it_was_setup()
|
||||
{
|
||||
$parser = recursive();
|
||||
$parser->recurse(char('a'));
|
||||
$labeledParser = $parser->label("test");
|
||||
$this->assertParses("abc", $labeledParser, "a");
|
||||
$this->assertParseFails("bc", $labeledParser, "test");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function calling_combinators_on_a_recursive_parser_before_it_is_setup()
|
||||
{
|
||||
$p1 = recursive();
|
||||
$p2 = char('a')->followedBy($p1->label("test"));
|
||||
$this->expectException(Exception::class);
|
||||
$this->assertParses("abc", $p2, "a");
|
||||
}
|
||||
}
|
||||
53
vendor/parsica-php/parsica/tests/sideEffectsTest.php
vendored
Normal file
53
vendor/parsica-php/parsica/tests/sideEffectsTest.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\StringStream;
|
||||
use function Parsica\Parsica\char;
|
||||
use function Parsica\Parsica\emit;
|
||||
|
||||
final class sideEffectsTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function emit()
|
||||
{
|
||||
$cache = new Cache();
|
||||
$addToCache = fn($output) => $cache->add($output, $output);
|
||||
|
||||
$parser = emit(char('a'), $addToCache);
|
||||
|
||||
$input = "a";
|
||||
$parser->run(new StringStream($input));
|
||||
$this->assertEquals("a", $cache->get('a'));
|
||||
|
||||
$input = "b";
|
||||
$parser->run(new StringStream($input));
|
||||
$this->assertNull($cache->get('b'));
|
||||
}
|
||||
}
|
||||
|
||||
class Cache
|
||||
{
|
||||
private $items = [];
|
||||
|
||||
function add($key, $value)
|
||||
{
|
||||
$this->items[$key] = $value;
|
||||
}
|
||||
|
||||
function get($key)
|
||||
{
|
||||
return array_key_exists($key, $this->items)
|
||||
? $this->items[$key]
|
||||
: null;
|
||||
}
|
||||
}
|
||||
89
vendor/parsica-php/parsica/tests/spaceTest.php
vendored
Normal file
89
vendor/parsica-php/parsica/tests/spaceTest.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of the Parsica library.
|
||||
*
|
||||
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Tests\Parsica\Parsica;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Parsica\Parsica\PHPUnit\ParserAssertions;
|
||||
use function Parsica\Parsica\{crlf, eol, newline, skipHSpace, skipHSpace1, skipSpace, skipSpace1, tab};
|
||||
|
||||
final class spaceTest extends TestCase
|
||||
{
|
||||
use ParserAssertions;
|
||||
|
||||
/** @test */
|
||||
public function newline()
|
||||
{
|
||||
$this->assertParses("\nabc", newline(), "\n");
|
||||
$this->assertParseFails("\rabc", newline());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function crlf()
|
||||
{
|
||||
$this->assertParses("\r\nabc", crlf(), "\r\n");
|
||||
$this->assertParseFails("\rabc", crlf(), "<crlf>");
|
||||
$this->assertParseFails("\rabc", crlf(), "<crlf>");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function eol()
|
||||
{
|
||||
$this->assertParses("\nabc", eol(), "\n");
|
||||
$this->assertParses("\r\nabc", eol(), "\r\n");
|
||||
$this->assertParseFails("\rabc", eol(), "<EOL>");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tab()
|
||||
{
|
||||
$this->assertParses("\tabc", tab(), "\t");
|
||||
$this->assertParseFails("abc", tab(), "<tab>");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipSpace()
|
||||
{
|
||||
$this->assertRemainder("no space", skipSpace(), "no space");
|
||||
$this->assertRemainder(" 1 space", skipSpace(), "1 space");
|
||||
$this->assertRemainder("\ttab", skipSpace(), "tab");
|
||||
$this->assertRemainder("\nnewline", skipSpace(), "newline");
|
||||
$this->assertRemainder("\t \n \r\n abc", skipSpace(), "abc");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipHSpace()
|
||||
{
|
||||
$this->assertRemainder("abc", skipHSpace(), "abc");
|
||||
$this->assertRemainder("\t abc", skipHSpace(), "abc");
|
||||
$this->assertRemainder("\t \nabc", skipHSpace(), "\nabc");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function skipSpace1()
|
||||
{
|
||||
$this->assertParseFails("no space", skipSpace1(), "<space>");
|
||||
$this->assertRemainder(" 1 space", skipSpace1(), "1 space");
|
||||
$this->assertRemainder("\ttab", skipSpace1(), "tab");
|
||||
$this->assertRemainder("\nnewline", skipSpace1(), "newline");
|
||||
$this->assertRemainder("\t \n \r\n abc", skipSpace1(), "abc");
|
||||
}
|
||||
|
||||
|
||||
/** @test */
|
||||
public function skipHSpace1()
|
||||
{
|
||||
$this->assertParseFails("no space", skipHSpace1(), "<space>");
|
||||
$this->assertRemainder("\t some space", skipHSpace1(), "some space");
|
||||
$this->assertRemainder("\t abc", skipHSpace1(), "abc");
|
||||
$this->assertRemainder("\t \nabc", skipHSpace1(), "\nabc");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user