varsscope.go 9.8 KB

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