Host bindings
The JSON names things. C++ implements them. If you only write JSON and never bind, scripts can still define fn and call each other, plus the defaults print, len, str, type. Anything that talks to the real program (graphics, files, entities) needs a bind.
bind
engine.bind("spawn", [](const std::vector<rescripted::Value>& args) -> rescripted::Value {
if (args.size() < 2) {
throw rescripted::RuntimeError("spawn(name, hp)");
}
// ... create object in the game ...
return rescripted::Value(static_cast<double>(new_id));
});
Scripts:
let id = spawn("goblin", 12);
Rebind print if you want stdout:
engine.bind("print", [](const std::vector<rescripted::Value>& args) {
for (const auto& a : args) std::cout << a.to_string() << '\n';
return rescripted::Value();
});
unbind("print") removes it. Scripts that call it after that throw.
List every host function you bind in builtins.functions and/or custom.host_functions so the next agent and the user can see the contract.
bind_type
Registers a constructor and binds the same name.
engine.bind_type("vec2", [](const std::vector<rescripted::Value>& args) {
std::map<std::string, rescripted::Value> m;
m["x"] = args.size() > 0 ? args[0] : rescripted::Value(0.0);
m["y"] = args.size() > 1 ? args[1] : rescripted::Value(0.0);
return rescripted::Value(std::move(m));
});
let p = vec2(1, 2);
Separately, this declaration form is parsed from custom.types:
entity Hero { hp = 10; speed = 3; }
That does not call your bind_type constructor. It builds a map and run stores it as Hero. Use bind_type for Name(...) calls; use entity declarations for data blocks. You may do both.
bind_decorator
Runs when a script is loaded, once per decorated function.
std::vector<std::string> exports;
engine.bind_decorator("export", [&](const std::string& target, const rescripted::Value&) {
exports.push_back(target);
});
Language JSON:
"custom": {
"decorators": [
{ "name": "export", "prefix": "@", "description": "Visible to the host" }
]
}
Script:
@export
fn tick() { return 1; }
The hook receives the function name (tick) and the bound Value function. Prefix must lex as an operator-like token (@ works). If you use # as prefix, it may collide with line comments — pick something the lexer will not eat.
Decorators on let / types are parsed onto the statement but only function declarations currently fire hooks at load.
Libraries
CMake compiles .c++ files into the target. The host names them. See libraries.md.
engine.add_library("app.math", rescripted::library::math);
engine.add_library_file("MyMod", "packages/MyMod/main.mylang");
Lifetime
Bindings live on the engine, not on a script. unload does not remove binds or libraries. remove_language does not remove binds. You unbind or remove_library explicitly.