@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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "7.0.50",
4
+ "version": "7.0.53",
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.6"
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,7 +1,7 @@
1
1
  # call_stack.coffee
2
2
 
3
3
  import {
4
- undef, defined, croak, assert, isBoolean,
4
+ undef, defined, croak, assert, OL, isBoolean, escapeStr,
5
5
  } from '@jdeighan/coffee-utils'
6
6
  import {log, LOG} from '@jdeighan/coffee-utils/log'
7
7
  import {getPrefix} from '@jdeighan/coffee-utils/arrow'
@@ -21,7 +21,8 @@ export class CallStack
21
21
 
22
22
  constructor: () ->
23
23
 
24
- @reset()
24
+ @lStack = []
25
+ @level = 0
25
26
 
26
27
  # ........................................................................
27
28
 
@@ -29,86 +30,130 @@ export class CallStack
29
30
 
30
31
  if doDebugStack
31
32
  LOG "RESET STACK"
32
-
33
33
  @lStack = []
34
34
  @level = 0
35
35
  return
36
36
 
37
37
  # ........................................................................
38
38
 
39
- addCall: (funcName, hInfo, isLogged) ->
39
+ enter: (funcName, oldFlag=undef) ->
40
+ # --- funcName might be <object>.<method>
40
41
 
41
- @lStack.push({funcName, hInfo, isLogged})
42
- if isLogged
43
- @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
+ })
44
67
  return
45
68
 
46
69
  # ........................................................................
47
70
 
48
- removeCall: (fName) ->
49
-
50
- {funcName, hInfo, isLogged} = @lStack.pop()
51
- if isLogged && (@level > 0)
52
- @level -= 1
53
- while (funcName != fName) && (@lStack.length > 0)
54
- LOG "[MISSING RETURN FROM #{funcName} (return from #{fName})]"
55
- {funcName, hInfo, isLogged} = @lStack.pop()
56
- if isLogged && (@level > 0)
57
- @level -= 1
71
+ isLogging: () ->
58
72
 
59
- if funcName == fName
60
- return hInfo
73
+ if (@lStack.length == 0)
74
+ return false
61
75
  else
62
- @dump()
63
- LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
64
- return undef
76
+ return @lStack[@lStack.length - 1].isLogged
65
77
 
66
78
  # ........................................................................
79
+
80
+ isLoggingPrev: () ->
81
+
82
+ if (@lStack.length < 2)
83
+ return false
84
+ else
85
+ return @lStack[@lStack.length - 2].isLogged
86
+
67
87
  # ........................................................................
68
88
 
69
- doCall: (funcName, hInfo, isLogged) ->
89
+ logCurFunc: () ->
70
90
 
71
- assert isBoolean(isLogged), "CallStack.call(): 3 args required"
72
- 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) ->
73
103
 
74
104
  if doDebugStack
75
- prefix = ' '.repeat(@lStack.length)
76
- LOG "#{prefix}[--> CALL #{funcName}]"
105
+ LOG "[<-- BACK #{fName}]"
77
106
 
78
- @addCall funcName, hInfo, isLogged
79
- auxPre = getPrefix(@level)
80
- return [mainPre, auxPre]
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
81
126
 
82
127
  # ........................................................................
83
128
 
84
- logStr: () ->
129
+ getLevel: () ->
85
130
 
86
- pre = getPrefix(@level)
87
- return [pre, pre, undef]
131
+ return @level
88
132
 
89
133
  # ........................................................................
90
134
 
91
- returnFrom: (funcName) ->
135
+ curFunc: () ->
92
136
 
93
- # --- Prefixes are based on level before stack adjustment
94
- mainPre = getPrefix(@level, 'withArrow')
95
- auxPre = getPrefix(@level, 'returnVal')
137
+ if (@lStack.length == 0)
138
+ return 'main'
139
+ else
140
+ return @lStack[@lStack.length - 1].funcName
96
141
 
97
- if @lStack.length == 0
98
- LOG "returnFrom('#{funcName}') but stack is empty"
99
- return [mainPre, auxPre, undef]
142
+ # ........................................................................
100
143
 
101
- hInfo = @removeCall(funcName)
102
- if doDebugStack
103
- prefix = ' '.repeat(@lStack.length)
104
- LOG "#{prefix}[<-- BACK #{funcName}]"
144
+ isActive: (funcName) ->
145
+ # --- funcName won't be <obj>.<method>
146
+ # but the stack might contain that form
105
147
 
