code: public static <A> TreeNode<Op<A>> of(
  		final int depth,
  		final ISeq<? extends Op<A>> operations,
  		final ISeq<? extends Op<A>> terminals,
  		final Random random
  	) {
  		if (depth < 0) {
  			throw new IllegalArgumentException(
  				"Tree depth is smaller than zero: " + depth
  			);
  		}
  		if (!operations.forAll(o -> !o.isTerminal())) {
  			throw new IllegalArgumentException(
  				"Operation list contains terminal op."
  			);
  		}
  		if (!terminals.forAll(o -> o.isTerminal())) {
  			throw new IllegalArgumentException(
  				"Terminal list contains non-terminal op."
  			);
  		}
  
  		final TreeNode<Op<A>> root = TreeNode.of();
  		fill(depth, root, operations, terminals, random);
  		return root;
  	}
docs: Create a new, random program tree from the given (non) terminal
  operations with the desired depth. The created program tree is a
  <em>full</em> tree.
  
  @since 4.1
  
  @param depth the desired depth of the program tree
  @param operations the list of <em>non</em>-terminal operations
  @param terminals the list of terminal operations
  @param random the random engine used for creating the program
  @param <A> the operational type
  @return a new program tree
  @throws NullPointerException if one of the given operations is
  {@code null}
  @throws IllegalArgumentException if the given tree depth is smaller than
  zero