@jdeighan/coffee-utils 7.0.49 → 7.0.52

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "7.0.49",
4
+ "version": "7.0.52",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -52,6 +52,6 @@
52
52
  "svelte": "^3.48.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@jdeighan/unit-tester": "^2.0.3"
55
+ "@jdeighan/unit-tester": "^2.0.5"
56
56
  }
57
57
  }
package/src/arrow.coffee CHANGED
@@ -1,5 +1,9 @@
1
1
  # arrow.coffee
2
2
 
3
+ import {undef, OL, setCharsAt} from '@jdeighan/coffee-utils'
4
+
5
+ # --- We use spaces here because Windows Terminal handles TAB chars badly
6
+
3
7
  export vbar = '│' # unicode 2502
4
8
  export hbar = '─' # unicode 2500
5
9
  export corner = '└' # unicode 2514
@@ -8,18 +12,22 @@ export space = ' '
8
12
 
9
13
  export oneIndent = vbar + space + space + space
10
14
  export arrow = corner + hbar + arrowhead + space
11
- export fourSpaces = space + space + space + space
15
+ export clearIndent = space + space + space + space
12
16
 
13
17
  # ---------------------------------------------------------------------------
14
18
 
15
19
  export getPrefix = (level, option='none') ->
16
20
 
17
- if level==0 then return ''
21
+ if level==0
22
+ if (option == 'object')
23
+ return clearIndent
24
+ else
25
+ return ''
18
26
  switch option
19
27
  when 'withArrow'
20
28
  result = oneIndent.repeat(level-1) + arrow
21
- when 'returnVal'
22
- result = oneIndent.repeat(level-1) + fourSpaces
29
+ when 'object'
30
+ result = oneIndent.repeat(level) + clearIndent
23
31
  when 'none'
24
32
  result = oneIndent.repeat(level)
25
33
  else
@@ -27,3 +35,31 @@ export getPrefix = (level, option='none') ->
27
35
  if result.length % 4 != 0
28
36
  throw new Error("getPrefix(): Bad prefix '#{result}'")
29
37
  return result
38
+
39
+ # ---------------------------------------------------------------------------
40
+
41
+ export addArrow = (prefix) ->
42
+
43
+ # console.log "in addArrow(#{OL(prefix)})"
44
+ pos = prefix.lastIndexOf(vbar)
45
+ # console.log "pos = #{pos}"
46
+ if (pos == -1)
47
+ result = prefix
48
+ else
49
+ result = setCharsAt(prefix, pos, arrow)
50
+ # console.log "result = #{OL(result)}"
51
+ return result
52
+
53
+ # ---------------------------------------------------------------------------
54
+
55
+ export removeLastVbar = (prefix) ->
56
+
57
+ # console.log "in removeLastVbar(#{OL(prefix)})"
58
+ pos = prefix.lastIndexOf(vbar)
59
+ # console.log "pos = #{pos}"
60
+ if (pos == -1)
61
+ result = prefix
62
+ else
63
+ result = setCharsAt(prefix, pos, ' ')
64
+ # console.log "result = #{OL(result)}"
65
+ return result
package/src/arrow.js CHANGED
@@ -1,5 +1,12 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
- // arrow.coffee
2
+ // arrow.coffee
3
+ import {
4
+ undef,
5
+ OL,
6
+ setCharsAt
7
+ } from '@jdeighan/coffee-utils';
8
+
9
+ // --- We use spaces here because Windows Terminal handles TAB chars badly
3
10
  export var vbar = '│'; // unicode 2502
4
11
 
5
12
  export var hbar = '─'; // unicode 2500
@@ -14,20 +21,24 @@ export var oneIndent = vbar + space + space + space;
14
21
 
15
22
  export var arrow = corner + hbar + arrowhead + space;
16
23
 
17
- export var fourSpaces = space + space + space + space;
24
+ export var clearIndent = space + space + space + space;
18
25
 
19
26
  // ---------------------------------------------------------------------------
