# AngelScript 1.9.0 WIP 4 (2004/08/31)

This topic is 4891 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Ok, I'll work on some way of defining the message format in as_config.h. Probably a simple printf() formatting string, with numbered arguments.

I'll also see if I can give better information on the exact token that causes the message. This can be either the length, or the exact token, or both.

Another thing I've been thinking on adding is a line offset when calling AddScriptSection(), this will allow you to offset the line numbers reported in error messages and exceptions thrown by the scripts. This would be used by those who, like abrken, add code before the actual script.

abrken:

Could you give me a little more detail on what you want? What do you mean with a trick to raise a warning?

##### Share on other sites
My doubts are cleared. no problems as of now!

##### Share on other sites
It's ok, i have raised a Warning like this :
int iWarning;iWarning += 500;

That result in :
TheOtherCode (2, 1) : Info    : Compiling void TheOtherCode()TheOtherCode (11, 10) : Warning : 'iWarning' is not initialized.

##### Share on other sites
I've uploaded WIP 3 now.

This version adds dynamic binding of functions between modules, which allow functions to call into other modules.

The following code shows how the import can be done:

//// Tests importing functions from other modules//// Test author: Andreas Jonsson//#include "angelscript.h"#include <stdio.h>#include <stddef.h>#include <string.h>#include <string>namespace TestImport{#define TESTNAME "TestImport"static std::string output;class COutStream : public asIOutputStream{public:	void Write(const char *text) { printf(text); /*output += text;*/ }};static const char *script1 ="import void Test() from \"DynamicModule\";   \n""void main()                                  \n""{                                            \n""  Test();                                    \n""}                                            \n";static const char *script2 ="void Test()            \n""{                      \n""  number = 1234567890; \n""}                      \n";bool Test(){	bool fail = false;	int number = 0; 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	engine->RegisterGlobalProperty("int number", &number);	COutStream out;	engine->AddScriptSection(0, TESTNAME ":1", script1, strlen(script1));	engine->Build(0, &out);	engine->AddScriptSection("DynamicModule", TESTNAME ":2", script2, strlen(script2));	engine->Build("DynamicModule", &out);	int module1 = engine->GetModuleID(0);	// Bind imported functions	int c = engine->GetImportedFunctionCount(0);	for( int n = 0; n < c; ++n )	{		char buffer[256];		engine->GetImportedFunctionDeclaration(module1 + n, buffer, 256);		// Get module name from where the function should be imported		const char *moduleName = engine->GetImportedFunctionSourceModule(module1 + n);		int funcID = engine->GetFunctionIDByDecl(moduleName, buffer);		engine->BindImportedFunction(module1 + n, funcID);	}	engine->ExecuteString(0, "main()", &out, 0);	engine->Release();	if( number != 1234567890 )	{		printf("%s: Failed to set the number as expected\n", TESTNAME);		fail = true;	}	// Success	return fail;}} // namespace

I'm however not satisfied with how the asIScriptEngine interface has become so bloated with the latest additions. I will therefore break out the module interface, which will make it easier to work with.

Regards,
Andreas Jönsson

##### Share on other sites
Quote:
 Original post by WitchLordI'm however not satisfied with how the asIScriptEngine interface has become so bloated with the latest additions. I will therefore break out the module interface, which will make it easier to work with.

What do you mean when you write this ?
1/ Do the syntax that is discribed in your code will change for the script (import ... from ...)
2/ Do the link between the modules will change for the C++ (loop GetImportedFunctionCount)
3/ Is this going to be an internal change that wont change anything from script to C++ interface.

Since I was waiting for dynamic binding of functions between modules, I can wait for another version if WIP 3 is just a primary approach.

##### Share on other sites
I see the reason for all this manual work (users might have special cases), but I don't think it's really needed.

I would preffer it to be more automated. Something like engine->BindImported("module") after all the modules that are needed are compiled.

Or with slightly more control: engine->BindImported("module", "ImportedName", "RealModuleName");

The completely manual approach can co-exist with this one, should application writers desire this.

Just offering my suggestions :).

##### Share on other sites
abrken:

I'll answer your last question first: This will change the library interface. Though the changes won't be that big that you can't start using WIP 3 already.

Currently the script syntax is:

import void Function(int param) from "module";import void AnotherFunc() from "module";import void OneMoreFunc() from "module";

