Class: KaiserRuby::Transformer

Inherits:
Object
  • Object
show all
Defined in:
lib/kaiser_ruby/transformer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tree) ⇒ Transformer

Returns a new instance of Transformer.



5
6
7
8
9
10
11
12
# File 'lib/kaiser_ruby/transformer.rb', line 5

def initialize(tree)
  @parsed_tree = tree
  @output = []
  @method_names = []
  @nesting = 0
  @indentation = ''
  @lnum = 0
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object

Raises:

  • (ArgumentError)


48
49
50
# File 'lib/kaiser_ruby/transformer.rb', line 48

def method_missing(m, *args, &block)
  raise ArgumentError, "missing Transform rule: #{m}, #{args}"
end

Instance Attribute Details

#outputObject (readonly)

Returns the value of attribute output.



3
4
5
# File 'lib/kaiser_ruby/transformer.rb', line 3

def output
  @output
end

#parsed_treeObject (readonly)

Returns the value of attribute parsed_tree.



3
4
5
# File 'lib/kaiser_ruby/transformer.rb', line 3

def parsed_tree
  @parsed_tree
end

Instance Method Details

#additional_argument_transformation(argument) ⇒ Object



239
240
241
242
243
244
245
246
247
# File 'lib/kaiser_ruby/transformer.rb', line 239

def additional_argument_transformation(argument)
  # testing function existence
  arg = @method_names.include?(argument) ? "defined?(#{argument})" : argument

  # single variable without any operator needs to return a refined boolean
  arg = "#{arg}.to_bool" if arg !~ /==|>|>=|<|<=|!=/

  return arg
end

#filter_string(string, rxp: /[[:alpha:]]/) ⇒ Object



354
355
356
# File 'lib/kaiser_ruby/transformer.rb', line 354

def filter_string(string, rxp: /[[:alpha:]]/)
  string.to_s.split(/\s+/).map { |e| e.chars.select { |c| c =~ rxp }.join }.reject { |a| a.empty? }
end

#select_transformer(object) ⇒ Object



43
44
45
46
# File 'lib/kaiser_ruby/transformer.rb', line 43

def select_transformer(object)
  key = object.keys.first
  send("transform_#{key}", object)
end

#str_to_num(string) ⇒ Object

private



350
351
352
# File 'lib/kaiser_ruby/transformer.rb', line 350

def str_to_num(string)
  filter_string(string).map { |e| e.length % 10 }.join
end

#transformObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/kaiser_ruby/transformer.rb', line 14

def transform
  @last_variable = nil # name of last used variable for pronouns
  @else_already = nil # line number of a current if block, so we can avoid double else
  @local_variables = [] # locally defined variable names in current function block

  @parsed_tree.each_with_index do |line_object, lnum|
    @lnum = lnum
    transformed_line = select_transformer(line_object)
    if line_object[:nesting]
      @nesting = line_object[:nesting]
    else
      @nesting = 0
    end

    @indentation = '  ' * @nesting
    @output << @indentation + transformed_line
  end

  # at end of file, close all the blocks that are still started
  while @nesting > 0
    @nesting -= 1
    @indentation = '  ' * @nesting
    @output << @indentation + "end"
  end

  @output << '' if @output.size > 1
  @output.join("\n")
end

#transform_addition(object) ⇒ Object



131
132
133
134
135
# File 'lib/kaiser_ruby/transformer.rb', line 131

def transform_addition(object)
  left = select_transformer(object[:addition][:left])
  right = select_transformer(object[:addition][:right])
  "#{left} + #{right}"
end

#transform_and(object) ⇒ Object



322
323
324
325
326
327
# File 'lib/kaiser_ruby/transformer.rb', line 322

def transform_and(object)
  left = select_transformer(object[:and][:left])
  right = select_transformer(object[:and][:right])

  "#{left} && #{right}"
end

#transform_argument_list(object) ⇒ Object



122
123
124
125
126
127
128
129
# File 'lib/kaiser_ruby/transformer.rb', line 122

