Class: Goling::Reduction
- Inherits:
-
Object
- Object
- Goling::Reduction
- Defined in:
- lib/goling/reduction.rb
Constant Summary collapse
- @@reductions =
[]
Instance Attribute Summary collapse
-
#args ⇒ Object
Returns the value of attribute args.
-
#from ⇒ Object
Returns the value of attribute from.
-
#inline ⇒ Object
Returns the value of attribute inline.
-
#lang ⇒ Object
Returns the value of attribute lang.
-
#line ⇒ Object
Returns the value of attribute line.
-
#location ⇒ Object
Returns the value of attribute location.
-
#named_args ⇒ Object
Returns the value of attribute named_args.
-
#reduction_id ⇒ Object
Returns the value of attribute reduction_id.
-
#regexp ⇒ Object
Returns the value of attribute regexp.
-
#returns ⇒ Object
Returns the value of attribute returns.
-
#rule_args ⇒ Object
Returns the value of attribute rule_args.
-
#sexp ⇒ Object
Returns the value of attribute sexp.
Class Method Summary collapse
Instance Method Summary collapse
-
#compile_with_return_to_var(return_variable, replace = {}) ⇒ Object
Compile self.
- #determine_arguments ⇒ Object
-
#initialize(params) ⇒ Reduction
constructor
A new instance of Reduction.
-
#replace_variable_references(code, replacement, needle) ⇒ Object
Recurcively replace all references in a code section.
- #to_rexp ⇒ Object
Constructor Details
#initialize(params) ⇒ Reduction
Returns a new instance of Reduction.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/goling/reduction.rb', line 24 def initialize params @returns = params[:returns] @lang = params[:lang] @inline = params[:inline] @location = params[:location] @line = params[:line] @regexp = params[:regexp] @rule_args= @regexp.split(')').map{ |sub| sub.split('(')[1] }.select{ |v| v } @args = params[:args] @sexp = params[:sexp] @reduction_id = @@reductions.size determine_arguments @@reductions << self end |
Instance Attribute Details
#args ⇒ Object
Returns the value of attribute args.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def args @args end |
#from ⇒ Object
Returns the value of attribute from.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def from @from end |
#inline ⇒ Object
Returns the value of attribute inline.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def inline @inline end |
#lang ⇒ Object
Returns the value of attribute lang.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def lang @lang end |
#line ⇒ Object
Returns the value of attribute line.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def line @line end |
#location ⇒ Object
Returns the value of attribute location.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def location @location end |
#named_args ⇒ Object
Returns the value of attribute named_args.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def named_args @named_args end |
#reduction_id ⇒ Object
Returns the value of attribute reduction_id.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def reduction_id @reduction_id end |
#regexp ⇒ Object
Returns the value of attribute regexp.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def regexp @regexp end |
#returns ⇒ Object
Returns the value of attribute returns.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def returns @returns end |
#rule_args ⇒ Object
Returns the value of attribute rule_args.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def rule_args @rule_args end |
#sexp ⇒ Object
Returns the value of attribute sexp.
20 21 22 |
# File 'lib/goling/reduction.rb', line 20 def sexp @sexp end |
Class Method Details
.parse(str) ⇒ Object
65 66 67 68 69 70 71 72 73 |
# File 'lib/goling/reduction.rb', line 65 def self.parse str if /^{(?<return>[^:]*):(?<rid>[0-9]+)}$/ =~ str @@reductions[rid.to_i] elsif /^(?<return>[^:]*):(?<rid>[0-9]+)$/ =~ str @@reductions[rid.to_i] else raise "hell #{str}" end end |
Instance Method Details
#compile_with_return_to_var(return_variable, replace = {}) ⇒ Object
Compile self
-
return_variable
- The return variable. Can either be a symbol representing the variable name or nil to skip variable assigning. -
replace
- A list of variables in need of a new unique name or replacement with inlined code
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/goling/reduction.rb', line 80 def compile_with_return_to_var(return_variable, replace = {}) s = Marshal.load(Marshal.dump(self)) # sexp handling is not clean cut args = @named_args.keys # args[] now has the symbolized argument names of the code block args_code = [] s.args.each_with_index do |arg,i| if /^{(?<ret>[^:]*):(?<n>[0-9]+)}$/ =~ arg # got a argument that referes to a reduction # pseudo allocate a return variable name and compile the reduction red = Reduction::parse(arg) if red.lang != lang && red.lang == :js && lang == :ruby # paste javascript code into a ruby variable code = red.compile_with_return_to_var(nil,replace) clone = Marshal.load(Marshal.dump(code)) # code is not cleanly duplicated code = Sexp.new(:iter,Sexp.new(:call, nil, :lambda, Sexp.new(:arglist)), nil, Sexp.new(:block, *clone ) ) code = Ruby2Js.new.process(code) code = [Sexp.new(:lasgn, args[i], Sexp.new(:lit, code))] args_code += code else raise "trying to reference #{red.lang} code in #{lang} code" if red.lang != lang if red.inline code = red.compile_with_return_to_var(nil,replace) replace[args[i]] = Replacement.new(:sexp => Sexp.new(:block,*code), :inline => true) else code = red.compile_with_return_to_var("#{ret}_#{n}".to_sym,replace) args_code += code replace[args[i]] = Replacement.new(:sexp => "#{ret}_#{n}".to_sym) end end elsif /^[0-9]+$/ =~ arg # got a number argument, stuff it in a integer variable args_code << Sexp.new(:lasgn, args[i], Sexp.new(:lit, arg.to_i)) else raise "hell" end end if return_variable if s.sexp[3][0] == :block code = Sexp.new(:lasgn, return_variable, Sexp.new(:block, *(s.sexp[3][1..-1].map{ |s| s.dup }) ) ) else code = Sexp.new(:lasgn, return_variable, s.sexp[3].dup) end else code = s.sexp[3].dup end replace.each do |k,v| replace_variable_references(code,v,k) end return *args_code + [code] end |
#determine_arguments ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/goling/reduction.rb', line 39 def determine_arguments s = Marshal.load(Marshal.dump(self)) # sexp handling is not clean cut raise "what is this?" unless s.sexp[0] == :iter && s.sexp[1][0] == :call && s.sexp[1][1] == nil && s.sexp[1][2] == :proc && s.sexp[1][3][0] == :arglist block_args = s.sexp[2] if block_args if block_args[0]==:lasgn # single argument args = [block_args[1]] elsif block_args[0]==:masgn # multiple arguments args = block_args[1] raise "unsupported argument type #{args}" unless args[0]==:array args = args[1..-1].map{ |arg| raise "unsupported argument type #{arg}" unless arg[0]==:lasgn arg[1] } else raise "unsupported argument type #{args}" end end # args[] now has the symbolized argument names of the code block @named_args = Hash[*args.zip(@args).flatten] if args @named_args ||= {} end |
#replace_variable_references(code, replacement, needle) ⇒ Object
Recurcively replace all references in a code section
-
code
- The code haystack to search and replace in -
replacement
- The replacement code. Either a Sexp (containing code to inline) or a symbol -
needle
- The search needle
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/goling/reduction.rb', line 149 def replace_variable_references(code,replacement,needle) #inline = replacement.kind_of?(Sexp) case code[0] when :lasgn code[1]=replacement.sexp if code[1] == needle when :lvar if code[1] == needle unless replacement.inline? code[1]=replacement.sexp end end when :call code[2]=replacement.sexp if code[2] == needle when :lvar code[1]=replacement.sexp if code[1] == needle end # inlining requires complex code: if replacement.inline? && [:iter, :block].include?(code[0]) # we have a inline and a block, replace any references with the sexp code[1..-1].each_with_index do |h,i| if h && h.kind_of?(Sexp) && h == Sexp.new(:lvar, needle) # inline references like s(:lvar, :needle) # indicates a call to the needle, thus code wants to inline h[0] = replacement.sexp[0] h[1] = replacement.sexp[1] elsif h && h.kind_of?(Sexp) && @named_args.has_key?(needle) && Reduction.parse(@named_args[needle]).named_args.select{ |k,v| h == Sexp.new(:call, Sexp.new(:lvar, needle), :[], Sexp.new(:arglist, Sexp.new(:lit, k))) }.size == 1 # code is asking for a injection of one of the argument's with: # s(:call, s(:lvar, :needle), :[], s(:arglist, s(:lit, :argumen))) # which in ruby looks like: # needle[:argument] # which again is the way we support calling arguments of the neede arg = h[3][1][1] sexy = Marshal.load(Marshal.dump(Reduction.parse(Reduction.parse(@named_args[needle]).named_args[arg]).sexp)) # sexp handling is not clean cut code[i+1] = sexy[3] else replace_variable_references(h,replacement,needle) if h && h.kind_of?(Sexp) end end else code[1..-1].each do |h| replace_variable_references(h,replacement,needle) if h && h.kind_of?(Sexp) end end end |
#to_rexp ⇒ Object
199 200 201 202 |
# File 'lib/goling/reduction.rb', line 199 def to_rexp raise "hell" if returns.kind_of?(Array) "{#{returns}:#{reduction_id}}" end |