varsscope.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package scope
  11. import (
  12. "bytes"
  13. "fmt"
  14. "sort"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "devt.de/krotik/ecal/parser"
  19. )
  20. /*
  21. varsScope models a scope for variables in ECAL.
  22. */
  23. type varsScope struct {
  24. name string // Name of the scope
  25. parent parser.Scope // Parent scope
  26. children []*varsScope // Children of this scope (only if tracking is enabled)
  27. storage map[string]interface{} // Storage for variables
  28. lock sync.RWMutex // Lock for this scope
  29. }
  30. /*
  31. NewScope creates a new variable scope.
  32. */
  33. func NewScope(name string) parser.Scope {
  34. return NewScopeWithParent(name, nil)
  35. }
  36. /*
  37. NewScopeWithParent creates a new variable scope with a parent. This can be
  38. used to create scope structures without children links.
  39. */
  40. func NewScopeWithParent(name string, parent parser.Scope) parser.Scope {
  41. return &varsScope{name, parent, nil, make(map[string]interface{}), sync.RWMutex{}}
  42. }
  43. /*
  44. NewChild creates a new child scope for variables. The new child scope is tracked
  45. by the parent scope. This means it should not be used for global scopes with
  46. many children.
  47. */
  48. func (s *varsScope) NewChild(name string) parser.Scope {
  49. for _, c := range s.children {
  50. if c.name == name {
  51. return c
  52. }
  53. }
  54. child := NewScope(name).(*varsScope)
  55. child.parent = s
  56. s.children = append(s.children, child)
  57. return child
  58. }
  59. /*
  60. Parent returns the parent scope or nil.
  61. */
  62. func (s *varsScope) Parent() parser.Scope {
  63. return s.parent
  64. }
  65. /*
  66. SetValue sets a new value for a variable.
  67. */
  68. func (s *varsScope) SetValue(varName string, varValue interface{}) error {
  69. s.lock.Lock()
  70. defer s.lock.Unlock()
  71. return s.setValue(varName, varValue)
  72. }
  73. /*
  74. setValue sets a new value for a variable.
  75. */
  76. func (s *varsScope) setValue(varName string, varValue interface{}) error {
  77. var err error
  78. // Check for dotted names which access a container structure
  79. if cFields := strings.Split(varName, "."); len(cFields) > 1 {
  80. // Get the container
  81. if container, ok, _ := s.getValue(cFields[0]); ok {
  82. if len(cFields) > 2 {
  83. var containerAccess func(fields []string)
  84. containerAccess = func(fields []string) {
  85. // Get inner container
  86. if mapContainer, ok := container.(map[interface{}]interface{}); ok {
  87. if container, ok = mapContainer[fields[0]]; !ok {
  88. err = fmt.Errorf("Container field %v does not exist",
  89. strings.Join(cFields[:len(cFields)-len(fields)+1], "."))
  90. }
  91. } else if listContainer, ok := container.([]interface{}); ok {
  92. var index int
  93. if index, err = strconv.Atoi(fmt.Sprint(fields[0])); err == nil {
  94. if index < 0 {
  95. // Handle negative numbers
  96. index = len(listContainer) + index
  97. }
  98. if index < len(listContainer) {
  99. container = listContainer[index]
  100. } else {
  101. err = fmt.Errorf("Out of bounds access to list %v with index: %v",
  102. strings.Join(cFields[:len(cFields)-len(fields)], "."), index)
  103. }
  104. } else {
  105. container = nil
  106. err = fmt.Errorf("List %v needs a number index not: %v",
  107. strings.Join(cFields[:len(cFields)-len(fields)], "."), fields[0])
  108. }
  109. } else {
  110. container = nil
  111. err = fmt.Errorf("Variable %v is not a container",
  112. strings.Join(cFields[:len(cFields)-len(fields)], "."))
  113. }
  114. if err == nil && len(fields) > 2 {
  115. containerAccess(fields[1:])
  116. }
  117. }
  118. containerAccess(cFields[1:])
  119. }
  120. if err == nil && container != nil {
  121. fieldIndex := cFields[len(cFields)-1]
  122. if mapContainer, ok := container.(map[interface{}]interface{}); ok {
  123. mapContainer[fieldIndex] = varValue
  124. } else if listContainer, ok := container.([]interface{}); ok {
  125. var index int
  126. if index, err = strconv.Atoi(fieldIndex); err == nil {
  127. if index < 0 {
  128. // Handle negative numbers
  129. index = len(listContainer) + index
  130. }
  131. if index < len(listContainer) {
  132. listContainer[index] = varValue
  133. } else {
  134. err = fmt.Errorf("Out of bounds access to list %v with index: %v",
  135. strings.Join(cFields[:len(cFields)-1], "."), index)
  136. }
  137. } else {
  138. err = fmt.Errorf("List %v needs a number index not: %v",
  139. strings.Join(cFields[:len(cFields)-1], "."), fieldIndex)
  140. }
  141. } else {
  142. err = fmt.Errorf("Variable %v is not a container",
  143. strings.Join(cFields[:len(cFields)-1], "."))
  144. }
  145. }
  146. } else {
  147. err = fmt.Errorf("Variable %v is not a container", cFields[0])
  148. }
  149. return err
  150. }
  151. // Check if the variable is already defined in a parent scope
  152. if vs := s.getScopeForVariable(varName); vs != nil {
  153. s = vs
  154. }
  155. // Set value newly in scope
  156. s.storage[varName] = varValue
  157. return err
  158. }
  159. /*
  160. getScopeForVariable returns the scope (this or a parent scope) which holds a
  161. given variable.
  162. */
  163. func (s *varsScope) getScopeForVariable(varName string) *varsScope {
  164. _, ok := s.storage[varName]
  165. if ok {
  166. return s
  167. } else if s.parent != nil {
  168. return s.parent.(*varsScope).getScopeForVariable(varName)
  169. }
  170. return nil
  171. }
  172. /*
  173. GetValue gets the current value of a variable.
  174. */
  175. func (s *varsScope) GetValue(varName string) (interface{}, bool, error) {
  176. s.lock.Lock()
  177. defer s.lock.Unlock()
  178. return s.getValue(varName)
  179. }
  180. /*
  181. getValue gets the current value of a variable.
  182. */
  183. func (s *varsScope) getValue(varName string) (interface{}, bool, error) {
  184. // Check for dotted names which access a container structure
  185. if cFields := strings.Split(varName, "."); len(cFields) > 1 {
  186. var err error
  187. var containerAccess func(fields []string, container interface{}) (interface{}, bool, error)
  188. // Get the container
  189. container, ok, _ := s.getValue(cFields[0])
  190. if !ok {
  191. return nil, ok, err
  192. }
  193. // Now look into the container and get the value
  194. containerAccess = func(fields []string, container interface{}) (interface{}, bool, error) {
  195. var retContainer interface{}
  196. if mapContainer, ok := container.(map[interface{}]interface{}); ok {
  197. var ok bool
  198. if index, err := strconv.Atoi(fmt.Sprint(fields[0])); err == nil {
  199. // Numbers are usually converted to float64
  200. retContainer, ok = mapContainer[float64(index)]
  201. }
  202. if !ok {
  203. retContainer = mapContainer[fields[0]]
  204. }
  205. } else if listContainer, ok := container.([]interface{}); ok {
  206. var index int
  207. if index, err = strconv.Atoi(fmt.Sprint(fields[0])); err == nil {
  208. if index < 0 {
  209. // Handle negative numbers
  210. index = len(listContainer) + index
  211. }
  212. if index < len(listContainer) {
  213. retContainer = listContainer[index]
  214. } else {
  215. err = fmt.Errorf("Out of bounds access to list %v with index: %v",
  216. strings.Join(cFields[:len(cFields)-len(fields)], "."), index)
  217. }
  218. } else {
  219. err = fmt.Errorf("List %v needs a number index not: %v",
  220. strings.Join(cFields[:len(cFields)-len(fields)], "."), fields[0])
  221. }
  222. } else {
  223. err = fmt.Errorf("Variable %v is not a container",
  224. strings.Join(cFields[:len(cFields)-len(fields)], "."))
  225. }
  226. if err == nil && len(fields) > 1 {
  227. return containerAccess(fields[1:], retContainer)
  228. }
  229. return retContainer, retContainer != nil, err
  230. }
  231. return containerAccess(cFields[1:], container)
  232. }
  233. if vs := s.getScopeForVariable(varName); vs != nil {
  234. ret := vs.storage[varName]
  235. return ret, true, nil
  236. }
  237. return nil, false, nil
  238. }
  239. /*
  240. String returns a string representation of this varsScope and all its
  241. parents.
  242. */
  243. func (s *varsScope) String() string {
  244. s.lock.RLock()
  245. defer s.lock.RUnlock()
  246. return s.scopeStringParents(s.scopeStringChildren())
  247. }
  248. /*
  249. scopeStringChildren returns a string representation of all children scopes.
  250. */
  251. func (s *varsScope) scopeStringChildren() string {
  252. var buf bytes.Buffer
  253. // Write the known child scopes
  254. for i, c := range s.children {
  255. buf.WriteString(c.scopeString(c.scopeStringChildren()))
  256. if i < len(s.children)-1 {
  257. buf.WriteString("\n")
  258. }
  259. }
  260. return buf.String()
  261. }
  262. /*
  263. scopeStringParents returns a string representation of this varsScope
  264. with initial children and all its parents.
  265. */
  266. func (s *varsScope) scopeStringParents(childrenString string) string {
  267. ss := s.scopeString(childrenString)
  268. if s.parent != nil {
  269. return s.parent.(*varsScope).scopeStringParents(ss)
  270. }
  271. return fmt.Sprint(ss)
  272. }
  273. /*
  274. scopeString returns a string representation of this varsScope.
  275. */
  276. func (s *varsScope) scopeString(childrenString string) string {
  277. buf := bytes.Buffer{}
  278. varList := []string{}
  279. buf.WriteString(fmt.Sprintf("%v {\n", s.name))
  280. for k := range s.storage {
  281. varList = append(varList, k)
  282. }
  283. sort.Strings(varList)
  284. for _, v := range varList {
  285. buf.WriteString(fmt.Sprintf(" %s (%T) : %v\n", v, s.storage[v],
  286. EvalToString(s.storage[v])))
  287. }
  288. if childrenString != "" {
  289. // Indent all
  290. buf.WriteString(" ")
  291. buf.WriteString(strings.Replace(childrenString, "\n", "\n ", -1))
  292. buf.WriteString("\n")
  293. }
  294. buf.WriteString("}")
  295. return buf.String()
  296. }