repl.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package debugging
  2. import (
  3. "fmt"
  4. "sync"
  5. "kumachan/standalone/util"
  6. "kumachan/standalone/util/richtext"
  7. "kumachan/lang/source"
  8. "kumachan/lang/typsys"
  9. "kumachan/lang/textual/ast"
  10. "kumachan/lang/textual/syntax"
  11. "kumachan/lang/textual/parser"
  12. "kumachan/lang/textual/transformer"
  13. "kumachan/interpreter/core"
  14. "kumachan/interpreter/program"
  15. "kumachan/interpreter/compiler"
  16. )
  17. type Repl struct {
  18. mutex sync.Mutex
  19. debugInfo *compiler.DebugInfo
  20. evaluator *program.EvalContext
  21. bindings [] *program.Binding
  22. eventloop *core.EventLoop
  23. }
  24. func CreateRepl(info *compiler.DebugInfo, h core.RuntimeHandle) *Repl {
  25. var evaluator = program.CreateEvalContext(h)
  26. var bindings = make([] *program.Binding, 0)
  27. var eventloop = h.EventLoop()
  28. return &Repl {
  29. debugInfo: info,
  30. evaluator: evaluator,
  31. bindings: bindings,
  32. eventloop: eventloop,
  33. }
  34. }
  35. const ReplHelp = "<pre><b>*** REPL ***</b>\n" +
  36. "<b>Usage:</b> EXPR | NAME = EXPR | :run EXPR</pre>"
  37. func (ctx *Repl) HandleCommand(cmd string, id int, d core.ReplInterface, exit util.ExitNotifier) {
  38. ctx.mutex.Lock()
  39. defer ctx.mutex.Unlock()
  40. d.ReplEcho(cmd, id)
  41. var code = source.StringToCode(cmd)
  42. var path = fmt.Sprintf("%d", id)
  43. var root = syntax.ReplRoot()
  44. var cmd_cst, err = parser.Parse(code, root, path)
  45. if err != nil {
  46. d.ReplRespondExprError(err.Message(), id)
  47. return
  48. }
  49. var key = source.FileKey {
  50. Context: "repl",
  51. Path: path,
  52. }
  53. var name = fmt.Sprintf("temp%d", id)
  54. var cmd_ast = transformer.Transform(cmd_cst, key).(ast.VariousReplCmd)
  55. var expr_node = ast.ReplCmdGetExpr(cmd_ast.ReplCmd)
  56. { var expr, err = compiler.CompileExpr(expr_node, "", nil, ctx.bindings, ctx.debugInfo)
  57. if err != nil {
  58. d.ReplRespondExprError(err.Message(), id)
  59. return
  60. }
  61. var value = ctx.evaluator.Eval(expr)
  62. ctx.bindExprValue(name, expr, value)
  63. d.ReplRespondExprValue(value, expr.Type, id)
  64. switch C := cmd_ast.ReplCmd.(type) {
  65. case ast.ReplAssign:
  66. var specified_name = ast.Id2String(C.Name)
  67. ctx.bindExprValue(specified_name, expr, value)
  68. case ast.ReplRun:
  69. if o, ok := (*value).(core.Observable); ok {
  70. var inner_t_, _ = program.T_Observable_(expr.Type.Type)
  71. var inner_t = typsys.CertainType { Type: inner_t_}
  72. go ctx.subscribe(o, inner_t, id, d, exit)
  73. } else {
  74. var msg richtext.Block
  75. msg.WriteLine("run: expect Observable", richtext.TAG_ERR)
  76. d.ReplRespondExprError(msg, id)
  77. }
  78. default:
  79. // do nothing
  80. }}
  81. }
  82. func (ctx *Repl) Expose(name string, v core.Object, t typsys.CertainType, loc source.Location) func() {
  83. ctx.mutex.Lock()
  84. defer ctx.mutex.Unlock()
  85. b := ctx.bind(name, t, loc, v)
  86. return func() {
  87. ctx.unbind(b)
  88. }
  89. }
  90. func (ctx *Repl) bindExprValue(name string, expr *program.Expr, value core.Object) {
  91. ctx.bind(name, expr.Type, expr.Info.Location, value)
  92. }
  93. func (ctx *Repl) bind(name string, t typsys.CertainType, loc source.Location, value core.Object) *program.Binding {
  94. var binding = &program.Binding {
  95. Name: name,
  96. Type: t,
  97. Location: loc,
  98. }
  99. ctx.bindings = append(ctx.bindings, binding)
  100. ctx.evaluator = ctx.evaluator.NewCtxBind(binding, value)
  101. return binding
  102. }
  103. func (ctx *Repl) unbind(target *program.Binding) bool {
  104. var L = len(ctx.bindings)
  105. var index, found = -1, false
  106. for i := (L-1); i >= 0; i -= 1 {
  107. if ctx.bindings[i] == target {
  108. index, found = i, true
  109. ctx.evaluator = ctx.evaluator.NewCtxUnbind(ctx.bindings[i])
  110. }
  111. }
  112. if found {
  113. var new_bindings = make([] *program.Binding, 0, (L-1))
  114. for i, b := range ctx.bindings {
  115. if i != index {
  116. new_bindings = append(new_bindings, b)
  117. }
  118. }
  119. ctx.bindings = new_bindings
  120. return true
  121. } else {
  122. return false
  123. }
  124. }
  125. func (ctx *Repl) subscribe(o core.Observable, inner_t typsys.CertainType, id int, d core.ReplInterface, exit util.ExitNotifier) {
  126. var ch_values = make(chan core.Object, 256)
  127. var ch_error = make(chan error, 1)
  128. core.Run(o, ctx.eventloop, core.DataSubscriber {
  129. Values: ch_values,
  130. Error: ch_error,
  131. })
  132. var ch_exit = exit.Signal()
  133. loop: for {
  134. select {
  135. case v, not_close := <- ch_values:
  136. if not_close {
  137. d.ReplNotifyObValue(v, inner_t, id)
  138. } else {
  139. d.ReplNotifyObCompletion(id)
  140. break loop
  141. }
  142. case err, not_close := <- ch_error:
  143. if not_close {
  144. d.ReplNotifyObError(err, id)
  145. } else {
  146. break loop
  147. }
  148. case <- ch_exit:
  149. break loop
  150. }
  151. }
  152. }