AngelScript 1.10.0 WIP 6 (2004/10/31)

Started by
24 comments, last by WitchLord 19 years, 5 months ago
Quote:Original post by abrken
You should AT LEAST test the return value from ExecuteString, I'm sure it gives asINVALID_CONFIGURATION witch means : "Hey man, I cannot compile your code since you have made something wrong with the library BEFORE compiling".

Hm, okay, guess that makes sense.. I was only checking the outstream as I thought all errors would be printed there, guess I'll be a lot more rigorous with return values in the future. Still, would it be possible to keep the engine in a usable state even after an error like that or at least also print a visible message when it happens? It did confuse me a lot until I finally figured out what was going wrong.
Advertisement
Both Build() and ExecuteString() will return asINVALID_CONFIGURATION, in this case. No message is output to the output stream as the compilation isn't even begun.

I could possibly allow AngelScript continue to work even when the configuration is invalid, but it might produce more difficult to find errors further on. This is why I decided to simply disable everything if the application configures the engine incorrectly. By disabling the engine you can be sure that the configuration is completely correct when it works.

I will add the "Invalid configuration" message to the outstream again.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

It's a great day for AngelScript. WIP 5 has been released with first ever support for native arrays, which I'll describe in detail further down. First the list of changes in this WIP:

* The C++ VM was optimized using the ideas introduced with the ASM VM. Because of the optimizing features of the MSVC compiler the C++ VM is now even faster than the ASM VM (about 10%). Later on the ASM VM will be optimized further as it is possible to remove quite a few instructions from each bytecode implementation even after the C++ compilers optimization. The ASM VM has potential to become twice as fast as the C++ VM, but 25% faster ought to be a realistic number.
* The message "Invalid configuration" is now written to the output stream again if some of the registration functions failed. People kept forgetting to check the return codes, and got confused as to why the scripts didn't work. This might help pointing them in the right direction.
* The operator 'xor' has been added for boolean types. An alias '^^' is also available. The operator does the exact same thing as '!=' does for boolean types, but it might be easier to understand in complex boolean expressions.
* Native support for single dimensional arrays of any type has been added. They work perfectly for scripts, but cannot be passed to or from the application yet. The next WIP will complete this support.

That's what has changed. Now here is the detailed explanation for how the arrays work.

An array variable is declared as followed:

int[] a; // empty array of integers
object[] b(5); // 5 objects initialized with the default constructor

The array's elements must be initialized manually at the moment:

b[0] = GetObject("mace");
b[1] = GetObject("hammer");
...

An array can be passed by value or by reference to functions, but the internal array buffer is shared so it doesn't really make a difference except for a slight overhead of initializing the other array object when passed by value.

void TestArray()
{
int[] a(1);
a[0] = 1;
ModifyArray(a);
// a[0] will now be 0, even though the array object was passed by value
}

void ModifyArray(int[] a)
{
a[0] = 0;
}

The arrays have a default method length() that returns the number of elements in the array.

int[] array;
uint a = array.length();

The element access is out-of-bounds checked, so an exception is thrown if the script tries to access elements outside the allocated array.

int[] array(10);
array[10] = 3; // Throws "out of bounds" exception

Let's see what more is needed to explain. The array indices are 0 based. You can declare an array of pointers, but you can't declare a pointer to an array.

The object's registered destructor and assignment operator can't be virtual methods on GNUC based compilers, yet. MSVC should be able to handle virtual methods.

The object's constructor can not be a virtual method on any compiler as one of it's task is to initialize the virtual function table for the object.

What is still missing in the support for arrays:

* Multi dimensional arrays. The script compiler may crash if you try to declare these at the moment. If the compiler doesn't crash the VM will. It hasn't been tested. I will probably not include support for multi dimensional arrays in version 1.10.0, maybe in 1.10.1. If I don't I will at least make sure the compiler gives the proper error messages, instead of crashing without warning.
* Automatic initialization of arrays in declarations: int[] a = {23, 23, 4, 12, 5};
* Temporary array objects in expressions: Function(int[](10));
* Cleaning up the code
* A C++ interface that allow the application to interact with script arrays
* I will try to allow the application to extend the native array object with more methods and operators, e.g. resize(), copy(), push_back(), +, etc.
* Support virtual destructor and assignment operators for the contained objects on all compilers

