123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- package interpreter
- import (
- "io"
- "fmt"
- "kumachan/standalone/util"
- "kumachan/standalone/util/fatal"
- "kumachan/standalone/util/richtext"
- "kumachan/lang/source"
- "kumachan/lang/typsys"
- "kumachan/lang/textual/ast"
- "kumachan/lang/textual/syntax"
- "kumachan/lang/textual/parser"
- "kumachan/lang/textual/transformer"
- "kumachan/interpreter/core"
- "kumachan/interpreter/compiler"
- "kumachan/interpreter/program"
- "kumachan/interpreter/runtime"
- "kumachan/interpreter/runtime/debug"
- )
- type ReplConfig struct {
- Input io.Reader
- Output io.Writer
- }
- func CreateBlankProgram() (*program.Program, *compiler.NsHeaderMap, *compiler.Executable, fatal.Exception) {
- var project = compiler.Project {}
- var fs = compiler.RealFileSystem {}
- var meta = program.Metadata { ProgramPath: "." }
- var p, ctx, exe, errs1, errs2 = compiler.Compile(project, fs, meta)
- if errs1 != nil { return nil, nil, nil, errs1 }
- if errs2 != nil { return nil, nil, nil, errs2 }
- return p, ctx, exe, nil
- }
- func Repl(p *program.Program, ctx *compiler.NsHeaderMap, exe *compiler.Executable, env *runtime.Environment, cfg ReplConfig) {
- var main_exit = make(runtime.ExitSignal)
- var repl_exit = make(chan struct{})
- var h, _ = runtime.Run(p, "", env, main_exit)
- var input = cfg.Input
- var output = cfg.Output
- var inspect_ctx = debug.MakeInspectContext(ctx)
- go (func() {
- var eventloop = h.EventLoop()
- var eval_ctx = program.CreateEvalContext(h)
- var bindings = make([] *program.Binding, 0)
- var bind = func(name string, expr *program.Expr, value core.Object) {
- var binding = &program.Binding {
- Name: name,
- Type: expr.Type,
- Location: expr.Info.Location,
- }
- bindings = append(bindings, binding)
- eval_ctx = eval_ctx.NewCtxBind(binding, value)
- }
- const repl_title = "** REPL **"
- fmt.Fprintf(output, "%s\n\n", repl_title)
- var cmd_id = uint(0)
- for {
- cmd_id += 1
- var code, ok = replReadLine(input, output, cmd_id)
- if !(ok) {
- // EOF
- close(repl_exit)
- return
- }
- if len(code) == 0 {
- cmd_id -= 1
- continue
- }
- var cmd_label_err = fmt.Sprintf("\033[31m(%d)\033[0m", cmd_id)
- var cmd_ast_name = fmt.Sprintf("[%d]", cmd_id)
- const repl_root = syntax.ReplRootPartName
- cst, p_err := parser.Parse(code, repl_root, cmd_ast_name)
- if p_err != nil {
- fmt.Fprintf(output,
- "[%d] error:\n%s\n", cmd_id, replText(p_err.Message()))
- continue
- }
- var key = source.FileKey {
- Context: "repl",
- Path: cmd_ast_name,
- }
- var cmd = transformer.Transform(cst, key).(ast.ReplRoot)
- var expr_node = ast.ReplCmdGetExpr(cmd.Cmd)
- var expr, err = compiler.CompileExpr (
- expr_node, ctx, exe, bindings, "", nil,
- )
- if err != nil {
- fmt.Fprintf(output,
- "[%d] error:\n%s\n", cmd_id, replText(err.Message()))
- continue
- } else {
- goto ok
- }
- ok:
- var temp_name = fmt.Sprintf("temp%d", cmd_id)
- var value = eval_ctx.Eval(expr)
- bind(temp_name, expr, value)
- replInspect(value, expr.Type, inspect_ctx, output, cmd_id)
- switch cmd := cmd.Cmd.(type) {
- case ast.ReplAssign:
- var specified_name = source.CodeToString(cmd.Name.Name)
- bind(specified_name, expr, value)
- case ast.ReplRun:
- var o, ok = (*value).(core.Observable)
- if ok {
- var v_type = replMatchObservable(expr.Type.Type)
- replRun(o, eventloop, output, v_type, inspect_ctx, cmd_id)
- } else {
- fmt.Fprintf(output,
- "%s\nrun: expect Observable\n\n", cmd_label_err)
- }
- case ast.ReplEval:
- // do nothing extra
- }
- }
- })()
- <- main_exit
- <- repl_exit
- }
- func replText(msg richtext.Block) string {
- return msg.RenderConsole()
- }
- func replReadLine(input io.Reader, output io.Writer, cmd_id uint) (source.Code, bool) {
- { var _, err = fmt.Fprintf(output, "\033[1m[%d]\033[0m ", cmd_id)
- if err != nil { panic(err) } }
- var code_str, _, err = util.WellBehavedFscanln(input)
- if err != nil {
- if err == io.EOF {
- fmt.Fprintf(output, "\n")
- return nil, false
- } else {
- panic(err)
- }
- }
- return source.StringToCode(code_str), true
- }
- func replInspect(value core.Object, t typsys.CertainType, ctx debug.InspectContext, output io.Writer, cmd_id uint) {
- var cmd_label = fmt.Sprintf("\033[34m(%d)\033[0m", cmd_id)
- var msg = debug.Inspect(value, t.Type, ctx)
- var text = msg.RenderConsole()
- fmt.Fprintf(output,
- "%s\n%s\n",
- cmd_label, text)
- }
- func replMatchObservable(t typsys.Type) typsys.Type {
- var v_type, _ = program.T_Observable_(t)
- return v_type
- }
- func replRun(
- o core.Observable,
- eventloop *core.EventLoop,
- output io.Writer,
- v_type typsys.Type,
- ctx debug.InspectContext,
- cmd_id uint,
- ) {
- var cmd_label_ok = fmt.Sprintf("\033[32m(%d)\033[0m", cmd_id)
- var cmd_label_err = fmt.Sprintf("\033[31m(%d)\033[0m", cmd_id)
- var ch_values = make(chan core.Object, 1024)
- var ch_error = make(chan error, 1)
- core.Run(o, eventloop, core.DataSubscriber {
- Values: ch_values,
- Error: ch_error,
- })
- for {
- select {
- case v, not_closed := <- ch_values:
- if not_closed {
- var msg = debug.Inspect(v, v_type, ctx)
- _, err := fmt.Fprintf(output,
- "%s <value>\n%s\n", cmd_label_ok, replText(msg))
- if err != nil { panic(err) }
- } else {
- _, err := fmt.Fprintf(output,
- "%s <terminated> completed\n\n", cmd_label_ok)
- if err != nil { panic(err) }
- return
- }
- case e, not_closed := <- ch_error:
- if not_closed {
- var e_obj = core.Obj(core.Error { Value: e })
- var msg = debug.Inspect(e_obj, program.T_Error(), ctx)
- _, err := fmt.Fprintf(output,
- "%s <error>\n%s\n", cmd_label_err, replText(msg))
- if err != nil { panic(err) }
- } else {
- _, err := fmt.Fprintf(output,
- "%s <terminated> error occurred\n\n", cmd_label_err)
- if err != nil { panic(err) }
- return
- }
- }
- }
- return
- }
|