Sign in to follow this  
Desdemona

Strings

Recommended Posts

Desdemona    158
I have a problem that is nailing me in the back. I followed Dentoid's example on using the STL string for AS. When I pass strings from the host application to script functions, everything seems to work ok. But when I start making calls between script functions using string params/return values, then all hell breaks out. This code block shows the utility script functions (called by other script functions):
string get_string(Data* pObj, string tag)
{
	string temp;
	pObj->GetAttributeBase(tag, temp);
	return temp;
}

void sendto(Data* pTarget, string text)
{ pTarget->EnqueueOutput(text); }

This block shows two versions of the same function that are called by the host application:
// This version works fine
void look_monster(Data* pPlayer, Data* pMonster)
{
	string m_name, m_desc, p_name;

	pPlayer->GetAttributeBase("name", p_name);
	pMonster->GetAttributeBase("name", m_name);
	pMonster->GetAttributeBase("desc", m_desc);

	sendto(pPlayer->GetParent(), "\x1B[0;37m" + p_name + " looks at " + m_name + ".\r\n", pPlayer);
	sendto(pPlayer, "\x1B[1;36m" + p_name + "\r\n\x1B[0;37m" + m_desc + "\r\n");
}

// This version crashes
void look_monster(Data* pPlayer, Data* pMonster)
{
	string m_name = get_string(pMonster, "name");
	string m_desc = get_string(pMonster, "desc");
	string p_name = get_string(pPlayer, "name");

	sendto(pPlayer, m_name); // Prints ok
	sendto(pPlayer, m_desc); // Prints ok
	sendto(pPlayer, p_name); // Prints garbage

//	This crashes
//	sendto(pPlayer->GetParent(), "\x1B[0;37m" + p_name + " looks at " + m_name + ".\r\n", pPlayer);
//	sendto(pPlayer, "\x1B[1;36m" + p_name + "\r\n\x1B[0;37m" + m_desc + "\r\n");
}

This is how I am setting up the string in AS.
string string_factory(asUINT length, const char *s)			{ return string(s); }
void string_ctor(string *pthis)								{ new(pthis)string(); }
void string_dtor(string *pthis)								{ pthis->~string(); }
//string& string_assign_string(string &copy, string *pthis)	{ return *new(pthis)string(copy); }
string& string_assign_string(string &copy, string *pthis)	{ return *pthis = copy; }
bool string_equal(const string &l, const string &r)			{ return l == r; }
bool string_not_equal(const string &l, const string &r)		{ return l != r; }
string string_add_string(const string &l, const string &r)	{ return l + r; }

	pEngine->RegisterObjectType("string", sizeof (string), asOBJ_IS_COMPLEX);
	pEngine->RegisterStringFactory("string", asFUNCTION(string_factory), asCALL_CDECL/* | asCALL_RETURNBYREF*/);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(string_ctor), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(string_dtor), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour("string", asBEHAVE_ASSIGNMENT, "string& f(string&)", asFUNCTION(string_assign_string), asCALL_CDECL_OBJLAST);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_EQUAL, "bool f(const string&, const string&)", asFUNCTION(string_equal), asCALL_CDECL);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_NOTEQUAL, "bool f(const string&, const string&)", asFUNCTION(string_not_equal), asCALL_CDECL);
	pEngine->RegisterTypeBehaviour(0, asBEHAVE_ADD, "string f(const string&, const string&)", asFUNCTION(string_add_string), asCALL_CDECL);

I've been staring at this code for too long now and am not any closer to an answer. Any one have an idea?

Share this post


Link to post
Share on other sites
Desdemona    158
Oh, one more thing:

string m_name = get_string(pMonster, "name");
string m_desc = get_string(pMonster, "desc");
string p_name = get_string(pPlayer, "name");

It is always the 3rd string that becomes gibberish, regardless of which order the calls are in.

Share this post


Link to post
Share on other sites
WitchLord    4677
Since it is always the third call that fails, regardless of order it is possibly a bug in AngelScript. I'll take a look at it as soon as possible.

In the meanwhile: What version of the library are you using?

You might also want to use string get_string(Data* pObj, string &tag) instead, since it would avoid passing the string object by value. It will probably not solve your problem but it is a little more efficient.


Share this post


Link to post
Share on other sites
WitchLord    4677
I found two different bugs in WIP 4 that might be related to your problem:

as_bytecode.cpp, ln 293, change to:

d.sfOffset = 0x7FFFFFFE;


as_bytecode.cpp, ln 342, change to:

if( destructors[n].sfOffset == 0x7FFFFFFE )


as_compiler.cpp, ln 1318 - 1321, change to:


{
bc->InstrWORD(BC_COPY, (short)a->type.GetSizeInMemoryDWords());
bc->Pop(1); // Pop the reference to original value
}


With these changes I can successfully run the following test case:

