Jump to content

  • Log In with Google      Sign In   
  • Create Account

Multiple Scripting Languages With Identical User-work


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
4 replies to this topic

#1 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 09 August 2012 - 02:53 AM

I am attempting to make a system that would allow a user (in C++) to bind classes to their scripting language of choice, then compile the script and run it. The primary language I am using for any scripting needs is Squirrel, but I want to be able to switch languages at runtime (possibly with an enum), and using the same code, bind to, say, Python. I was thinking of doing it by having a class for each language's Class (eg. has Var, Func, Prop, Bind, etc, functions for binding) and a class for it's Script (eg. Compile and Run functions), then instantiating those runs through the Subsystem (which changes based on the enum to a child class with creation methods), which passes back a Class* pointer or Script* pointer, but I'd prefer it to be implicit. Like this:
[source lang="cpp"]void BindPlayer(){ scriptLang = "Squirrel"; // SClass is for ScriptClass, the parent top class, not for Squirrel specifics SClass<Player> pclass; pclass.Var("TestVar", &Player::TestVar); // Bind other vars/funcs/props pclass.Bind("Player"); Script scr; scr.Compile("TestPlayer.nut"); scr.Run(); scriptLang = "Python"; // Do the bind again, same code. Script scrp; scrp.Compile("TestPlayer.py"); scrp.Run();}[/source]
How feasible is this method; if at all, how exactly would I go about the implicit creation via another class? If that method wouldn't work well, then what would?

Sponsor:

#2 Ashaman73   Crossbones+   -  Reputation: 8005

Like
0Likes
Like

Posted 09 August 2012 - 03:13 AM

Supporting multiple languages should not be a technical problem at all, when using some kind of clean interface and binding. Something like this:

[source lang="cpp"]class ScriptInterface{ startNewCall( string pName); addParam(int pIntParam); addParam(string pStringParam); ScriptResult executeCall();}class ScriptSquirrel : ScriptInterface{// implement script binding etc.}class ScriptFactory { ScriptInterface createNewScriptInterface( String pLanguage) ;}[/source]


But the practical benefit could be lower than expected when mixing languages, because most scripting languages runs in its own VM including all data.

#3 Hodgman   Moderators   -  Reputation: 31968

Like
0Likes
Like

Posted 09 August 2012 - 03:16 AM

I'm working on a similar system, so I hope it's feasible Posted Image

I manually reflect on my bindable classes like:
class Test1
{
public:
    eiBind(Test1);
    int DoStuff() { return 0; }
private:
    int m_stuff;
};
eiBindClass( Test1 )
  eiBeginMethods()
    eiBindMethod( DoStuff )
  eiEndMethods()
  eiBeginData()
    eiBindData( m_stuff )
  eiEndData()
eiEndBind();
And then to bind it to a specific scripting VM, I can fetch the above info with
const TypeBinding& b = ReflectTest1();
Which gives me structures like
typedef void (FnTask)( void* obj, void* args, uint argSize );
struct DataBinding
{
    const char* name;
    memptr memvar;
    uint offset, size;
    Type type;
};
struct MethodBinding
{
    const char* name;
    FnTask* task;
    const DataBinding* args;
    uint argCount;
};
struct TypeBinding
{
    const DataBinding* data;
    uint dataCount;
    const MethodBinding* method;
    uint methodCount;
};

Edited by Hodgman, 09 August 2012 - 03:19 AM.


#4 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 09 August 2012 - 07:49 PM

I understand both of your concepts. I tried to implement both. For the first (Ashaman73) concept, I did it like so:
[source lang="cpp"]//SClass has Var, Func, Prop, and Bind functions without implementations//SqClass is a child and implements the functions for squirrel//ScriptSystem::NewClass() returns a pointer to a child SqClass or eg. LuaClass, based on mLang (set by SetLang();ScriptSystem::SetLang("Squirrel");SClass $Player# & scp = ScriptSystem::NewClass<Player>();scp.Var("Health", &Player::mHealth);scp.Bind("Player");Script& sqs = ScriptSystem::NewScript();sqs.Compile("Test.nut");sqs.Run();[/source]
Now, this should basically work, except that if I want to, say, shut off the Squirrel VM and launch the Lua VM, I have to rebind those classes. Using something closer to the other given concept (Hodgman), I'd be able to bind once, and it should keep a list of the classes to be bound in ScriptSystem (Since then the SClass holds actual data), then on VM binding (called just before script launching begins), it would take the data from all SClass instances in the list, using it to create VM specific Classes, binding their members and vars, then binding the actual class (Also, then it's easy to remove them from the bind list). The only problem is, I can't really figure out how I should manage the structures to use for data containment, and later usage for binding to the specific VM.
I was thinking something like this:
[source lang="cpp"]struct VarData{ string label; void* ref;};struct ClassData{ vector $VarData# vars;};struct SClass{ template $class T, typename V# void Var(string label, V T::*val) { VarData newvar; newvar.label = label; newvar.ref = val; data.vars.push_back(newvar); } void Bind(string label); ClassData data;};[/source]
But, the problem is about using that given data later.
[source lang="cpp"]Class $Player# cls;for(int i=0; i $ play.data.vars.size(); ++i){ cls.Var(play.data.vars[i].label, play.data.vars[i].ref); RootTable().Bind("NameHere", cls);}[/source] ("<>" are replaced by "$#", the code block doesnt like those characters, for some reason)
Something like that for Squirrel, except I can't use the void pointer directly, so would I use a different type for storage, or how can I cast to the correct type for this situation? I'm just not really sure how I'd approach it.

Edited by taylorsnead, 09 August 2012 - 07:55 PM.


#5 taylorsnead   Members   -  Reputation: 139

Like
0Likes
Like

Posted 02 September 2012 - 01:41 PM

I'm going to bump this, because I still haven't figured it out, and I'm still trying to implement it. I'm able to make a system for multiple languages, but it then forces the programmer to rebind their classes for each language. So, I was attempting to do something like what Hodgman suggested, but I don't really know how I'd reaccess the data later, since it would be a solely automatic grabbing and using of the data and I can't store a type as a variable so that it's known what type to bind it as. Once I can have the data grabbed later on in a separate function with the correct type and stuff, then I can have an easily extensible system to add new languages that work with no changes to existing binding code. Maybe it would be better to bind one language (eg. Squirrel) and use its dynamic typing to create a binding system there that routes back to C++, allowing someone to bind their classes in either Squirrel or C++?




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS