Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing array fill with a macro

Tags:

macros

scala

I am trying to write a function which fills an array with a given value using scala macros. For instance a call to:

val ary = Array( 0, 1, 2 )
fill3( ary, 50+25 )

should be expanded to:

val ary = Array(0, 1, 2 )
{
  val $value = 50+25
  ary(0) = $value
  ary(1) = $value
  ary(2) = $value       
}

Here is my first attempt:

def fill3( ary: Array[Int], x: Int ) = macro fill_impl3

def fill_impl3( c: Context )
( ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( 3 ){
  i => Apply( Select( ary.tree, "update"), List( const(i), ??? ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}

But here I'm stuck for two reasons:

  1. I don't know hot to get the precomputed value ($value)
  2. I need several of these function for Arrays of size 3, 4, 6, 9 and 27. Is there a way to dry the definitions, or should I write fill3, fill4, fill6, etc.

Is there the right way to proceed ? How can I solve my two problems ?

EDIT: I realized my initial question was stupid because the size must be known at compile time...

like image 553
paradigmatic Avatar asked May 01 '26 20:05

paradigmatic


1 Answers

def fill(size:Int, ary: Array[Int], x: Int ) = macro fill_impl

def fill_impl( c: Context )
(size:c.Expr[Int], ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  val Literal(Constant(arySize:Int)) = size.tree

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( arySize ){
  i => Apply( Select( ary.tree, "update"), List( const(i), Ident(valName) ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}
like image 51
Kim Stebel Avatar answered May 05 '26 06:05

Kim Stebel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!