/
trace.go
183 lines (154 loc) · 4.28 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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) 2018, Cogent Core. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package parser
import (
"fmt"
"os"
"strings"
"cogentcore.org/core/parse/lexer"
)
// TraceOptions provides options for debugging / monitoring the rule matching and execution process
type TraceOptions struct {
// perform tracing
On bool
// trace specific named rules here (space separated) -- if blank, then all rules are traced
Rules string `width:"50"`
// trace full rule matches -- when a rule fully matches
Match bool
// trace sub-rule matches -- when the parts of each rule match
SubMatch bool
// trace sub-rule non-matches -- why a rule doesn't match -- which terminates the matching process at first non-match (can be a lot of info)
NoMatch bool
// trace progress running through each of the sub-rules when a rule has matched and is 'running'
Run bool
// trace actions performed by running rules
RunAct bool
// if true, shows the full scope source for every trace statement
ScopeSrc bool
// for the ParseOut display, whether to display the full stack of rules at each position, or just the deepest one
FullStackOut bool
// list of rules
RulesList []string `view:"-" json:"-" xml:"-"`
// trace output is written here, connected via os.Pipe to OutRead
OutWrite *os.File `view:"-" json:"-" xml:"-"`
// trace output is read here; can connect this using [texteditor.OutputBuffer] to monitor tracing output
OutRead *os.File `view:"-" json:"-" xml:"-"`
}
// Init intializes tracer after any changes -- opens pipe if not already open
func (pt *TraceOptions) Init() {
if pt.Rules == "" {
pt.RulesList = nil
} else {
pt.RulesList = strings.Split(pt.Rules, " ")
}
}
// FullOn sets all options on
func (pt *TraceOptions) FullOn() {
pt.On = true
pt.Match = true
pt.SubMatch = true
pt.NoMatch = true
pt.Run = true
pt.RunAct = true
pt.ScopeSrc = true
}
// PipeOut sets output to a pipe for monitoring (OutWrite -> OutRead)
func (pt *TraceOptions) PipeOut() {
if pt.OutWrite == nil {
pt.OutRead, pt.OutWrite, _ = os.Pipe() // seriously, does this ever fail?
}
}
// Stdout sets [TraceOptions.OutWrite] to [os.Stdout]
func (pt *TraceOptions) Stdout() {
pt.OutWrite = os.Stdout
}
// CheckRule checks if given rule should be traced
func (pt *TraceOptions) CheckRule(rule string) bool {
if len(pt.RulesList) == 0 {
if pt.Rules != "" {
pt.Init()
if len(pt.RulesList) == 0 {
return true
}
} else {
return true
}
}
for _, rn := range pt.RulesList {
if rn == rule {
return true
}
}
return false
}
// Out outputs a trace message -- returns true if actually output
func (pt *TraceOptions) Out(ps *State, pr *Rule, step Steps, pos lexer.Pos, scope lexer.Reg, ast *Ast, msg string) bool {
if !pt.On {
return false
}
if !pt.CheckRule(pr.Nm) {
return false
}
switch step {
case Match:
if !pt.Match {
return false
}
case SubMatch:
if !pt.SubMatch {
return false
}
case NoMatch:
if !pt.NoMatch {
return false
}
case Run:
if !pt.Run {
return false
}
case RunAct:
if !pt.RunAct {
return false
}
}
tokSrc := pos.String() + `"` + string(ps.Src.TokenSrc(pos)) + `"`
plev := ast.ParentLevel(ps.Ast)
ind := ""
for i := 0; i < plev; i++ {
ind += "\t"
}
fmt.Fprintf(pt.OutWrite, "%v%v:\t %v\t %v\t tok: %v\t scope: %v\t ast: %v\n", ind, pr.Name(), step, msg, tokSrc, scope, ast.Path())
if pt.ScopeSrc {
scopeSrc := ps.Src.TokenRegSrc(scope)
fmt.Fprintf(pt.OutWrite, "%v\t%v\n", ind, scopeSrc)
}
return true
}
// CopyOpts copies just the options
func (pt *TraceOptions) CopyOpts(ot *TraceOptions) {
pt.On = ot.On
pt.Rules = ot.Rules
pt.Match = ot.Match
pt.SubMatch = ot.SubMatch
pt.NoMatch = ot.NoMatch
pt.Run = ot.Run
pt.RunAct = ot.RunAct
pt.ScopeSrc = ot.ScopeSrc
}
// Steps are the different steps of the parsing processing
type Steps int32 //enums:enum
// The parsing steps
const (
// Match happens when a rule matches
Match Steps = iota
// SubMatch is when a sub-rule within a rule matches
SubMatch
// NoMatch is when the rule fails to match (recorded at first non-match, which terminates
// matching process
NoMatch
// Run is when the rule is running and iterating through its sub-rules
Run
// RunAct is when the rule is running and performing actions
RunAct
)