repl.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package interpreter
  2. import (
  3. "io"
  4. "fmt"
  5. "kumachan/standalone/util"
  6. "kumachan/standalone/util/fatal"
  7. "kumachan/standalone/util/richtext"
  8. "kumachan/lang/source"
  9. "kumachan/lang/typsys"
  10. "kumachan/lang/textual/ast"
  11. "kumachan/lang/textual/syntax"
  12. "kumachan/lang/textual/parser"
  13. "kumachan/lang/textual/transformer"
  14. "kumachan/interpreter/core"
  15. "kumachan/interpreter/compiler"
  16. "kumachan/interpreter/program"
  17. "kumachan/interpreter/runtime"
  18. "kumachan/interpreter/runtime/debug"
  19. )
  20. type ReplConfig struct {
  21. Input io.Reader
  22. Output io.Writer
  23. }
  24. func CreateBlankProgram() (*program.Program, *compiler.NsHeaderMap, *compiler.Executable, fatal.Exception) {
  25. var project = compiler.Project {}
  26. var fs = compiler.RealFileSystem {}
  27. var meta = program.Metadata { ProgramPath: "." }
  28. var p, ctx, exe, errs1, errs2 = compiler.Compile(project, fs, meta)
  29. if errs1 != nil { return nil, nil, nil, errs1 }
  30. if errs2 != nil { return nil, nil, nil, errs2 }
  31. return p, ctx, exe, nil
  32. }
  33. func Repl(p *program.Program, ctx *compiler.NsHeaderMap, exe *compiler.Executable, env *runtime.Environment, cfg ReplConfig) {
  34. var main_exit = make(runtime.ExitSignal)
  35. var repl_exit = make(chan struct{})
  36. var h, _ = runtime.Run(p, "", env, main_exit)
  37. var input = cfg.Input
  38. var output = cfg.Output
  39. var inspect_ctx = debug.MakeInspectContext(ctx)
  40. go (func() {
  41. var eventloop = h.EventLoop()
  42. var eval_ctx = program.CreateEvalContext(h)
  43. var bindings = make([] *program.Binding, 0)
  44. var bind = func(name string, expr *program.Expr, value core.Object) {
  45. var binding = &program.Binding {
  46. Name: name,
  47. Type: expr.Type,
  48. Location: expr.Info.Location,
  49. }
  50. bindings = append(bindings, binding)
  51. eval_ctx = eval_ctx.NewCtxBind(binding, value)
  52. }
  53. const repl_title = "** REPL **"
  54. fmt.Fprintf(output, "%s\n\n", repl_title)
  55. var cmd_id = uint(0)
  56. for {
  57. cmd_id += 1
  58. var code, ok = replReadLine(input, output, cmd_id)
  59. if !(ok) {
  60. // EOF
  61. close(repl_exit)
  62. return
  63. }
  64. if len(code) == 0 {
  65. cmd_id -= 1
  66. continue
  67. }
  68. var cmd_label_err = fmt.Sprintf("\033[31m(%d)\033[0m", cmd_id)
  69. var cmd_ast_name = fmt.Sprintf("[%d]", cmd_id)
  70. const repl_root = syntax.ReplRootPartName
  71. cst, p_err := parser.Parse(code, repl_root, cmd_ast_name)
  72. if p_err != nil {
  73. fmt.Fprintf(output,
  74. "[%d] error:\n%s\n", cmd_id, replText(p_err.Message()))
  75. continue
  76. }
  77. var key = source.FileKey {
  78. Context: "repl",
  79. Path: cmd_ast_name,
  80. }
  81. var cmd = transformer.Transform(cst, key).(ast.ReplRoot)
  82. var expr_node = ast.ReplCmdGetExpr(cmd.Cmd)
  83. var expr, err = compiler.CompileExpr (
  84. expr_node, ctx, exe, bindings, "", nil,
  85. )
  86. if err != nil {
  87. fmt.Fprintf(output,
  88. "[%d] error:\n%s\n", cmd_id, replText(err.Message()))
  89. continue
  90. } else {
  91. goto ok
  92. }
  93. ok:
  94. var temp_name = fmt.Sprintf("temp%d", cmd_id)
  95. var value = eval_ctx.Eval(expr)
  96. bind(temp_name, expr, value)
  97. replInspect(value, expr.Type, inspect_ctx, output, cmd_id)
  98. switch cmd := cmd.Cmd.(type) {
  99. case ast.ReplAssign:
  100. var specified_name = source.CodeToString(cmd.Name.Name)
  101. bind(specified_name, expr, value)
  102. case ast.ReplRun:
  103. var o, ok = (*value).(core.Observable)
  104. if ok {
  105. var v_type = replMatchObservable(expr.Type.Type)
  106. replRun(o, eventloop, output, v_type, inspect_ctx, cmd_id)
  107. } else {
  108. fmt.Fprintf(output,
  109. "%s\nrun: expect Observable\n\n", cmd_label_err)
  110. }
  111. case ast.ReplEval:
  112. // do nothing extra
  113. }
  114. }
  115. })()
  116. <- main_exit
  117. <- repl_exit
  118. }
  119. func replText(msg richtext.Block) string {
  120. return msg.RenderConsole()
  121. }
  122. func replReadLine(input io.Reader, output io.Writer, cmd_id uint) (source.Code, bool) {
  123. { var _, err = fmt.Fprintf(output, "\033[1m[%d]\033[0m ", cmd_id)
  124. if err != nil { panic(err) } }
  125. var code_str, _, err = util.WellBehavedFscanln(input)
  126. if err != nil {
  127. if err == io.EOF {
  128. fmt.Fprintf(output, "\n")
  129. return nil, false
  130. } else {
  131. panic(err)
  132. }
  133. }
  134. return source.StringToCode(code_str), true
  135. }
  136. func replInspect(value core.Object, t typsys.CertainType, ctx debug.InspectContext, output io.Writer, cmd_id uint) {
  137. var cmd_label = fmt.Sprintf("\033[34m(%d)\033[0m", cmd_id)
  138. var msg = debug.Inspect(value, t.Type, ctx)
  139. var text = msg.RenderConsole()
  140. fmt.Fprintf(output,
  141. "%s\n%s\n",
  142. cmd_label, text)
  143. }
  144. func replMatchObservable(t typsys.Type) typsys.Type {
  145. var v_type, _ = program.T_Observable_(t)
  146. return v_type
  147. }
  148. func replRun(
  149. o core.Observable,
  150. eventloop *core.EventLoop,
  151. output io.Writer,
  152. v_type typsys.Type,
  153. ctx debug.InspectContext,
  154. cmd_id uint,
  155. ) {
  156. var cmd_label_ok = fmt.Sprintf("\033[32m(%d)\033[0m", cmd_id)
  157. var cmd_label_err = fmt.Sprintf("\033[31m(%d)\033[0m", cmd_id)
  158. var ch_values = make(chan core.Object, 1024)
  159. var ch_error = make(chan error, 1)
  160. core.Run(o, eventloop, core.DataSubscriber {
  161. Values: ch_values,
  162. Error: ch_error,
  163. })
  164. for {
  165. select {
  166. case v, not_closed := <- ch_values:
  167. if not_closed {
  168. var msg = debug.Inspect(v, v_type, ctx)
  169. _, err := fmt.Fprintf(output,
  170. "%s <value>\n%s\n", cmd_label_ok, replText(msg))
  171. if err != nil { panic(err) }
  172. } else {
  173. _, err := fmt.Fprintf(output,
  174. "%s <terminated> completed\n\n", cmd_label_ok)
  175. if err != nil { panic(err) }
  176. return
  177. }
  178. case e, not_closed := <- ch_error:
  179. if not_closed {
  180. var e_obj = core.Obj(core.Error { Value: e })
  181. var msg = debug.Inspect(e_obj, program.T_Error(), ctx)
  182. _, err := fmt.Fprintf(output,
  183. "%s <error>\n%s\n", cmd_label_err, replText(msg))
  184. if err != nil { panic(err) }
  185. } else {
  186. _, err := fmt.Fprintf(output,
  187. "%s <terminated> error occurred\n\n", cmd_label_err)
  188. if err != nil { panic(err) }
  189. return
  190. }
  191. }
  192. }
  193. return
  194. }