@jdeighan/coffee-utils 7.0.49 → 7.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,8 @@
1
1
  # debug_utils.coffee
2
2
 
3
3
  import {
4
- assert, undef, error, croak, warn, isString, isFunction, isBoolean,
4
+ assert, undef, error, croak, warn, defined,
5
+ isString, isFunction, isBoolean, sep_dash,
5
6
  OL, escapeStr, isNumber, isArray, words, pass,
6
7
  } from '@jdeighan/coffee-utils'
7
8
  import {blockToArray} from '@jdeighan/coffee-utils/block'
@@ -9,17 +10,134 @@ import {untabify} from '@jdeighan/coffee-utils/indent'
9
10
  import {slurp} from '@jdeighan/coffee-utils/fs'
10
11
  import {CallStack} from '@jdeighan/coffee-utils/stack'
11
12
  import {
12
- log, logItem, LOG, setStringifier, orderedStringify,
13
+ getPrefix, addArrow, removeLastVbar,
14
+ } from '@jdeighan/coffee-utils/arrow'
15
+ import {
16
+ log, logItem, LOG, shortEnough,
13
17
  } from '@jdeighan/coffee-utils/log'
14
18
 
15
- # --- These are saved/restored on the call stack
16
- export debugging = false
17
- shouldLogFunc = (func) -> debugging
18
- shouldLogString = (str) -> debugging
19
-
20
- stack = new CallStack()
19
+ callStack = new CallStack()
21
20
  doDebugDebug = false
22
21
 
22
+ export shouldLog = undef # set in resetDebugging() and setDebugging()
23
+ export lFuncList = []
24
+
25
+ # ---------------------------------------------------------------------------
26
+
27
+ export debug = (label, lObjects...) ->
28
+
29
+ assert isString(label), "1st arg #{OL(label)} should be a string"
30
+
31
+ # --- We want to allow objects to be undef. Therefore, we need to
32
+ # distinguish between 1 arg sent vs. 2 or more args sent
33
+ nObjects = lObjects.length
34
+
35
+ # --- funcName is only set for types 'enter' and 'return'
36
+ [type, funcName] = getType(label, nObjects)
37
+ if doDebugDebug
38
+ LOG "debug(): type = #{OL(type)}"
39
+ LOG "debug(): funcName = #{OL(funcName)}"
40
+
41
+ switch type
42
+ when 'enter'
43
+ callStack.enter funcName
44
+ label = shouldLog(label, type, funcName, callStack)
45
+ when 'return'
46
+ label = shouldLog(label, type, funcName, callStack)
47
+ when 'string'
48
+ label = shouldLog(label, type, undef, callStack)
49
+ assert (nObjects == 0),
50
+ "multiple objects only not allowed for #{OL(type)}"
51
+ when 'objects'
52
+ label = shouldLog(label, type, undef, callStack)
53
+ assert (nObjects > 0),
54
+ "multiple objects only not allowed for #{OL(type)}"
55
+ doLog = defined(label)
56
+
57
+ if doDebugDebug
58
+ if nObjects == 0
59
+ LOG "debug(#{OL(label)}) - 1 arg"
60
+ else
61
+ LOG "debug(#{OL(label)}), #{nObjects} args"
62
+ LOG "doLog = #{OL(doLog)}"
63
+
64
+ if doLog
65
+ level = callStack.getLevel()
66
+ prefix = getPrefix(level)
67
+
68
+ if doDebugDebug
69
+ LOG "callStack", callStack
70
+ LOG "level = #{OL(level)}"
71
+ LOG "prefix = #{OL(prefix)}"
72
+
73
+ switch type
74
+ when 'enter'
75
+ log label, {prefix}
76
+ for obj,i in lObjects
77
+ if (i > 0)
78
+ log sep_dash, {prefix: removeLastVbar(prefix)}
79
+ logItem undef, obj, {prefix: removeLastVbar(prefix)}
80
+ when 'return'
81
+ log label, {prefix: addArrow(prefix)}
82
+ for obj,i in lObjects
83
+ if (i > 0)
84
+ log sep_dash, {prefix: removeLastVbar(prefix)}
85
+ logItem undef, obj, {prefix: removeLastVbar(prefix)}
86
+ when 'string'
87
+ log label, {prefix}
88
+ when 'objects'
89
+ if (nObjects==1) && shortEnough(label, lObjects[0])
90
+ logItem label, lObjects[0], {prefix}
91
+ else
92
+ if (label.indexOf(':') != label.length - 1)
93
+ label += ':'
94
+ log label, {prefix}
95
+ for obj in lObjects
96
+ logItem undef, obj, {prefix}
97
+
98
+ if (type == 'enter') && doLog
99
+ callStack.logCurFunc()
100
+ else if (type == 'return')
101
+ callStack.returnFrom funcName
102
+
103
+ return true # allow use in boolean expressions
104
+
105
+ # ---------------------------------------------------------------------------
106
+
107
+ export stdShouldLog = (label, type, funcName, stack) ->
108
+ # --- if type is 'enter', then funcName won't be on the stack yet
109
+ # returns the (possibly modified) label to log
110
+
111
+ # --- If we're logging now,
112
+ # but we won't be logging when funcName is activated
113
+ # then change 'enter' to 'call'
114
+
115
+ assert isString(label), "label #{OL(label)} not a string"
116
+ assert isString(type), "type #{OL(type)} not a string"
117
+ if (type == 'enter') || (type == 'return')
118
+ assert isString(funcName), "func name #{OL(funcName)} not a string"
119
+ else
120
+ assert funcName == undef, "func name #{OL(funcName)} not undef"
121
+ assert stack instanceof CallStack, "not a call stack object"
122
+ if doDebugDebug
123
+ LOG "stdShouldLog(#{OL(label)}, #{OL(type)}, #{OL(funcName)}, stack)"
124
+ LOG "stack", stack
125
+ LOG "lFuncList", lFuncList
126
+ switch type
127
+ when 'enter'
128
+ if funcMatch(stack, lFuncList)
129
+ return label
130
+
131
+ # --- As a special case, if we enter a function where we will not
132
+ # be logging, but we were logging in the calling function,
133
+ # we'll log out the call itself
134
+ else if stack.isLoggingPrev()
135
+ return label.replace('enter', 'call')
136
+ else
137
+ if funcMatch(stack, lFuncList)
138
+ return label
139
+ return undef
140
+
23
141
  # ---------------------------------------------------------------------------
