98 lines
1.9 KiB
Go
98 lines
1.9 KiB
Go
package parser
|
|
|
|
type BlockType string
|
|
|
|
const (
|
|
BlockData BlockType = "data" // content between lines "{" and "}"
|
|
BlockMatching BlockType = "matching" // everything outside data blocks
|
|
)
|
|
|
|
type Block struct {
|
|
Type BlockType
|
|
Start, End int // byte offsets [Start, End)
|
|
src *string
|
|
}
|
|
|
|
func (b Block) GetContent() string {
|
|
if b.src == nil || b.Start < 0 || b.End > len(*b.src) || b.Start > b.End {
|
|
return ""
|
|
}
|
|
return (*b.src)[b.Start:b.End]
|
|
}
|
|
|
|
// ExtractBlocks 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 ExtractBlocks(src string) []Block {
|
|
var out []Block
|
|
var curlyIndex int
|
|
|
|
const CLOSING = '}'
|
|
const OPENING = '{'
|
|
|
|
if len(src) > 0 && src[0] == OPENING {
|
|
curlyIndex = 1
|
|
out = append(out, Block{
|
|
Start: 0,
|
|
Type: BlockData,
|
|
src: &src,
|
|
})
|
|
} else {
|
|
out = append(out, Block{
|
|
Start: 0,
|
|
Type: BlockMatching,
|
|
src: &src,
|
|
})
|
|
}
|
|
|
|
for i, r := range src {
|
|
|
|
var nextCurlyIndex = curlyIndex
|
|
|
|
switch r {
|
|
case OPENING:
|
|
nextCurlyIndex++
|
|
case CLOSING:
|
|
nextCurlyIndex--
|
|
}
|
|
|
|
var nextChar rune = ' '
|
|
if i+1 < len(src) {
|
|
nextChar = rune(src[i+1])
|
|
}
|
|
|
|
if curlyIndex == 0 && nextCurlyIndex == 1 {
|
|
out[len(out)-1].End = i
|
|
out = append(out, Block{
|
|
Start: i,
|
|
Type: BlockData,
|
|
src: &src,
|
|
})
|
|
} else if curlyIndex == 1 && nextCurlyIndex == 0 {
|
|
out[len(out)-1].End = i + 1
|
|
if nextChar == OPENING {
|
|
out = append(out, Block{
|
|
Start: i + 1,
|
|
Type: BlockData,
|
|
src: &src,
|
|
})
|
|
} else {
|
|
out = append(out, Block{
|
|
Start: i + 1,
|
|
Type: BlockMatching,
|
|
src: &src,
|
|
})
|
|
}
|
|
}
|
|
|
|
curlyIndex = nextCurlyIndex
|
|
}
|
|
|
|
var lastBlock = out[len(out)-1]
|
|
if lastBlock.End == 0 {
|
|
out = out[:len(out)-1]
|
|
}
|
|
|
|
return out
|
|
}
|