{"id":30617271,"url":"https://github.com/curtd/macroutilities.jl","last_synced_at":"2025-09-13T16:29:39.614Z","repository":{"id":178826196,"uuid":"662408631","full_name":"curtd/MacroUtilities.jl","owner":"curtd","description":"Because remembering stuff about Julia Exprs is overrated","archived":false,"fork":false,"pushed_at":"2024-10-17T19:37:18.000Z","size":669,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-30T10:03:01.462Z","etag":null,"topics":["julia","macros","metaprogramming"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/curtd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-07-05T04:39:18.000Z","updated_at":"2024-10-17T19:15:01.000Z","dependencies_parsed_at":"2023-12-30T00:36:00.607Z","dependency_job_id":"38d4f3d0-3117-4f05-92ac-3b597acd21b9","html_url":"https://github.com/curtd/MacroUtilities.jl","commit_stats":null,"previous_names":["curtd/macroutilities.jl"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/curtd/MacroUtilities.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FMacroUtilities.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FMacroUtilities.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FMacroUtilities.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FMacroUtilities.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/curtd","download_url":"https://codeload.github.com/curtd/MacroUtilities.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FMacroUtilities.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272833342,"owners_count":25000874,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["julia","macros","metaprogramming"],"created_at":"2025-08-30T10:02:57.474Z","updated_at":"2025-08-30T10:03:12.111Z","avatar_url":"https://github.com/curtd.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MacroUtilities\n\n[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://curtd.github.io/MacroUtilities.jl/stable/)\n[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://curtd.github.io/MacroUtilities.jl/dev/)\n[![Build Status](https://github.com/curtd/MacroUtilities.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/curtd/MacroUtilities.jl/actions/workflows/CI.yml?query=branch%3Amain)\n\n`MacroUtilities.jl` provides semantically meaningful decomposition of Julia syntax. The goal of this package is to help you, the package author, focus on implementing the logic of your macros, rather than the low-level details of manipulating expression syntax. \n\n## Keyword Arguments From Expressions\nAlthough macros operate at an expression level and don't have access to the types of their arguments, it is sometimes useful to access named values with expected literal types such as `String`, `Bool`, `Int`, or `Nothing`. \n\nThis package provides the `@parse_kwargs` macro, which can be used in your own macro definitions to specify type / default value information for keyword arguments parsed from expressions. An `ArgumentError` is thrown if either the required keyword arguments (i.e., those without a default value) are missing or the provided argument does not have the expected type.\n\nE.g., \n```julia\njulia\u003e using MacroUtilities \n\njulia\u003e macro ex_macro(args...)\n       @parse_kwargs args... begin \n           key1::Int \n           key2::Union{Bool,Symbol,Vector{Symbol}} = false\n       end\n       return quote \n           (key1 = $key1, key2 = $key2) \n       end |\u003e esc\n   end\n\njulia\u003e @ex_macro key2 = true\n\nERROR: ArgumentError: No value provided for key `key1`\n...\n\njulia\u003e @ex_macro key1=false key2=a\nERROR: ArgumentError: In `key1 = rhs` expression, rhs (= false) has type Bool, which is not one of the expected types (Int64)\n...\n\njulia\u003e @ex_macro key1=1 key2=(a,b,c)\n(key1 = 1, key2 = [:a, :b, :c])\n```\n\n## Expression Parsing \nDepending on the structure and purpose of your macro, you may also need to parse expressions involving various types of expressions, such as function calls or function definitions, in order to transform or extract information from them.  \n\nThis package provides various high-level syntactical constructs such as the `FuncDef`, `FuncCall`, and `FuncArg` types, along with the `from_expr` and `to_expr` functions, for extracting information from function expressions. \n\n```julia\njulia\u003e ex = quote \n            \"\"\"\n                f(a, b; key1, kwargs...)\n            \"\"\"\n            function f(a::T, b::Int; key1=\"abc\", kwargs...) where {T}\n                return nothing\n            end\n        end\njulia\u003e f = from_expr(FuncDef, ex)\n       FuncDef - begin\n           #= REPL[2]:2 =#\n           #= REPL[2]:2 =# Core.@doc \"    f(a, b; key1, kwargs...)\\n\" function f(a::T, b::Int; key1 = \"abc\", kwargs...) where T\n                   #= REPL[2]:5 =#\n                   #= REPL[2]:6 =#\n                   return nothing\n                end\n       end\n\njulia\u003e f.args\n       2-element Vector{FuncArg}:\n       FuncArg - a::T\n       FuncArg - b::Int\n\njulia\u003e f.kwargs\n       OrderedCollections.OrderedDict{Symbol, FuncArg} with 2 entries:\n       :key1   =\u003e FuncArg - key1 = abc\n       :kwargs =\u003e FuncArg - kwargs...\n\njulia\u003e f.line\n       :(#= REPL[2]:2 =#)\n\njulia\u003e f.whereparams\n       1-element view(::Vector{Any}, 2:2) with eltype Any:\n       :T\n\njulia\u003e to_expr(f)\n       quote\n       #= REPL[2]:2 =#\n       #= REPL[2]:2 =# Core.@doc \"    f(a, b; key1, kwargs...)\\n\" function f(a::T, b::Int; key1 = \"abc\", kwargs...) where T\n            #= REPL[2]:5 =#\n            #= REPL[2]:6 =#\n            return nothing\n       end\n       end\n```\n\nYou can also apply transformations to the arguments or keyword arguments of `f` with the `map_args` and `map_kwargs` functions, respectively.\n\n```julia\njulia\u003e map_args(t-\u003eFuncArg(t; name=Symbol(uppercase(string(t.name)))), f) |\u003e to_expr\n       quote\n       #= REPL[2]:2 =#\n       #= REPL[2]:2 =# Core.@doc \"    f(a, b; key1, kwargs...)\\n\" function f(a::T, b::Int; key1 = \"abc\", kwargs...) where T\n            #= REPL[2]:5 =#\n            #= REPL[2]:6 =#\n            return nothing\n       end\n       end\n\njulia\u003e map_kwargs(t-\u003eFuncArg(t; name=Symbol(uppercase(string(t.name)))), f) |\u003e to_expr\n      quote\n      #= REPL[2]:2 =#\n      #= REPL[2]:2 =# Core.@doc \"    f(a, b; key1, kwargs...)\\n\" function f(a::T, b::Int; KEY1 = \"abc\", KWARGS...) where T\n              #= REPL[2]:5 =#\n              #= REPL[2]:6 =#\n              return nothing\n          end\n      end\n```\n\nThere are additional types for parsing specific, more estoteric syntaxes (such as nested dotted expressions `A.b.c.d.e`) into a more manageable form.\n\n## Macro calls\nYou can use the `MacroCall` type to parse macro call expressions, as well as apply the parsed expression to a set of arguments, yielding another `MacroCall`, i.e., \n```julia \njulia\u003e m = MacroCall(; name=Symbol(\"@a\"))\n       MacroCall - @a\n\njulia\u003e m_applied = m(:(key=1), :(f(x)))\n       MacroCall - @a key = 1 f(x)\n\njulia\u003e to_expr(m_applied)\n       :(@a key = 1 f(x)) \n```\n\n## Similar Packages \n- [`MacroTools.jl`](https://github.com/FluxML/MacroTools.jl)\n- [`Expronicon.jl`](https://github.com/Roger-luo/Expronicon.jl/tree/main)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurtd%2Fmacroutilities.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcurtd%2Fmacroutilities.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurtd%2Fmacroutilities.jl/lists"}