public function testItemAt() { $parse = new Parse(new Map(['abc', 'def', 'abc'])); $actual = $parse->parse('itemAt("1")'); $this->assertEquals("def", $actual->getValue()); }
/** * parseInternal * @param $mapping * @param $until * @return ObjectInterface * @throws CatchableException * @throws \Exception */ private function parseInternal($mapping, $until) { $mappingLength = strlen($mapping); $totalOutput = null; $currentMapping = ''; $inQuote = false; $currentObject = $this->getOriginalObject(); $closingParenthesisFound = false; for ($i = 0; $i < $mappingLength; $i++) { $char = $mapping[$i]; $atEnd = $i + 1 == $mappingLength; $nextChar = $atEnd ? null : $mapping[$i + 1]; if ($char == '\\') { if ($atEnd) { $this->throwMappingException('An escape character "\\" must either be escaped or not at the end of a mapping', $mapping, $i); } //Add the next character since we are escaping it $currentMapping .= $nextChar; $i++; //Skip the next character continue; } if ($inQuote) { if ($char == '"') { if (!($atEnd || $nextChar == '+' || $nextChar == '.' || $until == self::UNTIL_CLOSING_COMMA_OR_CLOSING_PARENTHESIS && ($nextChar == ')' || $nextChar == ','))) { $this->throwMappingException('A closing quote "\\"" must either be followed by the end of the mapping, a closing parenthesis, a plus, a "," or a .', $mapping, $i); } $inQuote = false; if (is_numeric($currentMapping)) { $currentObject = new Number($currentMapping); } else { $currentObject = new String($currentMapping); } $currentMapping = ''; continue; } $currentMapping .= $char; continue; } if ($char == '"') { if ($currentMapping != '') { $this->throwMappingException('A beginning quote "\\"" must be at the beginning of a mapping', $mapping, $i); } $inQuote = true; continue; } if ($char == '(') { /** @type Parsable[] $parameters */ $parameters = []; $i++; //Offset for opening parenthesis $subMapping = substr($mapping, $i); if ($subMapping == '') { $this->throwMappingException('There are more opening parenthesis than closing parenthesis', $mapping, $i); } while (strlen($subMapping) > 0) { $parse = new Parse($currentObject); $parameter = $parse->parseInternal($subMapping, self::UNTIL_CLOSING_COMMA_OR_CLOSING_PARENTHESIS); $isLastParameter = substr($subMapping, $parse->getLastIndex(), 1) == ')'; if (!$isLastParameter || $parse->getLastIndex() > 0) { $parameters[] = $parameter; } $i += $parse->getLastIndex() + 1; $subMapping = substr($subMapping, $parse->getLastIndex() + 1); if ($isLastParameter) { break; //Found closing parenthesis } } $currentObject = $this->call($mapping, $i, $currentObject, $currentMapping, $parameters); $currentMapping = ''; continue; } if ($char == ')') { if ($until != self::UNTIL_CLOSING_COMMA_OR_CLOSING_PARENTHESIS) { $this->throwMappingException('There are more closing parenthesis than opening parenthesis', $mapping, $i); } $closingParenthesisFound = true; $this->setLastIndex($i); break; } if ($char == ',') { if ($until != self::UNTIL_CLOSING_COMMA_OR_CLOSING_PARENTHESIS) { $this->throwMappingException('Commas are only allowed inside of parameters for methods', $mapping, $i); } $closingParenthesisFound = true; $this->setLastIndex($i); break; } if ($char == '+') { $currentObject = $this->call($mapping, $i, $currentObject, $currentMapping); $this->addToTotalOutput($currentObject); //Reset mapping/object for next part $currentMapping = ''; $currentObject = $this->getOriginalObject(); continue; } if ($char == '.') { $currentObject = $this->call($mapping, $i, $currentObject, $currentMapping); $currentMapping = ''; continue; } $currentMapping .= $char; } if (!$closingParenthesisFound && $until == self::UNTIL_CLOSING_COMMA_OR_CLOSING_PARENTHESIS) { $this->throwMappingException('There are more opening parenthesis than closing parenthesis', $mapping, $i); } if ($inQuote) { $this->throwMappingException('There is no matching closing quote to an opening quote', $mapping, $mappingLength); } $currentObject = $this->call($mapping, $i, $currentObject, $currentMapping); $this->addToTotalOutput($currentObject); return $this->getTotalOutput(); }