@jdeighan/coffee-utils 7.0.56 → 7.0.59

Sign up to get free protection for your applications and to get access to all the features.
package/Debugging.md ADDED
@@ -0,0 +1,6 @@
1
+ Debugging CoffeeScript:
2
+
3
+ 1. install JetBrains IntellijIDE
4
+ 2. create file test/counting.coffee
5
+ 3. compile the file with the sourcemap option:
6
+ coffee -c -m test/counting.coffee
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "7.0.56",
4
+ "version": "7.0.59",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -36,10 +36,9 @@ export class CallStack
36
36
 
37
37
  # ........................................................................
38
38
 
39
- enter: (funcName, oldFlag=undef) ->
39
+ enter: (funcName) ->
40
40
  # --- funcName might be <object>.<method>
41
41
 
42
- assert (oldFlag == undef), "enter() takes only 1 arg"
43
42
  if doDebugStack
44
43
  LOG "[--> ENTER #{funcName}]"
45
44
 
@@ -54,13 +53,13 @@ export class CallStack
54
53
  [_, ident1, ident2] = lMatches
55
54
  if ident2
56
55
  @lStack.push({
57
- fullName: "#{ident1}.#{ident2}"
56
+ fullName: funcName # "#{ident1}.#{ident2}"
58
57
  funcName: ident2
59
58
  isLogged: false
60
59
  })
61
60
  else
62
61
  @lStack.push({
63
- fullName: ident1
62
+ fullName: funcName
64
63
  funcName: ident1
65
64
  isLogged: false
66
65
  })
@@ -68,6 +67,12 @@ export class CallStack
68
67
 
69
68
  # ........................................................................
70
69
 
70
+ getLevel: () ->
71
+
72
+ return @level
73
+
74
+ # ........................................................................
75
+
71
76
  isLogging: () ->
72
77
 
73
78
  if (@lStack.length == 0)
@@ -86,12 +91,17 @@ export class CallStack
86
91
 
87
92
  # ........................................................................
88
93
 
89
- logCurFunc: () ->
94
+ logCurFunc: (funcName) ->
90
95
 
91
96
  # --- funcName must be the current function
92
97
  # and the isLogged flag must currently be false
98
+
93
99
  cur = @lStack[@lStack.length - 1]
94
100
  assert (cur.isLogged == false), "isLogged is already true"
101
+ if (funcName != cur.fullName)
102
+ LOG "cur func #{cur.fullName} is not #{funcName}"
103
+ LOG @dump()
104
+ croak "BAD"
95
105
  cur.isLogged = true
96
106
  @level += 1
97
107
  return
@@ -105,7 +115,7 @@ export class CallStack
105
115
  LOG "[<-- BACK #{fName}]"
106
116
 
107
117
  if @lStack.length == 0
108
- LOG "ERROR: returnFrom('#{funcName}') but stack is empty"
118
+ LOG "ERROR: returnFrom('#{fName}') but stack is empty"
109
119
  return
110
120
 
111
121
  {fullName, isLogged} = @lStack.pop()
@@ -126,12 +136,6 @@ export class CallStack
126
136
 
127
137
  # ........................................................................
128
138
 
129
- getLevel: () ->
130
-
131
- return @level
132
-
133
- # ........................................................................
134
-
135
139
  curFunc: () ->
136
140
 
137
141
  if (@lStack.length == 0)
@@ -151,14 +155,28 @@ export class CallStack
151
155
  return false
152
156
 
153
157
  # ........................................................................
154
- # ........................................................................
155
158
 
156
159
  dump: (prefix='', label='CALL STACK') ->
157
160
 
158
- LOG "#{label}:"
161
+ lLines = ["#{label}:"]
159
162
  if @lStack.length == 0
160
- LOG " <EMPTY>"
163
+ lLines.push " <EMPTY>"
161
164
  else
162
165
  for item, i in @lStack
163
- LOG " #{i}: #{item.fullName} #{item.isLogged}"
164
- return
166
+ lLines.push " #{i}: #{item.fullName} #{item.isLogged}"
167
+ return lLines.join("\n") + "\n"
168
+
169
+ # ........................................................................
170
+
171
+ sdump: (label='CALL STACK') ->
172
+
173
+ lFuncNames = []
174
+ for item in @lStack
175
+ if item.isLogged
176
+ lFuncNames.push '*' + item.fullName
177
+ else
178
+ lFuncNames.push item.fullName
179
+ if @lStack.length == 0
180
+ return "#{label} <EMPTY>"
181
+ else
182
+ return "#{label} #{lFuncNames.join(' ')}"
package/src/call_stack.js CHANGED
@@ -45,10 +45,9 @@ export var CallStack = class CallStack {
45
45
  }
46
46
 
47
47
  // ........................................................................
48
- enter(funcName, oldFlag = undef) {
48
+ enter(funcName) {
49
49
  var _, ident1, ident2, lMatches;
50
50
  // --- funcName might be <object>.<method>
51
- assert(oldFlag === undef, "enter() takes only 1 arg");
52
51
  if (doDebugStack) {
53
52
  LOG(`[--> ENTER ${funcName}]`);
54
53
  }
@@ -57,19 +56,24 @@ export var CallStack = class CallStack {
57
56
  [_, ident1, ident2] = lMatches;
58
57
  if (ident2) {
59
58
  this.lStack.push({
60
- fullName: `${ident1}.${ident2}`,
59
+ fullName: funcName, // "#{ident1}.#{ident2}"
61
60
  funcName: ident2,
62
61
  isLogged: false
63
62
  });
64
63
  } else {
65
64
  this.lStack.push({
66
- fullName: ident1,
65
+ fullName: funcName,
67
66
  funcName: ident1,
68
67
  isLogged: false
69
68
  });
70
69
  }
71
70
  }
72
71
 
72
+ // ........................................................................
73
+ getLevel() {
74
+ return this.level;
75
+ }
76
+
73
77
  // ........................................................................
74
78
  isLogging() {
75
79
  if (this.lStack.length === 0) {
@@ -89,12 +93,17 @@ export var CallStack = class CallStack {
89
93
  }
90
94
 
91
95
  // ........................................................................
92
- logCurFunc() {
96
+ logCurFunc(funcName) {
93
97
  var cur;
94
98
  // --- funcName must be the current function
95
99
  // and the isLogged flag must currently be false
96
100
  cur = this.lStack[this.lStack.length - 1];
97
101
  assert(cur.isLogged === false, "isLogged is already true");
102
+ if (funcName !== cur.fullName) {
103
+ LOG(`cur func ${cur.fullName} is not ${funcName}`);
104
+ LOG(this.dump());
105
+ croak("BAD");
106
+ }
98
107
  cur.isLogged = true;
99
108
  this.level += 1;
100
109
  }
@@ -107,7 +116,7 @@ export var CallStack = class CallStack {
107
116
  LOG(`[<-- BACK ${fName}]`);
108
117
  }
109
118
  if (this.lStack.length === 0) {
110
- LOG(`ERROR: returnFrom('${funcName}') but stack is empty`);
119
+ LOG(`ERROR: returnFrom('${fName}') but stack is empty`);
111
120
  return;
112
121
  }
113
122
  ({fullName, isLogged} = this.lStack.pop());
@@ -128,11 +137,6 @@ export var CallStack = class CallStack {
128
137
  }
129
138
  }
130
139
 
131
- // ........................................................................
132
- getLevel() {
133
- return this.level;
134
- }
135
-
136
140
  // ........................................................................
137
141
  curFunc() {
138
142
  if (this.lStack.length === 0) {
@@ -157,20 +161,40 @@ export var CallStack = class CallStack {
157
161
  return false;
158
162
  }
159
163
 
160
- // ........................................................................
161
164
  // ........................................................................
162
165
  dump(prefix = '', label = 'CALL STACK') {
163
- var i, item, j, len, ref;
164
- LOG(`${label}:`);
166
+ var i, item, j, lLines, len, ref;
167
+ lLines = [`${label}:`];
165
168
  if (this.lStack.length === 0) {
166
- LOG(" <EMPTY>");
169
+ lLines.push(" <EMPTY>");
167
170
  } else {
168
171
  ref = this.lStack;
169
172
  for (i = j = 0, len = ref.length; j < len; i = ++j) {
170
173
  item = ref[i];
171
- LOG(` ${i}: ${item.fullName} ${item.isLogged}`);
174
+ lLines.push(` ${i}: ${item.fullName} ${item.isLogged}`);
172
175
  }
173
176
  }
177
+ return lLines.join("\n") + "\n";
178
+ }
179
+
180
+ // ........................................................................
181
+ sdump(label = 'CALL STACK') {
182
+ var item, j, lFuncNames, len, ref;
183
+ lFuncNames = [];
184
+ ref = this.lStack;
185
+ for (j = 0, len = ref.length; j < len; j++) {
186
+ item = ref[j];
187
+ if (item.isLogged) {
188
+ lFuncNames.push('*' + item.fullName);
189
+ } else {
190
+ lFuncNames.push(item.fullName);
191
+ }
192
+ }
193
+ if (this.lStack.length === 0) {
194
+ return `${label} <EMPTY>`;
195
+ } else {
196
+ return `${label} ${lFuncNames.join(' ')}`;
197
+ }
174
198
  }
175
199
 
176
200
  };
@@ -16,11 +16,83 @@ import {
16
16
  log, logItem, LOG, shortEnough, dashes,
17
17
  } from '@jdeighan/coffee-utils/log'
18
18
 
19
- callStack = new CallStack()
19
+ # --- set in resetDebugging() and setDebugging()
20
+ export callStack = new CallStack()
21
+ export shouldLog = () -> undef
22
+
23
+ lFuncList = []
24
+ strFuncList = undef # original string
25
+
26
+ # --- internal debugging
20
27
  doDebugDebug = false
28
+ lFunctions = undef # --- only used when doDebugDebug is true
29
+
30
+ # ---------------------------------------------------------------------------
31
+
32
+ export dumpCallStack = (label) ->
33
+
34
+ LOG callStack.dump('', label)
35
+ return
36
+
37
+ # ---------------------------------------------------------------------------
38
+
39
+ export setDebugDebugging = (value=true) ->
40
+ # --- value can be a boolean or string of words
41
+
42
+ if isBoolean(value)
43
+ doDebugDebug = value
44
+ else if isString(value)
45
+ doDebugDebug = true
46
+ lFunctions = words(value)
47
+ else
48
+ croak "Bad value: #{OL(value)}"
49
+ return
50
+
51
+ # ---------------------------------------------------------------------------
52
+
53
+ debugDebug = (label, lObjects...) ->
54
+ # --- For debugging functions in this module
55
+
56
+ if ! doDebugDebug
57
+ return
58
+
59
+ # --- At this point, doDebugDebug is true
60
+ doDebugDebug = false # temp - reset before returning
61
+
62
+ assert isString(label), "1st arg #{OL(label)} should be a string"
63
+ nObjects = lObjects.length
64
+ [type, funcName] = getType(label, nObjects)
65
+
66
+ switch type
67
+ when 'enter'
68
+ assert defined(funcName), "type enter, funcName = undef"
69
+ callStack.enter funcName
70
+ doLog = (lFunctions == undef) || (funcName in lFunctions)
71
+
72
+ when 'return'
73
+ assert defined(funcName), "type return, funcName = undef"
74
+ doLog = (lFunctions == undef) || (funcName in lFunctions)
75
+
76
+ when 'string'
77
+ assert (funcName == undef), "type string, funcName defined"
78
+ assert (nObjects == 0), "Objects not allowed for #{OL(type)}"
79
+ doLog = true
21
80
 
22
- export shouldLog = undef # set in resetDebugging() and setDebugging()
23
- export lFuncList = []
81
+ when 'objects'
82
+ assert (funcName == undef), "type objects, funcName defined"
83
+ assert (nObjects > 0), "Objects required for #{OL(type)}"
84
+ dolog = true
85
+
86
+ if doLog
87
+ doTheLogging type, label, lObjects
88
+
89
+ if (type == 'enter') && doLog
90
+ callStack.logCurFunc(funcName)
91
+ else if (type == 'return')
92
+ callStack.returnFrom funcName
93
+
94
+ doDebugDebug = true
95
+ return
24
96
 
25
97
  # ---------------------------------------------------------------------------
26
98
 
@@ -28,87 +100,98 @@ export debug = (label, lObjects...) ->
28
100
 
29
101
  assert isString(label), "1st arg #{OL(label)} should be a string"
30
102
 
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
103
+ # --- If label is "enter <funcname>, we need to put that on the stack
104
+ # BEFORE we do any internal logging
33
105
  nObjects = lObjects.length
34
-
35
- # --- funcName is only set for types 'enter' and 'return'
36
106
  [type, funcName] = getType(label, nObjects)
37
- if doDebugDebug
38
- LOG "debug(): type = #{OL(type)}"
39
- LOG "debug(): funcName = #{OL(funcName)}"
107
+ if (type == 'enter')
108
+ callStack.enter funcName
109
+
110
+ debugDebug "enter debug(#{OL(label)})", lObjects...
111
+ debugDebug "type = #{OL(type)}"
112
+ debugDebug "funcName = #{OL(funcName)}"
40
113
 
41
114
  # --- function shouldLog() returns the (possibly modified) label
42
115
  # if we should log this, else it returns undef
43
116
 
44
117
  switch type
45
118
  when 'enter'
46
- callStack.enter funcName
47
119
  label = shouldLog(label, type, funcName, callStack)
48
120
  when 'return'
49
121
  label = shouldLog(label, type, funcName, callStack)
50
122
  when 'string'
51
123
  label = shouldLog(label, type, undef, callStack)
52
124
  assert (nObjects == 0),
53
- "multiple objects only not allowed for #{OL(type)}"
125
+ "Objects not allowed for #{OL(type)}"
54
126
  when 'objects'
55
127
  label = shouldLog(label, type, undef, callStack)
56
128
  assert (nObjects > 0),
57
- "multiple objects only not allowed for #{OL(type)}"
58
- doLog = defined(label)
129
+ "Objects required for #{OL(type)}"
59
130
 
60
- if doDebugDebug
61
- if nObjects == 0
62
- LOG "debug(#{OL(label)}) - 1 arg"
63
- else
64
- LOG "debug(#{OL(label)}), #{nObjects} args"
65
- LOG "doLog = #{OL(doLog)}"
131
+ assert (label == undef) || isString(label),
132
+ "label not a string: #{OL(label)}"
133
+ doLog = defined(label)
134
+ debugDebug "doLog = #{OL(doLog)}"
135
+ debugDebug "#{nObjects} objects"
66
136
 
67
137
  if doLog
68
- level = callStack.getLevel()
69
- prefix = getPrefix(level)
70
- itemPrefix = removeLastVbar(prefix)
71
-
72
- if doDebugDebug
73
- LOG "callStack", callStack
74
- LOG "level = #{OL(level)}"
75
- LOG "prefix = #{OL(prefix)}"
76
- LOG "itemPrefix = #{OL(itemPrefix)}"
77
-
78
- switch type
79
- when 'enter'
80
- log label, {prefix}
81
- for obj,i in lObjects
82
- if (i > 0)
83
- log dashes(itemPrefix, 40)
84
- logItem undef, obj, {itemPrefix}
85
- when 'return'
86
- log label, {prefix: addArrow(prefix)}
87
- for obj,i in lObjects
88
- if (i > 0)
89
- log dashes(itemPrefix, 40)
90
- logItem undef, obj, {itemPrefix}
91
- when 'string'
92
- log label, {prefix}
93
- when 'objects'
94
- if (nObjects==1) && shortEnough(label, lObjects[0])
95
- logItem label, lObjects[0], {prefix}
96
- else
97
- if (label.indexOf(':') != label.length - 1)
98
- label += ':'
99
- log label, {prefix}
100
- for obj in lObjects
101
- logItem undef, obj, {prefix}
138
+ doTheLogging type, label, lObjects
102
139
 
103
140
  if (type == 'enter') && doLog && (label.indexOf('call') == -1)
104
- callStack.logCurFunc()
105
- else if (type == 'return')
141
+ callStack.logCurFunc(funcName)
142
+
143
+ # --- This must be called BEFORE we return from funcName
144
+ debugDebug "return from debug()"
145
+
146
+ if (type == 'return')
106
147
  callStack.returnFrom funcName
107
148
 
108
149
  return true # allow use in boolean expressions
109
150
 
110
151
  # ---------------------------------------------------------------------------
111
152
 
153
+ export doTheLogging = (type, label, lObjects) ->
154
+
155
+ level = callStack.getLevel()
156
+ prefix = getPrefix(level)
157
+ itemPrefix = removeLastVbar(prefix)
158
+ sep = dashes(itemPrefix, 40)
159
+ assert isString(sep), "sep is not a string"
160
+
161
+ debugDebug "callStack", callStack
162
+ debugDebug "level = #{OL(level)}"
163
+ debugDebug "prefix = #{OL(prefix)}"
164
+ debugDebug "itemPrefix = #{OL(itemPrefix)}"
165
+ debugDebug "sep = #{OL(sep)}"
166
+
167
+ switch type
168
+ when 'enter'
169
+ log label, {prefix}
170
+ for obj,i in lObjects
171
+ if (i > 0)
172
+ log sep
173
+ logItem undef, obj, {itemPrefix}
174
+ when 'return'
175
+ log label, {prefix: addArrow(prefix)}
176
+ for obj,i in lObjects
177
+ if (i > 0)
178
+ log sep
179
+ logItem undef, obj, {itemPrefix}
180
+ when 'string'
181
+ log label, {prefix}
182
+ when 'objects'
183
+ if (lObjects.length==1) && shortEnough(label, lObjects[0])
184
+ logItem label, lObjects[0], {prefix}
185
+ else
186
+ if (label.indexOf(':') != label.length - 1)
187
+ label += ':'
188
+ log label, {prefix}
189
+ for obj in lObjects
190
+ logItem undef, obj, {prefix}
191
+ return
192
+
193
+ # ---------------------------------------------------------------------------
194
+
112
195
  export stdShouldLog = (label, type, funcName, stack) ->
113
196
  # --- if type is 'enter', then funcName won't be on the stack yet
114
197
  # returns the (possibly modified) label to log
@@ -125,14 +208,12 @@ export stdShouldLog = (label, type, funcName, stack) ->
125
208
  assert funcName == undef, "func name #{OL(funcName)} not undef"
126
209
  assert stack instanceof CallStack, "not a call stack object"
127
210
 
128
- if doDebugDebug
129
- LOG "stdShouldLog(#{OL(label)}, #{OL(type)}, #{OL(funcName)}, stack)"
130
- LOG "stack", stack
131
- LOG "lFuncList", lFuncList
211
+ debugDebug "enter stdShouldLog(#{OL(label)}, #{OL(type)}, #{OL(funcName)}, stack)"
132
212
 
133
213
  switch type
134
214
  when 'enter'
135
- if funcMatch(stack, lFuncList)
215
+ if funcMatch()
216
+ debugDebug "return #{OL(label)} from stdShouldLog() - funcMatch"
136
217
  return label
137
218
 
138
219
  else
@@ -142,53 +223,31 @@ export stdShouldLog = (label, type, funcName, stack) ->
142
223
 
143
224
  prevLogged = stack.isLoggingPrev()
144
225
  if prevLogged
145
- return label.replace('enter', 'call')
226
+ result = label.replace('enter', 'call')
227
+ debugDebug "return #{OL(result)} from stdShouldLog() - s/enter/call/"
228
+ return result
146
229
  else
147
- if funcMatch(stack, lFuncList)
230
+ if funcMatch()
231
+ debugDebug "return #{OL(label)} from stdShouldLog()"
148
232
  return label
233
+ debugDebug "return undef from stdShouldLog()"
149
234
  return undef
150
235
 
151
236
  # ---------------------------------------------------------------------------
152
237
 
153
- export debugDebug = (flag=true) ->
154
-
155
- doDebugDebug = flag
156
- if doDebugDebug
157
- LOG "doDebugDebug = #{flag}"
158
- return
159
-
160
- # ---------------------------------------------------------------------------
161
-
162
- resetDebugging = () ->
163
-
164
- if doDebugDebug
165
- LOG "resetDebugging()"
166
- callStack.reset()
167
- shouldLog = (label, type, funcName, stack) -> undef
168
- return
169
-
170
- # ---------------------------------------------------------------------------
171
-
172
238
  export setDebugging = (option) ->
173
239
 
174
- resetDebugging()
240
+ callStack.reset()
175
241
  if isBoolean(option)
176
242
  if option
177
243
  shouldLog = (label, type, funcName, stack) -> label
178
244
  else
179
245
  shouldLog = (label, type, funcName, stack) -> undef
180
- if doDebugDebug
181
- LOG "setDebugging = #{option}"
182
246
  else if isString(option)
183
247
  lFuncList = getFuncList(option)
184
248
  shouldLog = stdShouldLog
185
- if doDebugDebug
186
- LOG "setDebugging FUNCS: #{option}"
187
- LOG 'lFuncList', lFuncList
188
249
  else if isFunction(option)
189
250
  shouldLog = option
190
- if doDebugDebug
191
- LOG "setDebugging to custom func"
192
251
  else
193
252
  croak "bad parameter #{OL(option)}"
194
253
  return
@@ -198,6 +257,7 @@ export setDebugging = (option) ->
198
257
 
199
258
  export getFuncList = (str) ->
200
259
 
260
+ strFuncList = str # store original string for debugging
201
261
  lFuncList = []
202
262
  for word in words(str)
203
263
  if lMatches = word.match(///^
@@ -227,27 +287,23 @@ export getFuncList = (str) ->
227
287
  # ---------------------------------------------------------------------------
228
288
  # --- export only to allow unit tests
229
289
 
230
- export funcMatch = (stack, lFuncList) ->
290
+ export funcMatch = () ->
231
291
 
232
292
  assert isArray(lFuncList), "not an array #{OL(lFuncList)}"
233
293
 
234
- curFunc = stack.curFunc()
235
- if doDebugDebug
236
- LOG "funcMatch(): curFunc = #{OL(curFunc)}"
237
- stack.dump(' ')
238
- LOG 'lFuncList', lFuncList
294
+ debugDebug "enter funcMatch()"
295
+ curFunc = callStack.curFunc()
296
+ debugDebug "curFunc = #{OL(curFunc)}"
297
+ debugDebug "lFuncList = #{strFuncList}"
239
298
  for h in lFuncList
240
299
  {name, object, plus} = h
241
300
  if (name == curFunc)
242
- if doDebugDebug
243
- LOG " curFunc in lFuncList - match successful"
301
+ debugDebug "return from funcMatch() - curFunc in lFuncList"
244
302
  return true
245
- if plus && stack.isActive(name)
246
- if doDebugDebug
247
- LOG " func #{OL(name)} is active - match successful"
303
+ if plus && callStack.isActive(name)
304
+ debugDebug "return from funcMatch() - func #{OL(name)} is active"
248
305
  return true
249
- if doDebugDebug
250
- LOG " - no match"
306
+ debugDebug "return from funcMatch() - no match"
251
307
  return false
252
308
 
253
309
  # ---------------------------------------------------------------------------
@@ -290,40 +346,3 @@ reMethod = ///^
290
346
 
291
347
  # ---------------------------------------------------------------------------
292
348
 
293
- export checkTrace = (block) ->
294
- # --- export only to allow unit tests
295
-
296
- lStack = []
297
-
298
- for line in blockToArray(block)
299
- if lMatches = line.match(///
300
- enter
301
- \s+
302
- ([A-Za-z_][A-Za-z0-9_\.]*)
303
- ///)
304
- funcName = lMatches[1]
305
- lStack.push funcName
306
- else if lMatches = line.match(///
307
- return
308
- .*
309
- from
310
- \s+
311
- ([A-Za-z_][A-Za-z0-9_\.]*)
312
- ///)
313
- funcName = lMatches[1]
314
- len = lStack.length
315
- if (len == 0)
316
- log "return from #{funcName} with empty stack"
317
- else if (lStack[len-1] == funcName)
318
- lStack.pop()
319
- else if (lStack[len-2] == funcName)
320
- log "missing return from #{lStack[len-2]}"
321
- lStack.pop()
322
- lStack.pop()
323
- else
324
- log "return from #{funcName} - not found on stack"
325
- return
326
-
327
- # ---------------------------------------------------------------------------
328
-
329
- resetDebugging()
@@ -1,6 +1,7 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
- // debug_utils.coffee
3
- var callStack, doDebugDebug, reMethod, resetDebugging;
2
+ // debug_utils.coffee
3
+ var debugDebug, doDebugDebug, lFuncList, lFunctions, reMethod, strFuncList,
4
+ indexOf = [].indexOf;
4
5
 
5
6
  import {
6
7
  assert,
@@ -50,32 +51,102 @@ import {
50
51
  dashes
51
52
  } from '@jdeighan/coffee-utils/log';
52
53
 
53
- callStack = new CallStack();
54
+ // --- set in resetDebugging() and setDebugging()
55
+ export var callStack = new CallStack();
54
56
 
57
+ export var shouldLog = function() {
58
+ return undef;
59
+ };
60
+
61
+ lFuncList = [];
62
+
63
+ strFuncList = undef; // original string
64
+
65
+
66
+ // --- internal debugging
55
67
  doDebugDebug = false;
56
68
 
57
- export var shouldLog = undef; // set in resetDebugging() and setDebugging()
69
+ lFunctions = undef; // --- only used when doDebugDebug is true
70
+
71
+
72
+ // ---------------------------------------------------------------------------
73
+ export var dumpCallStack = function(label) {
74
+ LOG(callStack.dump('', label));
75
+ };
76
+
77
+ // ---------------------------------------------------------------------------
78
+ export var setDebugDebugging = function(value = true) {
79
+ // --- value can be a boolean or string of words
80
+ if (isBoolean(value)) {
81
+ doDebugDebug = value;
82
+ } else if (isString(value)) {
83
+ doDebugDebug = true;
84
+ lFunctions = words(value);
85
+ } else {
86
+ croak(`Bad value: ${OL(value)}`);
87
+ }
88
+ };
58
89
 
59
- export var lFuncList = [];
90
+ // ---------------------------------------------------------------------------
91
+ debugDebug = function(label, ...lObjects) {
92
+ var doLog, dolog, funcName, nObjects, type;
93
+ if (!doDebugDebug) {
94
+ return;
95
+ }
96
+ // --- At this point, doDebugDebug is true
97
+ doDebugDebug = false; // temp - reset before returning
98
+ assert(isString(label), `1st arg ${OL(label)} should be a string`);
99
+ nObjects = lObjects.length;
100
+ [type, funcName] = getType(label, nObjects);
101
+ switch (type) {
102
+ case 'enter':
103
+ assert(defined(funcName), "type enter, funcName = undef");
104
+ callStack.enter(funcName);
105
+ doLog = (lFunctions === undef) || (indexOf.call(lFunctions, funcName) >= 0);
106
+ break;
107
+ case 'return':
108
+ assert(defined(funcName), "type return, funcName = undef");
109
+ doLog = (lFunctions === undef) || (indexOf.call(lFunctions, funcName) >= 0);
110
+ break;
111
+ case 'string':
112
+ assert(funcName === undef, "type string, funcName defined");
113
+ assert(nObjects === 0, `Objects not allowed for ${OL(type)}`);
114
+ doLog = true;
115
+ break;
116
+ case 'objects':
117
+ assert(funcName === undef, "type objects, funcName defined");
118
+ assert(nObjects > 0, `Objects required for ${OL(type)}`);
119
+ dolog = true;
120
+ }
121
+ if (doLog) {
122
+ doTheLogging(type, label, lObjects);
123
+ }
124
+ if ((type === 'enter') && doLog) {
125
+ callStack.logCurFunc(funcName);
126
+ } else if (type === 'return') {
127
+ callStack.returnFrom(funcName);
128
+ }
129
+ doDebugDebug = true;
130
+ };
60
131
 
61
132
  // ---------------------------------------------------------------------------
62
133
  export var debug = function(label, ...lObjects) {
63
- var doLog, funcName, i, itemPrefix, j, k, l, len1, len2, len3, level, nObjects, obj, prefix, type;
134
+ var doLog, funcName, nObjects, type;
64
135
  assert(isString(label), `1st arg ${OL(label)} should be a string`);
65
- // --- We want to allow objects to be undef. Therefore, we need to
66
- // distinguish between 1 arg sent vs. 2 or more args sent
136
+ // --- If label is "enter <funcname>, we need to put that on the stack
137
+ // BEFORE we do any internal logging
67
138
  nObjects = lObjects.length;
68
- // --- funcName is only set for types 'enter' and 'return'
69
139
  [type, funcName] = getType(label, nObjects);
70
- if (doDebugDebug) {
71
- LOG(`debug(): type = ${OL(type)}`);
72
- LOG(`debug(): funcName = ${OL(funcName)}`);
140
+ if (type === 'enter') {
141
+ callStack.enter(funcName);
73
142
  }
143
+ debugDebug(`enter debug(${OL(label)})`, ...lObjects);
144
+ debugDebug(`type = ${OL(type)}`);
145
+ debugDebug(`funcName = ${OL(funcName)}`);
74
146
  // --- function shouldLog() returns the (possibly modified) label
75
147
  // if we should log this, else it returns undef
76
148
  switch (type) {
77
149
  case 'enter':
78
- callStack.enter(funcName);
79
150
  label = shouldLog(label, type, funcName, callStack);
80
151
  break;
81
152
  case 'return':
@@ -83,84 +154,89 @@ export var debug = function(label, ...lObjects) {
83
154
  break;
84
155
  case 'string':
85
156
  label = shouldLog(label, type, undef, callStack);
86
- assert(nObjects === 0, `multiple objects only not allowed for ${OL(type)}`);
157
+ assert(nObjects === 0, `Objects not allowed for ${OL(type)}`);
87
158
  break;
88
159
  case 'objects':
89
160
  label = shouldLog(label, type, undef, callStack);
90
- assert(nObjects > 0, `multiple objects only not allowed for ${OL(type)}`);
161
+ assert(nObjects > 0, `Objects required for ${OL(type)}`);
91
162
  }
163
+ assert((label === undef) || isString(label), `label not a string: ${OL(label)}`);
92
164
  doLog = defined(label);
93
- if (doDebugDebug) {
94
- if (nObjects === 0) {
95
- LOG(`debug(${OL(label)}) - 1 arg`);
96
- } else {
97
- LOG(`debug(${OL(label)}), ${nObjects} args`);
98
- }
99
- LOG(`doLog = ${OL(doLog)}`);
100
- }
165
+ debugDebug(`doLog = ${OL(doLog)}`);
166
+ debugDebug(`${nObjects} objects`);
101
167
  if (doLog) {
102
- level = callStack.getLevel();
103
- prefix = getPrefix(level);
104
- itemPrefix = removeLastVbar(prefix);
105
- if (doDebugDebug) {
106
- LOG("callStack", callStack);
107
- LOG(`level = ${OL(level)}`);
108
- LOG(`prefix = ${OL(prefix)}`);
109
- LOG(`itemPrefix = ${OL(itemPrefix)}`);
110
- }
111
- switch (type) {
112
- case 'enter':
113
- log(label, {prefix});
114
- for (i = j = 0, len1 = lObjects.length; j < len1; i = ++j) {
115
- obj = lObjects[i];
116
- if (i > 0) {
117
- log(dashes(itemPrefix, 40));
118
- }
119
- logItem(undef, obj, {itemPrefix});
120
- }
121
- break;
122
- case 'return':
123
- log(label, {
124
- prefix: addArrow(prefix)
125
- });
126
- for (i = k = 0, len2 = lObjects.length; k < len2; i = ++k) {
127
- obj = lObjects[i];
128
- if (i > 0) {
129
- log(dashes(itemPrefix, 40));
130
- }
131
- logItem(undef, obj, {itemPrefix});
132
- }
133
- break;
134
- case 'string':
135
- log(label, {prefix});
136
- break;
137
- case 'objects':
138
- if ((nObjects === 1) && shortEnough(label, lObjects[0])) {
139
- logItem(label, lObjects[0], {prefix});
140
- } else {
141
- if (label.indexOf(':') !== label.length - 1) {
142
- label += ':';
143
- }
144
- log(label, {prefix});
145
- for (l = 0, len3 = lObjects.length; l < len3; l++) {
146
- obj = lObjects[l];
147
- logItem(undef, obj, {prefix});
148
- }
149
- }
150
- }
168
+ doTheLogging(type, label, lObjects);
151
169
  }
152
170
  if ((type === 'enter') && doLog && (label.indexOf('call') === -1)) {
153
- callStack.logCurFunc();
154
- } else if (type === 'return') {
171
+ callStack.logCurFunc(funcName);
172
+ }
173
+ // --- This must be called BEFORE we return from funcName
174
+ debugDebug("return from debug()");
175
+ if (type === 'return') {
155
176
  callStack.returnFrom(funcName);
156
177
  }
157
178
  return true; // allow use in boolean expressions
158
179
  };
159
180
 
160
181
 
182
+ // ---------------------------------------------------------------------------
183
+ export var doTheLogging = function(type, label, lObjects) {
184
+ var i, itemPrefix, j, k, l, len, len1, len2, level, obj, prefix, sep;
185
+ level = callStack.getLevel();
186
+ prefix = getPrefix(level);
187
+ itemPrefix = removeLastVbar(prefix);
188
+ sep = dashes(itemPrefix, 40);
189
+ assert(isString(sep), "sep is not a string");
190
+ debugDebug("callStack", callStack);
191
+ debugDebug(`level = ${OL(level)}`);
192
+ debugDebug(`prefix = ${OL(prefix)}`);
193
+ debugDebug(`itemPrefix = ${OL(itemPrefix)}`);
194
+ debugDebug(`sep = ${OL(sep)}`);
195
+ switch (type) {
196
+ case 'enter':
197
+ log(label, {prefix});
198
+ for (i = j = 0, len = lObjects.length; j < len; i = ++j) {
199
+ obj = lObjects[i];
200
+ if (i > 0) {
201
+ log(sep);
202
+ }
203
+ logItem(undef, obj, {itemPrefix});
204
+ }
205
+ break;
206
+ case 'return':
207
+ log(label, {
208
+ prefix: addArrow(prefix)
209
+ });
210
+ for (i = k = 0, len1 = lObjects.length; k < len1; i = ++k) {
211
+ obj = lObjects[i];
212
+ if (i > 0) {
213
+ log(sep);
214
+ }
215
+ logItem(undef, obj, {itemPrefix});
216
+ }
217
+ break;
218
+ case 'string':
219
+ log(label, {prefix});
220
+ break;
221
+ case 'objects':
222
+ if ((lObjects.length === 1) && shortEnough(label, lObjects[0])) {
223
+ logItem(label, lObjects[0], {prefix});
224
+ } else {
225
+ if (label.indexOf(':') !== label.length - 1) {
226
+ label += ':';
227
+ }
228
+ log(label, {prefix});
229
+ for (l = 0, len2 = lObjects.length; l < len2; l++) {
230
+ obj = lObjects[l];
231
+ logItem(undef, obj, {prefix});
232
+ }
233
+ }
234
+ }
235
+ };
236
+
161
237
  // ---------------------------------------------------------------------------
162
238
  export var stdShouldLog = function(label, type, funcName, stack) {
163
- var prevLogged;
239
+ var prevLogged, result;
164
240
  // --- if type is 'enter', then funcName won't be on the stack yet
165
241
  // returns the (possibly modified) label to log
166
242
 
@@ -175,14 +251,11 @@ export var stdShouldLog = function(label, type, funcName, stack) {
175
251
  assert(funcName === undef, `func name ${OL(funcName)} not undef`);
176
252
  }
177
253
  assert(stack instanceof CallStack, "not a call stack object");
178
- if (doDebugDebug) {
179
- LOG(`stdShouldLog(${OL(label)}, ${OL(type)}, ${OL(funcName)}, stack)`);
180
- LOG("stack", stack);
181
- LOG("lFuncList", lFuncList);
182
- }
254
+ debugDebug(`enter stdShouldLog(${OL(label)}, ${OL(type)}, ${OL(funcName)}, stack)`);
183
255
  switch (type) {
184
256
  case 'enter':
185
- if (funcMatch(stack, lFuncList)) {
257
+ if (funcMatch()) {
258
+ debugDebug(`return ${OL(label)} from stdShouldLog() - funcMatch`);
186
259
  return label;
187
260
  } else {
188
261
  // --- As a special case, if we enter a function where we will not
@@ -190,40 +263,25 @@ export var stdShouldLog = function(label, type, funcName, stack) {
190
263
  // we'll log out the call itself
191
264
  prevLogged = stack.isLoggingPrev();
192
265
  if (prevLogged) {
193
- return label.replace('enter', 'call');
266
+ result = label.replace('enter', 'call');
267
+ debugDebug(`return ${OL(result)} from stdShouldLog() - s/enter/call/`);
268
+ return result;
194
269
  }
195
270
  }
196
271
  break;
197
272
  default:
198
- if (funcMatch(stack, lFuncList)) {
273
+ if (funcMatch()) {
274
+ debugDebug(`return ${OL(label)} from stdShouldLog()`);
199
275
  return label;
200
276
  }
201
277
  }
278
+ debugDebug("return undef from stdShouldLog()");
202
279
  return undef;
203
280
  };
204
281
 
205
- // ---------------------------------------------------------------------------
206
- export var debugDebug = function(flag = true) {
207
- doDebugDebug = flag;
208
- if (doDebugDebug) {
209
- LOG(`doDebugDebug = ${flag}`);
210
- }
211
- };
212
-
213
- // ---------------------------------------------------------------------------
214
- resetDebugging = function() {
215
- if (doDebugDebug) {
216
- LOG("resetDebugging()");
217
- }
218
- callStack.reset();
219
- shouldLog = function(label, type, funcName, stack) {
220
- return undef;
221
- };
222
- };
223
-
224
282
  // ---------------------------------------------------------------------------
225
283
  export var setDebugging = function(option) {
226
- resetDebugging();
284
+ callStack.reset();
227
285
  if (isBoolean(option)) {
228
286
  if (option) {
229
287
  shouldLog = function(label, type, funcName, stack) {
@@ -234,21 +292,11 @@ export var setDebugging = function(option) {
234
292
  return undef;
235
293
  };
236
294
  }
237
- if (doDebugDebug) {
238
- LOG(`setDebugging = ${option}`);
239
- }
240
295
  } else if (isString(option)) {
241
296
  lFuncList = getFuncList(option);
242
297
  shouldLog = stdShouldLog;
243
- if (doDebugDebug) {
244
- LOG(`setDebugging FUNCS: ${option}`);
245
- LOG('lFuncList', lFuncList);
246
- }
247
298
  } else if (isFunction(option)) {
248
299
  shouldLog = option;
249
- if (doDebugDebug) {
250
- LOG("setDebugging to custom func");
251
- }
252
300
  } else {
253
301
  croak(`bad parameter ${OL(option)}`);
254
302
  }
@@ -257,10 +305,11 @@ export var setDebugging = function(option) {
257
305
  // ---------------------------------------------------------------------------
258
306
  // --- export only to allow unit tests
259
307
  export var getFuncList = function(str) {
260
- var _, ident1, ident2, j, lMatches, len1, plus, ref, word;
308
+ var _, ident1, ident2, j, lMatches, len, plus, ref, word;
309
+ strFuncList = str; // store original string for debugging
261
310
  lFuncList = [];
262
311
  ref = words(str);
263
- for (j = 0, len1 = ref.length; j < len1; j++) {
312
+ for (j = 0, len = ref.length; j < len; j++) {
264
313
  word = ref[j];
265
314
  if (lMatches = word.match(/^([A-Za-z_][A-Za-z0-9_]*)(?:\.([A-Za-z_][A-Za-z0-9_]*))?(\+)?$/)) {
266
315
  [_, ident1, ident2, plus] = lMatches;
@@ -285,34 +334,26 @@ export var getFuncList = function(str) {
285
334
 
286
335
  // ---------------------------------------------------------------------------
287
336
  // --- export only to allow unit tests
288
- export var funcMatch = function(stack, lFuncList) {
289
- var curFunc, h, j, len1, name, object, plus;
337
+ export var funcMatch = function() {
338
+ var curFunc, h, j, len, name, object, plus;
290
339
  assert(isArray(lFuncList), `not an array ${OL(lFuncList)}`);
291
- curFunc = stack.curFunc();
292
- if (doDebugDebug) {
293
- LOG(`funcMatch(): curFunc = ${OL(curFunc)}`);
294
- stack.dump(' ');
295
- LOG('lFuncList', lFuncList);
296
- }
297
- for (j = 0, len1 = lFuncList.length; j < len1; j++) {
340
+ debugDebug("enter funcMatch()");
341
+ curFunc = callStack.curFunc();
342
+ debugDebug(`curFunc = ${OL(curFunc)}`);
343
+ debugDebug(`lFuncList = ${strFuncList}`);
344
+ for (j = 0, len = lFuncList.length; j < len; j++) {
298
345
  h = lFuncList[j];
299
346
  ({name, object, plus} = h);
300
347
  if (name === curFunc) {
301
- if (doDebugDebug) {
302
- LOG(" curFunc in lFuncList - match successful");
303
- }
348
+ debugDebug("return from funcMatch() - curFunc in lFuncList");
304
349
  return true;
305
350
  }
306
- if (plus && stack.isActive(name)) {
307
- if (doDebugDebug) {
308
- LOG(` func ${OL(name)} is active - match successful`);
309
- }
351
+ if (plus && callStack.isActive(name)) {
352
+ debugDebug(`return from funcMatch() - func ${OL(name)} is active`);
310
353
  return true;
311
354
  }
312
355
  }
313
- if (doDebugDebug) {
314
- LOG(" - no match");
315
- }
356
+ debugDebug("return from funcMatch() - no match");
316
357
  return false;
317
358
  };
318
359
 
@@ -336,33 +377,3 @@ export var getType = function(str, nObjects) {
336
377
  reMethod = /^([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)$/;
337
378
 
338
379
  // ---------------------------------------------------------------------------
339
- export var checkTrace = function(block) {
340
- var funcName, j, lMatches, lStack, len, len1, line, ref;
341
- // --- export only to allow unit tests
342
- lStack = [];
343
- ref = blockToArray(block);
344
- for (j = 0, len1 = ref.length; j < len1; j++) {
345
- line = ref[j];
346
- if (lMatches = line.match(/enter\s+([A-Za-z_][A-Za-z0-9_\.]*)/)) {
347
- funcName = lMatches[1];
348
- lStack.push(funcName);
349
- } else if (lMatches = line.match(/return.*from\s+([A-Za-z_][A-Za-z0-9_\.]*)/)) {
350
- funcName = lMatches[1];
351
- len = lStack.length;
352
- if (len === 0) {
353
- log(`return from ${funcName} with empty stack`);
354
- } else if (lStack[len - 1] === funcName) {
355
- lStack.pop();
356
- } else if (lStack[len - 2] === funcName) {
357
- log(`missing return from ${lStack[len - 2]}`);
358
- lStack.pop();
359
- lStack.pop();
360
- } else {
361
- log(`return from ${funcName} - not found on stack`);
362
- }
363
- }
364
- }
365
- };
366
-
367
- // ---------------------------------------------------------------------------
368
- resetDebugging();
@@ -135,9 +135,9 @@ export log = (str, hOptions={}) ->
135
135
  # --- valid options:
136
136
  # prefix
137
137
 
138
+ assert isString(str), "log(): not a string: #{OL(str)}"
138
139
  assert isFunction(putstr), "putstr not properly set"
139
- assert isString(str), "log(): not a string"
140
- assert isHash(hOptions), "log(): arg 2 not a hash"
140
+ assert isHash(hOptions), "log(): arg 2 not a hash: #{OL(hOptions)}"
141
141
  prefix = fixForTerminal(hOptions.prefix)
142
142
 
143
143
  if doDebugLog
package/src/log_utils.js CHANGED
@@ -158,9 +158,9 @@ export var log = function(str, hOptions = {}) {
158
158
  var prefix;
159
159
  // --- valid options:
160
160
  // prefix
161
+ assert(isString(str), `log(): not a string: ${OL(str)}`);
161
162
  assert(isFunction(putstr), "putstr not properly set");
162
- assert(isString(str), "log(): not a string");
163
- assert(isHash(hOptions), "log(): arg 2 not a hash");
163
+ assert(isHash(hOptions), `log(): arg 2 not a hash: ${OL(hOptions)}`);
164
164
  prefix = fixForTerminal(hOptions.prefix);
165
165
  if (doDebugLog) {
166
166
  LOG(`CALL log(${OL(str)}), prefix = ${OL(prefix)}`);