lib/minjs/compressor/compressor.rb in minjs-0.4.0 vs lib/minjs/compressor/compressor.rb in minjs-0.4.1

- old
+ new

@@ -86,21 +86,22 @@ # # @param data [String] ECMAScript input element # @return self def parse(data) @lex = Minjs::Lex::Parser.new(data, :logger => @logger) - @global_context = ECMA262::Context.new + @global_var_env = ECMA262::LexEnv.new(outer: nil) @heading_comments = [] while a = (@lex.comment || @lex.line_terminator || @lex.white_space) @heading_comments.push(a) end while @heading_comments.last == ECMA262::LIT_LINE_TERMINATOR and !(@heading_comments[-2].kind_of?(ECMA262::SingleLineComment)) @heading_comments.pop end - @prog = @lex.program(@global_context) + @prog = @lex.program(@global_var_env) + @prog.exe_context = ECMA262::ExeContext.new remove_empty_statement @lex.clear_cache self end @@ -201,26 +202,26 @@ # this scope. def reorder_var(node = @prog) node.traverse(nil) {|parent, st| if st.kind_of? ECMA262::Prog vars = nil - context = st.context + var_env = st.var_env # # collect all of var variable in this function # var_vars = {} - context.var_env.record.binding.each do|k, v| + var_env.record.binding.each do|k, v| if v and v[:_parameter_list].nil? and !v[:value].kind_of?(ECMA262::StFunc) var_vars[k] = true end end # # traverse block and convert var statement to assignment expression # if variable has initializer # st.traverse(parent){|parent2, st2| - if st2.kind_of? ECMA262::StVar and st2.context.var_env == context.var_env + if st2.kind_of? ECMA262::StVar and st2.var_env == var_env exp = nil st2.vars.each do |name, initializer| if initializer if exp.nil? exp = ECMA262::ExpAssign.new(name, initializer) @@ -232,22 +233,22 @@ if exp parent2.replace(st2, ECMA262::StExp.new(exp)) else parent2.replace(st2, ECMA262::StEmpty.new()) end - elsif st2.kind_of? ECMA262::StForVar and st2.context.var_env == context.var_env + elsif st2.kind_of? ECMA262::StForVar and st2.var_env == var_env parent2.replace(st2, st2.to_st_for) - elsif st2.kind_of? ECMA262::StForInVar and st2.context.var_env == context.var_env + elsif st2.kind_of? ECMA262::StForInVar and st2.var_env == var_env parent2.replace(st2, st2.to_st_for_in) end } if var_vars.length > 0 elems = st.source_elements.source_elements v = ECMA262::StVar.new( - context, + var_env, var_vars.collect do |k, v| - [ECMA262::IdentifierName.get(context, k)] + [ECMA262::IdentifierName.get(k)] end ) idx = 0 elems.each do |e| @@ -339,11 +340,11 @@ # Converts Block to single statement if possible def block_to_statement(node = @prog) remove_empty_statement then_to_block node.traverse(nil) {|parent, st| - if st.kind_of? ECMA262::StBlock and !parent.kind_of?(ECMA262::StTry) and !parent.kind_of?(ECMA262::StIf) + if st.kind_of? ECMA262::StBlock and !parent.kind_of?(ECMA262::StTry) and !parent.kind_of?(ECMA262::StIf) and !parent.kind_of?(ECMA262::StTryCatch) if st.to_statement? parent.replace(st, st.to_statement) end end } @@ -567,36 +568,42 @@ self end # Compresses variable name as short as possible. # - # This method collects and counts all variables under this function, + # This method collects and counts all variables under the function/catch, # then trying to rename var_vars(see bellow) to # new name. # # outer_vars:: - # Variables which locate out of this function(or global variable) + # Variables which locate out of this function/catch(or global variable) # Them name cannot be renamed # nesting_vars:: - # Variables which locate in the function of this function. + # Variables which locate in the function/catch of this function/catch. # Them name cannot be renamed # var_vars:: - # Variables which have same scope in this function. + # Variables which have same scope in this function/catch. # all_vars:: - # All variables under this function. + # All variables under this function/catch. # # 1. If the new name is not in all_vars, the name can be renamed to it. # 2. If the new name belongs to var_vars, the name cannot be renamed. # 3. If the new name belongs to outer_vars the name cannot be renamed. # 4. If the new name belongs to nesting_vars, the name can be rename # to it after renaming nesting_vars's name to another name. # # def compress_var(node = @prog) + scopes = [] func_scopes = [] catch_scopes = [] with_scopes = [] + + node.traverse(nil) {|parent, st| + st.parent = parent + } + # # ECMA262 10.2: # # Usually a Lexical Environment is associated with some # specific syntactic structure of ECMAScript code such as a @@ -605,12 +612,14 @@ # time such code is evaluated. # node.traverse(nil) {|parent, st| if st.kind_of? ECMA262::StFunc func_scopes.push([parent, st]) - elsif st.kind_of? ECMA262::StTry + scopes.push([parent, st]) + elsif st.kind_of? ECMA262::StTryCatch catch_scopes.push([parent, st]) + scopes.push([parent, st]) elsif st.kind_of? ECMA262::StWith with_scopes.push([parent, st]) end } # @@ -651,46 +660,57 @@ # } #} #console.log(eee); //=>global #test(); # - catch_scopes.each{|parent, st| - if st.catch - catch_context = ECMA262::Context.new - catch_context.lex_env = st.context.lex_env.new_declarative_env() - catch_context.var_env = st.context.var_env - catch_context.lex_env.record.create_mutable_binding(st.catch[0], nil) - catch_context.lex_env.record.set_mutable_binding(st.catch[0], :undefined, nil) - st.catch[0].context = catch_context + scopes.reverse! - st.catch[1].traverse(parent){|parent2, st2| - if st2.kind_of? ECMA262::IdentifierName and st2 == st.catch[0] and st2.binding_env == st.catch[0].binding_env - st2.context = catch_context + # outer + scopes = scopes.collect {|parent, st| + if st.kind_of? ECMA262::StFunc or st.kind_of? ECMA262::StTryCatch + outer = st.parent + while outer + if outer.kind_of? ECMA262::StFunc or outer.kind_of? ECMA262::StTryCatch + break end - } - func_scopes.unshift([parent, st]) + outer = outer.parent + end end + if outer.nil? + outer = @prog + end + [parent, st, outer] } -# with_scopes.each{|st, parent| -# with_context = ECMA262::Context.new -# with_context.lex_env = st.context.lex_env.new_declarative_env() -# with_context.var_env = st.context.var_env -# st.statement.traverse(st) {|st2| -# if st2.kind_of? ECMA262::IdentifierName and st2.binding_env == st.context.var_env -# st2.context = with_context -# with_context.lex_env.record.create_mutable_binding(st2, nil) -# with_context.lex_env.record.set_mutable_binding(st2, :undefined, nil) -# end -# } -# } - func_scopes.reverse! - func_scopes.each {|parent, st| + + # exe_context + scopes.each {|parent, st, outer| if st.kind_of? ECMA262::StFunc - context = st.context - elsif st.kind_of? ECMA262::StTry - context = st.catch[0].context + st.exe_context = st.enter(outer.exe_context) + st.traverse(nil) {|parent2, st2| + if st2.kind_of? ECMA262::IdentifierName + if st.decl? and st2 .eql? st.name + ; + elsif st.var_env.record.binding[st2.to_s.to_sym] + st2.exe_context = st.exe_context + end + end + } + elsif st.kind_of? ECMA262::StTryCatch + st.exe_context = st.enter(outer.exe_context) + st.traverse(nil) {|parent2, st2| + if st2.kind_of? ECMA262::IdentifierName + if st2 == st.arg + st2.exe_context = st.exe_context + end + end + } end + } + + scopes.each {|parent, st| + exe_context = st.exe_context + var_sym = :a all_vars = {} var_vars = {} var_vars_list = [] outer_vars = {} @@ -698,43 +718,54 @@ nesting_vars_list = [] st.traverse(parent) {|parent2, st2| if st2.kind_of? ECMA262::IdentifierName var_name = st2.val.to_sym - #st2_var_env = st2.binding_env - st2_lex_env = st2.binding_env(:lex) all_vars[var_name] ||= 0 all_vars[var_name] += 1 - if st2_lex_env == nil #global + if st2.exe_context == nil #global outer_vars[var_name] ||= 0 outer_vars[var_name] += 1 - elsif st2_lex_env == @global_context.lex_env #global + elsif st2.exe_context.lex_env == @prog.exe_context.lex_env outer_vars[var_name] ||= 0 outer_vars[var_name] += 1 - elsif st2_lex_env == context.lex_env + elsif st2.exe_context.lex_env == exe_context.lex_env var_vars[var_name] ||= 0 var_vars[var_name] += 1 var_vars_list.push(st2) else - e = st2.binding_env(:lex) + e = st2.exe_context.lex_env while e - e = e.outer - if e == context.lex_env + if e == exe_context.lex_env nesting_vars[var_name] ||= 0 nesting_vars[var_name] += 1 nesting_vars_list.push(st2) break end + e = e.outer if e.nil? outer_vars[var_name] ||= 0 outer_vars[var_name] += 1 break end end end end } + +# puts "*" * 30 +# puts st.to_js +# puts "*" * 30 +# puts "all_vars" +# puts all_vars +# puts "outer_vars" +# puts outer_vars +# puts "var_vars" +# puts var_vars +# puts "nesting_vars" +# puts nesting_vars + unless var_vars[:eval] eval_flag = false st.traverse(parent) {|parent2, st2| if st2.kind_of? ECMA262::ExpCall and st2.name.to_js({}) == "eval" eval_flag = true @@ -767,11 +798,11 @@ end #STDERR.puts "trying to rename #{name}(#{count})" while true #condition b if outer_vars[var_sym] - #STDERR.puts "outer_vars has #{var_sym}" + #STDERR.puts "outer_vars has #{var_sym}" elsif var_vars[var_sym] #STDERR.puts "var_vars has #{var_sym}(#{var_vars[var_sym]})" #condigion c else #condition a&d #STDERR.puts "->#{var_sym}" @@ -781,26 +812,24 @@ end #rename nesting_vars if nesting_vars[var_sym] #STDERR.puts "nesting_vars has #{var_sym}" nesting_vars_list.each do |x| - #raise 'error' if x.binding_env(:var).nil? - raise 'error' if x.binding_env(:lex).nil? + #raise 'error' if x.binding_env(x.exe_context.var_env).nil? end var_sym2 = "XXX#{var_sym.to_s}".to_sym while all_vars[var_sym2] var_sym2 = next_sym(var_sym2) end #STDERR.puts "#{var_sym}->#{var_sym2}" + rl = {} nesting_vars_list.each do |x| if x.val.to_sym == var_sym - _var_env = x.binding_env(:var) - _lex_env = x.binding_env(:lex) + _var_env = x.binding_env(x.exe_context.var_env) rl[_var_env] = true - rl[_lex_env] = true end end rl.keys.each do |_env| if _env && _env.record.binding[var_sym] _env.record.binding[var_sym2] = _env.record.binding[var_sym] @@ -812,42 +841,43 @@ if x.val.to_sym == var_sym x.instance_eval{ @val = var_sym2 } end - #raise 'error' if x.binding_env(:var).nil? - raise x.to_js if x.binding_env(:lex).nil? end end rename_table[name] = var_sym var_sym = next_sym(var_sym) } var_vars_list.each {|st2| - raise st2.to_js if st2.binding_env(:lex).nil? + #raise 'error' if st2.binding_env(st2.exe_context.var_env).nil? } rename_table.each do |name, new_name| if name != new_name - if context.var_env.record.binding[name] - context.var_env.record.binding[new_name] = context.var_env.record.binding[name] - context.var_env.record.binding.delete(name) + if exe_context.var_env.record.binding[name] + exe_context.var_env.record.binding[new_name] = exe_context.var_env.record.binding[name] + exe_context.var_env.record.binding.delete(name) end - if context.lex_env.record.binding[name] - context.lex_env.record.binding[new_name] = context.lex_env.record.binding[name] - context.lex_env.record.binding.delete(name) + if exe_context.lex_env.record.binding[name] + exe_context.lex_env.record.binding[new_name] = exe_context.lex_env.record.binding[name] + exe_context.lex_env.record.binding.delete(name) end end end var_vars_list.each {|st2| st2.instance_eval{ if rename_table[@val] @val = rename_table[@val] #raise 'error' if st2.binding_env(:var).nil? - raise st2.to_js if st2.binding_env(:lex).nil? + #raise st2.to_js if st2.binding_env(:lex).nil? end } } + } + node.traverse(nil) {|parent, st| + st.parent = nil } self end # Reduces expression