Initial import of Lutok, version 0.2.

This is a required component of Kyua and its build will be guarded by
the MKKYUA knob.  core@ has approved this import.

Description:

Lutok is a lightweight C++ API library for Lua.

Lutok provides thin C++ wrappers around the Lua C API to ease the
interaction between C++ and Lua.  These wrappers make intensive use of
RAII to prevent resource leakage, expose C++-friendly data types, report
errors by means of exceptions and ensure that the Lua stack is always
left untouched in the face of errors.  The library also provides a small
subset of miscellaneous utility functions built on top of the wrappers.

Lutok focuses on providing a clean and safe C++ interface; the drawback
is that it is not suitable for performance-critical environments.  In
order to implement error-safe C++ wrappers on top of a Lua C binary
library, Lutok adds several layers or abstraction and error checking
that go against the original spirit of the Lua C API and thus degrade
performance.
This commit is contained in:
jmmv 2013-02-16 15:06:52 +00:00
parent 3bd42d5026
commit a15637525a
32 changed files with 4870 additions and 0 deletions

1
external/bsd/lutok/dist/AUTHORS vendored Normal file
View File

@ -0,0 +1 @@
* Julio Merino <jmmv@google.com>

11
external/bsd/lutok/dist/Atffile vendored Normal file
View File

@ -0,0 +1,11 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = lutok
tp: c_gate_test
tp: debug_test
tp: examples_test
tp: exceptions_test
tp: operations_test
tp: stack_cleaner_test
tp: state_test

27
external/bsd/lutok/dist/COPYING vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright 2011, 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.

11
external/bsd/lutok/dist/Kyuafile vendored Normal file
View File

@ -0,0 +1,11 @@
syntax("kyuafile", 1)
test_suite("lutok")
atf_test_program{name="c_gate_test"}
atf_test_program{name="debug_test"}
atf_test_program{name="examples_test"}
atf_test_program{name="exceptions_test"}
atf_test_program{name="operations_test"}
atf_test_program{name="stack_cleaner_test"}
atf_test_program{name="state_test"}

19
external/bsd/lutok/dist/NEWS vendored Normal file
View File

@ -0,0 +1,19 @@
Changes in version 0.2
======================
Released on 2012/05/30.
* New global constants: globals_index.
* New methods added to the state class: get_metafield, get_metatable,
insert, push_value, raw_get and raw_set.
* Acknowledged that Lua 5.2 is currently not supported.
Changes in version 0.1
======================
Released on 2012/01/29.
* This is the first public release of the Lutok package.

27
external/bsd/lutok/dist/README vendored Normal file
View File

@ -0,0 +1,27 @@
Lutok is a lightweight C++ API library for Lua.
Lutok provides thin C++ wrappers around the Lua C API to ease the
interaction between C++ and Lua. These wrappers make intensive use of
RAII to prevent resource leakage, expose C++-friendly data types, report
errors by means of exceptions and ensure that the Lua stack is always
left untouched in the face of errors. The library also provides a small
subset of miscellaneous utility functions built on top of the wrappers.
Lutok focuses on providing a clean and safe C++ interface; the drawback
is that it is not suitable for performance-critical environments. In
order to implement error-safe C++ wrappers on top of a Lua C binary
library, Lutok adds several layers or abstraction and error checking
that go against the original spirit of the Lua C API and thus degrade
performance.
For further information on the contents of this distribution file,
please refer to the following other documents:
* AUTHORS: List of authors and contributors to this project.
* COPYING: License information.
* INSTALL: Compilation and installation instructions.
* NEWS: List of major changes between formal releases.
For general project information, please visit:
http://code.google.com/p/lutok/

76
external/bsd/lutok/dist/c_gate.cpp vendored Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2011 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.
#include "c_gate.hpp"
#include "state.ipp"
/// Creates a new gateway to an existing C++ Lua state.
///
/// \param state_ The state to connect to. This object must remain alive while
/// the newly-constructed state_c_gate is alive.
lutok::state_c_gate::state_c_gate(state& state_) :
_state(state_)
{
}
/// Destructor.
///
/// Destroying this object has no implications on the life cycle of the Lua
/// state. Only the corresponding state object controls when the Lua state is
/// closed.
lutok::state_c_gate::~state_c_gate(void)
{
}
/// Creates a C++ state for a C Lua state.
///
/// \warning The created state object does NOT own the C state. You must take
/// care to properly destroy the input lua_State when you are done with it to
/// not leak resources.
///
/// \param raw_state The raw state to wrap temporarily.
///
/// \return The wrapped state without strong ownership on the input state.
lutok::state
lutok::state_c_gate::connect(lua_State* raw_state)
{
return state(static_cast< void* >(raw_state));
}
/// Returns the C native Lua state.
///
/// \return A native lua_State object holding the Lua C API state.
lua_State*
lutok::state_c_gate::c_state(void)
{
return static_cast< lua_State* >(_state.raw_state());
}

71
external/bsd/lutok/dist/c_gate.hpp vendored Normal file
View File

@ -0,0 +1,71 @@
// Copyright 2011 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 c_gate.hpp
/// Provides direct access to the C state of the Lua wrappers.
#if !defined(LUTOK_C_GATE_HPP)
#define LUTOK_C_GATE_HPP
#include <lua.hpp>
namespace lutok {
class state;
/// Gateway to the raw C state of Lua.
///
/// This class provides a mechanism to muck with the internals of the state
/// wrapper class. Client code may wish to do so if Lutok is missing some
/// features of the performance of Lutok in a particular situation is not
/// reasonable.
///
/// \warning The use of this class is discouraged. By using this class, you are
/// entering the world of unsafety. Anything you do through the objects exposed
/// through this class will not be controlled by RAII patterns not validated in
/// any other way, so you can end up corrupting the Lua state and later get
/// crashes on otherwise perfectly-valid C++ code.
class state_c_gate {
/// The C++ state that this class wraps.
state& _state;
public:
state_c_gate(state&);
~state_c_gate(void);
static state connect(lua_State*);
lua_State* c_state(void);
};
} // namespace lutok
#endif // !defined(LUTOK_C_GATE_HPP)

74
external/bsd/lutok/dist/c_gate_test.cpp vendored Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2011 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.
#include "c_gate.hpp"
#include <atf-c++.hpp>
#include <lua.hpp>
#include "state.ipp"
#include "test_utils.hpp"
ATF_TEST_CASE_WITHOUT_HEAD(connect);
ATF_TEST_CASE_BODY(connect)
{
lua_State* raw_state = lua_open();
ATF_REQUIRE(raw_state != NULL);
{
lutok::state state = lutok::state_c_gate::connect(raw_state);
lua_pushinteger(raw(state), 123);
}
// If the wrapper object had closed the Lua state, we could very well crash
// here.
ATF_REQUIRE_EQ(123, lua_tointeger(raw_state, -1));
lua_close(raw_state);
}
ATF_TEST_CASE_WITHOUT_HEAD(c_state);
ATF_TEST_CASE_BODY(c_state)
{
lutok::state state;
state.push_integer(5);
{
lutok::state_c_gate gate(state);
lua_State* raw_state = gate.c_state();
ATF_REQUIRE_EQ(5, lua_tointeger(raw_state, -1));
}
state.pop(1);
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, c_state);
ATF_ADD_TEST_CASE(tcs, connect);
}

192
external/bsd/lutok/dist/debug.cpp vendored Normal file
View File

