private void pushBlock(int pendingTextStart, int startPosition, int startLine, int startColumn, char c) {
            parser.expect(c);
            String name = parseArgumentName();

            BlockOperation block;
            switch (c) {
                case '#':
                    // Parse optional key value pair bindings in the form of:
                    // ${#foo as key, value}
                    //       ^  ^    ^ : one or more spaces
                    String keyPrefix = "key";
                    String value = "value";
                    if (parser.peek() == ' ') {
                        parser.sp();
                        parser.expect('a');
                        parser.expect('s');
                        parser.sp();
                        int startPos = parser.position();
                        parser.consumeWhile(this::isNameCharacter);
                        keyPrefix = parser.sliceFrom(startPos);
                        ensureNameIsValid(keyPrefix);
                        parser.expect(',');
                        parser.sp();
                        startPos = parser.position();
                        parser.consumeWhile(this::isNameCharacter);
                        value = parser.sliceFrom(startPos);
                        ensureNameIsValid(value);
                    }
                    block = new BlockOperation.Loop(name, keyPrefix, value);
                    break;
                case '^':
                    block = new BlockOperation.Conditional(name, true);
                    break;
                case '?':
                default:
                    block = new BlockOperation.Conditional(name, false);
            }

            boolean skipTrailingWs = parseStripTrailingWhitespace();
            parser.expect('}');
            handleConditionalOnLine(pendingTextStart, startPosition, startColumn);
            blocks.push(block);

            if (skipTrailingWs) {
                skipTrailingWhitespaceInParser();
            }
        }
A BlockOperation that repeats a template for each value referenced by the block. Each iteration pushes
a state to the writer that includes key, value, key.first, and key.last context properties. The name
of the context property can be customized in the template.
smithy-utils/src/main/java/software/amazon/smithy/utils/CodeFormatter.java