Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/StructTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1066,4 +1066,6 @@ function constructfrom(::AbstractType, ::Type{T}, obj::S) where {T, S}
return constructfrom(TT, obj)
end

include("macros.jl")

end # module
58 changes: 58 additions & 0 deletions src/macros.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
isolate_name(name) = split(string(name), '.')[end]

for struct_type in (:Struct, :Mutable, :CustomStruct, :OrderedStruct, :AbstractType, :DictType, :ArrayType, :StringType, :NumberType, :BoolType, :NullType)
@eval begin
"""
@$(isolate_name($struct_type))(expr::Expr)
@$(isolate_name($struct_type))(expr::Symbol)

If `expr` is a struct definition, sets the `StructType` of the defined struct to
`$(isolate_name($struct_type))()`. If `expr` is the name of a `Type`, sets the `StructType` of that
type to `$(isolate_name($struct_type))()`.

# Examples
```julia
@$(isolate_name($struct_type)) MyStruct
```
is equivalent to
```julia
StructTypes.StructType(::Type{MyStruct}) = StructType.Struct()
```
and
```julia
@$(isolate_name($struct_type)) struct MyStruct
val::Int
end
```
is equivalent to
```julia
struct MyStruct
val::Int
end
StructTypes.StructType(::Type{MyStruct}) = StructType.Struct()
```
""" macro $struct_type(expr)
return macro_constructor(expr, $struct_type)
end
end
end

function macro_constructor(expr::Expr, structtype)
if expr.head == :struct
return esc(quote
$expr
StructTypes.StructType(::Type{$(expr.args[2])}) = $structtype()
end)
else
return :(throw(ArgumentError("StructType macros can only be used with a struct definition or a Type")))
end
end
function macro_constructor(expr::Symbol, structtype)
return esc(quote
if $(expr) isa Type
StructTypes.StructType(::Type{$(expr)}) = $structtype()
else
throw(ArgumentError("StructType macros can only be used with a struct definition or a Type"))
end
end)
end
29 changes: 29 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,32 @@ StructTypes.StructType(::Type{C2}) = StructTypes.Mutable()
end
end
end

struct MyStruct1
val::Int
end
StructTypes.@Struct MyStruct1
StructTypes.@NullType struct MyStruct2
val::Int
end

StructTypes.@Mutable mutable struct MyStruct3
val::Int
end

@testset "Macros" begin
@test StructTypes.StructType(MyStruct1) isa StructTypes.Struct
@test StructTypes.StructType(MyStruct2) isa StructTypes.NullType
@test StructTypes.StructType(MyStruct3) isa StructTypes.Mutable

# Test an expression that is not a struct def
expr = StructTypes.macro_constructor(Expr(:a), StructTypes.Struct)
@test_throws ArgumentError eval(expr)

# Test a symbol that is not a type
expr = StructTypes.macro_constructor(:var, StructTypes.Struct)
eval(quote
var = 1
end)
@test_throws ArgumentError eval(expr.args[1]) # Extract body from within escape
end