2016-04-24 05:16:56 +08:00
tutorial: quick 'n' dirty
=========================
2016-04-24 05:07:51 +08:00
2016-04-24 06:24:48 +08:00
These are all the things. Use your browser's search to find things you want.
2016-04-24 05:07:51 +08:00
2016-04-24 09:20:45 +08:00
You'll need to `` #include <sol.hpp> `` /`` #include "sol.hpp" `` somewhere in your code. Sol is header-only, so you don't need to compile anything.
2016-04-24 05:07:51 +08:00
opening a state
---------------
.. code-block :: cpp
2016-04-25 00:40:35 +08:00
int main (int argc, char* argv[]) {
sol::state lua;
// open some common libraries
lua.open_libraries(sol::lib::base, sol::lib::package);
lua.script( "print('bark bark bark!')" );
}
2016-04-24 05:07:51 +08:00
sol::state on lua_State*
------------------------
For your system/game that already has lua, but you'd like something nice:
.. code-block :: cpp
int pre_existing_system( lua_State* L ) {
sol::state_view lua(L);
lua.script( "print('bark bark bark!')" );
2016-04-24 22:09:05 +08:00
return 0;
2016-04-24 05:07:51 +08:00
}
running lua code
----------------
2016-04-24 06:18:02 +08:00
.. code-block :: cpp
2016-04-24 05:07:51 +08:00
sol::state lua;
// load and execute from string
lua.script("a = 'test'");
// load and execute from file
lua.script_file("path/to/luascript.lua");
2016-09-18 10:15:46 +08:00
// run a script, get the result
int value = lua.script("return 54");
// value == 54
2016-04-24 05:07:51 +08:00
// load file without execute
2016-09-18 10:15:46 +08:00
sol::load_result script1 = lua.load_file("path/to/luascript.lua");
2016-04-24 05:07:51 +08:00
script1(); //execute
// load string without execute
2016-09-18 10:15:46 +08:00
sol::load_result script2 = lua.load("a = 'test'");
2016-04-24 05:07:51 +08:00
script2(); //execute
2016-09-18 10:15:46 +08:00
sol::load_result script3 = lua.load("return 24");
int value2 = script3(); // execute, get return value
// value2 == 24
2016-04-24 05:07:51 +08:00
2016-04-24 09:20:45 +08:00
set and get variables
---------------------
2016-04-24 05:07:51 +08:00
You can set/get everything.
.. code-block :: cpp
sol::lua_state lua;
2016-04-24 09:20:45 +08:00
lua.open_libraries(sol::lib::base);
2016-04-24 06:18:02 +08:00
// integer types
lua.set("number", 24);
2016-04-26 03:58:13 +08:00
2016-04-24 06:18:02 +08:00
// floating point numbers
lua["number2"] = 24.5;
2016-04-26 03:58:13 +08:00
2016-04-24 06:18:02 +08:00
// string types
lua["important_string"] = "woof woof";
2016-04-26 03:58:13 +08:00
2016-04-24 06:18:02 +08:00
// non-recognized types is stored as userdata
// is callable, therefore gets stored as a function
2016-04-26 03:58:13 +08:00
lua["a_function"] = [](){ return 100; };
// make a table
lua["some_table"] = lua.create_table_wth("value", 24);
Equivalent to loading a lua file with:
.. code-block :: lua
number = 24
number2 = 24.5
important_string = "woof woof"
a_function = function () return 100 end
some_table = { value = 24 }
Retrieve these variables using this syntax:
.. code-block :: cpp
2016-04-24 06:18:02 +08:00
// implicit conversion
int number = lua["number"];
2016-04-26 03:58:13 +08:00
2016-04-24 06:18:02 +08:00
// explicit get
auto number2 = lua.get<double>("number2");
2016-04-26 03:58:13 +08:00
2016-04-24 06:18:02 +08:00
// strings too
std::string important_string = lua["important_string"];
2016-04-26 03:58:13 +08:00
// dig into a table
int value = lua["value"]["value"];
2016-04-24 05:07:51 +08:00
// get a function
sol::function a_function = lua["a_function"];
int value_is_100 = a_function();
// get a std::function
std::function<int()> a_std_function = lua["a_function"];
int value_is_still_100 = a_std_function();
2016-04-24 09:20:45 +08:00
Retrieve Lua types using `` object `` and other `` sol:: `` types.
2016-04-24 05:07:51 +08:00
.. code-block :: cpp
sol::state lua;
// ... everything from before
sol::object number_obj = lua.get<sol::object>( "number" );
2016-04-24 09:20:45 +08:00
// sol::type::number
sol::type t1 = number_obj.get_type();
2016-04-24 05:07:51 +08:00
sol::object function_obj = lua[ "a_function" ];
2016-04-24 09:20:45 +08:00
// sol::type::function
sol::type t2 = function_obj.get_type();
2016-04-24 05:07:51 +08:00
bool is_it_really = function_obj.is<std::function<int()>(); // true
// will not contain data
sol::optional<int> check_for_me = lua["a_function"];
2016-04-24 22:09:05 +08:00
You can erase things by setting it to `` nullptr `` or `` sol::nil `` .
2016-04-24 05:07:51 +08:00
.. code-block :: cpp
sol::state lua;
2016-04-24 22:09:05 +08:00
lua.script("exists = 250");
2016-04-24 05:07:51 +08:00
2016-04-24 22:09:05 +08:00
int first_try = lua.get_or<int>( 322 );
// first_try == 250
2016-04-24 05:07:51 +08:00
2016-04-24 22:09:05 +08:00
lua.set("exists", sol::nil);
2016-04-24 05:07:51 +08:00
2016-04-24 22:09:05 +08:00
int second_try = lua.get_or<int>( 322 );
// second_try == 322
2016-04-24 05:07:51 +08:00
2016-07-09 15:43:51 +08:00
Note that if its a :doc: `userdata/usertype<../api/usertype>` for a C++ type, the destructor will run only when the garbage collector deems it appropriate to destroy the memory. If you are relying on the destructor being run when its set to `` sol::nil `` , you're probably committing a mistake.
2016-06-28 00:15:32 +08:00
2016-04-24 05:07:51 +08:00
tables
------
2016-04-24 22:09:05 +08:00
:doc: `sol::state<../api/state>` is a table too.
2016-04-24 05:07:51 +08:00
.. code-block :: cpp
sol::state lua;
// Raw string literal for easy multiline
lua.script( R"(
abc = { [0] = 24 }
def = {
ghi = {
bark = 50,
woof = abc
}
}
)"
);
sol::table abc = lua["abc"];
2016-09-01 01:15:43 +08:00
sol::table def = lua["def"];
2016-04-24 05:07:51 +08:00
sol::table ghi = lua["def"]["ghi"];
2016-04-24 09:20:45 +08:00
int bark1 = def["ghi"]["bark"];
int bark2 = lua["def"]["ghi"]["bark"];
2016-04-25 10:45:52 +08:00
// bark1 == bark2 == 50
2016-04-24 09:20:45 +08:00
int abcval1 = abc[0];
int abcval2 = ghi["woof"][0];
2016-04-25 10:45:52 +08:00
// abcval1 == abcval2 == 24
2016-04-24 05:07:51 +08:00
If you're going deep, be safe:
.. code-block :: cpp
2016-04-24 22:09:05 +08:00
sol::state lua;
2016-04-24 06:24:48 +08:00
sol::optional<int> will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"];
// will_not_error == sol::nullopt
int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or<int>(25);
// is 25
// if you don't go safe,
2016-04-24 05:07:51 +08:00
// will throw (or do at_panic if no exceptions)
int aaaahhh = lua["abc"]["hope_u_liek_crash"];
make tables
-----------
Make some:
.. code-block :: cpp
2016-09-01 01:15:43 +08:00
sol::state lua;
2016-04-24 05:07:51 +08:00
lua["abc"] = lua.create_table_with(
0, 24
);
lua.create_named_table("def",
"ghi", lua.create_table_with(
"bark", 50,
2016-04-25 00:49:27 +08:00
// can reference other existing stuff too
"woof", lua["abc"]
2016-04-24 05:07:51 +08:00
)
);
Equivalent Lua code:
.. code-block :: lua
abc = { [0] = 24 }
def = {
ghi = {
bark = 50,
woof = abc
}
}
2016-04-24 22:09:05 +08:00
You can put anything you want in tables as values or keys, including strings, numbers, functions, other tables.
2016-09-09 19:48:28 +08:00
Note that this idea that things can be nested is important and will help later when you get into :ref: `namespacing<namespaceing>` .
2016-04-24 22:09:05 +08:00
functions
---------
They're great. Use them:
.. code-block :: cpp
sol::state lua;
lua.script("function f (a, b, c, d) return 1 end");
2016-04-25 10:45:52 +08:00
lua.script("function g (a, b) return a + b end");
2016-04-24 22:09:05 +08:00
// fixed signature std::function<...>
std::function<int(int, double, int, std::string)> stdfx = lua["f"];
2016-04-25 00:49:27 +08:00
// sol::function is often easier:
// takes a variable number/types of arguments...
2016-04-24 22:09:05 +08:00
sol::function fx = lua["f"];
int is_one = stdfx(1, 34.5, 3, "bark");
int is_also_one = fx(1, "boop", 3, "bark");
// call through operator[]
int is_three = lua["g"](1, 2);
// is_three == 3
double is_4_8 = lua["g"](2.4, 2.4);
// is_4_8 == 4.8
2016-04-25 10:45:52 +08:00
If you need to protect against errors and parser problems and you're not ready to deal with Lua's `longjmp` problems (if you compiled with C), use :doc: `sol::protected_function<../api/protected_function>` .
2016-04-26 03:58:13 +08:00
You can bind member variables as functions too, as well as all KINDS of function-like things:
2016-04-24 22:09:05 +08:00
.. code-block :: cpp
void some_function () {
std::cout << "some function!" << std::endl;
}
2016-04-26 03:58:13 +08:00
void some_other_function () {
std::cout << "some other function!" << std::endl;
}
2016-04-24 22:09:05 +08:00
struct some_class {
int variable = 30;
double member_function () {
return 24.5;
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
// put an instance of "some_class" into lua
2016-04-26 03:58:13 +08:00
// (we'll go into more detail about this later
// just know here that it works and is
// put into lua as a userdata
2016-04-24 22:09:05 +08:00
lua.set("sc", some_class());
2016-04-26 03:58:13 +08:00
// binds a plain function
lua["f1"] = some_function;
lua.set_function("f2", &some_other_function);
2016-04-24 22:09:05 +08:00
// binds just the member function
lua["m1"] = &some_class::member_function;
2016-04-26 03:58:13 +08:00
2016-04-24 22:09:05 +08:00
// binds the class to the type
lua.set_function("m2", &some_class::member_function, some_class{});
// binds just the member variable as a function
lua["v1"] = &some_class::variable;
2016-04-26 03:58:13 +08:00
2016-04-24 22:09:05 +08:00
// binds class with member variable as function
lua.set_function("v2", &some_class::variable, some_class{});
2016-04-26 03:58:13 +08:00
The lua code to call these things is:
2016-04-24 22:09:05 +08:00
2016-04-26 03:58:13 +08:00
.. code-block :: lua
f1() -- some function!
f2() -- some other function!
-- need class instance if you don't bind it with the function
print(m1(sc)) -- 24.5
2016-09-01 01:15:43 +08:00
-- does not need class instance: was bound to lua with one
2016-04-26 03:58:13 +08:00
print(m2()) -- 24.5
-- need class instance if you
-- don't bind it with the function
print(v1(sc)) -- 30
-- does not need class instance:
-- it was bound with one
print(v2()) -- 30
-- can set, still
-- requires instance
v1(sc, 212)
-- can set, does not need
-- class instance: was bound with one
v2(254)
print(v1(sc)) -- 212
print(v2()) -- 254
2016-04-24 22:09:05 +08:00
Can use `` sol::readonly( &some_class::variable ) `` to make a variable readonly and error if someone tries to write to it.
2016-09-18 10:15:46 +08:00
self call
---------
You can pass the 'self' argument through C++ to emulate 'member function' calls in Lua.
.. code-block :: cpp
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table);
// a small script using 'self' syntax
lua.script(R"(
some_table = { some_val = 100 }
function some_table:add_to_some_val(value)
self.some_val = self.some_val + value
end
function print_some_val()
print("some_table.some_val = " .. some_table.some_val)
end
)");
// do some printing
lua["print_some_val"]();
// 100
sol::table self = lua["some_table"];
self["add_to_some_val"](self, 10);
lua["print_some_val"]();
2016-04-25 00:40:35 +08:00
multiple returns from lua
-------------------------
.. code-block :: cpp
sol::state lua;
lua.script("function f (a, b, c) return a, b, c end");
2016-04-26 03:58:13 +08:00
std::tuple<int, int, int> result;
result = lua["f"](100, 200, 300);
2016-04-25 00:40:35 +08:00
// result == { 100, 200, 300 }
int a, int b;
std::string c;
sol::tie( a, b, c ) = lua["f"](100, 200, "bark");
// a == 100
// b == 200
// c == "bark"
multiple returns to lua
-----------------------
.. code-block :: cpp
sol::state lua;
lua["f"] = [](int a, int b, sol::object c) {
// sol::object can be anything here: just pass it through
2016-06-17 22:44:55 +08:00
return std::make_tuple( a, b, c );
2016-04-25 00:40:35 +08:00
};
std::tuple<int, int, int> result = lua["f"](100, 200, 300);
// result == { 100, 200, 300 }
2016-04-26 03:58:13 +08:00
std::tuple<int, int, std::string> result2;
result2 = lua["f"](100, 200, "BARK BARK BARK!")
// result2 == { 100, 200, "BARK BARK BARK!" }
2016-04-25 00:40:35 +08:00
int a, int b;
std::string c;
sol::tie( a, b, c ) = lua["f"](100, 200, "bark");
// a == 100
// b == 200
// c == "bark"
2016-04-26 03:58:13 +08:00
C++ classes from C++
--------------------
2016-04-24 05:07:51 +08:00
Everything that is not a:
* primitive type: `` bool `` , `` char/short/int/long/long long `` , `` float/double ``
* string type: `` std::string `` , `` const char* ``
2016-04-24 22:09:05 +08:00
* function type: function pointers, `` lua_CFunction `` , `` std::function `` , :doc: `sol::function/sol::protected_function<../api/function>` , :doc: `sol::coroutine<../api/coroutine>` , member variable, member function
2016-04-24 05:07:51 +08:00
* designated sol type: :doc: `sol::table<../api/table>` , :doc: `sol::thread<../api/thread>` , :doc: `sol::error<../api/error>` , :doc: `sol::object<../api/object>`
* transparent argument type: :doc: `sol::variadic_arg<../api/variadic_args>` , :doc: `sol::this_state<../api/this_state>`
* usertype<T> class: :doc: `sol::usertype<../api/usertype>`
2016-04-24 22:09:05 +08:00
Is set as a :doc: `userdata + usertype<../api/usertype>` .
2016-04-24 05:07:51 +08:00
.. code-block :: cpp
2016-04-24 22:09:05 +08:00
struct Doge {
int tailwag = 50;
}
2016-04-24 05:07:51 +08:00
Doge dog{};
2016-04-24 22:09:05 +08:00
// Copy into lua: destroyed by Lua VM during garbage collection
2016-04-24 05:07:51 +08:00
lua["dog"] = dog;
// OR: move semantics - will call move constructor if present instead
2016-04-24 22:09:05 +08:00
// Again, owned by Lua
2016-04-24 05:07:51 +08:00
lua["dog"] = std::move( dog );
lua["dog"] = Doge{};
lua["dog"] = std::make_unique<Doge>();
lua["dog"] = std::make_shared<Doge>();
// Identical to above
2016-04-25 10:45:52 +08:00
Doge dog2{};
lua.set("dog", dog2);
lua.set("dog", std::move(dog2));
2016-04-24 05:07:51 +08:00
lua.set("dog", Doge{});
lua.set("dog", std::unique_ptr<Doge>(new Doge()));
lua.set("dog", std::shared_ptr<Doge>(new Doge()));
2016-04-24 22:09:05 +08:00
`` std::unique_ptr `` /`` std::shared_ptr `` 's reference counts / deleters will :doc: `be respected<../api/unique_usertype_traits>` . If you want it to refer to something, whose memory you know won't die in C++, do the following:
2016-04-24 05:07:51 +08:00
.. code-block :: cpp
2016-04-24 22:09:05 +08:00
struct Doge {
int tailwag = 50;
}
sol::state lua;
lua.open_libraries(sol::lib::base);
2016-04-24 05:07:51 +08:00
Doge dog{}; // Kept alive somehow
// Later...
// The following stores a reference, and does not copy/move
2016-04-24 06:24:48 +08:00
// lifetime is same as dog in C++
// (access after it is destroyed is bad)
2016-04-24 05:07:51 +08:00
lua["dog"] = &dog;
// Same as above: respects std::reference_wrapper
lua["dog"] = std::ref(dog);
// These two are identical to above
lua.set( "dog", &dog );
lua.set( "dog", std::ref( dog ) );
Get userdata in the same way as everything else:
.. code-block :: cpp
2016-04-24 22:09:05 +08:00
struct Doge {
int tailwag = 50;
}
sol::state lua;
lua.open_libraries(sol::lib::base);
Doge& dog = lua["dog"]; // References Lua memory
Doge* dog_pointer = lua["dog"]; // References Lua memory
Doge dog_copy = lua["dog"]; // Copies, will not affect lua
Note that you can change the data of usertype variables and it will affect things in lua if you get a pointer or a reference from Sol:
.. code-block :: cpp
struct Doge {
int tailwag = 50;
}
sol::state lua;
lua.open_libraries(sol::lib::base);
2016-04-24 05:07:51 +08:00
Doge& dog = lua["dog"]; // References Lua memory
Doge* dog_pointer = lua["dog"]; // References Lua memory
Doge dog_copy = lua["dog"]; // Copies, will not affect lua
dog_copy.tailwag = 525;
// Still 50
lua.script("assert(dog.tailwag == 50)");
dog.tailwag = 100;
// Now 100
lua.script("assert(dog.tailwag == 100)");
2016-04-26 03:58:13 +08:00
C++ classes put into Lua
------------------------
2016-04-25 00:40:35 +08:00
2016-04-26 03:58:13 +08:00
See this :doc: `section here<cxx-in-lua>` .
2016-04-24 09:20:45 +08:00
2016-04-25 00:49:27 +08:00
2016-09-09 19:48:28 +08:00
namespacing
-----------
You can emulate namespacing by having a table and giving it the namespace names you want before registering enums or usertypes:
.. code-block :: cpp
struct my_class {
int b = 24;
int f () const {
return 24;
}
void g () {
++b;
}
};
sol::state lua;
lua.open_libraries();
// set up table
sol::table bark = lua.create_named_table("bark");
bark.new_usertype<my_class>( "my_class",
"f", &my_class::f,
"g", &my_class::g
); // the usual
// 'bark' namespace
lua.script("obj = bark.my_class.new()" );
lua.script("obj:g()");
my_class& obj = lua["obj"];
// obj.b == 25
This technique can be used to register namespace-like functions and classes. It can be as deep as you want. Just make a table and name it appropriately, in either Lua script or using the equivalent Sol code. As long as the table FIRST exists (e.g., make it using a script or with one of Sol's methods or whatever you like), you can put anything you want specifically into that table using :doc: `sol::table's<../api/table>` abstractions.
2016-04-24 09:20:45 +08:00
advanced
2016-04-24 05:07:51 +08:00
--------
2016-04-26 03:58:13 +08:00
Some more advanced things you can do/read about:
2016-06-17 22:44:55 +08:00
* :doc: `metatable manipulations<../api/metatable_key>` allow a user to change how indexing, function calls, and other things work on a single type.
2016-04-26 03:58:13 +08:00
* :doc: `ownership semantics<ownership>` are described for how lua deals with (raw) pointers.
2016-04-24 05:07:51 +08:00
* :doc: `stack manipulation<../api/stack>` to safely play with the stack. You can also define customization points for `` stack::get `` /`` stack::check `` /`` stack::push `` for your type.
2016-06-20 21:51:26 +08:00
* :doc: `make_reference/make_object convenience function<../api/make_reference>` to get the same benefits and conveniences as the low-level stack API but put into objects you can specify.
2016-04-25 00:40:35 +08:00
* :doc: `stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry.
* :doc: `unique usertype traits<../api/unique_usertype_traits>` allows you to specialize handle/RAII types from other frameworks, like boost, and Unreal, to work with Sol.
2016-04-24 05:07:51 +08:00
* :doc: `variadic arguments<../api/variadic_args>` in functions with `` sol::variadic_args `` .
* :doc: `this_state<../api/this_state>` to get the current `` lua_State* `` .
2016-06-17 22:44:55 +08:00
* :doc: `resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility.