1

I'm trying to use LeMP to generate some C# bindings for a C++ library, and as part of this I need to generate a string that combines together some arguments from a LeMP macro to use in the DllImport EntryPoint value. Looking at the docs, it seems like a combination of concatId and stringify should do the job, but I can't get it to work. Here's a slightly simplified version of the code in question:

define TypedIndexer2D($CONTAINER_TYPE, $T1, $T2)
{
    replace(MethodName => concatId(Buffer, $CONTAINER_TYPE, GetExpr_, $T1, $T2));
    replace(CFunction => concatId(buffer_, $CONTAINER_TYPE, _getexpr__, $T1, $T2));

    [DllImport(Constants.LibName, EntryPoint = CFunction)]
public static extern IntPtr MethodName(IntPtr obj, IntPtr x, IntPtr y);
}

TypedIndexer2D(Int, Var, Var);

This emits the following:

[DllImport(Constants.LibName, EntryPoint = buffer_Int_getexpr__VarVar)] 
public static extern IntPtr BufferIntGetExpr_VarVar(IntPtr obj, IntPtr x, IntPtr y);

However, I need this:

[DllImport(Constants.LibName, EntryPoint = "buffer_Int_getexpr__VarVar")] 
public static extern IntPtr BufferIntGetExpr_VarVar(IntPtr obj, IntPtr x, IntPtr y);

(note the quoted EntryPoint).

I had thought that it would be something like the following:

replace(CFunction => stringify(concatId(buffer_, $CONTAINER_TYPE, _getexpr__, $T1, $T2)));

However that just emits the following:

[DllImport(Constants.LibName, EntryPoint = "concatId(buffer_, Int, _getexpr__, Var, Var)")]

How can I persuade LeMP to generate the string that I need here? Thanks!

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
j4m3z0r
  • 397
  • 1
  • 3
  • 8

1 Answers1

0

The answer is indeed to run stringify on the output of concatId, but there's a trick to it.

The difficulty is caused by execution order. Macros ordinarily run "outside-in", outermost macro first, in contrast to normal functions that run "inside-out". Therefore

stringify(concatId(Tea, ring, Cot, ton));

produces "concatId(Tea, ring, Cot, ton)". There isn't a super elegant way to reverse the order yet - in custom define macros you can use a [ProcessChildrenBefore] attribute, but this doesn't let you to modify the existing behavior of stringify. Here's a technique that works:

replacePP(xx => concatId(Tea, ring, Cot, ton)) { stringify(xx); }
// Output: "TearingCotton";

in contrast to normal replace, replacePP preprocesses the match and replacement expressions, thus concatId happens before stringify. Applying this solution to your TypedIndexer2D, we get

define TypedIndexer2D($CONTAINER_TYPE, $T1, $T2)
{
    replace(MethodName => concatId(Buffer, $CONTAINER_TYPE, GetExpr_, $T1, $T2));
    replacePP(CFunction => concatId(buffer_, $CONTAINER_TYPE, _getexpr__, $T1, $T2));

    [DllImport(Constants.LibName, EntryPoint = stringify(CFunction))]
    public static extern IntPtr MethodName(IntPtr obj, IntPtr x, IntPtr y);
}
Qwertie
  • 16,354
  • 20
  • 105
  • 148