@@ -35,19 +35,26 @@ WExpr ReadExprRaw(WSLINK lp, int depth) {
3535 return e;
3636 }
3737 if (type == WSTKSTR ) {
38- const char * s = nullptr ;
39- if (!WSGetString (lp, &s))
40- return WExpr::mkError (" WSGetString failed" );
41- WExpr e; e.kind = WExpr::String; e.strVal = s;
42- WSReleaseString (lp, s);
38+ // Use UTF-8 variant so Wolfram char escapes like \|01F605 and \[Alpha]
39+ // are decoded to actual UTF-8 bytes instead of being returned verbatim.
40+ const unsigned char * s = nullptr ;
41+ int bytes = 0 , chars = 0 ;
42+ if (!WSGetUTF8String (lp, &s, &bytes, &chars))
43+ return WExpr::mkError (" WSGetUTF8String failed" );
44+ WExpr e; e.kind = WExpr::String;
45+ e.strVal .assign (reinterpret_cast <const char *>(s), bytes);
46+ WSReleaseUTF8String (lp, s, bytes);
4347 return e;
4448 }
4549 if (type == WSTKSYM ) {
46- const char * s = nullptr ;
47- if (!WSGetSymbol (lp, &s))
48- return WExpr::mkError (" WSGetSymbol failed" );
49- WExpr e; e.kind = WExpr::Symbol; e.strVal = s;
50- WSReleaseSymbol (lp, s);
50+ // UTF-8 variant — decodes \|NNNN / \[Name] into UTF-8 bytes.
51+ const unsigned char * s = nullptr ;
52+ int bytes = 0 , chars = 0 ;
53+ if (!WSGetUTF8Symbol (lp, &s, &bytes, &chars))
54+ return WExpr::mkError (" WSGetUTF8Symbol failed" );
55+ WExpr e; e.kind = WExpr::Symbol;
56+ e.strVal .assign (reinterpret_cast <const char *>(s), bytes);
57+ WSReleaseUTF8Symbol (lp, s, bytes);
5158 return e;
5259 }
5360 if (type == WSTKFUNC ) {
0 commit comments