public function parse(Input $input) { $aggregatedResult = []; $isPositive = false; $count = 0; $lastOffset = $input->getOffset(); while ($this->max === null || $count < $this->max) { $result = parent::parse($input)->addParser($this); if ($result->positiveMatch) { $isPositive = true; } if ($result->errorMessage) { if ($count < $this->min) { return $input->errorHere("Expected {$this->min} elements, but found {$count}"); } elseif ($result->positiveMatch) { // If a branch got far enough to assert itself but still returned an error then we need to propagate return $result; } // Most errors are normal, they just signal the end of the repetition. break; } if ($input->getOffset() == $lastOffset) { throw new GrammarException('At ' . $input->getPositionDescription() . ": parser {$result->getParserStack()} did not consume any input, this is a bug with the grammar. Make sure there are no zero width matches in a Many. The result in was {$result}"); } if ($result->hasData) { $aggregatedResult[] = $result->data; } $lastOffset++; $count++; } if ($count < $this->min) { return $input->errorHere("Expected {$this->min} elements, but found {$count}", $isPositive)->addParser($this); } return $input->matchHere($aggregatedResult, $isPositive); }
public function parse(Input $input) { $initialOffset = $input->getOffset(); foreach ($this->getParsers() as $parser) { // Keep trying each of the parsers until one matches. $result = $parser->parse($input); // Stop on the first match if (!$result->errorMessage || $result->hasData) { return $result->addParser($this); } // To be safe we rewind the input after each attempt. $input->setOffset($initialOffset); } return $input->matchHere(null)->addParser($this); }
public function parse(Input $input) { $initialOffset = $input->getOffset(); foreach ($this->getParsers() as $parser) { // Keep trying each of the parsers until one matches. $result = $parser->parse($input); // Errors and positive results will stop us from searching. if (!$result->errorMessage || $result->positiveMatch) { return $result->addParser($this); } // To be safe we rewind the input after each attempt. $input->setOffset($initialOffset); } return $input->errorHere("Could not find any options that match {$input->get()}")->addParser($this); }
private function matches(Input $input) { $initialOffset = $input->getOffset(); foreach ($this->getParsers() as $parser) { // Keep trying each of the parsers until one matches. $result = $parser->parse($input); // Errors and positive results will stop us from searching. if ($result->match) { if ($initialOffset === $input->getOffset()) { throw new GrammarException('There was a zero width match inside a Not parser.'); } $input->setOffset($initialOffset); return true; } // To be safe we rewind the input after each attempt. $input->setOffset($initialOffset); } return false; }
public function parse(Input $input) { $aggregatedData = []; $isPositive = false; $initialOffset = $input->getOffset(); foreach ($this->getParsers() as $parser) { $result = $parser->parse($input); if ($result->hasData) { $aggregatedData[] = $result->data; } // Any single positive match in the sequence makes the whole sequence positive. if ($result->positiveMatch) { $isPositive = true; } // Any single error causes the whole sequence to error if ($result->errorMessage) { $result->positiveMatch = $isPositive; if ($aggregatedData) { $result->errorMessage .= "\nPrevious tokens:\n"; foreach ($aggregatedData as $token) { if (is_callable([$token, '__toString'])) { $result->errorMessage .= ' - ' . $token->__toString() . "\n"; } else { $result->errorMessage .= ' - ' . print_r($token, true) . "\n"; } } } return $result->addParser($this); } } if ($aggregatedData === []) { return $input->nonCapturingMatchHere($isPositive, $initialOffset)->addParser($this); } else { return $input->matchHere($aggregatedData, $isPositive, $initialOffset)->addParser($this); } }
public function testPeek() { $input = new Input('1234'); $this->assertEquals('1', $input->peek(0)); $this->assertEquals('2', $input->peek(1)); $this->assertEquals('3', $input->peek(2)); $this->assertEquals('4', $input->peek(3)); $this->assertEquals(0, $input->getOffset()); }