I'm mucking with the CScriptEngine code right now, aiming to refactor it so new scripting interfaces can be defined easily. If anyone has experience with the scripting engine code (or WSH in general) and is willing to share anything they might know, I'd appreciate it. And in case anyone is willing to lend a hand, here's my current battle plan. It's probably going to change a lot, too; this is just something I've built out while hacking on a pseudo-solution in Notepad++.
Initial thoughts: non-WSH Lua support seems to have been hacked into the CScriptEngine class to short-curcuit normal CScriptEngine behavior with regard to WSH, including lots of special-cases like IsLua(), ExecuteLua(), etc. It's basically DIY polymorphism. At first glance it doesn't seem too hard to create a base interface (IScriptEngine), which any scripting engine will have to implement.
In the process, I'm removing CreateScriptEngine() and DisableScripting(), moving their functionality into the constructor/destructor, and using exceptions in the constructor. Changing calling code here was trivial, and I think it looks better too.
Here's the current IScriptEngine interface. Please don't assume this is the final version. This is just what's pseudo-working right now. (I haven't created a LuaScriptEngine yet.)
The biggest design roadblock I've hit - luckily during the Notepad++ phase - is that MUSHclient intentionally treats Lua and WSH differently. This is going to make it really, really, really hard to abstract behind a common interface. For example, Lua functions registered with a trigger will receive the line styles as an extra parameter. This is passed as a table, which I'm not sure WSH can gracefully handle. (VBscript is an obvious example of a language without built-in maps.) Obviously, I can't lock down Lua from doing this. It would be simpler for me XD but it's a non-option.
I have two solutions I've been mulling over. The first is to come up with some common parameter/returns interface that remains backward-compatible and can handle the breadth of options Lua has. Ummm... Just writing that down was disheartening. The only way I've considered to do this is to use a DISPPARAMS structure of VT_ARRAY|VT_VARIANT, which I think can be nested. Backward compatibility is still up in the air at this point.
The second solution I've considered is to have "contextual" methods in IScriptEngine, so the engine knows what your intention is and can adapt the parameters accordingly. This seems most workable, especially as it seems to be how ExecuteLua works currently. (Among its parameters are a PaneLine and a t_regexp...) The idea is that you'd pass everything a given call might want, and the script engine implementation would pass on only the parameters it can handle. This is my preferred solution.
I'd really like to hear feedback on this in particular. It's the biggest issue I have right now.
tl;dr: I'm making lots of changes to scripting support, and I'd like feedback. I also have a pretty good-sized problem. Can you help me?
Thanks for reading! :S
Initial thoughts: non-WSH Lua support seems to have been hacked into the CScriptEngine class to short-curcuit normal CScriptEngine behavior with regard to WSH, including lots of special-cases like IsLua(), ExecuteLua(), etc. It's basically DIY polymorphism. At first glance it doesn't seem too hard to create a base interface (IScriptEngine), which any scripting engine will have to implement.
In the process, I'm removing CreateScriptEngine() and DisableScripting(), moving their functionality into the constructor/destructor, and using exceptions in the constructor. Changing calling code here was trivial, and I think it looks better too.
Here's the current IScriptEngine interface. Please don't assume this is the final version. This is just what's pseudo-working right now. (I haven't created a LuaScriptEngine yet.)
class IScriptEngine
{
public:
virtual ~IScriptEngine() {}
virtual DISPID GetDispid (const CString& strName) = 0;
virtual bool Parse (const CString& strCode, const CString& strWhat) = 0;
virtual bool Execute (DISPID& dispid,
LPCTSTR szProcedure,
const unsigned short iReason,
LPCTSTR szType,
LPCTSTR szReason,
DISPPARAMS& params,
long& nInvocationCount,
COleVariant* result) = 0;
// Use to create a script engine by name.
static IScriptEngine* Create (CString& strLanguage, CMUSHclientDoc* pDoc);
};The biggest design roadblock I've hit - luckily during the Notepad++ phase - is that MUSHclient intentionally treats Lua and WSH differently. This is going to make it really, really, really hard to abstract behind a common interface. For example, Lua functions registered with a trigger will receive the line styles as an extra parameter. This is passed as a table, which I'm not sure WSH can gracefully handle. (VBscript is an obvious example of a language without built-in maps.) Obviously, I can't lock down Lua from doing this. It would be simpler for me XD but it's a non-option.
I have two solutions I've been mulling over. The first is to come up with some common parameter/returns interface that remains backward-compatible and can handle the breadth of options Lua has. Ummm... Just writing that down was disheartening. The only way I've considered to do this is to use a DISPPARAMS structure of VT_ARRAY|VT_VARIANT, which I think can be nested. Backward compatibility is still up in the air at this point.
The second solution I've considered is to have "contextual" methods in IScriptEngine, so the engine knows what your intention is and can adapt the parameters accordingly. This seems most workable, especially as it seems to be how ExecuteLua works currently. (Among its parameters are a PaneLine and a t_regexp...) The idea is that you'd pass everything a given call might want, and the script engine implementation would pass on only the parameters it can handle. This is my preferred solution.
I'd really like to hear feedback on this in particular. It's the biggest issue I have right now.
tl;dr: I'm making lots of changes to scripting support, and I'd like feedback. I also have a pretty good-sized problem. Can you help me?
Thanks for reading! :S