/** * Attempt to parse a link reference, modifying the refmap. * * @param Cursor $cursor * * @return bool */ public function parse(Cursor $cursor) { if ($cursor->isAtEnd()) { return false; } $initialState = $cursor->saveState(); $matchChars = LinkParserHelper::parseLinkLabel($cursor); if ($matchChars === 0) { $cursor->restoreState($initialState); return false; } // We need to trim the opening and closing brackets from the previously-matched text $label = substr($cursor->getPreviousText(), 1, -1); if (preg_match('/[^\\s]/', $label) === 0) { $cursor->restoreState($initialState); return false; } if ($cursor->getCharacter() !== ':') { $cursor->restoreState($initialState); return false; } // Advance past the colon $cursor->advance(); // Link URL $cursor->advanceToFirstNonSpace(); $destination = LinkParserHelper::parseLinkDestination($cursor); if (empty($destination)) { $cursor->restoreState($initialState); return false; } $previousState = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $title = LinkParserHelper::parseLinkTitle($cursor); if ($title === null) { $title = ''; $cursor->restoreState($previousState); } // Make sure we're at line end: if ($cursor->match('/^ *(?:\\n|$)/') === null) { $cursor->restoreState($initialState); return false; } if (!$this->referenceMap->contains($label)) { $reference = new Reference($label, $destination, $title); $this->referenceMap->addReference($reference); } return true; }
/** * @param Cursor $cursor * @param ReferenceMap $referenceMap * @param Delimiter $opener * @param int $startPos * * @return Reference|null */ protected function tryParseReference(Cursor $cursor, ReferenceMap $referenceMap, Delimiter $opener, $startPos) { $savePos = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $beforeLabel = $cursor->getPosition(); $n = LinkParserHelper::parseLinkLabel($cursor); if ($n === 0 || $n === 2) { // Empty or missing second label $reflabel = mb_substr($cursor->getLine(), $opener->getIndex(), $startPos - $opener->getIndex(), 'utf-8'); } else { $reflabel = mb_substr($cursor->getLine(), $beforeLabel + 1, $n - 2, 'utf-8'); } if ($n === 0) { // If shortcut reference link, rewind before spaces we skipped $cursor->restoreState($savePos); } return $referenceMap->getReference($reflabel); }
/** * Attempt to parse a link reference, modifying the refmap. * * @param Cursor $cursor * * @return bool */ public function parse(Cursor $cursor) { if ($cursor->isAtEnd()) { return false; } $initialState = $cursor->saveState(); $matchChars = LinkParserHelper::parseLinkLabel($cursor); if ($matchChars === 0) { $cursor->restoreState($initialState); return false; } // We need to trim the opening and closing brackets from the previously-matched text $label = substr($cursor->getPreviousText(), 1, -1); if (preg_match('/[^\\s]/', $label) === 0) { $cursor->restoreState($initialState); return false; } if ($cursor->getCharacter() !== ':') { $cursor->restoreState($initialState); return false; } // Advance past the colon $cursor->advance(); // Link URL $cursor->advanceToFirstNonSpace(); $destination = LinkParserHelper::parseLinkDestination($cursor); if (empty($destination)) { $cursor->restoreState($initialState); return false; } $previousState = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $title = LinkParserHelper::parseLinkTitle($cursor); if ($title === null) { $title = ''; $cursor->restoreState($previousState); } // Make sure we're at line end: $atLineEnd = true; if ($cursor->match('/^ *(?:\\n|$)/') === null) { if ($title === '') { $atLineEnd = false; } else { // The potential title we found is not at the line end, // but it could still be a legal link reference if we // discard the title $title = ''; // rewind before spaces $cursor->restoreState($previousState); // and instead check if the link URL is at the line end $atLineEnd = $cursor->match('/^ *(?:\\n|$)/') !== null; } } if (!$atLineEnd) { $cursor->restoreState($initialState); return false; } if (!$this->referenceMap->contains($label)) { $reference = new Reference($label, $destination, $title); $this->referenceMap->addReference($reference); } return true; }