Skip to content

Commit f0cb59c

Browse files
committed
fix out of order and lingering printing
1 parent d53eafe commit f0cb59c

File tree

2 files changed

+149
-109
lines changed

2 files changed

+149
-109
lines changed

internal/repl/commands.go

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func actionDoc(s *Session, in string) (string, error) {
190190
s.storeMainBody()
191191
defer s.restoreMainBody()
192192

193-
exprs, err := s.evalExpr(in)
193+
expr, err := s.evalExpr(in)
194194
if err != nil {
195195
return "", err
196196
}
@@ -206,35 +206,33 @@ func actionDoc(s *Session, in string) (string, error) {
206206
debugf("typecheck error (ignored): %s", err)
207207
}
208208

209+
// :doc patterns:
210+
// - "json" -> "encoding/json" (package name)
211+
// - "json.Encoder" -> "encoding/json", "Encoder" (package member)
212+
// - "json.NewEncoder(nil).Encode" -> "encoding/json", "Decode" (package type member)
209213
var docObj types.Object
210-
for _, expr := range exprs {
211-
// :doc patterns:
212-
// - "json" -> "encoding/json" (package name)
213-
// - "json.Encoder" -> "encoding/json", "Encoder" (package member)
214-
// - "json.NewEncoder(nil).Encode" -> "encoding/json", "Decode" (package type member)
215-
if sel, ok := expr.(*ast.SelectorExpr); ok {
216-
// package member, package type member
217-
docObj = s.TypeInfo.ObjectOf(sel.Sel)
218-
} else if t := s.TypeInfo.TypeOf(expr); t != nil && t != types.Typ[types.Invalid] {
219-
for {
220-
if pt, ok := t.(*types.Pointer); ok {
221-
t = pt.Elem()
222-
} else {
223-
break
224-
}
225-
}
226-
switch t := t.(type) {
227-
case *types.Named:
228-
docObj = t.Obj()
229-
case *types.Basic:
230-
// builtin types
231-
docObj = types.Universe.Lookup(t.Name())
214+
if sel, ok := expr.(*ast.SelectorExpr); ok {
215+
// package member, package type member
216+
docObj = s.TypeInfo.ObjectOf(sel.Sel)
217+
} else if t := s.TypeInfo.TypeOf(expr); t != nil && t != types.Typ[types.Invalid] {
218+
for {
219+
if pt, ok := t.(*types.Pointer); ok {
220+
t = pt.Elem()
221+
} else {
222+
break
232223
}
233-
} else if ident, ok := expr.(*ast.Ident); ok {
234-
// package name
235-
mainScope := s.TypeInfo.Scopes[s.mainFunc().Type]
236-
_, docObj = mainScope.LookupParent(ident.Name, ident.NamePos)
237224
}
225+
switch t := t.(type) {
226+
case *types.Named:
227+
docObj = t.Obj()
228+
case *types.Basic:
229+
// builtin types
230+
docObj = types.Universe.Lookup(t.Name())
231+
}
232+
} else if ident, ok := expr.(*ast.Ident); ok {
233+
// package name
234+
mainScope := s.TypeInfo.Scopes[s.mainFunc().Type]
235+
_, docObj = mainScope.LookupParent(ident.Name, ident.NamePos)
238236
}
239237

240238
if docObj == nil {

internal/repl/repl.go

Lines changed: 124 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -154,65 +154,103 @@ func goRun(files []string) ([]byte, bytes.Buffer, error) {
154154
return out, stderr, err
155155
}
156156

157-
func (s *Session) evalExpr(in string) ([]ast.Expr, error) {
158-
inLines := strings.Split(in, "\n")
159-
160-
var exprs []ast.Expr
161-
for _, line := range inLines {
162-
163-
expr, err := parser.ParseExpr(line)
164-
if err != nil {
165-
return nil, err
166-
}
167-
exprs = append(exprs, expr)
168-
169-
stmt := &ast.ExprStmt{
170-
X: &ast.CallExpr{
171-
Fun: ast.NewIdent(printerName),
172-
Args: []ast.Expr{expr},
173-
},
174-
}
157+
func (s *Session) evalExpr(in string) (ast.Expr, error) {
158+
expr, err := parser.ParseExpr(in)
159+
if err != nil {
160+
return nil, err
161+
}
175162

176-
s.appendStatements(stmt)
163+
stmt := &ast.ExprStmt{
164+
X: &ast.CallExpr{
165+
Fun: ast.NewIdent(printerName),
166+
Args: []ast.Expr{expr},
167+
},
177168
}
178169

179-
return exprs, nil
170+
s.appendStatements(stmt)
171+
172+
return expr, nil
180173
}
181174

182175
func isNamedIdent(expr ast.Expr, name string) bool {
183176
ident, ok := expr.(*ast.Ident)
184177
return ok && ident.Name == name
185178
}
186179

187-
func (s *Session) evalStmt(in string) error {
180+
func (s *Session) evalStmt(in string, noPrint bool) error {
188181
src := fmt.Sprintf("package P; func F() { %s }", in)
189182
f, err := parser.ParseFile(s.Fset, "stmt.go", src, parser.Mode(0))
190183
if err != nil {
191-
return err
184+
debugf("stmt :: err = %s", err)
185+
186+
// try to import this as a proxy function and correct for any imports
187+
appendForImport := `package main
188+
189+
190+
`
191+
192+
f, err := os.Create(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
193+
if err != nil {
194+
return err
195+
}
196+
197+
_, err = f.Write([]byte(appendForImport + in))
198+
if err != nil {
199+
return err
200+
}
201+
f.Close()
202+
203+
b := new(bytes.Buffer)
204+
cmd := exec.Command("goimports", "-w", string(filepath.Dir(s.FilePath))+"/func_proxy.go")
205+
cmd.Stdout = b
206+
cmd.Stderr = b
207+
err = cmd.Run()
208+
if err != nil {
209+
os.Stderr.WriteString("Error running goimports:\n")
210+
io.Copy(os.Stderr, b)
211+
return err
212+
}
213+
214+
functproxy, err := ioutil.ReadFile(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
215+
if err != nil {
216+
return err
217+
}
218+
219+
if err = s.importFile(functproxy); err != nil {
220+
errorf("%s", err)
221+
if _, ok := err.(scanner.ErrorList); ok {
222+
return ErrContinue
223+
}
224+
}
225+
192226
}
193227

194228
enclosingFunc := f.Scope.Lookup("F").Decl.(*ast.FuncDecl)
195229
stmts := enclosingFunc.Body.List
196230

197231
if len(stmts) > 0 {
232+
198233
debugf("evalStmt :: %s", showNode(s.Fset, stmts))
199234
lastStmt := stmts[len(stmts)-1]
235+
200236
// print last assigned/defined values
201-
if assign, ok := lastStmt.(*ast.AssignStmt); ok {
202-
vs := []ast.Expr{}
203-
for _, v := range assign.Lhs {
204-
if !isNamedIdent(v, "_") {
205-
vs = append(vs, v)
237+
if !noPrint {
238+
if assign, ok := lastStmt.(*ast.AssignStmt); ok {
239+
vs := []ast.Expr{}
240+
for _, v := range assign.Lhs {
241+
if !isNamedIdent(v, "_") {
242+
vs = append(vs, v)
243+
}
206244
}
207-
}
208-
if len(vs) > 0 {
209-
printLastValues := &ast.ExprStmt{
210-
X: &ast.CallExpr{
211-
Fun: ast.NewIdent(printerName),
212-
Args: vs,
213-
},
245+
if len(vs) > 0 {
246+
printLastValues := &ast.ExprStmt{
247+
X: &ast.CallExpr{
248+
Fun: ast.NewIdent(printerName),
249+
Args: vs,
250+
},
251+
}
252+
stmts = append(stmts, printLastValues)
214253
}
215-
stmts = append(stmts, printLastValues)
216254
}
217255
}
218256
}
@@ -345,53 +383,9 @@ func (s *Session) Eval(in string) (string, bytes.Buffer, error) {
345383
return "", bytes.Buffer{}, nil
346384
}
347385

348-
if _, err := s.evalExpr(in); err != nil {
349-
debugf("expr :: err = %s", err)
350-
351-
err := s.evalStmt(in)
352-
if err != nil {
353-
debugf("stmt :: err = %s", err)
354-
355-
// try to import this as a proxy function and correct for any imports
356-
appendForImport := `package main
357-
358-
359-
`
360-
361-
f, err := os.Create(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
362-
if err != nil {
363-
panic(err)
364-
}
365-
366-
_, err = f.Write([]byte(appendForImport + in))
367-
if err != nil {
368-
panic(err)
369-
}
370-
f.Close()
371-
372-
b := new(bytes.Buffer)
373-
cmd := exec.Command("goimports", "-w", string(filepath.Dir(s.FilePath))+"/func_proxy.go")
374-
cmd.Stdout = b
375-
cmd.Stderr = b
376-
err = cmd.Run()
377-
if err != nil {
378-
os.Stderr.WriteString("Error running goimports:\n")
379-
io.Copy(os.Stderr, b)
380-
panic(err)
381-
}
382-
383-
functproxy, err := ioutil.ReadFile(string(filepath.Dir(s.FilePath)) + "/func_proxy.go")
384-
if err != nil {
385-
panic(err)
386-
}
387-
388-
if err = s.importFile(functproxy); err != nil {
389-
errorf("%s", err)
390-
if _, ok := err.(scanner.ErrorList); ok {
391-
return "", bytes.Buffer{}, ErrContinue
392-
}
393-
}
394-
}
386+
// Extract statements.
387+
if err := s.separateEvalStmt(in); err != nil {
388+
return "", bytes.Buffer{}, err
395389
}
396390

397391
s.doQuickFix()
@@ -413,6 +407,54 @@ func (s *Session) Eval(in string) (string, bytes.Buffer, error) {
413407
return string(output), strerr, err
414408
}
415409

410+
// separateEvalStmt separates what can be evaluated via evalExpr from what cannot.
411+
func (s *Session) separateEvalStmt(in string) error {
412+
var stmtLines []string
413+
var exprCount int
414+
415+
inLines := strings.Split(in, "\n")
416+
417+
for _, line := range inLines {
418+
419+
priorLen := len(s.mainBody.List)
420+
421+
if _, err := s.evalExpr(line); err != nil {
422+
stmtLines = append(stmtLines, line)
423+
continue
424+
}
425+
426+
if len(stmtLines) != 0 {
427+
428+
currentLen := len(s.mainBody.List)
429+
trimNum := currentLen - priorLen
430+
s.mainBody.List = s.mainBody.List[0 : currentLen-trimNum]
431+
432+
if err := s.evalStmt(strings.Join(stmtLines, "\n"), true); err != nil {
433+
return err
434+
}
435+
stmtLines = []string{}
436+
437+
if _, err := s.evalExpr(line); err != nil {
438+
return err
439+
}
440+
}
441+
442+
exprCount++
443+
}
444+
445+
if len(stmtLines) != 0 {
446+
var noPrint bool
447+
if exprCount > 0 {
448+
noPrint = true
449+
}
450+
if err := s.evalStmt(strings.Join(stmtLines, "\n"), noPrint); err != nil {
451+
return err
452+
}
453+
}
454+
455+
return nil
456+
}
457+
416458
// storeMainBody stores current state of code so that it can be restored
417459
// actually it saves the length of statements inside main()
418460
func (s *Session) storeMainBody() {

0 commit comments

Comments
 (0)