Modules are registered as class handlers — the same mechanism the built-in modules use. You do not need to modify the parser.
kse_mymodule.cpp#include "kse.hpp"
static size_t mymodule_handler(Engine& e, size_t i) {
++i; // skip "MyModule"
if (e.tokenText(i) != ":") return e.skipOptSemi(i);
++i; // skip ":"
std::string method = e.tokenText(i);
++i; // skip method name
if (e.tokenText(i) == "(") ++i; // skip (
if (method == "Hello") {
// read input argument, then outVar (ByRef convention)
Value v = e.evalExpr(i);
if (e.tokenText(i) == ",") ++i; // skip comma
std::string outVar = e.tokenText(i); ++i; // read receiver name
if (e.tokenText(i) == ")") ++i; // skip )
std::string msg = "Hello from MyModule: " + toString(v);
e.setVar(outVar, Value(msg));
return e.skipOptSemi(i);
}
return e.skipOptSemi(i);
}
void register_mymodule(Engine& e) {
e.registerClass("MyModule", mymodule_handler);
}
kse.cppDeclare the registrar at the top:
void register_mymodule(Engine&);
Then call it in the Engine constructor:
Engine::Engine() {
scopedVars_[""];
register_math(*this);
// ... existing registrations ...
register_mymodule(*this); // add this line
}
MakefileSRCS = kse.cpp kse_konsol.cpp kse_math.cpp kse_string.cpp \
kse_file.cpp kse_time.cpp kse_class.cpp kse_try.cpp \
kse_mymodule.cpp
Var:String result;
MyModule:Hello("world", result);
Konsol:Print(result);
e.tokenText(i) // text of token at i
e.tokenCmd(i) // command/type id of token at i
e.tokenLine(i) // source line number
e.tokenCount() // total token count
e.evalExpr(i) // evaluate expression starting at i; advances i past it
e.setVar("name", v) // set a variable (use the caller's outVar name for return values)
e.getVar("name") // get a variable's Value
e.hasVar("name") // check existence
e.skipOptSemi(i) // call as final return; skips ; if present
e.skipPast("}", i) // scan forward to given token, return its index
// Value helpers (free functions from kse_types.hpp)
toString(v) // Value → std::string
toDouble(v) // Value → double
toBool(v) // Value → bool
Value("text") // make a string Value
Value(3.14) // make a number Value
Value(true) // make a bool Value
if (method == "Add") {
Value a = e.evalExpr(i);
if (e.tokenText(i) == ",") ++i;
Value b = e.evalExpr(i);
if (e.tokenText(i) == ",") ++i;
std::string outVar = e.tokenText(i); ++i; // receiver
if (e.tokenText(i) == ")") ++i;
e.setVar(outVar, Value(toDouble(a) + toDouble(b)));
return e.skipOptSemi(i);
}
The pattern: eval each input argument (leaving i at the following delimiter), skip commas between arguments, read the last token as the receiver variable name, skip ), write the result with e.setVar(outVar, ...).
If you want script code to instantiate your module type like a class (field storage, method dispatch), register it via Class:Create at runtime from a .ks file, or directly manipulate e.classDefs() and e.classInsts() from C++ — the same maps the built-in Class: keyword uses.
For a simpler plugin-based approach, see Plugin system.