def transform_argument_list(object)
  list = []
  object[:argument_list].each do |arg|
    list << select_transformer(arg)
  end

  list.join(', ')
end

#transform_assignment(object) ⇒ Object



155
156
157
158
159
# File 'lib/kaiser_ruby/transformer.rb', line 155

def transform_assignment(object)
  left = select_transformer(object[:assignment][:left])
  right = select_transformer(object[:assignment][:right])
  "#{left} = #{right}"
end

#transform_break(object) ⇒ Object



79
80
81
82
# File 'lib/kaiser_ruby/transformer.rb', line 79

def transform_break(object)
  raise KaiserRuby::RockstarSyntaxError, "Break used outside of a loop" if object[:nesting].to_i.zero?
  "break"
end

#transform_continue(object) ⇒ Object



74
75
76
77
# File 'lib/kaiser_ruby/transformer.rb', line 74

def transform_continue(object)
  raise KaiserRuby::RockstarSyntaxError, "Continue used outside of a loop" if object[:nesting].to_i.zero?
  "next"
end

#transform_decrement(object) ⇒ Object



161
162
163
164
165
# File 'lib/kaiser_ruby/transformer.rb', line 161

def transform_decrement(object)
  argument = select_transformer(object[:decrement])
  amount = object.dig(:decrement, :amount)
  "#{argument} -= #{amount}"
end

#transform_division(object) ⇒ Object



149
150
151
152
153
# File 'lib/kaiser_ruby/transformer.rb', line 149

def transform_division(object)
  left = select_transformer(object[:division][:left])
  right = select_transformer(object[:division][:right])
  "#{left} / #{right}"
end

#transform_else(object) ⇒ Object



255
256
257
258
259
260
261
# File 'lib/kaiser_ruby/transformer.rb', line 255

def transform_else(object)
  raise KaiserRuby::RockstarSyntaxError, "Else outside an if block" if object[:nesting].to_i.zero?
  raise KaiserRuby::RockstarSyntaxError, "Double else inside if block" if @else_already != nil && object[:nesting_start_line] == @else_already

  @else_already = object[:nesting_start_line]
  "else"
end

#transform_empty_line(_object) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/kaiser_ruby/transformer.rb', line 227

def transform_empty_line(_object)
  if @nesting == 0
    return ""
  elsif @nesting == 1
    @local_variables = []
    return "end\n"
  else
    @else_already = nil
    return "end\n"
  end
end

#transform_equality(object) ⇒ Object



275
276
277
278
279
# File 'lib/kaiser_ruby/transformer.rb', line 275

def transform_equality(object)
  left = select_transformer(object[:equality][:left])
  right = select_transformer(object[:equality][:right])
  "#{left} == #{right}"
end

#transform_function(object) ⇒ Object



311
312
313
314
315
316
317
318
319
320
# File 'lib/kaiser_ruby/transformer.rb', line 311

def transform_function(object)
  funcname = transform_function_name(object[:function][:name])
  argument = select_transformer(object[:function][:argument])

  # save method name and make local variables out of the function arguments
  @method_names << funcname
  @local_variables = argument.split(', ')

  "def #{funcname}(#{argument})"
end

#transform_function_call(object) ⇒ Object



173
174
175
176
177
178
# File 'lib/kaiser_ruby/transformer.rb', line 173

def transform_function_call(object)
  func_name = select_transformer(object[:function_call][:left])
  argument = select_transformer(object[:function_call][:right])

  "#{func_name}(#{argument})"
end

#transform_function_name(object) ⇒ Object



106
107
108
# File 'lib/kaiser_ruby/transformer.rb', line 106

def transform_function_name(object)
  object[:function_name]
end

#transform_gt(object) ⇒ Object



287
288
289
290
291
# File 'lib/kaiser_ruby/transformer.rb', line 287

def transform_gt(object)
  left = select_transformer(object[:gt][:left])
  right = select_transformer(object[:gt][:right])
  "#{left} > #{right}"
end