@ -0,0 +1,192 @@
// Copyright 2011 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.
#include <cassert>
#include <lua.hpp>
#include <lutok/c_gate.hpp>
#include <lutok/debug.hpp>
#include <lutok/exceptions.hpp>
#include <lutok/state.ipp>
/// Internal implementation for lutok::debug.
struct lutok::debug::impl {
/// The Lua internal debug state.
lua_Debug lua_debug;
};
/// Constructor for an empty debug structure.
lutok::debug::debug(void) :
_pimpl(new impl())
{
}
/// Destructor.
lutok::debug::~debug(void)
{
}
/// Wrapper around lua_getinfo.
///
/// \param s The Lua state.
/// \param what_ The second parameter to lua_getinfo.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::debug::get_info(state& s, const std::string& what_)
{
lua_State* raw_state = state_c_gate(s).c_state();
if (lua_getinfo(raw_state, what_.c_str(), &_pimpl->lua_debug) == 0)
throw lutok::api_error::from_stack(s, "lua_getinfo");
}
/// Wrapper around lua_getstack.
///
/// \param s The Lua state.
/// \param level The second parameter to lua_getstack.
void
lutok::debug::get_stack(state& s, const int level)
{
lua_State* raw_state = state_c_gate(s).c_state();
lua_getstack(raw_state, level, &_pimpl->lua_debug);
}
/// Accessor for the 'event' field of lua_Debug.
///
/// \return Returns the 'event' field of the internal lua_Debug structure.
int
lutok::debug::event(void) const
{
return _pimpl->lua_debug.event;
}
/// Accessor for the 'name' field of lua_Debug.
///
/// \return Returns the 'name' field of the internal lua_Debug structure.
std::string
lutok::debug::name(void) const
{
assert(_pimpl->lua_debug.name != NULL);
return _pimpl->lua_debug.name;
}
/// Accessor for the 'namewhat' field of lua_Debug.
///
/// \return Returns the 'namewhat' field of the internal lua_Debug structure.
std::string
lutok::debug::name_what(void) const
{
assert(_pimpl->lua_debug.namewhat != NULL);
return _pimpl->lua_debug.namewhat;
}
/// Accessor for the 'what' field of lua_Debug.
///
/// \return Returns the 'what' field of the internal lua_Debug structure.
std::string
lutok::debug::what(void) const
{
assert(_pimpl->lua_debug.what != NULL);
return _pimpl->lua_debug.what;
}
/// Accessor for the 'source' field of lua_Debug.
///
/// \return Returns the 'source' field of the internal lua_Debug structure.
std::string
lutok::debug::source(void) const
{
assert(_pimpl->lua_debug.source != NULL);
return _pimpl->lua_debug.source;
}
/// Accessor for the 'currentline' field of lua_Debug.
///
/// \return Returns the 'currentline' field of the internal lua_Debug structure.
int
lutok::debug::current_line(void) const
{
return _pimpl->lua_debug.currentline;
}
/// Accessor for the 'nups' field of lua_Debug.
///
/// \return Returns the 'nups' field of the internal lua_Debug structure.
int
lutok::debug::n_ups(void) const
{
return _pimpl->lua_debug.nups;
}
/// Accessor for the 'linedefined' field of lua_Debug.
///
/// \return Returns the 'linedefined' field of the internal lua_Debug structure.
int
lutok::debug::line_defined(void) const
{
return _pimpl->lua_debug.linedefined;
}
/// Accessor for the 'lastlinedefined' field of lua_Debug.
///
/// \return Returns the 'lastlinedefined' field of the internal lua_Debug
/// structure.
int
lutok::debug::last_line_defined(void) const
{
return _pimpl->lua_debug.lastlinedefined;
}
/// Accessor for the 'short_src' field of lua_Debug.
///
/// \return Returns the 'short_src' field of the internal lua_Debug structure.
std::string
lutok::debug::short_src(void) const
{
assert(_pimpl->lua_debug.short_src != NULL);
return _pimpl->lua_debug.short_src;
}

83
external/bsd/lutok/dist/debug.hpp vendored Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2011 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 debug.hpp
/// Provides the debug wrapper class for the Lua C debug state.
#if !defined(LUTOK_DEBUG_HPP)
#define LUTOK_DEBUG_HPP
#include <string>
#include <tr1/memory>
namespace lutok {
class state;
/// A model for the Lua debug state.
///
/// This extremely-simple class provides a mechanism to hide the internals of
/// the C native lua_Debug type, exposing its internal fields using friendlier
/// C++ types.
///
/// This class also acts as a complement to the state class by exposing any
/// state-related functions as methods of this function. For example, while it
/// might seem that get_info() belongs in state, we expose it from here because
/// its result is really mutating a debug object, not the state object.
class debug {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
public:
debug(void);
~debug(void);
void get_info(state&, const std::string&);
void get_stack(state&, const int);
int event(void) const;
std::string name(void) const;
std::string name_what(void) const;
std::string what(void) const;
std::string source(void) const;
int current_line(void) const;
int n_ups(void) const;
int line_defined(void) const;
int last_line_defined(void) const;
std::string short_src(void) const;
};
} // namespace lutok
#endif // !defined(LUTOK_DEBUG_HPP)

68
external/bsd/lutok/dist/debug_test.cpp vendored Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2011 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.
#include "debug.hpp"
#include <atf-c++.hpp>
#include <lua.hpp>
#include "state.ipp"
#include "test_utils.hpp"
ATF_TEST_CASE_WITHOUT_HEAD(get_info);
ATF_TEST_CASE_BODY(get_info)
{
lutok::state state;
ATF_REQUIRE(luaL_dostring(raw(state), "\n\nfunction hello() end\n"
"return hello") == 0);
lutok::debug debug;
debug.get_info(state, ">S");
ATF_REQUIRE_EQ(3, debug.line_defined());
}
ATF_TEST_CASE_WITHOUT_HEAD(get_stack);
ATF_TEST_CASE_BODY(get_stack)
{
lutok::state state;
ATF_REQUIRE(luaL_dostring(raw(state), "error('Hello')") == 1);
lutok::debug debug;
debug.get_stack(state, 0);
lua_pop(raw(state), 1);
// Not sure if we can actually validate anything here, other than we did not
// crash... (because get_stack only is supposed to update internal values of
// the debug structure).
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, get_info);
ATF_ADD_TEST_CASE(tcs, get_stack);
}

View File

@ -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())
throw std::runtime_error("Argument to factorial must be an integer");
const int i = state.to_integer();
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());
return EXIT_SUCCESS;
} catch (const lutok::error& e) {
std::cerr << "ERROR: " << e.what() << '\n';
return EXIT_FAILURE;
}
}

View File

@ -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;
}

View File

@ -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);
} 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;
}

View File

@ -0,0 +1,125 @@
// 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());
// 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();
// Stack contents: -2: table, -1: field value.
if (!state.is_string()) {
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()
<< '\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'}");
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;
}

114
external/bsd/lutok/dist/examples_test.sh vendored Normal file
View File

@ -0,0 +1,114 @@
#! __ATF_SH__
# 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.
ExamplesDir="__EXAMPLESDIR__"
LibDir="__LIBDIR__"
make_example() {
cp "${ExamplesDir}/Makefile" "${ExamplesDir}/${1}.cpp" .
make "${1}"
# Ensure that the binary we just built can find liblutok. This is
# needed because the lutok.pc file (which the Makefile used above
# queries) does not provide rpaths to the installed library and
# therefore the binary may not be able to locate it. Hardcoding the
# rpath flags into lutok.pc is non-trivial because we simply don't
# have any knowledge about what the correct flag to set an rpath is.
#
# Additionally, setting rpaths is not always the right thing to do.
# For example, pkgsrc will automatically change lutok.pc to add the
# missing rpath, in which case this is unnecessary. But in the case
# of Fedora, adding rpaths goes against the packaging guidelines.
if [ -n "${LD_LIBRARY_PATH}" ]; then
export LD_LIBRARY_PATH="${LibDir}:${LD_LIBRARY_PATH}"
else
export LD_LIBRARY_PATH="${LibDir}"
fi
}
example_test_case() {
local name="${1}"; shift
atf_test_case "${name}"
eval "${name}_head() { \
atf_set 'require.files' '${ExamplesDir}/${name}.cpp'; \
atf_set 'require.progs' 'make pkg-config'; \
}"
eval "${name}_body() { \
make_example '${name}'; \
${name}_validate; \
}"
}
example_test_case bindings
bindings_validate() {
atf_check -s exit:0 -o inline:'120\n' ./bindings 5
atf_check -s exit:1 -e match:'Argument.*must be an integer' ./bindings foo
atf_check -s exit:1 -e match:'Argument.*must be positive' ./bindings -5
}
example_test_case hello
hello_validate() {
atf_check -s exit:0 -o inline:'Hello, world!\n' ./hello
}
example_test_case interpreter
interpreter_validate() {
cat >script.lua <<EOF
test_variable = 12345
print("From the interpreter: " .. (test_variable - 345))
EOF
atf_check -s exit:0 -o match:"From the interpreter: 12000" \
-x "./interpreter <script.lua"
}
example_test_case raii
raii_validate() {
cat >expout <<EOF
String in field foo: hello
String in field bar: 123
String in field baz: bye
EOF
atf_check -s exit:0 -o file:expout ./raii
}
atf_init_test_cases() {
atf_add_test_case bindings
atf_add_test_case hello
atf_add_test_case interpreter
atf_add_test_case raii
}

126
external/bsd/lutok/dist/exceptions.cpp vendored Normal file
View File

