-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtrace.go
168 lines (151 loc) · 3.96 KB
/
trace.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright 2014-2015 Rocky Bernstein
package ssa2
import (
"fmt"
"go/token"
"go/ast"
)
//-------------------------------
type TraceEvent uint8
const (
OTHER TraceEvent = iota
ASSIGN_STMT
BLOCK_END
BREAK_STMT
BREAKPOINT
CALL_ENTER
CALL_RETURN
DEFER_ENTER
EXPR
IF_INIT
IF_COND
FOR_INIT
FOR_COND
FOR_ITER
PANIC
PROGRAM_TERMINATION
RANGE_STMT
MAIN
SELECT_TYPE
STEP_INSTRUCTION
STMT_IN_LIST
SWITCH_COND
TRACE_CALL
)
const TRACE_EVENT_FIRST = OTHER
const TRACE_EVENT_LAST = TRACE_CALL
type TraceEventMask map[TraceEvent]bool
var Event2Name map[TraceEvent]string
func init() {
Event2Name = map[TraceEvent]string{
OTHER : "?",
ASSIGN_STMT : "Assignment Statement",
BLOCK_END : "Block End",
BREAK_STMT : "BREAK",
BREAKPOINT : "Breakpoint",
CALL_ENTER : "function entry",
CALL_RETURN : "function return",
EXPR : "Expression",
IF_INIT : "IF initialize",
IF_COND : "IF expression",
FOR_INIT : "FOR initialize",
FOR_COND : "FOR condition",
FOR_ITER : "FOR iteration",
MAIN : "before main()",
RANGE_STMT : "range statement",
SELECT_TYPE : "SELECT type",
STEP_INSTRUCTION: "Instruction step",
STMT_IN_LIST : "STATEMENT in list",
SWITCH_COND : "SWITCH condition",
PROGRAM_TERMINATION : "Program Terminated",
}
}
// The Trace instruction marks that some event in the source code
// about to take place. For example:
// - a new statement
// - an interesting expression in a "case" or "if" or "loop" statement
// - a return that is about to occur
// - a message synchronization
//
// These can be used by a debugger, profiler, code coverage
// tool or tracing tool.
//
// I'd like this to be a flag an instruction, but that
// was too difficult or ugly to be able for the high-level
// builder call to be able to access the first generated instruction.
// So instead we make it it's own instruction.
type Trace struct {
anInstruction
Start token.Pos // start position of source
End token.Pos // end position of source
Event TraceEvent
Breakpoint bool // Set if we should stop here
syntax ast.Node
}
// FIXME: arrange to put in ast
func PositionRange(start token.Position, end token.Position) string {
s := ""
if start.IsValid() {
s = start.Filename + ":" + PositionRangeSansFile(start, end)
} else if end.IsValid() {
s = "-"
if end.Filename != "" {
s += end.Filename + ":"
}
s += fmt.Sprintf("%d:%d", end.Line, end.Column)
}
if s == "" {
s = "-"
}
return s
}
func PositionRangeSansFile(start token.Position, end token.Position) string {
s := ""
if start.IsValid() {
s += fmt.Sprintf("%d:%d", start.Line, start.Column)
if start.Filename == end.Filename && end.IsValid() {
// this is what we expect
if start.Line == end.Line {
if start.Column != end.Column {
s += fmt.Sprintf("-%d", end.Column)
}
} else {
s += fmt.Sprintf("-%d:%d", end.Line, end.Column)
}
}
} else if end.IsValid() {
s = "-"
s += fmt.Sprintf("%d:%d", end.Line, end.Column)
}
if s == "" {
s = "-"
}
return s
}
func FmtPos(fset *token.FileSet, start token.Pos) string {
if start == token.NoPos { return "-" }
startP := fset.Position(start)
return PositionRange(startP, startP)
}
func FmtRangeWithFset(fset *token.FileSet, start token.Pos, end token.Pos) string {
startP := fset.Position(start)
endP := fset.Position(end)
return PositionRange(startP, endP)
}
func FmtRange(fn *Function, start token.Pos, end token.Pos) string {
fset := fn.Fset()
return FmtRangeWithFset(fset, start, end)
}
func (t *Trace) String() string {
fset := t.block.parent.Prog.Fset
startP := fset.Position(t.Start)
endP := fset.Position(t.End)
return fmt.Sprintf("trace <%s> at %s",
Event2Name[t.Event], PositionRange(startP, endP))
}
func (v *Trace) Operands(rands []*Value) []*Value {
return rands
}
func (t *Trace) Syntax() ast.Node { return t.syntax }
// Accessors
func (v *Trace) Pos() token.Pos { return v.Start }