20
27
  export var getPrefix = function(level, option = 'none') {
21
28
  var result;
22
29
  if (level === 0) {
23
- return '';
30
+ if (option === 'object') {
31
+ return clearIndent;
32
+ } else {
33
+ return '';
34
+ }
24
35
  }
25
36
  switch (option) {
26
37
  case 'withArrow':
27
38
  result = oneIndent.repeat(level - 1) + arrow;
28
39
  break;
29
- case 'returnVal':
30
- result = oneIndent.repeat(level - 1) + fourSpaces;
40
+ case 'object':
41
+ result = oneIndent.repeat(level) + clearIndent;
31
42
  break;
32
43
  case 'none':
33
44
  result = oneIndent.repeat(level);
@@ -40,3 +51,33 @@ export var getPrefix = function(level, option = 'none') {
40
51
  }
41
52
  return result;
42
53
  };
54
+
55
+ // ---------------------------------------------------------------------------
56
+ export var addArrow = function(prefix) {
57
+ var pos, result;
58
+ // console.log "in addArrow(#{OL(prefix)})"
59
+ pos = prefix.lastIndexOf(vbar);
60
+ // console.log "pos = #{pos}"
61
+ if (pos === -1) {
62
+ result = prefix;
63
+ } else {
64
+ result = setCharsAt(prefix, pos, arrow);
65
+ }
66
+ // console.log "result = #{OL(result)}"
67
+ return result;
68
+ };
69
+
70
+ // ---------------------------------------------------------------------------
71
+ export var removeLastVbar = function(prefix) {
72
+ var pos, result;
73
+ // console.log "in removeLastVbar(#{OL(prefix)})"
74
+ pos = prefix.lastIndexOf(vbar);
75
+ // console.log "pos = #{pos}"
76
+ if (pos === -1) {
77
+ result = prefix;
78
+ } else {
79
+ result = setCharsAt(prefix, pos, ' ');
80
+ }
81
+ // console.log "result = #{OL(result)}"
82
+ return result;
83
+ };
@@ -1,6 +1,8 @@
1
1
  # call_stack.coffee
2
2
 
3
- import {undef, croak, assert} from '@jdeighan/coffee-utils'
3
+ import {
4
+ undef, defined, croak, assert, OL, isBoolean, escapeStr,
5
+ } from '@jdeighan/coffee-utils'
4
6
  import {log, LOG} from '@jdeighan/coffee-utils/log'
5
7
  import {getPrefix} from '@jdeighan/coffee-utils/arrow'
6
8
 
@@ -19,7 +21,8 @@ export class CallStack
19
21
 
20
22
  constructor: () ->
21
23
 
22
- @reset()
24
+ @lStack = []
25
+ @level = 0
23
26
 
24
27
  # ........................................................................
25
28
 
@@ -27,86 +30,130 @@ export class CallStack
27
30
 
28
31
  if doDebugStack
29
32
  LOG "RESET STACK"
30
-
31
33
  @lStack = []
32
34
  @level = 0
33
35
  return
34
36
 
35
37
  # ........................................................................
36
38
 
37
- addCall: (funcName, hInfo, isLogged) ->
39
+ enter: (funcName, oldFlag=undef) ->
40
+ # --- funcName might be <object>.<method>
38
41
 
39
- @lStack.push({funcName, hInfo, isLogged})
40
- if isLogged
41
- @level += 1
42
+ assert (oldFlag == undef), "enter() takes only 1 arg"
43
+ if doDebugStack
44
+ LOG "[--> ENTER #{funcName}]"
45
+
46
+ lMatches = funcName.match(///^
47
+ ([A-Za-z_][A-Za-z0-9_]*)
48
+ (?:
49
+ \.
50
+ ([A-Za-z_][A-Za-z0-9_]*)
51
+ )?
52
+ $///)
53
+ assert defined(lMatches), "Bad funcName: #{OL(funcName)}"
54
+ [_, ident1, ident2] = lMatches
55
+ if ident2
56
+ @lStack.push({
57
+ fullName: "#{ident1}.#{ident2}"
58
+ funcName: ident2
59
+ isLogged: false
60
+ })
61
+ else
62
+ @lStack.push({
63
+ fullName: ident1
64
+ funcName: ident1
65
+ isLogged: false
66
+ })
42
67
  return
43
68
 
44
69
  # ........................................................................
45
70
 
46
- removeCall: (fName) ->
47
-
48
- {funcName, hInfo, isLogged} = @lStack.pop()
49
- if isLogged && (@level > 0)
50
- @level -= 1
51
- while (funcName != fName) && (@lStack.length > 0)
52
- LOG "[MISSING RETURN FROM #{funcName} (return from #{fName})]"
53
- {funcName, hInfo, isLogged} = @lStack.pop()
54
- if isLogged && (@level > 0)
55
- @level -= 1
71
+ isLogging: () ->
56
72
 
57
- if funcName == fName
58
- return hInfo
73
+ if (@lStack.length == 0)
74
+ return false
59
75
  else
60
- @dump()
61
- LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
62
- return undef
76
+ return @lStack[@lStack.length - 1].isLogged
63
77
 
64
78
  # ........................................................................
79
+
80
+ isLoggingPrev: () ->
81
+
82
+ if (@lStack.length < 2)
83
+ return false
84
+ else
85
+ return @lStack[@lStack.length - 2].isLogged
86
+
65
87
  # ........................................................................
66
88
 
67
- call: (funcName, hInfo, isLogged=undef) ->
89
+ logCurFunc: () ->
68
90
 
69
- assert isLogged != undef, "CallStack.call(): 3 args required"
70
- mainPre = getPrefix(@level)
91
+ # --- funcName must be the current function
92
+ # and the isLogged flag must currently be false
93
+ cur = @lStack[@lStack.length - 1]
94
+ assert (cur.isLogged == false), "isLogged is already true"
95
+ cur.isLogged = true
96
+ @level += 1
97
+ return
98
+
99
+ # ........................................................................
100
+ # --- if stack is empty, log the error, but continue
101
+
102
+ returnFrom: (fName) ->
71
103
 
72
104
  if doDebugStack
73
- prefix = ' '.repeat(@lStack.length)
74
- LOG "#{prefix}[--> CALL #{funcName}]"
105
+ LOG "[<-- BACK #{fName}]"
75
106
 
76
- @addCall funcName, hInfo, isLogged
77
- auxPre = getPrefix(@level)
78
- return [mainPre, auxPre, undef]
107
+ if @lStack.length == 0
108
+ LOG "ERROR: returnFrom('#{funcName}') but stack is empty"
109
+ return
110
+
111
+ {fullName, isLogged} = @lStack.pop()
112
+ if isLogged && (@level > 0)
113
+ @level -= 1
114
+
115
+ # --- This should do nothing
116
+ while (fullName != fName) && (@lStack.length > 0)
117
+ LOG "[MISSING RETURN FROM #{fullName} (return from #{fName})]"
118
+ {fullName, isLogged} = @lStack.pop()
119
+ if isLogged && (@level > 0)
120
+ @level -= 1
121
+
122
+ if fullName != fName
123
+ @dump()
124
+ LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
125
+ return
79
126
 
80
127
  # ........................................................................
81
128
 
82
- logStr: () ->
129
+ getLevel: () ->
83
130
 
84
- pre = getPrefix(@level)
85
- return [pre, pre, undef]
131
+ return @level
86
132
 
87
133
  # ........................................................................
88
134
 
89
- returnFrom: (funcName) ->
135
+ curFunc: () ->
90
136
 
91
- # --- Prefixes are based on level before stack adjustment
92
- mainPre = getPrefix(@level, 'withArrow')
93
- auxPre = getPrefix(@level, 'returnVal')
137
+ if (@lStack.length == 0)
138
+ return 'main'
139
+ else
140
+ return @lStack[@lStack.length - 1].funcName
94
141
 
95
- if @lStack.length == 0
96
- LOG "returnFrom('#{funcName}') but stack is empty"
97
- return [mainPre, auxPre, undef]
142
+ # ........................................................................
98
143
 
99
- hInfo = @removeCall(funcName)
100
- if doDebugStack
101
- prefix = ' '.repeat(@lStack.length)
102
- LOG "#{prefix}[<-- BACK #{funcName}]"
144
+ isActive: (funcName) ->
145
+ # --- funcName won't be <obj>.<method>
146
+ # but the stack might contain that form
103
147
 
104
- return [mainPre, auxPre, hInfo]
148
+ for h in @lStack
149
+ if (h.funcName == funcName)
150
+ return true
151
+ return false
105
152
 
106
153
  # ........................................................................
107
154
  # ........................................................................
108
155
 
109
- dump: (label='CALL STACK') ->
156
+ dump: (prefix='', label='CALL STACK') ->
110
157
 
111
158
  LOG "#{label}:"
112
159
  if @lStack.length == 0
package/src/call_stack.js CHANGED
@@ -4,8 +4,12 @@ var doDebugStack;
4
4
 
5
5
  import {
6
6
  undef,
7
+ defined,
7
8
  croak,
8
- assert
9
+ assert,
10
+ OL,
11
+ isBoolean,
12
+ escapeStr
9
13
  } from '@jdeighan/coffee-utils';
10
14
 
11
15
  import {
@@ -27,7 +31,8 @@ export var debugStack = function(flag = true) {
27
31
  // ---------------------------------------------------------------------------
28
32
  export var CallStack = class CallStack {
29
33
  constructor() {
30
- this.reset();
34
+ this.lStack = [];
35
+ this.level = 0;
31
36
  }
32
37
 
33
38
  // ........................................................................
@@ -40,79 +45,121 @@ export var CallStack = class CallStack {
40
45
  }
41
46
 
42
47
  // ........................................................................
43
- addCall(funcName, hInfo, isLogged) {
44
- this.lStack.push({funcName, hInfo, isLogged});
45
- if (isLogged) {
46
- this.level += 1;
48
+ enter(funcName, oldFlag = undef) {
49
+ var _, ident1, ident2, lMatches;
50
+ // --- funcName might be <object>.<method>
51
+ assert(oldFlag === undef, "enter() takes only 1 arg");
52
+ if (doDebugStack) {
53
+ LOG(`[--> ENTER ${funcName}]`);
54
+ }
55
+ lMatches = funcName.match(/^([A-Za-z_][A-Za-z0-9_]*)(?:\.([A-Za-z_][A-Za-z0-9_]*))?$/);
56
+ assert(defined(lMatches), `Bad funcName: ${OL(funcName)}`);
57
+ [_, ident1, ident2] = lMatches;
58
+ if (ident2) {
59
+ this.lStack.push({
60
+ fullName: `${ident1}.${ident2}`,
61
+ funcName: ident2,
62
+ isLogged: false
63
+ });
64
+ } else {
65
+ this.lStack.push({
66
+ fullName: ident1,
67
+ funcName: ident1,
68
+ isLogged: false
69
+ });
47
70
  }
48
71
  }
49
72
 
50
73
  // ........................................................................
51
- removeCall(fName) {
52
- var funcName, hInfo, isLogged;
53
- ({funcName, hInfo, isLogged} = this.lStack.pop());
74
+ isLogging() {
75
+ if (this.lStack.length === 0) {
76
+ return false;
77
+ } else {
78
+ return this.lStack[this.lStack.length - 1].isLogged;
79
+ }
80
+ }
81
+
82
+ // ........................................................................
83
+ isLoggingPrev() {
84
+ if (this.lStack.length < 2) {
85
+ return false;
86
+ } else {
87
+ return this.lStack[this.lStack.length - 2].isLogged;
88
+ }
89
+ }
90
+
91
+ // ........................................................................
92
+ logCurFunc() {
93
+ var cur;
94
+ // --- funcName must be the current function
95
+ // and the isLogged flag must currently be false
96
+ cur = this.lStack[this.lStack.length - 1];
97
+ assert(cur.isLogged === false, "isLogged is already true");
98
+ cur.isLogged = true;
99
+ this.level += 1;
100
+ }
101
+
102
+ // ........................................................................
103
+ // --- if stack is empty, log the error, but continue
104
+ returnFrom(fName) {
105
+ var fullName, isLogged;
106
+ if (doDebugStack) {
107
+ LOG(`[<-- BACK ${fName}]`);
108
+ }
109
+ if (this.lStack.length === 0) {
110
+ LOG(`ERROR: returnFrom('${funcName}') but stack is empty`);
111
+ return;
112
+ }
113
+ ({fullName, isLogged} = this.lStack.pop());
54
114
  if (isLogged && (this.level > 0)) {
55
115
  this.level -= 1;
56
116
  }
57
- while ((funcName !== fName) && (this.lStack.length > 0)) {
58
- LOG(`[MISSING RETURN FROM ${funcName} (return from ${fName})]`);
59
- ({funcName, hInfo, isLogged} = this.lStack.pop());
117
+ // --- This should do nothing
118
+ while ((fullName !== fName) && (this.lStack.length > 0)) {
119
+ LOG(`[MISSING RETURN FROM ${fullName} (return from ${fName})]`);
120
+ ({fullName, isLogged} = this.lStack.pop());
60
121
  if (isLogged && (this.level > 0)) {
61
122
  this.level -= 1;
62
123
  }
63
124
  }
64
- if (funcName === fName) {
65
- return hInfo;
66
- } else {
125
+ if (fullName !== fName) {
67
126
  this.dump();
68
127
  LOG(`BAD BAD BAD BAD returnFrom('${fName}')`);
69
- return undef;
70
128
  }
71
129
  }
72
130
 
73
131
  // ........................................................................
74
- // ........................................................................
75
- call(funcName, hInfo, isLogged = undef) {
76
- var auxPre, mainPre, prefix;
77
- assert(isLogged !== undef, "CallStack.call(): 3 args required");
78
- mainPre = getPrefix(this.level);
79
- if (doDebugStack) {
80
- prefix = ' '.repeat(this.lStack.length);
81
- LOG(`${prefix}[--> CALL ${funcName}]`);
82
- }
83
- this.addCall(funcName, hInfo, isLogged);
84
- auxPre = getPrefix(this.level);
85
- return [mainPre, auxPre, undef];
132
+ getLevel() {
133
+ return this.level;
86
134
  }
87
135
 
88
136
  // ........................................................................
89
- logStr() {
90
- var pre;
91
- pre = getPrefix(this.level);
92
- return [pre, pre, undef];
137
+ curFunc() {
138
+ if (this.lStack.length === 0) {
139
+ return 'main';
140
+ } else {
141
+ return this.lStack[this.lStack.length - 1].funcName;
142
+ }
93
143
  }
94
144
 
95
145
  // ........................................................................
96
- returnFrom(funcName) {
97
- var auxPre, hInfo, mainPre, prefix;
98
- // --- Prefixes are based on level before stack adjustment
99
- mainPre = getPrefix(this.level, 'withArrow');
100
- auxPre = getPrefix(this.level, 'returnVal');
101
- if (this.lStack.length === 0) {
102
- LOG(`returnFrom('${funcName}') but stack is empty`);
103
- return [mainPre, auxPre, undef];
104
- }
105
- hInfo = this.removeCall(funcName);
106
- if (doDebugStack) {
107
- prefix = ' '.repeat(this.lStack.length);
108
- LOG(`${prefix}[<-- BACK ${funcName}]`);
146
+ isActive(funcName) {
147
+ var h, j, len, ref;
148
+ ref = this.lStack;
149
+ // --- funcName won't be <obj>.<method>
150
+ // but the stack might contain that form
151
+ for (j = 0, len = ref.length; j < len; j++) {
152
+ h = ref[j];
153
+ if (h.funcName === funcName) {
154
+ return true;
155
+ }
109
156
  }
110
- return [mainPre, auxPre, hInfo];
157
+ return false;
111
158
  }
112
159
 
113
160
  // ........................................................................
114
161
  // ........................................................................
115
- dump(label = 'CALL STACK') {
162
+ dump(prefix = '', label = 'CALL STACK') {
116
163
  var i, item, j, len, ref;
117
164
  LOG(`${label}:`);
118
165
  if (this.lStack.length === 0) {
@@ -503,3 +503,15 @@ export className = (aClass) ->
503
503
  export range = (n) ->
504
504
 
505
505
  return [0..n-1]
506
+
507
+ # ---------------------------------------------------------------------------
508
+
509
+ export setCharsAt = (str, pos, str2) ->
510
+
511
+ assert (pos >= 0), "negative pos #{pos} not allowed"
512
+ assert (pos < str.length), "pos #{pos} not in #{OL(str)}"
513
+ if (pos + str2.length >= str.length)
514
+ return str.substring(0, pos) + str2
515
+ else
516
+ return str.substring(0, pos) + str2 + str.substring(pos + str2.length)
517
+
@@ -543,3 +543,14 @@ export var range = function(n) {
543
543
  return results;
544
544
  }).apply(this);
545
545
  };
546
+
547
+ // ---------------------------------------------------------------------------
548
+ export var setCharsAt = function(str, pos, str2) {
549
+ assert(pos >= 0, `negative pos ${pos} not allowed`);
550
+ assert(pos < str.length, `pos ${pos} not in ${OL(str)}`);
551
+ if (pos + str2.length >= str.length) {
552
+ return str.substring(0, pos) + str2;
553
+ } else {
554
+ return str.substring(0, pos) + str2 + str.substring(pos + str2.length);
555
+ }
556
+ };