/pypy/module/cpyext/eval.py
Python | 230 lines | 177 code | 16 blank | 37 comment | 13 complexity | 7c11e3abc996b9440b730e709002994b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
- from pypy.interpreter.error import oefmt
- from pypy.interpreter.astcompiler import consts
- from rpython.rtyper.lltypesystem import rffi, lltype
- from pypy.module.cpyext.api import (
- cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, fread, feof, Py_ssize_tP,
- cpython_struct, is_valid_fp)
- from pypy.module.cpyext.pyobject import PyObject
- from pypy.module.cpyext.pyerrors import PyErr_SetFromErrno
- from pypy.module.cpyext.funcobject import PyCodeObject
- from pypy.module.__builtin__ import compiling
- PyCompilerFlags = cpython_struct(
- "PyCompilerFlags", (("cf_flags", rffi.INT),))
- PyCompilerFlagsPtr = lltype.Ptr(PyCompilerFlags)
- PyCF_MASK = (consts.CO_FUTURE_DIVISION |
- consts.CO_FUTURE_ABSOLUTE_IMPORT |
- consts.CO_FUTURE_WITH_STATEMENT |
- consts.CO_FUTURE_PRINT_FUNCTION |
- consts.CO_FUTURE_UNICODE_LITERALS)
- @cpython_api([PyObject, PyObject, PyObject], PyObject)
- def PyEval_CallObjectWithKeywords(space, w_obj, w_arg, w_kwds):
- return space.call(w_obj, w_arg, w_kwds)
- @cpython_api([], PyObject, result_borrowed=True)
- def PyEval_GetBuiltins(space):
- """Return a dictionary of the builtins in the current execution
- frame, or the interpreter of the thread state if no frame is
- currently executing."""
- caller = space.getexecutioncontext().gettopframe_nohidden()
- if caller is not None:
- w_globals = caller.get_w_globals()
- w_builtins = space.getitem(w_globals, space.wrap('__builtins__'))
- if not space.isinstance_w(w_builtins, space.w_dict):
- w_builtins = w_builtins.getdict(space)
- else:
- w_builtins = space.builtin.getdict(space)
- return w_builtins # borrowed ref in all cases
- @cpython_api([], PyObject, error=CANNOT_FAIL, result_borrowed=True)
- def PyEval_GetLocals(space):
- """Return a dictionary of the local variables in the current execution
- frame, or NULL if no frame is currently executing."""
- caller = space.getexecutioncontext().gettopframe_nohidden()
- if caller is None:
- return None
- return caller.getdictscope() # borrowed ref
- @cpython_api([], PyObject, error=CANNOT_FAIL, result_borrowed=True)
- def PyEval_GetGlobals(space):
- """Return a dictionary of the global variables in the current execution
- frame, or NULL if no frame is currently executing."""
- caller = space.getexecutioncontext().gettopframe_nohidden()
- if caller is None:
- return None
- return caller.get_w_globals() # borrowed ref
- @cpython_api([PyCodeObject, PyObject, PyObject], PyObject)
- def PyEval_EvalCode(space, w_code, w_globals, w_locals):
- """This is a simplified interface to PyEval_EvalCodeEx(), with just
- the code object, and the dictionaries of global and local variables.
- The other arguments are set to NULL."""
- if w_globals is None:
- w_globals = space.w_None
- if w_locals is None:
- w_locals = space.w_None
- return compiling.eval(space, w_code, w_globals, w_locals)
- @cpython_api([PyObject, PyObject], PyObject)
- def PyObject_CallObject(space, w_obj, w_arg):
- """
- Call a callable Python object callable_object, with arguments given by the
- tuple args. If no arguments are needed, then args may be NULL. Returns
- the result of the call on success, or NULL on failure. This is the equivalent
- of the Python expression apply(callable_object, args) or
- callable_object(*args)."""
- return space.call(w_obj, w_arg)
- @cpython_api([PyObject, PyObject, PyObject], PyObject)
- def PyObject_Call(space, w_obj, w_args, w_kw):
- """
- Call a callable Python object, with arguments given by the
- tuple args, and named arguments given by the dictionary kw. If no named
- arguments are needed, kw may be NULL. args must not be NULL, use an
- empty tuple if no arguments are needed. Returns the result of the call on
- success, or NULL on failure. This is the equivalent of the Python expression
- apply(callable_object, args, kw) or callable_object(*args, **kw)."""
- return space.call(w_obj, w_args, w_kw)
- # These constants are also defined in include/eval.h
- Py_single_input = 256
- Py_file_input = 257
- Py_eval_input = 258
- def compile_string(space, source, filename, start, flags=0):
- w_source = space.newbytes(source)
- start = rffi.cast(lltype.Signed, start)
- if start == Py_file_input:
- mode = 'exec'
- elif start == Py_eval_input:
- mode = 'eval'
- elif start == Py_single_input:
- mode = 'single'
- else:
- raise oefmt(space.w_ValueError,
- "invalid mode parameter for compilation")
- return compiling.compile(space, w_source, filename, mode, flags)
- def run_string(space, source, filename, start, w_globals, w_locals):
- w_code = compile_string(space, source, filename, start)
- return compiling.eval(space, w_code, w_globals, w_locals)
- @cpython_api([CONST_STRING], rffi.INT_real, error=-1)
- def PyRun_SimpleString(space, command):
- """This is a simplified interface to PyRun_SimpleStringFlags() below,
- leaving the PyCompilerFlags* argument set to NULL."""
- command = rffi.charp2str(command)
- run_string(space, command, "<string>", Py_file_input,
- space.w_None, space.w_None)
- return 0
- @cpython_api([CONST_STRING, rffi.INT_real,PyObject, PyObject], PyObject)
- def PyRun_String(space, source, start, w_globals, w_locals):
- """This is a simplified interface to PyRun_StringFlags() below, leaving
- flags set to NULL."""
- source = rffi.charp2str(source)
- filename = "<string>"
- return run_string(space, source, filename, start, w_globals, w_locals)
- @cpython_api([CONST_STRING, rffi.INT_real, PyObject, PyObject,
- PyCompilerFlagsPtr], PyObject)
- def PyRun_StringFlags(space, source, start, w_globals, w_locals, flagsptr):
- """Execute Python source code from str in the context specified by the
- dictionaries globals and locals with the compiler flags specified by
- flags. The parameter start specifies the start token that should be used to
- parse the source code.
- Returns the result of executing the code as a Python object, or NULL if an
- exception was raised."""
- source = rffi.charp2str(source)
- if flagsptr:
- flags = rffi.cast(lltype.Signed, flagsptr.c_cf_flags)
- else:
- flags = 0
- w_code = compile_string(space, source, "<string>", start, flags)
- return compiling.eval(space, w_code, w_globals, w_locals)
- @cpython_api([FILEP, CONST_STRING, rffi.INT_real, PyObject, PyObject], PyObject)
- def PyRun_File(space, fp, filename, start, w_globals, w_locals):
- """This is a simplified interface to PyRun_FileExFlags() below, leaving
- closeit set to 0 and flags set to NULL."""
- BUF_SIZE = 8192
- source = ""
- filename = rffi.charp2str(filename)
- buf = lltype.malloc(rffi.CCHARP.TO, BUF_SIZE, flavor='raw')
- if not is_valid_fp(fp):
- lltype.free(buf, flavor='raw')
- PyErr_SetFromErrno(space, space.w_IOError)
- return None
- try:
- while True:
- count = fread(buf, 1, BUF_SIZE, fp)
- count = rffi.cast(lltype.Signed, count)
- source += rffi.charpsize2str(buf, count)
- if count < BUF_SIZE:
- if feof(fp):
- break
- PyErr_SetFromErrno(space, space.w_IOError)
- finally:
- lltype.free(buf, flavor='raw')
- return run_string(space, source, filename, start, w_globals, w_locals)
- # Undocumented function!
- @cpython_api([PyObject, Py_ssize_tP], rffi.INT_real, error=0)
- def _PyEval_SliceIndex(space, w_obj, pi):
- """Extract a slice index from a PyInt or PyLong or an object with the
- nb_index slot defined, and store in *pi.
- Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
- and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1.
- Return 0 on error, 1 on success.
- Note: If v is NULL, return success without storing into *pi. This
- is because_PyEval_SliceIndex() is called by apply_slice(), which can be
- called by the SLICE opcode with v and/or w equal to NULL.
- """
- if w_obj is not None:
- pi[0] = space.getindex_w(w_obj, None)
- return 1
- @cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real, PyCompilerFlagsPtr],
- PyObject)
- def Py_CompileStringFlags(space, source, filename, start, flagsptr):
- """Parse and compile the Python source code in str, returning the
- resulting code object. The start token is given by start; this
- can be used to constrain the code which can be compiled and should
- be Py_eval_input, Py_file_input, or Py_single_input. The filename
- specified by filename is used to construct the code object and may
- appear in tracebacks or SyntaxError exception messages. This
- returns NULL if the code cannot be parsed or compiled."""
- source = rffi.charp2str(source)
- filename = rffi.charp2str(filename)
- if flagsptr:
- flags = rffi.cast(lltype.Signed, flagsptr.c_cf_flags)
- else:
- flags = 0
- return compile_string(space, source, filename, start, flags)
- @cpython_api([PyCompilerFlagsPtr], rffi.INT_real, error=CANNOT_FAIL)
- def PyEval_MergeCompilerFlags(space, cf):
- """This function changes the flags of the current evaluation
- frame, and returns true on success, false on failure."""
- flags = rffi.cast(lltype.Signed, cf.c_cf_flags)
- result = flags != 0
- current_frame = space.getexecutioncontext().gettopframe_nohidden()
- if current_frame:
- codeflags = current_frame.pycode.co_flags
- compilerflags = codeflags & PyCF_MASK
- if compilerflags:
- result = 1
- flags |= compilerflags
- # No future keyword at the moment
- # if codeflags & CO_GENERATOR_ALLOWED:
- # result = 1
- # flags |= CO_GENERATOR_ALLOWED
- cf.c_cf_flags = rffi.cast(rffi.INT, flags)
- return result