You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: step8_macros.rb
    path of file: ./repos/mal/impls/ruby.2
    
    the code of the file until where you have to start completion: require "readline"

require_relative "core"
require_relative "env"
require_relative "errors"
require_relative "printer"
require_relative "reader"

module Mal
  extend self

  def boot_repl!
    @repl_env = Env.new

    Core.ns.each do |k, v|
      @repl_env.set(k, v)
    end

    @
    
  def EVAL(ast, environment)
    loop do
      ast = macro_expand(ast, environment)

      if Types::List === ast && ast.size > 0
        case ast.first
        when Types::Symbol.for("def!")
          _, sym, val = ast
          return environment.set(sym, EVAL(val, environment))
        when Types::Symbol.for("defmacro!")
          _, sym, val = ast
          result = EVAL(val, environment)

          case result
          when Types::Function
            return environment.set(sym, result.to_macro)
          else
            raise TypeError
          end
        when Types::Symbol.for("macroexpand")
          _, ast_rest = ast
          return macro_expand(ast_rest, environment)
        when Types::Symbol.for("let*")
          e = Env.new(environment)
          _, bindings, val = ast

          unless Types::List === bindings || Types::Vector === bindings
            raise InvalidLetBindingsError
          end