CodeTools::AST << {

DeclareMeme < Node {
  node_type meme
  field decorations, field body

  bytecode: |g| {
    pos(g)

    self.effective_name.node_type == :symbol &? (
      ##
      # module = scope.for_method_definition
      # module.send :declare_meme, name, decorations, Proc(body)
      #
      g.push_scope
      g.send(:for_method_definition, 0)
        self.effective_name.bytecode(g)
        self.effective_decorations.bytecode(g)
        self.effective_body.bytecode(g)
      g.send(:declare_meme, 3)
    ) ?? (
      ConstantAssignment.new(
        line:     self.line
        constant: self.effective_name
        value:    self.effective_body.block.body
      ).bytecode(g)
    )
  }

  effective_name: self.decorations.last

  effective_decorations: {
    decorations = self.decorations[Ruby::Range.new(0, -1, true)]

    ArrayAssembly.new(line: self.line, body: decorations.reverse.map |d| {
      d.node_type == :invoke &? (
        ArrayAssembly.new(line: d.line, body: [
          SymbolLiteral.new(line: d.line, value: d.name)
          ArrayAssembly.new(line: d.line, body: d.arguments.body)
        ])
      ) ?? (
        d
      )
    })
  }

  effective_body: {
    body = self.body || BlockLiteral.new(line: self.line,
      block: Block.new(line: self.line,
        body: NullLiteral.new(line: self.line)
      )
    )
    body.block.new_cscope = true
    body
  }
}

}