I am playing with the thought of changing this to:

import from "module" {  void Function(int param);  void AnotherFunc();  void OneMoreFunc();}

But that's not really the important change. I might even use both ways.

What I noticed when doing the tests for importing functions is that there can be a slight confusion between imported function IDs and script function IDs. The current loop for binding functions will change a little, but not that much that you can't start using WIP 3 already.

The code will probably end up something like this:

asIScriptModule *module = engine->GetModule(0);// Bind imported functionsint c = module->GetImportedFunctionCount();for( int n = 0; n < c; ++n ){  char buffer[256];  module->GetImportedFunctionDeclaration(n, buffer, 256);  // Get module name from where the function should be imported  const char *moduleName = module->GetImportedFunctionSourceModule(n);  asIScriptModule *otherModule = engine->GetModule(moduleName);  asFUNCID funcID = otherModule->GetFunctionIDByDecl(buffer);  module->BindImportedFunction(n, funcID);}

Basically, most of the functions that require a module name or module index will be moved into the module interface. There will be one more interface to keep track of but I think the interfaces will be more easy to understand and use.

Gyrbo:

I've had the same thoughts, and I just might go ahead and do something like that.

##### Share on other sites
If anyone has any suggestion for how to improve the dynamic binding of modules now is the time to tell me. Give WIP 3 a try and give me your feedback.

Thanks.

##### Share on other sites
WIP3 is not as easy to integrate as others ... acString changed to asString need extra work !

##### Share on other sites
Yes, I decided to include acCString and acCArray as integrated parts of the library, which meant changing the name of them to follow the naming standard of the library.

Are you using acCString/acCArray outside the library?

##### Share on other sites
Did you try to compile AngelScrit as Debug ?

Try it and you get compil error in as_bytecode.cpp.

This is what I was meaning in : it's not so easy ...

