varsscope.go 9.3 KB

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