#transform_gte(object) ⇒ Object



293
294
295
296
297
# File 'lib/kaiser_ruby/transformer.rb', line 293

def transform_gte(object)
  left = select_transformer(object[:gte][:left])
  right = select_transformer(object[:gte][:right])
  "#{left} >= #{right}"
end

#transform_if(object) ⇒ Object



249
250
251
252
253
# File 'lib/kaiser_ruby/transformer.rb', line 249

def transform_if(object)
  argument = select_transformer(object[:if][:argument])
  argument = additional_argument_transformation(argument)
  "if #{argument}"
end

#transform_increment(object) ⇒ Object



167
168
169
170
171
# File 'lib/kaiser_ruby/transformer.rb', line 167

def transform_increment(object)
  argument = select_transformer(object[:increment])
  amount = object.dig(:increment, :amount)
  "#{argument} += #{amount}"
end

#transform_inequality(object) ⇒ Object



281
282
283
284
285
# File 'lib/kaiser_ruby/transformer.rb', line 281

def transform_inequality(object)
  left = select_transformer(object[:inequality][:left])
  right = select_transformer(object[:inequality][:right])
  "#{left} != #{right}"
end

#transform_listen(_object) ⇒ Object



64
65
66
# File 'lib/kaiser_ruby/transformer.rb', line 64

def transform_listen(_object)
  "print '> '\n$stdin.gets.chomp"
end

#transform_listen_to(object) ⇒ Object



59
60
61
62
# File 'lib/kaiser_ruby/transformer.rb', line 59

def transform_listen_to(object)
  var = select_transformer(object[:listen_to])
  "print '> '\n__input = $stdin.gets.chomp\n#{var} = Float(__input) rescue __input"
end

#transform_local_variable_name(object) ⇒ Object



102
103
104
# File 'lib/kaiser_ruby/transformer.rb', line 102

def transform_local_variable_name(object)
  object[:local_variable_name]
end

#transform_lt(object) ⇒ Object



299
300
301
302
303
# File 'lib/kaiser_ruby/transformer.rb', line 299

def transform_lt(object)
  left = select_transformer(object[:lt][:left])
  right = select_transformer(object[:lt][:right])
  "#{left} < #{right}"
end

#transform_lte(object) ⇒ Object



305
306
307
308
309
# File 'lib/kaiser_ruby/transformer.rb', line 305

def transform_lte(object)
  left = select_transformer(object[:lte][:left])
  right = select_transformer(object[:lte][:right])
  "#{left} <= #{right}"
end

#transform_multiplication(object) ⇒ Object



137
138
139
140
141
# File 'lib/kaiser_ruby/transformer.rb', line 137

def transform_multiplication(object)
  left = select_transformer(object[:multiplication][:left])
  right = select_transformer(object[:multiplication][:right])
  "#{left} * #{right}"
end

#transform_nor(object) ⇒ Object



341
342
343
344
345
346
# File 'lib/kaiser_ruby/transformer.rb', line 341

def transform_nor(object)
  left = select_transformer(object[:nor][:left])
  right = select_transformer(object[:nor][:right])

  "!(#{left} || #{right})"
end

#transform_not(object) ⇒ Object



329
330
331
332
# File 'lib/kaiser_ruby/transformer.rb', line 329

def transform_not(object)
  arg = select_transformer(object[:not])
  "!#{arg}"
end

#transform_number(object) ⇒ Object



118
119
120
# File 'lib/kaiser_ruby/transformer.rb', line 118

def transform_number(object)
  object[:number]
end

#transform_number_literal(object) ⇒ Object



203
204
205
206
207
208
209
210
211
212
# File 'lib/kaiser_ruby/transformer.rb', line 203

def transform_number_literal(object)
  string = object[:number_literal]
  if string.include?('.')
    string.split('.', 2).map do |sub|
      str_to_num(sub.strip)
    end.join('.').to_f
  else
    str_to_num(string).to_f
  end
end

#transform_or(object) ⇒ Object



