Commit e943d3b1 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #458 from kmod/metaserver_misc

Metaserver misc
parents a1100ede f19b6fba
...@@ -47,6 +47,8 @@ gmon.out ...@@ -47,6 +47,8 @@ gmon.out
find_problem.status find_problem.status
*.expected_cache *.expected_cache
plugins/clang_capi
*.so *.so
*.pch *.pch
......
...@@ -206,7 +206,7 @@ add_test(NAME gc_unittest COMMAND gc_unittest) ...@@ -206,7 +206,7 @@ add_test(NAME gc_unittest COMMAND gc_unittest)
add_test(NAME analysis_unittest COMMAND analysis_unittest) add_test(NAME analysis_unittest COMMAND analysis_unittest)
add_test(NAME pyston_defaults COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests) add_test(NAME pyston_defaults COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
# we pass -I to cpython tests and skip failing ones b/c they are slooow otherwise # we pass -I to cpython tests and skip failing ones b/c they are slooow otherwise
add_test(NAME pyston_defaults_cpython_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -a=-I -k --exit-code-only --skip-failing ${CMAKE_SOURCE_DIR}/test/cpython) add_test(NAME pyston_defaults_cpython_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing ${CMAKE_SOURCE_DIR}/test/cpython)
add_test(NAME pyston_defaults_integration_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing -t60 ${CMAKE_SOURCE_DIR}/test/integration) add_test(NAME pyston_defaults_integration_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing -t60 ${CMAKE_SOURCE_DIR}/test/integration)
add_test(NAME pyston_max_compilation_tier COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-O -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests) add_test(NAME pyston_max_compilation_tier COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-O -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
add_test(NAME pyston_old_parser COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -a=-x -R ./pyston -j1 -a=-n -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests) add_test(NAME pyston_old_parser COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -a=-x -R ./pyston -j1 -a=-n -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
......
...@@ -493,7 +493,7 @@ check: ...@@ -493,7 +493,7 @@ check:
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests & skip failing ones because they are sloooow otherwise @# we pass -I to cpython tests & skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S -a=-I --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t60 $(TEST_DIR)/integration $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t60 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-n -a=-x -a=-S $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-n -a=-x -a=-S $(TESTS_DIR) $(ARGS)
@# skip -O for dbg @# skip -O for dbg
...@@ -510,7 +510,7 @@ check: ...@@ -510,7 +510,7 @@ check:
@# since we can make different decisions about which internal functions to inline or not. @# since we can make different decisions about which internal functions to inline or not.
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise @# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S -a=-I --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t60 $(TEST_DIR)/integration $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t60 $(TEST_DIR)/integration $(ARGS)
@# skip -n for dbg @# skip -n for dbg
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-O -a=-x -a=-S $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-O -a=-x -a=-S $(TESTS_DIR) $(ARGS)
...@@ -955,7 +955,7 @@ $(eval \ ...@@ -955,7 +955,7 @@ $(eval \
check$1 test$1: $(PYTHON_EXE_DEPS) pyston$1 ext_pyston check$1 test$1: $(PYTHON_EXE_DEPS) pyston$1 ext_pyston
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise @# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -a=-I -k --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t=60 $(TEST_DIR)/integration $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t=60 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -a=-x -R pyston$1 -j$(TEST_THREADS) -a=-n -a=-S -k $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -a=-x -R pyston$1 -j$(TEST_THREADS) -a=-n -a=-S -k $(TESTS_DIR) $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-O -a=-S -k $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-O -a=-S -k $(TESTS_DIR) $(ARGS)
...@@ -1182,6 +1182,27 @@ $(FROM_CPYTHON_SRCS:.c=.prof.o): %.prof.o: %.c $(BUILD_SYSTEM_DEPS) ...@@ -1182,6 +1182,27 @@ $(FROM_CPYTHON_SRCS:.c=.prof.o): %.prof.o: %.c $(BUILD_SYSTEM_DEPS)
$(ECHO) Compiling C file to $@ $(ECHO) Compiling C file to $@
$(VERB) $(CC_PROFILE) $(EXT_CFLAGS_PROFILE) -c $< -o $@ -g -MMD -MP -MF $(patsubst %.o,%.d,$@) $(VERB) $(CC_PROFILE) $(EXT_CFLAGS_PROFILE) -c $< -o $@ -g -MMD -MP -MF $(patsubst %.o,%.d,$@)
# These are necessary until we support unicode:
../from_cpython/Modules/_sre.o: EXT_CFLAGS += -Wno-sometimes-uninitialized
../from_cpython/Modules/_sre.release.o: EXT_CFLAGS += -Wno-sometimes-uninitialized
# TESTING:
_plugins/clang_capi.so: plugins/clang_capi.cpp $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -std=c++11 $(LLVM_CXXFLAGS) -I$(LLVM_SRC)/tools/clang/include -I$(LLVM_BUILD)/tools/clang/include -shared
plugins/clang_capi.o: plugins/clang_capi.cpp $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -std=c++11 $(LLVM_CXXFLAGS) -O0 -I$(LLVM_SRC)/tools/clang/include -I$(LLVM_BUILD)/tools/clang/include -c
plugins/clang_capi: plugins/clang_capi.o $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -L$(LLVM_BUILD)/Release/lib -lclangASTMatchers -lclangRewrite -lclangFrontend -lclangDriver -lclangTooling -lclangParse -lclangSema -lclangAnalysis -lclangAST -lclangEdit -lclangLex -lclangBasic -lclangSerialization $(shell $(LLVM_BUILD)/Release+Asserts/bin/llvm-config --ldflags --system-libs --libs all)
plugins/clang_capi.so: plugins/clang_capi.o $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -shared
.PHONY: plugin_test
plugin_test: plugins/clang_capi.so
$(CLANG_CXX) -Xclang -load -Xclang plugins/clang_capi.so -Xclang -add-plugin -Xclang print-fns test/test.cpp -c -S -o -
.PHONY: tool_test
tool_test: plugins/clang_capi
plugins/clang_capi test/test.cpp --
...@@ -14,6 +14,8 @@ extern "C" { ...@@ -14,6 +14,8 @@ extern "C" {
// Pyston change: this is no longer a static object // Pyston change: this is no longer a static object
//PyAPI_DATA(PyTypeObject) PyCFunction_Type; //PyAPI_DATA(PyTypeObject) PyCFunction_Type;
PyAPI_DATA(PyTypeObject*) builtin_function_or_method_cls;
#define PyCFunction_Type (*builtin_function_or_method_cls)
#define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type) #define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type)
......
...@@ -117,7 +117,7 @@ struct _varobject { ...@@ -117,7 +117,7 @@ struct _varobject {
}; };
// Pyston change: hacks to allow C++ features // Pyston change: hacks to allow C++ features
#ifndef __cplusplus #ifndef _PYSTON_API
typedef struct _object PyObject; typedef struct _object PyObject;
typedef struct _varobject PyVarObject; typedef struct _varobject PyVarObject;
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
...@@ -323,7 +323,7 @@ typedef struct { ...@@ -323,7 +323,7 @@ typedef struct {
// Pyston change: hacks to allow C++ features // Pyston change: hacks to allow C++ features
#ifndef __cplusplus #ifndef _PYSTON_API
typedef struct _typeobject PyTypeObject; typedef struct _typeobject PyTypeObject;
#else #else
namespace pyston { namespace pyston {
...@@ -826,7 +826,7 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force) PYSTON_NOEXCEPT; ...@@ -826,7 +826,7 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force) PYSTON_NOEXCEPT;
#define Py_INCREF(op) ((void)(op)) #define Py_INCREF(op) ((void)(op))
#define Py_DECREF(op) asm volatile("" : : "X"(op)) #define Py_DECREF(op) __asm volatile("" : : "X"(op))
/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
* and tp_dealloc implementatons. * and tp_dealloc implementatons.
...@@ -874,7 +874,7 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force) PYSTON_NOEXCEPT; ...@@ -874,7 +874,7 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force) PYSTON_NOEXCEPT;
/* Macros to use in case the object pointer may be NULL: */ /* Macros to use in case the object pointer may be NULL: */
// Pyston change: made these noops as well // Pyston change: made these noops as well
#define Py_XINCREF(op) ((void)(op)) #define Py_XINCREF(op) ((void)(op))
#define Py_XDECREF(op) asm volatile("" : : "X"(op)) #define Py_XDECREF(op) __asm volatile("" : : "X"(op))
/* /*
These are provided as conveniences to Python runtime embedders, so that These are provided as conveniences to Python runtime embedders, so that
......
...@@ -7,10 +7,21 @@ ...@@ -7,10 +7,21 @@
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus > 199711L
#define PYSTON_NOEXCEPT noexcept #define PYSTON_NOEXCEPT noexcept
#else #else
#define PYSTON_NOEXCEPT #define PYSTON_NOEXCEPT
#endif #endif
#else
#define PYSTON_NOEXCEPT
#endif
// HACK: we should set this manually rather than cluing off of the C++ version
#ifdef __cplusplus
#if __cplusplus > 199711L
#define _PYSTON_API
#endif
#endif
#define Py_PROTO(x) x #define Py_PROTO(x) x
...@@ -374,6 +385,11 @@ typedef PY_LONG_LONG Py_intptr_t; ...@@ -374,6 +385,11 @@ typedef PY_LONG_LONG Py_intptr_t;
#endif /* !HAVE_SYS_TIME_H */ #endif /* !HAVE_SYS_TIME_H */
#endif /* !TIME_WITH_SYS_TIME */ #endif /* !TIME_WITH_SYS_TIME */
#ifdef SIZE_MAX
#define PY_SIZE_MAX SIZE_MAX
#else
#define PY_SIZE_MAX ((size_t)-1)
#endif
/* Py_ARITHMETIC_RIGHT_SHIFT /* Py_ARITHMETIC_RIGHT_SHIFT
* C doesn't define whether a right-shift of a signed integer sign-extends * C doesn't define whether a right-shift of a signed integer sign-extends
......
...@@ -23,15 +23,12 @@ names are from range). After much talk with Guido, it was decided to ...@@ -23,15 +23,12 @@ names are from range). After much talk with Guido, it was decided to
let these be any arbitrary python type. Py_None stands for omitted values. let these be any arbitrary python type. Py_None stands for omitted values.
*/ */
// Pyston change: comment this out since this is not the format we're using // Pyston note: this happens to be the same format we use (not a lot going on here),
#if 0 // and we assert so in runtime/types.h
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *start, *stop, *step; /* not NULL */ PyObject *start, *stop, *step; /* not NULL */
} PySliceObject; } PySliceObject;
#endif
struct _PySliceObject;
typedef struct _PySliceObject PySliceObject;
// Pyston change: these are no longer static objects // Pyston change: these are no longer static objects
PyAPI_DATA(PyTypeObject*) slice_cls; PyAPI_DATA(PyTypeObject*) slice_cls;
......
...@@ -29,7 +29,7 @@ PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, const char *, int, int) PYSTON ...@@ -29,7 +29,7 @@ PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, const char *, int, int) PYSTON
/* Reveal traceback type so we can typecheck traceback objects */ /* Reveal traceback type so we can typecheck traceback objects */
// Pyston change: not a static type any more // Pyston change: not a static type any more
PyAPI_DATA(PyTypeObject*) traceback_cls; PyAPI_DATA(PyTypeObject*) traceback_cls;
#define PyTraceback_Type (*traceback_cls) #define PyTraceBack_Type (*traceback_cls)
// PyAPI_DATA(PyTypeObject) PyTraceBack_Type; // PyAPI_DATA(PyTypeObject) PyTraceBack_Type;
#define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type) #define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type)
......
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
# This module should be kept compatible with Python 2.2, see PEP 291. # This module should be kept compatible with Python 2.2, see PEP 291.
from __future__ import generators from __future__ import generators
# Pyston change:
import sys
del sys.modules['modulefinder']
raise ImportError("This isn't really supported in Pyston yet")
import dis import dis
import imp import imp
import marshal import marshal
......
//------------------------------------------------------------------------------
// Tooling sample. Demonstrates:
//
// * How to write a simple source tool using libTooling.
// * How to use RecursiveASTVisitor to find interesting AST nodes.
// * How to use the Rewriter API to rewrite the source code.
//
// Eli Bendersky (eliben@gmail.com)
// This code is in the public domain
//------------------------------------------------------------------------------
#include <sstream>
#include <string>
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace clang::ast_matchers;
static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample");
//auto matcher = memberExpr().bind("member_expr");
auto matcher = memberExpr(member(fieldDecl(hasName("ob_refcnt")).bind("field"))).bind("member_expr");
MatchFinder Finder;
Rewriter TheRewriter;
class Replacer : public MatchFinder::MatchCallback {
public:
virtual void run (const MatchFinder::MatchResult &Result) {
errs() << "matched!\n";
if (const MemberExpr* ME = Result.Nodes.getNodeAs<clang::MemberExpr>("member_expr")) {
ME->dump();
//cast<FieldDecl>(ME->getMemberDecl())->dump();
TheRewriter.InsertTextBefore(ME->getSourceRange().getBegin(), "/* Pyston change, was: ");
TheRewriter.InsertTextAfter(ME->getSourceRange().getEnd(), "*/ 2");
for (auto c : ME->Stmt::children()) {
c->dump();
}
}
if (const FieldDecl* ME = Result.Nodes.getNodeAs<clang::FieldDecl>("field")) {
ME->dump();
TheRewriter.InsertTextAfter(ME->getLocStart(), "/**/");
}
//Result.dump();
}
};
class MyFrontendAction : public ASTFrontendAction {
public:
MyFrontendAction() {}
void EndSourceFileAction() override {
SourceManager &SM = TheRewriter.getSourceMgr();
// Now emit the rewritten buffer.
TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs());
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& CI, StringRef file) override {
TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
return Finder.newASTConsumer();
}
};
int main(int argc, const char **argv) {
CommonOptionsParser op(argc, argv, ToolingSampleCategory);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
Replacer replacer;
Finder.addMatcher(matcher, &replacer);
return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
}
...@@ -28,8 +28,41 @@ ...@@ -28,8 +28,41 @@
namespace pyston { namespace pyston {
extern "C" Py_ssize_t _PyObject_LengthHint(PyObject* o, Py_ssize_t defaultvalue) noexcept { extern "C" Py_ssize_t _PyObject_LengthHint(PyObject* o, Py_ssize_t defaultvalue) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); static PyObject* hintstrobj = NULL;
return -1; PyObject* ro, *hintmeth;
Py_ssize_t rv;
/* try o.__len__() */
rv = PyObject_Size(o);
if (rv >= 0)
return rv;
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear();
}
if (PyInstance_Check(o))
return defaultvalue;
/* try o.__length_hint__() */
hintmeth = _PyObject_LookupSpecial(o, "__length_hint__", &hintstrobj);
if (hintmeth == NULL) {
if (PyErr_Occurred())
return -1;
else
return defaultvalue;
}
ro = PyObject_CallFunctionObjArgs(hintmeth, NULL);
Py_DECREF(hintmeth);
if (ro == NULL) {
if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear();
return defaultvalue;
}
rv = PyNumber_Check(ro) ? PyInt_AsSsize_t(ro) : defaultvalue;
Py_DECREF(ro);
return rv;
} }
static int _IsFortranContiguous(Py_buffer* view) { static int _IsFortranContiguous(Py_buffer* view) {
...@@ -1126,6 +1159,85 @@ extern "C" int PySequence_Contains(PyObject* seq, PyObject* ob) noexcept { ...@@ -1126,6 +1159,85 @@ extern "C" int PySequence_Contains(PyObject* seq, PyObject* ob) noexcept {
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
} }
extern "C" PyObject* PySequence_Tuple(PyObject* v) noexcept {
PyObject* it; /* iter(v) */
Py_ssize_t n; /* guess for result tuple size */
PyObject* result = NULL;
Py_ssize_t j;
if (v == NULL)
return null_error();
/* Special-case the common tuple and list cases, for efficiency. */
if (PyTuple_CheckExact(v)) {
/* Note that we can't know whether it's safe to return
a tuple *subclass* instance as-is, hence the restriction
to exact tuples here. In contrast, lists always make
a copy, so there's no need for exactness below. */
Py_INCREF(v);
return v;
}
if (PyList_Check(v))
return PyList_AsTuple(v);
/* Get iterator. */
it = PyObject_GetIter(v);
if (it == NULL)
return NULL;
/* Guess result size and allocate space. */
n = _PyObject_LengthHint(v, 10);
if (n == -1)
goto Fail;
result = PyTuple_New(n);
if (result == NULL)
goto Fail;
/* Fill the tuple. */
for (j = 0;; ++j) {
PyObject* item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto Fail;
break;
}
if (j >= n) {
Py_ssize_t oldn = n;
/* The over-allocation strategy can grow a bit faster
than for lists because unlike lists the
over-allocation isn't permanent -- we reclaim
the excess before the end of this routine.
So, grow by ten and then add 25%.
*/
n += 10;
n += n >> 2;
if (n < oldn) {
/* Check for overflow */
PyErr_NoMemory();
Py_DECREF(item);
goto Fail;
}
if (_PyTuple_Resize(&result, n) != 0) {
Py_DECREF(item);
goto Fail;
}
}
PyTuple_SET_ITEM(result, j, item);
}
/* Cut tuple back if guess was too large. */
if (j < n && _PyTuple_Resize(&result, j) != 0)
goto Fail;
Py_DECREF(it);
return result;
Fail:
Py_XDECREF(result);
Py_DECREF(it);
return NULL;
}
extern "C" PyObject* PyObject_CallFunction(PyObject* callable, const char* format, ...) noexcept { extern "C" PyObject* PyObject_CallFunction(PyObject* callable, const char* format, ...) noexcept {
va_list va; va_list va;
PyObject* args; PyObject* args;
...@@ -1318,14 +1430,20 @@ extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) noexcept { ...@@ -1318,14 +1430,20 @@ extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) noexcept {
} }
} }
extern "C" PyObject* PyNumber_Xor(PyObject*, PyObject*) noexcept { extern "C" PyObject* PyNumber_Xor(PyObject* lhs, PyObject* rhs) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); try {
return nullptr; return binop(lhs, rhs, AST_TYPE::BitXor);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
} }
extern "C" PyObject* PyNumber_Or(PyObject*, PyObject*) noexcept { extern "C" PyObject* PyNumber_Or(PyObject* lhs, PyObject* rhs) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); try {
return nullptr; return binop(lhs, rhs, AST_TYPE::BitOr);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
} }
extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) noexcept { extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) noexcept {
......
...@@ -381,8 +381,29 @@ extern "C" PyObject* Py_BuildValue(const char* fmt, ...) noexcept { ...@@ -381,8 +381,29 @@ extern "C" PyObject* Py_BuildValue(const char* fmt, ...) noexcept {
return r; return r;
} }
extern "C" {
char* _Py_PackageContext = NULL;
}
extern "C" PyObject* Py_InitModule4(const char* name, PyMethodDef* methods, const char* doc, PyObject* self, extern "C" PyObject* Py_InitModule4(const char* name, PyMethodDef* methods, const char* doc, PyObject* self,
int apiver) noexcept { int apiver) noexcept {
// Comment from CPython:
/* Make sure name is fully qualified.
This is a bit of a hack: when the shared library is loaded,
the module name is "package.module", but the module calls
Py_InitModule*() with just "module" for the name. The shared
library loader squirrels away the true name of the module in
_Py_PackageContext, and Py_InitModule*() will substitute this
(if the name actually matches).
*/
if (_Py_PackageContext != NULL) {
const char* p = strrchr(_Py_PackageContext, '.');
if (p != NULL && strcmp(name, p + 1) == 0) {
name = _Py_PackageContext;
_Py_PackageContext = NULL;
}
}
BoxedModule* module = createModule(name, "__builtin__", doc); BoxedModule* module = createModule(name, "__builtin__", doc);
// Pass self as is, even if NULL we are not allowed to change it to None // Pass self as is, even if NULL we are not allowed to change it to None
......
...@@ -64,7 +64,7 @@ union Value { ...@@ -64,7 +64,7 @@ union Value {
Value(double d) : d(d) {} Value(double d) : d(d) {}
Value(Box* o) : o(o) { Value(Box* o) : o(o) {
if (DEBUG >= 2) if (DEBUG >= 2)
assert(gc::isValidGCObject(o)); ASSERT(gc::isValidGCObject(o), "%p", o);
} }
}; };
...@@ -532,8 +532,15 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) { ...@@ -532,8 +532,15 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
CompiledFunction* partial_func = compilePartialFuncInternal(&exit); CompiledFunction* partial_func = compilePartialFuncInternal(&exit);
auto arg_tuple = getTupleFromArgsArray(&arg_array[0], arg_array.size()); auto arg_tuple = getTupleFromArgsArray(&arg_array[0], arg_array.size());
return partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple), Box* r = partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple),
std::get<3>(arg_tuple)); std::get<3>(arg_tuple));
// This is one of the few times that we are allowed to have an invalid value in a Box* Value.
// Check for it, and return as an int so that we don't trigger a potential assert when
// creating the Value.
if (compiled_func->getReturnType() != VOID)
assert(r);
return (intptr_t)r;
} }
} }
...@@ -859,13 +866,18 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -859,13 +866,18 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
continue; continue;
} else if (vst == ScopeInfo::VarScopeType::NAME) { } else if (vst == ScopeInfo::VarScopeType::NAME) {
assert(frame_info.boxedLocals != NULL); assert(frame_info.boxedLocals != NULL);
assert(frame_info.boxedLocals->cls == dict_cls); if (frame_info.boxedLocals->cls == dict_cls) {
auto& d = static_cast<BoxedDict*>(frame_info.boxedLocals)->d; auto& d = static_cast<BoxedDict*>(frame_info.boxedLocals)->d;
auto it = d.find(boxString(target->id.str())); auto it = d.find(boxString(target->id.str()));
if (it == d.end()) { if (it == d.end()) {
assertNameDefined(0, target->id.c_str(), NameError, false /* local_var_msg */); assertNameDefined(0, target->id.c_str(), NameError, false /* local_var_msg */);
}
d.erase(it);
} else if (frame_info.boxedLocals->cls == attrwrapper_cls) {
attrwrapperDel(frame_info.boxedLocals, target->id.str());
} else {
RELEASE_ASSERT(0, "%s", frame_info.boxedLocals->cls->tp_name);
} }
d.erase(it);
} else { } else {
assert(vst == ScopeInfo::VarScopeType::FAST); assert(vst == ScopeInfo::VarScopeType::FAST);
......
...@@ -382,7 +382,17 @@ Box* eval(Box* boxedCode) { ...@@ -382,7 +382,17 @@ Box* eval(Box* boxedCode) {
// TODO this memory leaks // TODO this memory leaks
RELEASE_ASSERT(boxedCode->cls == str_cls, "%s", boxedCode->cls->tp_name); RELEASE_ASSERT(boxedCode->cls == str_cls, "%s", boxedCode->cls->tp_name);
const char* code = static_cast<BoxedString*>(boxedCode)->s.data(); const char* code = static_cast<BoxedString*>(boxedCode)->s.data();
// Hack: we need to support things like `eval(" 2")`.
// This is over-accepting since it will accept things like `eval("\n 2")`
while (*code == ' ' || *code == '\t' || *code == '\n' || *code == '\r')
code++;
AST_Module* parsedModule = parse_string(code); AST_Module* parsedModule = parse_string(code);
if (parsedModule->body.size() == 0)
raiseSyntaxError("unexpected EOF while parsing", 0, 0, "<string>", "");
RELEASE_ASSERT(parsedModule->body.size() == 1, "");
RELEASE_ASSERT(parsedModule->body[0]->type == AST_TYPE::Expr, ""); RELEASE_ASSERT(parsedModule->body[0]->type == AST_TYPE::Expr, "");
AST_Expression* parsedExpr = new AST_Expression(std::move(parsedModule->interned_strings)); AST_Expression* parsedExpr = new AST_Expression(std::move(parsedModule->interned_strings));
parsedExpr->body = static_cast<AST_Expr*>(parsedModule->body[0])->value; parsedExpr->body = static_cast<AST_Expr*>(parsedModule->body[0])->value;
......
...@@ -985,7 +985,9 @@ AST_Module* parse_file(const char* fn) { ...@@ -985,7 +985,9 @@ AST_Module* parse_file(const char* fn) {
Timer _t("parsing"); Timer _t("parsing");
if (ENABLE_PYPA_PARSER) { if (ENABLE_PYPA_PARSER) {
return pypa_parse(fn); AST_Module* rtn = pypa_parse(fn);
assert(rtn);
return rtn;
} }
FILE* fp = popen(getParserCommandLine(fn).c_str(), "r"); FILE* fp = popen(getParserCommandLine(fn).c_str(), "r");
......
...@@ -699,7 +699,7 @@ FrameStackState getFrameStackState() { ...@@ -699,7 +699,7 @@ FrameStackState getFrameStackState() {
Box* v = e.type->deserializeFromFrame(vals); Box* v = e.type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first.c_str(), e._debug_pp_id, v); // printf("%s: (pp id %ld) %p\n", p.first.c_str(), e._debug_pp_id, v);
assert(gc::isValidGCObject(v)); ASSERT(gc::isValidGCObject(v), "%p", v);
d->d[boxString(p.first)] = v; d->d[boxString(p.first)] = v;
} }
} }
......
...@@ -591,4 +591,9 @@ struct CallattrFlags { ...@@ -591,4 +591,9 @@ struct CallattrFlags {
}; };
} }
namespace std {
template <> std::pair<pyston::Box**, std::ptrdiff_t> get_temporary_buffer<pyston::Box*>(std::ptrdiff_t count) noexcept;
template <> void return_temporary_buffer<pyston::Box*>(pyston::Box** p);
}
#endif #endif
...@@ -30,6 +30,16 @@ ...@@ -30,6 +30,16 @@
//#undef VERBOSITY //#undef VERBOSITY
//#define VERBOSITY(x) 2 //#define VERBOSITY(x) 2
namespace std {
template <> std::pair<pyston::Box**, std::ptrdiff_t> get_temporary_buffer<pyston::Box*>(std::ptrdiff_t count) noexcept {
void* r = pyston::gc::gc_alloc(sizeof(pyston::Box*) * count, pyston::gc::GCKind::CONSERVATIVE);
return std::make_pair((pyston::Box**)r, count);
}
template <> void return_temporary_buffer<pyston::Box*>(pyston::Box** p) {
pyston::gc::gc_free(p);
}
}
namespace pyston { namespace pyston {
namespace gc { namespace gc {
......
...@@ -56,15 +56,31 @@ extern void setEncodingAndErrors(); ...@@ -56,15 +56,31 @@ extern void setEncodingAndErrors();
// return code in `*retcode`. does not touch `*retcode* if it returns false. // return code in `*retcode`. does not touch `*retcode* if it returns false.
static bool handle_toplevel_exn(const ExcInfo& e, int* retcode) { static bool handle_toplevel_exn(const ExcInfo& e, int* retcode) {
if (e.matches(SystemExit)) { if (e.matches(SystemExit)) {
Box* code = e.value->getattr("code"); Box* value = e.value;
if (!code || code == None) if (value && PyExceptionInstance_Check(value)) {
Box* code = getattr(value, "code");
if (code)
value = code;
}
if (!value || value == None)
*retcode = 0; *retcode = 0;
else if (isSubclass(code->cls, int_cls)) else if (isSubclass(value->cls, int_cls))
*retcode = static_cast<BoxedInt*>(code)->n; *retcode = static_cast<BoxedInt*>(value)->n;
else else {
*retcode = 1; *retcode = 1;
PyObject* sys_stderr = PySys_GetObject("stderr");
if (sys_stderr != NULL && sys_stderr != Py_None) {
PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
} else {
PyObject_Print(value, stderr, Py_PRINT_RAW);
fflush(stderr);
}
PySys_WriteStderr("\n");
}
return true; return true;
} }
e.printExcAndTraceback(); e.printExcAndTraceback();
...@@ -82,7 +98,10 @@ static int main(int argc, char** argv) { ...@@ -82,7 +98,10 @@ static int main(int argc, char** argv) {
bool stats = false; bool stats = false;
bool unbuffered = false; bool unbuffered = false;
const char* command = NULL; const char* command = NULL;
while ((code = getopt(argc, argv, "+OqdIibpjtrsSvnxc:FuP")) != -1) {
// Suppress getopt errors so we can throw them ourselves
opterr = 0;
while ((code = getopt(argc, argv, "+:OqdIibpjtrsSvnxEc:FuP")) != -1) {
if (code == 'O') if (code == 'O')
FORCE_OPTIMIZE = true; FORCE_OPTIMIZE = true;
else if (code == 't') else if (code == 't')
...@@ -115,16 +134,31 @@ static int main(int argc, char** argv) { ...@@ -115,16 +134,31 @@ static int main(int argc, char** argv) {
USE_REGALLOC_BASIC = false; USE_REGALLOC_BASIC = false;
} else if (code == 'x') { } else if (code == 'x') {
ENABLE_PYPA_PARSER = false; ENABLE_PYPA_PARSER = false;
} else if (code == 'E') {
Py_IgnoreEnvironmentFlag = 1;
} else if (code == 'P') { } else if (code == 'P') {
PAUSE_AT_ABORT = true; PAUSE_AT_ABORT = true;
} else if (code == 'F') { } else if (code == 'F') {
CONTINUE_AFTER_FATAL = true; CONTINUE_AFTER_FATAL = true;
} else if (code == 'c') { } else if (code == 'c') {
assert(optarg);
command = optarg; command = optarg;
// no more option parsing; the rest of our arguments go into sys.argv. // no more option parsing; the rest of our arguments go into sys.argv.
break; break;
} else } else {
if (code == ':') {
fprintf(stderr, "Argument expected for the -%c option\n", optopt);
return 2;
}
if (code == '?') {
fprintf(stderr, "Unknown option: -%c\n", optopt);
return 2;
}
fprintf(stderr, "Unknown getopt() error. '%c' '%c'\n", code, optopt);
abort(); abort();
}
} }
const char* fn = NULL; const char* fn = NULL;
......
...@@ -258,11 +258,16 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept ...@@ -258,11 +258,16 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept
} }
extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept { extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept {
Box* r = getattrInternalGeneric(o, static_cast<BoxedString*>(name)->data(), NULL, false, false, NULL, NULL); try {
if (!r) Box* r = getattrInternalGeneric(o, static_cast<BoxedString*>(name)->s.data(), NULL, false, false, NULL, NULL);
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, if (!r)
PyString_AS_STRING(name)); PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
return r; PyString_AS_STRING(name));
return r;
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} }
extern "C" PyObject* _PyObject_GenericGetAttrWithDict(PyObject* obj, PyObject* name, PyObject* dict) noexcept { extern "C" PyObject* _PyObject_GenericGetAttrWithDict(PyObject* obj, PyObject* name, PyObject* dict) noexcept {
...@@ -399,7 +404,6 @@ extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, Py ...@@ -399,7 +404,6 @@ extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, Py
extern "C" int PyObject_GetBuffer(PyObject* obj, Py_buffer* view, int flags) noexcept { extern "C" int PyObject_GetBuffer(PyObject* obj, Py_buffer* view, int flags) noexcept {
if (!PyObject_CheckBuffer(obj)) { if (!PyObject_CheckBuffer(obj)) {
printf("%s\n", obj->cls->tp_name);
PyErr_Format(PyExc_TypeError, "'%100s' does not have the buffer interface", Py_TYPE(obj)->tp_name); PyErr_Format(PyExc_TypeError, "'%100s' does not have the buffer interface", Py_TYPE(obj)->tp_name);
return -1; return -1;
} }
...@@ -520,16 +524,6 @@ extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) noexcept { ...@@ -520,16 +524,6 @@ extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) noexcept {
return -1; return -1;
} }
extern "C" PyObject* PySequence_Tuple(PyObject* o) noexcept {
if (o->cls == tuple_cls)
return o;
if (PyList_Check(o))
return PyList_AsTuple(o);
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
}
extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept { extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept {
try { try {
Box* hasnext = iter->hasnextOrNullIC(); Box* hasnext = iter->hasnextOrNullIC();
...@@ -1239,6 +1233,14 @@ extern "C" PyObject* PyCFunction_NewEx(PyMethodDef* ml, PyObject* self, PyObject ...@@ -1239,6 +1233,14 @@ extern "C" PyObject* PyCFunction_NewEx(PyMethodDef* ml, PyObject* self, PyObject
return new BoxedCApiFunction(ml->ml_flags, self, ml->ml_name, ml->ml_meth); return new BoxedCApiFunction(ml->ml_flags, self, ml->ml_name, ml->ml_meth);
} }
extern "C" PyCFunction PyCFunction_GetFunction(PyObject* op) noexcept {
if (!PyCFunction_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyCFunctionObject*)op)->m_ml->ml_meth;
}
extern "C" int _PyEval_SliceIndex(PyObject* v, Py_ssize_t* pi) noexcept { extern "C" int _PyEval_SliceIndex(PyObject* v, Py_ssize_t* pi) noexcept {
if (v != NULL) { if (v != NULL) {
Py_ssize_t x; Py_ssize_t x;
...@@ -1278,6 +1280,7 @@ extern "C" char* PyModule_GetName(PyObject* m) noexcept { ...@@ -1278,6 +1280,7 @@ extern "C" char* PyModule_GetName(PyObject* m) noexcept {
BoxedModule* importCExtension(const std::string& full_name, const std::string& last_name, const std::string& path) { BoxedModule* importCExtension(const std::string& full_name, const std::string& last_name, const std::string& path) {
void* handle = dlopen(path.c_str(), RTLD_NOW); void* handle = dlopen(path.c_str(), RTLD_NOW);
if (!handle) { if (!handle) {
// raiseExcHelper(ImportError, "%s", dlerror());
fprintf(stderr, "%s\n", dlerror()); fprintf(stderr, "%s\n", dlerror());
exit(1); exit(1);
} }
...@@ -1288,17 +1291,26 @@ BoxedModule* importCExtension(const std::string& full_name, const std::string& l ...@@ -1288,17 +1291,26 @@ BoxedModule* importCExtension(const std::string& full_name, const std::string& l
char* error; char* error;
if ((error = dlerror()) != NULL) { if ((error = dlerror()) != NULL) {
// raiseExcHelper(ImportError, "%s", error);
fprintf(stderr, "%s\n", error); fprintf(stderr, "%s\n", error);
exit(1); exit(1);
} }
assert(init); assert(init);
char* packagecontext = strdup(full_name.c_str());
char* oldcontext = _Py_PackageContext;
_Py_PackageContext = packagecontext;
(*init)(); (*init)();
_Py_PackageContext = oldcontext;
free(packagecontext);
checkAndThrowCAPIException();
BoxedDict* sys_modules = getSysModulesDict(); BoxedDict* sys_modules = getSysModulesDict();
Box* s = boxStrConstant(full_name.c_str()); Box* s = boxStrConstant(full_name.c_str());
Box* _m = sys_modules->d[s]; Box* _m = sys_modules->d[s];
RELEASE_ASSERT(_m, "module failed to initialize properly?"); RELEASE_ASSERT(_m, "dynamic module not initialized properly");
assert(_m->cls == module_cls); assert(_m->cls == module_cls);
BoxedModule* m = static_cast<BoxedModule*>(_m); BoxedModule* m = static_cast<BoxedModule*>(_m);
......
...@@ -480,7 +480,15 @@ static PyObject* file_write(BoxedFile* f, Box* arg) noexcept { ...@@ -480,7 +480,15 @@ static PyObject* file_write(BoxedFile* f, Box* arg) noexcept {
if (!f->writable) if (!f->writable)
return err_mode("writing"); return err_mode("writing");
if (f->f_binary) { if (f->f_binary) {
if (PyObject_GetBuffer(arg, &pbuf, 0)) // In CPython, this branch calls PyArg_ParseTuple for all types, but we never created
// the "args" tuple so we have to do some of the work that ParseTuple does.
// Mostly it's easy since we've already unpacked the args, but there is some unicode-specific
// code in it that is better not to duplicate.
// So, if it's unicode, just make the tuple for now and send it through PyArg_ParseTuple.
if (PyUnicode_Check(arg)) {
if (!PyArg_ParseTuple(BoxedTuple::create({ arg }), "s*", &pbuf))
return NULL;
} else if (PyObject_GetBuffer(arg, &pbuf, 0))
return NULL; return NULL;
s = (const char*)pbuf.buf; s = (const char*)pbuf.buf;
...@@ -537,6 +545,124 @@ static PyObject* file_write(BoxedFile* f, Box* arg) noexcept { ...@@ -537,6 +545,124 @@ static PyObject* file_write(BoxedFile* f, Box* arg) noexcept {
return Py_None; return Py_None;
} }
static PyObject* file_writelines(BoxedFile* f, PyObject* seq) noexcept {
#define CHUNKSIZE 1000
PyObject* list, *line;
PyObject* it; /* iter(seq) */
PyObject* result;
int index, islist;
Py_ssize_t i, j, nwritten, len;
assert(seq != NULL);
if (f->f_fp == NULL)
return err_closed();
if (!f->writable)
return err_mode("writing");
result = NULL;
list = NULL;
islist = PyList_Check(seq);
if (islist)
it = NULL;
else {
it = PyObject_GetIter(seq);
if (it == NULL) {
PyErr_SetString(PyExc_TypeError, "writelines() requires an iterable argument");
return NULL;
}
/* From here on, fail by going to error, to reclaim "it". */
list = PyList_New(CHUNKSIZE);
if (list == NULL)
goto error;
}
/* Strategy: slurp CHUNKSIZE lines into a private list,
checking that they are all strings, then write that list
without holding the interpreter lock, then come back for more. */
for (index = 0;; index += CHUNKSIZE) {
if (islist) {
Py_XDECREF(list);
list = PyList_GetSlice(seq, index, index + CHUNKSIZE);
if (list == NULL)
goto error;
j = PyList_GET_SIZE(list);
} else {
for (j = 0; j < CHUNKSIZE; j++) {
line = PyIter_Next(it);
if (line == NULL) {
if (PyErr_Occurred())
goto error;
break;
}
PyList_SetItem(list, j, line);
}
/* The iterator might have closed the file on us. */
if (f->f_fp == NULL) {
err_closed();
goto error;
}
}
if (j == 0)
break;
/* Check that all entries are indeed strings. If not,
apply the same rules as for file.write() and
convert the results to strings. This is slow, but
seems to be the only way since all conversion APIs
could potentially execute Python code. */
for (i = 0; i < j; i++) {
PyObject* v = PyList_GET_ITEM(list, i);
if (!PyString_Check(v)) {
const char* buffer;
int res;
if (f->f_binary) {
res = PyObject_AsReadBuffer(v, (const void**)&buffer, &len);
} else {
res = PyObject_AsCharBuffer(v, &buffer, &len);
}
if (res) {
PyErr_SetString(PyExc_TypeError, "writelines() argument must be a sequence of strings");
goto error;
}
line = PyString_FromStringAndSize(buffer, len);
if (line == NULL)
goto error;
Py_DECREF(v);
PyList_SET_ITEM(list, i, line);
}
}
/* Since we are releasing the global lock, the
following code may *not* execute Python code. */
f->f_softspace = 0;
FILE_BEGIN_ALLOW_THREADS(f)
errno = 0;
for (i = 0; i < j; i++) {
line = PyList_GET_ITEM(list, i);
len = PyString_GET_SIZE(line);
nwritten = fwrite(PyString_AS_STRING(line), 1, len, f->f_fp);
if (nwritten != len) {
FILE_ABORT_ALLOW_THREADS(f)
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
goto error;
}
}
FILE_END_ALLOW_THREADS(f)
if (j < CHUNKSIZE)
break;
}
Py_INCREF(Py_None);
result = Py_None;
error:
Py_XDECREF(list);
Py_XDECREF(it);
return result;
#undef CHUNKSIZE
}
Box* fileWrite(BoxedFile* self, Box* val) { Box* fileWrite(BoxedFile* self, Box* val) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
...@@ -1469,6 +1595,7 @@ PyDoc_STRVAR(isatty_doc, "isatty() -> true or false. True if the file is connec ...@@ -1469,6 +1595,7 @@ PyDoc_STRVAR(isatty_doc, "isatty() -> true or false. True if the file is connec
PyMethodDef file_methods[] = { PyMethodDef file_methods[] = {
{ "seek", (PyCFunction)file_seek, METH_VARARGS, seek_doc }, { "seek", (PyCFunction)file_seek, METH_VARARGS, seek_doc },
{ "readlines", (PyCFunction)file_readlines, METH_VARARGS, readlines_doc }, { "readlines", (PyCFunction)file_readlines, METH_VARARGS, readlines_doc },
{ "writelines", (PyCFunction)file_writelines, METH_O, NULL },
{ "isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc }, { "isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc },
}; };
......
...@@ -27,6 +27,10 @@ extern "C" PyObject* PyFloat_FromDouble(double d) noexcept { ...@@ -27,6 +27,10 @@ extern "C" PyObject* PyFloat_FromDouble(double d) noexcept {
return boxFloat(d); return boxFloat(d);
} }
extern "C" PyObject* PyFloat_FromString(PyObject* v, char** pend) noexcept {
Py_FatalError("unimplemented");
}
extern "C" double PyFloat_AsDouble(PyObject* o) noexcept { extern "C" double PyFloat_AsDouble(PyObject* o) noexcept {
if (o->cls == float_cls) if (o->cls == float_cls)
return static_cast<BoxedFloat*>(o)->d; return static_cast<BoxedFloat*>(o)->d;
......
...@@ -274,7 +274,14 @@ static Box* getParent(Box* globals, int level, std::string& buf) { ...@@ -274,7 +274,14 @@ static Box* getParent(Box* globals, int level, std::string& buf) {
if (modname == NULL || modname->cls != str_cls) if (modname == NULL || modname->cls != str_cls)
return None; return None;
Box* modpath = getattrInternal(globals, path_str, NULL); Box* modpath = NULL;
try {
modpath = getattrInternal(globals, path_str, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
raiseRaw(e);
}
if (modpath != NULL) { if (modpath != NULL) {
/* __path__ is set, so modname is already the package name */ /* __path__ is set, so modname is already the package name */
if (modname->size() > PATH_MAX) { if (modname->size() > PATH_MAX) {
...@@ -516,7 +523,15 @@ extern "C" PyObject* PyImport_ImportModuleLevel(const char* name, PyObject* glob ...@@ -516,7 +523,15 @@ extern "C" PyObject* PyImport_ImportModuleLevel(const char* name, PyObject* glob
} }
static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool recursive) { static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool recursive) {
if (getattrInternal(module, path_str, NULL) == NULL) { Box* pathlist = NULL;
try {
pathlist = getattrInternal(module, path_str, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
raiseRaw(e);
}
if (pathlist == NULL) {
// If it's not a package, then there's no sub-importing to do // If it's not a package, then there's no sub-importing to do
return; return;
} }
......
...@@ -246,6 +246,138 @@ static void sliceIndex(Box* b, int64_t* out) { ...@@ -246,6 +246,138 @@ static void sliceIndex(Box* b, int64_t* out) {
*out = static_cast<BoxedInt*>(b)->n; *out = static_cast<BoxedInt*>(b)->n;
} }
// Copied from CPython's list_ass_subscript
int list_ass_ext_slice(BoxedList* self, PyObject* item, PyObject* value) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) {
return -1;
}
RELEASE_ASSERT(step != 1, "should have handled this elsewhere");
// if (step == 1)
// return list_ass_slice(self, start, stop, value);
/* Make sure s[5:2] = [..] inserts at the right place:
before 5, not before 2. */
if ((step < 0 && start < stop) || (step > 0 && start > stop))
stop = start;
if (value == NULL) {
/* delete slice */
PyObject** garbage;
size_t cur;
Py_ssize_t i;
if (slicelength <= 0)
return 0;
if (step < 0) {
stop = start + 1;
start = stop + step * (slicelength - 1) - 1;
step = -step;
}
assert((size_t)slicelength <= PY_SIZE_MAX / sizeof(PyObject*));
garbage = (PyObject**)PyMem_MALLOC(slicelength * sizeof(PyObject*));
if (!garbage) {
PyErr_NoMemory();
return -1;
}
/* drawing pictures might help understand these for
loops. Basically, we memmove the parts of the
list that are *not* part of the slice: step-1
items for each item that is part of the slice,
and then tail end of the list that was not
covered by the slice */
for (cur = start, i = 0; cur < (size_t)stop; cur += step, i++) {
Py_ssize_t lim = step - 1;
garbage[i] = PyList_GET_ITEM(self, cur);
if (cur + step >= self->size) {
lim = self->size - cur - 1;
}
memmove(self->elts->elts + cur - i, self->elts->elts + cur + 1, lim * sizeof(PyObject*));
}
cur = start + slicelength * step;
if (cur < self->size) {
memmove(self->elts->elts + cur - slicelength, self->elts->elts + cur,
(self->size - cur) * sizeof(PyObject*));
}
self->size -= slicelength;
// list_resize(self, Py_SIZE(self));
for (i = 0; i < slicelength; i++) {
Py_DECREF(garbage[i]);
}
PyMem_FREE(garbage);
return 0;
} else {
/* assign slice */
PyObject* ins, *seq;
PyObject** garbage, **seqitems, **selfitems;
Py_ssize_t cur, i;
/* protect against a[::-1] = a */
if (self == value) {
abort();
// seq = list_slice((PyListObject*)value, 0,
// PyList_GET_SIZE(value));
} else {
seq = PySequence_Fast(value, "must assign iterable "
"to extended slice");
}
if (!seq)
return -1;
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
PyErr_Format(PyExc_ValueError, "attempt to assign sequence of "
"size %zd to extended slice of "
"size %zd",
PySequence_Fast_GET_SIZE(seq), slicelength);
Py_DECREF(seq);
return -1;
}
if (!slicelength) {
Py_DECREF(seq);
return 0;
}
garbage = (PyObject**)PyMem_MALLOC(slicelength * sizeof(PyObject*));
if (!garbage) {
Py_DECREF(seq);
PyErr_NoMemory();
return -1;
}
selfitems = self->elts->elts;
seqitems = PySequence_Fast_ITEMS(seq);
for (cur = start, i = 0; i < slicelength; cur += step, i++) {
garbage[i] = selfitems[cur];
ins = seqitems[i];
Py_INCREF(ins);
selfitems[cur] = ins;
}
for (i = 0; i < slicelength; i++) {
Py_DECREF(garbage[i]);
}
PyMem_FREE(garbage);
Py_DECREF(seq);
return 0;
}
}
extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
LOCK_REGION(self->lock.asWrite()); LOCK_REGION(self->lock.asWrite());
...@@ -258,6 +390,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { ...@@ -258,6 +390,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
sliceIndex(slice->stop, &stop); sliceIndex(slice->stop, &stop);
sliceIndex(slice->step, &step); sliceIndex(slice->step, &step);
if (step != 1) {
int r = list_ass_ext_slice(self, slice, v);
if (r)
throwCAPIException();
return None;
}
RELEASE_ASSERT(step == 1, "step sizes must be 1 for now"); RELEASE_ASSERT(step == 1, "step sizes must be 1 for now");
// Logic from PySequence_GetSlice: // Logic from PySequence_GetSlice:
...@@ -566,6 +704,18 @@ extern "C" int PyList_Sort(PyObject* v) noexcept { ...@@ -566,6 +704,18 @@ extern "C" int PyList_Sort(PyObject* v) noexcept {
return 0; return 0;
} }
extern "C" Box* PyList_GetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
assert(isSubclass(a->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(a);
try {
// Lots of extra copies here; we can do better if we need to:
return listGetitemSlice(self, new BoxedSlice(boxInt(ilow), boxInt(ihigh), boxInt(1)));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
Box* listContains(BoxedList* self, Box* elt) { Box* listContains(BoxedList* self, Box* elt) {
LOCK_REGION(self->lock.asRead()); LOCK_REGION(self->lock.asRead());
...@@ -775,6 +925,46 @@ Box* listNe(BoxedList* self, Box* rhs) { ...@@ -775,6 +925,46 @@ Box* listNe(BoxedList* self, Box* rhs) {
return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::NotEq); return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::NotEq);
} }
Box* listLt(BoxedList* self, Box* rhs) {
if (rhs->cls != list_cls) {
return NotImplemented;
}
LOCK_REGION(self->lock.asRead());
return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::Lt);
}
Box* listLe(BoxedList* self, Box* rhs) {
if (rhs->cls != list_cls) {
return NotImplemented;
}
LOCK_REGION(self->lock.asRead());
return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::LtE);
}
Box* listGt(BoxedList* self, Box* rhs) {
if (rhs->cls != list_cls) {
return NotImplemented;
}
LOCK_REGION(self->lock.asRead());
return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::Gt);
}
Box* listGe(BoxedList* self, Box* rhs) {
if (rhs->cls != list_cls) {
return NotImplemented;
}
LOCK_REGION(self->lock.asRead());
return _listCmp(self, static_cast<BoxedList*>(rhs), AST_TYPE::GtE);
}
extern "C" PyObject* _PyList_Extend(PyListObject* self, PyObject* b) noexcept { extern "C" PyObject* _PyList_Extend(PyListObject* self, PyObject* b) noexcept {
BoxedList* l = (BoxedList*)self; BoxedList* l = (BoxedList*)self;
assert(isSubclass(l->cls, list_cls)); assert(isSubclass(l->cls, list_cls));
...@@ -831,6 +1021,10 @@ void setupList() { ...@@ -831,6 +1021,10 @@ void setupList() {
list_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)listEq, UNKNOWN, 2))); list_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)listEq, UNKNOWN, 2)));
list_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)listNe, UNKNOWN, 2))); list_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)listNe, UNKNOWN, 2)));
list_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)listLt, UNKNOWN, 2)));
list_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)listLe, UNKNOWN, 2)));
list_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)listGt, UNKNOWN, 2)));
list_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)listGe, UNKNOWN, 2)));
list_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)listRepr, STR, 1))); list_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)listRepr, STR, 1)));
list_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)listNonzero, BOXED_BOOL, 1))); list_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)listNonzero, BOXED_BOOL, 1)));
......
...@@ -1579,7 +1579,6 @@ Box* getattrInternalGeneric(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1579,7 +1579,6 @@ Box* getattrInternalGeneric(Box* obj, const std::string& attr, GetattrRewriteArg
return getattrInternalEx(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call, return getattrInternalEx(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call,
bind_obj_out, NULL); bind_obj_out, NULL);
} }
// Finally, check __getattr__
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
...@@ -2160,7 +2159,7 @@ extern "C" i64 unboxedLen(Box* obj) { ...@@ -2160,7 +2159,7 @@ extern "C" i64 unboxedLen(Box* obj) {
return rtn; return rtn;
} }
extern "C" void dump(void* p) { extern "C" void dumpEx(void* p, int levels) {
printf("\n"); printf("\n");
printf("Raw address: %p\n", p); printf("Raw address: %p\n", p);
...@@ -2233,7 +2232,32 @@ extern "C" void dump(void* p) { ...@@ -2233,7 +2232,32 @@ extern "C" void dump(void* p) {
} }
if (isSubclass(b->cls, tuple_cls)) { if (isSubclass(b->cls, tuple_cls)) {
printf("%ld elements\n", static_cast<BoxedTuple*>(b)->size()); BoxedTuple* t = static_cast<BoxedTuple*>(b);
printf("%ld elements\n", t->size());
if (levels > 0) {
int i = 0;
for (auto e : *t) {
printf("\nElement %d:", i);
i++;
dumpEx(e, levels - 1);
}
}
}
if (isSubclass(b->cls, dict_cls)) {
BoxedDict* d = static_cast<BoxedDict*>(b);
printf("%ld elements\n", d->d.size());
if (levels > 0) {
int i = 0;
for (auto t : d->d) {
printf("\nKey:");
dumpEx(t.first, levels - 1);
printf("Value:");
dumpEx(t.second, levels - 1);
}
}
} }
if (isSubclass(b->cls, int_cls)) { if (isSubclass(b->cls, int_cls)) {
...@@ -2269,6 +2293,10 @@ extern "C" void dump(void* p) { ...@@ -2269,6 +2293,10 @@ extern "C" void dump(void* p) {
RELEASE_ASSERT(0, "%d", (int)al->kind_id); RELEASE_ASSERT(0, "%d", (int)al->kind_id);
} }
extern "C" void dump(void* p) {
dumpEx(p, 0);
}
// For rewriting purposes, this function assumes that nargs will be constant. // For rewriting purposes, this function assumes that nargs will be constant.
// That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand. // That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand.
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args, extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args,
...@@ -2441,7 +2469,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -2441,7 +2469,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
extern "C" Box* callattr(Box* obj, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec, Box* arg1, extern "C" Box* callattr(Box* obj, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) { Box* arg2, Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
assert(gc::isValidGCObject(obj)); ASSERT(gc::isValidGCObject(obj), "%p", obj);
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
...@@ -4381,11 +4409,7 @@ extern "C" Box* getGlobal(Box* globals, const std::string* name) { ...@@ -4381,11 +4409,7 @@ extern "C" Box* getGlobal(Box* globals, const std::string* name) {
} }
extern "C" Box* importFrom(Box* _m, const std::string* name) { extern "C" Box* importFrom(Box* _m, const std::string* name) {
assert(isSubclass(_m->cls, module_cls)); Box* r = getattrInternal(_m, *name, NULL);
BoxedModule* m = static_cast<BoxedModule*>(_m);
Box* r = getattrInternal(m, *name, NULL);
if (r) if (r)
return r; return r;
......
...@@ -94,6 +94,7 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o); ...@@ -94,6 +94,7 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o);
extern "C" bool hasnext(Box* o); extern "C" bool hasnext(Box* o);
extern "C" void dump(void* p); extern "C" void dump(void* p);
extern "C" void dumpEx(void* p, int levels = 0);
struct SetattrRewriteArgs; struct SetattrRewriteArgs;
void setattrGeneric(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args); void setattrGeneric(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args);
......
...@@ -159,7 +159,8 @@ extern "C" void abort() { ...@@ -159,7 +159,8 @@ extern "C" void abort() {
// In case something calls abort down the line: // In case something calls abort down the line:
static bool recursive = false; static bool recursive = false;
if (!recursive) { // If object_cls is NULL, then we somehow died early on, and won't be able to display a traceback.
if (!recursive && object_cls) {
recursive = true; recursive = true;
fprintf(stderr, "Someone called abort!\n"); fprintf(stderr, "Someone called abort!\n");
......
...@@ -1431,6 +1431,10 @@ Box* attrwrapperKeys(Box* b) { ...@@ -1431,6 +1431,10 @@ Box* attrwrapperKeys(Box* b) {
return AttrWrapper::keys(b); return AttrWrapper::keys(b);
} }
void attrwrapperDel(Box* b, const std::string& attr) {
AttrWrapper::delitem(b, boxString(attr));
}
Box* objectNewNoArgs(BoxedClass* cls) { Box* objectNewNoArgs(BoxedClass* cls) {
assert(isSubclass(cls->cls, type_cls)); assert(isSubclass(cls->cls, type_cls));
assert(typeLookup(cls, "__new__", NULL) == typeLookup(object_cls, "__new__", NULL) assert(typeLookup(cls, "__new__", NULL) == typeLookup(object_cls, "__new__", NULL)
...@@ -2336,13 +2340,21 @@ void setupRuntime() { ...@@ -2336,13 +2340,21 @@ void setupRuntime() {
BoxedModule* createModule(const std::string& name, const std::string& fn, const char* doc) { BoxedModule* createModule(const std::string& name, const std::string& fn, const char* doc) {
assert(fn.size() && "probably wanted to set the fn to <stdin>?"); assert(fn.size() && "probably wanted to set the fn to <stdin>?");
BoxedModule* module = new BoxedModule(name, fn, doc);
BoxedDict* d = getSysModulesDict(); BoxedDict* d = getSysModulesDict();
Box* b_name = boxStringPtr(&name); Box* b_name = boxStringPtr(&name);
ASSERT(d->d.count(b_name) == 0, "%s", name.c_str());
d->d[b_name] = module;
// Surprisingly, there are times that we need to return the existing module if
// one exists:
Box*& ptr = d->d[b_name];
if (ptr && isSubclass(ptr->cls, module_cls)) {
return static_cast<BoxedModule*>(ptr);
} else {
ptr = NULL;
}
BoxedModule* module = new BoxedModule(name, fn, doc);
ptr = module;
return module; return module;
} }
......
...@@ -655,6 +655,10 @@ public: ...@@ -655,6 +655,10 @@ public:
DEFAULT_CLASS_SIMPLE(slice_cls); DEFAULT_CLASS_SIMPLE(slice_cls);
}; };
static_assert(sizeof(BoxedSlice) == sizeof(PySliceObject), "");
static_assert(offsetof(BoxedSlice, start) == offsetof(PySliceObject, start), "");
static_assert(offsetof(BoxedSlice, stop) == offsetof(PySliceObject, stop), "");
static_assert(offsetof(BoxedSlice, step) == offsetof(PySliceObject, step), "");
class BoxedMemberDescriptor : public Box { class BoxedMemberDescriptor : public Box {
public: public:
...@@ -786,6 +790,7 @@ Box* objectSetattr(Box* obj, Box* attr, Box* value); ...@@ -786,6 +790,7 @@ Box* objectSetattr(Box* obj, Box* attr, Box* value);
Box* makeAttrWrapper(Box* b); Box* makeAttrWrapper(Box* b);
Box* unwrapAttrWrapper(Box* b); Box* unwrapAttrWrapper(Box* b);
Box* attrwrapperKeys(Box* b); Box* attrwrapperKeys(Box* b);
void attrwrapperDel(Box* b, const std::string& attr);
#define SystemError ((BoxedClass*)PyExc_SystemError) #define SystemError ((BoxedClass*)PyExc_SystemError)
#define StopIteration ((BoxedClass*)PyExc_StopIteration) #define StopIteration ((BoxedClass*)PyExc_StopIteration)
......
...@@ -7,7 +7,7 @@ with open('/dev/null')as ignore: ...@@ -7,7 +7,7 @@ with open('/dev/null')as ignore:
# We don't (yet?) require exact stderr or return code compatibility w/ # We don't (yet?) require exact stderr or return code compatibility w/
# python. So we just check that we succeed or fail as appropriate. # python. So we just check that we succeed or fail as appropriate.
def run(args): def run(args):
print 0 == subprocess.call([me] + args, stderr=ignore) print subprocess.call([me] + args, stderr=ignore)
run(["-c", "print 2 + 2"]) run(["-c", "print 2 + 2"])
run(["-c", "import sys; print sys.argv", "hello", "world"]) run(["-c", "import sys; print sys.argv", "hello", "world"])
...@@ -16,3 +16,6 @@ with open('/dev/null')as ignore: ...@@ -16,3 +16,6 @@ with open('/dev/null')as ignore:
run(["-c"]) run(["-c"])
run(["-c", "-c"]) run(["-c", "-c"])
run(["-c", "this should not work"]) run(["-c", "this should not work"])
run(["-c", ";"])
run(["-cprint 1"])
# expected: fail
try:
eval("\n 2")
print "bad, should have thrown an exception"
except SyntaxError:
print "good, threw exception"
...@@ -157,3 +157,9 @@ def wrap(): ...@@ -157,3 +157,9 @@ def wrap():
inner2() inner2()
wrap() wrap()
try:
eval(" ")
print "worked?"
except SyntaxError:
pass
# fail-if: '-x' in EXTRA_JIT_ARGS
# - we don't get syntax errors through the old parser correctly
try:
exec ";"
print "worked?"
except SyntaxError:
pass
...@@ -4,13 +4,15 @@ import tempfile ...@@ -4,13 +4,15 @@ import tempfile
fd, fn = tempfile.mkstemp() fd, fn = tempfile.mkstemp()
with open(fn, "wb") as f: with open(fn, "wb") as f:
f.write("hello world!") f.write("hello world!\n")
f.write(u"hello world2")
with open(fn) as f: with open(fn) as f:
print repr(f.read()) print repr(f.read())
with open(fn, "w") as f: with open(fn, "w") as f:
f.write("hello world!") f.write("hello world!")
f.writelines(["hi", "world"])
with open(fn) as f: with open(fn) as f:
print repr(f.read()) print repr(f.read())
......
# This throws an exception in the import machinery when we try to access __path__,
# but that should get caught.
# Also, email.MIMEText isn't even a Module or a subclass of Module...
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
# TODO check similar cases with descriptors
...@@ -153,3 +153,21 @@ print l ...@@ -153,3 +153,21 @@ print l
l = range(5) l = range(5)
l[2:4] = tuple(range(2)) l[2:4] = tuple(range(2))
print l print l
l = [None]*4
try:
l[::-1] = range(5)
except ValueError as e:
print e
l[::-1] = range(4)
print l
del l[::2]
print l
for i in xrange(3):
for j in xrange(3):
for k in xrange(3):
l1 = [i]
l2 = [j, k]
print l1 < l2, l1 <= l2, l1 > l2, l1 >= l2
# regression test: list sorting had a gc bug
import gc
class C(object):
def __init__(self, n):
self.n = range(n)
def __eq__(self, rhs):
# print "eq"
gc.collect()
return self.n == rhs.n
def __lt__(self, rhs):
# print "lt"
gc.collect()
return self.n < rhs.n
def keyfunc(c):
return c
def f():
for i in xrange(10):
print i
l = [C(i % 5) for i in xrange(10)]
l.sort(key=keyfunc)
f()
...@@ -29,6 +29,7 @@ def f3(): ...@@ -29,6 +29,7 @@ def f3():
s = "hello world" s = "hello world"
t = (1.0, "asdf") t = (1.0, "asdf")
print sorted(locals().items()) print sorted(locals().items())
print sorted(vars().items())
f3() f3()
def f4(t): def f4(t):
...@@ -38,6 +39,7 @@ def f4(t): ...@@ -38,6 +39,7 @@ def f4(t):
else: else:
y = 2 y = 2
print sorted(locals().items()) print sorted(locals().items())
print sorted(vars().items())
f4(0) f4(0)
f4(1) f4(1)
...@@ -52,6 +54,7 @@ def f5(): ...@@ -52,6 +54,7 @@ def f5():
print a print a
print b print b
print sorted(locals().items()) print sorted(locals().items())
print sorted(vars().items())
i() i()
h() h()
g() g()
......
# should_error
# no-collect-stats
try:
raise SystemExit, "hello"
except Exception as e:
pass
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment