Search code examples
compilationprogramming-languageserlang

How to define a wildcard pattern using cerl:c_clause


I'm trying to compile some personal language to erlang. I want to create a function with pattern matching on clauses.

This is my data :

Data =
    [ {a, <a_body> }
    , {b, <b_body> }
    , {c, <c_body> }
    ].

This is what i want :

foo(a) -> <a_body>;
foo(b) -> <b_body>;
foo(c) -> <c_body>;
foo(_) -> undefined. %% <- this

I do that at the moment :

MkCaseClause =
    fun({Pattern,Body}) ->
        cerl:c_clause([cerl:c_atom(Pattern)], deep_literal(Body))
    end,
WildCardClause = cerl:c_clause([ ??? ], cerl:c_atom(undefined)),
CaseClauses = [MkCaseClause(S) || S <- Data] ++ [WildCardClause],

So please help me to define WildCardClause. I saw that if i call my compiled function with neither a nor b nor c it results in ** exception error: no true branch found when evaluating an if expression in function ....

When i print my Core Erlang code i get this :

'myfuncname'/1 =
    fun (Key) ->
        case Key of
          <'a'> when 'true' -> ...
          <'b'> when 'true' -> ...
          <'c'> when 'true' -> ...
        end

So okay, case is translated to if when core is compiled. So i need to specify a true clause as in an if expression to get a pure wildcard. I don't know how to do it, since matching true in an if expression and in a case one are different semantics. In a case, true is not a wildcard.

And what if i would like match expressions with wildcards inside like {sometag,_,_,Thing} -> {ok, Thing}.

Thank you


Solution

  • I've found a way to do this

    ...
    WildCardVar = cerl:c_var('_Any'),
    WildCardClause = cerl:c_clause([WildCardVar], cerl:c_atom(undefined)),
    ...
    

    It should work for inner wildcards too, but one has to be careful to give different variable names to each _ wildcard since only multiple _ do not match each other, variables do.

    f(X,_, _ ) %% matches f(a,b,c)
    f(X,_X,_X) %% doesn't