@ -0,0 +1,126 @@
// Copyright 2011 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.
#include <cassert>
#include <lua.hpp>
#include "c_gate.hpp"
#include "exceptions.hpp"
#include "state.ipp"
/// Constructs a new error with a plain-text message.
///
/// \param message The plain-text error message.
lutok::error::error(const std::string& message) :
std::runtime_error(message)
{
}
/// Destructor for the error.
lutok::error::~error(void) throw()
{
}
/// Constructs a new error.
///
/// \param api_function_ The name of the API function that caused the error.
/// \param message The plain-text error message provided by Lua.
lutok::api_error::api_error(const std::string& api_function_,
const std::string& message) :
error(message),
_api_function(api_function_)
{
}
/// Destructor for the error.
lutok::api_error::~api_error(void) throw()
{
}
/// Constructs a new api_error with the message on the top of the Lua stack.
///
/// \pre There is an error message on the top of the stack.
/// \post The error message is popped from the stack.
///
/// \param state_ The Lua state.
/// \param api_function_ The name of the Lua API function that caused the error.
///
/// \return A new api_error with the popped message.
lutok::api_error
lutok::api_error::from_stack(state& state_, const std::string& api_function_)
{
lua_State* raw_state = lutok::state_c_gate(state_).c_state();
assert(lua_isstring(raw_state, -1));
const std::string message = lua_tostring(raw_state, -1);
lua_pop(raw_state, 1);
return lutok::api_error(api_function_, message);
}
/// Gets the name of the Lua API function that caused this error.
///
/// \return The name of the function.
const std::string&
lutok::api_error::api_function(void) const
{
return _api_function;
}
/// Constructs a new error.
///
/// \param filename_ The file that count not be found.
lutok::file_not_found_error::file_not_found_error(
const std::string& filename_) :
error("File '" + filename_ + "' not found"),
_filename(filename_)
{
}
/// Destructor for the error.
lutok::file_not_found_error::~file_not_found_error(void) throw()
{
}
/// Gets the name of the file that could not be found.
///
/// \return The name of the file.
const std::string&
lutok::file_not_found_error::filename(void) const
{
return _filename;
}

83
external/bsd/lutok/dist/exceptions.hpp vendored Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2011 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 exceptions.hpp
/// Exception types raised by lutok.
#if !defined(LUTOK_EXCEPTIONS_HPP)
#define LUTOK_EXCEPTIONS_HPP
#include <stdexcept>
#include <string>
namespace lutok {
class state;
/// Base exception for lua errors.
class error : public std::runtime_error {
public:
explicit error(const std::string&);
virtual ~error(void) throw();
};
/// Exception for errors raised by the Lua API library.
class api_error : public error {
/// Name of the Lua C API function that caused the error.
std::string _api_function;
public:
explicit api_error(const std::string&, const std::string&);
virtual ~api_error(void) throw();
static api_error from_stack(state&, const std::string&);
const std::string& api_function(void) const;
};
/// File not found error.
class file_not_found_error : public error {
/// Name of the not-found file.
std::string _filename;
public:
explicit file_not_found_error(const std::string&);
virtual ~file_not_found_error(void) throw();
const std::string& filename(void) const;
};
} // namespace lutok
#endif // !defined(LUTOK_EXCEPTIONS_HPP)

View File

@ -0,0 +1,88 @@
// Copyright 2011 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.
#include "exceptions.hpp"
#include <cstring>
#include <atf-c++.hpp>
#include "state.ipp"
ATF_TEST_CASE_WITHOUT_HEAD(error);
ATF_TEST_CASE_BODY(error)
{
const lutok::error e("Some text");
ATF_REQUIRE(std::strcmp("Some text", e.what()) == 0);
}
ATF_TEST_CASE_WITHOUT_HEAD(api_error__explicit);
ATF_TEST_CASE_BODY(api_error__explicit)
{
const lutok::api_error e("some_function", "Some text");
ATF_REQUIRE(std::strcmp("Some text", e.what()) == 0);
ATF_REQUIRE_EQ("some_function", e.api_function());
}
ATF_TEST_CASE_WITHOUT_HEAD(api_error__from_stack);
ATF_TEST_CASE_BODY(api_error__from_stack)
{
lutok::state state;
state.push_integer(123);
state.push_string("The error message");
const lutok::api_error e = lutok::api_error::from_stack(state,
"the_function");
ATF_REQUIRE_EQ(1, state.get_top());
ATF_REQUIRE_EQ(123, state.to_integer());
state.pop(1);
ATF_REQUIRE(std::strcmp("The error message", e.what()) == 0);
ATF_REQUIRE_EQ("the_function", e.api_function());
}
ATF_TEST_CASE_WITHOUT_HEAD(file_not_found_error);
ATF_TEST_CASE_BODY(file_not_found_error)
{
const lutok::file_not_found_error e("missing-file");
ATF_REQUIRE(std::strcmp("File 'missing-file' not found", e.what()) == 0);
ATF_REQUIRE_EQ("missing-file", e.filename());
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, error);
ATF_ADD_TEST_CASE(tcs, api_error__explicit);
ATF_ADD_TEST_CASE(tcs, api_error__from_stack);
ATF_ADD_TEST_CASE(tcs, file_not_found_error);
}

8
external/bsd/lutok/dist/lutok.pc.in vendored Normal file
View File

@ -0,0 +1,8 @@
includedir=__INCLUDEDIR__
libdir=__LIBDIR__
Name: lutok
Description: Lightweight C++ API for Lua
Version: __VERSION__
Cflags: __LUA_CFLAGS__ -I${includedir}
Libs: __LUA_LIBS__ -L${libdir} -llutok

143
external/bsd/lutok/dist/operations.cpp vendored Normal file
View File

@ -0,0 +1,143 @@
// Copyright 2011 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.
#include <cassert>
#include <lua.hpp>
#include "exceptions.hpp"
#include "operations.hpp"
#include "stack_cleaner.hpp"
#include "state.hpp"
/// Creates a module: i.e. a table with a set of methods in it.
///
/// \param s The Lua state.
/// \param name The name of the module to create.
/// \param members The list of member functions to add to the module.
void
lutok::create_module(state& s, const std::string& name,
const std::map< std::string, cxx_function >& members)
{
stack_cleaner cleaner(s);
s.new_table();
for (std::map< std::string, cxx_function >::const_iterator
iter = members.begin(); iter != members.end(); iter++) {
s.push_string((*iter).first);
s.push_cxx_function((*iter).second);
s.set_table(-3);
}
s.set_global(name);
}
/// Loads and processes a Lua file.
///
/// This is a replacement for luaL_dofile but with proper error reporting
/// and stack control.
///
/// \param s The Lua state.
/// \param file The file to load.
/// \param nresults The number of results to expect; -1 for any.
///
/// \return The number of results left on the stack.
///
/// \throw error If there is a problem processing the file.
unsigned int
lutok::do_file(state& s, const std::string& file, const int nresults)
{
assert(nresults >= -1);
const int height = s.get_top();
stack_cleaner cleaner(s);
try {
s.load_file(file);
s.pcall(0, nresults == -1 ? LUA_MULTRET : nresults, 0);
} catch (const lutok::api_error& e) {
throw lutok::error("Failed to load Lua file '" + file + "': " +
e.what());
}
cleaner.forget();
const int actual_results = s.get_top() - height;
assert(nresults == -1 || actual_results == nresults);
assert(actual_results >= 0);
return static_cast< unsigned int >(actual_results);
}
/// Processes a Lua script.
///
/// This is a replacement for luaL_dostring but with proper error reporting
/// and stack control.
///
/// \param s The Lua state.
/// \param str The string to process.
/// \param nresults The number of results to expect; -1 for any.
///
/// \return The number of results left on the stack.
///
/// \throw error If there is a problem processing the string.
unsigned int
lutok::do_string(state& s, const std::string& str, const int nresults)
{
assert(nresults >= -1);
const int height = s.get_top();
stack_cleaner cleaner(s);
try {
s.load_string(str);
s.pcall(0, nresults == -1 ? LUA_MULTRET : nresults, 0);
} catch (const lutok::api_error& e) {
throw lutok::error("Failed to process Lua string '" + str + "': " +
e.what());
}
cleaner.forget();
const int actual_results = s.get_top() - height;
assert(nresults == -1 || actual_results == nresults);
assert(actual_results >= 0);
return static_cast< unsigned int >(actual_results);
}
/// Convenience function to evaluate a Lua expression.
///
/// \param s The Lua state.
/// \param expression The textual expression to evaluate.
/// \param nresults The number of results to leave on the stack. Must be
/// positive.
///
/// \throw api_error If there is a problem evaluating the expression.
void
lutok::eval(state& s, const std::string& expression, const int nresults)
{
assert(nresults > 0);
do_string(s, "return " + expression, nresults);
}

