I need help with my Macros (newbie question)

I’m trying to enter the Metaprogramming world, and I decided to convert some functions into a macro.

I have one function get_return, that depending on one parameter , call two other functions. One that returns a sum, and other function that returns an array with all values.

function get_return(a,B,c; whatToDo=:sum)
    if whatToDo==:sum
        return _return_a_sum(a, B, c)
    elseif whatToDo==:vec
        return _return_a_vec(a, B, c)
    else
        @error "wrong input"
    end
end
function _return_a_sum(a, B, c)
    E = zero(ComplexF64)
    j = 1
    for b in eachcol(B)
        temp = rand(ComplexF64)*sum(b)
        E += temp * c[j]
        j += 1
    end
    return E
end
function _return_a_vec(a, B, c)
    E = Array{eltype(c)}(undef, length(c))
    j = 1
    for b in eachcol(B)
        temp = rand(ComplexF64)*sum(b)
        E[j] = temp * c[j]
        j += 1
    end
    return E
end

Now, I want to write two macros, one that creates an array, and other the access its elements. My best code so far is:

macro fix1(scalar_or_vector, original_code)
    quote
        local the_command_string = $(string(original_code))
        local the_command_expression = Base.Meta.parse(the_command_string)
        
        var_E    = the_command_expression.args[1]
        var_name = the_command_expression.args[2].args[2].args[2]

        if $(esc(scalar_or_vector)) == :sum
            return eval(Base.Meta.parse("$(var_E) = zero( eltype($(var_name)) )"))
            return $(esc(original_code))
        elseif $(esc(scalar_or_vector)) == :vec
            
            return eval(Base.Meta.parse("$(var_E) = Array{eltype($(var_name))}(undef, length($(var_name)))"))
        end
    end
end
macro fix2(scalar_or_vector, original_code)
    quote
        local the_command_string = $(string(original_code))
        local the_command_expression = Base.Meta.parse(the_command_string)

        var_E     = the_command_expression.args[1]
        var_fixed = the_command_expression.args[2].args[2]
        var_array = the_command_expression.args[2].args[3].args[1]
        var_fillA = the_command_expression.args[2].args[3].args[2]
        
        if $(esc(scalar_or_vector)) == :sum
            return Base.Meta.parse("$(var_E) += $(var_fixed) * $(var_array)[$(var_fillA)]")
        elseif $(esc(scalar_or_vector)) == :vec
            return Base.Meta.parse("$(var_E)[$(var_fillA)] = $(var_fixed) * $(var_array)[$(var_fillA)]")
        end
    end
end

Then I apply these new macros :

function _return_a_sum(a, B, c; whatToDo = :sum)
    @fix1 whatToDo E = zero(eltype(c))
    j = 1
    for b in eachcol(B)
        temp = rand(ComplexF64)*sum(b)
        @fix2 whatToDo E += temp * c[j]
        j += 1
    end
    return E
end

Now I run the code:

a, B, c = rand(3), rand(3,40), rand(ComplexF64, 40)
_return_a_sum(a, B, c; whatToDo = :sum)

The answer is not an error message, but the value is zero (or empty array).

I have no idea how to debug this code, because I cannot print anything inside the _return_a_sum. I need help to understand why :sob:.

If possible, I would like to someone tell me all the conceptual errors that I’m doing here too.

Thank you in advance.

It is very very hard to understand what you’re trying to do, maybe you can ask smaller partial questions about aspects that you’re uncertain with? To start with, can you explain why you think you need a macro for what you want to do?

One tip that I can definitely give you already, is that this stuff is not good style eval(Base.Meta.parse("$(var_E) = zero( eltype($(var_name)) )", it is basically never the right thing to eval expressions that you build from strings and then parse inside a macro. You usually build expressions directly and those are executed like normal code, no need for eval etc.

I’m trying to write one single function, that sometimes sum all values with the loop. Other times, just stored all values and returns an array.

Originally, I have two functions to make this happen ( _return_a_sum and _return_a_vec).
My goal would be to write one function, (_return_a_sum) that has the code to sum all values, but if I want, it will change to return an array.

The @fix1 changes (or not) the variable to store the result from

E = zero(eltype(c))

to

E = zeros(eltype(c), length(c))

@fix2 I change (or not) the accumulator into an array access from

 E += temp * c[j]

to

 E[j] = temp * c[j]

Maybe now my question is more explicit about what I want to do.