delve/_fixtures/fncall.go

205 lines
3.8 KiB
Go
Raw Normal View History

package main
import (
"fmt"
"os"
"runtime"
"strings"
)
var call = "this is a variable named `call`"
func callstacktrace() (stacktrace string) {
for skip := 0; ; skip++ {
pc, file, line, ok := runtime.Caller(skip)
if !ok {
break
}
fn := runtime.FuncForPC(pc)
stacktrace += fmt.Sprintf("in %s at %s:%d\n", fn.Name(), file, line)
}
return stacktrace
}
func call0(a, b int) {
fmt.Printf("call0: first: %d second: %d\n", a, b)
}
func call1(a, b int) int {
fmt.Printf("first: %d second: %d\n", a, b)
return a + b
}
func call2(a, b int) (int, int) {
fmt.Printf("call2: first: %d second: %d\n", a, b)
return a, b
}
func callexit() {
fmt.Printf("about to exit\n")
os.Exit(0)
}
func callpanic() {
fmt.Printf("about to panic\n")
panic("callpanic panicked")
}
func callbreak() {
fmt.Printf("about to break")
runtime.Breakpoint()
}
func stringsJoin(v []string, sep string) string {
// This is needed because strings.Join is in an optimized package and
// because of a bug in the compiler arguments of optimized functions don't
// have a location.
return strings.Join(v, sep)
}
type astruct struct {
X int
}
type a2struct struct {
Y int
}
func (a astruct) VRcvr(x int) string {
return fmt.Sprintf("%d + %d = %d", x, a.X, x+a.X)
}
func (pa *astruct) PRcvr(x int) string {
return fmt.Sprintf("%d - %d = %d", x, pa.X, x-pa.X)
}
type PRcvrable interface {
PRcvr(int) string
}
type VRcvrable interface {
VRcvr(int) string
}
var zero = 0
func makeclos(pa *astruct) func(int) string {
i := 0
return func(x int) string {
i++
return fmt.Sprintf("%d + %d + %d = %d", i, pa.X, x, i+pa.X+x)
}
}
var ga astruct
var globalPA2 *a2struct
func escapeArg(pa2 *a2struct) {
globalPA2 = pa2
}
proc: allow function calls to appear inside an expression (#1503) The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates #119
2019-05-09 15:29:58 +00:00
func square(x int) int {
return x * x
}
func intcallpanic(a int) int {
if a == 0 {
panic("panic requested")
}
return a
}
func onetwothree(n int) []int {
return []int{n + 1, n + 2, n + 3}
}
func curriedAdd(n int) func(int) int {
return func(m int) int {
return n + m
}
}
func getAStruct(n int) astruct {
return astruct{X: n}
}
func getAStructPtr(n int) *astruct {
return &astruct{X: n}
}
func getVRcvrableFromAStruct(n int) VRcvrable {
return astruct{X: n}
}
func getPRcvrableFromAStructPtr(n int) PRcvrable {
return &astruct{X: n}
}
func getVRcvrableFromAStructPtr(n int) VRcvrable {
return &astruct{X: n}
}
func noreturncall(n int) {
return
}
type Base struct {
y int
}
type Derived struct {
x int
Base
}
func (b *Base) Method() int {
return b.y
}
type X int
func (_ X) CallMe() {
println("foo")
}
type X2 int
func (_ X2) CallMe(i int) int {
return i * i
}
func main() {
one, two := 1, 2
intslice := []int{1, 2, 3}
stringslice := []string{"one", "two", "three"}
comma := ","
a := astruct{X: 3}
pa := &astruct{X: 6}
a2 := a2struct{Y: 7}
var pa2 *astruct
var str string = "old string value"
dap: use larger string type variable load limits in 'repl', 'variables' context (#2418) * dap: use larger variable load limits in 'repl', 'variables' context When evaluate requests are triggered in the context of 'repl' (DEBUG CONSOLE in VSCode) or 'variables' (copy values from VARIABLES section in VSCode), they are the result of human action and have more rooms to display. So it is not too bad to apply longer limits. Variable auto-loading for strings or arrays is nice but currently it's unclear to me how this should be integrated in the DEBUG CONSOLE or with the Copy Value feature. Until we have better ideas and tools, let's go with these larger limits. Unfortunately, the "Copy Value" from WATCH section triggers evaluate requests with "watch" context and we don't want to load large data automatically for "watch". So, users who want to query a large value should first copy the expression to DEBUG CONSOLE and evaluate it. Not ideal but not the end of the world either. Updates golang/vscode-go#1318 * dap: apply large limit only to the string type result * dap: move string reload logic to convertVariable* where other reload logic is Currently we are thinking string reload for evaluation as a temporary workaround until we figure out an intutitive way to present long strings. So, I hope moving this logic near other reload logic may be better. And, use the address based expression when reloading - when handling the function return values, we may not have an expression to use. * dap: make deep source check happy * dap: move string reevaluation logic back to onEvaluateRequest Reloading string variables is tricky if they are in registers. We don't attempt to reload them but for clarity, move this up to the onEvaluateRequest handler. For function call, use a generous limit for string load since the results are volatile. * dap: check variable isn't affected by evaluate in other context
2021-05-25 17:23:41 +00:00
longstrs := []string{"very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"}
var vable_a VRcvrable = a
var vable_pa VRcvrable = pa
var pable_pa PRcvrable = pa
var x X = 2
var x2 X2 = 2
fn2clos := makeclos(pa)
fn2glob := call1
fn2valmeth := pa.VRcvr
fn2ptrmeth := pa.PRcvr
var fn2nil func()
d := &Derived{3, Base{4}}
runtime.Breakpoint() // breakpoint here
call1(one, two)
fn2clos(2)
strings.LastIndexByte(stringslice[1], 'w')
d.Method()
d.Base.Method()
x.CallMe()
dap: use larger string type variable load limits in 'repl', 'variables' context (#2418) * dap: use larger variable load limits in 'repl', 'variables' context When evaluate requests are triggered in the context of 'repl' (DEBUG CONSOLE in VSCode) or 'variables' (copy values from VARIABLES section in VSCode), they are the result of human action and have more rooms to display. So it is not too bad to apply longer limits. Variable auto-loading for strings or arrays is nice but currently it's unclear to me how this should be integrated in the DEBUG CONSOLE or with the Copy Value feature. Until we have better ideas and tools, let's go with these larger limits. Unfortunately, the "Copy Value" from WATCH section triggers evaluate requests with "watch" context and we don't want to load large data automatically for "watch". So, users who want to query a large value should first copy the expression to DEBUG CONSOLE and evaluate it. Not ideal but not the end of the world either. Updates golang/vscode-go#1318 * dap: apply large limit only to the string type result * dap: move string reload logic to convertVariable* where other reload logic is Currently we are thinking string reload for evaluation as a temporary workaround until we figure out an intutitive way to present long strings. So, I hope moving this logic near other reload logic may be better. And, use the address based expression when reloading - when handling the function return values, we may not have an expression to use. * dap: make deep source check happy * dap: move string reevaluation logic back to onEvaluateRequest Reloading string variables is tricky if they are in registers. We don't attempt to reload them but for clarity, move this up to the onEvaluateRequest handler. For function call, use a generous limit for string load since the results are volatile. * dap: check variable isn't affected by evaluate in other context
2021-05-25 17:23:41 +00:00
fmt.Println(one, two, zero, call, call0, call2, callexit, callpanic, callbreak, callstacktrace, stringsJoin, intslice, stringslice, comma, a.VRcvr, a.PRcvr, pa, vable_a, vable_pa, pable_pa, fn2clos, fn2glob, fn2valmeth, fn2ptrmeth, fn2nil, ga, escapeArg, a2, square, intcallpanic, onetwothree, curriedAdd, getAStruct, getAStructPtr, getVRcvrableFromAStruct, getPRcvrableFromAStructPtr, getVRcvrableFromAStructPtr, pa2, noreturncall, str, d, x, x2.CallMe(5), longstrs)
}