package template import ( "fmt" ) // CompileTemplate scans once, emitting: // - data blocks: inner content between a line that's exactly "{" and a line that's exactly "}" // - matching blocks: gaps between data blocks (excluding the brace lines themselves) func CompileTemplate(template string) ([]Block, error) { var out []Block var curlyIndex int const OPENING = '{' const CLOSING = '}' var start int var blockType BlockType if len(template) > 0 && template[0] == OPENING { blockType = DataBlock } else { blockType = MatchingBlock } for i, r := range template { nextCurlyIndex := curlyIndex switch r { case OPENING: nextCurlyIndex++ case CLOSING: nextCurlyIndex-- } if curlyIndex == 0 && nextCurlyIndex == 1 { if i > start { block, err := ParseTemplateBlock(template[start:i], blockType) if err != nil { return nil, fmt.Errorf("cannot parse block: %w", err) } out = append(out, block) } start = i blockType = DataBlock } else if curlyIndex == 1 && nextCurlyIndex == 0 { if i > start { block, err := ParseTemplateBlock(template[start:i+1], blockType) if err != nil { return nil, fmt.Errorf("cannot parse block: %w", err) } out = append(out, block) } nextChar := ' ' if i+1 < len(template) { nextChar = rune(template[i+1]) } if nextChar == OPENING { start = i + 1 blockType = DataBlock } else { start = i + 1 blockType = MatchingBlock } } curlyIndex = nextCurlyIndex } return out, nil }