Lexer.php
protected function scanControlStatement($type, array $names, $nameAttribute = null)
    {

        foreach ($names as $name) {

            if (!$this->match("{$name}[:\t \n]"))
                continue;

            $this->consumeMatch();
            $this->readSpaces();

            $token = $this->createToken($type);
            if ($nameAttribute)
                $token[$nameAttribute] = str_replace(' ', '', $name);
            $token['subject'] = null;

            //each is a special little unicorn
            if ($name === 'each') {

                if (!$this->match(
                    '\$?(?<itemName>[a-zA-Z_][a-zA-Z0-9_]*)(?:[\t ]*,[\t ]*\$?(?<keyName>[a-zA-Z_][a-zA-Z0-9_]*))?[\t ]+in[\t ]+'
                )) {
                    $this->throwException(
                        "The syntax for each is `each [$]itemName[, [$]keyName]] in [subject]`, not ".$this->peek(20)
                    );
                }

                $this->consumeMatch();
                $token['itemName'] = $this->getMatch('itemName');
                $token['keyName'] = $this->getMatch('keyName');
                $this->readSpaces();
            }

            if ($this->peek() === '(') {

                $this->consume();
                $token['subject'] = $this->readBracketContents();

                if ($this->peek() !== ')')
                    $this->throwException(
                        "A closing [`)`] is missing in a control statement subject"
                    );

                $this->consume();
            } elseif ($this->match("([^:\n]+)")) {

                $this->consumeMatch();
                $token['subject'] = trim($this->getMatch(1));
            }

            yield $token;

            foreach ($this->scanSub() as $subToken)
                yield $subToken;
        }
    }
protected function scanControlStatement($type, array $names, $nameAttribute = null)
    {

        foreach ($names as $name) {

            if (!$this->match("{$name}[:\t \n]"))
                continue;

            $this->consumeMatch();
            $this->readSpaces();

            $token = $this->createToken($type);
            if ($nameAttribute)
                $token[$nameAttribute] = str_replace(' ', '', $name);
            $token['subject'] = null;

            //each is a special little unicorn
            if ($name === 'each') {

                if (!$this->match(
                    '\$?(?<itemName>[a-zA-Z_][a-zA-Z0-9_]*)(?:[\t ]*,[\t ]*\$?(?<keyName>[a-zA-Z_][a-zA-Z0-9_]*))?[\t ]+in[\t ]+'
                )) {
                    $this->throwException(
                        "The syntax for each is `each [$]itemName[, [$]keyName]] in [subject]`, not ".$this->peek(20)
                    );
                }

                $this->consumeMatch();
                $token['itemName'] = $this->getMatch('itemName');
                $token['keyName'] = $this->getMatch('keyName');
                $this->readSpaces();
            }

            if ($this->peek() === '(') {

                $this->consume();
                $token['subject'] = $this->readBracketContents();

                if ($this->peek() !== ')')
                    $this->throwException(
                        "A closing [`)`] is missing in a control statement subject"
                    );

                $this->consume();
            } elseif ($this->match("([^:\n]+)")) {

                $this->consumeMatch();
                $token['subject'] = trim($this->getMatch(1));
            }

            yield $token;

            foreach ($this->scanSub() as $subToken)
                yield $subToken;
        }
    }
protected function scanControlStatement ( $ type , array $ names , $ nameAttribute = null ) { foreach ( $ names as $ name ) { if ( ! $ this -> match ( "{$name}[:\t \n]" ) ) continue ; $ this -> consumeMatch ( ) ; $ this -> readSpaces ( ) ; $ token = $ this -> createToken ( $ type ) ; if ( $ nameAttribute ) $ token [ $ nameAttribute ] = str_replace ( ' ' , '' , $ name ) ; $ token [ 'subject' ] = null ; //each is a special little unicorn if ( $ name === 'each' ) { if ( ! $ this -> match ( '\$?(?<itemName>[a-zA-Z_][a-zA-Z0-9_]*)(?:[\t ]*,[\t ]*\$?(?<keyName>[a-zA-Z_][a-zA-Z0-9_]*))?[\t ]+in[\t ]+' ) ) { $ this -> throwException ( "The syntax for each is `each [$]itemName[, [$]keyName]] in [subject]`, not " . $ this -> peek ( 20 ) ) ; } $ this -> consumeMatch ( ) ; $ token [ 'itemName' ] = $ this -> getMatch ( 'itemName' ) ; $ token [ 'keyName' ] = $ this -> getMatch ( 'keyName' ) ; $ this -> readSpaces ( ) ; } if ( $ this -> peek ( ) === '(' ) { $ this -> consume ( ) ; $ token [ 'subject' ] = $ this -> readBracketContents ( ) ; if ( $ this -> peek ( ) !== ')' ) $ this -> throwException ( "A closing [`)`] is missing in a control statement subject" ) ; $ this -> consume ( ) ; } elseif ( $ this -> match ( "([^:\n]+)" ) ) { $ this -> consumeMatch ( ) ; $ token [ 'subject' ] = trim ( $ this -> getMatch ( 1 ) ) ; } yield $ token ; foreach ( $ this -> scanSub ( ) as $ subToken ) yield $ subToken ; } }
Scans for a control-statement-kind of token.

e.g.
control-statement-name ($expression)

Since the <each>-statement is a special little unicorn, it
get's handled very specifically inside this function (But correctly!)

If the condition can have a subject, the subject
will be set as the "subject"-value of the token

@todo Avoid block parsing on <do>-loops

@param string      $type          The token type that should be created if scan is successful
@param array       $names         The names the statement can have (e.g. do, while, if, else etc.)
@param string|null $nameAttribute The attribute the name gets saved into, if wanted

@return \Generator
@throws \Tale\Jade\Lexer\Exception
Scans for a control - statement - kind of token .