wikitext-parser/template.go

191 lines
4.3 KiB
Go

package wikitext_parser
import (
"fmt"
"strings"
)
type Template struct {
Name string
IsLink bool
Parameters map[string][]interface{}
UnkeyedIndex int
}
func NewTemplate(name string, isLink bool) *Template {
return &Template{
Name: name,
IsLink: isLink,
Parameters: make(map[string][]interface{}),
}
}
func (t *Template) AddParameterUnkeyed(value interface{}) {
t.AddParameter(fmt.Sprintf("%d", t.UnkeyedIndex), value)
}
func (t *Template) AddParameter(key string, value interface{}) {
if _, ok := t.Parameters[key]; !ok {
t.Parameters[key] = make([]interface{}, 0, 1)
}
t.Parameters[key] = append(t.Parameters[key], value)
}
func ParseTemplate(text string, index int, depth int, startCharacter byte) (i int, template *Template) {
var c byte
lastToken := index
var key string
addValue := func() int {
if lastToken < len(text) && i-lastToken > 0 {
t := strings.TrimSpace(text[lastToken:i])
if len(t) > 0 {
if template == nil {
template = NewTemplate(t, startCharacter == '[')
} else {
if key == "" {
template.AddParameterUnkeyed(text[lastToken:i])
} else {
template.AddParameter(key, text[lastToken:i])
}
}
}
return len(t)
}
return 0
}
addKey := func() {
if lastToken < len(text) && i-lastToken > 0 {
t := strings.TrimSpace(text[lastToken:i])
if len(t) > 0 {
key = t
}
}
}
afterNewLine := false
for i = index; i < len(text); i++ {
c = text[i]
if startCharacter == '{' && c == '}' && i < len(text)-1 && text[i+1] == '}' { //end of template
addValue()
i += 2
break
} else if startCharacter == '[' && c == ']' && i < len(text)-1 && text[i+1] == ']' { //end of link
addValue()
i += 2
break
//template or light might have parameters
} else if (c == '{' && i < len(text)-1 && text[i+1] == '{') || (c == '[' && i < len(text)-1 && text[i+1] == '[') {
addValue()
var tpl *Template
var scanIndex int
scanIndex, tpl = ParseTemplate(text, i+2, depth+1, c)
if tpl != nil {
if key == "" {
template.AddParameterUnkeyed(tpl)
} else {
template.AddParameter(key, tpl)
}
}
lastToken = scanIndex
i = scanIndex - 1
} else if (c == '{' && i < len(text)-1 && text[i+1] != '{' && text[i+1] != '[') || (c == '[' && i < len(text)-1 && text[i+1] != '[' && text[i+1] != '{') {
addValue()
var link *Link
var scanIndex int
scanIndex, link = ParseLink(text, i+1, depth+1, c)
if link != nil && template != nil {
if key == "" {
template.AddParameterUnkeyed(link)
} else {
template.AddParameter(key, link)
}
}
lastToken = scanIndex
i = scanIndex - 1
} else if c == '<' { //html trigger
addValue()
var html *HTML
var scanIndex int
scanIndex, html = ParseHTML(text, i, depth+1)
if html != nil && template != nil {
if key == "" {
template.AddParameterUnkeyed(html)
} else {
template.AddParameter(key, html)
}
}
lastToken = scanIndex
i = scanIndex - 1
} else if c == '|' {
hasTemplate := template != nil
addValue()
lastToken = i + 1
if hasTemplate {
template.UnkeyedIndex++
}
key = ""
} else if c == '\n' {
addValue()
lastToken = i + 1
afterNewLine = true
if template != nil {
if key == "" {
template.AddParameterUnkeyed(NewLineToken{})
} else {
template.AddParameter(key, NewLineToken{})
}
}
} else if afterNewLine && (c == '*' || c == '#') {
addValue()
var list *UnorderedList
var scanIndex int
scanIndex, list = ParseUnorderedList(text, i, depth+1, 1, c)
if list != nil {
if key == "" {
template.AddParameterUnkeyed(list)
} else {
template.AddParameter(key, list)
}
}
lastToken = scanIndex
i = scanIndex - 1
} else if afterNewLine && c == ';' {
addValue()
var list *DescriptionList
var scanIndex int
scanIndex, list = ParseDescriptionList(text, i+1, depth+1)
if list != nil {
if key == "" {
template.AddParameterUnkeyed(list)
} else {
template.AddParameter(key, list)
}
}
lastToken = scanIndex
i = scanIndex - 1
} else if afterNewLine && c == ':' {
addValue()
lastToken = i + 1
} else if c == '=' {
if key == "" {
addKey()
lastToken = i + 1
}
}
if afterNewLine && c != '\n' && c != ' ' && c != '\t' {
afterNewLine = false
}
}
return
}