24
142
 
25
143
  export debugDebug = (flag=true) ->
@@ -33,176 +151,124 @@ export debugDebug = (flag=true) ->
33
151
 
34
152
  resetDebugging = () ->
35
153
 
36
- debugging = false
37
154
  if doDebugDebug
38
- LOG "resetDebugging() - debugging = false"
39
- stack.reset()
40
- shouldLogFunc = (func) -> debugging
41
- shouldLogString = (str) -> debugging
155
+ LOG "resetDebugging()"
156
+ callStack.reset()
157
+ shouldLog = (label, type, funcName, stack) -> undef
42
158
  return
43
159
 
44
160
  # ---------------------------------------------------------------------------
45
161
 
46
- export setDebugging = (funcDoDebug=undef, funcDoLog=undef) ->
162
+ export setDebugging = (option) ->
47
163
 
48
164
  resetDebugging()
49
- if isBoolean(funcDoDebug)
50
- debugging = funcDoDebug
165
+ if isBoolean(option)
166
+ if option
167
+ shouldLog = (label, type, funcName, stack) -> label
168
+ else
169
+ shouldLog = (label, type, funcName, stack) -> undef
51
170
  if doDebugDebug
52
- LOG "setDebugging(): debugging = #{funcDoDebug}"
53
- else if isString(funcDoDebug)
54
- debugging = false
55
- lFuncNames = words(funcDoDebug)
56
- assert isArray(lFuncNames), "words('#{funcDoDebug}') returned non-array"
57
- shouldLogFunc = (funcName) ->
58
- funcMatch(funcName, lFuncNames)
171
+ LOG "setDebugging = #{option}"
172
+ else if isString(option)
173
+ lFuncList = getFuncList(option)
174
+ shouldLog = stdShouldLog
59
175
  if doDebugDebug
