1
$\begingroup$

I am attempting to send text from a WSTP C++ backend to the Mathematica kernel which should be parsed and rendered as boxes.

The goal is for the user to see the outputs of things like Echo as:

enter image description here

Frustratingly, when text like this is sent as a packet through WSTP, it does not render, and hides anything else in the string:

enter image description here

I construct the string representation of the boxes in C++ through raw string literals (having also tried explicit character escaping):

std::string x = R"delimiter(\!\(\*SubscriptBox[A,0]\))delimiter"

which, by writing to file, I have confirmed produces precisely the input to the Echo in my first example.

Yet when I send Echo[x] to the kernel through

WSPutFunction(stdlink, "EvaluatePacket", 1);
WSPutFunction(stdlink, "Echo", 1);
WSPutString(stdlink, x.c_str());
WSEndPacket(stdlink);

it doesn't render. What am I doing wrong?

Note that I must embed the boxes into larger strings. Ergo something like this workaround, letting the kernel generate the box strings, is not acceptable:

std::string expr = "Subscript[A,0]";

WSPutFunction(stdlink, "EvaluatePacket", 1);
WSPutFunction(stdlink, "Echo", 1);

// send StringJoin[..., ToString @ StandardForm @ ToExpression @ expr]
WSPutFunction(stdlink, "StringJoin", 2);
    WSPutString(stdlink, "message prefix or something: ");
    WSPutFunction(stdlink, "ToString", 1);
        WSPutFunction(stdlink, "StandardForm", 1);
            WSPutFunction(stdlink, "ToExpression", 1);
                WSPutString(stdlink, expr.c_str());
$\endgroup$

1 Answer 1

1
$\begingroup$

A compromise is to let the kernel generate the boxes string and pass it back to the WSTP process, for concatenation with other strings as needed.

std::string local_getStandardFormFromMMA(std::string expr) {
    
    WSPutFunction(stdlink, "EvaluatePacket", 1);
    WSPutFunction(stdlink, "ToString", 1);
    WSPutFunction(stdlink, "StandardForm", 1);
    WSPutFunction(stdlink, "ToExpression", 1);
    WSPutString(stdlink, expr.c_str());
    WSEndPacket(stdlink);
    
    // I like to live dangerously
    long success;
    WSCheckFunction(stdlink, "ReturnPacket", &success);
    
    const char* response;
    WSGetString(stdlink, &response);
    std::string ret = std::string(response);
    WSReleaseString(stdlink, response);
    return ret;
}

Needlessly communicating with the kernel to obtain a string is still a small evil I'd like to avoid, so I will keep this question open.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.