Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8159333
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 6, 20262026-06-06T17:52:23+00:00 2026-06-06T17:52:23+00:00

Disclaimer : I kept this because some things may be useful to others, however,

  • 0

Disclaimer: I kept this because some things may be useful to others, however, it does not solve what I had initially tried to do.

Right now, I’m trying to solve the following:

Given something like {a, B, {c, D}} I want to scan through Erlang forms given to parse_transform/2 and find each use of the send operator (!). Then I want to check the message being sent and determine whether it would fit the pattern {a, B, {c, D}}.

Therefore, consider finding the following form:

{op,17,'!',
           {var,17,'Pid'},
           {tuple,17,[{atom,17,a},{integer,17,5},{var,17,'SomeVar'}]}}]}]}

Since the message being sent is:

{tuple,17,[{atom,17,a},{integer,17,5},{var,17,'SomeVar'}]}

which is an encoding of {a, 5, SomeVar}, this would match the original pattern of {a, B, {c, D}}.

I’m not exactly sure how I’m going to go about this but do you know of any API functions which could help?

Turning the given {a, B, {c, D}} into a form is possible by first substituting the variables with something, e.g. strings (and taking a note of this), else they’ll be unbound, and then using:

> erl_syntax:revert(erl_syntax:abstract({a, "B", {c, "D"}})).
{tuple,0,
   [{atom,0,a},
    {string,0,"B"},
    {tuple,0,[{atom,0,c},{string,0,"D"}]}]}

I was thinking that after getting them in the same format like this, I could analyze them together:

> erl_syntax:type({tuple,0,[{atom,0,a},{string,0,"B"},{tuple,0,[{atom,0,c},string,0,"D"}]}]}).
tuple
%% check whether send argument is also a tuple.
%% then, since it's a tuple, use erl_syntax:tuple_elements/1 and keep comparing in this way, matching anything when you come across a string which was a variable...

