Class: Kapusta::Compiler::MacroExpander::Lowering

Inherits:
Object
  • Object
show all
Defined in:
lib/kapusta/compiler/macro_expander.rb

Instance Method Summary collapse

Constructor Details

#initializeLowering

Returns a new instance of Lowering.



150
151
152
# File 'lib/kapusta/compiler/macro_expander.rb', line 150

def initialize
  @gensyms = {}
end

Instance Method Details

#collected_gensymsObject



154
155
156
# File 'lib/kapusta/compiler/macro_expander.rb', line 154

def collected_gensyms
  @gensyms.map { |prefix, sym| [sym, prefix] }
end

#gensym_local_for(prefix) ⇒ Object



250
251
252
# File 'lib/kapusta/compiler/macro_expander.rb', line 250

def gensym_local_for(prefix)
  @gensyms[prefix] ||= MacroExpander.fresh_local_gensym(prefix)
end

#lower(form) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/kapusta/compiler/macro_expander.rb', line 158

def lower(form)
  case form
  when Quasiquote then lower_quasi(form.form)
  when Unquote, UnquoteSplice
    raise Error, 'unquote outside quasiquote'
  when AutoGensym
    raise Error, "auto-gensym #{form.name}# outside quasiquote"
  when List then List.new(form.items.map { |item| lower(item) })
  when Vec then Vec.new(form.items.map { |item| lower(item) })
  when HashLit
    HashLit.new(form.entries.map do |entry|
      entry.is_a?(Array) ? [lower(entry[0]), lower(entry[1])] : entry
    end)
  else
    form
  end
end

#lower_quasi(form) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/kapusta/compiler/macro_expander.rb', line 176

def lower_quasi(form)
  case form
  when AutoGensym then gensym_local_for(form.name)
  when Sym then List.new([Sym.new('quasi-sym'), form.name])
  when List then lower_quasi_list(form)
  when Vec then lower_quasi_vec(form)
  when HashLit then lower_quasi_hash(form)
  when Unquote then lower(form.form)
  when UnquoteSplice
    raise Error, 'unquote-splice must appear inside a quoted list/vec'
  when Quasiquote
    raise Error, 'nested quasiquote is not supported'
  else
    form
  end
end

#lower_quasi_hash(hash) ⇒ Object



217
218
219
220
221
222
223
224
225
226
# File 'lib/kapusta/compiler/macro_expander.rb', line 217

def lower_quasi_hash(hash)
  parts = []
  hash.entries.each do |entry|
    next unless entry.is_a?(Array)

    key, value = entry
    parts << lower_quasi(key) << lower_quasi(value)
  end
  List.new([Sym.new('quasi-hash'), *parts])
end

#lower_quasi_item(item) ⇒ Object



228
229
230
231
232
233
234
235
# File 'lib/kapusta/compiler/macro_expander.rb', line 228

def lower_quasi_item(item)
  if item.is_a?(Unquote) && unpack_call?(item.form)
    inner = lower(item.form.items[1])
    List.new([Sym.new('.'), inner, 0])
  else
    lower_quasi(item)
  end
end

#lower_quasi_list(list) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/kapusta/compiler/macro_expander.rb', line 193

def lower_quasi_list(list)
  items = list.items
  return List.new([Sym.new('quasi-list')]) if items.empty?

  if (tail_expr = splice_tail(items))
    head_items = items[0...-1].map { |item| lower_quasi(item) }
    return List.new([Sym.new('quasi-list-tail'), Vec.new(head_items), tail_expr])
  end

  lowered_items = items.map { |item| lower_quasi_item(item) }
  List.new([Sym.new('quasi-list'), *lowered_items])
end

#lower_quasi_vec(vec) ⇒ Object



206
207
208
209
210
211
212
213
214
215
# File 'lib/kapusta/compiler/macro_expander.rb', line 206

def lower_quasi_vec(vec)
  items = vec.items
  if (tail_expr = splice_tail(items))
    head_items = items[0...-1].map { |item| lower_quasi(item) }
    return List.new([Sym.new('quasi-vec-tail'), Vec.new(head_items), tail_expr])
  end

  lowered_items = items.map { |item| lower_quasi_item(item) }
  List.new([Sym.new('quasi-vec'), *lowered_items])
end

#splice_tail(items) ⇒ Object



237
238
239
240
241
242
243
244
# File 'lib/kapusta/compiler/macro_expander.rb', line 237

def splice_tail(items)
  last = items.last
  return unless last
  return lower(last.form) if last.is_a?(UnquoteSplice)
  return lower(last.form.items[1]) if last.is_a?(Unquote) && unpack_call?(last.form)

  nil
end

#unpack_call?(form) ⇒ Boolean

Returns:

  • (Boolean)


246
247
248
# File 'lib/kapusta/compiler/macro_expander.rb', line 246

def unpack_call?(form)
  form.is_a?(List) && form.head.is_a?(Sym) && form.head.name == 'unpack'
end