I'm working on embedding Embeddable Common Lisp into a library and I've been writing utility functions to convert ECL's cl_object
to various C/C++ types - e.g. to convert a cl_object
representing a string to a std::string.
My question is this - why am I failing to retrieve a string containing the name of a symbol in ECL?
I'm having trouble getting the following function ecl_symbol_to_string
to work, which should take an ECL symbol and return a std::string with it's name:
string ecl_symbol_to_string(cl_object sym) {
return ecl_string_to_string(sym->symbol.name);
}
string ecl_string_to_string(cl_object echar) {
string res("");
int j = echar->string.dim; //get dimension
ecl_character* selv = echar->string.self; //get pointer
//do simple pointer addition
for(int i=0;i<j;i++){
res += (*(selv+i));
}
return res;
};
Note that ecl_string_to_string
works for lisp strings.
A simple unit test illustrates the failure:
TEST_CASE( "ecl_symbol_to_string returns a string for symbol",
"[ecl_string_to_string]" ) {
LispRuntime *rt = new LispRuntime("()");
std::string eval_script;
cl_object eval_result;
std::string subject_result;
eval_script = "'mysymbol";
eval_result = rt->evaluate(eval_script);
REQUIRE( ECL_SYMBOLP(eval_result) );
subject_result = ecl_symbol_to_string(eval_result);
REQUIRE ( ECL_STRINGP(cl_symbol_name(eval_result)) );
std::cout << subject_result.c_str() << std::endl;
REQUIRE( subject_result.compare("mysymbol") == 0 );
delete rt;
}
This test case prints out MM
for the call to cout. I have also tried comparing to "MYSYMBOL", which fails, and "M" which passes.
LispRuntime::eval_script simply converts and evaluates the form:
cl_object LispRuntime::evaluate(std::string &code) {
cl_object form = c_string_to_object(code.c_str());
cl_object result = cl_eval(form);
return result;
}
I compiled ECL version 16.1.3 locally with the C++ option enabled, with debugging symbols and with all other settings default. Any assistance is greatly appreciated.
I believe this is a unicode/non-unicode mix-up: ECL defines two string types in object.h. One is
ecl_base_string
, where the memberself
ultimately typedefs to anunsigned char*
and the other isecl_string
where the memberself
usually (depending on compile time arguments, I think) typedefs to aint*
. You're accessing it as anecl_string
.If you trace through the workings of
ecl_make_symbol
you find it ends up calling the functionmake_constant_base_string
which returns a base string. Thus yourecl_string_to_string
accesses it through the wrong type.I suspect the easiest solution is to build a type-check/conversion into
ecl_string_to_string
:The extra code I've added was heavily copied from the ECL function
cl_make_symbol
. I decided to convert toecl_base_string
rather thanecl_string
since the C++ string won't accept unicode characters anyway. You could probably do it the other way round if you had good reason to.