package template // 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(templateSource string) ([]Block, error) { var out []Block var curlyIndex int const OPENING = '{' const CLOSING = '}' var start int var blockType BlockType template := NewSlice(templateSource) if template.Len() > 0 && template.At(0) == OPENING { blockType = DataBlock } else { blockType = MatchingBlock } for i, r := range template.Chars() { nextCurlyIndex := curlyIndex switch r { case OPENING: nextCurlyIndex++ case CLOSING: nextCurlyIndex-- } if curlyIndex == 0 && nextCurlyIndex == 1 { if i > start { block, err := ParseTemplateBlock(template.Slice(start, i), blockType) if err != nil { return nil, NewErrorf("cannot parse block @pos -> %w", err).WithPosition(start, i) } out = append(out, block) } start = i blockType = DataBlock } else if curlyIndex == 1 && nextCurlyIndex == 0 { if i > start { block, err := ParseTemplateBlock(template.Slice(start, i), blockType) if err != nil { return nil, NewErrorf("cannot parse block @pos -> %w", err).WithPosition(start, i) } out = append(out, block) } nextChar := ' ' if i+1 < template.Len() { nextChar = rune(template.At(i + 1)) } if nextChar == OPENING { start = i + 1 blockType = DataBlock } else { start = i + 1 blockType = MatchingBlock } } curlyIndex = nextCurlyIndex } return out, nil }