106
- return [mainPre, auxPre, hInfo]
148
+ for h in @lStack
149
+ if (h.funcName == funcName)
150
+ return true
151
+ return false
107
152
 
108
153
  # ........................................................................
109
154
  # ........................................................................
110
155
 
111
- dump: (label='CALL STACK') ->
156
+ dump: (prefix='', label='CALL STACK') ->
112
157
 
113
158
  LOG "#{label}:"
114
159
  if @lStack.length == 0
package/src/call_stack.js CHANGED
@@ -7,7 +7,9 @@ import {
7
7
  defined,
8
8
  croak,
9
9
  assert,
10
- isBoolean
10
+ OL,
11
+ isBoolean,
12
+ escapeStr
11
13
  } from '@jdeighan/coffee-utils';
12
14
 
13
15
  import {
@@ -29,7 +31,8 @@ export var debugStack = function(flag = true) {
29
31
  // ---------------------------------------------------------------------------
30
32
  export var CallStack = class CallStack {
31
33
  constructor() {
32
- this.reset();
34
+ this.lStack = [];
35
+ this.level = 0;
33
36
  }
34
37
 
35
38
  // ........................................................................
@@ -42,79 +45,121 @@ export var CallStack = class CallStack {
42
45
  }
43
46
 
44
47
  // ........................................................................
45
- addCall(funcName, hInfo, isLogged) {
46
- this.lStack.push({funcName, hInfo, isLogged});
47
- if (isLogged) {
48
- 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
+ });
49
70
  }
50
71
  }
51
72
 
52
73
  // ........................................................................
53
- removeCall(fName) {
54
- var funcName, hInfo, isLogged;
55
- ({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());
56
114
  if (isLogged && (this.level > 0)) {
57
115
  this.level -= 1;
58
116
  }
59
- while ((funcName !== fName) && (this.lStack.length > 0)) {
60
- LOG(`[MISSING RETURN FROM ${funcName} (return from ${fName})]`);
61
- ({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());
62
121
  if (isLogged && (this.level > 0)) {
63
122
  this.level -= 1;
64
123
  }
65
124
  }
66
- if (funcName === fName) {
67
- return hInfo;
68
- } else {
125
+ if (fullName !== fName) {
69
126
  this.dump();
70
127
  LOG(`BAD BAD BAD BAD returnFrom('${fName}')`);
71
- return undef;
72
128
  }
73
129
  }
74
130
 
75
131
  // ........................................................................
76
- // ........................................................................
77
- doCall(funcName, hInfo, isLogged) {
78
- var auxPre, mainPre, prefix;
79
- assert(isBoolean(isLogged), "CallStack.call(): 3 args required");
80
- mainPre = getPrefix(this.level);
81
- if (doDebugStack) {
82
- prefix = ' '.repeat(this.lStack.length);
83
- LOG(`${prefix}[--> CALL ${funcName}]`);
84
- }
85
- this.addCall(funcName, hInfo, isLogged);
86
- auxPre = getPrefix(this.level);
87
- return [mainPre, auxPre];
132
+ getLevel() {
133
+ return this.level;
88
134
  }
89
135
 
90
136
  // ........................................................................
91
- logStr() {
92
- var pre;
93
- pre = getPrefix(this.level);
94
- 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
+ }
95
143
  }
96
144
 
97
145
  // ........................................................................
98
- returnFrom(funcName) {
99
- var auxPre, hInfo, mainPre, prefix;
100
- // --- Prefixes are based on level before stack adjustment
101
- mainPre = getPrefix(this.level, 'withArrow');
102
- auxPre = getPrefix(this.level, 'returnVal');
103
- if (this.lStack.length === 0) {
104
- LOG(`returnFrom('${funcName}') but stack is empty`);
105
- return [mainPre, auxPre, undef];
106
- }
107
- hInfo = this.removeCall(funcName);
108
- if (doDebugStack) {
109
- prefix = ' '.repeat(this.lStack.length);
110
- 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
+ }
111
156
  }
112
- return [mainPre, auxPre, hInfo];
157
+ return false;
113
158
  }
114
159
 
115
160
  // ........................................................................
116
161
  // ........................................................................
117
- dump(label = 'CALL STACK') {
162
+ dump(prefix = '', label = 'CALL STACK') {
118
163
  var i, item, j, len, ref;
119
164
  LOG(`${label}:`);
120
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
+ };