53
external/bsd/lutok/dist/operations.hpp vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2011 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 operations.hpp
/// Extra generic functions to interact with Lua.
#if !defined(LUTOK_OPERATIONS_HPP)
#define LUTOK_OPERATIONS_HPP
#include <map>
#include <string>
#include <vector>
#include <lutok/state.hpp>
namespace lutok {
void create_module(state&, const std::string&,
const std::map< std::string, cxx_function >&);
unsigned int do_file(state&, const std::string&, const int = 0);
unsigned int do_string(state&, const std::string&, const int = 0);
void eval(state&, const std::string&, const int = 1);
} // namespace lutok
#endif // !defined(LUTOK_OPERATIONS_HPP)

View File

@ -0,0 +1,296 @@
// Copyright 2011 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.
#include "operations.hpp"
#include <fstream>
#include <atf-c++.hpp>
#include "exceptions.hpp"
#include "state.ipp"
#include "test_utils.hpp"
namespace {
/// Addition function for injection into Lua.
///
/// \pre stack(-2) The first summand.
/// \pre stack(-1) The second summand.
/// \post stack(-1) The result of the sum.
///
/// \param state The Lua state.
///
/// \return The number of results (1).
static int
hook_add(lutok::state& state)
{
state.push_integer(state.to_integer(-1) + state.to_integer(-2));
return 1;
}
/// Multiplication function for injection into Lua.
///
/// \pre stack(-2) The first factor.
/// \pre stack(-1) The second factor.
/// \post stack(-1) The product.
///
/// \param state The Lua state.
///
/// \return The number of results (1).
static int
hook_multiply(lutok::state& state)
{
state.push_integer(state.to_integer(-1) * state.to_integer(-2));
return 1;
}
} // anonymous namespace
ATF_TEST_CASE_WITHOUT_HEAD(create_module__empty);
ATF_TEST_CASE_BODY(create_module__empty)
{
lutok::state state;
std::map< std::string, lutok::cxx_function > members;
lutok::create_module(state, "my_math", members);
state.open_base();
lutok::do_string(state, "return next(my_math) == nil", 1);
ATF_REQUIRE(state.to_boolean());
state.pop(1);
}
ATF_TEST_CASE_WITHOUT_HEAD(create_module__one);
ATF_TEST_CASE_BODY(create_module__one)
{
lutok::state state;
std::map< std::string, lutok::cxx_function > members;
members["add"] = hook_add;
lutok::create_module(state, "my_math", members);
lutok::do_string(state, "return my_math.add(10, 20)", 1);
ATF_REQUIRE_EQ(30, state.to_integer());
state.pop(1);
}
ATF_TEST_CASE_WITHOUT_HEAD(create_module__many);
ATF_TEST_CASE_BODY(create_module__many)
{
lutok::state state;
std::map< std::string, lutok::cxx_function > members;
members["add"] = hook_add;
members["multiply"] = hook_multiply;
members["add2"] = hook_add;
lutok::create_module(state, "my_math", members);
lutok::do_string(state, "return my_math.add(10, 20)", 1);
ATF_REQUIRE_EQ(30, state.to_integer());
lutok::do_string(state, "return my_math.multiply(10, 20)", 1);
ATF_REQUIRE_EQ(200, state.to_integer());
lutok::do_string(state, "return my_math.add2(20, 30)", 1);
ATF_REQUIRE_EQ(50, state.to_integer());
state.pop(3);
}
ATF_TEST_CASE_WITHOUT_HEAD(do_file__any_results);
ATF_TEST_CASE_BODY(do_file__any_results)
{
std::ofstream output("test.lua");
output << "return 10, 20, 30\n";
output.close();
lutok::state state;
ATF_REQUIRE_EQ(3, lutok::do_file(state, "test.lua", -1));
ATF_REQUIRE_EQ(3, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer(-3));
ATF_REQUIRE_EQ(20, state.to_integer(-2));
ATF_REQUIRE_EQ(30, state.to_integer(-1));
state.pop(3);
}
ATF_TEST_CASE_WITHOUT_HEAD(do_file__no_results);
ATF_TEST_CASE_BODY(do_file__no_results)
{
std::ofstream output("test.lua");
output << "return 10, 20, 30\n";
output.close();
lutok::state state;
ATF_REQUIRE_EQ(0, lutok::do_file(state, "test.lua"));
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_TEST_CASE_WITHOUT_HEAD(do_file__many_results);
ATF_TEST_CASE_BODY(do_file__many_results)
{
std::ofstream output("test.lua");
output << "return 10, 20, 30\n";
output.close();
lutok::state state;
ATF_REQUIRE_EQ(2, lutok::do_file(state, "test.lua", 2));
ATF_REQUIRE_EQ(2, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer(-2));
ATF_REQUIRE_EQ(20, state.to_integer(-1));
state.pop(2);
}
ATF_TEST_CASE_WITHOUT_HEAD(do_file__not_found);
ATF_TEST_CASE_BODY(do_file__not_found)
{
lutok::state state;
stack_balance_checker checker(state);
ATF_REQUIRE_THROW_RE(lutok::file_not_found_error, "missing.lua",
lutok::do_file(state, "missing.lua"));
}
ATF_TEST_CASE_WITHOUT_HEAD(do_file__error);
ATF_TEST_CASE_BODY(do_file__error)
{
std::ofstream output("test.lua");
output << "a b c\n";
output.close();
lutok::state state;
stack_balance_checker checker(state);
ATF_REQUIRE_THROW_RE(lutok::error, "Failed to load Lua file 'test.lua'",
lutok::do_file(state, "test.lua"));
}
ATF_TEST_CASE_WITHOUT_HEAD(do_string__any_results);
ATF_TEST_CASE_BODY(do_string__any_results)
{
lutok::state state;
ATF_REQUIRE_EQ(3, lutok::do_string(state, "return 10, 20, 30", -1));
ATF_REQUIRE_EQ(3, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer(-3));
ATF_REQUIRE_EQ(20, state.to_integer(-2));
ATF_REQUIRE_EQ(30, state.to_integer(-1));
state.pop(3);
}
ATF_TEST_CASE_WITHOUT_HEAD(do_string__no_results);
ATF_TEST_CASE_BODY(do_string__no_results)
{
lutok::state state;
ATF_REQUIRE_EQ(0, lutok::do_string(state, "return 10, 20, 30"));
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_TEST_CASE_WITHOUT_HEAD(do_string__many_results);
ATF_TEST_CASE_BODY(do_string__many_results)
{
lutok::state state;
ATF_REQUIRE_EQ(2, lutok::do_string(state, "return 10, 20, 30", 2));
ATF_REQUIRE_EQ(2, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer(-2));
ATF_REQUIRE_EQ(20, state.to_integer(-1));
state.pop(2);
}
ATF_TEST_CASE_WITHOUT_HEAD(do_string__error);
ATF_TEST_CASE_BODY(do_string__error)
{
lutok::state state;
stack_balance_checker checker(state);
ATF_REQUIRE_THROW_RE(lutok::error, "Failed to process Lua string 'a b c'",
lutok::do_string(state, "a b c"));
}
ATF_TEST_CASE_WITHOUT_HEAD(eval__one_result);
ATF_TEST_CASE_BODY(eval__one_result)
{
lutok::state state;
stack_balance_checker checker(state);
lutok::eval(state, "3 + 10");
ATF_REQUIRE_EQ(13, state.to_integer());
state.pop(1);
}
ATF_TEST_CASE_WITHOUT_HEAD(eval__many_results);
ATF_TEST_CASE_BODY(eval__many_results)
{
lutok::state state;
stack_balance_checker checker(state);
lutok::eval(state, "5, 8, 10", 3);
ATF_REQUIRE_EQ(5, state.to_integer(-3));
ATF_REQUIRE_EQ(8, state.to_integer(-2));
ATF_REQUIRE_EQ(10, state.to_integer(-1));
state.pop(3);
}
ATF_TEST_CASE_WITHOUT_HEAD(eval__error);
ATF_TEST_CASE_BODY(eval__error)
{
lutok::state state;
stack_balance_checker checker(state);
ATF_REQUIRE_THROW(lutok::error,
lutok::eval(state, "non_existent.method()"));
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, create_module__empty);
ATF_ADD_TEST_CASE(tcs, create_module__one);
ATF_ADD_TEST_CASE(tcs, create_module__many);
ATF_ADD_TEST_CASE(tcs, do_file__any_results);
ATF_ADD_TEST_CASE(tcs, do_file__no_results);
ATF_ADD_TEST_CASE(tcs, do_file__many_results);
ATF_ADD_TEST_CASE(tcs, do_file__not_found);
ATF_ADD_TEST_CASE(tcs, do_file__error);
ATF_ADD_TEST_CASE(tcs, do_string__any_results);
ATF_ADD_TEST_CASE(tcs, do_string__no_results);
ATF_ADD_TEST_CASE(tcs, do_string__many_results);
ATF_ADD_TEST_CASE(tcs, do_string__error);
ATF_ADD_TEST_CASE(tcs, eval__one_result);
ATF_ADD_TEST_CASE(tcs, eval__many_results);
ATF_ADD_TEST_CASE(tcs, eval__error);
}

View File

@ -0,0 +1,91 @@
// Copyright 2011 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.
#include <cassert>
#include <cstring>
#include "stack_cleaner.hpp"
#include "state.ipp"
/// Internal implementation for lutok::stack_cleaner.
struct lutok::stack_cleaner::impl {
/// Reference to the Lua state this stack_cleaner refers to.
state& state_ref;
/// The depth of the Lua stack to be restored.
unsigned int original_depth;
/// Constructor.
///
/// \param state_ref_ Reference to the Lua state.
/// \param original_depth_ The depth of the Lua stack.
impl(state& state_ref_, const unsigned int original_depth_) :
state_ref(state_ref_),
original_depth(original_depth_)
{
}
};
/// Creates a new stack cleaner.
///
/// This gathers the current height of the stack so that extra elements can be
/// popped during destruction.
///
/// \param state_ The Lua state.
lutok::stack_cleaner::stack_cleaner(state& state_) :
_pimpl(new impl(state_, state_.get_top()))
{
}
/// Pops any values from the stack not known at construction time.
///
/// \pre The current height of the stack must be equal or greater to the height
/// of the stack when this object was instantiated.
lutok::stack_cleaner::~stack_cleaner(void)
{
const unsigned int current_depth = _pimpl->state_ref.get_top();
assert(current_depth >= _pimpl->original_depth);
const unsigned int diff = current_depth - _pimpl->original_depth;
if (diff > 0)
_pimpl->state_ref.pop(diff);
}
/// Forgets about any elements currently in the stack.
///
/// This allows a function to return values on the stack because all the
/// elements that are currently in the stack will not be touched during
/// destruction when the function is called.
void
lutok::stack_cleaner::forget(void)
{
_pimpl->original_depth = _pimpl->state_ref.get_top();
}

View File

@ -0,0 +1,93 @@
// Copyright 2011 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 stack_cleaner.hpp
/// Provides the stack_cleaner class.
#if !defined(LUTOK_STACK_CLEANER_HPP)
#define LUTOK_STACK_CLEANER_HPP
#include <memory>
#include <lutok/state.hpp>
namespace lutok {
/// A RAII model for values on the Lua stack.
///
/// At creation time, the object records the current depth of the Lua stack and,
/// during destruction, restores the recorded depth by popping as many stack
/// entries as required. As a corollary, the stack can only grow during the
/// lifetime of a stack_cleaner object (or shrink, but cannot become shorter
/// than the depth recorded at creation time).
///
/// Use this class as follows:
///
/// state s;
/// {
/// stack_cleaner cleaner1(s);
/// s.push_integer(3);
/// s.push_integer(5);
/// ... do stuff here ...
/// for (...) {
/// stack_cleaner cleaner2(s);
/// s.load_string("...");
/// s.pcall(0, 1, 0);
/// ... do stuff here ...
/// }
/// // cleaner2 destroyed; the result of pcall is gone.
/// }
/// // cleaner1 destroyed; the integers 3 and 5 are gone.
///
/// You must give a name to the instantiated objects even if they cannot be
/// accessed later. Otherwise, the instance will be destroyed right away and
/// will not have the desired effect.
class stack_cleaner {
struct impl;
/// Pointer to the shared internal implementation.
std::auto_ptr< impl > _pimpl;
/// Disallow copies.
stack_cleaner(const stack_cleaner&);
/// Disallow assignment.
stack_cleaner& operator=(const stack_cleaner&);
public:
stack_cleaner(state&);
~stack_cleaner(void);
void forget(void);
};
} // namespace lutok
#endif // !defined(LUTOK_STACK_CLEANER_HPP)

View File

@ -0,0 +1,108 @@
// Copyright 2011 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.
#include "stack_cleaner.hpp"
#include <atf-c++.hpp>
ATF_TEST_CASE_WITHOUT_HEAD(empty);
ATF_TEST_CASE_BODY(empty)
{
lutok::state state;
{
lutok::stack_cleaner cleaner(state);
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_TEST_CASE_WITHOUT_HEAD(some);
ATF_TEST_CASE_BODY(some)
{
lutok::state state;
{
lutok::stack_cleaner cleaner(state);
state.push_integer(15);
ATF_REQUIRE_EQ(1, state.get_top());
state.push_integer(30);
ATF_REQUIRE_EQ(2, state.get_top());
}
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_TEST_CASE_WITHOUT_HEAD(nested);
ATF_TEST_CASE_BODY(nested)
{
lutok::state state;
{
lutok::stack_cleaner cleaner1(state);
state.push_integer(10);
ATF_REQUIRE_EQ(1, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer());
{
lutok::stack_cleaner cleaner2(state);
state.push_integer(20);
ATF_REQUIRE_EQ(2, state.get_top());
ATF_REQUIRE_EQ(20, state.to_integer(-1));
ATF_REQUIRE_EQ(10, state.to_integer(-2));
}
ATF_REQUIRE_EQ(1, state.get_top());
ATF_REQUIRE_EQ(10, state.to_integer());
}
ATF_REQUIRE_EQ(0, state.get_top());
}
ATF_TEST_CASE_WITHOUT_HEAD(forget);
ATF_TEST_CASE_BODY(forget)
{
lutok::state state;
{
lutok::stack_cleaner cleaner(state);
state.push_integer(15);
state.push_integer(30);
cleaner.forget();
state.push_integer(60);
ATF_REQUIRE_EQ(3, state.get_top());
}
ATF_REQUIRE_EQ(2, state.get_top());
ATF_REQUIRE_EQ(30, state.to_integer());
state.pop(2);
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, empty);
ATF_ADD_TEST_CASE(tcs, some);
ATF_ADD_TEST_CASE(tcs, nested);
ATF_ADD_TEST_CASE(tcs, forget);
}

862
external/bsd/lutok/dist/state.cpp vendored Normal file
View File

@ -0,0 +1,862 @@
// Copyright 2011 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.
extern "C" {
#include <unistd.h>
}
#include <cassert>
#include <cstring>
#include "c_gate.hpp"
#include "exceptions.hpp"
#include "state.ipp"
namespace {
/// Wrapper around lua_getglobal to run in a protected environment.
///
/// \pre stack(-1) is the name of the global to get.
/// \post stack(-1) is the value of the global.
///
/// \param state The Lua C API state.
///
/// \return The number of return values pushed onto the stack.
static int
protected_getglobal(lua_State* state)
{
lua_getglobal(state, lua_tostring(state, -1));
return 1;
}
/// Wrapper around lua_gettable to run in a protected environment.
///
/// \pre stack(-2) is the table to get the element from.
/// \pre stack(-1) is the table index.
/// \post stack(-1) is the value of stack(-2)[stack(-1)].
///
/// \param state The Lua C API state.
///
/// \return The number of return values pushed onto the stack.
static int
protected_gettable(lua_State* state)
{
lua_gettable(state, -2);
return 1;
}
/// Wrapper around lua_next to run in a protected environment.
///
/// \pre stack(-2) is the table to get the next element from.
/// \pre stack(-1) is the last processed key.
/// \post stack(-1) is the value of next(stack(-2), stack(-1)).
///
/// \param state The Lua C API state.
///
/// \return The number of return values pushed onto the stack.
static int
protected_next(lua_State* state)
{
const int more = lua_next(state, -2) != 0;
lua_pushboolean(state, more);
return more ? 3 : 1;
}
/// Wrapper around lua_setglobal to run in a protected environment.
///
/// \pre stack(-2) is the name of the global to set.
/// \pre stack(-1) is the value to set the global to.
///
/// \param state The Lua C API state.
///
/// \return The number of return values pushed onto the stack.
static int
protected_setglobal(lua_State* state)
{
lua_setglobal(state, lua_tostring(state, -2));
return 0;
}
/// Wrapper around lua_settable to run in a protected environment.
///
/// \pre stack(-3) is the table to set the element into.
/// \pre stack(-2) is the table index.
/// \pre stack(-1) is the value to set.
///
/// \param state The Lua C API state.
///
/// \return The number of return values pushed onto the stack.
static int
protected_settable(lua_State* state)
{
lua_settable(state, -3);
return 0;
}
/// Calls a C++ Lua function from a C calling environment.
///
/// Any errors reported by the C++ function are caught and reported to the
/// caller as Lua errors.
///
/// \param function The C++ function to call.
/// \param raw_state The raw Lua state.
///
/// \return The number of return values pushed onto the Lua stack by the
/// function.
static int
call_cxx_function_from_c(lutok::cxx_function function,
lua_State* raw_state) throw()
{
char error_buf[1024];
try {
lutok::state state = lutok::state_c_gate::connect(raw_state);
return function(state);
} catch (const std::exception& e) {
std::strncpy(error_buf, e.what(), sizeof(error_buf));
} catch (...) {
std::strncpy(error_buf, "Unhandled exception in Lua C++ hook",
sizeof(error_buf));
}
error_buf[sizeof(error_buf) - 1] = '\0';
// We raise the Lua error from outside the try/catch context and we use
// a stack-based buffer to hold the message to ensure that we do not leak
// any C++ objects (and, as a likely result, memory) when Lua performs its
// longjmp.
return luaL_error(raw_state, "%s", error_buf);
}
/// Lua glue to call a C++ closure.
///
/// This Lua binding is actually a closure that we have constructed from the
/// state.push_cxx_closure() method. The closure contains the same upvalues
/// provided by the user plus an extra upvalue that contains the address of the
/// C++ function we have to call. All we do here is safely delegate the
/// execution to the wrapped C++ closure.
///
/// \param raw_state The Lua C API state.
///
/// \return The number of return values of the called closure.
static int
cxx_closure_trampoline(lua_State* raw_state)
{
lutok::state state = lutok::state_c_gate::connect(raw_state);
int nupvalues;
{
lua_Debug debug;
lua_getstack(raw_state, 0, &debug);
lua_getinfo(raw_state, "u", &debug);
nupvalues = debug.nups;
}
lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >(
state.upvalue_index(nupvalues));
return call_cxx_function_from_c(*function, raw_state);
}
/// Lua glue to call a C++ function.
///
/// This Lua binding is actually a closure that we have constructed from the
/// state.push_cxx_function() method. The closure has a single upvalue that
/// contains the address of the C++ function we have to call. All we do here is
/// safely delegate the execution to the wrapped C++ function.
///
/// \param raw_state The Lua C API state.
///
/// \return The number of return values of the called function.
static int
cxx_function_trampoline(lua_State* raw_state)
{
lutok::state state = lutok::state_c_gate::connect(raw_state);
lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >(
state.upvalue_index(1));
return call_cxx_function_from_c(*function, raw_state);
}
} // anonymous namespace
const int lutok::globals_index = LUA_GLOBALSINDEX;
/// Internal implementation for lutok::state.
struct lutok::state::impl {
/// The Lua internal state.
lua_State* lua_state;
/// Whether we own the state or not (to decide if we close it).
bool owned;
/// Constructor.
///
/// \param lua_ The Lua internal state.
/// \param owned_ Whether we own the state or not.
impl(lua_State* lua_, bool owned_) :
lua_state(lua_),
owned(owned_)
{
}
};
/// Initializes the Lua state.
///
/// You must share the same state object alongside the lifetime of your Lua
/// session. As soon as the object is destroyed, the session is terminated.
lutok::state::state(void)
{
lua_State* lua = lua_open();
if (lua == NULL)
throw lutok::error("lua open failed");
_pimpl.reset(new impl(lua, true));
}
/// Initializes the Lua state from an existing raw state.
///
/// Instances constructed using this method do NOT own the raw state. This
/// means that, on exit, the state will not be destroyed.
///
/// \param raw_state_ The raw Lua state to wrap.
lutok::state::state(void* raw_state_) :
_pimpl(new impl(reinterpret_cast< lua_State* >(raw_state_), false))
{
}
/// Destructor for the Lua state.
///
/// Closes the session unless it has already been closed by calling the
/// close() method. It is recommended to explicitly close the session in the
/// code.
lutok::state::~state(void)
{
if (_pimpl->owned && _pimpl->lua_state != NULL)
close();
}
/// Terminates this Lua session.
///
/// It is recommended to call this instead of relying on the destructor to do
/// the cleanup, but it is not a requirement to use close().
///
/// \pre close() has not yet been called.
/// \pre The Lua stack is empty. This is not truly necessary but ensures that
/// our code is consistent and clears the stack explicitly.
void
lutok::state::close(void)
{
assert(_pimpl->lua_state != NULL);
assert(lua_gettop(_pimpl->lua_state) == 0);
lua_close(_pimpl->lua_state);
_pimpl->lua_state = NULL;
}
/// Wrapper around lua_getglobal.
///
/// \param name The second parameter to lua_getglobal.
///
/// \throw api_error If lua_getglobal fails.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::state::get_global(const std::string& name)
{
lua_pushcfunction(_pimpl->lua_state, protected_getglobal);
lua_pushstring(_pimpl->lua_state, name.c_str());
if (lua_pcall(_pimpl->lua_state, 1, 1, 0) != 0)
throw lutok::api_error::from_stack(*this, "lua_getglobal");
}
/// Wrapper around luaL_getmetafield.
///
/// \param index The second parameter to luaL_getmetafield.
/// \param name The third parameter to luaL_getmetafield.
///
/// \return The return value of luaL_getmetafield.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
bool
lutok::state::get_metafield(const int index, const std::string& name)
{
return luaL_getmetafield(_pimpl->lua_state, index, name.c_str()) != 0;
}
/// Wrapper around lua_getmetatable.
///
/// \param index The second parameter to lua_getmetatable.
///
/// \return The return value of lua_getmetatable.
bool
lutok::state::get_metatable(const int index)
{
return lua_getmetatable(_pimpl->lua_state, index) != 0;
}
/// Wrapper around lua_gettable.
///
/// \param index The second parameter to lua_gettable.
///
/// \throw api_error If lua_gettable fails.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::state::get_table(const int index)
{
assert(lua_gettop(_pimpl->lua_state) >= 2);
lua_pushcfunction(_pimpl->lua_state, protected_gettable);
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
lua_pushvalue(_pimpl->lua_state, -3);
if (lua_pcall(_pimpl->lua_state, 2, 1, 0) != 0)
throw lutok::api_error::from_stack(*this, "lua_gettable");
lua_remove(_pimpl->lua_state, -2);
}
/// Wrapper around lua_gettop.
///
/// \return The return value of lua_gettop.
int
lutok::state::get_top(void)
{
return lua_gettop(_pimpl->lua_state);
}
/// Wrapper around lua_insert.
///
/// \param index The second parameter to lua_insert.
void
lutok::state::insert(const int index)
{
lua_insert(_pimpl->lua_state, index);
}
/// Wrapper around lua_isboolean.
///
/// \param index The second parameter to lua_isboolean.
///
/// \return The return value of lua_isboolean.
bool
lutok::state::is_boolean(const int index)
{
return lua_isboolean(_pimpl->lua_state, index);
}
/// Wrapper around lua_isfunction.
///
/// \param index The second parameter to lua_isfunction.
///
/// \return The return value of lua_isfunction.
bool
lutok::state::is_function(const int index)
{
return lua_isfunction(_pimpl->lua_state, index);
}
/// Wrapper around lua_isnil.
///
/// \param index The second parameter to lua_isnil.
///
/// \return The return value of lua_isnil.
bool
lutok::state::is_nil(const int index)
{
return lua_isnil(_pimpl->lua_state, index);
}
/// Wrapper around lua_isnumber.
///
/// \param index The second parameter to lua_isnumber.
///
/// \return The return value of lua_isnumber.
bool
lutok::state::is_number(const int index)
{
return lua_isnumber(_pimpl->lua_state, index);
}
/// Wrapper around lua_isstring.
///
/// \param index The second parameter to lua_isstring.
///
/// \return The return value of lua_isstring.
bool
lutok::state::is_string(const int index)
{
return lua_isstring(_pimpl->lua_state, index);
}
/// Wrapper around lua_istable.
///
/// \param index The second parameter to lua_istable.
///
/// \return The return value of lua_istable.
bool
lutok::state::is_table(const int index)
{
return lua_istable(_pimpl->lua_state, index);
}
/// Wrapper around lua_isuserdata.
///
/// \param index The second parameter to lua_isuserdata.
///
/// \return The return value of lua_isuserdata.
bool
lutok::state::is_userdata(const int index)
{
return lua_isuserdata(_pimpl->lua_state, index);
}
/// Wrapper around luaL_loadfile.
///
/// \param file The second parameter to luaL_loadfile.
///
/// \throw api_error If luaL_loadfile returns an error.
/// \throw file_not_found_error If the file cannot be accessed.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::load_file(const std::string& file)
{
if (!::access(file.c_str(), R_OK) == 0)
throw lutok::file_not_found_error(file);
if (luaL_loadfile(_pimpl->lua_state, file.c_str()) != 0)
throw lutok::api_error::from_stack(*this, "luaL_loadfile");
}
/// Wrapper around luaL_loadstring.
///
/// \param str The second parameter to luaL_loadstring.
///
/// \throw api_error If luaL_loadstring returns an error.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::load_string(const std::string& str)
{
if (luaL_loadstring(_pimpl->lua_state, str.c_str()) != 0)
throw lutok::api_error::from_stack(*this, "luaL_loadstring");
}
/// Wrapper around lua_newtable.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::new_table(void)
{
lua_newtable(_pimpl->lua_state);
}
/// Wrapper around lua_newuserdata.
///
/// This is internal. The public type-safe interface of this method should be
/// used instead.
///
/// \param size The second parameter to lua_newuserdata.
///
/// \return The return value of lua_newuserdata.
///
/// \warning Terminates execution if there is not enough memory.
void*
lutok::state::new_userdata_voidp(const size_t size)
{
return lua_newuserdata(_pimpl->lua_state, size);
}
/// Wrapper around lua_next.
///
/// \param index The second parameter to lua_next.
///
/// \return True if there are more elements to process; false otherwise.
///
/// \warning Terminates execution if there is not enough memory.
bool
lutok::state::next(const int index)
{
assert(lua_istable(_pimpl->lua_state, index));
assert(lua_gettop(_pimpl->lua_state) >= 1);
lua_pushcfunction(_pimpl->lua_state, protected_next);
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
lua_pushvalue(_pimpl->lua_state, -3);
if (lua_pcall(_pimpl->lua_state, 2, LUA_MULTRET, 0) != 0)
throw lutok::api_error::from_stack(*this, "lua_next");
const bool more = lua_toboolean(_pimpl->lua_state, -1);
lua_pop(_pimpl->lua_state, 1);
if (more)
lua_remove(_pimpl->lua_state, -3);
else
lua_pop(_pimpl->lua_state, 1);
return more;
}
/// Wrapper around luaopen_base.
///
/// \throw api_error If luaopen_base fails.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::open_base(void)
{
lua_pushcfunction(_pimpl->lua_state, luaopen_base);
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
throw lutok::api_error::from_stack(*this, "luaopen_base");
}
/// Wrapper around luaopen_string.
///
/// \throw api_error If luaopen_string fails.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::open_string(void)
{
lua_pushcfunction(_pimpl->lua_state, luaopen_string);
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
throw lutok::api_error::from_stack(*this, "luaopen_string");
}
/// Wrapper around luaopen_table.
///
/// \throw api_error If luaopen_table fails.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::open_table(void)
{
lua_pushcfunction(_pimpl->lua_state, luaopen_table);
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
throw lutok::api_error::from_stack(*this, "luaopen_table");
}
/// Wrapper around lua_pcall.
///
/// \param nargs The second parameter to lua_pcall.
/// \param nresults The third parameter to lua_pcall.
/// \param errfunc The fourth parameter to lua_pcall.
///
/// \throw api_error If lua_pcall returns an error.
void
lutok::state::pcall(const int nargs, const int nresults, const int errfunc)
{
if (lua_pcall(_pimpl->lua_state, nargs, nresults, errfunc) != 0)
throw lutok::api_error::from_stack(*this, "lua_pcall");
}
/// Wrapper around lua_pop.
///
/// \param count The second parameter to lua_pop.
void
lutok::state::pop(const int count)
{
assert(count <= lua_gettop(_pimpl->lua_state));
lua_pop(_pimpl->lua_state, count);
assert(lua_gettop(_pimpl->lua_state) >= 0);
}
/// Wrapper around lua_pushboolean.
///
/// \param value The second parameter to lua_pushboolean.
void
lutok::state::push_boolean(const bool value)
{
lua_pushboolean(_pimpl->lua_state, value ? 1 : 0);
}
/// Wrapper around lua_pushcclosure.
///
/// This is not a pure wrapper around lua_pushcclosure because this has to do
/// extra magic to allow passing C++ functions instead of plain C functions.
///
/// \param function The C++ function to be pushed as a closure.
/// \param nvalues The number of upvalues that the function receives.
void
lutok::state::push_cxx_closure(cxx_function function, const int nvalues)
{
cxx_function *data = static_cast< cxx_function* >(
lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function)));
*data = function;
lua_pushcclosure(_pimpl->lua_state, cxx_closure_trampoline, nvalues + 1);
}
/// Wrapper around lua_pushcfunction.
///
/// This is not a pure wrapper around lua_pushcfunction because this has to do
/// extra magic to allow passing C++ functions instead of plain C functions.
///
/// \param function The C++ function to be pushed.
void
lutok::state::push_cxx_function(cxx_function function)
{
cxx_function *data = static_cast< cxx_function* >(
lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function)));
*data = function;
lua_pushcclosure(_pimpl->lua_state, cxx_function_trampoline, 1);
}
/// Wrapper around lua_pushinteger.
///
/// \param value The second parameter to lua_pushinteger.
void
lutok::state::push_integer(const int value)
{
lua_pushinteger(_pimpl->lua_state, value);
}
/// Wrapper around lua_pushnil.
void
lutok::state::push_nil(void)
{
lua_pushnil(_pimpl->lua_state);
}
/// Wrapper around lua_pushstring.
///
/// \param str The second parameter to lua_pushstring.
///
/// \warning Terminates execution if there is not enough memory.
void
lutok::state::push_string(const std::string& str)
{
lua_pushstring(_pimpl->lua_state, str.c_str());
}
/// Wrapper around lua_pushvalue.
///
/// \param index The second parameter to lua_pushvalue.
void
lutok::state::push_value(const int index)
{
lua_pushvalue(_pimpl->lua_state, index);
}
/// Wrapper around lua_rawget.
///
/// \param index The second parameter to lua_rawget.
void
lutok::state::raw_get(const int index)
{
lua_rawget(_pimpl->lua_state, index);
}
/// Wrapper around lua_rawset.
///
/// \param index The second parameter to lua_rawset.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::state::raw_set(const int index)
{
lua_rawset(_pimpl->lua_state, index);
}
/// Wrapper around lua_setglobal.
///
/// \param name The second parameter to lua_setglobal.
///
/// \throw api_error If lua_setglobal fails.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::state::set_global(const std::string& name)
{
lua_pushcfunction(_pimpl->lua_state, protected_setglobal);
lua_pushstring(_pimpl->lua_state, name.c_str());
lua_pushvalue(_pimpl->lua_state, -3);
if (lua_pcall(_pimpl->lua_state, 2, 0, 0) != 0)
throw lutok::api_error::from_stack(*this, "lua_setglobal");
lua_pop(_pimpl->lua_state, 1);
}
/// Wrapper around lua_setmetatable.
///
/// \param index The second parameter to lua_setmetatable.
void
lutok::state::set_metatable(const int index)
{
lua_setmetatable(_pimpl->lua_state, index);
}
/// Wrapper around lua_settable.
///
/// \param index The second parameter to lua_settable.
///
/// \throw api_error If lua_settable fails.
///
/// \warning Terminates execution if there is not enough memory to manipulate
/// the Lua stack.
void
lutok::state::set_table(const int index)
{
lua_pushcfunction(_pimpl->lua_state, protected_settable);
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
lua_pushvalue(_pimpl->lua_state, -4);
lua_pushvalue(_pimpl->lua_state, -4);
if (lua_pcall(_pimpl->lua_state, 3, 0, 0) != 0)
throw lutok::api_error::from_stack(*this, "lua_settable");
lua_pop(_pimpl->lua_state, 2);
}
/// Wrapper around lua_toboolean.
///
/// \param index The second parameter to lua_toboolean.
///
/// \return The return value of lua_toboolean.
bool
lutok::state::to_boolean(const int index)
{
assert(is_boolean(index));
return lua_toboolean(_pimpl->lua_state, index);
}
/// Wrapper around lua_tointeger.
///
/// \param index The second parameter to lua_tointeger.
///
/// \return The return value of lua_tointeger.
long
lutok::state::to_integer(const int index)
{
assert(is_number(index));
return lua_tointeger(_pimpl->lua_state, index);
}
/// Wrapper around lua_touserdata.
///
/// This is internal. The public type-safe interface of this method should be
/// used instead.
///
/// \param index The second parameter to lua_touserdata.
///
/// \return The return value of lua_touserdata.
///
/// \warning Terminates execution if there is not enough memory.
void*
lutok::state::to_userdata_voidp(const int index)
{
return lua_touserdata(_pimpl->lua_state, index);
}
/// Wrapper around lua_tostring.
///
/// \param index The second parameter to lua_tostring.
///
/// \return The return value of lua_tostring.
///
/// \warning Terminates execution if there is not enough memory.
std::string
lutok::state::to_string(const int index)
{
assert(is_string(index));
const char *raw_string = lua_tostring(_pimpl->lua_state, index);
// Note that the creation of a string object below (explicit for clarity)
// implies that the raw string is duplicated and, henceforth, the string is
// safe even if the corresponding element is popped from the Lua stack.
return std::string(raw_string);
}
/// Wrapper around lua_upvalueindex.
///
/// \param index The first parameter to lua_upvalueindex.
///
/// \return The return value of lua_upvalueindex.
int
lutok::state::upvalue_index(const int index)
{
return lua_upvalueindex(index);
}
/// Gets the internal lua_State object.
///
/// \return The raw Lua state. This is returned as a void pointer to prevent
/// including the lua.hpp header file from our public interface. The only way
/// to call this method is by using the c_gate module, and c_gate takes care of
/// casting this object to the appropriate type.
void*
lutok::state::raw_state(void)
{
return _pimpl->lua_state;
}

