original_string: public function parse(Array $tokens)
  	{	
  		// if groups are mis-matched, short-circuit
  		if ($this->countGroupOpen($tokens) !== $this->countGroupClose($tokens)) {
  			throw new \InvalidArgumentException(
  				__METHOD__."() expects parameter one, tokens, to be valid RTF "
  				 . "string; however, the number of groups opened does not equal "
  				 . "the number of groups closed"
  			);
  		}
  		
  		$root  = null;
  		
  		// loop through the tokens
  		$stack = new \SplStack();
  		foreach ($tokens as $token) {
  			// if the token is a group-open token
  			if ($token instanceof Token\Group\Open) {
  				$this->parseGroupOpen($token, $stack, $root);
  				if ($root === null) {
  					$root = $stack->bottom();
  				}
  			} else {
  				// if at least a root group exists
  				if ($stack->count()) {
  					if ($token instanceof Token\Group\Close) {
  						$this->parseGroupClose($token, $stack);
  					} elseif ($token instanceof Token\Control\Word) {
  						$this->parseControlWord($token, $stack->top());
  					} elseif ($token instanceof Token\Control\Symbol) {
  						$this->parseControlSymbol($token, $stack->top());
  					} elseif ($token instanceof Token\Text) {
  						$this->parseText($token, $stack->top());
  					}
  				} else {
  					// otherwise, ignore the tokens
  					// hmmm, this is good because if text preceeds the root group 
  					//     (observed in wild) it's ignored as it should be; however, 
  					//     it's also bad, because if an extra bracket closes the 
  					//     root-group early (also observed in the wild), it's not an 
  					//     error
  					//
  				}
  			}
  		}
  		
  		return $root;
  	}
code: public function parse(Array $tokens)
  	{	
  		// if groups are mis-matched, short-circuit
  		if ($this->countGroupOpen($tokens) !== $this->countGroupClose($tokens)) {
  			throw new \InvalidArgumentException(
  				__METHOD__."() expects parameter one, tokens, to be valid RTF "
  				 . "string; however, the number of groups opened does not equal "
  				 . "the number of groups closed"
  			);
  		}
  		
  		$root  = null;
  		
  		// loop through the tokens
  		$stack = new \SplStack();
  		foreach ($tokens as $token) {
  			// if the token is a group-open token
  			if ($token instanceof Token\Group\Open) {
  				$this->parseGroupOpen($token, $stack, $root);
  				if ($root === null) {
  					$root = $stack->bottom();
  				}
  			} else {
  				// if at least a root group exists
  				if ($stack->count()) {
  					if ($token instanceof Token\Group\Close) {
  						$this->parseGroupClose($token, $stack);
  					} elseif ($token instanceof Token\Control\Word) {
  						$this->parseControlWord($token, $stack->top());
  					} elseif ($token instanceof Token\Control\Symbol) {
  						$this->parseControlSymbol($token, $stack->top());
  					} elseif ($token instanceof Token\Text) {
  						$this->parseText($token, $stack->top());
  					}
  				} else {
  					// otherwise, ignore the tokens
  					// hmmm, this is good because if text preceeds the root group 
  					//     (observed in wild) it's ignored as it should be; however, 
  					//     it's also bad, because if an extra bracket closes the 
  					//     root-group early (also observed in the wild), it's not an 
  					//     error
  					//
  				}
  			}
  		}
  		
  		return $root;
  	}
code_tokens: public function parse ( Array $ tokens ) { // if groups are mis-matched, short-circuit if ( $ this -> countGroupOpen ( $ tokens ) !== $ this -> countGroupClose ( $ tokens ) ) { throw new \ InvalidArgumentException ( __METHOD__ . "() expects parameter one, tokens, to be valid RTF " . "string; however, the number of groups opened does not equal " . "the number of groups closed" ) ; } $ root = null ; // loop through the tokens $ stack = new \ SplStack ( ) ; foreach ( $ tokens as $ token ) { // if the token is a group-open token if ( $ token instanceof Token \ Group \ Open ) { $ this -> parseGroupOpen ( $ token , $ stack , $ root ) ; if ( $ root === null ) { $ root = $ stack -> bottom ( ) ; } } else { // if at least a root group exists if ( $ stack -> count ( ) ) { if ( $ token instanceof Token \ Group \ Close ) { $ this -> parseGroupClose ( $ token , $ stack ) ; } elseif ( $ token instanceof Token \ Control \ Word ) { $ this -> parseControlWord ( $ token , $ stack -> top ( ) ) ; } elseif ( $ token instanceof Token \ Control \ Symbol ) { $ this -> parseControlSymbol ( $ token , $ stack -> top ( ) ) ; } elseif ( $ token instanceof Token \ Text ) { $ this -> parseText ( $ token , $ stack -> top ( ) ) ; } } else { // otherwise, ignore the tokens // hmmm, this is good because if text preceeds the root group  //     (observed in wild) it's ignored as it should be; however,  //     it's also bad, because if an extra bracket closes the  //     root-group early (also observed in the wild), it's not an  //     error // } } } return $ root ; }
docstring: Parses tokens into a parse tree
  
  @param  Jstewmc\Rtf\Token[]  $tokens  an array of tokens to parse
  @return  Jstewmc\Rtf\Element\Group|null  the parse tree's root group (or
  null if $tokens is an empty array)
  @throws  InvalidArgumentException  if groups are mismatched in $tokens
  @since  0.1.0
  @since  0.4.2  add test for group-open and group-close mismatch
docstring_tokens: Parses tokens into a parse tree