closure.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package eval
  2. import (
  3. "fmt"
  4. "sort"
  5. "strconv"
  6. "strings"
  7. "unsafe"
  8. "src.elv.sh/pkg/diag"
  9. "src.elv.sh/pkg/eval/errs"
  10. "src.elv.sh/pkg/eval/vals"
  11. "src.elv.sh/pkg/eval/vars"
  12. "src.elv.sh/pkg/parse"
  13. "src.elv.sh/pkg/persistent/hash"
  14. )
  15. // Closure is a function defined with Elvish code. Each Closure has its unique
  16. // identity.
  17. type Closure struct {
  18. ArgNames []string
  19. // The index of the rest argument. -1 if there is no rest argument.
  20. RestArg int
  21. OptNames []string
  22. OptDefaults []any
  23. SrcMeta parse.Source
  24. DefRange diag.Ranging
  25. op effectOp
  26. newLocal []staticVarInfo
  27. captured *Ns
  28. }
  29. var _ Callable = &Closure{}
  30. // Kind returns "fn".
  31. func (*Closure) Kind() string {
  32. return "fn"
  33. }
  34. // Equal compares by address.
  35. func (c *Closure) Equal(rhs any) bool {
  36. return c == rhs
  37. }
  38. // Hash returns the hash of the address of the closure.
  39. func (c *Closure) Hash() uint32 {
  40. return hash.Pointer(unsafe.Pointer(c))
  41. }
  42. // Repr returns an opaque representation "<closure 0x23333333>".
  43. func (c *Closure) Repr(int) string {
  44. return fmt.Sprintf("<closure %p>", c)
  45. }
  46. // Call calls a closure.
  47. func (c *Closure) Call(fm *Frame, args []any, opts map[string]any) error {
  48. // Check number of arguments.
  49. if c.RestArg != -1 {
  50. if len(args) < len(c.ArgNames)-1 {
  51. return errs.ArityMismatch{What: "arguments",
  52. ValidLow: len(c.ArgNames) - 1, ValidHigh: -1, Actual: len(args)}
  53. }
  54. } else {
  55. if len(args) != len(c.ArgNames) {
  56. return errs.ArityMismatch{What: "arguments",
  57. ValidLow: len(c.ArgNames), ValidHigh: len(c.ArgNames), Actual: len(args)}
  58. }
  59. }
  60. // Check whether all supplied options are supported. This map contains the
  61. // subset of keys from opts that can be found in c.OptNames.
  62. optSupported := make(map[string]struct{})
  63. for _, name := range c.OptNames {
  64. _, ok := opts[name]
  65. if ok {
  66. optSupported[name] = struct{}{}
  67. }
  68. }
  69. if len(optSupported) < len(opts) {
  70. // Report all the options that are not supported.
  71. unsupported := make([]string, 0, len(opts)-len(optSupported))
  72. for name := range opts {
  73. _, supported := optSupported[name]
  74. if !supported {
  75. unsupported = append(unsupported, parse.Quote(name))
  76. }
  77. }
  78. sort.Strings(unsupported)
  79. return UnsupportedOptionsError{unsupported}
  80. }
  81. // This Frame is dedicated to the current form, so we can modify it in place.
  82. // BUG(xiaq): When evaluating closures, async access to global variables
  83. // and ports can be problematic.
  84. // Make upvalue namespace and capture variables.
  85. fm.up = c.captured
  86. // Populate local scope with arguments, options, and newly created locals.
  87. localSize := len(c.ArgNames) + len(c.OptNames) + len(c.newLocal)
  88. local := &Ns{make([]vars.Var, localSize), make([]staticVarInfo, localSize)}
  89. for i, name := range c.ArgNames {
  90. local.infos[i] = staticVarInfo{name, false, false}
  91. }
  92. if c.RestArg == -1 {
  93. for i := range c.ArgNames {
  94. local.slots[i] = vars.FromInit(args[i])
  95. }
  96. } else {
  97. for i := 0; i < c.RestArg; i++ {
  98. local.slots[i] = vars.FromInit(args[i])
  99. }
  100. restOff := len(args) - len(c.ArgNames)
  101. local.slots[c.RestArg] = vars.FromInit(
  102. vals.MakeList(args[c.RestArg : c.RestArg+restOff+1]...))
  103. for i := c.RestArg + 1; i < len(c.ArgNames); i++ {
  104. local.slots[i] = vars.FromInit(args[i+restOff])
  105. }
  106. }
  107. offset := len(c.ArgNames)
  108. for i, name := range c.OptNames {
  109. v, ok := opts[name]
  110. if !ok {
  111. v = c.OptDefaults[i]
  112. }
  113. local.infos[offset+i] = staticVarInfo{name, false, false}
  114. local.slots[offset+i] = vars.FromInit(v)
  115. }
  116. offset += len(c.OptNames)
  117. for i, info := range c.newLocal {
  118. local.infos[offset+i] = info
  119. // TODO: Take info.readOnly into account too when creating variable
  120. local.slots[offset+i] = MakeVarFromName(info.name)
  121. }
  122. fm.local = local
  123. fm.srcMeta = c.SrcMeta
  124. fm.defers = new([]func(*Frame) Exception)
  125. exc := c.op.exec(fm)
  126. excDefer := fm.runDefers()
  127. // TODO: Combine exc and excDefer if both are not nil
  128. if excDefer != nil && exc == nil {
  129. exc = excDefer
  130. }
  131. return exc
  132. }
  133. var (
  134. fnDefault = NewGoFn("nop~", nop)
  135. nsDefault = &Ns{}
  136. )
  137. // MakeVarFromName creates a Var with a suitable type constraint inferred from
  138. // the name.
  139. func MakeVarFromName(name string) vars.Var {
  140. switch {
  141. case strings.HasSuffix(name, FnSuffix):
  142. val := fnDefault
  143. return vars.FromPtr(&val)
  144. case strings.HasSuffix(name, NsSuffix):
  145. val := nsDefault
  146. return vars.FromPtr(&val)
  147. default:
  148. return vars.FromInit(nil)
  149. }
  150. }
  151. // UnsupportedOptionsError is an error returned by a closure call when there are
  152. // unsupported options.
  153. type UnsupportedOptionsError struct {
  154. Options []string
  155. }
  156. func (er UnsupportedOptionsError) Error() string {
  157. if len(er.Options) == 1 {
  158. return fmt.Sprintf("unsupported option: %s", er.Options[0])
  159. }
  160. return fmt.Sprintf("unsupported options: %s", strings.Join(er.Options, ", "))
  161. }
  162. func (c *Closure) Fields() vals.StructMap { return closureFields{c} }
  163. type closureFields struct{ c *Closure }
  164. func (closureFields) IsStructMap() {}
  165. func (cf closureFields) ArgNames() vals.List { return vals.MakeListFromStrings(cf.c.ArgNames...) }
  166. func (cf closureFields) RestArg() string { return strconv.Itoa(cf.c.RestArg) }
  167. func (cf closureFields) OptNames() vals.List { return vals.MakeListFromStrings(cf.c.OptNames...) }
  168. func (cf closureFields) Src() parse.Source { return cf.c.SrcMeta }
  169. func (cf closureFields) OptDefaults() vals.List {
  170. return vals.MakeList(cf.c.OptDefaults...)
  171. }
  172. func (cf closureFields) Body() string {
  173. r := cf.c.op.(diag.Ranger).Range()
  174. return cf.c.SrcMeta.Code[r.From:r.To]
  175. }
  176. func (cf closureFields) Def() string {
  177. return cf.c.SrcMeta.Code[cf.c.DefRange.From:cf.c.DefRange.To]
  178. }