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;
	}
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;
	}
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 ; }
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
Parses tokens into a parse tree