minjs 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +7 -0
- data/exe/minjs +2 -1
- data/lib/minjs.rb +1 -5
- data/lib/minjs/compressor.rb +3 -1140
- data/lib/minjs/compressor/compressor.rb +1146 -0
- data/lib/minjs/ctype.rb +71 -28
- data/lib/minjs/ecma262.rb +9 -4
- data/lib/minjs/ecma262/base.rb +89 -8
- data/lib/minjs/ecma262/env.rb +39 -16
- data/lib/minjs/ecma262/{exp.rb → expression.rb} +988 -281
- data/lib/minjs/ecma262/{lit.rb → literal.rb} +429 -48
- data/lib/minjs/ecma262/punctuator.rb +141 -0
- data/lib/minjs/ecma262/{st.rb → statement.rb} +328 -76
- data/lib/minjs/lex.rb +8 -1009
- data/lib/minjs/{exceptions.rb → lex/exceptions.rb} +3 -1
- data/lib/minjs/lex/expression.rb +1092 -0
- data/lib/minjs/{func.rb → lex/function.rb} +43 -23
- data/lib/minjs/lex/parser.rb +1147 -0
- data/lib/minjs/lex/program.rb +56 -0
- data/lib/minjs/{statement.rb → lex/statement.rb} +136 -126
- data/lib/minjs/minjs_compressor.rb +1 -1
- data/lib/minjs/version.rb +2 -1
- data/minjs.gemspec +1 -1
- metadata +28 -11
- data/lib/minjs/ecma262/punc.rb +0 -92
- data/lib/minjs/expression.rb +0 -833
- data/lib/minjs/program.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf7918e2d61056e016f1903050b7866612ab4dc0
|
4
|
+
data.tar.gz: 0576989a9e9705cb43a696d10532d848ee83d27c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccf02697889e825b9c5bb7fdb80d91e235980753d3f8aa1c8598cf1512e06b638e8365d23197fa774812d7d5efbcc8c66805872a34072cefc5c81645a2bbbcf9
|
7
|
+
data.tar.gz: 373dd8eed54811bfae0a1498224fb775e47075d00a5c71087f1644063a2d697241101418cffac5aa028e2829758c429f8acf584c1b33b32ad783aca0a1519cff
|
data/Rakefile
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
|
+
require "yard"
|
4
|
+
require "yard/rake/yardoc_task"
|
3
5
|
|
4
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
YARD::Rake::YardocTask.new do |t|
|
8
|
+
t.files = FileList["lib/**/*.rb"]
|
9
|
+
t.options = ['--embed-mixins']
|
10
|
+
# t.stats_options = ['--list-undoc']
|
11
|
+
end
|
5
12
|
|
6
13
|
task :default => :spec
|
7
14
|
|
data/exe/minjs
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'minjs'
|
4
|
+
require 'minjs/compressor/compressor'
|
4
5
|
|
5
6
|
argv = ARGV.dup
|
6
7
|
f = []
|
@@ -17,6 +18,6 @@ argv.each do |x|
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
prog = Minjs::Compressor.new(:debug => false)
|
21
|
+
prog = Minjs::Compressor::Compressor.new(:debug => false)
|
21
22
|
prog.compress(f.join("\n"), options)
|
22
23
|
puts prog.to_js(options)
|
data/lib/minjs.rb
CHANGED
@@ -1,15 +1,11 @@
|
|
1
1
|
require "minjs/version"
|
2
|
-
require "minjs/expression"
|
3
|
-
require "minjs/func"
|
4
2
|
require "minjs/lex"
|
5
|
-
require "minjs/program"
|
6
|
-
require "minjs/statement"
|
7
3
|
require "minjs/compressor"
|
8
4
|
require "minjs/ecma262"
|
9
5
|
require "minjs/minjs_compressor"
|
10
6
|
require "minjs/ctype"
|
11
|
-
require "minjs/exceptions"
|
12
7
|
|
8
|
+
# Minjs
|
13
9
|
module Minjs
|
14
10
|
# Your code goes here...
|
15
11
|
end
|
data/lib/minjs/compressor.rb
CHANGED
@@ -1,1144 +1,7 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# coding: utf-8
|
3
|
-
require 'minjs/lex'
|
4
|
-
require 'minjs/ecma262'
|
5
|
-
require 'minjs/statement'
|
6
|
-
require 'minjs/expression'
|
7
|
-
require 'minjs/func'
|
8
|
-
require 'minjs/program'
|
9
|
-
require 'minjs/exceptions'
|
10
|
-
require 'minjs/version'
|
11
|
-
require 'logger'
|
12
|
-
|
13
1
|
module Minjs
|
14
|
-
|
15
|
-
|
16
|
-
include Exp
|
17
|
-
include Func
|
18
|
-
include Program
|
19
|
-
include Ctype
|
20
|
-
|
21
|
-
attr_reader :prog
|
22
|
-
|
23
|
-
def initialize(options = {})
|
24
|
-
@logger = options[:logger]
|
25
|
-
if !@logger
|
26
|
-
@logger = Logger.new(STDERR)
|
27
|
-
@logger.level = (options[:debug_level] || Logger::WARN)
|
28
|
-
@logger.formatter = proc{|severity, datetime, progname, message|
|
29
|
-
"#{message}\n"
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def debug
|
35
|
-
puts @prog.to_js()
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_js(options = {})
|
39
|
-
remove_empty_statement
|
40
|
-
@prog.to_js(options).sub(/;;\Z/, ";")
|
41
|
-
end
|
42
|
-
|
43
|
-
def remove_empty_statement(node = @prog)
|
44
|
-
node.traverse(nil) {|st, parent|
|
45
|
-
if st.kind_of? ECMA262::StatementList
|
46
|
-
st.remove_empty_statement
|
47
|
-
end
|
48
|
-
}
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def compress(data, options = {})
|
53
|
-
@logger.info '* parse'
|
54
|
-
parse(data)
|
55
|
-
|
56
|
-
if options[:only_parse]
|
57
|
-
return
|
58
|
-
end
|
59
|
-
|
60
|
-
algo = [
|
61
|
-
:reorder_function_decl,
|
62
|
-
:simple_replacement,
|
63
|
-
:reorder_var,
|
64
|
-
:assignment_after_var,
|
65
|
-
:grouping_statement,
|
66
|
-
:block_to_statement,
|
67
|
-
:reduce_if,
|
68
|
-
:if_to_cond,
|
69
|
-
:optimize_if_return,
|
70
|
-
:compress_var,
|
71
|
-
:reduce_exp,
|
72
|
-
:grouping_statement,
|
73
|
-
:block_to_statement,
|
74
|
-
:if_to_cond,
|
75
|
-
:optimize_if_return2,
|
76
|
-
:block_to_statement,
|
77
|
-
:add_remove_paren,
|
78
|
-
]
|
79
|
-
algo.each do |a|
|
80
|
-
if (options.empty? || options[:all] || options[a]) && !options[("no_" + a.to_s).to_sym]
|
81
|
-
@logger.info "* #{a}"
|
82
|
-
__send__(a, @prog)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
@heading_comments.reverse.each do |c|
|
87
|
-
@prog.source_elements.source_elements.unshift(c)
|
88
|
-
end
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
def parse(data)
|
93
|
-
@lex = Minjs::Lex.new(data, :logger => @logger)
|
94
|
-
@global_context = ECMA262::Context.new
|
95
|
-
@heading_comments = []
|
96
|
-
|
97
|
-
while a = (@lex.comment || @lex.line_terminator || @lex.white_space)
|
98
|
-
@heading_comments.push(a)
|
99
|
-
end
|
100
|
-
while @heading_comments.last == ECMA262::LIT_LINE_FEED and
|
101
|
-
!(@heading_comments[-2].kind_of?(ECMA262::SingleLineComment))
|
102
|
-
@heading_comments.pop
|
103
|
-
end
|
104
|
-
@prog = program(@lex, @global_context)
|
105
|
-
|
106
|
-
remove_empty_statement
|
107
|
-
@lex.clear_cache
|
108
|
-
self
|
109
|
-
end
|
110
|
-
|
111
|
-
def next_sym(s)
|
112
|
-
def c2i(c)
|
113
|
-
c = c.ord
|
114
|
-
if c >= 0x30 and c <= 0x39
|
115
|
-
c = c - 0x30
|
116
|
-
elsif c >= 0x61 and c <= 0x7a
|
117
|
-
c = c - 0x61 + 10
|
118
|
-
elsif c >= 0x41 and c <= 0x5a
|
119
|
-
c = c - 0x41 + 10 + 26
|
120
|
-
elsif c == 0x5f
|
121
|
-
c = 62
|
122
|
-
elsif c == 0x24
|
123
|
-
c = 63
|
124
|
-
end
|
125
|
-
end
|
126
|
-
def i2c(c)
|
127
|
-
if c < 10
|
128
|
-
c = "%c" % (0x30 + c)
|
129
|
-
elsif c < 10 + 26
|
130
|
-
c = "%c" % (0x61 + c - 10)
|
131
|
-
elsif c < 10 + 26 + 26
|
132
|
-
c = "%c" % (0x41 + c - 10 - 26)
|
133
|
-
elsif c < 63
|
134
|
-
c = "_"
|
135
|
-
elsif c < 64
|
136
|
-
c = "$"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
v = 0
|
141
|
-
s.to_s.split("").each do |x|
|
142
|
-
v *= 64
|
143
|
-
v += c2i(x)
|
144
|
-
end
|
145
|
-
|
146
|
-
while true
|
147
|
-
v += 1
|
148
|
-
ret = []
|
149
|
-
vv = v
|
150
|
-
while vv > 0
|
151
|
-
ret.unshift(i2c(vv % 64))
|
152
|
-
vv /= 64
|
153
|
-
end
|
154
|
-
ret = ret.join("")
|
155
|
-
if ECMA262::IdentifierName.reserved?(ret.to_sym)
|
156
|
-
;
|
157
|
-
elsif ret.to_s.match(/^\d/)
|
158
|
-
;
|
159
|
-
else
|
160
|
-
break
|
161
|
-
end
|
162
|
-
end
|
163
|
-
ret.to_sym
|
164
|
-
|
165
|
-
end
|
166
|
-
|
167
|
-
def grouping_statement(node = @prog)
|
168
|
-
node.traverse(nil) {|st, parent|
|
169
|
-
if st.kind_of? ECMA262::StatementList
|
170
|
-
st.grouping
|
171
|
-
end
|
172
|
-
}
|
173
|
-
add_remove_paren
|
174
|
-
self
|
175
|
-
end
|
176
|
-
|
177
|
-
def reorder_function_decl(node = @prog)
|
178
|
-
flist = []
|
179
|
-
node.traverse(nil) {|st, parent|
|
180
|
-
if st.kind_of? ECMA262::StFunc and parent.kind_of? ECMA262::StatementList and st.decl?
|
181
|
-
if parent.index(st)
|
182
|
-
flist.push([st, parent])
|
183
|
-
end
|
184
|
-
end
|
185
|
-
}
|
186
|
-
flist.reverse.each do |st, parent|
|
187
|
-
parent.remove(st)
|
188
|
-
sl = parent.statement_list
|
189
|
-
if sl[0].kind_of? ECMA262::StExp and sl[0].exp.kind_of? ECMA262::ECMA262String and sl[0].exp.val == "use strict"
|
190
|
-
sl[1,0] = st
|
191
|
-
else
|
192
|
-
sl.unshift(st)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
self
|
196
|
-
end
|
197
|
-
|
198
|
-
def reorder_var(node = @prog)
|
199
|
-
node.traverse(nil) {|st, parent|
|
200
|
-
if st.kind_of? ECMA262::Prog
|
201
|
-
vars = nil
|
202
|
-
context = st.context
|
203
|
-
#
|
204
|
-
# collect all of var variable in this function
|
205
|
-
#
|
206
|
-
var_vars = {}
|
207
|
-
context.var_env.record.binding.each do|k, v|
|
208
|
-
if v and v[:_parameter_list].nil? and !v[:value].kind_of?(ECMA262::StFunc)
|
209
|
-
var_vars[k] = true
|
210
|
-
end
|
211
|
-
end
|
212
|
-
#
|
213
|
-
# traverse block and convert var statement to assignment expression
|
214
|
-
# if variable has initializer
|
215
|
-
#
|
216
|
-
st.traverse(parent){|st2, parent2|
|
217
|
-
if st2.kind_of? ECMA262::StVar and st2.context.var_env == context.var_env
|
218
|
-
exp = nil
|
219
|
-
st2.vars.each do |name, initializer|
|
220
|
-
if initializer
|
221
|
-
if exp.nil?
|
222
|
-
exp = ECMA262::ExpAssign.new(name, initializer)
|
223
|
-
else
|
224
|
-
exp = ECMA262::ExpComma.new(exp, ECMA262::ExpAssign.new(name, initializer))
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
if exp
|
229
|
-
parent2.replace(st2, ECMA262::StExp.new(exp))
|
230
|
-
else
|
231
|
-
parent2.replace(st2, ECMA262::StEmpty.new())
|
232
|
-
end
|
233
|
-
elsif st2.kind_of? ECMA262::StForVar and st2.context.var_env == context.var_env
|
234
|
-
parent2.replace(st2, st2.to_st_for)
|
235
|
-
elsif st2.kind_of? ECMA262::StForInVar and st2.context.var_env == context.var_env
|
236
|
-
parent2.replace(st2, st2.to_st_for_in)
|
237
|
-
end
|
238
|
-
}
|
239
|
-
if var_vars.length > 0
|
240
|
-
elems = st.source_elements.source_elements
|
241
|
-
v = ECMA262::StVar.new(
|
242
|
-
context,
|
243
|
-
var_vars.collect do |k, v|
|
244
|
-
[ECMA262::IdentifierName.new(context, k)]
|
245
|
-
end
|
246
|
-
)
|
247
|
-
|
248
|
-
idx = 0
|
249
|
-
elems.each do |e|
|
250
|
-
found = false
|
251
|
-
if e.kind_of? ECMA262::StFunc and e.decl?
|
252
|
-
;
|
253
|
-
elsif e.kind_of? ECMA262::StExp and e.exp.kind_of? ECMA262::ECMA262String and e.exp.val == "use strict"
|
254
|
-
;
|
255
|
-
else
|
256
|
-
e.traverse(nil){|ee, pp|
|
257
|
-
if ee.kind_of? ECMA262::IdentifierName and var_vars[ee.val.to_sym]
|
258
|
-
found = true
|
259
|
-
break
|
260
|
-
end
|
261
|
-
}
|
262
|
-
end
|
263
|
-
break if found
|
264
|
-
idx += 1
|
265
|
-
end
|
266
|
-
|
267
|
-
if idx == 0
|
268
|
-
elems.unshift(v)
|
269
|
-
else
|
270
|
-
elems[idx..0] = v
|
271
|
-
end
|
272
|
-
st.source_elements.remove_empty_statement
|
273
|
-
end
|
274
|
-
end
|
275
|
-
self
|
276
|
-
}
|
277
|
-
self
|
278
|
-
end
|
279
|
-
|
280
|
-
def add_remove_paren(node = @prog)
|
281
|
-
node.traverse(nil) {|st, parent|
|
282
|
-
if st.respond_to? :remove_paren
|
283
|
-
st.remove_paren
|
284
|
-
st.add_paren
|
285
|
-
end
|
286
|
-
}
|
287
|
-
self
|
288
|
-
end
|
289
|
-
|
290
|
-
def remove_paren(node = @prog)
|
291
|
-
add_remove_paren(node)
|
292
|
-
end
|
293
|
-
|
294
|
-
#
|
295
|
-
# To determine removing "block" is available or not is difficult.
|
296
|
-
# For example, next code's if-block must not be removed, because
|
297
|
-
# "else" cluase combined to second "if" statement.
|
298
|
-
#
|
299
|
-
# if(a){ //<= this block must not be removed
|
300
|
-
# while(true)
|
301
|
-
# if(b){
|
302
|
-
# ;
|
303
|
-
# }
|
304
|
-
# }
|
305
|
-
# else{
|
306
|
-
# ;
|
307
|
-
# }
|
308
|
-
#
|
309
|
-
# The next code's while-block must not be removed, because
|
310
|
-
# "else" cluase combined to second "if" statement.
|
311
|
-
#
|
312
|
-
# if(a)
|
313
|
-
# while(true){ //<= this block must not be removed
|
314
|
-
# if(b){
|
315
|
-
# ;
|
316
|
-
# }
|
317
|
-
# }
|
318
|
-
# else{
|
319
|
-
# ;
|
320
|
-
# }
|
321
|
-
#
|
322
|
-
# To solve this problem, first, every then-clause without block
|
323
|
-
# converts to block statement. After converted, all blocks
|
324
|
-
# except then-clause can be removed safety.
|
325
|
-
#
|
326
|
-
def then_to_block(node = @prog)
|
327
|
-
node.traverse(nil) {|st, parent|
|
328
|
-
if st.kind_of? ECMA262::StIf
|
329
|
-
if !st.then_st.kind_of?(ECMA262::StBlock)
|
330
|
-
st.replace(st.then_st, ECMA262::StBlock.new([st.then_st]))
|
331
|
-
end
|
332
|
-
end
|
333
|
-
}
|
334
|
-
end
|
335
|
-
|
336
|
-
def block_to_statement(node = @prog)
|
337
|
-
remove_empty_statement
|
338
|
-
then_to_block
|
339
|
-
node.traverse(nil) {|st, parent|
|
340
|
-
if st.kind_of? ECMA262::StBlock and !parent.kind_of?(ECMA262::StTry) and !parent.kind_of?(ECMA262::StIf)
|
341
|
-
if st.to_statement?
|
342
|
-
parent.replace(st, st.to_statement)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
}
|
346
|
-
if_block_to_statement
|
347
|
-
end
|
348
|
-
|
349
|
-
def if_block_to_statement(node = @prog)
|
350
|
-
remove_empty_statement
|
351
|
-
# The "else" cluase's block can be removed always
|
352
|
-
node.traverse(nil) {|st, parent|
|
353
|
-
if st.kind_of? ECMA262::StIf
|
354
|
-
if st.else_st and st.else_st.kind_of? ECMA262::StBlock
|
355
|
-
st.else_st.remove_empty_statement
|
356
|
-
end
|
357
|
-
|
358
|
-
if st.else_st and st.else_st.kind_of? ECMA262::StBlock and st.else_st.to_statement?
|
359
|
-
st.replace(st.else_st, st.else_st.to_statement)
|
360
|
-
end
|
361
|
-
end
|
362
|
-
}
|
363
|
-
node.traverse(nil) {|st, parent|
|
364
|
-
if st.kind_of? ECMA262::StIf
|
365
|
-
if st.then_st and st.then_st.kind_of? ECMA262::StBlock
|
366
|
-
st.then_st.remove_empty_statement
|
367
|
-
end
|
368
|
-
if !st.else_st and st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
|
369
|
-
st.replace(st.then_st, st.then_st.to_statement)
|
370
|
-
elsif st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
|
371
|
-
_st = st.then_st
|
372
|
-
st2 = st.then_st.to_statement
|
373
|
-
while true
|
374
|
-
if st2.kind_of? ECMA262::StVar or st2.kind_of? ECMA262::StEmpty or
|
375
|
-
st2.kind_of? ECMA262::StExp or st2.kind_of? ECMA262::StBlock or
|
376
|
-
st2.kind_of? ECMA262::StDoWhile or st2.kind_of? ECMA262::StSwitch or
|
377
|
-
st2.kind_of? ECMA262::StContinue or st2.kind_of? ECMA262::StBreak or
|
378
|
-
st2.kind_of? ECMA262::StReturn or st2.kind_of? ECMA262::StThrow or
|
379
|
-
st2.kind_of? ECMA262::StTry or st2.kind_of? ECMA262::StDebugger
|
380
|
-
st.replace(st.then_st, st.then_st.to_statement)
|
381
|
-
break;
|
382
|
-
elsif st2.kind_of? ECMA262::StWhile or
|
383
|
-
st2.kind_of? ECMA262::StFor or
|
384
|
-
st2.kind_of? ECMA262::StForIn or
|
385
|
-
st2.kind_of? ECMA262::StForVar or
|
386
|
-
st2.kind_of? ECMA262::StForInVar or
|
387
|
-
st2.kind_of? ECMA262::StWith or
|
388
|
-
st2.kind_of? ECMA262::StLabelled
|
389
|
-
st2 = st2.statement
|
390
|
-
elsif st2.kind_of? ECMA262::StIf
|
391
|
-
if st2.else_st
|
392
|
-
st2 = st2.else_st
|
393
|
-
else
|
394
|
-
break
|
395
|
-
end
|
396
|
-
else #?
|
397
|
-
break
|
398
|
-
end
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|
402
|
-
}
|
403
|
-
=begin
|
404
|
-
node.traverse(nil) {|st0, parent|
|
405
|
-
st = st0.deep_dup
|
406
|
-
if st.kind_of? ECMA262::StIf
|
407
|
-
if st.then_st and st.then_st.kind_of? ECMA262::StBlock
|
408
|
-
st.then_st.remove_empty_statement
|
409
|
-
end
|
410
|
-
|
411
|
-
if st.then_st and st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
|
412
|
-
st.replace(st.then_st, st.then_st.to_statement)
|
413
|
-
end
|
414
|
-
|
415
|
-
_lex = Minjs::Lex.new(st.to_js)
|
416
|
-
_context = ECMA262::Context.new
|
417
|
-
_if = if_statement(_lex, _context)
|
418
|
-
reduce_exp(_if)
|
419
|
-
if _if == st #
|
420
|
-
if st0.then_st and st0.then_st.kind_of? ECMA262::StBlock
|
421
|
-
st0.then_st.remove_empty_statement
|
422
|
-
end
|
423
|
-
if st0.then_st and st0.then_st.kind_of? ECMA262::StBlock and st0.then_st.to_statement?
|
424
|
-
st0.replace(st0.then_st, st0.then_st.to_statement)
|
425
|
-
end
|
426
|
-
else
|
427
|
-
p '!='
|
428
|
-
puts st.to_js
|
429
|
-
puts _if.to_js
|
430
|
-
end
|
431
|
-
end
|
432
|
-
}
|
433
|
-
=end
|
434
|
-
self
|
435
|
-
end
|
436
|
-
|
437
|
-
#
|
438
|
-
# if(a)b;else c;
|
439
|
-
# =>
|
440
|
-
# a?b:c
|
441
|
-
#
|
442
|
-
# if(a)b
|
443
|
-
# =>
|
444
|
-
# a&&b; or a?b:0;
|
445
|
-
#
|
446
|
-
# NOTE:
|
447
|
-
# Sometimes, "conditional operator" will be shorter than
|
448
|
-
# "logical and operator", because "conditional operator"'s
|
449
|
-
# priority is lower than almost all other expressions.
|
450
|
-
#
|
451
|
-
def if_to_cond(node = @prog)
|
452
|
-
node.traverse(nil) {|st, parent|
|
453
|
-
if st.kind_of? ECMA262::StIf
|
454
|
-
if st.to_exp?
|
455
|
-
t = ECMA262::StExp.new(st.to_exp({}))
|
456
|
-
t2 = ECMA262::StExp.new(st.to_exp({cond: true}))
|
457
|
-
if t2.to_js.length < t.to_js.length
|
458
|
-
t = t2
|
459
|
-
end
|
460
|
-
add_remove_paren(t)
|
461
|
-
simple_replacement(t)
|
462
|
-
|
463
|
-
if t.to_js.length <= st.to_js.length
|
464
|
-
parent.replace(st, t)
|
465
|
-
end
|
466
|
-
end
|
467
|
-
end
|
468
|
-
}
|
469
|
-
if_to_return(node)
|
470
|
-
self
|
471
|
-
end
|
472
|
-
#
|
473
|
-
# if(a)return b;else return c;
|
474
|
-
# => return a?b:c;
|
475
|
-
#
|
476
|
-
def if_to_return(node = @prog)
|
477
|
-
node.traverse(nil) {|st, parent|
|
478
|
-
if st.kind_of? ECMA262::StIf
|
479
|
-
if st.to_return?
|
480
|
-
t = st.to_return
|
481
|
-
add_remove_paren(t)
|
482
|
-
simple_replacement(t)
|
483
|
-
if t.to_js.length <= st.to_js.length
|
484
|
-
parent.replace(st, t)
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
}
|
489
|
-
self
|
490
|
-
end
|
491
|
-
|
492
|
-
#
|
493
|
-
# if(a)return b;
|
494
|
-
# return c;
|
495
|
-
#
|
496
|
-
# => return a?b:c;
|
497
|
-
#
|
498
|
-
def optimize_if_return(node = @prog)
|
499
|
-
node.traverse(nil) {|st0, parent0|
|
500
|
-
if st0.kind_of? ECMA262::StatementList
|
501
|
-
st0.remove_empty_statement
|
502
|
-
st = st0.deep_dup
|
503
|
-
while true
|
504
|
-
#check last statement
|
505
|
-
ls = st.statement_list[-1]
|
506
|
-
ls2 = st.statement_list[-2]
|
507
|
-
if st.kind_of? ECMA262::SourceElements and !(ls.kind_of? ECMA262::StReturn)
|
508
|
-
ls2 = ls
|
509
|
-
ls = ECMA262::StReturn.new(ECMA262::ExpVoid.new(ECMA262::ECMA262Numeric.new(0)))
|
510
|
-
end
|
511
|
-
break if ls.nil?
|
512
|
-
break if ls2.nil?
|
513
|
-
break if !ls.to_return?
|
514
|
-
break if !ls2.kind_of?(ECMA262::StIf)
|
515
|
-
break if ls2.else_st
|
516
|
-
break if !ls2.then_st.to_return?
|
517
|
-
|
518
|
-
# if !ls2.then_st.kind_of? ECMA262::StIf and !ls2.then_st.to_return?
|
519
|
-
# break
|
520
|
-
# end
|
521
|
-
# if ls2.then_st.kind_of? ECMA262::StIf and !ls2.then_to_return?
|
522
|
-
# break
|
523
|
-
# end
|
524
|
-
|
525
|
-
then_exp = ls2.then_st.to_return.exp
|
526
|
-
else_exp = ls.to_return.exp
|
527
|
-
then_exp = ECMA262::ExpVoid.new(ECMA262::ECMA262Numeric.new(0)) if then_exp.nil?
|
528
|
-
else_exp = ECMA262::ExpVoid.new(ECMA262::ECMA262Numeric.new(0)) if else_exp.nil?
|
529
|
-
if ls2.cond.kind_of? ECMA262::ExpLogicalNot
|
530
|
-
cond = ECMA262::ExpCond.new(ls2.cond.val, else_exp, then_exp)
|
531
|
-
else
|
532
|
-
cond = ECMA262::ExpCond.new(ls2.cond, then_exp, else_exp)
|
533
|
-
end
|
534
|
-
ret = ECMA262::StReturn.new(cond)
|
535
|
-
#puts ret.to_js
|
536
|
-
#puts ls2.to_js
|
537
|
-
st.replace(ls2, ret)
|
538
|
-
st.remove(ls)
|
539
|
-
end
|
540
|
-
if st0.to_js.length > st.to_js.length
|
541
|
-
parent0.replace(st0, st)
|
542
|
-
end
|
543
|
-
end
|
544
|
-
}
|
545
|
-
self
|
546
|
-
end
|
547
|
-
|
548
|
-
#
|
549
|
-
# if(a)return b;else c;
|
550
|
-
# =>
|
551
|
-
# if(a)return b;c;
|
552
|
-
#
|
553
|
-
def optimize_if_return2(node = @prog)
|
554
|
-
node.traverse(nil) {|st, parent|
|
555
|
-
if st.kind_of? ECMA262::StIf and st.else_st and parent.kind_of? ECMA262::StatementList
|
556
|
-
st.remove_empty_statement
|
557
|
-
if (st.then_st.kind_of? ECMA262::StBlock and st.then_st[-1].kind_of? ECMA262::StReturn) or
|
558
|
-
st.then_st.kind_of? ECMA262::StReturn
|
559
|
-
idx = parent.index(st)
|
560
|
-
parent[idx+1..0] = st.else_st
|
561
|
-
st.replace(st.else_st, nil)
|
562
|
-
elsif (st.else_st.kind_of? ECMA262::StBlock and st.else_st[-1].kind_of? ECMA262::StReturn) or
|
563
|
-
st.else_st.kind_of? ECMA262::StReturn
|
564
|
-
idx = parent.index(st)
|
565
|
-
parent[idx+1..0] = st.then_st
|
566
|
-
st.instance_eval{
|
567
|
-
@then_st = @else_st
|
568
|
-
@else_st = nil
|
569
|
-
@cond = ECMA262::ExpLogicalNot.new(@cond)
|
570
|
-
}
|
571
|
-
end
|
572
|
-
end
|
573
|
-
}
|
574
|
-
self
|
575
|
-
end
|
576
|
-
|
577
|
-
def compress_var(node = @prog, options = {})
|
578
|
-
func_scopes = []
|
579
|
-
catch_scopes = []
|
580
|
-
with_scopes = []
|
581
|
-
#
|
582
|
-
# ECMA262 10.2:
|
583
|
-
#
|
584
|
-
# Usually a Lexical Environment is associated with some
|
585
|
-
# specific syntactic structure of ECMAScript code such as a
|
586
|
-
# FunctionDeclaration, a WithStatement, or a Catch clause of a
|
587
|
-
# TryStatement and a new Lexical Environment is created each
|
588
|
-
# time such code is evaluated.
|
589
|
-
#
|
590
|
-
node.traverse(nil) {|st, parent|
|
591
|
-
if st.kind_of? ECMA262::StFunc
|
592
|
-
func_scopes.push([st, parent])
|
593
|
-
elsif st.kind_of? ECMA262::StTry
|
594
|
-
catch_scopes.push([st, parent])
|
595
|
-
elsif st.kind_of? ECMA262::StWith
|
596
|
-
with_scopes.push([st, parent])
|
597
|
-
end
|
598
|
-
}
|
599
|
-
#
|
600
|
-
# 10.2, 12.14
|
601
|
-
#
|
602
|
-
#eee = 'global';
|
603
|
-
#function test()
|
604
|
-
#{
|
605
|
-
# /*
|
606
|
-
# "eee" is local variable(belongs to this function)
|
607
|
-
# because var declaration is exist in this function.
|
608
|
-
# (see also catch's scope comment)
|
609
|
-
# So, global variable 'eee' is not changed.
|
610
|
-
# */
|
611
|
-
# eee = 'function';
|
612
|
-
# try{
|
613
|
-
# console.log(eee); //=>function
|
614
|
-
# throw "exception";
|
615
|
-
# }
|
616
|
-
# catch(eee){
|
617
|
-
# /*
|
618
|
-
# The catch's variable scope will be created at execution time.
|
619
|
-
# so next var declaration should belong to "test" function.
|
620
|
-
# */
|
621
|
-
# var eee;
|
622
|
-
# /*
|
623
|
-
# In execution time, "eee" belongs to this
|
624
|
-
# catch-clause's scope.
|
625
|
-
# */
|
626
|
-
# console.log(eee); //=>exception
|
627
|
-
# /*
|
628
|
-
# Next function has its own scope and 'eee' belongs to its.
|
629
|
-
# */
|
630
|
-
# (function(){
|
631
|
-
# var eee;
|
632
|
-
# console.log(eee); //=>undefined
|
633
|
-
# })();
|
634
|
-
# }
|
635
|
-
#}
|
636
|
-
#console.log(eee); //=>global
|
637
|
-
#test();
|
638
|
-
#
|
639
|
-
catch_scopes.each{|st, parent|
|
640
|
-
if st.catch
|
641
|
-
catch_context = ECMA262::Context.new
|
642
|
-
catch_context.lex_env = st.context.lex_env.new_declarative_env()
|
643
|
-
catch_context.var_env = st.context.var_env
|
644
|
-
catch_context.lex_env.record.create_mutable_binding(st.catch[0], nil)
|
645
|
-
catch_context.lex_env.record.set_mutable_binding(st.catch[0], :undefined, nil)
|
646
|
-
st.catch[0].context = catch_context
|
647
|
-
|
648
|
-
st.catch[1].traverse(parent){|st2|
|
649
|
-
if st2.kind_of? ECMA262::IdentifierName and st2 == st.catch[0] and st2.binding_env == st.catch[0].binding_env
|
650
|
-
st2.context = catch_context
|
651
|
-
end
|
652
|
-
}
|
653
|
-
func_scopes.unshift([st, parent])
|
654
|
-
end
|
655
|
-
}
|
656
|
-
# with_scopes.each{|st, parent|
|
657
|
-
# with_context = ECMA262::Context.new
|
658
|
-
# with_context.lex_env = st.context.lex_env.new_declarative_env()
|
659
|
-
# with_context.var_env = st.context.var_env
|
660
|
-
# st.statement.traverse(st) {|st2|
|
661
|
-
# if st2.kind_of? ECMA262::IdentifierName and st2.binding_env == st.context.var_env
|
662
|
-
# st2.context = with_context
|
663
|
-
# with_context.lex_env.record.create_mutable_binding(st2, nil)
|
664
|
-
# with_context.lex_env.record.set_mutable_binding(st2, :undefined, nil)
|
665
|
-
# end
|
666
|
-
# }
|
667
|
-
# }
|
668
|
-
func_scopes.reverse!
|
669
|
-
func_scopes.each {|st, parent|
|
670
|
-
if st.kind_of? ECMA262::StFunc
|
671
|
-
context = st.context
|
672
|
-
elsif st.kind_of? ECMA262::StTry
|
673
|
-
context = st.catch[0].context
|
674
|
-
end
|
675
|
-
var_sym = :a
|
676
|
-
#
|
677
|
-
# collect and counting all variables under this function
|
678
|
-
#
|
679
|
-
all_vars = {}
|
680
|
-
var_vars = {}
|
681
|
-
var_vars_list = []
|
682
|
-
outer_vars = {}
|
683
|
-
nesting_vars = {}
|
684
|
-
nesting_vars_list = []
|
685
|
-
|
686
|
-
st.traverse(parent) {|st2|
|
687
|
-
#
|
688
|
-
# Next, tring to rename var_vars(see bellow) to
|
689
|
-
# new name.
|
690
|
-
#
|
691
|
-
# 1. outer_vars:
|
692
|
-
# Variables which locate out of this function(or global variable)
|
693
|
-
# Them name cannot be renamed
|
694
|
-
# 2. nesting_vars:
|
695
|
-
# Variables which locate in the function of this function.
|
696
|
-
# Them name cannot be renamed
|
697
|
-
# 3. var_vars:
|
698
|
-
# Variables which have same scope in this function.
|
699
|
-
# 4. all_vars:
|
700
|
-
# All variables under this function.
|
701
|
-
#
|
702
|
-
# a. If the new name is not in all_vars, the name can be renamed to it.
|
703
|
-
# b. If the new name belongs to var_vars, the name cannot be renamed.
|
704
|
-
# c. If the new name belongs to outer_vars the name cannot be renamed.
|
705
|
-
# d. If the new name belongs to nesting_vars, the name can be rename
|
706
|
-
# to it after renaming nesting_vars's name to another name.
|
707
|
-
#
|
708
|
-
if st2.kind_of? ECMA262::IdentifierName
|
709
|
-
var_name = st2.val.to_sym
|
710
|
-
#st2_var_env = st2.binding_env
|
711
|
-
st2_lex_env = st2.binding_env(:lex)
|
712
|
-
all_vars[var_name] ||= 0
|
713
|
-
all_vars[var_name] += 1
|
714
|
-
if st2_lex_env == nil #global
|
715
|
-
outer_vars[var_name] ||= 0
|
716
|
-
outer_vars[var_name] += 1
|
717
|
-
elsif st2_lex_env == @global_context.lex_env #global
|
718
|
-
outer_vars[var_name] ||= 0
|
719
|
-
outer_vars[var_name] += 1
|
720
|
-
elsif st2_lex_env == context.lex_env
|
721
|
-
var_vars[var_name] ||= 0
|
722
|
-
var_vars[var_name] += 1
|
723
|
-
var_vars_list.push(st2)
|
724
|
-
else
|
725
|
-
e = st2.binding_env(:lex)
|
726
|
-
while e
|
727
|
-
e = e.outer
|
728
|
-
if e == context.lex_env
|
729
|
-
nesting_vars[var_name] ||= 0
|
730
|
-
nesting_vars[var_name] += 1
|
731
|
-
nesting_vars_list.push(st2)
|
732
|
-
break
|
733
|
-
end
|
734
|
-
if e.nil?
|
735
|
-
outer_vars[var_name] ||= 0
|
736
|
-
outer_vars[var_name] += 1
|
737
|
-
break
|
738
|
-
end
|
739
|
-
end
|
740
|
-
end
|
741
|
-
end
|
742
|
-
}
|
743
|
-
unless var_vars[:eval]
|
744
|
-
eval_flag = false
|
745
|
-
st.traverse(parent) {|st2|
|
746
|
-
if st2.kind_of? ECMA262::ExpCall and st2.name.to_js({}) == "eval"
|
747
|
-
eval_flag = true
|
748
|
-
break
|
749
|
-
end
|
750
|
-
if st2.kind_of? ECMA262::StWith
|
751
|
-
eval_flag = true
|
752
|
-
break
|
753
|
-
end
|
754
|
-
}
|
755
|
-
if eval_flag
|
756
|
-
next
|
757
|
-
end
|
758
|
-
end
|
759
|
-
#
|
760
|
-
# sort var_vars
|
761
|
-
#
|
762
|
-
var_vars_array = var_vars.sort {|(k1,v1), (k2,v2)| v2 <=> v1}
|
763
|
-
#
|
764
|
-
# create renaming table
|
765
|
-
#
|
766
|
-
rename_table = {}
|
767
|
-
var_vars_array.each {|name, count|
|
768
|
-
if name.nil?
|
769
|
-
next #bug?
|
770
|
-
end
|
771
|
-
if name.length == 1
|
772
|
-
#STDERR.puts "#{name}=>#{count}"
|
773
|
-
next
|
774
|
-
end
|
775
|
-
#STDERR.puts "trying to rename #{name}(#{count})"
|
776
|
-
while true
|
777
|
-
#condition b
|
778
|
-
if outer_vars[var_sym]
|
779
|
-
#STDERR.puts "outer_vars has #{var_sym}"
|
780
|
-
elsif var_vars[var_sym]
|
781
|
-
#STDERR.puts "var_vars has #{var_sym}(#{var_vars[var_sym]})"
|
782
|
-
#condigion c
|
783
|
-
else #condition a&d
|
784
|
-
#STDERR.puts "->#{var_sym}"
|
785
|
-
break
|
786
|
-
end
|
787
|
-
var_sym = next_sym(var_sym)
|
788
|
-
end
|
789
|
-
#rename nesting_vars
|
790
|
-
if nesting_vars[var_sym]
|
791
|
-
#STDERR.puts "nesting_vars has #{var_sym}"
|
792
|
-
nesting_vars_list.each do |x|
|
793
|
-
#raise 'error' if x.binding_env(:var).nil?
|
794
|
-
raise 'error' if x.binding_env(:lex).nil?
|
795
|
-
end
|
796
|
-
|
797
|
-
var_sym2 = "XXX#{var_sym.to_s}".to_sym
|
798
|
-
while all_vars[var_sym2]
|
799
|
-
var_sym2 = next_sym(var_sym2)
|
800
|
-
end
|
801
|
-
#STDERR.puts "#{var_sym}->#{var_sym2}"
|
802
|
-
rl = {}
|
803
|
-
nesting_vars_list.each do |x|
|
804
|
-
if x.val.to_sym == var_sym
|
805
|
-
_var_env = x.binding_env(:var)
|
806
|
-
_lex_env = x.binding_env(:lex)
|
807
|
-
rl[_var_env] = true
|
808
|
-
rl[_lex_env] = true
|
809
|
-
end
|
810
|
-
end
|
811
|
-
rl.keys.each do |_env|
|
812
|
-
if _env && _env.record.binding[var_sym]
|
813
|
-
_env.record.binding[var_sym2] = _env.record.binding[var_sym]
|
814
|
-
_env.record.binding.delete var_sym
|
815
|
-
end
|
816
|
-
end
|
817
|
-
|
818
|
-
nesting_vars_list.each do |x|
|
819
|
-
if x.val.to_sym == var_sym
|
820
|
-
x.instance_eval{
|
821
|
-
@val = var_sym2
|
822
|
-
}
|
823
|
-
end
|
824
|
-
#raise 'error' if x.binding_env(:var).nil?
|
825
|
-
raise x.to_js if x.binding_env(:lex).nil?
|
826
|
-
end
|
827
|
-
end
|
828
|
-
rename_table[name] = var_sym
|
829
|
-
var_sym = next_sym(var_sym)
|
830
|
-
}
|
831
|
-
var_vars_list.each {|st2|
|
832
|
-
raise st2.to_js if st2.binding_env(:lex).nil?
|
833
|
-
}
|
834
|
-
|
835
|
-
rename_table.each do |name, new_name|
|
836
|
-
if name != new_name
|
837
|
-
if context.var_env.record.binding[name]
|
838
|
-
context.var_env.record.binding[new_name] = context.var_env.record.binding[name]
|
839
|
-
context.var_env.record.binding.delete(name)
|
840
|
-
end
|
841
|
-
if context.lex_env.record.binding[name]
|
842
|
-
context.lex_env.record.binding[new_name] = context.lex_env.record.binding[name]
|
843
|
-
context.lex_env.record.binding.delete(name)
|
844
|
-
end
|
845
|
-
end
|
846
|
-
end
|
847
|
-
|
848
|
-
var_vars_list.each {|st2|
|
849
|
-
st2.instance_eval{
|
850
|
-
if rename_table[@val]
|
851
|
-
@val = rename_table[@val]
|
852
|
-
#raise 'error' if st2.binding_env(:var).nil?
|
853
|
-
raise st2.to_js if st2.binding_env(:lex).nil?
|
854
|
-
end
|
855
|
-
}
|
856
|
-
}
|
857
|
-
}
|
858
|
-
self
|
859
|
-
end
|
860
|
-
|
861
|
-
def reduce_exp(node = @prog)
|
862
|
-
node.traverse(nil) {|st, parent|
|
863
|
-
if st.kind_of? ECMA262::Exp
|
864
|
-
st.reduce(parent)
|
865
|
-
end
|
866
|
-
}
|
867
|
-
self
|
868
|
-
end
|
869
|
-
|
870
|
-
def simple_replacement(node = @prog)
|
871
|
-
node.traverse(nil) {|st, parent|
|
872
|
-
#
|
873
|
-
#true => !0
|
874
|
-
#false => !1
|
875
|
-
#
|
876
|
-
if st.kind_of? ECMA262::Boolean
|
877
|
-
if st.true?
|
878
|
-
parent.replace(st, ECMA262::ExpParen.new(ECMA262::ExpLogicalNot.new(ECMA262::ECMA262Numeric.new(0))))
|
879
|
-
else
|
880
|
-
parent.replace(st, ECMA262::ExpParen.new(ECMA262::ExpLogicalNot.new(ECMA262::ECMA262Numeric.new(1))))
|
881
|
-
end
|
882
|
-
#
|
883
|
-
#if(true){<then>}else{<else>} => <then>
|
884
|
-
#if(false){<then>}else{<else>} => <else>
|
885
|
-
#
|
886
|
-
elsif st.kind_of? ECMA262::StIf
|
887
|
-
if st.cond.respond_to? :to_ecma262_boolean
|
888
|
-
if st.cond.to_ecma262_boolean.nil?
|
889
|
-
;
|
890
|
-
elsif st.cond.to_ecma262_boolean == true
|
891
|
-
parent.replace(st, st.then_st)
|
892
|
-
elsif st.cond.to_ecma262_boolean == false and st.else_st
|
893
|
-
parent.replace(st, st.else_st)
|
894
|
-
elsif st.cond.to_ecma262_boolean == false
|
895
|
-
parent.replace(st, ECMA262::StEmpty.new)
|
896
|
-
end
|
897
|
-
end
|
898
|
-
#
|
899
|
-
# while(true) => for(;;)
|
900
|
-
# while(false) => remove
|
901
|
-
#
|
902
|
-
elsif st.kind_of? ECMA262::StWhile and st.exp.respond_to? :to_ecma262_boolean
|
903
|
-
if st.exp.to_ecma262_boolean.nil?
|
904
|
-
;
|
905
|
-
elsif st.exp.to_ecma262_boolean
|
906
|
-
parent.replace(st, ECMA262::StFor.new(nil,nil,nil, st.statement))
|
907
|
-
else
|
908
|
-
parent.replace(st, ECMA262::StEmpty.new)
|
909
|
-
end
|
910
|
-
#
|
911
|
-
# new A() => (new A)
|
912
|
-
#
|
913
|
-
elsif st.kind_of? ECMA262::ExpNew and st.args and st.args.length == 0
|
914
|
-
st.replace(st.args, nil)
|
915
|
-
parent.add_paren.remove_paren
|
916
|
-
#
|
917
|
-
# !c?a:b => c?b:a
|
918
|
-
# true?a:b => a
|
919
|
-
# false?a:b => b
|
920
|
-
#
|
921
|
-
elsif st.kind_of? ECMA262::ExpCond
|
922
|
-
if st.val.kind_of? ECMA262::ExpLogicalNot
|
923
|
-
st.instance_eval{
|
924
|
-
@val = @val.val
|
925
|
-
t = @val2
|
926
|
-
@val2 = @val3
|
927
|
-
@val3 = t
|
928
|
-
}
|
929
|
-
simple_replacement(st)
|
930
|
-
end
|
931
|
-
|
932
|
-
if st.val.respond_to? :to_ecma262_boolean
|
933
|
-
if st.val.to_ecma262_boolean.nil?
|
934
|
-
;
|
935
|
-
elsif st.val.to_ecma262_boolean
|
936
|
-
parent.replace(st, st.val2)
|
937
|
-
else
|
938
|
-
parent.replace(st, st.val3)
|
939
|
-
end
|
940
|
-
end
|
941
|
-
#
|
942
|
-
# A["B"] => A.N
|
943
|
-
#
|
944
|
-
elsif st.kind_of? ECMA262::ExpPropBrac and st.val2.kind_of? ECMA262::ECMA262String
|
945
|
-
if idname?(st.val2.val)
|
946
|
-
parent.replace(st, ECMA262::ExpProp.new(st.val, st.val2))
|
947
|
-
elsif !st.val2.to_ecma262_number.nil? and (v=ECMA262::ECMA262Numeric.new(st.val2.to_ecma262_number)).to_ecma262_string == st.val2.to_ecma262_string
|
948
|
-
st.replace(st.val2, v)
|
949
|
-
end
|
950
|
-
end
|
951
|
-
}
|
952
|
-
self
|
953
|
-
end
|
954
|
-
|
955
|
-
#
|
956
|
-
# reduce_if
|
957
|
-
#
|
958
|
-
def reduce_if(node = @prog)
|
959
|
-
retry_flag = true
|
960
|
-
while retry_flag
|
961
|
-
retry_flag = false
|
962
|
-
node.traverse(nil) {|st, parent|
|
963
|
-
if st.kind_of? ECMA262::StIf
|
964
|
-
# if(a)
|
965
|
-
# if(b) ...;
|
966
|
-
# if(a && b) ...;
|
967
|
-
#
|
968
|
-
if st.else_st.nil? and
|
969
|
-
st.then_st.kind_of? ECMA262::StIf and st.then_st.else_st.nil?
|
970
|
-
st.replace(st.cond, ECMA262::ExpLogicalAnd.new(st.cond, st.then_st.cond))
|
971
|
-
st.replace(st.then_st, st.then_st.then_st)
|
972
|
-
end
|
973
|
-
#if(a)z;else;
|
974
|
-
#if(a)z;else{}
|
975
|
-
# => {if(a)z;}
|
976
|
-
if st.else_st and st.else_st.empty?
|
977
|
-
st.replace(st.else_st, nil)
|
978
|
-
parent.replace(st, ECMA262::StBlock.new([st]))
|
979
|
-
retry_flag = true
|
980
|
-
break
|
981
|
-
end
|
982
|
-
#if(a);else z;
|
983
|
-
#=>{if(!a)z};
|
984
|
-
#if(a){}else z;
|
985
|
-
#=>{if(!a)z};
|
986
|
-
if st.then_st.empty? and st.else_st
|
987
|
-
st.replace(st.cond, ECMA262::ExpLogicalNot.new(st.cond));
|
988
|
-
else_st = st.else_st
|
989
|
-
st.replace(st.else_st, nil)
|
990
|
-
st.replace(st.then_st, else_st)
|
991
|
-
parent.replace(st, ECMA262::StBlock.new([st]))
|
992
|
-
retry_flag = true
|
993
|
-
break
|
994
|
-
end
|
995
|
-
#if(a);
|
996
|
-
# => a
|
997
|
-
#if(a){}
|
998
|
-
# => a
|
999
|
-
if st.then_st.empty? and st.else_st.nil?
|
1000
|
-
parent.replace(st, ECMA262::StExp.new(st.cond))
|
1001
|
-
end
|
1002
|
-
=begin
|
1003
|
-
#if(!(a&&b))
|
1004
|
-
#=>
|
1005
|
-
#if(!a||!b)
|
1006
|
-
if st.cond.kind_of? ECMA262::ExpLogicalNot and st.cond.val.kind_of? ECMA262::ExpParen and
|
1007
|
-
st.cond.val.val.kind_of? ECMA262::ExpLogicalAnd
|
1008
|
-
a = ECMA262::ExpLogicalNot.new(st.cond.val.val.val)
|
1009
|
-
b = ECMA262::ExpLogicalNot.new(st.cond.val.val.val2)
|
1010
|
-
r = ECMA262::ExpLogicalOr.new(a,b).add_remove_paren
|
1011
|
-
if r.to_js.length <= st.cond.to_js.length
|
1012
|
-
st.replace(st.cond, r)
|
1013
|
-
end
|
1014
|
-
end
|
1015
|
-
#if(!(a||b))
|
1016
|
-
#=>
|
1017
|
-
#if(!a&&!b)
|
1018
|
-
if st.cond.kind_of? ECMA262::ExpLogicalNot and st.cond.val.kind_of? ECMA262::ExpParen and
|
1019
|
-
st.cond.val.val.kind_of? ECMA262::ExpLogicalOr
|
1020
|
-
a = ECMA262::ExpLogicalNot.new(st.cond.val.val.val)
|
1021
|
-
b = ECMA262::ExpLogicalNot.new(st.cond.val.val.val2)
|
1022
|
-
r = ECMA262::ExpLogicalAnd.new(a,b).add_remove_paren
|
1023
|
-
if r.to_js.length <= st.cond.to_js.length
|
1024
|
-
st.replace(st.cond, r)
|
1025
|
-
end
|
1026
|
-
end
|
1027
|
-
=end
|
1028
|
-
#if((a))
|
1029
|
-
if st.cond.kind_of? ECMA262::ExpParen
|
1030
|
-
st.replace(st.cond, st.cond.val)
|
1031
|
-
end
|
1032
|
-
#if(!!a)
|
1033
|
-
if st.cond.kind_of? ECMA262::ExpLogicalNot and st.cond.val.kind_of? ECMA262::ExpLogicalNot
|
1034
|
-
st.replace(st.cond, st.cond.val.val)
|
1035
|
-
end
|
1036
|
-
end
|
1037
|
-
}
|
1038
|
-
end
|
1039
|
-
block_to_statement
|
1040
|
-
self
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
def assignment_after_var(node = @prog)
|
1044
|
-
def rewrite_var(var_st, name, initializer)
|
1045
|
-
var_st.normalization
|
1046
|
-
i = 0
|
1047
|
-
var_st.vars.each do |_name, _initializer|
|
1048
|
-
if _name == name and _initializer.nil?
|
1049
|
-
var_st.vars[i] = [name, initializer]
|
1050
|
-
var_st.normalization
|
1051
|
-
return true
|
1052
|
-
end
|
1053
|
-
i += 1
|
1054
|
-
end
|
1055
|
-
false
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
retry_flag = true
|
1059
|
-
while retry_flag
|
1060
|
-
retry_flag = false
|
1061
|
-
node.traverse(nil) {|st, parent|
|
1062
|
-
if st.kind_of? ECMA262::StVar and parent.kind_of? ECMA262::SourceElements
|
1063
|
-
catch(:break){
|
1064
|
-
idx = parent.index(st) + 1
|
1065
|
-
while true
|
1066
|
-
st2 = parent[idx]
|
1067
|
-
if st2.kind_of? ECMA262::StEmpty or (st2.kind_of? ECMA262::StFunc and st2.decl?)
|
1068
|
-
idx +=1
|
1069
|
-
next
|
1070
|
-
elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpAssign
|
1071
|
-
if rewrite_var(st, st2.exp.val, st2.exp.val2)
|
1072
|
-
parent.replace(st2, ECMA262::StEmpty.new())
|
1073
|
-
retry_flag = true
|
1074
|
-
else
|
1075
|
-
throw :break
|
1076
|
-
end
|
1077
|
-
idx += 1
|
1078
|
-
next
|
1079
|
-
elsif st2.kind_of? ECMA262::StFor and st2.exp1.kind_of? ECMA262::ExpAssign
|
1080
|
-
if rewrite_var(st, st2.exp1.val, st2.exp1.val2)
|
1081
|
-
st2.replace(st2.exp1, nil)
|
1082
|
-
retry_flag = true
|
1083
|
-
else
|
1084
|
-
throw :break
|
1085
|
-
end
|
1086
|
-
throw :break
|
1087
|
-
elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpComma
|
1088
|
-
exp_parent = st2
|
1089
|
-
exp = st2.exp
|
1090
|
-
|
1091
|
-
while exp.val.kind_of? ECMA262::ExpComma
|
1092
|
-
exp_parent = exp
|
1093
|
-
exp = exp.val
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
if exp.val.kind_of? ECMA262::ExpAssign
|
1097
|
-
if rewrite_var(st, exp.val.val, exp.val.val2)
|
1098
|
-
exp_parent.replace(exp, exp.val2)
|
1099
|
-
retry_flag = true
|
1100
|
-
else
|
1101
|
-
throw :break
|
1102
|
-
end
|
1103
|
-
else
|
1104
|
-
throw :break
|
1105
|
-
end
|
1106
|
-
else
|
1107
|
-
throw :break
|
1108
|
-
end
|
1109
|
-
end
|
1110
|
-
}
|
1111
|
-
end
|
1112
|
-
}
|
1113
|
-
end
|
1114
|
-
self
|
1115
|
-
end
|
2
|
+
# Compressor
|
3
|
+
module Compressor
|
1116
4
|
end
|
1117
5
|
end
|
1118
6
|
|
1119
|
-
|
1120
|
-
argv = ARGV.dup
|
1121
|
-
f = []
|
1122
|
-
options = {}
|
1123
|
-
argv.each do |x|
|
1124
|
-
if x.match(/^--?version/)
|
1125
|
-
puts Minjs::VERSION
|
1126
|
-
exit(0)
|
1127
|
-
elsif x.match(/^--?/)
|
1128
|
-
opt = $'.gsub(/-/, '_').to_sym
|
1129
|
-
options[opt] = true
|
1130
|
-
else
|
1131
|
-
f.push(open(x.to_s).read())
|
1132
|
-
end
|
1133
|
-
end
|
1134
|
-
|
1135
|
-
js = f.join("\n")
|
1136
|
-
|
1137
|
-
comp = Minjs::Compressor.new(:debug => false)
|
1138
|
-
comp.compress(js, options)
|
1139
|
-
comp_js = comp.to_js(options)
|
1140
|
-
#p comp_js.length
|
1141
|
-
js = comp_js
|
1142
|
-
puts js
|
1143
|
-
|
1144
|
-
end
|
7
|
+
require 'minjs/compressor/compressor'
|