varsscope.go 10 KB

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