/** ----------------------------------------------------------------------+ * @desc Split token stream into nodes of type function, comment, * class or method. * @param int Start position * @param Object Node * @param int Depth * @return int ----------------------------------------------------------------------+ */ protected function measure($pos, Lint\Node $node, &$ret) { $start = $this->last_newline($pos); $node->start = $start; if ($node->type === T_FILE) { $node->start_line = 1; $node->empty = false; } else { $node->start_line = $this->tokens[$start][2] + 1; $node->empty = true; } $this->debug(sprintf('In Node `%s` of type `%s` line %d; Owned by `%s`', $node->name, Tokenizer::token_name($node->type), $node->start_line, $node->owner), $node->depth, OPT_SCOPE_MAP, true); $this->scope = array(); $next_node = new Lint\Node(); $last_comment = null; $tokens = $this->tokens; for ($i = $pos; $i < $this->tcount; $i++) { if (count($this->scope) > 0 && $node->empty && Tokenizer::meaningfull($tokens[$i][0]) && $tokens[$i][0] !== T_CURLY_CLOSE) { $node->empty = false; } if (!empty($this->ignore_next) && $tokens[$i][0] === $this->ignore_next[count($this->ignore_next) - 1]) { $node->tokens[] = $tokens[$i]; array_pop($this->ignore_next); continue; } switch ($tokens[$i][0]) { case T_INLINE_HTML: // Gather inline html into one token $node->tokens[] = $tokens[$i]; while (++$i < $this->tcount && in_array($tokens[$i][0], array(T_INLINE_HTML, T_NEWLINE))) { } $i--; break; case T_ELSE: // treat `else if` like `elseif` // perhaps the tokenizer should do this ? if ($tokens[$this->next($i)][0] === T_IF) { $this->tokens[$i][0] = T_ELSEIF; $this->tokens[$i][1] = 'elseif'; $this->ignore_next[] = T_IF; } $this->open_scope($i, $node); break; case T_IF: case T_ELSEIF: case T_THEN: case T_FOREACH: case T_WHILE: case T_SWITCH: $this->open_scope($i, $node); break; case T_FOR: $this->open_scope($i, $node); $this->ignore_next[] = T_SEMICOLON; $this->ignore_next[] = T_SEMICOLON; break; case T_BASIC_CURLY_OPEN: $this->open_scope($i, $node); break; case T_SEMICOLON: $this->close_scope($i, $node); $node->tokens[] = $tokens[$i]; if (empty($this->scope) && $node->empty) { $i++; break 2; } break; case T_CURLY_CLOSE: $this->close_scope($i, $node); if (empty($this->scope) && $node->type !== T_FILE) { $i++; break 2; } break; case T_CURLY_OPEN: $this->ignore_next[] = T_CURLY_CLOSE; break; case T_PUBLIC: case T_PRIVATE: case T_PROTECTED: $next_node->visibility = Tokenizer::token_name($tokens[$i][0]); break; case T_ABSTRACT: $next_node->abstract = true; break; case T_STATIC: $next_node->static = true; break; case T_COMMENT: $node->tokens[] = $tokens[$i]; $node->comments[] = $this->measure_comment($i, $node->depth, $i); break; case T_DOC_COMMENT: $node->tokens[] = $tokens[$i]; if ($last_comment) { $node->comments[] = $last_comment; } $last_comment = $this->measure_comment($i, $node->depth, $i); break; case T_CLASS: case T_INTERFACE: case T_FUNCTION: list($type, $name, $owner) = $this->determine_type($i, $node, $next_node); $next_node->type = $type; $next_node->name = $name; $next_node->depth = $node->depth + 1; $next_node->owner = $owner; $next_node->file = $node->file; if ($last_comment) { $next_node->comments[] = $last_comment; } $node->tokens[] = $tokens[$i]; // preserve scope $scope = $this->scope; $node->nodes[] = $this->measure($i + 1, $next_node, $i); $this->scope = $scope; $next_node = new Lint\Node(); $last_comment = null; break; default: $node->tokens[] = $tokens[$i]; break; } } // In case $i is over the buffer $node->end = $i >= $this->tcount ? --$i : $i; $node->end_line = $tokens[$i][2]; $node->length = $node->end_line - $node->start_line; $node->token_count = count($node->tokens); $ret = $i > 0 ? --$i : $i; $this->debug(sprintf('Exiting Node `%s` of type `%s` line %d', $node->name, Tokenizer::token_name($node->type), $node->end_line), $node->depth, OPT_SCOPE_MAP, true); return $node; }