Free Electron
Exposing Components to Scripting

In C++, member functions of components are exposed using the plugin system.

(see Plugin Walkthrough)

To bind to scripting languages there are the following options:

Direct support in the script binding module

The preferred method of direct binding is to bind interfaces, not implementations.

Pros:

Cons:

Direct Binding in Lua

In ext/lua/LuaComponent.cc there is the function populateMethods() which is where directly bound interfaces have their implementations bound. Note that this binding is between a string (the function name) and C-like functions.

void LuaComponentObject::populateMethods(void)
{
if(is<SignalerI>())
{
setMethod("insert", signal_insert);
setMethod("signal", signal_signal);
}
if(is<HandlerI>())
{
setMethod("handle", handler_handle);
setMethod("slot", handler_slot);
}
...
}

The C-like binding functions usually go through this sequence:

(preferred)

See fe::ConfigI

ParserI (deprecated)

see fe::ParserI

ParserI is simply an interface which itself is directly bound as above, but allows components to expose arbitrary functionality that can be called via a sequence of string tokens.

Pros:

Cons:

Example Usage:

class MyParser : virtual public ParserI
{
public:
virtual void parse(std::vector<String> &tokens)
{
for(int i = 0; i < tokens.size(); i++)
{
feLog("%s\n", tokens[i].c_str());
}
}
};

ParserI in Lua

In lua a call to a ParserI component might look like:

c_parser = create("ArbitraryI.SomeObjectThatIsAParserI")
c_parser:parse("string one", 2) -- note that 2 is converted into a string

DispatchI (only when ConfigI falls short)

see fe::DispatchI

DispatchI is simply an interface which itself is directly bound as above. DispatchI supports named calls with typed arguments.

With DispatchI all arguments are two-way/by-reference/read-write.

Pros:

Cons:

Example Usage:

class MyDispatch : virtual public DispatchI, virtual Initialize<MyDispatch>
{
public:
virtual void initialize(void)
{
dispatch<Record>("my_function");
dispatch<int>("my_function");
dispatch<float>("sqr");
}
virtual bool call(const String &a_name, std::vector<Instance> a_argv)
{
if(a_name == "my_function")
{
Record r = a_argv[0].cast<Record>();
int &i = a_argv[1].cast<int>();
feLog("myfunction(record, %d)\n", i);
i = 42;
}
if(a_name == "sqr")
{
float &f = a_argv[0].cast<float>();
f = f*f;
}
return true;
}
virtual SignatureMap &signatures(void)
{
return m_signatures;
}
private:
SignatureMap m_signatures;
};

DispatchI in Lua

Due to the way lua works, to support DispatchI's two-way arguments, the return values are the written version of the call arguments.

In lua a call to a DispatchI component might look like:

c_dispatch = create("ArbitraryI.SomeObjectThatIsADispatchI")
return_rec, return_int = c_dispatch:my_function(rec, 17)