rt_identifier.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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. "strings"
  14. "devt.de/krotik/ecal/parser"
  15. "devt.de/krotik/ecal/scope"
  16. "devt.de/krotik/ecal/stdlib"
  17. "devt.de/krotik/ecal/util"
  18. )
  19. /*
  20. identifierRuntime is the runtime component for identifiers.
  21. */
  22. type identifierRuntime struct {
  23. *baseRuntime
  24. }
  25. /*
  26. identifierRuntimeInst returns a new runtime component instance.
  27. */
  28. func identifierRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
  29. return &identifierRuntime{newBaseRuntime(erp, node)}
  30. }
  31. /*
  32. Eval evaluate this runtime component.
  33. */
  34. func (rt *identifierRuntime) Eval(vs parser.Scope, is map[string]interface{}) (interface{}, error) {
  35. return rt.resolveValue(vs, is, rt.node)
  36. }
  37. /*
  38. resolveValue resolves the value of this identifier.
  39. */
  40. func (rt *identifierRuntime) resolveValue(vs parser.Scope, is map[string]interface{}, node *parser.ASTNode) (interface{}, error) {
  41. var anode *parser.ASTNode
  42. var astring string
  43. var result interface{}
  44. var err error
  45. functionResolved := func(astring string, rnode *parser.ASTNode) *parser.ASTNode {
  46. res := &parser.ASTNode{ // Create a dummy identifier which models the value evaluation so far
  47. Name: parser.NodeIDENTIFIER,
  48. Token: &parser.LexToken{
  49. ID: node.Token.ID,
  50. Identifier: node.Token.Identifier,
  51. Lline: node.Token.Lline,
  52. Lpos: node.Token.Lpos,
  53. Pos: node.Token.Pos,
  54. Val: strings.Replace(astring, ".", ">", -1),
  55. },
  56. Children: nil,
  57. }
  58. for i, c := range rnode.Children {
  59. if c.Name == parser.NodeFUNCCALL {
  60. res.Children = rnode.Children[i+1:]
  61. }
  62. }
  63. return res
  64. }
  65. anode, astring, err = buildAccessString(rt.erp, vs, is, node, node.Token.Val)
  66. if len(node.Children) == 0 {
  67. // Simple case we just have a variable
  68. result, _, err = vs.GetValue(node.Token.Val)
  69. } else if cval, ok := stdlib.GetStdlibConst(astring); ok {
  70. result = cval
  71. } else {
  72. if rerr, ok := err.(*util.RuntimeError); err == nil || ok && rerr.Type == util.ErrInvalidConstruct {
  73. funcCallInAccessStringExecuted := ok && rerr.Type == util.ErrInvalidConstruct
  74. if result, _, err = vs.GetValue(astring); err == nil {
  75. if funcCallInAccessStringExecuted {
  76. result, err = rt.resolveFunction(astring, vs, is, rerr.Node, result, err)
  77. node = functionResolved(astring, anode)
  78. if len(node.Children) > 0 {
  79. // We have more identifiers after the func call - there is more to do ...
  80. vs = scope.NewScope("funcresult")
  81. vs.SetValue(node.Token.Val, result)
  82. result, err = rt.resolveValue(vs, is, node)
  83. }
  84. } else {
  85. result, err = rt.resolveFunction(astring, vs, is, node, result, err)
  86. }
  87. }
  88. }
  89. }
  90. return result, err
  91. }
  92. /*
  93. resolveFunction execute function calls and return the result.
  94. */
  95. func (rt *identifierRuntime) resolveFunction(astring string, vs parser.Scope, is map[string]interface{},
  96. node *parser.ASTNode, result interface{}, err error) (interface{}, error) {
  97. for _, funccall := range node.Children {
  98. if funccall.Name == parser.NodeFUNCCALL {
  99. funcObj, ok := result.(util.ECALFunction)
  100. if !ok {
  101. // Check for inbuild function
  102. funcObj, ok = inbuildFuncMap[astring]
  103. if !ok {
  104. // Check for stdlib function
  105. funcObj, ok = stdlib.GetStdlibFunc(astring)
  106. }
  107. }
  108. if ok {
  109. var args []interface{}
  110. // Collect the parameter values
  111. for _, c := range funccall.Children {
  112. var val interface{}
  113. if err == nil {
  114. val, err = c.Runtime.Eval(vs, is)
  115. args = append(args, val)
  116. }
  117. }
  118. if err == nil {
  119. // Execute the function and
  120. result, err = funcObj.Run(rt.instanceID, vs, is, args)
  121. if _, ok := err.(*util.RuntimeError); err != nil && !ok {
  122. // Convert into a proper runtime error if necessary
  123. rerr := rt.erp.NewRuntimeError(util.ErrRuntimeError,
  124. err.Error(), node).(*util.RuntimeError)
  125. if err == util.ErrIsIterator || err == util.ErrEndOfIteration || err == util.ErrContinueIteration {
  126. rerr.Type = err
  127. }
  128. err = rerr
  129. }
  130. }
  131. } else {
  132. err = rt.erp.NewRuntimeError(util.ErrUnknownConstruct,
  133. fmt.Sprintf("Unknown function: %v", node.Token.Val), node)
  134. }
  135. break
  136. }
  137. }
  138. return result, err
  139. }
  140. /*
  141. Set sets a value to this identifier.
  142. */
  143. func (rt *identifierRuntime) Set(vs parser.Scope, is map[string]interface{}, value interface{}) error {
  144. var err error
  145. if len(rt.node.Children) == 0 {
  146. // Simple case we just have a variable
  147. err = vs.SetValue(rt.node.Token.Val, value)
  148. } else {
  149. var as string
  150. _, as, err = buildAccessString(rt.erp, vs, is, rt.node, rt.node.Token.Val)
  151. if err == nil {
  152. // Collect all the children and find the right spot
  153. err = vs.SetValue(as, value)
  154. }
  155. }
  156. return err
  157. }
  158. /*
  159. buildAccessString builds an access string using a given node and a prefix.
  160. */
  161. func buildAccessString(erp *ECALRuntimeProvider, vs parser.Scope, is map[string]interface{},
  162. node *parser.ASTNode, prefix string) (*parser.ASTNode, string, error) {
  163. var err error
  164. res := prefix
  165. for i, c := range node.Children {
  166. if err == nil {
  167. // The unexpected construct error is used in two ways:
  168. // 1. Error message when a function call is used on the left hand of
  169. // an assignment.
  170. // 2. Signalling there is a function call involved on the right hand
  171. // of an assignment.
  172. if c.Name == parser.NodeCOMPACCESS {
  173. var val interface{}
  174. val, err = c.Children[0].Runtime.Eval(vs, is)
  175. res = fmt.Sprintf("%v.%v", res, val)
  176. if len(node.Children) > i+1 && node.Children[i+1].Name == parser.NodeFUNCCALL {
  177. err = erp.NewRuntimeError(util.ErrInvalidConstruct,
  178. "Unexpected construct", node)
  179. break
  180. }
  181. } else if c.Name == parser.NodeIDENTIFIER {
  182. res = fmt.Sprintf("%v.%v", res, c.Token.Val)
  183. if len(c.Children) > 0 && c.Children[0].Name == parser.NodeFUNCCALL {
  184. node = c
  185. err = erp.NewRuntimeError(util.ErrInvalidConstruct,
  186. "Unexpected construct", node)
  187. break
  188. }
  189. node, res, err = buildAccessString(erp, vs, is, c, res)
  190. }
  191. }
  192. }
  193. return node, res, err
  194. }