2017-11-07 22:38:15 +00:00
|
|
|
//+lbuild experiment
|
2017-10-21 00:27:47 +00:00
|
|
|
|
|
|
|
// ! EXPERIMENTAL
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-02-21 03:32:53 +00:00
|
|
|
"errors"
|
|
|
|
"regexp"
|
2017-10-21 00:27:47 +00:00
|
|
|
)
|
|
|
|
|
2017-11-07 22:38:15 +00:00
|
|
|
type Mango struct {
|
2022-02-21 03:32:53 +00:00
|
|
|
tagFinder *regexp.Regexp
|
2017-11-06 16:24:45 +00:00
|
|
|
}
|
2017-10-21 00:27:47 +00:00
|
|
|
|
2017-11-07 22:38:15 +00:00
|
|
|
func (m *Mango) Init() {
|
2022-02-21 03:32:53 +00:00
|
|
|
m.tagFinder = regexp.MustCompile(`(?s)\{\{(.*)\}\}`)
|
2017-10-21 00:27:47 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 22:38:15 +00:00
|
|
|
func (m *Mango) Parse(tmpl string) (out string, err error) {
|
2022-02-21 03:32:53 +00:00
|
|
|
tagIndices := m.tagFinder.FindAllStringIndex(tmpl, -1)
|
|
|
|
if len(tagIndices) > 0 {
|
|
|
|
if tagIndices[0][0] == 0 {
|
|
|
|
return "", errors.New("We don't support tags in the outermost layer yet")
|
|
|
|
}
|
|
|
|
var lastTag = 0
|
|
|
|
var lastID = 0
|
|
|
|
for _, tagIndex := range tagIndices {
|
|
|
|
var nestingLayer = 0
|
|
|
|
for i := tagIndex[0]; i > 0; i-- {
|
|
|
|
switch tmpl[i] {
|
|
|
|
case '>':
|
|
|
|
ii, closeTag, err := m.tasteTagToLeft(tmpl, i)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if closeTag {
|
|
|
|
nestingLayer++
|
|
|
|
} else {
|
|
|
|
_, tagID := m.parseTag(tmpl, ii, i)
|
|
|
|
if tagID == "" {
|
|
|
|
out += tmpl[lastTag:ii] + m.injectID(ii, i)
|
|
|
|
lastID++
|
|
|
|
} else {
|
|
|
|
out += tmpl[lastTag:i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case '<':
|
2017-10-21 00:27:47 +00:00
|
|
|
|
2022-02-21 03:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "", nil
|
2017-11-07 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mango) injectID(start int, end int) string {
|
2022-02-21 03:32:53 +00:00
|
|
|
return ""
|
2017-11-07 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mango) parseTag(tmpl string, start int, end int) (tagType string, tagID string) {
|
2022-02-21 03:32:53 +00:00
|
|
|
var i = start
|
|
|
|
for ; i < end; i++ {
|
|
|
|
if tmpl[i] == ' ' {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tagType = tmpl[start:i]
|
|
|
|
i = start
|
|
|
|
for ; i < (end - 4); i++ {
|
|
|
|
if tmpl[i] == ' ' && tmpl[i+1] == 'i' && tmpl[i+2] == 'd' && tmpl[i+3] == '=' {
|
|
|
|
tagID = m.extractAttributeContents(tmpl, i+4, end)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return tagType, tagID
|
2017-11-07 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mango) extractAttributeContents(tmpl string, i int, end int) (contents string) {
|
2022-02-21 03:32:53 +00:00
|
|
|
var start = i
|
|
|
|
var quoteChar byte = 0 // nolint
|
|
|
|
if m.isHTMLQuoteChar(tmpl[i]) {
|
|
|
|
i++
|
|
|
|
quoteChar = tmpl[i]
|
|
|
|
}
|
|
|
|
i += 3
|
|
|
|
for ; i < end; i++ {
|
|
|
|
if quoteChar != 0 {
|
|
|
|
if tmpl[i] == quoteChar {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
} else if tmpl[i] == ' ' {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return tmpl[start:i]
|
2017-11-07 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mango) isHTMLQuoteChar(char byte) bool {
|
2022-02-21 03:32:53 +00:00
|
|
|
return char == '\'' || char == '"'
|
2017-10-21 00:27:47 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 22:38:15 +00:00
|
|
|
func (m *Mango) tasteTagToLeft(tmpl string, index int) (indexOut int, closeTag bool, err error) {
|
2022-02-21 03:32:53 +00:00
|
|
|
var foundLeftBrace = false
|
|
|
|
for ; index > 0; index-- {
|
|
|
|
// What if the / isn't adjacent to the < but has a space instead? Is that even valid?
|
|
|
|
if index >= 1 && tmpl[index] == '/' && tmpl[index-1] == '<' {
|
|
|
|
closeTag = true
|
|
|
|
break
|
|
|
|
} else if tmpl[index] == '<' {
|
|
|
|
foundLeftBrace = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !foundLeftBrace {
|
|
|
|
return index, closeTag, errors.New("The left portion of the tag is missing")
|
|
|
|
}
|
|
|
|
return index, closeTag, nil
|
2017-10-21 00:27:47 +00:00
|
|
|
}
|