Skip to content

Commit 013d46e

Browse files
committed
Merge pull request #988 from kmod/repl
Parser fix: call fclose
2 parents 209350e + cee9765 commit 013d46e

File tree

3 files changed

+66
-17
lines changed

3 files changed

+66
-17
lines changed

src/codegen/parser.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,13 +1018,26 @@ static std::string getParserCommandLine(const char* fn) {
10181018
AST_Module* parse_string(const char* code, FutureFlags inherited_flags) {
10191019
inherited_flags &= ~(CO_NESTED | CO_FUTURE_DIVISION);
10201020

1021+
if (ENABLE_CPYTHON_PARSER) {
1022+
PyCompilerFlags cf;
1023+
cf.cf_flags = inherited_flags;
1024+
ArenaWrapper arena;
1025+
assert(arena);
1026+
const char* fn = "<string>";
1027+
mod_ty mod = PyParser_ASTFromString(code, fn, Py_file_input, &cf, arena);
1028+
if (!mod)
1029+
throwCAPIException();
1030+
auto rtn = cpythonToPystonAST(mod, fn);
1031+
return rtn;
1032+
}
1033+
10211034
if (ENABLE_PYPA_PARSER || inherited_flags) {
10221035
AST_Module* rtn = pypa_parse_string(code, inherited_flags);
10231036
RELEASE_ASSERT(rtn, "unknown parse error (possibly: '%s'?)", strerror(errno));
10241037
return rtn;
10251038
}
10261039

1027-
ASSERT(!inherited_flags, "the old cpython parser doesn't support specifying initial future flags");
1040+
RELEASE_ASSERT(!inherited_flags, "the old cpython parser doesn't support specifying initial future flags");
10281041

10291042
int size = strlen(code);
10301043
char buf[] = "pystontmp_XXXXXX";
@@ -1035,10 +1048,11 @@ AST_Module* parse_string(const char* code, FutureFlags inherited_flags) {
10351048
printf("writing %d bytes to %s\n", size, tmp.c_str());
10361049
}
10371050

1038-
FILE* f = fopen(tmp.c_str(), "w");
1039-
fwrite(code, 1, size, f);
1040-
fputc('\n', f);
1041-
fclose(f);
1051+
{
1052+
FileHandle f(tmp.c_str(), "w");
1053+
fwrite(code, 1, size, f);
1054+
fputc('\n', f);
1055+
}
10421056

10431057
AST_Module* m = parse_file(tmp.c_str(), inherited_flags);
10441058
removeDirectoryIfExists(tmpdir);
@@ -1050,10 +1064,9 @@ AST_Module* parse_file(const char* fn, FutureFlags inherited_flags) {
10501064
Timer _t("parsing");
10511065

10521066
if (ENABLE_CPYTHON_PARSER) {
1053-
ASSERT(!inherited_flags, "unimplemented");
1054-
FILE* fp = fopen(fn, "r");
1067+
FileHandle fp(fn, "r");
10551068
PyCompilerFlags cf;
1056-
cf.cf_flags = 0;
1069+
cf.cf_flags = inherited_flags;
10571070
ArenaWrapper arena;
10581071
assert(arena);
10591072
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
@@ -1106,7 +1119,7 @@ const char* getMagic() {
11061119
static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, AST_Module*& module,
11071120
FutureFlags inherited_flags) {
11081121
inherited_flags &= ~(CO_NESTED | CO_FUTURE_DIVISION);
1109-
FILE* cache_fp = fopen(cache_fn.c_str(), "w");
1122+
FileHandle cache_fp(cache_fn.c_str(), "w");
11101123

11111124
if (DEBUG_PARSING) {
11121125
fprintf(stderr, "_reparse('%s', '%s'), pypa=%d\n", fn, cache_fn.c_str(), ENABLE_PYPA_PARSER);
@@ -1137,10 +1150,9 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A
11371150

11381151
if (ENABLE_CPYTHON_PARSER || ENABLE_PYPA_PARSER || inherited_flags) {
11391152
if (ENABLE_CPYTHON_PARSER) {
1140-
ASSERT(!inherited_flags, "unimplemented");
1141-
FILE* fp = fopen(fn, "r");
1153+
FileHandle fp(fn, "r");
11421154
PyCompilerFlags cf;
1143-
cf.cf_flags = 0;
1155+
cf.cf_flags = inherited_flags;
11441156
ArenaWrapper arena;
11451157
assert(arena);
11461158
mod_ty mod = PyParser_ASTFromFile(fp, fn, Py_file_input, 0, 0, &cf, NULL, arena);
@@ -1159,7 +1171,7 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A
11591171
checksum = p.second;
11601172
bytes_written += p.first;
11611173
} else {
1162-
ASSERT(!inherited_flags, "the old cpython parser doesn't support specifying initial future flags");
1174+
RELEASE_ASSERT(!inherited_flags, "the old cpython parser doesn't support specifying initial future flags");
11631175
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
11641176
char buf[80];
11651177
while (true) {
@@ -1188,8 +1200,6 @@ static std::vector<char> _reparse(const char* fn, const std::string& cache_fn, A
11881200
fwrite(&checksum, 1, CHECKSUM_LENGTH, cache_fp);
11891201
memcpy(&file_data[checksum_start + LENGTH_LENGTH], &checksum, CHECKSUM_LENGTH);
11901202

1191-
if (cache_fp)
1192-
fclose(cache_fp);
11931203
return std::move(file_data);
11941204
}
11951205

@@ -1221,7 +1231,8 @@ AST_Module* caching_parse_file(const char* fn, FutureFlags inherited_flags) {
12211231
&& cache_stat.st_mtim.tv_nsec > source_stat.st_mtim.tv_nsec))) {
12221232
oss << "reading pyc file\n";
12231233
char buf[1024];
1224-
FILE* cache_fp = fopen(cache_fn.c_str(), "r");
1234+
1235+
FileHandle cache_fp(cache_fn.c_str(), "r");
12251236
if (cache_fp) {
12261237
while (true) {
12271238
int read = fread(buf, 1, 1024, cache_fp);
@@ -1239,7 +1250,6 @@ AST_Module* caching_parse_file(const char* fn, FutureFlags inherited_flags) {
12391250
break;
12401251
}
12411252
}
1242-
fclose(cache_fp);
12431253
}
12441254
}
12451255

src/core/types.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,20 @@ class ArenaWrapper {
803803
operator PyArena*() const { return arena; }
804804
};
805805

806+
class FileHandle {
807+
private:
808+
FILE* file;
809+
810+
public:
811+
FileHandle(const char* fn, const char* mode) : file(fopen(fn, mode)) {}
812+
~FileHandle() {
813+
if (file)
814+
fclose(file);
815+
}
816+
817+
operator FILE*() const { return file; }
818+
};
819+
806820
// similar to Java's Array.binarySearch:
807821
// return values are either:
808822
// >= 0 : the index where a given item was found

src/runtime/capi.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,31 @@ static void err_input(perrdetail* err) noexcept {
13671367
#endif
13681368

13691369
extern "C" grammar _PyParser_Grammar;
1370+
1371+
/* Preferred access to parser is through AST. */
1372+
extern "C" mod_ty PyParser_ASTFromString(const char* s, const char* filename, int start, PyCompilerFlags* flags,
1373+
PyArena* arena) noexcept {
1374+
mod_ty mod;
1375+
PyCompilerFlags localflags;
1376+
perrdetail err;
1377+
int iflags = PARSER_FLAGS(flags);
1378+
1379+
node* n = PyParser_ParseStringFlagsFilenameEx(s, filename, &_PyParser_Grammar, start, &err, &iflags);
1380+
if (flags == NULL) {
1381+
localflags.cf_flags = 0;
1382+
flags = &localflags;
1383+
}
1384+
if (n) {
1385+
flags->cf_flags |= iflags & PyCF_MASK;
1386+
mod = PyAST_FromNode(n, flags, filename, arena);
1387+
PyNode_Free(n);
1388+
return mod;
1389+
} else {
1390+
err_input(&err);
1391+
return NULL;
1392+
}
1393+
}
1394+
13701395
extern "C" mod_ty PyParser_ASTFromFile(FILE* fp, const char* filename, int start, char* ps1, char* ps2,
13711396
PyCompilerFlags* flags, int* errcode, PyArena* arena) noexcept {
13721397
mod_ty mod;

0 commit comments

Comments
 (0)