60
- LOG "setDebugging FUNCS: #{lFuncNames.join(',')}, debugging = false"
61
- else if isFunction(funcDoDebug)
62
- shouldLogFunc = funcDoDebug
176
+ LOG "setDebugging FUNCS: #{option}"
177
+ LOG 'lFuncList', lFuncList
178
+ else if isFunction(option)
179
+ shouldLog = option
63
180
  if doDebugDebug
64
181
  LOG "setDebugging to custom func"
65
182
  else
66
- croak "setDebugging(): bad parameter #{OL(funcDoDebug)}"
67
-
68
- if funcDoLog
69
- assert isFunction(funcDoLog), "setDebugging: arg 2 not a function"
70
- shouldLogString = funcDoLog
183
+ croak "bad parameter #{OL(option)}"
71
184
  return
72
185
 
73
186
  # ---------------------------------------------------------------------------
74
187
  # --- export only to allow unit tests
75
188
 
76
- export funcMatch = (curFunc, lFuncNames) ->
189
+ export getFuncList = (str) ->
190
+
191
+ lFuncList = []
192
+ for word in words(str)
193
+ if lMatches = word.match(///^
194
+ ([A-Za-z_][A-Za-z0-9_]*)
195
+ (?:
196
+ \.
197
+ ([A-Za-z_][A-Za-z0-9_]*)
198
+ )?
199
+ (\+)?
200
+ $///)
201
+ [_, ident1, ident2, plus] = lMatches
202
+ if ident2
203
+ lFuncList.push {
204
+ name: ident2
205
+ object: ident1
206
+ plus: (plus == '+')
207
+ }
208
+ else
209
+ lFuncList.push {
210
+ name: ident1
211
+ plus: (plus == '+')
212
+ }
213
+ else
214
+ croak "Bad word in func list: #{OL(word)}"
215
+ return lFuncList
77
216
 
78
- assert isString(curFunc), "funcMatch(): not a string"
79
- assert isArray(lFuncNames), "funcMatch(): bad array #{lFuncNames}"
80
- if lFuncNames.includes(curFunc)
81
- return true
82
- else if (lMatches = curFunc.match(reMethod)) \
83
- && ([_, cls, meth] = lMatches) \
84
- && lFuncNames.includes(meth)
85
- return true
86
- else
87
- return false
217
+ # ---------------------------------------------------------------------------
218
+ # --- export only to allow unit tests
219
+
220
+ export funcMatch = (stack, lFuncList) ->
221
+
222
+ assert isArray(lFuncList), "not an array #{OL(lFuncList)}"
223
+
224
+ curFunc = stack.curFunc()
225
+ if doDebugDebug
226
+ LOG "funcMatch(): curFunc = #{OL(curFunc)}"
227
+ stack.dump(' ')
228
+ LOG 'lFuncList', lFuncList
229
+ for h in lFuncList
230
+ {name, object, plus} = h
231
+ if (name == curFunc)
232
+ if doDebugDebug
233
+ LOG " curFunc in lFuncList - match successful"
234
+ return true
235
+ if plus && stack.isActive(name)
236
+ if doDebugDebug
237
+ LOG " func #{OL(name)} is active - match successful"
238
+ return true
239
+ if doDebugDebug
240
+ LOG " - no match"
241
+ return false
88
242
 
89
243
  # ---------------------------------------------------------------------------
90
- # 1. adjust call stack on 'enter' or 'return from'
91
- # 2. adjust debugging flag
92
- # 3. return [mainPrefix, auxPrefix, hEnv] - hEnv can be undef
93
- # 4. disable logging by setting mainPrefix to undef
244
+ # --- type is one of: 'enter', 'return', 'string', 'object'
94
245
 
95
- adjustStack = (str) ->
246
+ export getType = (str, nObjects) ->
96
247
 
97
- if (lMatches = str.match(///^
248
+ if lMatches = str.match(///^
98
249
  \s*
99
250
  enter
100
251
  \s+
101
252
  ([A-Za-z_][A-Za-z0-9_\.]*)
102
- ///))
103
- curFunc = lMatches[1]
104
- hEnv = {
105
- debugging
106
- shouldLogFunc
107
- shouldLogString
108
- }
109
- debugging = shouldLogFunc(curFunc)
110
- if doDebugDebug
111
- trans = "#{hEnv.debugging} => #{debugging}"
112
- LOG " ENTER #{curFunc}, debugging: #{trans}"
113
- [mainPre, auxPre, _] = stack.call(curFunc, hEnv, debugging)
114
- return [
115
- mainPre
116
- auxPre
117
- undef
118
- if shouldLogFunc(curFunc) then 'enter' else undef
119
- ]
120
- else if (lMatches = str.match(///^
253
+ ///)
254
+
255
+ # --- We are entering function curFunc
256
+ return ['enter', lMatches[1]]
257
+
258
+ else if lMatches = str.match(///^
121
259
  \s*
122
260
  return
123
261
  .+
124
262
  from
125
263
  \s+
126
264
  ([A-Za-z_][A-Za-z0-9_\.]*)
127
- ///))
128
- curFunc = lMatches[1]
129
- [mainPre, auxPre, hEnv] = stack.returnFrom(curFunc)
130
- if doDebugDebug
131
- LOG " RETURN FROM #{curFunc}"
132
- return [
133
- mainPre
134
- auxPre
135
- hEnv
136
- if shouldLogFunc(curFunc) then 'return' else undef
137
- ]
138
- else
139
- [mainPre, auxPre, _] = stack.logStr()
140
- return [
141
- mainPre
142
- auxPre
143
- undef
144
- if shouldLogString(str) then 'string' else undef
145
- ]
146
-
147
- # ---------------------------------------------------------------------------
148
-
149
- export debug = (lArgs...) ->
265
+ ///)
266
+ return ['return', lMatches[1]]
150
267
 
151
- # --- We want to allow item to be undef. Therefore, we need to
152
- # distinguish between 1 arg sent vs. 2 args sent
153
- nArgs = lArgs.length
154
- assert (nArgs==1) || (nArgs==2), "debug(): #{nArgs} args"
155
- [label, item] = lArgs
156
- assert isString(label),
157
- "debug(): 1st arg #{OL(label)} should be a string"
158
-
159
- if doDebugDebug
160
- if nArgs==1
161
- LOG "debug('#{escapeStr(label)}') - 1 arg"
162
- else
163
- LOG "debug('#{escapeStr(label)}', #{typeof item}) - 2 args"
164
- LOG "debugging flag = #{OL(debugging)}"
165
-
166
- # --- We always need to manipulate the stack when we encounter
167
- # either "enter X" or "return from X", so we can't short-circuit
168
- # when debugging is off
169
-
170
- lResult = adjustStack(label)
171
- if doDebugDebug
172
- LOG 'lResult', lResult
173
- [mainPre, auxPre, hEnv, type] = lResult
174
- if doDebugDebug && (type == undef)
175
- LOG "type is undef - NOT LOGGING"
176
-
177
- hOptions = {
178
- prefix: mainPre
179
- itemPrefix: auxPre
180
- }
181
-
182
- switch type
183
- when 'enter'
184
- log label, hOptions
185
- if (nArgs==2)
186
- # --- don't repeat the label
187
- logItem undef, item, hOptions
188
- when 'return'
189
- log label, hOptions
190
- if (nArgs==2)
191
- # --- don't repeat the label
192
- logItem undef, item, hOptions
193
- when 'string'
194
- if (nArgs==2)
195
- logItem label, item, hOptions
196
- else
197
- log label, hOptions
198
-
199
- if hEnv
200
- orgDebugging = debugging
201
- {debugging, shouldLogFunc, shouldLogString} = hEnv
202
- if doDebugDebug
203
- trans = "#{orgDebugging} => #{debugging}"
204
- LOG " Restore hEnv: debugging: #{trans}"
205
- return true # allow use in boolean expressions
268
+ else if (nObjects > 0)
269
+ return ['objects', undef]
270
+ else
271
+ return ['string', undef]
206
272
 
207
273
  # ---------------------------------------------------------------------------
208
274