docs: static <B> TreeNode<B> parse(
  		final String value,
  		final Function<? super String, ? extends B> mapper
  	) {
  		requireNonNull(value);
  		requireNonNull(mapper);
  
  		final TreeNode<B> root = TreeNode.of();
  		final Deque<TreeNode<B>> parents = new ArrayDeque<>();
  
  		TreeNode<B> current = root;
  		for (Token token : tokenize(value.trim())) {
  			switch (token.seq) {
  				case "(":
  					if (current == null) {
  						throw new IllegalArgumentException(format(
  							"Illegal parentheses tree string: '%s'.",
  							value
  						));
  					}
  
  					final TreeNode<B> tn1 = TreeNode.of();
  					current.attach(tn1);
  					parents.push(current);
  					current = tn1;
  					break;
  				case ",":
  					if (parents.isEmpty()) {
  						throw new IllegalArgumentException(format(
  							"Expect '(' at position %d.",
  							token.pos
  						));
  					}
  
  					final TreeNode<B> tn2 = TreeNode.of();
  					assert parents.peek() != null;
  					parents.peek().attach(tn2);
  					current = tn2;
  					break;
  				case ")":
  					if (parents.isEmpty()) {
  						throw new IllegalArgumentException(format(
  							"Unbalanced parentheses at position %d.",
  							token.pos
  						));
  					}
  					current = parents.pop();
  					if (parents.isEmpty()) {
  						current = null;
  					}
  					break;
  				default:
  					if (current == null) {
  						throw new IllegalArgumentException(format(
  							"More than one root element at pos %d: '%s'.",
  							token.pos, value
  						));
  					}
  					if (current.getValue() == null) {
  						current.setValue(mapper.apply(token.seq));
  					}
  					break;
  			}
  		}
  
  		if (!parents.isEmpty()) {
  			throw new IllegalArgumentException("Unbalanced parentheses.");
  		}
  
  		return root;
  	}