I think I’ll end up missing something out (and for example recognizing some things but not others … even though they should have matched).
Are there any API functions which I could use to ease this task? And as for a pattern match test operator or something along those lines, that does not exist right? (i.e. only suggested here: http://erlang.org/pipermail/erlang-questions/2007-December/031449.html).

Edit: (Explaining things from the beginning this time)

Using erl_types as Daniel suggests below is probably doable if you play around with the erl_type() returned by t_from_term/1 i.e. t_from_term/1 takes a term with no free variables so you’d have to stay changing something like {a, B, {c, D}} into {a, '_', {c, '_'}} (i.e. fill the variables), use t_from_term/1 and then go through the returned data structure and change the ‘_’ atoms to variables using the module’s t_var/1 or something.

Before explaining how I ended up going about it, let me state the problem a bit better.

Problem

I’m working on a pet project (ErlAOP extension) which I’ll be hosting on SourceForge when ready. Basically, another project already exists (ErlAOP) through which one can inject code before/after/around/etc… function calls (see doc if interested).

I wanted to extend this to support injection of code at the send/receive level (because of another project). I’ve already done this but before hosting the project, I’d like to make some improvements.

Currently, my implementation simply finds each use of the send operator or receive expression and injects a function before/after/around (receive expressions have a little gotcha because of tail recursion). Let’s call this function dmfun (dynamic match function).

The user will be specifying that when a message of the form e.g. {a, B, {c, D}} is being sent, then the function do_something/1 should be evaluated before the sending takes place. Therefore, the current implementation injects dmfun before each use of the send op in the source code. Dmfun would then have something like:

case Arg of
    {a, B, {c, D}} -> do_something(Arg);
    _ -> continue
end

where Arg can simply be passed to dmfun/1 because you have access to the forms generated from the source code.

So the problem is that any send operator will have dmfun/1 injected before it (and the send op’s message passed as a parameter). But when sending messages like 50, {a, b}, [6, 4, 3] etc… these messages will certainly not match {a, B, {c, D}}, so injecting dmfun/1 at sends with these messages is a waste.

I want to be able to pick out plausible send operations like e.g. Pid ! {a, 5, SomeVar}, or Pid ! {a, X, SomeVar}. In both of these cases, it makes sense to inject dmfun/1 because if at runtime, SomeVar = {c, 50}, then the user supplied do_something/1 should be evaluated (but if SomeVar = 50, then it should not, because we’re interested in {a, B, {c, D}} and 50 does not match {c, D}).

I wrote the following prematurely. It doesn’t solve the problem I had. I ended up not including this feature. I left the explanation anyway, but if it were up to me, I’d delete this post entirely… I was still experimenting and I don’t think what there is here will be of any use to anyone.

Before the explanation, let:

msg_format = the user supplied message format which will determine which messages being sent/received are interesting (e.g. {a, B, {c, D}}).

msg = the actual message being sent in the source code (e.g. Pid ! {a, X, Y}).

I gave the explanation below in a previous edit, but later found out that it wouldn’t match some things it should. E.g. when msg_format = {a, B, {c, D}}, msg = {a, 5, SomeVar} wouldn’t match when it should (by “match” I mean that dmfun/1 should be injected.

Let’s call the “algorithm” outlined below Alg. The approach I took was to execute Alg(msg_format, msg) and Alg(msg, msg_format). The explanation below only goes through one of these. By repeating the same thing only getting a different matching function (matching_fun(msg_format) instead of matching_fun(msg)), and injecting dmfun/1 only if at least one of Alg(msg_format, msg) or Alg(msg, msg_format) returns true, then the result should be the injection of dmfun/1 where the desired message can actually be generated at runtime.

  1. Take the message form you find in the [Forms] given to parse_transform/2 e.g. lets say you find: {op,24,'!',{var,24,'Pid'},{tuple,24,[{atom,24,a},{var,24,'B'},{var,24,'C'}]}}
    So you would take {tuple,24,[{atom,24,a},{var,24,'B'},{var,24,'C'}]} which is the message being sent. (bind to Msg).

  2. Do fill_vars(Msg) where:

    -define(VARIABLE_FILLER, "_").
    -spec fill_vars(erl_parse:abstract_form()) -> erl_parse:abstract_form().
    %% @doc This function takes an abstract_form() and replaces all {var, LineNum, Variable} forms with 
    %% {string, LineNum, ?VARIABLE_FILLER}.
    fill_vars(Form) ->
        erl_syntax:revert(
            erl_syntax_lib:map(
            fun(DeltaTree) ->
                case erl_syntax:type(DeltaTree) of
                    variable ->
                        erl_syntax:string(?VARIABLE_FILLER);
                    _ ->
                        DeltaTree
                end
            end,
            Form)).
    
  3. Do form_to_term/1 on 2’s output, where:

    form_to_term(Form) -> element(2, erl_eval:exprs([Form], [])).
    
  4. Do term_to_str/1 on 3’s output, where:

    -define(inject_str(FormatStr, TermList), lists:flatten(io_lib:format(FormatStr, TermList))).
    term_to_str(Term) -> ?inject_str("~p", [Term]).
    
  5. Do gsub(v(4), "\"_\"", "_"), where v(4) is 4’s output and gsub is: (taken from here)

    gsub(Str,Old,New) -> RegExp = "\\Q"++Old++"\\E", re:replace(Str,RegExp,New,[global, multiline, {return, list}]).
    
  6. Bind a variable (e.g. M) to matching_fun(v(5)), where:

    matching_fun(StrPattern) ->
        form_to_term(
            str_to_form(
                ?inject_str(
                    "fun(MsgFormat) ->
                        case MsgFormat of
                            ~s ->
                                true;
                            _ ->
                                false
                        end
                    end.", [StrPattern])
            )
        ).
    
    str_to_form(MsgFStr) ->
        {_, Tokens, _} = erl_scan:string(end_with_period(MsgFStr)),
        {_, Exprs} = erl_parse:parse_exprs(Tokens),
        hd(Exprs).
    
    end_with_period(String) ->
        case lists:last(String) of
            $. -> String;
            _ -> String ++ "."
        end.
    
  7. Finally, take the user supplied message format (which is given as a string), e.g. MsgFormat = “{a, B, {c, D}}”, and do: MsgFormatTerm = form_to_term(fill_vars(str_to_form(MsgFormat))). Then you can M(MsgFormatTerm).

e.g. with user supplied message format = {a, B, {c, D}}, and Pid ! {a, B, C} found in code:

2> weaver_ext:fill_vars({tuple,24,[{atom,24,a},{var,24,'B'},{var,24,'C'}]}).
{tuple,24,[{atom,24,a},{string,0,"_"},{string,0,"_"}]}
3> weaver_ext:form_to_term(v(2)).
{a,"_","_"}
4> weaver_ext:term_to_str(v(3)).
"{a,\"_\",\"_\"}"
5> weaver_ext:gsub(v(4), "\"_\"", "_").
"{a,_,_}"
6> M = weaver_ext:matching_fun(v(5)).
#Fun<erl_eval.6.13229925>
7> MsgFormatTerm = weaver_ext:form_to_term(weaver_ext:fill_vars(weaver_ext:str_to_form("{a, B, {c, D}}"))).
{a,"_",{c,"_"}}
8> M(MsgFormatTerm).
true
9> M({a, 10, 20}).
true
10> M({b, "_", 20}).
false
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-06T17:52:24+00:00Added an answer on June 6, 2026 at 5:52 pm

    There is functionality for this in erl_types (HiPE).

    I’m not sure you have the data in the right form for using this module though. I seem to remember that it takes Erlang terms as input. If you figure out the form issue you should be able to do most what you need with erl_types:t_from_term/1 and erl_types:t_is_subtype/2.

    It was a long time ago that I last used these and I only ever did my testing runtime, as opposed to compile time. If you want to take a peek at usage pattern from my old code (not working any more) you can find it available at github.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Disclaimer: this question is purely informational and does not represent an actual problem I'm
Disclaimer: not sure this is WordPress related or not. I'm following a simple tutorial
Disclaimer, I'm not a PHP programmer, so you might find this question trivial. That's
Disclaimer Despite the title, this is a genuine question, not an attempt at Emacs/Vi
(Firstly, as a disclaimer, this is related to an assignment. I'm not asking anyone
Disclaimer: This question is not about fixing visual studio So, I've used VSS for
Disclaimer This is not strictly a programming question, but most programmers soon or later
( Disclaimer: This question is not specific to ASP.NET) I have a control which
Disclaimer before the uppity types start in: This is not to be deployed in
Disclaimer: This is not actually a programming question, but I feel the audience on

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.