@@ -89,6 +89,9 @@ export const debugIf = p => expr => {
89
89
} ;
90
90
91
91
92
+ //█████ Type Signatures ███████████████████████████████████████████████████████
93
+
94
+
92
95
// intercept type signatures
93
96
94
97
export const trace = x => {
@@ -97,10 +100,237 @@ export const trace = x => {
97
100
} ;
98
101
99
102
103
+ export const Sign = { } ;
104
+
105
+ Sign . retrieve = x => {
106
+ if ( typeof x === "function" ) {
107
+ if ( x [ $ ] === "Visor" ) return x . toString ( ) ;
108
+ return x . name || "λ" ;
109
+ }
110
+
111
+ else if ( x === null ) return "Nul" ;
112
+ else if ( x === undefined ) return "Und" ;
113
+
114
+ else if ( typeof x === "object" ) {
115
+ const tag = Object . prototype . toString . call ( x ) . slice ( 8 , - 1 ) ;
116
+
117
+ switch ( tag ) {
118
+ case "Array" : return `[${ Sign . arr ( x ) } ]` ;
119
+ case "Boolean" : return "Bol{}" ;
120
+ case "Date" : return "Dat{}" ;
121
+ case "Map" : return `Map<${ Sign . map ( x ) } >` ;
122
+ case "Number" : return "Num{}" ;
123
+ case "Promise" : return "Pro{}" ;
124
+ case "RegExp" : return "Rex{}" ;
125
+ case "Set" : return `Set<${ Sign . set ( x ) } >` ;
126
+ case "String" : return "Str{}" ;
127
+ case "Symbol" : return "Sym{}" ;
128
+ case "WeakMap" : return `Wap<${ Sign . map ( x ) } >` ;
129
+ case "WeakRef" : return "Ref{}" ;
130
+ case "WeakSet" : return `Wet<${ Sign . set ( x ) } >` ;
131
+
132
+ case "Object" : {
133
+ if ( x ?. [ $ ] ) return `${ x [ $ ] } {${ Sign . obj ( x ) } }` ;
134
+
135
+ else {
136
+ const name = x ?. constructor ?. name === "Object"
137
+ ? "" : x . constructor . name ;
138
+
139
+ return `${ name } {${ Sign . obj ( x ) } }` ;
140
+ }
141
+ }
142
+
143
+ default : throw new Err ( `unknown tag "${ tag } ` ) ;
144
+ }
145
+ }
146
+
147
+ else switch ( Object . prototype . toString . call ( x ) . slice ( 8 , - 1 ) ) {
148
+ // Primitives (excluding function/null/undefined handled above)
149
+ case "Boolean" : return "Boo" ;
150
+ case "BigInt" : return "Big" ;
151
+ case "NaN" : return "NaN" ;
152
+ case "Number" : return "Num" ;
153
+ case "String" : return "Str" ;
154
+ case "Symbol" : return "Sym" ;
155
+ default : throw new Err ( `unknown primitive tag "${ tag } ` ) ;
156
+ }
157
+ } ;
158
+
159
+
160
+ Sign . arr = xs => {
161
+ const s = xs . reduce ( ( acc , x ) => {
162
+ return acc . add ( Sign . retrieve ( x ) )
163
+ } , new Set ( ) ) ;
164
+
165
+ return Array . from ( s ) . join ( "," ) ;
166
+ } ;
167
+
168
+
169
+ Sign . set = s => {
170
+ const s2 = Array . from ( s ) . reduce ( ( acc , x ) => {
171
+ return acc . add ( Sign . retrieve ( x ) )
172
+ } , new Set ( ) ) ;
173
+
174
+ return Array . from ( s2 ) . join ( "," ) ;
175
+ } ;
176
+
177
+
178
+ Sign . map = m => {
179
+ const s2 = Array . from ( m ) . reduce ( ( acc , pair ) => {
180
+ return acc . add ( `${ Sign . retrieve ( pair [ 0 ] ) } :${ Sign . retrieve ( pair [ 1 ] ) } ` ) ;
181
+ } , new Set ( ) ) ;
182
+
183
+ return Array . from ( s2 ) . join ( "," ) ;
184
+ } ;
185
+
186
+
187
+ Sign . obj = o => {
188
+ const s2 = Object . entries ( o ) . reduce ( ( acc , pair ) => {
189
+ return acc . add ( `${ Sign . retrieve ( pair [ 0 ] ) } :${ Sign . retrieve ( pair [ 1 ] ) } ` ) ;
190
+ } , new Set ( ) ) ;
191
+
192
+ return Array . from ( s2 ) . join ( "," ) ;
193
+ } ;
194
+
195
+
100
196
//█████ Visualization █████████████████████████████████████████████████████████
101
197
102
198
199
+ /* Instead of static typing, scriptum tries to visualize the nested intermediate
200
+ function call tree that is build by the computation. It does so by logging all
201
+ intermediate results. This profoundly assists the programmer during development.
202
+ Evaluating `comp(comp) (comp) (sqr) (add) (3) (4)`, for instance, yields the
203
+ following log:
204
+
205
+ ➡️ comp(comp(f) (g) (x))
206
+ ✅ comp(comp(f) (g) (x)) 🠲 comp(comp(f) (g) (x)) (g) (x)
207
+ ➡️ comp(comp(f) (g) (x)) (comp(f) (g) (x))
208
+ ✅ comp(comp(f) (g) (x)) (comp(f) (g) (x)) 🠲 comp(comp(f) (g) (x)) (comp(f) (g) (x)) (x)
209
+ ➡️ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x))
210
+ ➡️ comp(sqr(x))
211
+ ✅ comp(sqr(x)) 🠲 comp(sqr(x)) (g) (x)
212
+ ➡️ comp(comp(sqr(x)) (g) (x))
213
+ ✅ comp(comp(sqr(x)) (g) (x)) 🠲 comp(comp(sqr(x)) (g) (x)) (g) (x)
214
+ ➡️ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (add(x) (y))
215
+ ➡️ comp(comp(sqr(x)) (g) (x)) (add(x) (y))
216
+ ✅ comp(comp(sqr(x)) (g) (x)) (add(x) (y)) 🠲 comp(comp(sqr(x)) (g) (x)) (add(x) (y)) (x)
217
+ ✅ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (add(x) (y)) 🠲 comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x))
218
+ ➡️ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (Num)
219
+ ➡️ comp(comp(sqr(x)) (g) (x)) (add(x) (y)) (Num)
220
+ ➡️ add(Num)
221
+ ✅ add(Num) 🠲 add(Num) (y)
222
+ ➡️ comp(sqr(x)) (add(Num) (y))
223
+ ✅ comp(sqr(x)) (add(Num) (y)) 🠲 comp(sqr(x)) (add(Num) (y)) (x)
224
+ ✅ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (Num) 🠲 comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x))
225
+ ➡️ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (Num)
226
+ ➡️ comp(comp(sqr(x)) (g) (x)) (add(x) (y)) (Num) (Num)
227
+ ➡️ comp(sqr(x)) (add(Num) (y)) (Num)
228
+ ➡️ add(Num) (Num)
229
+ ✅ add(Num) (Num) 🠲 Num
230
+ ➡️ sqr(Num)
231
+ ✅ sqr(Num) 🠲 Num
232
+ ✅ comp(sqr(x)) (add(Num) (y)) (Num) 🠲 Num
233
+ ✅ comp(comp(sqr(x)) (g) (x)) (add(x) (y)) (Num) (Num) 🠲 Num
234
+ ✅ comp(comp(f) (g) (x)) (comp(f) (g) (x)) (sqr(x)) (Num) 🠲 Num */
235
+
236
+
237
+ export const Visor = { } ;
238
+
239
+
240
+ Visor . serialize = x => {
241
+ if ( x ?. [ $ ] === "Visor" ) return x . toString ( ) ;
242
+ return Sign . retrieve ( x ) ;
243
+ } ;
244
+
245
+
246
+ Visor . visualize = o => {
247
+ if ( ! o ) return "?" ;
248
+
249
+ let s = o . baseName , xs = [ ...o . baseParams ] ;
250
+
251
+ for ( let i = 0 ; i < o . appliedArgs . length && i < xs . length ; i ++ ) {
252
+ const argValue = o . appliedArgs [ i ] ;
253
+ s += `(${ Visor . serialize ( argValue ) } )` ;
254
+ }
255
+
256
+ const ys = xs . slice ( o . appliedArgs . length ) ;
257
+ for ( const param of ys ) s += `(${ param } )` ;
258
+ return s ;
259
+ } ;
260
+
261
+
262
+ Visor . createWrapper = ( f , o ) => {
263
+ const wrapper = function ( ...newArgs ) {
264
+ const xs = o . appliedArgs ,
265
+ ys = [ ...xs , ...newArgs ] ;
266
+
267
+ let s = o . baseName ;
268
+
269
+ for ( let i = 0 ; i < o . baseParams . length ; i ++ ) {
270
+ if ( i < xs . length ) s += `(${ Visor . serialize ( xs [ i ] ) } )` ;
271
+ else break ;
272
+ }
273
+
274
+ s += newArgs . map ( arg => `(${ Visor . serialize ( arg ) } )` ) . join ( "" ) ;
275
+
276
+ const callStr = s . replaceAll ( / \) (? = \( ) / g, ") " ) ;
277
+ console . log ( `➡️ ${ callStr } ` ) ;
278
+
279
+ let r ;
280
+ let resultToLog ;
281
+ let finalReturnValue ;
282
+
283
+ try {
284
+ r = f . apply ( this , newArgs ) ;
285
+
286
+ if ( typeof r === "function" ) {
287
+ const p = { ...o , appliedArgs : ys } ;
288
+ finalReturnValue = Visor . createWrapper ( r , p ) ;
289
+ resultToLog = finalReturnValue ;
290
+ } else {
291
+ finalReturnValue = r ;
292
+ resultToLog = r ;
293
+ }
294
+
295
+ let resultStr = Visor . serialize ( resultToLog ) ;
296
+
297
+ if ( callStr . replaceAll ( / / g, "" ) !== resultStr . replaceAll ( / / g, "" ) ) {
298
+ let s3 = `✅ ${ callStr } 🠲 ${ resultStr } ` ;
299
+ console . log ( s3 . replaceAll ( / \) (? = \( ) / g, ") " ) ) ;
300
+ }
301
+ }
302
+
303
+ catch ( e ) {
304
+ const s2 = s . replaceAll ( / \) (? = \( ) / g, ") " ) ;
305
+
306
+ console . error ( `💥 error during: ${ s2 } ` ) ;
307
+ console . error ( ` function: ${ f . name || "λ" } ` ) ;
308
+ console . error ( ` wrapper: ${ Visor . visualize ( o ) } ` ) ;
309
+ console . error ( ` applying ${ newArgs . map ( Visor . serialize ) . join ( ", " ) } ` )
310
+ console . error ( ` message: ${ e . message } ` ) ;
311
+ if ( e . stack ) console . error ( ` Stack: ${ e . stack . split ( '\n' ) . slice ( 1 ) . join ( '\n' ) } ` ) ;
312
+ throw e ;
313
+ }
103
314
315
+ return finalReturnValue ;
316
+ } ;
317
+
318
+ wrapper [ $ ] = "Visor" ;
319
+ wrapper [ $$ ] = "Visor" ;
320
+ wrapper . toString = ( ) => Visor . visualize ( o ) ;
321
+ return wrapper ;
322
+ } ;
323
+
324
+
325
+ Visor . augment = ( f , name , params = [ ] ) => {
326
+ const o = {
327
+ baseName : name ,
328
+ baseParams : params ,
329
+ appliedArgs : [ ] ,
330
+ } ;
331
+
332
+ return Visor . createWrapper ( f , o ) ;
333
+ } ;
104
334
105
335
106
336
/*█████████████████████████████████████████████████████████████████████████████
@@ -717,112 +947,6 @@ Stack.Base = function Base(x) {
717
947
} ;
718
948
719
949
720
- /*█████████████████████████████████████████████████████████████████████████████
721
- ███████████████████████████████ TYPE SIGNATURES ███████████████████████████████
722
- ███████████████████████████████████████████████████████████████████████████████*/
723
-
724
-
725
- export const Sign = { } ;
726
-
727
-
728
- Sign . get = x => {
729
- if ( x === null ) return "Nul" ;
730
- else if ( x === undefined ) return "Und" ;
731
-
732
- else if ( typeof x === "object" ) {
733
- const tag = Object . prototype . toString . call ( x ) . slice ( 8 , - 1 ) ;
734
-
735
- switch ( tag ) {
736
- case "Array" : return `[${ Sign . arr ( x ) } ]` ;
737
- case "Boolean" : return "Bol{}" ;
738
- case "Date" : return "Dat{}" ;
739
- case "Map" : return `Map<${ Sign . map ( x ) } >` ;
740
- case "Number" : return "Num{}" ;
741
- case "Promise" : return "Pro{}" ;
742
- case "RegExp" : return "Rex{}" ;
743
- case "Set" : return `Set<${ Sign . set ( x ) } >` ;
744
- case "String" : return "Str{}" ;
745
- case "Symbol" : return "Sym{}" ;
746
- case "WeakMap" : return `Wap<${ Sign . map ( x ) } >` ;
747
- case "WeakRef" : return "Ref{}" ;
748
- case "WeakSet" : return `Wet<${ Sign . set ( x ) } >` ;
749
-
750
- case "Object" : {
751
- if ( x ?. [ $ ] ) return `${ x [ $ ] } {${ Sign . obj ( x ) } }` ;
752
-
753
- else {
754
- const name = x ?. constructor ?. name === "Object"
755
- ? "" : x . constructor . name ;
756
-
757
- return `${ name } {${ Sign . obj ( x ) } }` ;
758
- }
759
- }
760
-
761
- default : throw new Err ( `unknown tag "${ tag } ` ) ;
762
- }
763
- }
764
-
765
- else switch ( Object . prototype . toString . call ( x ) . slice ( 8 , - 1 ) ) {
766
- case "Boolean" : return "Boo" ;
767
- case "BigInt" : return "Big" ;
768
- case "Function" : return "=>" ;
769
- case "NaN" : return "NaN" ;
770
- case "Null" : return "Nul" ;
771
- case "Number" : return "Num" ;
772
- case "String" : return "Str" ;
773
- case "Undefined" : return "Und" ;
774
-
775
- default : {
776
-
777
- }
778
- }
779
- } ;
780
-
781
-
782
- Sign . arr = xs => {
783
- const s = xs . reduce ( ( acc , x ) => {
784
- return acc . add ( Sign . get ( x ) )
785
- } , new Set ( ) ) ;
786
-
787
- return Array . from ( s ) . join ( "," ) ;
788
- } ;
789
-
790
-
791
- Sign . set = s => {
792
- const s2 = Array . from ( s ) . reduce ( ( acc , x ) => {
793
- return acc . add ( Sign . get ( x ) )
794
- } , new Set ( ) ) ;
795
-
796
- return Array . from ( s2 ) . join ( "," ) ;
797
- } ;
798
-
799
-
800
- Sign . map = m => {
801
- const s2 = Array . from ( m ) . reduce ( ( acc , pair ) => {
802
- return acc . add ( `${ Sign . get ( pair [ 0 ] ) } :${ Sign . get ( pair [ 1 ] ) } ` ) ;
803
- } , new Set ( ) ) ;
804
-
805
- return Array . from ( s2 ) . join ( "," ) ;
806
- } ;
807
-
808
-
809
- Sign . obj = o => {
810
- const s2 = Object . entries ( o ) . reduce ( ( acc , pair ) => {
811
- return acc . add ( `${ Sign . key ( pair [ 0 ] ) } :${ Sign . get ( pair [ 1 ] ) } ` ) ;
812
- } , new Set ( ) ) ;
813
-
814
- return Array . from ( s2 ) . join ( "," ) ;
815
- } ;
816
-
817
-
818
- Sign . key = x => {
819
- if ( Object . prototype . toString . call ( x ) . slice ( 8 , - 1 ) === "Symbol" )
820
- return "Sym" ;
821
-
822
- else return x ;
823
- } ;
824
-
825
-
826
950
/*█████████████████████████████████████████████████████████████████████████████
827
951
███████████████████████████████████████████████████████████████████████████████
828
952
████████████████████████████████████ ARRAY ████████████████████████████████████
0 commit comments