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); } }