private static <A> void fill(
		final int level,
		final TreeNode<Op<A>> tree,
		final ISeq<? extends Op<A>> operations,
		final ISeq<? extends Op<A>> terminals,
		final RandomGenerator random
	) {
		final Op<A> op = level == 0
			? terminals.get(random.nextInt(terminals.size()))
			: operations.get(random.nextInt(operations.size()));

		tree.value(op);

		if (level > 1) {
			for (int i = 0; i < op.arity(); ++i) {
				final TreeNode<Op<A>> node = TreeNode.of();
				fill(level - 1, node, operations, terminals, random);
				tree.attach(node);
			}
		} else {
			for (int i = 0; i < op.arity(); ++i) {
				final Op<A> term = terminals.get(random.nextInt(terminals.size()));
				tree.attach(TreeNode.of(term));
			}
		}
	}
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
jenetics.prog/src/main/java/io/jenetics/prog/op/Program.java