334
335
336
337
338
339
# File 'lib/kaiser_ruby/transformer.rb', line 334

def transform_or(object)
  left = select_transformer(object[:or][:left])
  right = select_transformer(object[:or][:right])

  "#{left} || #{right}"
end

#transform_passed_function_call(object) ⇒ Object



180
181
182
# File 'lib/kaiser_ruby/transformer.rb', line 180

def transform_passed_function_call(object)
  return transform_function_call(object[:passed_function_call])
end

#transform_poetic_number(object) ⇒ Object



197
198
199
200
201
# File 'lib/kaiser_ruby/transformer.rb', line 197

def transform_poetic_number(object)
  var = select_transformer(object[:poetic_number][:left])
  value = select_transformer(object[:poetic_number][:right])
  "#{var} = #{value}"
end

#transform_poetic_string(object) ⇒ Object



184
185
186
187
188
189
# File 'lib/kaiser_ruby/transformer.rb', line 184

def transform_poetic_string(object)
  var = select_transformer(object[:poetic_string][:left])
  value = select_transformer(object[:poetic_string][:right])

  "#{var} = #{value}"
end

#transform_poetic_type(object) ⇒ Object



191
192
193
194
195
# File 'lib/kaiser_ruby/transformer.rb', line 191

def transform_poetic_type(object)
  var = select_transformer(object[:poetic_type][:left])
  value = select_transformer(object[:poetic_type][:right])
  "#{var} = #{value}"
end

#transform_print(object) ⇒ Object

transform language tree into Ruby



54
55
56
57
# File 'lib/kaiser_ruby/transformer.rb', line 54

def transform_print(object)
  var = select_transformer(object[:print])
  "puts #{var}"
end

#transform_pronoun(_object) ⇒ Object



110
111
112
# File 'lib/kaiser_ruby/transformer.rb', line 110

def transform_pronoun(_object)
  @last_variable
end

#transform_return(object) ⇒ Object



68
69
70
71
72
# File 'lib/kaiser_ruby/transformer.rb', line 68

def transform_return(object)
  raise KaiserRuby::RockstarSyntaxError, "Return used outside of a function" if object[:nesting].to_i.zero?
  var = select_transformer(object[:return])
  "return #{var}"
end

#transform_string(object) ⇒ Object



114
115
116
# File 'lib/kaiser_ruby/transformer.rb', line 114

def transform_string(object)
  object[:string]
end

#transform_subtraction(object) ⇒ Object



143
144
145
146
147
# File 'lib/kaiser_ruby/transformer.rb', line 143

def transform_subtraction(object)
  left = select_transformer(object[:subtraction][:left])
  right = select_transformer(object[:subtraction][:right])
  "#{left} - #{right}"
end

#transform_type(object) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/kaiser_ruby/transformer.rb', line 214

def transform_type(object)
  case object[:type]
  when "nil"
    'nil'
  when "null"
    '0.0'
  when "true"
    'true'
  when "false"
    'false'
  end
end

#transform_until(object) ⇒ Object



269
270
271
272
273
# File 'lib/kaiser_ruby/transformer.rb', line 269

def transform_until(object)
  argument = select_transformer(object[:until][:argument])
  argument = additional_argument_transformation(argument)
  "until #{argument}"
end

#transform_variable_name(object) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/kaiser_ruby/transformer.rb', line 84

def transform_variable_name(object)
  varname = object[:variable_name]
  if object[:type] == :assignment
    if @local_variables.empty?
      varname = "@#{varname}"
    else
      @local_variables << varname
    end
  else
    unless @local_variables.include?(varname)
      varname = @method_names.include?(varname) ? varname : "@#{varname}"
    end
  end

  @last_variable = varname
  varname
end

#transform_while(object) ⇒ Object



263
264
265
266
267
# File 'lib/kaiser_ruby/transformer.rb', line 263

def transform_while(object)
  argument = select_transformer(object[:while][:argument])
  argument = additional_argument_transformation(argument)
  "while #{argument}"
end