void asCByteCode::DebugOutput(const char *name){#ifdef AS_DEBUG	mkdir("AS_DEBUG");	acCString str = "AS_DEBUG\\";

Also, I'm working with source control, witch mean changing files, and it takes some times too !

And finaly, no I'm not using acStrings !

Ooops, Yes finaly I was using acString !

Oooops 2, I must write some wrapper code to pure virtual methods added to asIScriptEngine !

##### Share on other sites
Hi everyone

This might sound a little stupid, but why do we need to bind modules manually?

Wouldn't it be much easyer if we just define that modules from which we use functions must be previously declared?

In the importing module we could write
BModule::trackEntity(e);

and the engines build method tries to bind the function automatically.

In case we need late binding (if we have circular dependencies) we still could do the binding by hand (although the engine could do this too by keeping track of what was bound and what is still unbound and checking for unbound functions after a new module is included), but this should not be the regular case.

Now, there are probably some good reasons why we need to do this by hand. I'm not familiar with the internals of AngelScript so forgive me if this really sounds like a silly thing to do.

Regards,
Tom

##### Share on other sites
abrken:

Ooops from me too [wink]. I haven't compiled with the AS_DEBUG flag in quite some time. I'll do that to check the code.

You are doing some heavy integration with the library. It's only expected that you are going to have more work to do with each version.

zola:

I chose not to require the modules to be compiled in a specific order because it makes it easier to use. With the import statement a module can be correctly compiled even if the other module doesn't exist yet. You can even execute the code, but if an imported function is called before being bound you'll get a script exception.

I also wanted to allow rebinding afterwards, so that the imported functions could be exchanged at runtime, possibly even by a function called from the script itself.

Another reason why I didn't want to make it automatic is that I want to allow an application to have control over which functions that are bound. It might be that an application don't want to allow binding of all script functions, in which case it must verify what functions the script is trying to bind.

If I didn't have the above requirements I could have used automatic binding. However, I will probably do what Gyrbo suggested and provide a method that automatically binds all imported functions after compilation, which is probably what most want to do anyway.

##### Share on other sites
After giving it a try I've decided not to create the separate module interface.

It got more awkward to work with the engine when using a separate interface. It became necessary to explicitly create the modules, and then keep track of references, etc. It was good that there was less parameters to pass with each call, but the negative impact outweighed the good ones.

I will still do some changes to the interface, but they will be minor and mostly cosmetic, e.g. using a struct for function IDs instead of just an integer (for compile time verification).

Just thought I'd let you know...

##### Share on other sites
After having integrated WIP3 I get returned to WIP2 !

My program that was working suddenly get troubles on string destructors (std::string integrated).

Sad to say that I can't reproduce the bug in a code snippset, so I have decided to continue working with WIP2.

When I get time I'll try to understand what's going on with ~string, at the time it re-work perfectly with WIP2 !

##### Share on other sites
I don't know either what's wrong. I have a test case in the framework that uses std::string and it works perfectly.

That said Lennart Denninger discovered yesterday a bug when doing multiple assignments in one statement:

a = b = c;

If a, b, and c are registered objects with the assignment behaviour then they won't be assigned correctly.

I've already fixed this problem in WIP4, and I'll show you how to fix it here as well:

In the file as_scriptengine.cpp:

Method RegisterObjectBehaviour():

	if( !isGlobal )		func.objectType = type.extendedType;

after this part (aprox. 70 lines into the function):

	r = bld.ParseFunctionDeclaration(decl, &func);	if( r < 0 )		return ConfigError(asINVALID_DECLARATION);

	f->objectType = func.objectType;

after this part (aprox. 10 lines into the function):

	asCScriptFunction *f = new asCScriptFunction;

[Edited by - WitchLord on August 31, 2004 8:44:03 AM]

##### Share on other sites
I've uploaded the latest work in progress.

• Removed GetModuleID()
• Added GetModuleIndex(), and GetModuleNameFromIndex()
• Changed the interface for import functions, to work with module name and imported function index, instead of a single function ID. This was done to prevent confusion between functionID and imported function indices.
• Added GetFunctionIDByIndex() and GetGlobalVarIDByIndex()
• bug fix: Multiple assignments in the same statement didn't work for objects. Introduced in 1.9.0 (thanks Lennart Denninger)
• Added functions for automatically binding all functions imported in a module. New error code asCANT_BIND_ALL_FUNCTIONS
• Added the lineOffset parameter to AddScriptSection()
• bug fix: Saving and loading byte code is actually working now. Introduced in 1.9.0

As I mentioned earlier the changes aren't quite so drastic as I had planned.

The new method BindAllFunctions() can be used to automatically bind all imported functions after the modules have been built.

I will probably only do a few minor corrections here and there before releasing 1.9.0 as beta.

##### Share on other sites
Yes !

I have downloaded WIP4 and everything is working like in WIP2 now !
Thank's for wathever you did to the WIP3 code !

Also I did test imported function and it's great ! (except that it took me some times to understand how BindAllImportedFunctions was working !)

I've got one question :
Why does the import statement MUST be outside a function ? (of course I ask you this because inserting an import statement in a function raised me a compile error !).

Again, great job, great thank you.

##### Share on other sites
I'm glad that WIP4 is working ok.

I'll update the manual when I release version 1.9.0 as beta. It ought to explain everything about importing functions. [smile]

The import statement must be global because AngelScript doesn't understand nested functions. After the function has been declared with the import statement, the compiler will treat it just like any other function.

##### Share on other sites
I'm having trouble with the asFUNCTIONP/PR macros. Each of the asMETHODP/PR versions work fine, but I can't seem to get the asFUNCTIONP/PR macros to work on overloaded functions (or on a non-overloaded functions for that matter).

pEngine->RegisterGlobalFunction("void ReadFile(const string& filename, string& buffer)", asFUNCTIONP(ReadFile, (const string&, string&)), asCALL_CDECL);d:\Code\Rpg_test\asExtensions.cpp(174): error C2664: 'asFunctionPtr' : cannot convert parameter 1 from 'void (__cdecl *)(const std::string &,std::string &)' to 'asFUNCTION_t'// ...pEngine->RegisterGlobalFunction("Command& CMD(string scr, string fmt)", asFUNCTIONPR(CMD, (string,string), CCommand&), asCALL_CDECL);d:\Code\Rpg_test\asExtensions.cpp(171): error C2664: 'asFunctionPtr' : cannot convert parameter 1 from 'CCommand &(__cdecl *)(std::string,std::string)' to 'asFUNCTION_t'

##### Share on other sites
I gave it a try, and found out that the macro needs one more cast to void(*)() in order to work.

The fix is to change the macros in angelscript.h to the following:

#define asFUNCTIONP(f,p) asFunctionPtr((void (*)())((void (*)p)(f)))
#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())((r (*)p)(f)))