/** * Use a parser to parse an input sequence. * * @param Parser $p * A parser. * @param Positional[] $input * An input sequence. * @return \Parco\Result Parse result. */ public function parse(Parser $p, array $input) { if ($this->atEnd($input)) { $pos = array(1, 1); } else { $pos = $this->head($input)->getPosition(); } return $p->parse($input, $pos); }
/** * A parser that returns the `$i`th group of a regex parse result. * * @param int $i * Group number starting from 0, where 0 is the entire matched * string. * @param Parser $p * A regex parser, see {@see regex}. * @return Parser A parser that returns the group or null if the group is * empty. */ public function group($i, Parser $p) { return new FuncParser(function ($input, array $pos) use($i, $p) { $r = $p->parse($input, $pos); if (!$r->successful) { return $r; } $group = $r->group($i); $offset = $r->offset($i); if (isset($offset)) { $pos[1] += $offset; } return new Success($group, $pos, $r->nextInput, $r->nextPos); }); }
/** * A parser for right-associative chaining. * * @param Parser $p * A parser. * @param Parser $sep * A parser that parses the elements that separate the elements * parsed by `$p` and returns a right-associative function that * combines two elements returned by `$p`. */ public function chainr(Parser $p, Parser $sep) { return new FuncParser(function ($input, array $pos) use($p, $sep) { $r = $p->parse($input, $pos); if (!$r->successful) { return $r; } $ops = array(array($r->result, null)); $input = $r->nextInput; $nextPos = $r->nextPos; while (true) { $s = $sep->parse($input, $nextPos); if (!$s->successful) { break; } $r = $p->parse($s->nextInput, $s->nextPos); if (!$r->successful) { break; } $f = $s->result; $ops[] = array($r->result, $f); $input = $r->nextInput; $nextPos = $r->nextPos; } $length = count($ops); $rightOperand = $ops[$length - 1][0]; for ($i = $length - 2; $i >= 0; $i--) { $f = $ops[$i + 1][1]; $leftOperand = $ops[$i][0]; $rightOperand = call_user_func($f, $leftOperand, $rightOperand); } return new Success($rightOperand, $pos, $input, $nextPos); }); }