//
// This test shows how to register the std::string to be used in the scripts.
// It also used to verify that objects are always constructed before destructed.
//
// Author: Andreas Jönsson
//

#include "angelscript.h"
#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;

#define TESTNAME "TestStdString"

class COutStream : public asIOutputStream
{
public:
void Write(const char *text) { printf(text); }
};

static string StringFactory(asUINT length, const char *s)
{
return string(s);
}

static void ConstructString(string *thisPointer)
{
new(thisPointer) string();
}

static void DestructString(string *thisPointer)
{
thisPointer->~string();
}

static string &AssignString(string &other, string &thisPointer)
{
return thisPointer = other;
}

static string ConcatenateString(string &first, string &second)
{
return first + second;
}

static string printOutput;

static void PrintString(string &str)
{
printOutput = str;
}

static const char *script2 =
"void testString() \n"
"{ \n"
" print(getString(\"Ida\")); \n"
"} \n"
" \n"
"string getString(string &str) \n"
"{ \n"
" return \"hello \" + str; \n"
"} \n";


bool TestStdString()
{
bool fail = false;

asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

engine->RegisterObjectType ("string", sizeof(string), asOBJ_CLASS_CDA);
engine->RegisterStringFactory ("string", asFUNCTION(StringFactory), asCALL_CDECL);
engine->RegisterObjectBehaviour ("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour ("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour ("string", asBEHAVE_ASSIGNMENT, "string &f(const string&)", asFUNCTION(AssignString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour (0, asBEHAVE_ADD, "string f(const string&, const string &)", asFUNCTION(ConcatenateString), asCALL_CDECL);
engine->RegisterGlobalFunction("void print(string &)", asFUNCTION(PrintString), asCALL_CDECL);

COutStream out;


engine->AddScriptSection(0, TESTNAME, script2, strlen(script2), 0);
engine->Build(0, &out);

engine->ExecuteString(0, "testString()", &out, 0);

if( printOutput != "hello Ida" )
{
fail = true;
printf("%s: Failed to print the correct string\n", TESTNAME);
}

engine->Release();

return fail;
}





You're probably running version 1.8.2, right? I'll verify if the same bugs exists in that version and let you know how to fix them.


Share this post


Link to post
Share on other sites
Desdemona    158
I'm using 1.8.1 at the moment (last official release when I started my project). I'm to a point in my project that it wont be any hassle to start trying out the WIPs, so I'll upgrade to the latest one.

Thanks for the response. Going to lunch now but I'll check your suggestions when I get back

Share this post


Link to post
Share on other sites
Desdemona    158
I tried changing "get_string(Data* pData, string tag)" to "get_string(Data* pData, string& tag)" but that didnt work. For example, if I have a statement like "string p_name = get_string(pPlayer, "name")", then AS will call the function ok. But afterwards, any attempt to use p_name will cause AS to quiety abort out of the function.

I download WIP4 and applied the changes you suggested, but AS is refusing to compile my script code:


Code.as (514, 7) : Error : Expected '('
Code.as (517, 2) : Error : Expected expression value
Code.as (521, 38) : Error : Expected expression value
Code.as (526, 2) : Error : Expected expression value
Code.as (531, 2) : Error : Expected expression value
Code.as (536, 2) : Error : Expected expression value
Code.as (541, 2) : Error : Expected expression value
Code.as (546, 2) : Error : Expected expression value
Code.as (551, 2) : Error : Expected expression value
Code.as (556, 2) : Error : Expected expression value
Code.as (561, 2) : Error : Expected expression value
Code.as (566, 2) : Error : Expected expression value



I am assuming the line numbers relate to the code below are correct. I only have one script file and I added the section at line offset 0.


511 void show_move(Data* pPlayer, Data* pDst, Data* pSrc)
512 {
513 uint temp = 0;
514 uint from = 0;
515 string name, to_src, to_dst;
516
517 from = pSrc->GetId();
518
519 pPlayer->GetAttributeBase("name", name);
520
521 if (pDst->GetRefid("east", temp) && from == temp)
// ...



I'm still looking into this problem at the moment, but yeah, it doesn't make a lot of sense.

Share this post


Link to post
Share on other sites
Desdemona    158
At the moment it seems that if functions that have 2 or more uints declared are causing the problems. If I remove one of the uints from the function it compiles ok.

Also, the declaration "uint temp, from" results in "Code.as (590, 13) : Error : Expected identifier"

Share this post


Link to post
Share on other sites
WitchLord    4677
"from" is a reserved keyword in 1.9.0, as is "import". This is why you're getting these errors.

They are used by the new global statement:

import void function_decl(int param1, int param2) from "module";

I've yet to come up with a good solution for allowing the use of these keywords in other contexts, e.g. variable names.

You could temporarily rename the keywords by changing the as_tokendef.h file.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this