FormattingNode COMPOSITE(String keyword) throws ScanException {
        CompositeNode compositeNode = new CompositeNode(keyword);

        Node childNode = E();
        compositeNode.setChildNode(childNode);

        Token t = getNextToken();

        if (t == null || t.getType() != Token.RIGHT_PARENTHESIS) {
            String msg = "Expecting RIGHT_PARENTHESIS token but got " + t;
            addError(msg);
            addError("See also " + MISSING_RIGHT_PARENTHESIS);
            throw new ScanException(msg);
        }
        Token ot = getCurentToken();
        if (ot != null && ot.getType() == Token.OPTION) {
            List<String> optionList = ot.getOptionsList();
            compositeNode.setOptions(optionList);
            advanceTokenPointer();
        }
        return compositeNode;
    }
@Test
    public void testComposite() throws Exception {
        {
            Parser<Object> p = new Parser<>("hello%(%child)");
            Node t = p.parse();

            Node witness = new Node(Node.LITERAL, "hello");
            CompositeNode composite = new CompositeNode(BARE);
            Node child = new SimpleKeywordNode("child");
            composite.setChildNode(child);
            witness.next = composite;

            // System.out.println("w:" + witness);
            // System.out.println(t);

            Assertions.assertEquals(witness, t);
        }

        // System.out.println("testRecursive part 2");
        {
            Parser<Object> p = new Parser<>("hello%(%child )");
            Node t = p.parse();

            Node witness = new Node(Node.LITERAL, "hello");
            CompositeNode composite = new CompositeNode(BARE);
            Node child = new SimpleKeywordNode("child");
            composite.setChildNode(child);
            witness.next = composite;
            child.next = new Node(Node.LITERAL, " ");
            Assertions.assertEquals(witness, t);
        }

        {
            Parser<Object> p = new Parser<>("hello%(%child %h)");
            Node t = p.parse();
            Node witness = new Node(Node.LITERAL, "hello");
            CompositeNode composite = new CompositeNode(BARE);
            Node child = new SimpleKeywordNode("child");
            composite.setChildNode(child);
            child.next = new Node(Node.LITERAL, " ");
            child.next.next = new SimpleKeywordNode("h");
            witness.next = composite;
            Assertions.assertEquals(witness, t);
        }

        {
            Parser<Object> p = new Parser<>("hello%(%child %h) %m");
            Node t = p.parse();
            Node witness = new Node(Node.LITERAL, "hello");
            CompositeNode composite = new CompositeNode(BARE);
            Node child = new SimpleKeywordNode("child");
            composite.setChildNode(child);
            child.next = new Node(Node.LITERAL, " ");
            child.next.next = new SimpleKeywordNode("h");
            witness.next = composite;
            composite.next = new Node(Node.LITERAL, " ");
            composite.next.next = new SimpleKeywordNode("m");
            Assertions.assertEquals(witness, t);
        }

        {
            Parser<Object> p = new Parser<>("hello%( %child \\(%h\\) ) %m");
            Node t = p.parse();
            Node witness = new Node(Node.LITERAL, "hello");
            CompositeNode composite = new CompositeNode(BARE);
            Node child = new Node(Node.LITERAL, " ");
            composite.setChildNode(child);
            Node c = child;
            c = c.next = new SimpleKeywordNode("child");
            c = c.next = new Node(Node.LITERAL, " (");
            c = c.next = new SimpleKeywordNode("h");
            c = c.next = new Node(Node.LITERAL, ") ");
            witness.next = composite;
            composite.next = new Node(Node.LITERAL, " ");
            composite.next.next = new SimpleKeywordNode("m");
            Assertions.assertEquals(witness, t);
        }

    }