Leafo\ScssPhp\Parser::parseChunk PHP Метод

parseChunk() защищенный Метод

Returns false when the buffer is empty, or when there is an error. This function is called repeatedly until the entire document is parsed. This parser is most similar to a recursive descent parser. Single functions represent discrete grammatical rules for the language, and they are able to capture the text that represents those rules. Consider the function Compiler::keyword(). (All parse functions are structured the same.) The function takes a single reference argument. When calling the function it will attempt to match a keyword on the head of the buffer. If it is successful, it will place the keyword in the referenced argument, advance the position in the buffer, and return true. If it fails then it won't advance the buffer and it will return false. All of these parse functions are powered by Compiler::match(), which behaves the same way, but takes a literal regular expression. Sometimes it is more convenient to use match instead of creating a new function. Because of the format of the functions, to parse an entire string of grammatical rules, you can chain them together using &&. But, if some of the rules in the chain succeed before one fails, then the buffer position will be left at an invalid state. In order to avoid this, Compiler::seek() is used to remember and set buffer positions. Before parsing a chain, use $s = $this->seek() to remember the current position into $s. Then if a chain fails, use $this->seek($s) to go back where we started.
protected parseChunk ( ) : boolean
Результат boolean
    protected function parseChunk()
    {
        $s = $this->seek();
        // the directives
        if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] === '@') {
            if ($this->literal('@at-root') && ($this->selectors($selector) || true) && ($this->map($with) || true) && $this->literal('{')) {
                $atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
                $atRoot->selector = $selector;
                $atRoot->with = $with;
                return true;
            }
            $this->seek($s);
            if ($this->literal('@media') && $this->mediaQueryList($mediaQueryList) && $this->literal('{')) {
                $media = $this->pushSpecialBlock(Type::T_MEDIA, $s);
                $media->queryList = $mediaQueryList[2];
                return true;
            }
            $this->seek($s);
            if ($this->literal('@mixin') && $this->keyword($mixinName) && ($this->argumentDef($args) || true) && $this->literal('{')) {
                $mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s);
                $mixin->name = $mixinName;
                $mixin->args = $args;
                return true;
            }
            $this->seek($s);
            if ($this->literal('@include') && $this->keyword($mixinName) && ($this->literal('(') && ($this->argValues($argValues) || true) && $this->literal(')') || true) && ($this->end() || $this->literal('{') && ($hasBlock = true))) {
                $child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null];
                if (!empty($hasBlock)) {
                    $include = $this->pushSpecialBlock(Type::T_INCLUDE, $s);
                    $include->child = $child;
                } else {
                    $this->append($child, $s);
                }
                return true;
            }
            $this->seek($s);
            if ($this->literal('@scssphp-import-once') && $this->valueList($importPath) && $this->end()) {
                $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@import') && $this->valueList($importPath) && $this->end()) {
                $this->append([Type::T_IMPORT, $importPath], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@import') && $this->url($importPath) && $this->end()) {
                $this->append([Type::T_IMPORT, $importPath], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@extend') && $this->selectors($selectors) && $this->end()) {
                // check for '!flag'
                $optional = $this->stripOptionalFlag($selectors);
                $this->append([Type::T_EXTEND, $selectors, $optional], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@function') && $this->keyword($fnName) && $this->argumentDef($args) && $this->literal('{')) {
                $func = $this->pushSpecialBlock(Type::T_FUNCTION, $s);
                $func->name = $fnName;
                $func->args = $args;
                return true;
            }
            $this->seek($s);
            if ($this->literal('@break') && $this->end()) {
                $this->append([Type::T_BREAK], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@continue') && $this->end()) {
                $this->append([Type::T_CONTINUE], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@return') && ($this->valueList($retVal) || true) && $this->end()) {
                $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@each') && $this->genericList($varNames, 'variable', ',', false) && $this->literal('in') && $this->valueList($list) && $this->literal('{')) {
                $each = $this->pushSpecialBlock(Type::T_EACH, $s);
                foreach ($varNames[2] as $varName) {
                    $each->vars[] = $varName[1];
                }
                $each->list = $list;
                return true;
            }
            $this->seek($s);
            if ($this->literal('@while') && $this->expression($cond) && $this->literal('{')) {
                $while = $this->pushSpecialBlock(Type::T_WHILE, $s);
                $while->cond = $cond;
                return true;
            }
            $this->seek($s);
            if ($this->literal('@for') && $this->variable($varName) && $this->literal('from') && $this->expression($start) && ($this->literal('through') || ($forUntil = true && $this->literal('to'))) && $this->expression($end) && $this->literal('{')) {
                $for = $this->pushSpecialBlock(Type::T_FOR, $s);
                $for->var = $varName[1];
                $for->start = $start;
                $for->end = $end;
                $for->until = isset($forUntil);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@if') && $this->valueList($cond) && $this->literal('{')) {
                $if = $this->pushSpecialBlock(Type::T_IF, $s);
                $if->cond = $cond;
                $if->cases = [];
                return true;
            }
            $this->seek($s);
            if ($this->literal('@debug') && $this->valueList($value) && $this->end()) {
                $this->append([Type::T_DEBUG, $value], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@warn') && $this->valueList($value) && $this->end()) {
                $this->append([Type::T_WARN, $value], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@error') && $this->valueList($value) && $this->end()) {
                $this->append([Type::T_ERROR, $value], $s);
                return true;
            }
            $this->seek($s);
            if ($this->literal('@content') && $this->end()) {
                $this->append([Type::T_MIXIN_CONTENT], $s);
                return true;
            }
            $this->seek($s);
            $last = $this->last();
            if (isset($last) && $last[0] === Type::T_IF) {
                list(, $if) = $last;
                if ($this->literal('@else')) {
                    if ($this->literal('{')) {
                        $else = $this->pushSpecialBlock(Type::T_ELSE, $s);
                    } elseif ($this->literal('if') && $this->valueList($cond) && $this->literal('{')) {
                        $else = $this->pushSpecialBlock(Type::T_ELSEIF, $s);
                        $else->cond = $cond;
                    }
                    if (isset($else)) {
                        $else->dontAppend = true;
                        $if->cases[] = $else;
                        return true;
                    }
                }
                $this->seek($s);
            }
            // only retain the first @charset directive encountered
            if ($this->literal('@charset') && $this->valueList($charset) && $this->end()) {
                if (!isset($this->charset)) {
                    $statement = [Type::T_CHARSET, $charset];
                    list($line, $column) = $this->getSourcePosition($s);
                    $statement[static::SOURCE_LINE] = $line;
                    $statement[static::SOURCE_COLUMN] = $column;
                    $statement[static::SOURCE_INDEX] = $this->sourceIndex;
                    $this->charset = $statement;
                }
                return true;
            }
            $this->seek($s);
            // doesn't match built in directive, do generic one
            if ($this->literal('@', false) && $this->keyword($dirName) && ($this->variable($dirValue) || $this->openString('{', $dirValue) || true) && $this->literal('{')) {
                if ($dirName === 'media') {
                    $directive = $this->pushSpecialBlock(Type::T_MEDIA, $s);
                } else {
                    $directive = $this->pushSpecialBlock(Type::T_DIRECTIVE, $s);
                    $directive->name = $dirName;
                }
                if (isset($dirValue)) {
                    $directive->value = $dirValue;
                }
                return true;
            }
            $this->seek($s);
            return false;
        }
        // property shortcut
        // captures most properties before having to parse a selector
        if ($this->keyword($name, false) && $this->literal(': ') && $this->valueList($value) && $this->end()) {
            $name = [Type::T_STRING, '', [$name]];
            $this->append([Type::T_ASSIGN, $name, $value], $s);
            return true;
        }
        $this->seek($s);
        // variable assigns
        if ($this->variable($name) && $this->literal(':') && $this->valueList($value) && $this->end()) {
            // check for '!flag'
            $assignmentFlags = $this->stripAssignmentFlags($value);
            $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlags], $s);
            return true;
        }
        $this->seek($s);
        // misc
        if ($this->literal('-->')) {
            return true;
        }
        // opening css block
        if ($this->selectors($selectors) && $this->literal('{')) {
            $this->pushBlock($selectors, $s);
            return true;
        }
        $this->seek($s);
        // property assign, or nested assign
        if ($this->propertyName($name) && $this->literal(':')) {
            $foundSomething = false;
            if ($this->valueList($value)) {
                $this->append([Type::T_ASSIGN, $name, $value], $s);
                $foundSomething = true;
            }
            if ($this->literal('{')) {
                $propBlock = $this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s);
                $propBlock->prefix = $name;
                $foundSomething = true;
            } elseif ($foundSomething) {
                $foundSomething = $this->end();
            }
            if ($foundSomething) {
                return true;
            }
        }
        $this->seek($s);
        // closing a block
        if ($this->literal('}')) {
            $block = $this->popBlock();
            if (isset($block->type) && $block->type === Type::T_INCLUDE) {
                $include = $block->child;
                unset($block->child);
                $include[3] = $block;
                $this->append($include, $s);
            } elseif (empty($block->dontAppend)) {
                $type = isset($block->type) ? $block->type : Type::T_BLOCK;
                $this->append([$type, $block], $s);
            }
            return true;
        }
        // extra stuff
        if ($this->literal(';') || $this->literal('<!--')) {
            return true;
        }
        return false;
    }