diff options
author | Brooks Davis <brooks@FreeBSD.org> | 2020-03-17 16:48:52 +0000 |
---|---|---|
committer | Brooks Davis <brooks@FreeBSD.org> | 2020-03-17 16:48:52 +0000 |
commit | 4b2c3eb9d49a797f91eee2be4e41cacb3b8167e7 (patch) | |
tree | cfd66184091e02da4c65f7db8ef829133a8da4f8 /examples |
Notes
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile | 67 | ||||
-rw-r--r-- | examples/bindings.cpp | 133 | ||||
-rw-r--r-- | examples/hello.cpp | 58 | ||||
-rw-r--r-- | examples/interpreter.cpp | 83 | ||||
-rw-r--r-- | examples/raii.cpp | 126 |
5 files changed, 467 insertions, 0 deletions
diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 000000000000..834b20fc114e --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,67 @@ +# Copyright 2012 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CXX ?= c++ +CPPFLAGS ?= +CXXFLAGS ?= -Wall -O2 +LDFLAGS ?= +LIBS ?= + +LUTOK_CPPFLAGS = $$(pkg-config --cflags-only-I lutok) +LUTOK_CXXFLAGS = $$(pkg-config --cflags-only-other lutok) +LUTOK_LDFLAGS = $$(pkg-config --libs-only-L lutok) \ + $$(pkg-config --libs-only-other lutok) +LUTOK_LIBS = $$(pkg-config --libs-only-l lutok) + +BUILD = $(CXX) \ + $(CPPFLAGS) $(LUTOK_CPPFLAGS) \ + $(CXXFLAGS) $(LUTOK_CXXFLAGS) \ + $(LDFLAGS) $(LUTOK_LDFLAGS) \ + -o $${target} $${source} \ + $(LIBS) $(LUTOK_LIBS) + +PROGRAMS = bindings hello interpreter raii + +.PHONY: all +all: $(PROGRAMS) + +bindings: bindings.cpp + @target=bindings source=bindings.cpp; echo $(BUILD); $(BUILD) + +hello: hello.cpp + @target=hello source=hello.cpp; echo $(BUILD); $(BUILD) + +interpreter: interpreter.cpp + @target=interpreter source=interpreter.cpp; echo $(BUILD); $(BUILD) + +raii: raii.cpp + @target=raii source=raii.cpp; echo $(BUILD); $(BUILD) + +.PHONY: clean +clean: + rm -f $(PROGRAMS) diff --git a/examples/bindings.cpp b/examples/bindings.cpp new file mode 100644 index 000000000000..dca235a8962d --- /dev/null +++ b/examples/bindings.cpp @@ -0,0 +1,133 @@ +// Copyright 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// \file examples/bindings.cpp +/// Showcases how to define Lua functions from C++ code. +/// +/// A major selling point of Lua is that it is very easy too hook native C and +/// C++ functions into the runtime environment so that Lua can call them. The +/// purpose of this example program is to show how this is done by using Lutok. + +#include <cassert> +#include <cstdlib> +#include <iostream> +#include <map> +#include <sstream> +#include <stdexcept> +#include <string> + +#include <lutok/exceptions.hpp> +#include <lutok/operations.hpp> +#include <lutok/state.ipp> + + +/// Calculates the factorial of a given number. +/// +/// \param i The postivie number to calculate the factorial of. +/// +/// \return The factorial of i. +static int +factorial(const int i) +{ + assert(i >= 0); + + if (i == 0) + return 1; + else + return i * factorial(i - 1); +} + + +/// A custom factorial function for Lua. +/// +/// \pre stack(-1) contains the number to calculate the factorial of. +/// \post stack(-1) contains the result of the operation. +/// +/// \param state The Lua state from which to get the function arguments and into +/// which to push the results. +/// +/// \return The number of results pushed onto the stack, i.e. 1. +/// +/// \throw std::runtime_error If the input parameters are invalid. Note that +/// Lutok will convert this exception to lutok::error. +static int +lua_factorial(lutok::state& state) +{ + if (!state.is_number(-1)) + throw std::runtime_error("Argument to factorial must be an integer"); + const int i = state.to_integer(-1); + if (i < 0) + throw std::runtime_error("Argument to factorial must be positive"); + state.push_integer(factorial(i)); + return 1; +} + + +/// Program's entry point. +/// +/// \param argc Length of argv. Must be 2. +/// \param argv Command-line arguments to the program. The first argument to +/// the tool has to be a number. +/// +/// \return A system exit code. +int +main(int argc, char** argv) +{ + if (argc != 2) { + std::cerr << "Usage: bindings <number>\n"; + return EXIT_FAILURE; + } + + // Create a new Lua session and load the print() function. + lutok::state state; + state.open_base(); + + // Construct a 'module' that contains an entry point to our native factorial + // function. A module is just a Lua table that contains a mapping of names + // to functions. Instead of creating a module by using our create_module() + // helper function, we could have used push_cxx_function on the state to + // define the function ourselves. + std::map< std::string, lutok::cxx_function > module; + module["factorial"] = lua_factorial; + lutok::create_module(state, "native", module); + + // Use a little Lua script to call our native factorial function providing + // it the first argument passed to the program. Note that this will error + // out in a controlled manner if the passed argument is not an integer. The + // important thing to notice is that the exception comes from our own C++ + // binding and that it has been converted to a lutok::error. + std::ostringstream script; + script << "print(native.factorial(" << argv[1] << "))"; + try { + lutok::do_string(state, script.str(), 0, 0, 0); + return EXIT_SUCCESS; + } catch (const lutok::error& e) { + std::cerr << "ERROR: " << e.what() << '\n'; + return EXIT_FAILURE; + } +} diff --git a/examples/hello.cpp b/examples/hello.cpp new file mode 100644 index 000000000000..40afdd5724b7 --- /dev/null +++ b/examples/hello.cpp @@ -0,0 +1,58 @@ +// Copyright 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// \file examples/hello.cpp +/// Minimal example using Lua code to print a traditional hello-world message. + +#include <cstdlib> + +#include <lutok/state.ipp> + + +/// Program's entry point. +/// +/// \return A system exit code. +int +main(void) +{ + // Initializes a new Lua state. Every Lua state is independent from each + // other. + lutok::state state; + + // Loads the standard library into the Lua state. Among many other + // functions, this gives us access to print(), which is used below. + state.open_base(); + + // Pushes the print() function into the Lua stack, then its only argument, + // and then proceeds to execute it within the Lua state. + state.get_global("print"); + state.push_string("Hello, world!"); + state.pcall(1, 0, 0); + + return EXIT_SUCCESS; +} diff --git a/examples/interpreter.cpp b/examples/interpreter.cpp new file mode 100644 index 000000000000..08fba796a45d --- /dev/null +++ b/examples/interpreter.cpp @@ -0,0 +1,83 @@ +// Copyright 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// \file examples/interpreter.cpp +/// Implementation of a basic command-line Lua interpreter. + +#include <cstdlib> +#include <iostream> +#include <string> + +#include <lutok/exceptions.hpp> +#include <lutok/operations.hpp> +#include <lutok/state.ipp> + + +/// Executes a Lua statement provided by the user with error checking. +/// +/// \param state The Lua state in which to process the statement. +/// \param line The textual statement provided by the user. +static void +run_statement(lutok::state& state, const std::string& line) +{ + try { + // This utility function allows us to feed a given piece of Lua code to + // the interpreter and process it. The piece of code can include + // multiple statements separated by a semicolon or by a newline + // character. + lutok::do_string(state, line, 0, 0, 0); + } catch (const lutok::error& error) { + std::cerr << "ERROR: " << error.what() << '\n'; + } +} + + +/// Program's entry point. +/// +/// \return A system exit code. +int +main(void) +{ + // Create a new session and load some standard libraries. + lutok::state state; + state.open_base(); + state.open_string(); + state.open_table(); + + for (;;) { + std::cout << "lua> "; + std::cout.flush(); + + std::string line; + if (!std::getline(std::cin, line).good()) + break; + run_statement(state, line); + } + + return EXIT_SUCCESS; +} diff --git a/examples/raii.cpp b/examples/raii.cpp new file mode 100644 index 000000000000..eae76538e992 --- /dev/null +++ b/examples/raii.cpp @@ -0,0 +1,126 @@ +// Copyright 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// \file examples/raii.cpp +/// Demonstrates how RAII helps in keeping the Lua state consistent. +/// +/// One of the major complains that is raised against the Lua C API is that it +/// is very hard to ensure it remains consistent during the execution of the +/// program. In the case of native C code, there exist many tools that help the +/// developer catch memory leaks, access to uninitialized variables, etc. +/// However, when using the Lua C API, none of these tools can validate that, +/// for example, the Lua stack remains balanced across calls. +/// +/// Enter RAII. The RAII pattern, intensively applied by Lutok, helps the +/// developer in maintaining the Lua state consistent at all times in a +/// transparent manner. This example program attempts to illustrate this. + +#include <cassert> +#include <cstdlib> +#include <iostream> +#include <string> + +#include <lutok/operations.hpp> +#include <lutok/stack_cleaner.hpp> +#include <lutok/state.ipp> + + +/// Prints the string-typed field of a table. +/// +/// If the field contains a string, this function prints its value. If the +/// field contains any other type, this prints an error message. +/// +/// \pre The top of the Lua stack in 'state' references a table. +/// +/// \param state The Lua state. +/// \param field The name of the string-typed field. +static void +print_table_field(lutok::state& state, const std::string& field) +{ + assert(state.is_table(-1)); + + // Bring in some RAII magic: the stack_cleaner object captures the current + // height of the Lua stack at this point. Whenever the object goes out of + // scope, it will pop as many entries from the stack as necessary to restore + // the stack to its previous level. + // + // This ensures that, no matter how we exit the function, we do not leak + // objects in the stack. + lutok::stack_cleaner cleaner(state); + + // Stack contents: -1: table. + state.push_string(field); + // Stack contents: -2: table, -1: field name. + state.get_table(-2); + // Stack contents: -2: table, -1: field value. + + if (!state.is_string(-1)) { + std::cout << "The field " << field << " does not contain a string\n"; + // Stack contents: -2: table, -1: field value. + // + // This is different than when we started! We should pop our extra + // value from the stack at this point. However, it is extremely common + // for software to have bugs (in this case, leaks) in error paths, + // mostly because such code paths are rarely exercised. + // + // By using the stack_cleaner object, we can be confident that the Lua + // stack will be cleared for us at this point, no matter what happened + // earlier on the stack nor how we exit the function. + return; + } + + std::cout << "String in field " << field << ": " << state.to_string(-1) + << '\n'; + // A well-behaved program explicitly pops anything extra from the stack to + // return it to its original state. Mostly for clarity. + state.pop(1); + + // Stack contents: -1: table. Same as when we started. +} + + +/// Program's entry point. +/// +/// \return A system exit code. +int +main(void) +{ + lutok::state state; + state.open_base(); + + lutok::do_string(state, "example = {foo='hello', bar=123, baz='bye'}", + 0, 0, 0); + + state.get_global("example"); + print_table_field(state, "foo"); + print_table_field(state, "bar"); + print_table_field(state, "baz"); + state.pop(1); + + return EXIT_SUCCESS; +} |