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 }