In the future I will also allow the application to register specialized array objects that will override the built-in array. The benefit of this is that the application can have a much cleaner interface with the script when working with a specialized array object, it would for example be possible to register std::vector. The script writer wouldn't know the difference.

I think that is all for now. Please let me know if you find any problems, or have any suggestions on how to improve the array support.

Regards,
Andreas Jönsson
Author of AngelScript
www.AngelCode.com

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

The sixth WIP has been released. The changes for this version include:

  • Minor changes to make compilation on Linux smoother (thanks Johannes Plass)
  • Separate output files for release and debug mode (thanks Dan Royer for that suggestion)
  • Inclusion of std::vector add-on that allows for simple registration of any std::vector object (implementation by Anthony "Deyja" Casteel). Note: MSVC6 seems to have trouble with vectors of vectors, e.g: vector< vector<int> > doesn't work. On GNUC it works though.
  • It is now possible to register array objects, overriding AngelScript's native array for that type. This is the only way the application can interact with arrays in scripts. The array objects are registered as normal objects, except their data type should include the [] type modifier, e.g: int[].
  • Multidimensional arrays are now working as well
  • Array elements are copied on assignment with the native array.
  • bug fix: Constants weren't correctly converted to references when passed as function arguments (thanks Anthony "Deyja" Casteel for detecting that one)
  • bug fix: Switch case didn't treat 8 and 16 bit integer types correctly (thanks Alain "abrken" Bridel for spotting that)
  • bug fix: Exception handler wasn't working correctly

There is still a little work left before I can release the final version of 1.10.0.

  • Native arrays currently don't work on GNUC. It is possible to override the native array though.
  • Registration of arrays of pointers probably don't work at the moment.
  • The engine should report configuration error if an application function is registered that tries to interact with the native array.
  • I need to verify that native arrays work with saved/loaded bytecode.

Once that has been done I will take care of the compiler performance problems that have been reported lately. I also want to make a much improved interface to script functions. I will also improve the rules implicit conversion.

In parallel with that I plan to start working on AngelScript 2. AngelScript 2 will change the way objects are handled by the script engine, which will be more like that of Java, with that pointers will no longer be supported. These changes will improve the library in several ways, where the two most important ones are a much cleaner syntax for script writers, and a library that is much easier to maintain and improve.

However AngelScript 1.x.x will continue to exist and I will continue supporting it with bug fixes and minor enhancements.

Regards,
Andreas Jönsson
Author of AngelScript

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Yah!

I didn't actually try to register vector<vector<*> >, but they seem to have worked for rain dog. I'll dump it into MSVC6 and check it out. I'll also have it register the array type.

[edit]
Due to the simplicity of overiding native arrays, simply registering the vector with the name 'containedtype[]' should work. No new code required on my part! :D
Though might I ask why you chose to leave erase and insert out by default?

Also, it should be noted that you can't register vector<vector<int> > without first registering vector<int>. It worked for me (No errors from MSVC or AS - but I didn't actually test the run time behavior) Can you show me your code that failed?
[/edit]

[Edited by - Deyja on November 1, 2004 5:00:03 PM]
First of all, the problem with your RegisterVector() is probably because of a bug in MSVC6, and not in your implementation. If there is a work-around I would be very pleased to hear about it.

I wrote a test case for your RegisterVector(), as I can't release code with the library that I haven't tested. You'll find this in the feature test project with the filename test_stdvector.cpp. This is where I discovered the problem with vector< vector<int> >.

Here's the code to save you some time:

