Interpolate expression into macro

The full background is the following: I have implemented a type Particles <: Real which wraps a vector for Float64. I can define lots of functions for this type, but some functions are hard to define in a meaningful way. In those situations, I want to fall back to propagate each float of the wrapped vector through the function one by one and collect the result in a new Particles at the output. If the particles appear as an argument to the top-level function, this is really straightforward. The problem appears when my type Particles appears as a field nested somewhere in a struct I have no control over. As an example, consider this structure

julia> P
TransferFunction{ControlSystems.SisoRational{StaticParticles{Float64,100}}}
   0.998 ± 0.1
-----------------
1.0*s + 1.0 ± 0.1

Continuous-time transfer function model

julia> dump(P)
TransferFunction{ControlSystems.SisoRational{StaticParticles{Float64,100}}}
  matrix: Array{ControlSystems.SisoRational{StaticParticles{Float64,100}}}((1, 1))
    1: ControlSystems.SisoRational{StaticParticles{Float64,100}}
      num: Polynomials.Poly{StaticParticles{Float64,100}}
        a: Array{StaticParticles{Float64,100}}((1,)) StaticParticles{Float64,100}[0.998 ± 0.1]
        var: Symbol x
      den: Polynomials.Poly{StaticParticles{Float64,100}}
        a: Array{StaticParticles{Float64,100}}((2,)) StaticParticles{Float64,100}[1.0 ± 0.1, 1.0]
        var: Symbol x
  Ts: Float64 0.0
  nu: Int64 1
  ny: Int64 1

The particles appear deeply nested in the object P which is the input to my function, and can be accessed by P.matrix[1].num.a[:] and P.matrix[1].den.a[:]. which are the expressions I am generating.

I want to create an object identical to P, let’s call it P2, but in all places where Particles appear, I want to have Float64 instead. I then want to populate P2 with particle index i for eachindex(particles). I then call my function with P2 which is completely free of weird particle types and put the result of the computation into an output object with the desired Particles fields.

The real code to generate the expressions is here
I turn these expressions into functions that get and set fields in the generated intermediate buffers P2 and Pres to store the result. The buffer is autogenerated here and it mostly works okay at the moment. The only problem is with the world age, causing me to not be able to use the getter and setter functions until the world age is updated. My current strategy is to make the user create a Workspace object which creates the internal buffer P2 and the evaled functions, and then call this workspace object with the desired function in a later stage:

P = tf(1 ∓ 0.1, [1, 1∓0.1]) # The P shown above
w = Workspace(P)   # Creates work buffer `P2` and some getter/setter functions
f = x->c2d(x,0.1) # This is the computation I want to perform on P but which fails if P contains Particles
Pd = w(f) # This works

However, if created and called in the same function:

    tt = function (P)
        w = Workspace(P)
        f = x->c2d(x,0.1)
        @time Pd = w(f)
    end
    @test_throws MethodError tt(P) # This causes a world-age problem. If this tests suddenly break, it would be nice and we can get rid of the intermediate workspace object.