134
external/bsd/lutok/dist/state.hpp vendored Normal file
View File

@ -0,0 +1,134 @@
// Copyright 2011 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 state.hpp
/// Provides the state wrapper class for the Lua C state.
#if !defined(LUTOK_STATE_HPP)
#define LUTOK_STATE_HPP
#include <string>
#include <tr1/memory>
namespace lutok {
class debug;
class state;
/// The type of a C++ function that can be bound into Lua.
///
/// Functions of this type are free to raise exceptions. These will not
/// propagate into the Lua C API. However, any such exceptions will be reported
/// as a Lua error and their type will be lost.
typedef int (*cxx_function)(state&);
/// Stack index constant pointing to the globals table (_G).
extern const int globals_index;
/// A RAII model for the Lua state.
///
/// This class holds the state of the Lua interpreter during its existence and
/// provides wrappers around several Lua library functions that operate on such
/// state.
///
/// These wrapper functions differ from the C versions in that they use the
/// implicit state hold by the class, they use C++ types where appropriate and
/// they use exceptions to report errors.
///
/// The wrappers intend to be as lightweight as possible but, in some
/// situations, they are pretty complex because they need to do extra work to
/// capture the errors reported by the Lua C API. We prefer having fine-grained
/// error control rather than efficiency, so this is OK.
class state {
struct impl;
/// Pointer to the shared internal implementation.
std::tr1::shared_ptr< impl > _pimpl;
void* new_userdata_voidp(const size_t);
void* to_userdata_voidp(const int);
friend class state_c_gate;
explicit state(void*);
void* raw_state(void);
public:
state(void);
~state(void);
void close(void);
void get_global(const std::string&);
bool get_metafield(const int, const std::string&);
bool get_metatable(const int = -1);
void get_table(const int = -2);
int get_top(void);
void insert(const int);
bool is_boolean(const int = -1);
bool is_function(const int = -1);
bool is_nil(const int = -1);
bool is_number(const int = -1);
bool is_string(const int = -1);
bool is_table(const int = -1);
bool is_userdata(const int = -1);
void load_file(const std::string&);
void load_string(const std::string&);
void new_table(void);
template< typename Type > Type* new_userdata(void);
bool next(const int = -2);
void open_base(void);
void open_string(void);
void open_table(void);
void pcall(const int, const int, const int);
void pop(const int);
void push_boolean(const bool);
void push_cxx_closure(cxx_function, const int);
void push_cxx_function(cxx_function);
void push_integer(const int);
void push_nil(void);
void push_string(const std::string&);
void push_value(const int = -1);
void raw_get(const int = -2);
void raw_set(const int = -3);
void set_global(const std::string&);
void set_metatable(const int = -2);
void set_table(const int = -3);
bool to_boolean(const int = -1);
long to_integer(const int = -1);
template< typename Type > Type* to_userdata(const int = -1);
std::string to_string(const int = -1);
int upvalue_index(const int);
};
} // namespace lutok
#endif // !defined(LUTOK_STATE_HPP)

