1*c697fb7fSBrooks Davis // Copyright 2012 Google Inc.
2*c697fb7fSBrooks Davis // All rights reserved.
3*c697fb7fSBrooks Davis //
4*c697fb7fSBrooks Davis // Redistribution and use in source and binary forms, with or without
5*c697fb7fSBrooks Davis // modification, are permitted provided that the following conditions are
6*c697fb7fSBrooks Davis // met:
7*c697fb7fSBrooks Davis //
8*c697fb7fSBrooks Davis // * Redistributions of source code must retain the above copyright
9*c697fb7fSBrooks Davis // notice, this list of conditions and the following disclaimer.
10*c697fb7fSBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*c697fb7fSBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*c697fb7fSBrooks Davis // documentation and/or other materials provided with the distribution.
13*c697fb7fSBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*c697fb7fSBrooks Davis // may be used to endorse or promote products derived from this software
15*c697fb7fSBrooks Davis // without specific prior written permission.
16*c697fb7fSBrooks Davis //
17*c697fb7fSBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*c697fb7fSBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*c697fb7fSBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*c697fb7fSBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*c697fb7fSBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*c697fb7fSBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*c697fb7fSBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*c697fb7fSBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*c697fb7fSBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*c697fb7fSBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*c697fb7fSBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*c697fb7fSBrooks Davis
29*c697fb7fSBrooks Davis /// \file examples/bindings.cpp
30*c697fb7fSBrooks Davis /// Showcases how to define Lua functions from C++ code.
31*c697fb7fSBrooks Davis ///
32*c697fb7fSBrooks Davis /// A major selling point of Lua is that it is very easy too hook native C and
33*c697fb7fSBrooks Davis /// C++ functions into the runtime environment so that Lua can call them. The
34*c697fb7fSBrooks Davis /// purpose of this example program is to show how this is done by using Lutok.
35*c697fb7fSBrooks Davis
36*c697fb7fSBrooks Davis #include <cassert>
37*c697fb7fSBrooks Davis #include <cstdlib>
38*c697fb7fSBrooks Davis #include <iostream>
39*c697fb7fSBrooks Davis #include <map>
40*c697fb7fSBrooks Davis #include <sstream>
41*c697fb7fSBrooks Davis #include <stdexcept>
42*c697fb7fSBrooks Davis #include <string>
43*c697fb7fSBrooks Davis
44*c697fb7fSBrooks Davis #include <lutok/exceptions.hpp>
45*c697fb7fSBrooks Davis #include <lutok/operations.hpp>
46*c697fb7fSBrooks Davis #include <lutok/state.ipp>
47*c697fb7fSBrooks Davis
48*c697fb7fSBrooks Davis
49*c697fb7fSBrooks Davis /// Calculates the factorial of a given number.
50*c697fb7fSBrooks Davis ///
51*c697fb7fSBrooks Davis /// \param i The postivie number to calculate the factorial of.
52*c697fb7fSBrooks Davis ///
53*c697fb7fSBrooks Davis /// \return The factorial of i.
54*c697fb7fSBrooks Davis static int
factorial(const int i)55*c697fb7fSBrooks Davis factorial(const int i)
56*c697fb7fSBrooks Davis {
57*c697fb7fSBrooks Davis assert(i >= 0);
58*c697fb7fSBrooks Davis
59*c697fb7fSBrooks Davis if (i == 0)
60*c697fb7fSBrooks Davis return 1;
61*c697fb7fSBrooks Davis else
62*c697fb7fSBrooks Davis return i * factorial(i - 1);
63*c697fb7fSBrooks Davis }
64*c697fb7fSBrooks Davis
65*c697fb7fSBrooks Davis
66*c697fb7fSBrooks Davis /// A custom factorial function for Lua.
67*c697fb7fSBrooks Davis ///
68*c697fb7fSBrooks Davis /// \pre stack(-1) contains the number to calculate the factorial of.
69*c697fb7fSBrooks Davis /// \post stack(-1) contains the result of the operation.
70*c697fb7fSBrooks Davis ///
71*c697fb7fSBrooks Davis /// \param state The Lua state from which to get the function arguments and into
72*c697fb7fSBrooks Davis /// which to push the results.
73*c697fb7fSBrooks Davis ///
74*c697fb7fSBrooks Davis /// \return The number of results pushed onto the stack, i.e. 1.
75*c697fb7fSBrooks Davis ///
76*c697fb7fSBrooks Davis /// \throw std::runtime_error If the input parameters are invalid. Note that
77*c697fb7fSBrooks Davis /// Lutok will convert this exception to lutok::error.
78*c697fb7fSBrooks Davis static int
lua_factorial(lutok::state & state)79*c697fb7fSBrooks Davis lua_factorial(lutok::state& state)
80*c697fb7fSBrooks Davis {
81*c697fb7fSBrooks Davis if (!state.is_number(-1))
82*c697fb7fSBrooks Davis throw std::runtime_error("Argument to factorial must be an integer");
83*c697fb7fSBrooks Davis const int i = state.to_integer(-1);
84*c697fb7fSBrooks Davis if (i < 0)
85*c697fb7fSBrooks Davis throw std::runtime_error("Argument to factorial must be positive");
86*c697fb7fSBrooks Davis state.push_integer(factorial(i));
87*c697fb7fSBrooks Davis return 1;
88*c697fb7fSBrooks Davis }
89*c697fb7fSBrooks Davis
90*c697fb7fSBrooks Davis
91*c697fb7fSBrooks Davis /// Program's entry point.
92*c697fb7fSBrooks Davis ///
93*c697fb7fSBrooks Davis /// \param argc Length of argv. Must be 2.
94*c697fb7fSBrooks Davis /// \param argv Command-line arguments to the program. The first argument to
95*c697fb7fSBrooks Davis /// the tool has to be a number.
96*c697fb7fSBrooks Davis ///
97*c697fb7fSBrooks Davis /// \return A system exit code.
98*c697fb7fSBrooks Davis int
main(int argc,char ** argv)99*c697fb7fSBrooks Davis main(int argc, char** argv)
100*c697fb7fSBrooks Davis {
101*c697fb7fSBrooks Davis if (argc != 2) {
102*c697fb7fSBrooks Davis std::cerr << "Usage: bindings <number>\n";
103*c697fb7fSBrooks Davis return EXIT_FAILURE;
104*c697fb7fSBrooks Davis }
105*c697fb7fSBrooks Davis
106*c697fb7fSBrooks Davis // Create a new Lua session and load the print() function.
107*c697fb7fSBrooks Davis lutok::state state;
108*c697fb7fSBrooks Davis state.open_base();
109*c697fb7fSBrooks Davis
110*c697fb7fSBrooks Davis // Construct a 'module' that contains an entry point to our native factorial
111*c697fb7fSBrooks Davis // function. A module is just a Lua table that contains a mapping of names
112*c697fb7fSBrooks Davis // to functions. Instead of creating a module by using our create_module()
113*c697fb7fSBrooks Davis // helper function, we could have used push_cxx_function on the state to
114*c697fb7fSBrooks Davis // define the function ourselves.
115*c697fb7fSBrooks Davis std::map< std::string, lutok::cxx_function > module;
116*c697fb7fSBrooks Davis module["factorial"] = lua_factorial;
117*c697fb7fSBrooks Davis lutok::create_module(state, "native", module);
118*c697fb7fSBrooks Davis
119*c697fb7fSBrooks Davis // Use a little Lua script to call our native factorial function providing
120*c697fb7fSBrooks Davis // it the first argument passed to the program. Note that this will error
121*c697fb7fSBrooks Davis // out in a controlled manner if the passed argument is not an integer. The
122*c697fb7fSBrooks Davis // important thing to notice is that the exception comes from our own C++
123*c697fb7fSBrooks Davis // binding and that it has been converted to a lutok::error.
124*c697fb7fSBrooks Davis std::ostringstream script;
125*c697fb7fSBrooks Davis script << "print(native.factorial(" << argv[1] << "))";
126*c697fb7fSBrooks Davis try {
127*c697fb7fSBrooks Davis lutok::do_string(state, script.str(), 0, 0, 0);
128*c697fb7fSBrooks Davis return EXIT_SUCCESS;
129*c697fb7fSBrooks Davis } catch (const lutok::error& e) {
130*c697fb7fSBrooks Davis std::cerr << "ERROR: " << e.what() << '\n';
131*c697fb7fSBrooks Davis return EXIT_FAILURE;
132*c697fb7fSBrooks Davis }
133*c697fb7fSBrooks Davis }
134