Commit 90b74680 authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by Kevin Modzelewski

Have the conversion process handle checking for errors

parent f8cec61e
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "core/types.h" #include "core/types.h"
#include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -56,8 +57,13 @@ while lines: ...@@ -56,8 +57,13 @@ while lines:
class Converter { class Converter {
private: private:
InternedStringPool* pool = NULL; InternedStringPool* pool = NULL;
int loop_depth = 0;
int in_finally = 0;
llvm::StringRef fn;
public: public:
Converter(llvm::StringRef fn) : fn(fn) {}
template <typename T, typename P> std::vector<P> convert(asdl_seq* seq) { template <typename T, typename P> std::vector<P> convert(asdl_seq* seq) {
std::vector<P> rtn; std::vector<P> rtn;
if (!seq) if (!seq)
...@@ -506,7 +512,12 @@ public: ...@@ -506,7 +512,12 @@ public:
auto v = stmt->v.For; auto v = stmt->v.For;
r->target = convert(v.target); r->target = convert(v.target);
r->iter = convert(v.iter); r->iter = convert(v.iter);
auto fin = in_finally;
in_finally = 0;
loop_depth++;
r->body = convert<stmt_ty, AST_stmt*>(v.body); r->body = convert<stmt_ty, AST_stmt*>(v.body);
loop_depth--;
in_finally = fin;
r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse); r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse);
return r; return r;
} }
...@@ -514,7 +525,12 @@ public: ...@@ -514,7 +525,12 @@ public:
auto r = new AST_While(); auto r = new AST_While();
auto v = stmt->v.While; auto v = stmt->v.While;
r->test = convert(v.test); r->test = convert(v.test);
auto fin = in_finally;
in_finally = 0;
loop_depth++;
r->body = convert<stmt_ty, AST_stmt*>(v.body); r->body = convert<stmt_ty, AST_stmt*>(v.body);
loop_depth--;
in_finally = fin;
r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse); r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse);
return r; return r;
} }
...@@ -554,7 +570,9 @@ public: ...@@ -554,7 +570,9 @@ public:
auto r = new AST_TryFinally(); auto r = new AST_TryFinally();
auto v = stmt->v.TryFinally; auto v = stmt->v.TryFinally;
r->body = convert<stmt_ty, AST_stmt*>(v.body); r->body = convert<stmt_ty, AST_stmt*>(v.body);
in_finally++;
r->finalbody = convert<stmt_ty, AST_stmt*>(v.finalbody); r->finalbody = convert<stmt_ty, AST_stmt*>(v.finalbody);
in_finally--;
return r; return r;
} }
case Assert_kind: { case Assert_kind: {
...@@ -601,8 +619,16 @@ public: ...@@ -601,8 +619,16 @@ public:
case Pass_kind: case Pass_kind:
return new AST_Pass(); return new AST_Pass();
case Break_kind: case Break_kind:
// This is not really the right place to be handling this, but this whole thing is temporary anyway.
if (loop_depth == 0)
raiseSyntaxError("'break' outside loop", stmt->lineno, stmt->col_offset, fn, "", true);
return new AST_Break(); return new AST_Break();
case Continue_kind: case Continue_kind:
if (loop_depth == 0)
raiseSyntaxError("'continue' not properly in loop", stmt->lineno, stmt->col_offset, fn, "", true);
if (in_finally)
raiseSyntaxError("'continue' not supported inside 'finally' clause", stmt->lineno, stmt->col_offset,
fn, "", true);
return new AST_Continue(); return new AST_Continue();
}; };
} }
...@@ -630,8 +656,8 @@ public: ...@@ -630,8 +656,8 @@ public:
} }
}; };
AST_Module* cpythonToPystonAST(mod_ty mod) { AST_Module* cpythonToPystonAST(mod_ty mod, llvm::StringRef fn) {
Converter c; Converter c(fn);
return c.convert(mod); return c.convert(mod);
} }
} }
...@@ -1054,13 +1054,12 @@ AST_Module* parse_file(const char* fn, FutureFlags inherited_flags) { ...@@ -1054,13 +1054,12 @@ AST_Module* parse_file(const char* fn, FutureFlags inherited_flags) {
FILE* fp = fopen(fn, "r"); FILE* fp = fopen(fn, "r");
PyCompilerFlags cf; PyCompilerFlags cf;
cf.cf_flags = 0; cf.cf_flags = 0;
PyArena* arena = PyArena_New(); ArenaWrapper arena;
assert(arena); assert(arena);
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena); mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
if (!mod) if (!mod)
throwCAPIException(); throwCAPIException();
auto rtn = cpythonToPystonAST(mod); auto rtn = cpythonToPystonAST(mod, fn);
PyArena_Free(arena);
return rtn; return rtn;
} }
...@@ -1142,12 +1141,12 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A ...@@ -1142,12 +1141,12 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A
FILE* fp = fopen(fn, "r"); FILE* fp = fopen(fn, "r");
PyCompilerFlags cf; PyCompilerFlags cf;
cf.cf_flags = 0; cf.cf_flags = 0;
PyArena* arena = PyArena_New(); ArenaWrapper arena;
assert(arena); assert(arena);
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena); mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
if (!mod) if (!mod)
throwCAPIException(); throwCAPIException();
module = cpythonToPystonAST(mod); module = cpythonToPystonAST(mod, fn);
} else { } else {
module = pypa_parse(fn, inherited_flags); module = pypa_parse(fn, inherited_flags);
RELEASE_ASSERT(module, "unknown parse error"); RELEASE_ASSERT(module, "unknown parse error");
......
...@@ -725,7 +725,11 @@ void addToSysArgv(const char* str); ...@@ -725,7 +725,11 @@ void addToSysArgv(const char* str);
// Raise a SyntaxError that occurs at a specific location. // Raise a SyntaxError that occurs at a specific location.
// The traceback given to the user will include this, // The traceback given to the user will include this,
// even though the execution didn't actually arrive there. // even though the execution didn't actually arrive there.
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func); // CPython has slightly different behavior depending on where in the pipeline (parser vs compiler)
// the SyntaxError was thrown; setting compiler_error=True is for the case that it was thrown in
// the compiler portion (which calls a function called compiler_error()).
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func,
bool compiler_error = false);
void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...) void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...)
__attribute__((format(printf, 4, 5))); __attribute__((format(printf, 4, 5)));
...@@ -784,6 +788,21 @@ struct CallattrFlags { ...@@ -784,6 +788,21 @@ struct CallattrFlags {
}; };
static_assert(sizeof(CallattrFlags) == sizeof(uint64_t), ""); static_assert(sizeof(CallattrFlags) == sizeof(uint64_t), "");
// A C++-style way of handling a PyArena*
class ArenaWrapper {
private:
PyArena* arena;
public:
ArenaWrapper() { arena = PyArena_New(); }
~ArenaWrapper() {
if (arena)
PyArena_Free(arena);
}
operator PyArena*() const { return arena; }
};
// similar to Java's Array.binarySearch: // similar to Java's Array.binarySearch:
// return values are either: // return values are either:
// >= 0 : the index where a given item was found // >= 0 : the index where a given item was found
......
...@@ -1236,11 +1236,10 @@ extern "C" int PyRun_InteractiveOneFlags(FILE* fp, const char* filename, PyCompi ...@@ -1236,11 +1236,10 @@ extern "C" int PyRun_InteractiveOneFlags(FILE* fp, const char* filename, PyCompi
// d = PyModule_GetDict(m); // d = PyModule_GetDict(m);
// v = run_mod(mod, filename, d, d, flags, arena); // v = run_mod(mod, filename, d, d, flags, arena);
assert(PyModule_Check(m)); assert(PyModule_Check(m));
AST_Module* pyston_module = cpythonToPystonAST(mod);
makeModuleInteractive(pyston_module);
bool failed = false; bool failed = false;
try { try {
AST_Module* pyston_module = cpythonToPystonAST(mod, filename);
makeModuleInteractive(pyston_module);
compileAndRunModule(pyston_module, static_cast<BoxedModule*>(m)); compileAndRunModule(pyston_module, static_cast<BoxedModule*>(m));
} catch (ExcInfo e) { } catch (ExcInfo e) {
setCAPIException(e); setCAPIException(e);
......
...@@ -33,10 +33,27 @@ void raiseExc(Box* exc_obj) { ...@@ -33,10 +33,27 @@ void raiseExc(Box* exc_obj) {
// Have a special helper function for syntax errors, since we want to include the location // Have a special helper function for syntax errors, since we want to include the location
// of the syntax error in the traceback, even though it is not part of the execution: // of the syntax error in the traceback, even though it is not part of the execution:
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func) { void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func,
Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL); bool compiler_error) {
Box* exc;
Box* tb = None;
if (compiler_error) {
// This is how CPython's compiler_error() works:
assert(file.data()[file.size()] == '\0');
Box* loc = PyErr_ProgramText(file.data(), lineno);
if (!loc) {
Py_INCREF(Py_None);
loc = Py_None;
}
auto args = BoxedTuple::create({ boxString(file), boxInt(lineno), None, loc });
exc = runtimeCall(SyntaxError, ArgPassSpec(2), boxString(msg), args, NULL, NULL, NULL);
} else {
// This is more like how the parser handles it:
exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL);
tb = new BoxedTraceback(LineInfo(lineno, col_offset, boxString(file), boxString(func)), None);
}
auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, boxString(file), boxString(func)), None);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
throw ExcInfo(exc->cls, exc, tb); throw ExcInfo(exc->cls, exc, tb);
} }
......
# Similar to finally_continue.py, but this is allowable
for i in xrange(10):
try:
pass
finally:
for i in xrange(10):
continue
while False:
continue
...@@ -43,3 +43,6 @@ test("import sys\nsys.exit(2)", 2) ...@@ -43,3 +43,6 @@ test("import sys\nsys.exit(2)", 2)
test("import sys; sys.exit(\n2)", 2) test("import sys; sys.exit(\n2)", 2)
test("class C(object):\n a=1\nprint C().a", 0) test("class C(object):\n a=1\nprint C().a", 0)
test("class C(object):\n a=1\n\nprint C().a", 0) test("class C(object):\n a=1\n\nprint C().a", 0)
test("continue", 0)
test("break", 0)
# test("exec '+'", 0) # We don't get the traceback 100% right on this one
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