67
external/bsd/lutok/dist/state.ipp vendored Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2011 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.
#if !defined(LUTOK_STATE_IPP)
#define LUTOK_STATE_IPP
#include <lutok/state.hpp>
namespace lutok {
/// Wrapper around lua_newuserdata.
///
/// This allocates an object as big as the size of the provided Type.
///
/// \return The pointer to the allocated userdata object.
///
/// \warning Terminates execution if there is not enough memory.
template< typename Type >
Type*
state::new_userdata(void)
{
return static_cast< Type* >(new_userdata_voidp(sizeof(Type)));
}
/// Wrapper around lua_touserdata.
///
/// \param index The second parameter to lua_touserdata.
///
/// \return The return value of lua_touserdata.
template< typename Type >
Type*
state::to_userdata(const int index)
{
return static_cast< Type* >(to_userdata_voidp(index));
}
} // namespace lutok
#endif // !defined(LUTOK_STATE_IPP)

1404
external/bsd/lutok/dist/state_test.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

141
external/bsd/lutok/dist/test_utils.hpp vendored Normal file
View File

@ -0,0 +1,141 @@
// Copyright 2011 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 test_utils.hpp
/// Utilities for tests of the lua modules.
///
/// This file is intended to be included once, and only once, for every test
/// program that needs it. All the code is herein contained to simplify the
/// dependency chain in the build rules.
#if !defined(LUTOK_TEST_UTILS_HPP)
# define LUTOK_TEST_UTILS_HPP
#else
# error "test_utils.hpp can only be included once"
#endif
#include <atf-c++.hpp>
#include "c_gate.hpp"
#include "exceptions.hpp"
#include "state.hpp"
namespace {
/// Checks that a given expression raises a particular lutok::api_error.
///
/// We cannot make any assumptions regarding the error text provided by Lua, so
/// we resort to checking only which API function raised the error (because our
/// code is the one hardcoding these strings).
///
/// \param exp_api_function The name of the Lua C API function that causes the
/// error.
/// \param statement The statement to execute.
#define REQUIRE_API_ERROR(exp_api_function, statement) \
do { \
try { \
statement; \
ATF_FAIL("api_error not raised by " #statement); \
} catch (const lutok::api_error& api_error) { \
ATF_REQUIRE_EQ(exp_api_function, api_error.api_function()); \
} \
} while (0)
/// Gets the pointer to the internal lua_State of a state object.
///
/// This is pure syntactic sugar to simplify typing in the test cases.
///
/// \param state The Lua state.
///
/// \return The internal lua_State of the input Lua state.
static inline lua_State*
raw(lutok::state& state)
{
return lutok::state_c_gate(state).c_state();
}
/// Ensures that the Lua stack maintains its original height upon exit.
///
/// Use an instance of this class to check that a piece of code does not have
/// side-effects on the Lua stack.
///
/// To be used within a test case only.
class stack_balance_checker {
/// The Lua state.
lutok::state& _state;
/// Whether to install a sentinel on the stack for balance enforcement.
bool _with_sentinel;
/// The height of the stack on creation.
unsigned int _old_count;
public:
/// Constructs a new stack balance checker.
///
/// \param state_ The Lua state to validate.
/// \param with_sentinel_ If true, insert a sentinel item into the stack and
/// validate upon exit that the item is still there. This is an attempt
/// to ensure that already-existing items are not removed from the stack
/// by the code under test.
stack_balance_checker(lutok::state& state_,
const bool with_sentinel_ = true) :
_state(state_),
_with_sentinel(with_sentinel_),
_old_count(_state.get_top())
{
if (_with_sentinel)
_state.push_integer(987654321);
}
/// Destructor for the object.
///
/// If the stack height does not match the height when the instance was
/// created, this fails the test case.
~stack_balance_checker(void)
{
if (_with_sentinel) {
if (!_state.is_number() || _state.to_integer() != 987654321)
ATF_FAIL("Stack corrupted: sentinel not found");
_state.pop(1);
}
unsigned int new_count = _state.get_top();
if (_old_count != new_count)
//ATF_FAIL(F("Stack not balanced: before %d, after %d") %
// _old_count % new_count);
ATF_FAIL("Stack not balanced");
}
};
} // anonymous namespace