Nette\Neon\Decoder::parse PHP Метод

parse() приватный Метод

private parse ( $indent, $result = NULL, $key = NULL, $hasKey = FALSE ) : array
Результат array
    private function parse($indent, $result = NULL, $key = NULL, $hasKey = FALSE)
    {
        $inlineParser = $indent === FALSE;
        $value = NULL;
        $hasValue = FALSE;
        $tokens = $this->tokens;
        $n =& $this->pos;
        $count = count($tokens);
        $mainResult =& $result;
        for (; $n < $count; $n++) {
            $t = $tokens[$n][0];
            if ($t === ',') {
                // ArrayEntry separator
                if (!$hasKey && !$hasValue || !$inlineParser) {
                    $this->error();
                }
                $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
                $hasKey = $hasValue = FALSE;
            } elseif ($t === ':' || $t === '=') {
                // KeyValuePair separator
                if ($hasValue && (is_array($value) || is_object($value))) {
                    $this->error('Unacceptable key');
                } elseif ($hasKey && $key === NULL && $hasValue && !$inlineParser) {
                    $n++;
                    $result[] = $this->parse($indent . '  ', [], $value, TRUE);
                    $newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : '';
                    // not last
                    if (strlen($newIndent) > strlen($indent)) {
                        $n++;
                        $this->error('Bad indentation');
                    } elseif (strlen($newIndent) < strlen($indent)) {
                        return $mainResult;
                        // block parser exit point
                    }
                    $hasKey = $hasValue = FALSE;
                } elseif ($hasKey || !$hasValue) {
                    $this->error();
                } else {
                    $key = (string) $value;
                    $hasKey = TRUE;
                    $hasValue = FALSE;
                    $result =& $mainResult;
                }
            } elseif ($t === '-') {
                // BlockArray bullet
                if ($hasKey || $hasValue || $inlineParser) {
                    $this->error();
                }
                $key = NULL;
                $hasKey = TRUE;
            } elseif (($tmp = self::BRACKETS) && isset($tmp[$t])) {
                // Opening bracket [ ( {
                if ($hasValue) {
                    if ($t !== '(') {
                        $this->error();
                    }
                    $n++;
                    if ($value instanceof Entity && $value->value === Neon::CHAIN) {
                        end($value->attributes)->attributes = $this->parse(FALSE, []);
                    } else {
                        $value = new Entity($value, $this->parse(FALSE, []));
                    }
                } else {
                    $n++;
                    $value = $this->parse(FALSE, []);
                }
                $hasValue = TRUE;
                if (!isset($tokens[$n]) || $tokens[$n][0] !== self::BRACKETS[$t]) {
                    // unexpected type of bracket or block-parser
                    $this->error();
                }
            } elseif ($t === ']' || $t === '}' || $t === ')') {
                // Closing bracket ] ) }
                if (!$inlineParser) {
                    $this->error();
                }
                break;
            } elseif ($t[0] === "\n") {
                // Indent
                if ($inlineParser) {
                    if ($hasKey || $hasValue) {
                        $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
                        $hasKey = $hasValue = FALSE;
                    }
                } else {
                    while (isset($tokens[$n + 1]) && $tokens[$n + 1][0][0] === "\n") {
                        $n++;
                        // skip to last indent
                    }
                    if (!isset($tokens[$n + 1])) {
                        break;
                    }
                    $newIndent = (string) substr($tokens[$n][0], 1);
                    if ($indent === NULL) {
                        // first iteration
                        $indent = $newIndent;
                    }
                    $minlen = min(strlen($newIndent), strlen($indent));
                    if ($minlen && (string) substr($newIndent, 0, $minlen) !== (string) substr($indent, 0, $minlen)) {
                        $n++;
                        $this->error('Invalid combination of tabs and spaces');
                    }
                    if (strlen($newIndent) > strlen($indent)) {
                        // open new block-array or hash
                        if ($hasValue || !$hasKey) {
                            $n++;
                            $this->error('Bad indentation');
                        }
                        $this->addValue($result, $key, $this->parse($newIndent));
                        $newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : '';
                        // not last
                        if (strlen($newIndent) > strlen($indent)) {
                            $n++;
                            $this->error('Bad indentation');
                        }
                        $hasKey = FALSE;
                    } else {
                        if ($hasValue && !$hasKey) {
                            // block items must have "key"; NULL key means list item
                            break;
                        } elseif ($hasKey) {
                            $this->addValue($result, $key, $hasValue ? $value : NULL);
                            if ($key !== NULL && !$hasValue && $newIndent === $indent && isset($tokens[$n + 1]) && $tokens[$n + 1][0] === '-') {
                                $result =& $result[$key];
                            }
                            $hasKey = $hasValue = FALSE;
                        }
                    }
                    if (strlen($newIndent) < strlen($indent)) {
                        // close block
                        return $mainResult;
                        // block parser exit point
                    }
                }
            } else {
                // Value
                if ($t[0] === '"' || $t[0] === "'") {
                    if (preg_match('#^...\\n+([\\t ]*)#', $t, $m)) {
                        $converted = substr($t, 3, -3);
                        $converted = str_replace("\n" . $m[1], "\n", $converted);
                        $converted = preg_replace('#^\\n|\\n[\\t ]*+\\z#', '', $converted);
                    } else {
                        $converted = substr($t, 1, -1);
                    }
                    if ($t[0] === '"') {
                        $converted = preg_replace_callback('#\\\\(?:ud[89ab][0-9a-f]{2}\\\\ud[c-f][0-9a-f]{2}|u[0-9a-f]{4}|x[0-9a-f]{2}|.)#i', [$this, 'cbString'], $converted);
                    }
                } elseif (($fix56 = self::SIMPLE_TYPES) && isset($fix56[$t]) && (!isset($tokens[$n + 1][0]) || $tokens[$n + 1][0] !== ':' && $tokens[$n + 1][0] !== '=')) {
                    $converted = constant(self::SIMPLE_TYPES[$t]);
                } elseif (is_numeric($t)) {
                    $converted = $t * 1;
                } elseif (preg_match(self::PATTERN_HEX, $t)) {
                    $converted = hexdec($t);
                } elseif (preg_match(self::PATTERN_OCTAL, $t)) {
                    $converted = octdec($t);
                } elseif (preg_match(self::PATTERN_BINARY, $t)) {
                    $converted = bindec($t);
                } elseif (preg_match(self::PATTERN_DATETIME, $t)) {
                    $converted = new \DateTimeImmutable($t);
                } else {
                    // literal
                    $converted = $t;
                }
                if ($hasValue) {
                    if ($value instanceof Entity) {
                        // Entity chaining
                        if ($value->value !== Neon::CHAIN) {
                            $value = new Entity(Neon::CHAIN, [$value]);
                        }
                        $value->attributes[] = new Entity($converted);
                    } else {
                        $this->error();
                    }
                } else {
                    $value = $converted;
                    $hasValue = TRUE;
                }
            }
        }
        if ($inlineParser) {
            if ($hasKey || $hasValue) {
                $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
            }
        } else {
            if ($hasValue && !$hasKey) {
                // block items must have "key"
                if ($result === NULL) {
                    $result = $value;
                    // simple value parser
                } else {
                    $this->error();
                }
            } elseif ($hasKey) {
                $this->addValue($result, $key, $hasValue ? $value : NULL);
            }
        }
        return $mainResult;
    }