visitor.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package ini
  2. import (
  3. "fmt"
  4. "sort"
  5. )
  6. // Visitor is an interface used by walkers that will
  7. // traverse an array of ASTs.
  8. type Visitor interface {
  9. VisitExpr(AST) error
  10. VisitStatement(AST) error
  11. }
  12. // DefaultVisitor is used to visit statements and expressions
  13. // and ensure that they are both of the correct format.
  14. // In addition, upon visiting this will build sections and populate
  15. // the Sections field which can be used to retrieve profile
  16. // configuration.
  17. type DefaultVisitor struct {
  18. scope string
  19. Sections Sections
  20. }
  21. // NewDefaultVisitor return a DefaultVisitor
  22. func NewDefaultVisitor() *DefaultVisitor {
  23. return &DefaultVisitor{
  24. Sections: Sections{
  25. container: map[string]Section{},
  26. },
  27. }
  28. }
  29. // VisitExpr visits expressions...
  30. func (v *DefaultVisitor) VisitExpr(expr AST) error {
  31. t := v.Sections.container[v.scope]
  32. if t.values == nil {
  33. t.values = values{}
  34. }
  35. switch expr.Kind {
  36. case ASTKindExprStatement:
  37. opExpr := expr.GetRoot()
  38. switch opExpr.Kind {
  39. case ASTKindEqualExpr:
  40. children := opExpr.GetChildren()
  41. if len(children) <= 1 {
  42. return NewParseError("unexpected token type")
  43. }
  44. rhs := children[1]
  45. // The right-hand value side the equality expression is allowed to contain '[', ']', ':', '=' in the values.
  46. // If the token is not either a literal or one of the token types that identifies those four additional
  47. // tokens then error.
  48. if !(rhs.Root.Type() == TokenLit || rhs.Root.Type() == TokenOp || rhs.Root.Type() == TokenSep) {
  49. return NewParseError("unexpected token type")
  50. }
  51. key := EqualExprKey(opExpr)
  52. v, err := newValue(rhs.Root.ValueType, rhs.Root.base, rhs.Root.Raw())
  53. if err != nil {
  54. return err
  55. }
  56. t.values[key] = v
  57. default:
  58. return NewParseError(fmt.Sprintf("unsupported expression %v", expr))
  59. }
  60. default:
  61. return NewParseError(fmt.Sprintf("unsupported expression %v", expr))
  62. }
  63. v.Sections.container[v.scope] = t
  64. return nil
  65. }
  66. // VisitStatement visits statements...
  67. func (v *DefaultVisitor) VisitStatement(stmt AST) error {
  68. switch stmt.Kind {
  69. case ASTKindCompletedSectionStatement:
  70. child := stmt.GetRoot()
  71. if child.Kind != ASTKindSectionStatement {
  72. return NewParseError(fmt.Sprintf("unsupported child statement: %T", child))
  73. }
  74. name := string(child.Root.Raw())
  75. v.Sections.container[name] = Section{}
  76. v.scope = name
  77. default:
  78. return NewParseError(fmt.Sprintf("unsupported statement: %s", stmt.Kind))
  79. }
  80. return nil
  81. }
  82. // Sections is a map of Section structures that represent
  83. // a configuration.
  84. type Sections struct {
  85. container map[string]Section
  86. }
  87. // GetSection will return section p. If section p does not exist,
  88. // false will be returned in the second parameter.
  89. func (t Sections) GetSection(p string) (Section, bool) {
  90. v, ok := t.container[p]
  91. return v, ok
  92. }
  93. // values represents a map of union values.
  94. type values map[string]Value
  95. // List will return a list of all sections that were successfully
  96. // parsed.
  97. func (t Sections) List() []string {
  98. keys := make([]string, len(t.container))
  99. i := 0
  100. for k := range t.container {
  101. keys[i] = k
  102. i++
  103. }
  104. sort.Strings(keys)
  105. return keys
  106. }
  107. // Section contains a name and values. This represent
  108. // a sectioned entry in a configuration file.
  109. type Section struct {
  110. Name string
  111. values values
  112. }
  113. // Has will return whether or not an entry exists in a given section
  114. func (t Section) Has(k string) bool {
  115. _, ok := t.values[k]
  116. return ok
  117. }
  118. // ValueType will returned what type the union is set to. If
  119. // k was not found, the NoneType will be returned.
  120. func (t Section) ValueType(k string) (ValueType, bool) {
  121. v, ok := t.values[k]
  122. return v.Type, ok
  123. }
  124. // Bool returns a bool value at k
  125. func (t Section) Bool(k string) bool {
  126. return t.values[k].BoolValue()
  127. }
  128. // Int returns an integer value at k
  129. func (t Section) Int(k string) int64 {
  130. return t.values[k].IntValue()
  131. }
  132. // Float64 returns a float value at k
  133. func (t Section) Float64(k string) float64 {
  134. return t.values[k].FloatValue()
  135. }
  136. // String returns the string value at k
  137. func (t Section) String(k string) string {
  138. _, ok := t.values[k]
  139. if !ok {
  140. return ""
  141. }
  142. return t.values[k].StringValue()
  143. }