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 @@
#include "llvm/ADT/STLExtras.h"
#include "core/types.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace pyston {
......@@ -56,8 +57,13 @@ while lines:
class Converter {
private:
InternedStringPool* pool = NULL;
int loop_depth = 0;
int in_finally = 0;
llvm::StringRef fn;
public:
Converter(llvm::StringRef fn) : fn(fn) {}
template <typename T, typename P> std::vector<P> convert(asdl_seq* seq) {
std::vector<P> rtn;
if (!seq)
......@@ -506,7 +512,12 @@ public:
auto v = stmt->v.For;
r->target = convert(v.target);
r->iter = convert(v.iter);
auto fin = in_finally;
in_finally = 0;
loop_depth++;
r->body = convert<stmt_ty, AST_stmt*>(v.body);
loop_depth--;
in_finally = fin;
r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse);
return r;
}
......@@ -514,7 +525,12 @@ public:
auto r = new AST_While();
auto v = stmt->v.While;
r->test = convert(v.test);
auto fin = in_finally;
in_finally = 0;
loop_depth++;
r->body = convert<stmt_ty, AST_stmt*>(v.body);
loop_depth--;
in_finally = fin;
r->orelse = convert<stmt_ty, AST_stmt*>(v.orelse);
return r;
}
......@@ -554,7 +570,9 @@ public:
auto r = new AST_TryFinally();
auto v = stmt->v.TryFinally;
r->body = convert<stmt_ty, AST_stmt*>(v.body);
in_finally++;
r->finalbody = convert<stmt_ty, AST_stmt*>(v.finalbody);
in_finally--;
return r;
}
case Assert_kind: {
......@@ -601,8 +619,16 @@ public:
case Pass_kind:
return new AST_Pass();
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();
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();
};
}
......@@ -630,8 +656,8 @@ public:
}
};
AST_Module* cpythonToPystonAST(mod_ty mod) {
Converter c;
AST_Module* cpythonToPystonAST(mod_ty mod, llvm::StringRef fn) {
Converter c(fn);
return c.convert(mod);
}
}
......@@ -1054,13 +1054,12 @@ AST_Module* parse_file(const char* fn, FutureFlags inherited_flags) {
FILE* fp = fopen(fn, "r");
PyCompilerFlags cf;
cf.cf_flags = 0;
PyArena* arena = PyArena_New();
ArenaWrapper arena;
assert(arena);
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
if (!mod)
throwCAPIException();
auto rtn = cpythonToPystonAST(mod);
PyArena_Free(arena);
auto rtn = cpythonToPystonAST(mod, fn);
return rtn;
}
......@@ -1142,12 +1141,12 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A
FILE* fp = fopen(fn, "r");
PyCompilerFlags cf;
cf.cf_flags = 0;
PyArena* arena = PyArena_New();
ArenaWrapper arena;
assert(arena);
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
if (!mod)
throwCAPIException();
module = cpythonToPystonAST(mod);
module = cpythonToPystonAST(mod, fn);
} else {
module = pypa_parse(fn, inherited_flags);
RELEASE_ASSERT(module, "unknown parse error");
......
......@@ -725,7 +725,11 @@ void addToSysArgv(const char* str);
// Raise a SyntaxError that occurs at a specific location.
// The traceback given to the user will include this,
// 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, ...)
__attribute__((format(printf, 4, 5)));
......@@ -784,6 +788,21 @@ struct CallattrFlags {
};
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:
// return values are either:
// >= 0 : the index where a given item was found
......
......@@ -1236,11 +1236,10 @@ extern "C" int PyRun_InteractiveOneFlags(FILE* fp, const char* filename, PyCompi
// d = PyModule_GetDict(m);
// v = run_mod(mod, filename, d, d, flags, arena);
assert(PyModule_Check(m));
AST_Module* pyston_module = cpythonToPystonAST(mod);
makeModuleInteractive(pyston_module);
bool failed = false;
try {
AST_Module* pyston_module = cpythonToPystonAST(mod, filename);
makeModuleInteractive(pyston_module);
compileAndRunModule(pyston_module, static_cast<BoxedModule*>(m));
} catch (ExcInfo e) {
setCAPIException(e);
......
......@@ -33,10 +33,27 @@ void raiseExc(Box* exc_obj) {
// 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:
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);
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func,
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());
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)
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\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