...
1
2
3
4
5
6
7
8
9
10
11
12
13 package repl
14
15 import (
16 "context"
17 "fmt"
18 "io"
19 "os"
20 "os/signal"
21
22 "github.com/chzyer/readline"
23 "go.starlark.net/resolve"
24 "go.starlark.net/starlark"
25 "go.starlark.net/syntax"
26 )
27
28 var interrupted = make(chan os.Signal, 1)
29
30
31
32
33
34
35
36
37 func REPL(thread *starlark.Thread, globals starlark.StringDict) {
38 signal.Notify(interrupted, os.Interrupt)
39 defer signal.Stop(interrupted)
40
41 rl, err := readline.New(">>> ")
42 if err != nil {
43 PrintError(err)
44 return
45 }
46 defer rl.Close()
47 for {
48 if err := rep(rl, thread, globals); err != nil {
49 if err == readline.ErrInterrupt {
50 fmt.Println(err)
51 continue
52 }
53 break
54 }
55 }
56 }
57
58
59
60
61
62 func rep(rl *readline.Instance, thread *starlark.Thread, globals starlark.StringDict) error {
63
64
65
66
67
68 ctx, cancel := context.WithCancel(context.Background())
69 defer cancel()
70 go func() {
71 select {
72 case <-interrupted:
73 cancel()
74 case <-ctx.Done():
75 }
76 }()
77
78 thread.SetLocal("context", ctx)
79
80 eof := false
81
82
83 rl.SetPrompt(">>> ")
84 readline := func() ([]byte, error) {
85 line, err := rl.Readline()
86 rl.SetPrompt("... ")
87 if err != nil {
88 if err == io.EOF {
89 eof = true
90 }
91 return nil, err
92 }
93 return []byte(line + "\n"), nil
94 }
95
96
97 f, err := syntax.ParseCompoundStmt("<stdin>", readline)
98 if err != nil {
99 if eof {
100 return io.EOF
101 }
102 PrintError(err)
103 return nil
104 }
105
106
107
108
109
110 defer func(prev bool) { resolve.LoadBindsGlobally = prev }(resolve.LoadBindsGlobally)
111 resolve.LoadBindsGlobally = true
112
113 if expr := soleExpr(f); expr != nil {
114
115 v, err := starlark.EvalExpr(thread, expr, globals)
116 if err != nil {
117 PrintError(err)
118 return nil
119 }
120
121
122 if v != starlark.None {
123 fmt.Println(v)
124 }
125 } else if err := starlark.ExecREPLChunk(f, thread, globals); err != nil {
126 PrintError(err)
127 return nil
128 }
129
130 return nil
131 }
132
133 func soleExpr(f *syntax.File) syntax.Expr {
134 if len(f.Stmts) == 1 {
135 if stmt, ok := f.Stmts[0].(*syntax.ExprStmt); ok {
136 return stmt.X
137 }
138 }
139 return nil
140 }
141
142
143
144 func PrintError(err error) {
145 if evalErr, ok := err.(*starlark.EvalError); ok {
146 fmt.Fprintln(os.Stderr, evalErr.Backtrace())
147 } else {
148 fmt.Fprintln(os.Stderr, err)
149 }
150 }
151
152
153
154
155 func MakeLoad() func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
156 type entry struct {
157 globals starlark.StringDict
158 err error
159 }
160
161 var cache = make(map[string]*entry)
162
163 return func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
164 e, ok := cache[module]
165 if e == nil {
166 if ok {
167
168 return nil, fmt.Errorf("cycle in load graph")
169 }
170
171
172 cache[module] = nil
173
174
175 thread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
176 globals, err := starlark.ExecFile(thread, module, nil, nil)
177 e = &entry{globals, err}
178
179
180 cache[module] = e
181 }
182 return e.globals, e.err
183 }
184 }
185
View as plain text