Adapt to python 3.3
This commit is contained in:
parent
a275068193
commit
45e70333fd
43 changed files with 251 additions and 188 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#include <python3adapt.h>
|
||||||
#include <capsulethunk.h>
|
#include <capsulethunk.h>
|
||||||
#include <llvm_binding/capsule_context.h>
|
#include <llvm_binding/capsule_context.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ def _capsule_weakref_dtor(item):
|
||||||
class Capsule(object):
|
class Capsule(object):
|
||||||
"Wraps PyCapsule so that we can build weakref of it."
|
"Wraps PyCapsule so that we can build weakref of it."
|
||||||
|
|
||||||
from _capsule import check, getClassName, getName, getPointer
|
from ._capsule import check, getClassName, getName, getPointer
|
||||||
|
|
||||||
def __init__(self, capsule):
|
def __init__(self, capsule):
|
||||||
assert Capsule.valid(capsule)
|
assert Capsule.valid(capsule)
|
||||||
|
|
@ -75,6 +75,9 @@ class Capsule(object):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return super(Capsule, self).__hash__()
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not (self == other)
|
return not (self == other)
|
||||||
|
|
||||||
|
|
@ -122,7 +125,7 @@ def wrap(cap, owned=False):
|
||||||
'''
|
'''
|
||||||
if not Capsule.valid(cap):
|
if not Capsule.valid(cap):
|
||||||
if isinstance(cap, list):
|
if isinstance(cap, list):
|
||||||
return map(wrap, cap)
|
return list(map(wrap, cap))
|
||||||
return cap # bypass if cap is not a PyCapsule and not a list
|
return cap # bypass if cap is not a PyCapsule and not a list
|
||||||
|
|
||||||
cap = Capsule(cap)
|
cap = Capsule(cap)
|
||||||
|
|
@ -170,6 +173,9 @@ class Wrapper(object):
|
||||||
def _ptr(self):
|
def _ptr(self):
|
||||||
return self._capsule.capsule
|
return self._capsule.capsule
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return super(Wrapper, self).__hash__()
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self._capsule == other._capsule
|
return self._capsule == other._capsule
|
||||||
|
|
||||||
|
|
@ -184,7 +190,7 @@ class Wrapper(object):
|
||||||
return hasattr(cls, '_delete_')
|
return hasattr(cls, '_delete_')
|
||||||
|
|
||||||
def downcast(obj, cls):
|
def downcast(obj, cls):
|
||||||
import _api
|
from . import _api
|
||||||
if type(obj) is cls:
|
if type(obj) is cls:
|
||||||
return obj
|
return obj
|
||||||
fromty = obj._llvm_type_
|
fromty = obj._llvm_type_
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from llvmpy import _api
|
||||||
def _wrapper(func):
|
def _wrapper(func):
|
||||||
"Wrap the re-exported functions"
|
"Wrap the re-exported functions"
|
||||||
def _core(*args):
|
def _core(*args):
|
||||||
unwrapped = map(capsule.unwrap, args)
|
unwrapped = list(map(capsule.unwrap, args))
|
||||||
ret = func(*unwrapped)
|
ret = func(*unwrapped)
|
||||||
return capsule.wrap(ret)
|
return capsule.wrap(ret)
|
||||||
return _core
|
return _core
|
||||||
|
|
|
||||||
|
|
@ -348,7 +348,7 @@ class Enum(object):
|
||||||
def __init__(self, *value_names):
|
def __init__(self, *value_names):
|
||||||
self.parent = None
|
self.parent = None
|
||||||
if len(value_names) == 1:
|
if len(value_names) == 1:
|
||||||
value_names = filter(bool, value_names[0].replace(',', ' ').split())
|
value_names = list(filter(bool, value_names[0].replace(',', ' ').split()))
|
||||||
self.value_names = value_names
|
self.value_names = value_names
|
||||||
self.includes = set()
|
self.includes = set()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ class PyCodeWriter(CodeWriterBase):
|
||||||
|
|
||||||
def unwrap_many(self, args):
|
def unwrap_many(self, args):
|
||||||
unwrapped = self.new_symbol('unwrapped')
|
unwrapped = self.new_symbol('unwrapped')
|
||||||
self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals())
|
self.println('%(unwrapped)s = list(map(capsule.unwrap, %(args)s))' % locals())
|
||||||
return unwrapped
|
return unwrapped
|
||||||
|
|
||||||
def unwrap(self, val):
|
def unwrap(self, val):
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ def populate_headers(println):
|
||||||
includes = [
|
includes = [
|
||||||
'cstring',
|
'cstring',
|
||||||
'Python.h',
|
'Python.h',
|
||||||
|
'python3adapt.h',
|
||||||
'capsulethunk.h',
|
'capsulethunk.h',
|
||||||
'llvm_binding/conversion.h',
|
'llvm_binding/conversion.h',
|
||||||
'llvm_binding/binding.h',
|
'llvm_binding/binding.h',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,29 @@
|
||||||
|
|
||||||
// python object unwrapper
|
// python object unwrapper
|
||||||
|
|
||||||
|
static
|
||||||
|
int py_bytes_to(PyObject *bytesobj, llvm::StringRef &strref){
|
||||||
|
// type check
|
||||||
|
if (!PyBytes_Check(bytesobj)) {
|
||||||
|
// raises TypeError
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Expecting a str");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// get len and buffer
|
||||||
|
const Py_ssize_t len = PyBytes_Size(bytesobj);
|
||||||
|
const char * buf = PyBytes_AsString(bytesobj);
|
||||||
|
if (!buf) {
|
||||||
|
// raises TypeError
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// set output
|
||||||
|
strref = llvm::StringRef(buf, len);
|
||||||
|
// success
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int py_str_to(PyObject *strobj, llvm::StringRef &strref){
|
int py_str_to(PyObject *strobj, llvm::StringRef &strref){
|
||||||
// type check
|
// type check
|
||||||
|
|
|
||||||
|
|
@ -497,11 +497,9 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj)
|
||||||
llvm::WriteBitcodeToFile(M, rso);
|
llvm::WriteBitcodeToFile(M, rso);
|
||||||
rso.flush();
|
rso.flush();
|
||||||
StringRef ref = rso.str();
|
StringRef ref = rso.str();
|
||||||
PyObject* buf = PyString_FromStringAndSize(ref.data(), ref.size());
|
PyObject* buf = PyBytes_FromStringAndSize(ref.data(), ref.size());
|
||||||
if (-1 == PyFile_WriteObject(buf, FObj, Py_PRINT_RAW)){
|
puts(PyString_AsString(PyObject_Str(PyObject_Type(buf))));
|
||||||
return NULL;
|
return PyObject_CallMethod(FObj, "write", "O", buf);
|
||||||
}
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
|
||||||
32
llvmpy/include/python3adapt.h
Normal file
32
llvmpy/include/python3adapt.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef PYTHON3ADAPT_H
|
||||||
|
#define PYTHON3ADAPT_H
|
||||||
|
|
||||||
|
#if (PY_VERSION_HEX < 0x03000000)
|
||||||
|
|
||||||
|
#define PyBytes_Check PyString_Check
|
||||||
|
#define PyBytes_Size PyString_Size
|
||||||
|
#define PyBytes_AsString PyString_AsString
|
||||||
|
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
|
||||||
|
#define PyBytes_FromString PyString_FromString
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PY_VERSION_HEX >= 0x03000000)
|
||||||
|
|
||||||
|
#define PyString_Check PyUnicode_Check
|
||||||
|
#define PyString_Size PyUnicode_GET_SIZE
|
||||||
|
#define PyString_AsString PyUnicode_AsUTF8
|
||||||
|
#define PyString_FromStringAndSize PyUnicode_FromStringAndSize
|
||||||
|
#define PyString_FromString PyUnicode_FromString
|
||||||
|
|
||||||
|
#define PyInt_Check PyLong_Check
|
||||||
|
#define PyInt_FromLong PyLong_FromLong
|
||||||
|
#define PyInt_AsLong PyLong_AsLong
|
||||||
|
#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
|
||||||
|
#define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
|
||||||
|
|
||||||
|
#define PyFile_Check(x) (1)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //PYTHON3ADAPT_H
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from ..namespace import llvm
|
from ..namespace import llvm
|
||||||
from StringRef import StringRef
|
from .StringRef import StringRef
|
||||||
|
|
||||||
Triple = llvm.Class()
|
Triple = llvm.Class()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Argument, Value
|
from .Value import Argument, Value
|
||||||
from Attributes import Attributes
|
from .Attributes import Attributes
|
||||||
|
|
||||||
@Argument
|
@Argument
|
||||||
class Argument:
|
class Argument:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
|
|
||||||
llvm.includes.add('llvm/Attributes.h')
|
llvm.includes.add('llvm/Attributes.h')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Function, BasicBlock
|
from .Value import Function, BasicBlock
|
||||||
from Instruction import Instruction, TerminatorInst
|
from .Instruction import Instruction, TerminatorInst
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
|
|
||||||
@BasicBlock
|
@BasicBlock
|
||||||
class BasicBlock:
|
class BasicBlock:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ llvm.includes.add('llvm/Bitcode/ReaderWriter.h')
|
||||||
ParseBitCodeFile = llvm.CustomFunction('ParseBitCodeFile',
|
ParseBitCodeFile = llvm.CustomFunction('ParseBitCodeFile',
|
||||||
'llvm_ParseBitCodeFile',
|
'llvm_ParseBitCodeFile',
|
||||||
PyObjectPtr, # returns Module*
|
PyObjectPtr, # returns Module*
|
||||||
cast(str, StringRef),
|
cast(bytes, StringRef),
|
||||||
ref(LLVMContext),
|
ref(LLVMContext),
|
||||||
PyObjectPtr, # file-like object
|
PyObjectPtr, # file-like object
|
||||||
).require_only(2)
|
).require_only(2)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
CallingConv = llvm.Namespace('CallingConv')
|
CallingConv = llvm.Namespace('CallingConv')
|
||||||
ID = CallingConv.Enum('ID', '''
|
ID = CallingConv.Enum('ID', '''
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Value
|
from .Value import Value
|
||||||
from Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray
|
from .Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray
|
||||||
from Value import ConstantStruct, ConstantVector, ConstantVector
|
from .Value import ConstantStruct, ConstantVector, ConstantVector
|
||||||
from Value import ConstantDataSequential, ConstantDataArray, ConstantExpr
|
from .Value import ConstantDataSequential, ConstantDataArray, ConstantExpr
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned
|
from .ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned
|
||||||
from Type import Type, IntegerType, ArrayType, StructType
|
from .Type import Type, IntegerType, ArrayType, StructType
|
||||||
from Instruction import CmpInst
|
from .Instruction import CmpInst
|
||||||
|
|
||||||
@Constant
|
@Constant
|
||||||
class Constant:
|
class Constant:
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Pass import ImmutablePass
|
from .Pass import ImmutablePass
|
||||||
|
|
||||||
DataLayout = llvm.Class(ImmutablePass)
|
DataLayout = llvm.Class(ImmutablePass)
|
||||||
StructLayout = llvm.Class()
|
StructLayout = llvm.Class()
|
||||||
|
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Type import Type, IntegerType, StructType
|
from .Type import Type, IntegerType, StructType
|
||||||
from ADT.SmallVector import SmallVector_Value
|
from .ADT.SmallVector import SmallVector_Value
|
||||||
from GlobalVariable import GlobalVariable
|
from .GlobalVariable import GlobalVariable
|
||||||
|
|
||||||
|
|
||||||
@DataLayout
|
@DataLayout
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
from ADT.SmallVector import SmallVector_Type
|
from .ADT.SmallVector import SmallVector_Type
|
||||||
|
|
||||||
FunctionType = llvm.Class(Type)
|
FunctionType = llvm.Class(Type)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from JITMemoryManager import JITMemoryManager
|
from .JITMemoryManager import JITMemoryManager
|
||||||
from Support.CodeGen import CodeGenOpt, Reloc, CodeModel
|
from .Support.CodeGen import CodeGenOpt, Reloc, CodeModel
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from ExecutionEngine.ExecutionEngine import ExecutionEngine
|
from .ExecutionEngine.ExecutionEngine import ExecutionEngine
|
||||||
from Target.TargetMachine import TargetMachine
|
from .Target.TargetMachine import TargetMachine
|
||||||
from ADT.Triple import Triple
|
from .ADT.Triple import Triple
|
||||||
|
|
||||||
EngineBuilder = llvm.Class()
|
EngineBuilder = llvm.Class()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,6 @@ class ExecutionEngine:
|
||||||
@CustomPythonMethod
|
@CustomPythonMethod
|
||||||
def runFunction(self, fn, args):
|
def runFunction(self, fn, args):
|
||||||
from llvmpy import capsule
|
from llvmpy import capsule
|
||||||
unwrapped = map(capsule.unwrap, args)
|
unwrapped = list(map(capsule.unwrap, args))
|
||||||
return self._runFunction(fn, tuple(unwrapped))
|
return self._runFunction(fn, tuple(unwrapped))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import GlobalValue, Constant, Function, Argument, Value
|
from .Value import GlobalValue, Constant, Function, Argument, Value
|
||||||
from BasicBlock import BasicBlock
|
from .BasicBlock import BasicBlock
|
||||||
from Attributes import Attributes
|
from .Attributes import Attributes
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
from DerivedTypes import FunctionType
|
from .DerivedTypes import FunctionType
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from CallingConv import CallingConv
|
from .CallingConv import CallingConv
|
||||||
|
|
||||||
@Function
|
@Function
|
||||||
class Function:
|
class Function:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
|
|
||||||
GenericValue = llvm.Class()
|
GenericValue = llvm.Class()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import GlobalValue
|
from .Value import GlobalValue
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
|
|
||||||
@GlobalValue
|
@GlobalValue
|
||||||
class GlobalValue:
|
class GlobalValue:
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
from GlobalValue import GlobalValue
|
from .GlobalValue import GlobalValue
|
||||||
GlobalVariable = llvm.Class(GlobalValue)
|
GlobalVariable = llvm.Class(GlobalValue)
|
||||||
|
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Value import Constant
|
from .Value import Constant
|
||||||
|
|
||||||
@GlobalVariable
|
@GlobalVariable
|
||||||
class GlobalVariable:
|
class GlobalVariable:
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from BasicBlock import BasicBlock
|
from .BasicBlock import BasicBlock
|
||||||
from Instruction import Instruction
|
from .Instruction import Instruction
|
||||||
from Instruction import ReturnInst, CallInst, BranchInst, SwitchInst
|
from .Instruction import ReturnInst, CallInst, BranchInst, SwitchInst
|
||||||
from Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode
|
from .Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode
|
||||||
from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst
|
from .Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst
|
||||||
from Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst
|
from .Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst
|
||||||
from Instruction import LandingPadInst, VAArgInst
|
from .Instruction import LandingPadInst, VAArgInst
|
||||||
from Instruction import AtomicOrdering, SynchronizationScope
|
from .Instruction import AtomicOrdering, SynchronizationScope
|
||||||
from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned
|
from .ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Value import Value, MDNode
|
from .Value import Value, MDNode
|
||||||
from Type import Type, IntegerType
|
from .Type import Type, IntegerType
|
||||||
|
|
||||||
IRBuilder = llvm.Class()
|
IRBuilder = llvm.Class()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Value
|
from .Value import Value
|
||||||
from DerivedTypes import FunctionType
|
from .DerivedTypes import FunctionType
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
|
|
||||||
llvm.includes.add('llvm/InlineAsm.h')
|
llvm.includes.add('llvm/InlineAsm.h')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Value, MDNode, User, BasicBlock, Function, ConstantInt
|
from .Value import Value, MDNode, User, BasicBlock, Function, ConstantInt
|
||||||
|
|
||||||
|
|
||||||
Instruction = llvm.Class(User)
|
Instruction = llvm.Class(User)
|
||||||
|
|
@ -63,10 +63,10 @@ SynchronizationScope = llvm.Enum('SynchronizationScope',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from CallingConv import CallingConv
|
from .CallingConv import CallingConv
|
||||||
from Attributes import Attributes
|
from .Attributes import Attributes
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Function import Function
|
from .Function import Function
|
||||||
|
|
||||||
|
|
||||||
Intrinsic = llvm.Namespace('Intrinsic')
|
Intrinsic = llvm.Namespace('Intrinsic')
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
@llvm.Class()
|
@llvm.Class()
|
||||||
class JITMemoryManager:
|
class JITMemoryManager:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
@llvm.Class()
|
@llvm.Class()
|
||||||
class LLVMContext:
|
class LLVMContext:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
|
|
||||||
llvm.includes.add('llvm/Linker.h')
|
llvm.includes.add('llvm/Linker.h')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Value, MDNode, MDString
|
from .Value import Value, MDNode, MDString
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Function import Function
|
from .Function import Function
|
||||||
from Support.raw_ostream import raw_ostream
|
from .Support.raw_ostream import raw_ostream
|
||||||
from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
||||||
|
|
||||||
@MDNode
|
@MDNode
|
||||||
class MDNode:
|
class MDNode:
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
Module = llvm.Class()
|
Module = llvm.Class()
|
||||||
|
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Constant import Constant
|
from .Constant import Constant
|
||||||
from GlobalVariable import GlobalVariable
|
from .GlobalVariable import GlobalVariable
|
||||||
from Function import Function
|
from .Function import Function
|
||||||
from DerivedTypes import FunctionType
|
from .DerivedTypes import FunctionType
|
||||||
from Support.raw_ostream import raw_ostream
|
from .Support.raw_ostream import raw_ostream
|
||||||
from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
||||||
from Type import Type, StructType
|
from .Type import Type, StructType
|
||||||
from Metadata import NamedMDNode
|
from .Metadata import NamedMDNode
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class Module:
|
class Module:
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
Pass = llvm.Class()
|
Pass = llvm.Class()
|
||||||
ModulePass = llvm.Class(Pass)
|
ModulePass = llvm.Class(Pass)
|
||||||
FunctionPass = llvm.Class(Pass)
|
FunctionPass = llvm.Class(Pass)
|
||||||
ImmutablePass = llvm.Class(ModulePass)
|
ImmutablePass = llvm.Class(ModulePass)
|
||||||
|
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Value import Function
|
from .Value import Function
|
||||||
|
|
||||||
@Pass
|
@Pass
|
||||||
class Pass:
|
class Pass:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Pass import Pass
|
from .Pass import Pass
|
||||||
from Module import Module
|
from .Module import Module
|
||||||
from Value import Function
|
from .Value import Function
|
||||||
|
|
||||||
PassManagerBase = llvm.Class()
|
PassManagerBase = llvm.Class()
|
||||||
PassManager = llvm.Class(PassManagerBase)
|
PassManager = llvm.Class(PassManagerBase)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from src.ADT.StringRef import StringRef
|
from src.ADT.StringRef import StringRef
|
||||||
|
|
||||||
PassRegistry = llvm.Class()
|
PassRegistry = llvm.Class()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
PassInfo = llvm.Class()
|
PassInfo = llvm.Class()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from ..namespace import llvm
|
from ..namespace import llvm
|
||||||
from raw_ostream import raw_ostream
|
from .raw_ostream import raw_ostream
|
||||||
|
|
||||||
@llvm.Class(raw_ostream)
|
@llvm.Class(raw_ostream)
|
||||||
class formatted_raw_ostream:
|
class formatted_raw_ostream:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from Support.raw_ostream import raw_ostream
|
from .Support.raw_ostream import raw_ostream
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
|
|
||||||
Type = llvm.Class()
|
Type = llvm.Class()
|
||||||
IntegerType = llvm.Class(Type)
|
IntegerType = llvm.Class(Type)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
from Value import Value, User
|
from .Value import Value, User
|
||||||
|
|
||||||
@User
|
@User
|
||||||
class User:
|
class User:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from binding import *
|
from binding import *
|
||||||
from namespace import llvm
|
from .namespace import llvm
|
||||||
|
|
||||||
# forward declarations
|
# forward declarations
|
||||||
Value = llvm.Class()
|
Value = llvm.Class()
|
||||||
|
|
@ -21,11 +21,11 @@ ConstantDataSequential = llvm.Class(Constant)
|
||||||
ConstantDataArray = llvm.Class(ConstantDataSequential)
|
ConstantDataArray = llvm.Class(ConstantDataSequential)
|
||||||
ConstantExpr = llvm.Class(Constant)
|
ConstantExpr = llvm.Class(Constant)
|
||||||
|
|
||||||
from Support.raw_ostream import raw_ostream
|
from .Support.raw_ostream import raw_ostream
|
||||||
from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
||||||
from Type import Type
|
from .Type import Type
|
||||||
from LLVMContext import LLVMContext
|
from .LLVMContext import LLVMContext
|
||||||
from ADT.StringRef import StringRef
|
from .ADT.StringRef import StringRef
|
||||||
|
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@ import os.path
|
||||||
def _init(root=__name__, file=__file__):
|
def _init(root=__name__, file=__file__):
|
||||||
base = os.path.dirname(file)
|
base = os.path.dirname(file)
|
||||||
for fname in os.listdir(base):
|
for fname in os.listdir(base):
|
||||||
print fname
|
|
||||||
is_python_script = fname.endswith('.py') or fname.endswith('.pyc')
|
is_python_script = fname.endswith('.py') or fname.endswith('.pyc')
|
||||||
is_init_script = fname.startswith('__init__')
|
is_init_script = fname.startswith('__init__')
|
||||||
is_directory = os.path.isdir(os.path.join(base, fname))
|
is_directory = os.path.isdir(os.path.join(base, fname))
|
||||||
if (is_directory or is_python_script) and not is_init_script :
|
is_python_module = is_directory and not fname.startswith('__')
|
||||||
|
if (is_python_module or is_python_script) and not is_init_script:
|
||||||
|
print(fname)
|
||||||
modname = os.path.basename(fname).rsplit('.', 1)[0]
|
modname = os.path.basename(fname).rsplit('.', 1)[0]
|
||||||
#importlib.import_module('.' + modname, __name__)
|
#importlib.import_module('.' + modname, __name__)
|
||||||
__import__('.'.join([root, modname]))
|
__import__('.'.join([root, modname]))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
from StringIO import StringIO
|
from io import BytesIO, StringIO
|
||||||
|
|
||||||
from llvmpy.api import llvm
|
from llvmpy.api import llvm
|
||||||
from llvmpy import extra
|
from llvmpy import extra
|
||||||
from llvmpy import _capsule
|
from llvmpy import _capsule
|
||||||
import llvmpy.capsule
|
import llvmpy.capsule
|
||||||
|
import collections
|
||||||
llvmpy.capsule.set_debug(True)
|
llvmpy.capsule.set_debug(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -14,19 +15,19 @@ def test_basic_jit_use():
|
||||||
context = llvm.getGlobalContext()
|
context = llvm.getGlobalContext()
|
||||||
|
|
||||||
m = llvm.Module.new("modname", context)
|
m = llvm.Module.new("modname", context)
|
||||||
print m.getModuleIdentifier()
|
print(m.getModuleIdentifier())
|
||||||
m.setModuleIdentifier('modname2')
|
m.setModuleIdentifier('modname2')
|
||||||
print m.getModuleIdentifier()
|
print(m.getModuleIdentifier())
|
||||||
print 'endianness', m.getEndianness()
|
print('endianness', m.getEndianness())
|
||||||
assert m.getEndianness() == llvm.Module.Endianness.AnyEndianness
|
assert m.getEndianness() == llvm.Module.Endianness.AnyEndianness
|
||||||
print 'pointer-size', m.getPointerSize()
|
print('pointer-size', m.getPointerSize())
|
||||||
assert m.getPointerSize() == llvm.Module.PointerSize.AnyPointerSize
|
assert m.getPointerSize() == llvm.Module.PointerSize.AnyPointerSize
|
||||||
m.dump()
|
m.dump()
|
||||||
|
|
||||||
|
|
||||||
os = extra.make_raw_ostream_for_printing()
|
os = extra.make_raw_ostream_for_printing()
|
||||||
m.print_(os, None)
|
m.print_(os, None)
|
||||||
print os.str()
|
print(os.str())
|
||||||
|
|
||||||
|
|
||||||
int1ty = llvm.Type.getInt1Ty(context)
|
int1ty = llvm.Type.getInt1Ty(context)
|
||||||
|
|
@ -40,11 +41,11 @@ def test_basic_jit_use():
|
||||||
types = [llvm.Type.getIntNTy(context, 8), llvm.Type.getIntNTy(context, 32)]
|
types = [llvm.Type.getIntNTy(context, 8), llvm.Type.getIntNTy(context, 32)]
|
||||||
fnty = llvm.FunctionType.get(llvm.Type.getIntNTy(context, 8), types, False)
|
fnty = llvm.FunctionType.get(llvm.Type.getIntNTy(context, 8), types, False)
|
||||||
|
|
||||||
print fnty
|
print(fnty)
|
||||||
|
|
||||||
const = m.getOrInsertFunction("foo", fnty)
|
const = m.getOrInsertFunction("foo", fnty)
|
||||||
fn = const._downcast(llvm.Function)
|
fn = const._downcast(llvm.Function)
|
||||||
print fn
|
print(fn)
|
||||||
assert fn.hasName()
|
assert fn.hasName()
|
||||||
assert 'foo' == fn.getName()
|
assert 'foo' == fn.getName()
|
||||||
fn.setName('bar')
|
fn.setName('bar')
|
||||||
|
|
@ -63,7 +64,7 @@ def test_basic_jit_use():
|
||||||
assert len(fn_uselist) == 0
|
assert len(fn_uselist) == 0
|
||||||
|
|
||||||
builder = llvm.IRBuilder.new(context)
|
builder = llvm.IRBuilder.new(context)
|
||||||
print builder
|
print(builder)
|
||||||
|
|
||||||
bb = llvm.BasicBlock.Create(context, "entry", fn, None)
|
bb = llvm.BasicBlock.Create(context, "entry", fn, None)
|
||||||
assert bb.empty()
|
assert bb.empty()
|
||||||
|
|
@ -72,19 +73,19 @@ def test_basic_jit_use():
|
||||||
assert bb.getTerminator() is None
|
assert bb.getTerminator() is None
|
||||||
|
|
||||||
arg0, arg1 = fn.getArgumentList()
|
arg0, arg1 = fn.getArgumentList()
|
||||||
print arg0, arg1
|
print(arg0, arg1)
|
||||||
|
|
||||||
extended = builder.CreateZExt(arg0, arg1.getType())
|
extended = builder.CreateZExt(arg0, arg1.getType())
|
||||||
result = builder.CreateAdd(extended, arg1)
|
result = builder.CreateAdd(extended, arg1)
|
||||||
ret = builder.CreateTrunc(result, fn.getReturnType())
|
ret = builder.CreateTrunc(result, fn.getReturnType())
|
||||||
builder.CreateRet(ret)
|
builder.CreateRet(ret)
|
||||||
|
|
||||||
print arg0.list_use()
|
print(arg0.list_use())
|
||||||
|
|
||||||
print fn
|
print(fn)
|
||||||
|
|
||||||
errio = StringIO()
|
errio = StringIO()
|
||||||
print m
|
print(m)
|
||||||
|
|
||||||
# verifier
|
# verifier
|
||||||
action = llvm.VerifierFailureAction.ReturnStatusAction
|
action = llvm.VerifierFailureAction.ReturnStatusAction
|
||||||
|
|
@ -92,7 +93,7 @@ def test_basic_jit_use():
|
||||||
corrupted = llvm.verifyFunction(fn, action)
|
corrupted = llvm.verifyFunction(fn, action)
|
||||||
assert not corrupted
|
assert not corrupted
|
||||||
corrupted = llvm.verifyModule(m, action, errio)
|
corrupted = llvm.verifyModule(m, action, errio)
|
||||||
print corrupted
|
print(corrupted)
|
||||||
assert not corrupted, errio.getvalue()
|
assert not corrupted, errio.getvalue()
|
||||||
|
|
||||||
# build pass manager
|
# build pass manager
|
||||||
|
|
@ -114,13 +115,13 @@ def test_basic_jit_use():
|
||||||
|
|
||||||
pm.run(m)
|
pm.run(m)
|
||||||
|
|
||||||
print m
|
print(m)
|
||||||
|
|
||||||
# build engine
|
# build engine
|
||||||
|
|
||||||
ee = llvm.ExecutionEngine.createJIT(m, errio)
|
ee = llvm.ExecutionEngine.createJIT(m, errio)
|
||||||
print ee, errio.getvalue()
|
print(ee, errio.getvalue())
|
||||||
print ee.getDataLayout().getStringRepresentation()
|
print(ee.getDataLayout().getStringRepresentation())
|
||||||
|
|
||||||
datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64'
|
datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64'
|
||||||
|
|
||||||
|
|
@ -149,7 +150,7 @@ def test_basic_jit_use():
|
||||||
assert 44 == gvR.toUnsignedInt()
|
assert 44 == gvR.toUnsignedInt()
|
||||||
|
|
||||||
# write bitcode
|
# write bitcode
|
||||||
bc_buffer = StringIO()
|
bc_buffer = BytesIO()
|
||||||
llvm.WriteBitcodeToFile(m, bc_buffer)
|
llvm.WriteBitcodeToFile(m, bc_buffer)
|
||||||
bc = bc_buffer.getvalue()
|
bc = bc_buffer.getvalue()
|
||||||
bc_buffer.close()
|
bc_buffer.close()
|
||||||
|
|
@ -187,7 +188,7 @@ def test_engine_builder():
|
||||||
builder.SetInsertPoint(bb)
|
builder.SetInsertPoint(bb)
|
||||||
builder.CreateRet(fn.getArgumentList()[0])
|
builder.CreateRet(fn.getArgumentList()[0])
|
||||||
|
|
||||||
print fn
|
print(fn)
|
||||||
|
|
||||||
eb = llvm.EngineBuilder.new(m)
|
eb = llvm.EngineBuilder.new(m)
|
||||||
eb2 = eb.setEngineKind(llvm.EngineKind.Kind.JIT)
|
eb2 = eb.setEngineKind(llvm.EngineKind.Kind.JIT)
|
||||||
|
|
@ -196,13 +197,13 @@ def test_engine_builder():
|
||||||
|
|
||||||
tm = eb.selectTarget()
|
tm = eb.selectTarget()
|
||||||
|
|
||||||
print 'target triple:', tm.getTargetTriple()
|
print('target triple:', tm.getTargetTriple())
|
||||||
print 'target cpu:', tm.getTargetCPU()
|
print('target cpu:', tm.getTargetCPU())
|
||||||
print 'target feature string:', tm.getTargetFeatureString()
|
print('target feature string:', tm.getTargetFeatureString())
|
||||||
|
|
||||||
target = tm.getTarget()
|
target = tm.getTarget()
|
||||||
print 'target name:', target.getName()
|
print('target name:', target.getName())
|
||||||
print 'target short description:', target.getShortDescription()
|
print('target short description:', target.getShortDescription())
|
||||||
|
|
||||||
assert target.hasJIT()
|
assert target.hasJIT()
|
||||||
assert target.hasTargetMachine()
|
assert target.hasTargetMachine()
|
||||||
|
|
@ -218,7 +219,7 @@ def test_engine_builder():
|
||||||
triple_32variant = triple.get32BitArchVariant()
|
triple_32variant = triple.get32BitArchVariant()
|
||||||
assert triple_32variant.isArch32Bit()
|
assert triple_32variant.isArch32Bit()
|
||||||
|
|
||||||
print tm.getDataLayout()
|
print(tm.getDataLayout())
|
||||||
|
|
||||||
pm = llvm.PassManager.new()
|
pm = llvm.PassManager.new()
|
||||||
pm.add(llvm.DataLayout.new(str(tm.getDataLayout())))
|
pm.add(llvm.DataLayout.new(str(tm.getDataLayout())))
|
||||||
|
|
@ -240,7 +241,7 @@ def test_engine_builder():
|
||||||
formatted.flush()
|
formatted.flush()
|
||||||
raw.flush()
|
raw.flush()
|
||||||
asm = raw.str()
|
asm = raw.str()
|
||||||
print asm
|
print(asm)
|
||||||
assert 'foo' in asm
|
assert 'foo' in asm
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -301,7 +302,7 @@ def test_globalvariable():
|
||||||
gvar2 = m.getNamedGlobal('apple')
|
gvar2 = m.getNamedGlobal('apple')
|
||||||
assert gvar2 is gvar
|
assert gvar2 is gvar
|
||||||
|
|
||||||
print m.list_globals()
|
print(m.list_globals())
|
||||||
|
|
||||||
|
|
||||||
def test_sequentialtypes():
|
def test_sequentialtypes():
|
||||||
|
|
@ -345,9 +346,9 @@ def test_passregistry():
|
||||||
|
|
||||||
passinfo = passreg.getPassInfo("dce")
|
passinfo = passreg.getPassInfo("dce")
|
||||||
dcepass = passinfo.createPass()
|
dcepass = passinfo.createPass()
|
||||||
print dcepass.getPassName()
|
print(dcepass.getPassName())
|
||||||
|
|
||||||
print passreg.enumerate()
|
print(passreg.enumerate())
|
||||||
|
|
||||||
def test_targetregistry():
|
def test_targetregistry():
|
||||||
llvm.TargetRegistry.printRegisteredTargetsForVersion()
|
llvm.TargetRegistry.printRegisteredTargetsForVersion()
|
||||||
|
|
@ -356,15 +357,15 @@ def test_targetregistry():
|
||||||
target = llvm.TargetRegistry.getClosestTargetForJIT(errmsg)
|
target = llvm.TargetRegistry.getClosestTargetForJIT(errmsg)
|
||||||
errmsg.close()
|
errmsg.close()
|
||||||
|
|
||||||
print target.getName()
|
print(target.getName())
|
||||||
print target.getShortDescription()
|
print(target.getShortDescription())
|
||||||
assert target.hasJIT()
|
assert target.hasJIT()
|
||||||
assert target.hasTargetMachine()
|
assert target.hasTargetMachine()
|
||||||
|
|
||||||
next = target.getNext()
|
next = target.getNext()
|
||||||
if next:
|
if next:
|
||||||
print next.getName()
|
print(next.getName())
|
||||||
print next.getShortDescription()
|
print(next.getShortDescription())
|
||||||
|
|
||||||
triple = llvm.sys.getDefaultTargetTriple()
|
triple = llvm.sys.getDefaultTargetTriple()
|
||||||
cpu = llvm.sys.getHostCPUName()
|
cpu = llvm.sys.getHostCPUName()
|
||||||
|
|
@ -375,9 +376,9 @@ def test_targetregistry():
|
||||||
tm = target.createTargetMachine(triple, cpu, "", targetoptions)
|
tm = target.createTargetMachine(triple, cpu, "", targetoptions)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
for name, value in globals().items():
|
for name, value in list(globals().items()):
|
||||||
if name.startswith('test_') and callable(value):
|
if name.startswith('test_') and isinstance(value, collections.Callable):
|
||||||
print name.center(80, '-')
|
print(name.center(80, '-'))
|
||||||
value()
|
value()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue