@jdeighan/coffee-utils 7.0.50 → 7.0.53

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  assert, undef, error, croak, warn, defined,
5
- isString, isFunction, isBoolean,
5
+ isString, isFunction, isBoolean, sep_dash,
6
6
  OL, escapeStr, isNumber, isArray, words, pass,
7
7
  } from '@jdeighan/coffee-utils'
8
8
  import {blockToArray} from '@jdeighan/coffee-utils/block'
@@ -10,17 +10,134 @@ import {untabify} from '@jdeighan/coffee-utils/indent'
10
10
  import {slurp} from '@jdeighan/coffee-utils/fs'
11
11
  import {CallStack} from '@jdeighan/coffee-utils/stack'
12
12
  import {
13
- log, logItem, LOG, setStringifier, orderedStringify,
13
+ getPrefix, addArrow, removeLastVbar,
14
+ } from '@jdeighan/coffee-utils/arrow'
15
+ import {
16
+ log, logItem, LOG, shortEnough,
14
17
  } from '@jdeighan/coffee-utils/log'
15
18
 
16
- # --- These are saved/restored on the call stack
17
- export debugging = false
18
- shouldLogFunc = (func) -> return debugging
19
- shouldLogString = (str) -> return debugging
20
-
21
- stack = new CallStack()
19
+ callStack = new CallStack()
22
20
  doDebugDebug = false
23
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
+
24
141
  # ---------------------------------------------------------------------------
25
142
 
26
143
  export debugDebug = (flag=true) ->
@@ -34,183 +151,124 @@ export debugDebug = (flag=true) ->
34
151
 
35
152
  resetDebugging = () ->
36
153
 
37
- debugging = false
38
154
  if doDebugDebug
39
- LOG "resetDebugging() - debugging = false"
40
- stack.reset()
41
- shouldLogFunc = (func) -> return debugging
42
- shouldLogString = (str) -> return debugging
155
+ LOG "resetDebugging()"
156
+ callStack.reset()
157
+ shouldLog = (label, type, funcName, stack) -> undef
43
158
  return
44
159
 
45
160
  # ---------------------------------------------------------------------------
46
161
 
47
- export setDebugging = (funcDoDebug=undef, funcDoLog=undef) ->
162
+ export setDebugging = (option) ->
48
163
 
49
164
  resetDebugging()
50
- if isBoolean(funcDoDebug)
51
- 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
52
170
  if doDebugDebug
53
- LOG "setDebugging(): debugging = #{funcDoDebug}"
54
- else if isString(funcDoDebug)
55
- debugging = false
56
- lFuncNames = words(funcDoDebug)
57
- assert isArray(lFuncNames), "words('#{funcDoDebug}') returned non-array"
58
- shouldLogFunc = (funcName) ->
59
- funcMatch(funcName, lFuncNames)
171
+ LOG "setDebugging = #{option}"
172
+ else if isString(option)
173
+ lFuncList = getFuncList(option)
174
+ shouldLog = stdShouldLog
60
175
  if doDebugDebug
61
- LOG "setDebugging FUNCS: #{lFuncNames.join(',')}, debugging = false"
62
- else if isFunction(funcDoDebug)
63
- shouldLogFunc = funcDoDebug
176
+ LOG "setDebugging FUNCS: #{option}"
177
+ LOG 'lFuncList', lFuncList
178
+ else if isFunction(option)
179
+ shouldLog = option
64
180
  if doDebugDebug
65
181
  LOG "setDebugging to custom func"
66
182
  else
67
- croak "setDebugging(): bad parameter #{OL(funcDoDebug)}"
68
-
69
- if isFunction(funcDoLog)
70
- assert isFunction(funcDoLog), "setDebugging: arg 2 not a function"
71
- shouldLogString = funcDoLog
183
+ croak "bad parameter #{OL(option)}"
72
184
  return
73
185
 
74
186
  # ---------------------------------------------------------------------------
75
187
  # --- export only to allow unit tests
76
188
 
77
- 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
78
216
 
79
- assert isString(curFunc), "funcMatch(): not a string"
80
- assert isArray(lFuncNames), "funcMatch(): bad array #{lFuncNames}"
81
- if lFuncNames.includes(curFunc)
82
- return true
83
- else if (lMatches = curFunc.match(reMethod)) \
84
- && ([_, cls, meth] = lMatches) \
85
- && lFuncNames.includes(meth)
86
- return true
87
- else
88
- 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
89
242
 
90
243
  # ---------------------------------------------------------------------------
91
- # 1. adjust call stack on 'enter' or 'return from'
92
- # 2. adjust debugging flag
93
- # 3. return [mainPrefix, auxPrefix, hEnv, type] - hEnv can be undef
94
- # 4. disable logging by setting type to undef
244
+ # --- type is one of: 'enter', 'return', 'string', 'object'
95
245
 
96
- adjustStack = (str) ->
246
+ export getType = (str, nObjects) ->
97
247
 
98
- if (lMatches = str.match(///^
248
+ if lMatches = str.match(///^
99
249
  \s*
100
250
  enter
101
251
  \s+
102
252
  ([A-Za-z_][A-Za-z0-9_\.]*)
103
- ///))
253
+ ///)
104
254
 
105
255
  # --- We are entering function curFunc
106
- curFunc = lMatches[1]
107
-
108
- hEnv = {
109
- debugging
110
- shouldLogFunc
111
- shouldLogString
112
- }
256
+ return ['enter', lMatches[1]]
113
257
 
114
- debugging = shouldLogFunc(curFunc)
115
- if doDebugDebug
116
- trans = "#{hEnv.debugging} => #{debugging}"
117
- LOG " ENTER #{curFunc}, debugging: #{trans}"
118
- [mainPre, auxPre] = stack.doCall(curFunc, hEnv, debugging)
119
- return [
120
- mainPre
121
- auxPre
122
- undef
123
- if shouldLogFunc(curFunc) then 'enter' else undef
124
- ]
125
- else if (lMatches = str.match(///^
258
+ else if lMatches = str.match(///^
126
259
  \s*
127
260
  return
128
261
  .+
129
262
  from
130
263
  \s+
131
264
  ([A-Za-z_][A-Za-z0-9_\.]*)
132
- ///))
133
- curFunc = lMatches[1]
134
- [mainPre, auxPre, hEnv] = stack.returnFrom(curFunc)
135
- if doDebugDebug
136
- LOG " RETURN FROM #{curFunc}"
137
- return [
138
- mainPre
139
- auxPre
140
- hEnv
141
- if shouldLogFunc(curFunc) then 'return' else undef
142
- ]
143
- else
144
- [mainPre, auxPre, _] = stack.logStr()
145
- return [
146
- mainPre
147
- auxPre
148
- undef
149
- if shouldLogString(str) then 'string' else undef
150
- ]
151
-
152
- # ---------------------------------------------------------------------------
153
-
154
- export debug = (lArgs...) ->
155
-
156
- # --- We want to allow item to be undef. Therefore, we need to
157
- # distinguish between 1 arg sent vs. 2 args sent
158
- nArgs = lArgs.length
159
- assert (nArgs==1) || (nArgs==2), "debug(): #{nArgs} args"
265
+ ///)
266
+ return ['return', lMatches[1]]
160
267
 
161
- # --- label must always be there, and be a string
162
- # item is optional
163
- [label, item] = lArgs
164
- assert isString(label),
165
- "debug(): 1st arg #{OL(label)} should be a string"
166
-
167
- if doDebugDebug
168
- if nArgs==1
169
- LOG "debug('#{escapeStr(label)}') - 1 arg"
170
- else
171
- LOG "debug('#{escapeStr(label)}', #{typeof item}) - 2 args"
172
- LOG "debugging flag = #{OL(debugging)}"
173
-
174
- # --- We always need to manipulate the stack when we encounter
175
- # either "enter X" or "return from X", so we can't short-circuit
176
- # when debugging is off
177
-
178
- lResult = adjustStack(label)
179
- if doDebugDebug
180
- LOG 'lResult', lResult
181
- [mainPre, auxPre, hEnv, type] = lResult
182
- if doDebugDebug && (type == undef)
183
- LOG "type is undef - NOT LOGGING"
184
-
185
- hOptions = {
186
- prefix: mainPre
187
- itemPrefix: auxPre
188
- }
189
-
190
- switch type
191
- when 'enter'
192
- log label, hOptions
193
- if (nArgs==2)
194
- # --- don't repeat the label
195
- logItem undef, item, hOptions
196
- when 'return'
197
- log label, hOptions
198
- if (nArgs==2)
199
- # --- don't repeat the label
200
- logItem undef, item, hOptions
201
- when 'string'
202
- if (nArgs==2)
203
- logItem label, item, hOptions
204
- else
205
- log label, hOptions
206
-
207
- if hEnv
208
- orgDebugging = debugging
209
- {debugging, shouldLogFunc, shouldLogString} = hEnv
210
- if doDebugDebug
211
- trans = "#{orgDebugging} => #{debugging}"
212
- LOG " Restore hEnv: debugging: #{trans}"
213
- return true # allow use in boolean expressions
268
+ else if (nObjects > 0)
269
+ return ['objects', undef]
270
+ else
271
+ return ['string', undef]
214
272
 
215
273
  # ---------------------------------------------------------------------------
216
274