src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

parse.go (2854B)


      1 package ini
      2 
      3 import (
      4 	"fmt"
      5 	"strings"
      6 )
      7 
      8 func parse(tokens []lineToken, path string) Sections {
      9 	parser := &parser{
     10 		path:     path,
     11 		sections: NewSections(),
     12 	}
     13 	parser.parse(tokens)
     14 	return parser.sections
     15 }
     16 
     17 type parser struct {
     18 	csection, ckey string   // current state
     19 	path           string   // source file path
     20 	sections       Sections // parse result
     21 }
     22 
     23 func (p *parser) parse(tokens []lineToken) {
     24 	for _, otok := range tokens {
     25 		switch tok := otok.(type) {
     26 		case *lineTokenProfile:
     27 			p.handleProfile(tok)
     28 		case *lineTokenProperty:
     29 			p.handleProperty(tok)
     30 		case *lineTokenSubProperty:
     31 			p.handleSubProperty(tok)
     32 		case *lineTokenContinuation:
     33 			p.handleContinuation(tok)
     34 		}
     35 	}
     36 }
     37 
     38 func (p *parser) handleProfile(tok *lineTokenProfile) {
     39 	name := tok.Name
     40 	if tok.Type != "" {
     41 		name = fmt.Sprintf("%s %s", tok.Type, tok.Name)
     42 	}
     43 	p.ckey = ""
     44 	p.csection = name
     45 	if _, ok := p.sections.container[name]; !ok {
     46 		p.sections.container[name] = NewSection(name)
     47 	}
     48 }
     49 
     50 func (p *parser) handleProperty(tok *lineTokenProperty) {
     51 	if p.csection == "" {
     52 		return // LEGACY: don't error on "global" properties
     53 	}
     54 
     55 	p.ckey = tok.Key
     56 	if _, ok := p.sections.container[p.csection].values[tok.Key]; ok {
     57 		section := p.sections.container[p.csection]
     58 		section.Logs = append(p.sections.container[p.csection].Logs,
     59 			fmt.Sprintf(
     60 				"For profile: %v, overriding %v value, with a %v value found in a duplicate profile defined later in the same file %v. \n",
     61 				p.csection, tok.Key, tok.Key, p.path,
     62 			),
     63 		)
     64 		p.sections.container[p.csection] = section
     65 	}
     66 
     67 	p.sections.container[p.csection].values[tok.Key] = Value{
     68 		str: tok.Value,
     69 	}
     70 	p.sections.container[p.csection].SourceFile[tok.Key] = p.path
     71 }
     72 
     73 func (p *parser) handleSubProperty(tok *lineTokenSubProperty) {
     74 	if p.csection == "" {
     75 		return // LEGACY: don't error on "global" properties
     76 	}
     77 
     78 	if p.ckey == "" || p.sections.container[p.csection].values[p.ckey].str != "" {
     79 		// This is an "orphaned" subproperty, either because it's at
     80 		// the beginning of a section or because the last property's
     81 		// value isn't empty. Either way we're lenient here and
     82 		// "promote" this to a normal property.
     83 		p.handleProperty(&lineTokenProperty{
     84 			Key:   tok.Key,
     85 			Value: strings.TrimSpace(trimPropertyComment(tok.Value)),
     86 		})
     87 		return
     88 	}
     89 
     90 	if p.sections.container[p.csection].values[p.ckey].mp == nil {
     91 		p.sections.container[p.csection].values[p.ckey] = Value{
     92 			mp: map[string]string{},
     93 		}
     94 	}
     95 	p.sections.container[p.csection].values[p.ckey].mp[tok.Key] = tok.Value
     96 }
     97 
     98 func (p *parser) handleContinuation(tok *lineTokenContinuation) {
     99 	if p.ckey == "" {
    100 		return
    101 	}
    102 
    103 	value, _ := p.sections.container[p.csection].values[p.ckey]
    104 	if value.str != "" && value.mp == nil {
    105 		value.str = fmt.Sprintf("%s\n%s", value.str, tok.Value)
    106 	}
    107 
    108 	p.sections.container[p.csection].values[p.ckey] = value
    109 }