Overview: not a “REPL” exactly
- REPL: Read-Eval-Print-Loop
- No “Eval” and “Print” phase
- As we do them by “go run”
- Much like: Read-Generate-Run-Loop
Generate: The Delicious Part
- Append the input AST nodes to our main()
- Add the code to print the value
Printing Values
- The generated program prints values (not gore)
- “New Values” should be printed
- Expression: Its resulting value
- Statement: Values assigned
Printing Values: Statements
- ast.AssignStmt stands for assign/define
- User: a, b := foo()
- Gore: a, b := foo(); __gore_p(a, b)
Printing Values: __gore_p()
- “Pretty prints” values
- Defined along with the main()
- Depends on installed packages
- ! k0kubun/pp, ! davecgh/go-spew or plain old %#v
The Initial .go File (pp)
package main
import "github.com/k0kubun/pp"
func __gore_p(xx ...interface{}) {
for _, x := range xx {
pp.Println(x)
}
}
func main() {
// User input goes here
}
The Initial .go File (go-spew)
package main
import "github.com/davecgh/go-spew/spew"
func __gore_p(xx ...interface{}) {
for _, x := range xx {
spew.Printf("%#vn", x)
}
}
func main() {
// User input goes here
}
The Initial .go File (%#v)
package main
import "fmt"
func __gore_p(xx ...interface{}) {
for _, x := range xx {
fmt.Printf("%#vn", x)
}
}
func main() {
// User input goes here
}
Generate: Append to main()
- Just append those generated statements
s.mainBody.List = append(s.mainBody.List, stmts…)
- Now we’ve got the working code!
- Really? No! %
Go compiler complaints (you know)
- “x declared but not used”
- “p imported but not used”
- “no new variables of left side of :=“
- & Should remove these to a successful go run
Quick Fixing Erroneous Program
- “x declared but not used”
- “p imported but not used”
- “no new variables on left side of :=“
Use it!!
Anonymize it!!
Make it `=‘ !!
“declared but not used”
package P
func main() {
s := "hello"
}
package P
func main() {
s := "hello"
_ = s
}
”imported but not used”
package P
import "fmt"
func main() {
}
package P
import _ "fmt"
func main() {
}
“no new variables on left side of :=“
package P
func main() {
var a int
a := 1
}
package P
func main() {
var a int
a = 1
}
! motemen/go-quickfix to do the work
- Type check source code using go/types.Check()
- Catch errors and modify AST
- Packed with a bin
- goquickfix -w main.go
Running
- Output the AST to file — go/printer
- Then go run
- If failed to run, revert the last input
Recap: Read-Gen-Quickfix-Run-Loop
1. Read and parse the input to obtain AST
2. Add printing function call __gore_p()
3. Append the code to main()
4. Quickfix it so that it compiles well
5. go run
Code Completion
- liner has support for completion
- Great tool for editors: ! nsf/gocode
- Server/client model
- And an interface to it: motemen/gore/gocode
- If gocode binary can be located, use it