python-lua-0.6.orig/0000755000175000017500000000000014375004153013754 5ustar shevekshevekpython-lua-0.6.orig/src/0000755000175000017500000000000014375004153014543 5ustar shevekshevekpython-lua-0.6.orig/src/lua/0000755000175000017500000000000014375004153015324 5ustar shevekshevekpython-lua-0.6.orig/src/lua/python-lua.70000644000175000017500000001673014374405204017524 0ustar shevekshevek\" python-lua.7 - manual page for python-lua \" Copyright 2012-2023 Bas Wijnen \" \" This program is free software: you can redistribute it and/or modify \" it under the terms of the GNU Affero General Public License as \" published by the Free Software Foundation, either version 3 of the \" License, or (at your option) any later version. \" \" This program is distributed in the hope that it will be useful, \" but WITHOUT ANY WARRANTY; without even the implied warranty of \" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \" GNU Affero General Public License for more details. \" \" You should have received a copy of the GNU Affero General Public License \" along with this program. If not, see . .TH PYTHON-LUA 7 2023-02-19 "Python-Lua" "Python-Lua" .SH NAME python-lua \- using lua scripts from python .SH SYNOPSIS .B import lua .br .IΒ lua_handle " = lua.Lua(debug = " False ", loadlib = " False ", doloadfile = " False ", io = " False ", os = " False ", all = " False ", luaversion = " None ) .br .IB lua_handle ".run(script = " None ", var = " None ", value = " None ", name = " "python string" ) .br .IB lua_handle ".run_file(" script_file ) .br .IB lua_handle ".module(" name ", " my_module ) .br .B lua_table._dict() .br .B lua_table._list() .SH DESCRIPTION The lua module interfaces Python code to the Lua library, thus allowing Lua scripts to be run from Python. For most operations, a \fIlua.Lua\fR object must be created. This object does all the work. Creating multiple Lua objects from one Python program should work, but is mostly untested. They are supposed to be completely independent of each other; they don't even share global variables. When creating a Lua instance with \fIdebug\fR set to False (the default), it will automatically run \fIself.run(b'debug = nil')\fR, which will disable the debugging library. \fIlua.run\fR is the main entry point into lua code. It allows running a script (which may be uncompiled or compiled lua code). It can also be used to set the value of a global lua variable to any Python value. \fIscript\fR may be omitted, in which case only the assignment is performed. If \fIvar\fR is omitted, only the script is run. If both are present, the variable is assigned before the script is run. To assign a variable inside a table, you can use \fIlua_handle.run(b'table.foo = tmp', 'tmp', value)\fR. The name is used for error reporting. When using Python objects from Lua, their python operations are used when invoked. For example, the __add__ function will be called when something is added to the object in lua. This is particularly useful for functions, which can be called from lua this way. Note that passing a method to Lua works fine, but the library will raise an exception if Lua tries to call it with a different object instance. Also, the library may raise exceptions when lua scripts don't expect them, for example when referencing a nonexistent member. \fIlua.run_file\fR is similar to \fIlua.run\fR, but it takes a filename where the code is located. It does not support variable assignment, so if that is required, a call to \fIlua.run\fR should be used first. \fIlua.module\fR allows importing an object into lua as a module. This works reasonably well, but there are some limitations, see \fBBUGS\fR. Lua tables are wrapped in a Python object when they are returned. When changes are made to this Python object, the change is passed through to the lua object. In other words, Lua remains the owner of the table. Python objects (which are owned by Python) can be created from Lua code using the \fIpython\fR module. It has two members, \fIlist\fR and \fIdict\fR, which convert a table to a list and dict respectively. In addition, it has a member \fIbytes\fR, which is described in the section STRINGS below. There are two things to remember when using \fIpython.list\fR. First, Lua starts counting at 1, but Python starts at 0. A value called \fIa[3]\fR in Lua is called \fIpython.list(a)[2]\fR. Second, when using \fIpython.list\fR on a table which contains non-integer keys, those elements are not present in the returned list. In fact, the generated list only has values up to the first index that is not in the table. Note that \fInil\fR cannot be a value. Setting it will instead remove the corresponding key from the table. The table wrapper supports most Python operations. It can also be useful to copy it to a dict. This is what \fIpython.dict()\fR does. Changes made to this dict are not reflected in the lua table that it was copied from. .SH STRINGS Python makes a clear distinction between strings containing text characters, and byte strings containing binary data. Lua makes no such distinction. Because of that, this module needed to make some choices on how to map the two types between the languages. Lua strings are considered to be text by this module. What this means is that setting a variable to a Python value of type \fIstr\fR will result in a Lua string value, and a Lua string is also returned as type \fIstr\fR. It is assumed to be encoded as utf-8 in Lua. A non-utf-8 binary string in Lua will not properly transfer to Python unless special precautions are taken. On the other hand, Python \fIbytes\fR objects can be passed into Lua. They are treated as Python-owned objects. This means that they can be normally accessed, for example by indexing them. Note that because they are Python-owned, the index of the first element is 0. If bytes objects are needed to be generated by Lua, this can be done using the \fIbytes\fR function in the \fIpython\fR module. As an argument, it can take a table (which is treated as a list of bytes, each of which must be an integer), a str (which is first encoded as utf-8, so non-utf-8 sequences in it will NOT survive!) or in integer (which creates a \fIbytes\fR object of the given length, filled with zeroes). This means that it is possible to pass a binary (non-utf-8) byte string to Python, but the Lua script must first build a table of integers from it. This can be done using \fIpython.bytes(value:byte(1, #value))\fR. .SH SECURITY CONSIDERATIONS By default, lua has the ability to load any libraries from the system. Lua should not be used for scripts from untrusted sources when this is the case. On the other hand, this module is secure by default: it disables the debug library and loading of external libraries. If this functionality is needed, it must be enabled in the constructor. When \fIall\fR is set to \fITrue\fR in the constructor, all potentially insecure features are enabled. .SH BUGS For module definitions, Lua only supports plain tables, not user objects. This means that no callbacks can be added for events which happen in the top level of the module. In particular, when a Python module is used as a lua module (which is a common use case), a list is built at registration time and passed to lua. When new variables are added to the Python module, or existing variables are changed so they link to new objects, those changes will not be reflected in lua. Similarly, such changes made from lua are not visible in Python. Changing the contents of variables is not affected by this problem. As a workaround, when changing or creating such variables from Python, you can manually add them to lua as well, using \fIlua.run(var = '', value = )\fR. When using variables which may have been changed by lua, instead of using their value directly from the python module, use \fIlua.run()\fR. .SH AUTHOR Python-lua was written by \fBBas Wijnen\fR \fI\fR python-lua-0.6.orig/src/lua/__init__.py0000644000175000017500000006710114375002541017441 0ustar shevekshevek# lua.py - Use Lua in Python programs # Copyright 2012-2023 Bas Wijnen {{{ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # }}} '''Module documentation {{{ This module provides an interface between Python and Lua. Objects of the Lua class contain the state of a Lua environment. Lua instances do not share variables. Interactions of Lua objects from different environments may not work; Lua's documentation isn't clear on that. By default, the Lua constructor disables all potentially insecure features. To enable them, set the corresponding argument to True. The features are: debug: debug library Not unsafe, but this should be disabled for production code, so it should only be enabled explicitly. Jailbreak: no. System damage: no. Privacy issue: no. loadlib: package.loadlib function It can load shared libraries from the system. Jailbreak: yes. System damage: yes. Privacy issue: yes. doloadfile: dofile and loadfile functions They access files on the file system. Jailbreak: no. System damage: no. Privacy issue: yes. (Very limited; only lua source can be run.) io: file read and write module The module accesses files on the file system. Jailbreak: no. System damage: yes. Privacy issue: yes. os: the os module, except for os.clock, os.date, os.difftime, os.setlocale and os.time It allows access to the os. Jailbreak: yes. System damage: yes. Privacy issue: yes. lua = Lua() After creating a Lua instance, it can be used to run a script either from a string, or from a file. The script may be lua source, or compiled lua code. Lua().run(source) Lua().run_file(filename) A variable in the Lua environment can be given a value using: Lua().run(var = 'name', value = 'value') When using run() to both set a variable and run code, the variable is set before running the code. While it is possible to access external code from Lua by setting a variable to a function, the normal way to do it is through a module which is loaded with a require statement. For this to work, the module must first be made available to Lua. This is done using: lua.module(name, object) }}}''' # Imports. {{{ import sys import os import types import ctypes import struct import numbers import traceback from .luaconst import * # }}} # Debugging settings. {{{ _DEBUGLEVEL = os.getenv('LUA_DEBUG') if _DEBUGLEVEL: _DEBUGLEVEL = int(_DEBUGLEVEL) else: _DEBUGLEVEL = None def _dprint(text, level = 0): '''Print stuff for debugging. This function does nothing when not debugging''' # Set the following to the desired debugging level. if _DEBUGLEVEL is not None and level > _DEBUGLEVEL: sys.stderr.write(text + '\n') # }}} # Load shared library. {{{ _libraryfilename = "liblua" + os.getenv('PYTHON_LUA_VERSION', '5.4') + ".so" # TODO: use .dll for Windows. # Allow users (or the calling program) to choose their lua version. _library = ctypes.CDLL(_libraryfilename) if not hasattr(_library, 'lua_len'): _library.lua_len = _library.lua_objlen # }}} # Module for accessing some Python parts from Lua. This prepared as a "python" module unless disabled. {{{ def construct_bytes(arg): 'Implementation of python.bytes()' if isinstance(arg, Table): return bytes(arg.list()) if isinstance(arg, str): return arg.encode('utf-8') return bytes(arg) python = { 'list': lambda table: table.list(), 'dict': lambda table: table.dict(), 'bytes': construct_bytes } # }}} class Lua(object): # {{{ # Lookup machinery. {{{ _states = {} @classmethod def _lookup(cls, state): return cls._states[state.value] def __del__(self): del self._states[self._state.value] # }}} def __init__(self, debug = False, loadlib = False, searchers = False, doloadfile = False, io = False, os = False, python_module = True): # {{{ '''Create a new lua object. This object provides the interface into the lua library. It also provides access to all the symbols that lua owns.''' _library.luaL_newstate.restype = ctypes.c_void_p self._state = ctypes.c_void_p(_library.luaL_newstate()) assert self._state.value not in self._states # Load standard functions and set return types. {{{ _library.luaL_openlibs(self._state) _library.lua_tolstring.restype = ctypes.c_char_p _library.lua_tonumberx.restype = ctypes.c_double _library.lua_topointer.restype = ctypes.c_void_p _library.lua_touserdata.restype = ctypes.c_void_p _library.lua_tothread.restype = ctypes.c_void_p _library.lua_tocfunction.restype = ctypes.c_void_p _library.lua_newuserdatauv.restype = ctypes.c_void_p _library.lua_len.restype = ctypes.c_longlong # }}} # Set attributes. {{{ self._objects = {} # Store back "pointer" to self. self._states[self._state.value] = self self._push(self._state.value) _library.lua_setfield(self._state, LUA_REGISTRYINDEX, b'self') # }}} # Store operators, because the API does not define them. ops = { '+': 'add', '-': 'sub', '*': 'mul', '/': 'truediv', '%': 'mod', '^': 'pow', '//': 'floordiv', '&': 'and', '|': 'or', '~': 'xor', '<<': 'lshift', '>>': 'rshift', '..': 'matmul', '==': 'eq', '<': 'lt', '<=': 'le' } self._ops = {} # Binary operators. for op, name in ops.items(): self._ops[name] = self.run(b'return function(a, b) return a %s b end' % op.encode('utf-8'), name = 'get %s' % name) # Unary operators. self._ops['neg'] = self.run(b'return function(a) return -a end', name = 'get neg') self._ops['invert'] = self.run(b'return function(a) return ~a end', name = 'get invert') self._ops['repr'] = self.run(b'return function(a) return tostring(a) end', name = 'get repr') # TODO?: __close, __gc # Skipped: len, getitem, setitem, delitem, because they have API calls which are used. # Store a copy of table.remove and package.loaded, so they still work if the original value is replaced. self._table_remove = self.run(b'return table.remove', name = 'get table.remove') self._package_loaded = self.run(b'return package.loaded', name = 'get package.loaded') self._G = self.run(b'return _G', name = 'get _G') # Set up metatable for userdata objects. {{{ self._factory = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p) ops = ('add', 'sub', 'mul', 'div', 'mod', 'pow', 'unm', 'idiv', 'band', 'bor', 'bxor', 'bnot', 'shl', 'shr', 'concat', 'len', 'eq', 'lt', 'le', 'index', 'newindex', 'call', 'close', 'gc', 'tostring') _library.lua_createtable(self._state, 0, len(ops)) for op in ops: setattr(self, '_the_' + op, self._factory(globals()['_object_' + op])) _library.lua_pushcclosure(self._state, getattr(self, '_the_' + op), 0) _library.lua_setfield(self._state, -2, b'__' + op.encode('utf-8')) _library.lua_setfield(self._state, LUA_REGISTRYINDEX, b'metatable') # }}} # Disable optional features that have not been requested. {{{ if not debug: self.run(b'debug = nil package.loaded.debug = nil', name = 'disabling debug') if not loadlib: self.run(b'package.loadlib = nil', name = 'disabling loadlib') if not searchers: self.run(b'package.searchers = {}', name = 'disabling searchers') if not doloadfile: self.run(b'loadfile = nil dofile = nil', name = 'disabling loadfile and dofile') if not os: self.run(b'os = {clock = os.clock, date = os.date, difftime = os.difftime, setlocale = os.setlocale, time = os.time} package.loaded.os = os', name = 'disabling some of os') if not io: self.run(b'io = nil package.loaded.io = nil', name = 'disabling io') # }}} # Add access to Python object constructors from Lua (unless disabled). if python_module is not False: self.module('python', python) # }}} def run_file(self, script, keep_single = False): # {{{ _dprint('running lua file %s' % script, 1) pos = _library.lua_gettop(self._state) if _library.luaL_loadfilex(self._state, script.encode('utf-8'), None) != LUA_OK: raise ValueError(_library.lua_tolstring(self._state, 1, None).decode('utf-8')) ret = _library.lua_pcallk(self._state, 0, LUA_MULTRET, None, 0, None) if ret == 0: size = _library.lua_gettop(self._state) - pos ret = [self._to_python(-size + i) for i in range(size)] _library.lua_settop(self._state, pos) if not keep_single: if len(ret) == 0: ret = None elif len(ret) == 1: ret = ret[0] return ret else: ret = _library.lua_tolstring(self._state, 1, None).decode('utf-8') _library.lua_settop(self._state, pos) raise ValueError(ret) # }}} def run(self, script = None, var = None, value = None, name = 'python string', keep_single = False): # {{{ _dprint('running lua script %s with var %s' % (name, str(var)), 5) assert script is None or isinstance(script, (bytes, str)) assert var is None or isinstance(var, str) assert isinstance(name, str) # For convenience, allow str scripts. if isinstance(script, str): script = script.encode('utf-8') if var is not None: _library.lua_rawgeti(self._state, LUA_REGISTRYINDEX, ctypes.c_longlong(LUA_RIDX_GLOBALS)) self._push(value) # Allow str identifiers for convenience, but convert them to bytes for Lua. if isinstance(var, str): var = var.encode('utf-8') _library.lua_setfield(self._state, -2, var) _library.lua_settop(self._state, -2) if script is not None: pos = _library.lua_gettop(self._state) if _library.luaL_loadbufferx(self._state, script, len(script), name.encode('utf-8'), None) != LUA_OK: raise ValueError(_library.lua_tolstring(self._state, 1, None).decode('utf-8')) ret = _library.lua_pcallk(self._state, 0, LUA_MULTRET, None, 0, None) if ret == 0: size = _library.lua_gettop(self._state) - pos ret = [self._to_python(-size + i) for i in range(size)] _library.lua_settop(self._state, pos) if not keep_single: if len(ret) == 0: ret = None elif len(ret) == 1: ret = ret[0] return ret else: ret = _library.lua_tolstring(self._state, -1, None) _library.lua_settop(self._state, pos) raise ValueError(ret.decode('utf-8')) # }}} def module(self, name, value): # {{{ _dprint('creating lua module %s' % name, 5) if not isinstance(value, (list, dict)): # module object must be a table, so convert the object to a table. module = {} for key in dir(value): # Keys must be str in Python, but they need to be bytes for Lua. assert isinstance(key, str) k = key.encode('utf-8') if k.startswith(b'_'): if k.startswith(b'_lua'): k = b'_' + k[4:] else: continue module[k] = getattr(value, key) value = module self._push(self._package_loaded) _dprint('package loaded %s' % repr(self._package_loaded.dict(True)), 1) self._push_luatable(value) n = name.encode('utf-8') #self._dump_lua_stack() #self._dump_lua_registry() _dprint('setting name to %s' % repr(n), 1) _library.lua_setfield(self._state, -2, n) _dprint('resetting top', 1) _library.lua_settop(self._state, -2) # }}} def _to_python(self, index, allow_unknown = False): # {{{ _dprint('creating python value from lua at %d' % index, 1) type = _library.lua_type(self._state, index) if type == LUA_TNIL: return None elif type == LUA_TBOOLEAN: return bool(_library.lua_toboolean(self._state, index)) elif type == LUA_TLIGHTUSERDATA: return _library.lua_touserdata(self._state, index) elif type == LUA_TNUMBER: ret = _library.lua_tonumberx(self._state, index, None) if int(ret) == ret: return int(ret) return ret elif type == LUA_TSTRING: return _library.lua_tolstring(self._state, index, None).decode('utf-8') elif type == LUA_TTABLE: _dprint('creating table', 1) _library.lua_pushvalue(self._state, index) return Table(self) elif type == LUA_TFUNCTION: _library.lua_pushvalue(self._state, index) return Function(self) elif type == LUA_TUSERDATA: id = _library.lua_touserdata(self._state, index) return self._objects[id] elif type == LUA_TTHREAD: return _library.lua_tothread(self._state, index) elif _library.lua_iscfunction(self._state, index): return _library.lua_tocfunction(self._state, index) elif allow_unknown: return '(Unknown type %x)' % type else: raise AssertionError('unexpected lua type %d' % type) # }}} def _push(self, obj): # {{{ _dprint('pushing %s (%s) to lua stack' % (str(obj), type(obj)), 1) if obj is None: _library.lua_pushnil(self._state) elif isinstance(obj, bool): _library.lua_pushboolean(self._state, obj) elif isinstance(obj, int): _library.lua_pushinteger(self._state, ctypes.c_longlong(obj)) elif isinstance(obj, str): # A str is encoded as bytes in Lua; bytes is wrapped as an object. obj = obj.encode('utf-8') _library.lua_pushlstring(self._state, obj, len(obj)) elif isinstance(obj, float): _library.lua_pushnumber(self._state, ctypes.c_double(obj)) elif isinstance(obj, (Function, Table)): _dprint('pushing table %s %d %d' % (obj._id, self._state.value, LUA_REGISTRYINDEX), 1) _library.lua_rawgeti(self._state, LUA_REGISTRYINDEX, ctypes.c_longlong(obj._id)) elif isinstance(obj, object): id = _library.lua_newuserdatauv(self._state, 1, 1) self._objects[id] = obj _library.lua_getfield(self._state, LUA_REGISTRYINDEX, b'metatable') _library.lua_setmetatable(self._state, -2) else: # This shouldn't be possible: everything is an object. raise ValueError('object of type %s cannot be converted to lua object' % str(type(obj))) _dprint('done pushing', 1) # }}} def _push_luatable(self, table): # {{{ '''Push a real lua table to the stack; not a userdata emulating a table. Table must be a list or dict''' _dprint('pushing lua table', 1) if isinstance(table, dict): _library.lua_createtable(self._state, 0, len(table)) # Pushes new table on the stack. for i in table: self._push(i) self._push(table[i]) _library.lua_settable(self._state, -3) # Pops key and value from the stack. else: _library.lua_createtable(self._state, len(table), 0) # Pushes new table on the stack. for i, v in enumerate(table): self._push(table[i]) _library.lua_rawseti(self._state, -2, ctypes.c_longlong(i + 1)) # Pops the value from the stack. _dprint('done pushing lua table', 1) # }}} def make_table(self, data = ()): # {{{ return Table(self, data) # }}} def _dump_lua_stack(self): # {{{ Dump lua stack to stderr. 'Dump the lua stack to stderr' num = _library.lua_gettop(self._state) print('Current Lua Stack:', file = sys.stderr) for i in range(num): value = self._to_python(i + 1, True) print(' %d\t%s\t%s' % (i + 1, type(value), repr(value)), file = sys.stderr) print('Top Of Stack', file = sys.stderr) # }}} def _dump_lua_registry(self): # {{{ Dump lua registry to stderr. 'Dump the lua registry to stderr' self._push(self._G) _library.lua_pushnil(self._state) print('Current Lua Registry:', file = sys.stderr) while _library.lua_next(self._state, -2) != 0: key = self._to_python(-2, True) value = self._to_python(-1, True) print('\t%s\t%s\t%s' % (repr(key), type(value), repr(value)), file = sys.stderr) _library.lua_settop(self._state, -2) print('End of Registry:', file = sys.stderr) _library.lua_settop(self._state, -2) # }}} # }}} # Operator definitions for using Python objects from Lua. {{{ def _op1(fn): def ret(state): self = Lua._lookup(ctypes.c_void_p(state)) try: A = self._to_python(1) self._push(fn(A)) except: _library.lua_settop(ctypes.c_void_p(state), 0) self._push(str(sys.exc_info()[1])) _library.lua_error(ctypes.c_void_p(state)) return 1 return ret def _op2(fn): def ret(state): self = Lua._lookup(ctypes.c_void_p(state)) try: A = self._to_python(1) B = self._to_python(2) self._push(fn(A, B)) except: _library.lua_settop(ctypes.c_void_p(state), 0) self._push(str(sys.exc_info()[1])) _library.lua_error(ctypes.c_void_p(state)) return 1 return ret @_op2 def _object_add(A, B): # + {{{ _dprint('adding lua stuff', 1) return A + B # }}} @_op2 def _object_sub(A, B): # + {{{ _dprint('subbing lua stuff', 1) return A - B # }}} @_op2 def _object_mul(A, B): # + {{{ _dprint('mulling lua stuff', 1) return A * B # }}} @_op2 def _object_div(A, B): # + {{{ _dprint('diving lua stuff', 1) return A / B # }}} @_op2 def _object_mod(A, B): # + {{{ _dprint('modding lua stuff', 1) return A % B # }}} @_op2 def _object_pow(A, B): # + {{{ _dprint('powing lua stuff', 1) return A ** B # }}} @_op1 def _object_unm(A): # + {{{ _dprint('unming lua stuff', 1) return -A # }}} @_op2 def _object_idiv(A, B): # + {{{ _dprint('idiving lua stuff', 1) return A // B # }}} @_op2 def _object_band(A, B): # + {{{ _dprint('banding lua stuff', 1) return A & B # }}} @_op2 def _object_bor(A, B): # + {{{ _dprint('powing lua stuff', 1) return A | B # }}} @_op2 def _object_bxor(A, B): # + {{{ _dprint('bxoring lua stuff', 1) return A ^ B # }}} @_op1 def _object_bnot(A): # + {{{ _dprint('bnotting lua stuff', 1) return ~A # }}} @_op2 def _object_shl(A, B): # + {{{ _dprint('shling lua stuff', 1) return A << B # }}} @_op2 def _object_shr(A, B): # + {{{ _dprint('shring lua stuff', 1) return A >> B # }}} @_op2 def _object_concat(A, B): # + {{{ _dprint('concatting lua stuff', 1) # @ is matrix multiplication, but no other operator is available, so (ab)use it for concat. return A @ B # }}} @_op1 def _object_len(A): # + {{{ _dprint('lenning lua stuff', 1) return len(A) # }}} @_op2 def _object_eq(A, B): # + {{{ _dprint('eqing lua stuff', 1) return A == B # }}} @_op2 def _object_lt(A, B): # + {{{ _dprint('neing lua stuff', 1) return A < B # }}} @_op2 def _object_le(A, B): # + {{{ _dprint('leing lua stuff', 1) return A <= B # }}} def _object_index(state): # [] (rvalue) {{{ _dprint('indexing lua stuff', 1) self = Lua._lookup(ctypes.c_void_p(state)) A = self._to_python(1) B = self._to_python(2) _dprint('trying to index %s[%s]' % (str(A), str(B)), 2) if isinstance(B, str): if B.startswith('_'): B = '_lua' + B[1:] elif isinstance(B, bytes): if B.startswith(b'_'): B = b'_lua' + B[1:] try: value = A[B] self._push(value) return 1 except: sys.stderr.write("Trying to index nonexistent %s[%s], returning nil.\n" % (str(A), str(B))) self._push(None) return 1 # }}} def _object_newindex(state): # [] (lvalue) {{{ _dprint('newindexing lua stuff', 1) self = Lua._lookup(ctypes.c_void_p(state)) table = self._to_python(1) key = self._to_python(2) value = self._to_python(3) try: if isinstance(key, str): if key.startswith('_'): key = '_lua' + key[1:] table[key] = value _dprint('set %s[%s] = %s' % (str(table), str(key), str(value)), 3) return 0 except: sys.stderr.write('error trying to newindex %s[%s] = %s: %s\n' % (str(table), str(key), str(value), sys.exc_info()[1])) _library.lua_settop(ctypes.c_void_p(state), 0) self._push(str(sys.exc_info()[1])) _library.lua_error(ctypes.c_void_p(state)) # }}} def _object_call(state): # () {{{ _dprint('calling lua stuff', 1) self = Lua._lookup(ctypes.c_void_p(state)) obj = self._to_python(1) num = _library.lua_gettop(ctypes.c_void_p(state)) - 1 args = [self._to_python(i + 2) for i in range(num)] # Don't bother the user with two self arguments. if isinstance(obj, types.MethodType): assert obj.im_self is args[0] args = args[1:] try: ret = obj(*args) _library.lua_settop(ctypes.c_void_p(state), 0) if isinstance(ret, tuple): for i in ret: self._push(i) return len(ret) else: self._push(ret) return 1 except: sys.stderr.write('Error: %s\n' % sys.exc_info()[1]) bt = sys.exc_info()[2] while bt: sys.stderr.write('\t%s:%d %s\n' % (bt.tb_frame.f_code.co_filename, bt.tb_lineno, bt.tb_frame.f_code.co_name)) bt = bt.tb_next _library.lua_settop(ctypes.c_void_p(state), 0) self._push(str(sys.exc_info()[1])) _library.lua_error(ctypes.c_void_p(state)) # lua_error does not return. # }}} def _object_close(state): # {{{ _dprint('closing lua stuff', 0) self = Lua._lookup(ctypes.c_void_p(state)) id = _library.lua_touserdata(ctypes.c_void_p(state), 1) arg = self._to_python(-1) self._objects[id].__close__(arg) return 0 # }}} def _object_gc(state): # {{{ _dprint('cleaning lua stuff', 1) self = Lua._lookup(ctypes.c_void_p(state)) id = _library.lua_touserdata(ctypes.c_void_p(state), 1) del self._objects[id] return 0 # }}} def _object_tostring(state): # {{{ _dprint('tostringing lua stuff', 1) self = Lua._lookup(ctypes.c_void_p(state)) A = self._to_python(1) self._push(str(A)) return 1 # }}} # }}} class Function: # Using Lua functions from Python. {{{ '''Python interface to a lua function. The function is defined and owned by lua; this class makes it callable from Python.''' def __init__(self, lua): # {{{ '''Create Python handle for Lua function. The function must have been pushed to the Lua stack before calling this.''' _dprint('creating lua function', 1) self._lua = lua self._id = _library.luaL_ref(self._lua._state, LUA_REGISTRYINDEX) # }}} def __call__(self, *args, **kwargs): # {{{ _dprint('calling lua function', 3) if 'keep_single' in kwargs: keep_single = kwargs.pop('keep_single') else: keep_single = False assert len(kwargs) == 0 pos = _library.lua_gettop(self._lua._state) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) for arg in args: self._lua._push(arg) if _library.lua_pcallk(self._lua._state, len(args), LUA_MULTRET, None, 0, None) != LUA_OK: msg = _library.lua_tolstring(self._lua._state, 1, None) sys.stderr.write('Error from lua: ' + msg.decode('utf-8') + '\n') raise ValueError('Error from lua: ' + msg.decode('utf-8')) size = _library.lua_gettop(self._lua._state) - pos ret = [self._lua._to_python(-size + i) for i in range(size)] if not keep_single: if len(ret) == 0: ret = None elif len(ret) == 1: ret = ret[0] _library.lua_settop(self._lua._state, pos) return ret # }}} def __del__(self): # {{{ _dprint('destroying lua function %s' % self._id, 1) _library.luaL_unref(self._lua._state, LUA_REGISTRYINDEX, self._id) # }}} # }}} class Table: # Using Lua tables from Python. {{{ '''Python interface to access a lua table. The table is owned by lua; this class only provides a view to it.''' def __init__(self, lua, table = None): # {{{ '''Create Python handle for Lua table. If the table is not given as an arugment, it must be pushed to the stack before calling this.''' _dprint('creating lua table', 1) self._lua = lua if table is not None: self._lua._push_luatable(table) self._id = _library.luaL_ref(self._lua._state, LUA_REGISTRYINDEX) for name, impl in self._lua._ops.items(): setattr(self, '__' + name + '__', impl) # }}} def __len__(self): # {{{ _dprint('requesting length of lua table', 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_len(self._lua._state, -1) ret = self._lua._to_python(-1) _library.lua_settop(self._lua._state, -3) return ret # }}} def __iadd__(self, other): # {{{ _dprint('adding objects to lua table', 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_len(self._lua._state, -1) length = self._lua._to_python(-1) _library.lua_settop(self._lua._state, -2) for item in other: self._lua._push(item) _library.lua_seti(self._lua._state, -2, ctypes.c_longlong(length + 1)) length += 1 _library.lua_settop(self._lua._state, -2) return self # }}} def __getitem__(self, key): # {{{ _dprint('requesting item of lua table: %s' % key, 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) self._lua._push(key) _library.lua_gettable(self._lua._state, -2) ret = self._lua._to_python(-1) _library.lua_settop(self._lua._state, -3) if ret is None: raise IndexError('Key %s does not exist in Lua table' % key) return ret # }}} def __setitem__(self, key, value): # {{{ _dprint('setting item of lua table: %s: %s' % (key, value), 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) self._lua._push(key) self._lua._push(value) _library.lua_settable(self._lua._state, -3) _library.lua_settop(self._lua._state, -2) # }}} def __delitem__(self, key): # {{{ _dprint('deleting item of lua table: %s' % key, 3) # Raise IndexError if key doesn't exist: use getitem. self[key] self[key] = None # }}} def __contains__(self, key): # {{{ _dprint('checking if %s is in lua table' % key, 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_pushnil(self._lua._state) while _library.lua_next(self._lua._state, -2) != 0: if self._lua._to_python(-2) == key: _library.lua_settop(self._lua._state, -4) return True _library.lua_settop(self._lua._state, -2) _library.lua_settop(self._lua._state, -2) return False # }}} def __iter__(self): # {{{ _dprint('iterating over lua table', 3) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_pushnil(self._lua._state) while _library.lua_next(self._lua._state, -2) != 0: ret = self._lua._to_python(-2) _library.lua_settop(self._lua._state, -2) ref = _library.luaL_ref(self._lua._state, LUA_REGISTRYINDEX) try: _library.lua_settop(self._lua._state, -2) yield ret _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(ref)) finally: _library.luaL_unref(self._lua._state, LUA_REGISTRYINDEX, ref) _library.lua_settop(self._lua._state, -2) # }}} def __del__(self): # {{{ _dprint('destroying lua table %s' % self._id, 1) _library.luaL_unref(self._lua._state, LUA_REGISTRYINDEX, self._id) # }}} def __ne__(self, other): # {{{ return not self == other # }}} def __gt__(self, other): # {{{ return self._lua._ops['lt'](other, self) # }}} def __ge__(self, other): # {{{ return self._lua._ops['le'](other, self) # }}} def dict(self, allow_unknown = False): # {{{ 'Get a copy of the table as a dict' _dprint('get dict from lua table %s' % self._id, 1) ret = {} _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_pushnil(self._lua._state) while _library.lua_next(self._lua._state, -2) != 0: ret[self._lua._to_python(-2, allow_unknown)] = self._lua._to_python(-1, allow_unknown) _library.lua_settop(self._lua._state, -2) _library.lua_settop(self._lua._state, -2) return ret # }}} def list(self): # {{{ 'Get a copy of the table, which must be a sequence, as a list. note that table[1] becomes list[0].' _dprint('get list from lua table %s' % self._id, 1) _library.lua_rawgeti(self._lua._state, LUA_REGISTRYINDEX, ctypes.c_longlong(self._id)) _library.lua_len(self._lua._state, -1) length = self._lua._to_python(-1) _library.lua_settop(self._lua._state, -2) ret = [None] * length for i in range(1, length + 1): _library.lua_rawgeti(self._lua._state, -1, ctypes.c_longlong(i)) ret[i - 1] = self._lua._to_python(-1) _library.lua_settop(self._lua._state, -2) _library.lua_settop(self._lua._state, -2) return ret # }}} def pop(self, index = -1): # {{{ '''Like list.pop''' _dprint('popping item %d of lua table.' % index, 3) if isinstance(index, int) and index < 0: index += len(self) return self._lua._table_remove(self, index) # }}} # }}} # vim: set foldmethod=marker : python-lua-0.6.orig/setup.cfg0000644000175000017500000000154314375003742015603 0ustar shevekshevek[metadata] name = lua-wrapper version = 0.6 author = Bas Wijnen author_email = wijnen@debian.org description = module for using Lua in Python programs long_description = file:README.md long_description_content_type = text/markdown license = AGPL3+ license_files = debian/copyright url = https://github.com/wijnen/python-lua project_urls = Bug Tracker = https://github.com/wijnen/python-lua/issues classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+) Intended Audience :: Developers Development Status :: 4 - Beta Operating System :: OS Independent include_package_data = True [options] package_dir = =src packages = find: python_requires = >=3 [options.packages.find] where = src [options.package_data] * = python-lua.7 python-lua-0.6.orig/mkconst.c0000644000175000017500000000524014366776604015620 0ustar shevekshevek// mkconst.c: Create helper file for giving python module access to lua constants. /* Copyright 2012-2023 Bas Wijnen {{{ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * }}} */ #include #include int main(int argc, char **argv) { (void)&argc; (void)&argv; printf("LUA_MULTRET = %d\n", LUA_MULTRET); printf("LUA_REGISTRYINDEX = %d\n", LUA_REGISTRYINDEX); printf("LUA_RIDX_GLOBALS = %d\n", LUA_RIDX_GLOBALS); printf("LUA_RIDX_MAINTHREAD = %d\n", LUA_RIDX_MAINTHREAD); printf("LUA_OK = %d\n", LUA_OK); printf("LUA_YIELD = %d\n", LUA_YIELD); printf("LUA_ERRRUN = %d\n", LUA_ERRRUN); printf("LUA_ERRSYNTAX = %d\n", LUA_ERRSYNTAX); printf("LUA_ERRMEM = %d\n", LUA_ERRMEM); printf("LUA_ERRERR = %d\n", LUA_ERRERR); printf("LUA_TNONE = %d\n", LUA_TNONE); printf("LUA_TNIL = %d\n", LUA_TNIL); printf("LUA_TBOOLEAN = %d\n", LUA_TBOOLEAN); printf("LUA_TLIGHTUSERDATA = %d\n", LUA_TLIGHTUSERDATA); printf("LUA_TNUMBER = %d\n", LUA_TNUMBER); printf("LUA_TSTRING = %d\n", LUA_TSTRING); printf("LUA_TTABLE = %d\n", LUA_TTABLE); printf("LUA_TFUNCTION = %d\n", LUA_TFUNCTION); printf("LUA_TUSERDATA = %d\n", LUA_TUSERDATA); printf("LUA_TTHREAD = %d\n", LUA_TTHREAD); printf("LUA_MINSTACK = %d\n", LUA_MINSTACK); printf("LUA_GCSTOP = %d\n", LUA_GCSTOP); printf("LUA_GCRESTART = %d\n", LUA_GCRESTART); printf("LUA_GCCOLLECT = %d\n", LUA_GCCOLLECT); printf("LUA_GCCOUNT = %d\n", LUA_GCCOUNT); printf("LUA_GCCOUNTB = %d\n", LUA_GCCOUNTB); printf("LUA_GCSTEP = %d\n", LUA_GCSTEP); printf("LUA_GCSETPAUSE = %d\n", LUA_GCSETPAUSE); printf("LUA_GCSETSTEPMUL = %d\n", LUA_GCSETSTEPMUL); printf("LUA_HOOKCALL = %d\n", LUA_HOOKCALL); printf("LUA_HOOKRET = %d\n", LUA_HOOKRET); printf("LUA_HOOKLINE = %d\n", LUA_HOOKLINE); printf("LUA_HOOKCOUNT = %d\n", LUA_HOOKCOUNT); printf("LUA_HOOKTAILCALL = %d\n", LUA_HOOKTAILCALL); printf("LUA_MASKCALL = %d\n", LUA_MASKCALL); printf("LUA_MASKRET = %d\n", LUA_MASKRET); printf("LUA_MASKLINE = %d\n", LUA_MASKLINE); printf("LUA_MASKCOUNT = %d\n", LUA_MASKCOUNT); return 0; } // vim: set foldmethod=marker : python-lua-0.6.orig/test.py0000755000175000017500000000067314374771331015326 0ustar shevekshevek#!/usr/bin/python3 import ctypes f='liblua5.4.so' l=ctypes.CDLL(f) l.lua_tolstring.restype = ctypes.c_char_p s = ctypes.c_void_p(l.luaL_newstate()) l.luaL_openlibs(s) script = b'return package.loaded' l.luaL_loadbufferx(s, script, len(script), b'test', None) l.lua_pcallk(s, 0, -1, None, 0, None) l.lua_pushnil(s) while l.lua_next(s, -2) != 0: print(l.lua_type(s, -2), l.lua_type(s, -1), l.lua_tolstring(s, -2, None)) l.lua_settop(s, -2) python-lua-0.6.orig/README.md0000644000175000017500000002632014367000635015240 0ustar shevekshevekThis module allows Lua code to be used in Python programs. The interface allows passing Python objects into the Lua environment and using Lua objects in the Python program. # Simple Example ```Python # Setup. import lua code = lua.Lua() code.run('python = require("python")') # If you want to use it. # Define a Python function. def pyfun(arg): print('Python function called with arg %s' % arg) # Define a Lua function. code.run('function luafun(arg) print("Lua function called with arg " .. arg) end') # Make the Lua function accessible to Python (this could have been done in one step). luafun = code.run('return luafun') # Make the Python function accessible to Lua. code.run(var = 'pyfun', value = pyfun) # Run the Lua function from Python. luafun('from Python') # Run the Python function from Lua. code.run('pyfun("from Lua")') # Create Python compound objects from Lua. print(type(code.run('return {1, 2, 3}'))) # Lua table (not a Python object) print(type(code.run('return python.list{1,2,3}'))) # Python list print(type(code.run('return python.dict{foo = "bar"}'))) # Python dict ``` This generates the following output: ``` Lua function called with arg from Python Python function called with arg from Lua ``` # API description The module API is described below. Note that due to limited time available, this may not be kept entirely up to date. If things don't seem to work as described here, please check the source code. ## Module Loading At the time of this writing, when the module is imported it will load Lua version 5.4. This can be adjusted using the environment variable `PYTHON_LUA_VERSION`, which should be set to the version (`'5.4'` is the default). This means that a program which requires a specific Lua version should set this variable before importing the module, even if it is 5.4, to make sure the correct version is loaded. Not doing so will allow the user to try different versions. ```Python # Optional. If this is used, it must come before importing lua. import os os.environ['PYTHON_LUA_VERSION'] = '5.4' # Import Lua module. import lua ``` ## Creating a Lua instance To use the module, an instance of the Lua class must be created. Creating multiple instances of this class allows you to have completely separate environments, which do not share any state with each other. Note that combining variables from different instances in one command results in undefined behavior. When creating an instance, the default is to disable all Lua features that are a risk for security or user privacy. Each of these features can be enabled by setting the corresponding constructor parameter to True. The features are: - debug: enable the debugging library. Not actually unsafe (probably?), but should only be enabled explicitly. - loadlib: enable the loadlib function. Allows running code on host system and thus cause damage and violate privacy. - searchers: enable the default contents of package.searchers. This allows loading lua modules using require. When disabled, only standard modules and modules that have been explicitly provided by the host can be accessed. - doloadfile: enable the dofile and loadfile functions. Allows running lua code from external files. Should not pose risks to the system, but does contain a privacy risk, because lua can find out what other lua files are available on the system. Users should also normally expect that an embedded language cannot access external files, so disabling it follows the Principle of Least Astonishment. - io: enable the io library. This library allows arbitrary file access on the host system and should only be enabled for trusted Lua code. - os: enable all of the os module. Even when not enabled, `clock`, `date`, `difftime`, `setlocale` and `time` are still available. The rest of os allows running executables on the host system. This should only be enabled for trusted Lua code. Additionally, the 'python' module, which contains list and dict constructors, can be disabled by setting it to False. It is enabled by default. Note that this setting does not create the `python` variable; it only allows lua code to `require` it. An example instance that allows access of the host filesystem through `io` is: ```Python code = lua.Lua(io = True) ``` ## Setting up the Lua environment Lua code will usually require access to some variables or functions from Python. There are two methods for granting this access: setting variables, and providing modules. ### Setting variables To set a Lua variable to a Python value, the run() method is used. This method is primarily intended for running Lua code (as described below), but it also serves to set a variable to a value. If a variable is set to a value and code to run is provided in the same call, the variable will be set before the code is run, so it has access to it. If the variable is mutable (for example, it is a `list`), then changing the contents of the value will result in a changed value in Python. In other words, mutable variables are passed by reference and remain owned by Python. ```Python my_list = [1, 2, 3] code.run('foo[2] = "bar"', var = 'foo', value = my_list) # my_list is now [1, 'bar', 3]. Note that lua-indexing is 1-based. ``` ### Providing modules The more common way to provide access to host functionality is through a module that can be loaded using the `require` function in Lua. This is done by calling the `module` function. The argument is a dict, or a Python module. The contents of the argument are provided to Lua. Note that the object itself is not, so if new items are added to the dict, these changes will not show up in Lua. Changes to the _values_ of the items will show up, however. ```Python import my_custom_module code.module(my_custom_module) code.run('mod = require "my_custom_module"; mod.custom_function()') ``` ## Running Lua code There are two ways to run Lua code. Using the `run()` function demonstrated in the previous section, and using the `run_file()` function. The `run_file()` function works very similar to `run()`. There are two differences: 1. The parameter of `run_file` is a file name, for `run()` it is Lua code. 1. `run()` allows setting a variable to a Python value. `run_file()` does not. The intent of both functions is slightly different: `run()` is meant to be used mostly for situations where `eval` might have been used if it was Python code; `run_file()` is meant to be used when `exec` is more appropriate. In other words, `run()` would be used for a short computation, while `run_file()` would be more likely to be used for running a potentially large chunk of code. Because of this, it is convenient for `run()` to pass a Python value, or perhaps a list or dict, to be used directly, while `run_file()` will normally need much more, and the `module()` function will be used to provide it in a more elegant way. However, while this is the consideration behind the functions, there is nothing to enforce it. If you want to run large amounts of code with `run()`, or a single line computation with `run_file()`, it will work without any problems. ### Return values Both `run()` and `run_file()` can return a value. This is the primary method for accessing Lua values from Python. (The other option is to provide a container from Python and injecting a value from Lua.) Because Lua functions can return multiple values, this leads to a usability issue: the return value could always be a sequence, but that is invonvenient for the usual case when zero or one value is returned. This is solved by converting the result in those cases: - When 0 values are returned, the functions return None instead. - When 1 value is returned, the functions return that value. - When 2 or more values are returned, the functions return a list of return values. This means that Python cannot see the difference between returning 0 values, and returning 1 value which is `nil`, or between multiple values and a single list. Normally this will not be a problem, but if this is important to the Python program, it can pass the parameter `keep_single = True`. In that case the returned value is always a list of values, even if it has 0 or 1 elements. ## Operators Most Python operators have obvious behavior when applied to Lua objects and vice versa. For example, when using `*` the objects will be multiplied. However, there are some exceptions. 1. In Lua there is a difference between adding numbers (which is done with `+`) and strings (which is done with `..`). Unfortunately there is no appropriate operator available in Python, so `..` has been mapped to `@`, the matrix multiplication operator. This means that running `lua_table @ python_object` from Python will call the `__concat` method in `lua_table`'s metatable, and that running `python_object .. lua_object` from Lua will call the `__matmul__` method on `python_object`. Note that this does not apply to simple objects like numbers and strings, because these are converted into native objects on both sides (so a Lua string that is passed to Python becomes a Python `str` object, and using the @ operator on that does not involve Lua). 1. Lua uses the `__close` metatable method for to-be-closed variables. Python does not have this concept. The module will call the `__close__` method (which despite its name, does not have a special meaning in Python) on the Python object when the underlying Lua object is closed by Lua. ## Using Lua tables from Python code In addition to all the obvious operators (including `@` as concat) working normally on Lua tables, there are a few extra members defined on them. Note that attributes cannot be used to access table contents, so `luatable.foo` does not work, but `luatable['foo']` does. - `luatable.dict()`: Converts the table to a Python dict, containing all items. - `luatable.list()`: Converts the table to a Python list. Only the values with integer keys are inserted, and the list stops at the first missing element. In other words, this is only useful for lists that don't contain nil "values". Also note that the indexing changes: luatable[1] is the first element, and it is the same as luatable.list()[0]. - `luatable.pop(index = -1)`: Removes the last index (or the given index) from the table and shifts the contents of the table to fill its place using `table.remove`. The index must be an integer. If it is negative, the length of the table is added to it. - `code.make_table(data = ())`: Create a Lua table from the given data and return it as a Python object. The object is created in and owned by Lua. The first element in the sequence will have index 1 in the table. ## First elements Because there is a difference between the index of the first element of a list in Python (0) and that of a table in Lua (1), indexing such structures from the other language can be confusing. The module does not account for this. What this means is that you must be aware of which language owns the object. When indexing a Lua table from Python code, the first index is 1, just like in Lua. When indexing a Python list from Lua, the first index is 0, just like in Python. Here's an example to show this: ```Python python_list = ['zero', 'one', 'two'] lua_table = code.run('return {"one", "two", "three"}') code.run('print("element 2 in the python list is two: " .. list[2])', var = 'list', value = python_list) print('element 2 in the lua table is "two":', lua_table[2]) ``` python-lua-0.6.orig/pyproject.toml0000644000175000017500000000012514252035332016663 0ustar shevekshevek[build-system] requires = ['setuptools>=42'] build-backend = 'setuptools.build_meta' python-lua-0.6.orig/Makefile0000644000175000017500000000177414366776416015447 0ustar shevekshevek# Makefile for building constants file needed by module. # Copyright 2012-2023 Bas Wijnen {{{ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # }}} all: src/lua/luaconst.py src/lua/luaconst.py: mkconst Makefile ./$< > $@ mkconst: mkconst.c Makefile gcc -Wall -Werror -Wextra `pkg-config --cflags lua5.4` $< -o $@ clean: rm -f src/lua/luaconst.py mkconst # vim: set foldmethod=marker : python-lua-0.6.orig/.gitignore0000644000175000017500000000007314255276741015757 0ustar shevekshevek__pycache__ *.egg-info dist /mkconst /src/lua/luaconst.py