#include "utils.h"#include "../../add_on/std_vector/stdvector.h"namespace TestStdVector{#define TESTNAME "TestStdVector"static void print(std::string &str){	printf("%s", str.c_str());}static void print(int num){	printf("%d", num);}static void Assert(bool expr){	if( !expr )	{		printf("Assert failed\n");		asIScriptContext *ctx = asGetActiveContext();		if( ctx )			ctx->SetException("Assert failed");	}}static const char *script1 ="void Test()                         \n""{                                   \n""   TestInt();                       \n""   TestChar();                      \n""   Test2D();                        \n""}                                   \n""                                    \n""void TestInt()                      \n""{                                   \n""   int[] A(5);                      \n""   Assert(A.size() == 5);           \n""	A.push_back(6);                  \n""   Assert(A.size() == 6);           \n""	int[] B(A);                      \n""   Assert(B.size() == 6);           \n""	A.pop_back();                    \n""   Assert(B.size() == 6);           \n""   Assert(A.size() == 5);           \n""	A = B;                           \n""   Assert(A.size() == 6);           \n""	A.resize(8);                     \n""   Assert(A.size() == 8);           \n""	A[1] = 20;                       \n""	Assert(A[1] == 20);              \n""}                                   \n""                                    \n""void TestChar()                     \n""{                                   \n""   int8[] A(5);                     \n""   Assert(A.size() == 5);           \n""   A.push_back(6);                  \n""   Assert(A.size() == 6);           \n""   int8[] B(A);                     \n""   Assert(B.size() == 6);           \n""   A.pop_back();                    \n""   Assert(B.size() == 6);           \n""   Assert(A.size() == 5);           \n""   A = B;                           \n""   Assert(A.size() == 6);           \n""   A.resize(8);                     \n""   Assert(A.size() == 8);           \n""   A[1] = 20;                       \n""   Assert(A[1] == 20);              \n""}                                   \n""                                    \n""void Test2D()                       \n""{                                   \n""   int[][] A(2);                    \n""   int[] B(2);                      \n""   A[0] = B;                        \n""   A[1] = B;                        \n""                                    \n""   A[0][0] = 0;                     \n""   A[0][1] = 1;                     \n""   A[1][0] = 2;                     \n""   A[1][1] = 3;                     \n""                                    \n""   Assert(A[0][0] == 0);            \n""   Assert(A[0][1] == 1);            \n""   Assert(A[1][0] == 2);            \n""   Assert(A[1][1] == 3);            \n""}                                   \n";using namespace std;bool Test(){	bool fail = false; 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	RegisterStdString(engine);	RegisterVector<char>("int8[]", "int8", engine);	RegisterVector<int>("int[]", "int", engine);#ifdef __GNUC__	RegisterVector< std::vector<int> >("int[][]", "int[]", engine);#else	// There is something going wrong when registering the following.	// It looks like it is a linker problem, but I can't be sure.	printf("%s: MSVC can't register vector< vector<int> >\n", TESTNAME);#endif	engine->RegisterGlobalFunction("void Print(string &)", asFUNCTIONP(print, (std::string&)), asCALL_CDECL);	engine->RegisterGlobalFunction("void Print(int)", asFUNCTIONP(print, (int)), asCALL_CDECL);	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_CDECL);	COutStream out;	engine->AddScriptSection(0, TESTNAME, script1, strlen(script1), 0);	int r = engine->Build(0, &out);	if( r < 0 )	{		fail = true;		printf("%s: Failed to compile the script\n", TESTNAME);	}	asIScriptContext *ctx = 0;	r = engine->ExecuteString(0, "Test()", 0, &ctx);	if( r != asEXECUTION_FINISHED )	{		printf("%s: Failed to execute script\n", TESTNAME);		if( r == asEXECUTION_EXCEPTION )			PrintException(ctx);				fail = true;	}		if( ctx ) ctx->Release();	engine->Release();	// Success	return fail;}} // namespace


I left Erase() and Insert() commented out because MinGW didn't want to compile with them. I didn't look into why as I was a bit short on time, maybe for the next release.

Well, the compilation and linking of vector< vector<int> > passes without reporting any errors. But in test_stdvector the execution fails with an exception when running the first test case that only uses vector<int>. This leads me to believe that it is a linker problem, in that MSVC6's linker confuses the function names for vector< vector<int> > with those of vector<int>. If I don't register vector< vector<int> >, the vector<int> works fine. To eliminate any doubts that the error was in AngelScript I even wrote a second test case, test_arrayobject.cpp, that overrides the default array object using non-templated classes. Needless to say this one worked just fine.









AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement