1
1
import { StaticExtractor } from './extractor.ts' ;
2
2
import type * as acorn from 'acorn' ;
3
+ import { analyzeBlock } from './internal/analyze/block.ts' ;
4
+ import { reductifyFunction } from './internal/analyze/expression.ts' ;
5
+ import { createBlock } from './internal/analyze/helper.ts' ;
3
6
4
7
export function liftDefault ( e : StaticExtractor , minSize : number ) {
5
8
const stats = {
@@ -10,6 +13,106 @@ export function liftDefault(e: StaticExtractor, minSize: number) {
10
13
_skip : 0 ,
11
14
} ;
12
15
16
+ // lift a subpath of a complex statement
17
+ const innerLiftMaybeBlock = ( b : acorn . Statement | null | undefined , dirty : string [ ] ) => {
18
+ if ( ! b ) {
19
+ return ;
20
+ }
21
+ if ( b . type !== 'BlockStatement' ) {
22
+ if ( b . type === 'VariableDeclaration' ) {
23
+ // only valid thing is 'if (1) var x = ...', nope nope nope
24
+ return ;
25
+ }
26
+ b = createBlock ( b ) ; // treat as miniblock
27
+ } else {
28
+ const a = analyzeBlock ( b , { nest : false } ) ;
29
+ const declaredHere : string [ ] = [ ] ;
30
+ a . vars . forEach ( ( info , key ) => {
31
+ if ( info . local ?. kind ) {
32
+ declaredHere . push ( key ) ;
33
+ }
34
+ } ) ;
35
+ dirty = dirty . concat ( declaredHere ) ;
36
+ }
37
+
38
+ innerLift ( b , dirty ) ;
39
+ } ;
40
+
41
+ const innerLift = ( b : acorn . BlockStatement , dirty : string [ ] ) => {
42
+ const maybeLift = ( expr : acorn . Expression | null | undefined , ok : ( ) => void ) => {
43
+ if ( ! expr ) {
44
+ return ;
45
+ }
46
+ const size = expr . end - expr . start ;
47
+ if ( size < minSize ) {
48
+ return ;
49
+ }
50
+ if ( e . liftExpression ( expr , dirty ) ) {
51
+ ok ( ) ;
52
+ } else {
53
+ ++ stats . _skip ;
54
+ }
55
+ } ;
56
+
57
+ for ( const part of b . body ) {
58
+ switch ( part . type ) {
59
+ case 'ExpressionStatement' :
60
+ if (
61
+ part . expression . type === 'CallExpression' &&
62
+ ( part . expression . callee . type === 'FunctionExpression' ||
63
+ part . expression . callee . type === 'ArrowFunctionExpression' )
64
+ ) {
65
+ // IIFE
66
+ const r = reductifyFunction ( part . expression . callee ) ;
67
+ innerLiftMaybeBlock ( r , dirty ) ;
68
+ } else if ( part . expression . type === 'AssignmentExpression' ) {
69
+ // find things on the right of "="
70
+ // this won't lift normally (the left part changes)
71
+ maybeLift ( part . expression . right , ( ) => stats . assignment ++ ) ;
72
+ } else {
73
+ // try the whole thing? :shrug:
74
+ maybeLift ( part . expression , ( ) => stats . expr ++ ) ;
75
+ }
76
+ continue ;
77
+
78
+ case 'VariableDeclaration' :
79
+ for ( const decl of part . declarations ) {
80
+ maybeLift ( decl . init , ( ) => stats . assignment ++ ) ;
81
+ }
82
+ continue ;
83
+
84
+ case 'ReturnStatement' :
85
+ // why not? might be big
86
+ maybeLift ( part . argument , ( ) => stats . expr ++ ) ;
87
+ continue ;
88
+
89
+ // -- nested control statements below here
90
+
91
+ case 'WhileStatement' :
92
+ case 'DoWhileStatement' :
93
+ innerLiftMaybeBlock ( part . body , dirty ) ;
94
+ break ;
95
+
96
+ case 'IfStatement' :
97
+ innerLiftMaybeBlock ( part . consequent , dirty ) ;
98
+ innerLiftMaybeBlock ( part . alternate , dirty ) ;
99
+ break ;
100
+
101
+ case 'BlockStatement' :
102
+ innerLiftMaybeBlock ( part , dirty ) ;
103
+ break ;
104
+
105
+ case 'TryStatement' :
106
+ innerLiftMaybeBlock ( part . block , dirty ) ;
107
+ // TODO: include handler (maybe declares var)
108
+ innerLiftMaybeBlock ( part . finalizer , dirty ) ;
109
+ break ;
110
+
111
+ // TODO: include for/etc which can declare vars
112
+ }
113
+ }
114
+ } ;
115
+
13
116
// lift top-level fn blocks
14
117
for ( const part of e . block . body ) {
15
118
const size = part . end - part . start ;
@@ -37,46 +140,8 @@ export function liftDefault(e: StaticExtractor, minSize: number) {
37
140
}
38
141
}
39
142
40
- // lift expressions in a few places (all top-level though?)
41
- const maybeLift = ( expr : acorn . Expression | null | undefined , ok : ( ) => void ) => {
42
- if ( ! expr ) {
43
- return ;
44
- }
45
- const size = expr . end - expr . start ;
46
- if ( size < minSize ) {
47
- return ;
48
- }
49
- if ( e . liftExpression ( expr ) ) {
50
- ok ( ) ;
51
- } else {
52
- ++ stats . _skip ;
53
- }
54
- } ;
55
- for ( const part of e . block . body ) {
56
- switch ( part . type ) {
57
- case 'ExpressionStatement' :
58
- if ( part . expression . type === 'AssignmentExpression' ) {
59
- // find things on the right of "="
60
- // this won't lift normally (the left part changes)
61
- maybeLift ( part . expression . right , ( ) => stats . assignment ++ ) ;
62
- } else {
63
- // try the whole thing? :shrug:
64
- maybeLift ( part . expression , ( ) => stats . expr ++ ) ;
65
- }
66
- continue ;
67
-
68
- case 'VariableDeclaration' :
69
- for ( const decl of part . declarations ) {
70
- maybeLift ( decl . init , ( ) => stats . assignment ++ ) ;
71
- }
72
- continue ;
73
-
74
- case 'ReturnStatement' :
75
- // why not? might be big
76
- maybeLift ( part . argument , ( ) => stats . expr ++ ) ;
77
- continue ;
78
- }
79
- }
143
+ // follow top-level statements
144
+ innerLift ( e . block , [ ] ) ;
80
145
81
146
return stats ;
82
147
}
0 commit comments