rt_value.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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 interpreter
  11. import (
  12. "fmt"
  13. "strconv"
  14. "strings"
  15. "devt.de/krotik/ecal/parser"
  16. "devt.de/krotik/ecal/scope"
  17. )
  18. /*
  19. numberValueRuntime is the runtime component for constant numeric values.
  20. */
  21. type numberValueRuntime struct {
  22. *baseRuntime
  23. numValue float64 // Numeric value
  24. }
  25. /*
  26. numberValueRuntimeInst returns a new runtime component instance.
  27. */
  28. func numberValueRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  29. return &numberValueRuntime{newBaseRuntime(erp, node), 0}
  30. }
  31. /*
  32. Validate this node and all its child nodes.
  33. */
  34. func (rt *numberValueRuntime) Validate() error {
  35. err := rt.baseRuntime.Validate()
  36. if err == nil {
  37. rt.numValue, err = strconv.ParseFloat(rt.node.Token.Val, 64)
  38. }
  39. return err
  40. }
  41. /*
  42. Eval evaluate this runtime component.
  43. */
  44. func (rt *numberValueRuntime) Eval(vs parser.Scope, is map[string]interface{}) (interface{}, error) {
  45. _, err := rt.baseRuntime.Eval(vs, is)
  46. return rt.numValue, err
  47. }
  48. /*
  49. stringValueRuntime is the runtime component for constant string values.
  50. */
  51. type stringValueRuntime struct {
  52. *baseRuntime
  53. }
  54. /*
  55. stringValueRuntimeInst returns a new runtime component instance.
  56. */
  57. func stringValueRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  58. return &stringValueRuntime{newBaseRuntime(erp, node)}
  59. }
  60. /*
  61. Eval evaluate this runtime component.
  62. */
  63. func (rt *stringValueRuntime) Eval(vs parser.Scope, is map[string]interface{}) (interface{}, error) {
  64. _, err := rt.baseRuntime.Eval(vs, is)
  65. ret := rt.node.Token.Val
  66. if rt.node.Token.AllowEscapes {
  67. // Do allow string interpolation if escape sequences are allowed
  68. for {
  69. var replace string
  70. code, ok := rt.GetInfix(ret, "{{", "}}")
  71. if !ok {
  72. break
  73. }
  74. ast, ierr := parser.ParseWithRuntime(
  75. fmt.Sprintf("String interpolation: %v", code), code, rt.erp)
  76. if ierr == nil {
  77. if ierr = ast.Runtime.Validate(); ierr == nil {
  78. var res interface{}
  79. res, ierr = ast.Runtime.Eval(
  80. vs.NewChild(scope.NameFromASTNode(rt.node)),
  81. make(map[string]interface{}))
  82. if ierr == nil {
  83. replace = fmt.Sprint(res)
  84. }
  85. }
  86. }
  87. if ierr != nil {
  88. replace = fmt.Sprintf("#%v", ierr.Error())
  89. }
  90. ret = strings.Replace(ret, fmt.Sprintf("{{%v}}", code), replace, 1)
  91. }
  92. }
  93. return ret, err
  94. }
  95. func (rt *stringValueRuntime) GetInfix(str string, start string, end string) (string, bool) {
  96. res := str
  97. if s := strings.Index(str, start); s >= 0 {
  98. s += len(start)
  99. if e := strings.Index(str, end); e >= 0 {
  100. res = str[s:e]
  101. }
  102. }
  103. return res, res != str
  104. }
  105. /*
  106. mapValueRuntime is the runtime component for map values.
  107. */
  108. type mapValueRuntime struct {
  109. *baseRuntime
  110. }
  111. /*
  112. mapValueRuntimeInst returns a new runtime component instance.
  113. */
  114. func mapValueRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  115. return &mapValueRuntime{newBaseRuntime(erp, node)}
  116. }
  117. /*
  118. Eval evaluate this runtime component.
  119. */
  120. func (rt *mapValueRuntime) Eval(vs parser.Scope, is map[string]interface{}) (interface{}, error) {
  121. _, err := rt.baseRuntime.Eval(vs, is)
  122. m := make(map[interface{}]interface{})
  123. if err == nil {
  124. for _, kvp := range rt.node.Children {
  125. var key, val interface{}
  126. if err == nil {
  127. if key, err = kvp.Children[0].Runtime.Eval(vs, is); err == nil {
  128. if val, err = kvp.Children[1].Runtime.Eval(vs, is); err == nil {
  129. m[key] = val
  130. }
  131. }
  132. }
  133. }
  134. }
  135. return m, err
  136. }
  137. /*
  138. listValueRuntime is the runtime component for list values.
  139. */
  140. type listValueRuntime struct {
  141. *baseRuntime
  142. }
  143. /*
  144. listValueRuntimeInst returns a new runtime component instance.
  145. */
  146. func listValueRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  147. return &listValueRuntime{newBaseRuntime(erp, node)}
  148. }
  149. /*
  150. Eval evaluate this runtime component.
  151. */
  152. func (rt *listValueRuntime) Eval(vs parser.Scope, is map[string]interface{}) (interface{}, error) {
  153. _, err := rt.baseRuntime.Eval(vs, is)
  154. var l []interface{}
  155. if err == nil {
  156. for _, item := range rt.node.Children {
  157. if err == nil {
  158. var val interface{}
  159. if val, err = item.Runtime.Eval(vs, is); err == nil {
  160. l = append(l, val)
  161. }
  162. }
  163. }
  164. }
  165. return l, err
  166. }