David117
David117

Reputation: 11

Using a macro to generate a Julia command to be executed in the REPL

I am a Julia (and stackoverflow) newbie but am trying unsuccessfully to simplify a function call. I need to define calls to create many instances of 30 different structs, each having a different set of properties. The code below works but will force the user to use exactly the same string twice, as in: EV_668876 = newEV("EV_668876", "test EV") This is a pain and likely to cause errors. I have written a macro to generate the command but can't get REPL to execute the command. Here is the code (sorry for its length).

 mutable struct EV
    label::FixedLabel
    id::FixedId
    name::String
    designAuth::Ident
    descripn::String
    timestamp::String
    priority::Int16
     assoc_EO::Ident   # this needs a new Set of EOstructs, to be defined
    origin_OV::Ident    # similar Set of OVstructs
    OV_destination::Ident    # this needs a new OVstruct, to be defined
    underRespOf::Ident
    underAuthOf::Ident
end

function newEV(id::String, name::String)
    trylabel = String(split(id,['-',':','_'])[1]) # Note that split() yields a SubString(String)
    if trylabel !== "EV"       # ! => not
        throw(DomainError("This id $id is not an EV, try again"))
    end
    labelFixed = FixedLabel(trylabel) 
    registerId(id) # registers id if OK 
    idFixed = FixedId(id)
    # ident = newId(id,name)
    new = EV(labelFixed,idFixed,name,anon_anon,"","",0,anon_anon,anon_anon,anon_anon,anon_anon,anon_anon)
end

EV_668876 = newEV("EV_668876", "test EV") # runs OK and produces
#=
This runs OK and produces
EV_668876 registered OK
EV(FixedLabel("EV"), FixedId("EV_668876"), "test EV", Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"), "", "", 0, Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"), Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"), Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"), Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"), Ident(FixedLabel("PPR"), FixedId("PPR-2"), "Anon_Anon"))
#=

# === Attempting to use a macro to simplify the newEV() function ===
macro create(id,name)
    label = "EV"
     return :(println($id," = new",$label,"(\"",$id,"\", \"",$name,"\")"))
end
@create("EV_97234894","new test")
#=
This   generates    
EV_97234894 = newEV("EV_97234894", "new test")   which is what I want 
but returns a type nothing – is that why REPL doesn't execute the result?
#=
# ==============================================

Upvotes: 1

Views: 93

Answers (1)

phipsgabler
phipsgabler

Reputation: 20950

As far as I understand (and I'm not sure what the printing does in your example), you want a macro that expands

@create <id> <name>

to

<id> = newEV("<id>", name)

The following will achieve that:

julia> macro create(id::Symbol, name)
           :($(esc(id)) = newEV($(String(id)), $name))
       end
@create (macro with 1 method)

julia> @macroexpand @create EV_234324 "new test"
:(EV_234324 = (Main.newEV)("EV_234324", "new test"))

@macroexpand is for debugging, since I didn't copy your code. It simply gets the expression that results from a macro call.

escaping is necessary here, since you want the identifier given by the symbol id to end up being defined in the calling scope.

Upvotes: 2

Related Questions