Commit 318be2fc authored by Kevin Modzelewski's avatar Kevin Modzelewski

Split parsing from compiling

This lets us support `exec compile(ast.parse(s))`.

Also, add 3-arg eval() support, and simple support for the _ast module.
parent 8364a607
...@@ -132,6 +132,9 @@ PyObject* PyGC_AddRoot(PyObject*) PYSTON_NOEXCEPT; ...@@ -132,6 +132,9 @@ PyObject* PyGC_AddRoot(PyObject*) PYSTON_NOEXCEPT;
#define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str) #define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str)
#define PyDoc_STR(str) str #define PyDoc_STR(str) str
// This is in Python-ast.h in CPython, which we don't yet have:
int PyAST_Check(PyObject* obj) PYSTON_NOEXCEPT;
#ifdef __cplusplus #ifdef __cplusplus
#define PyMODINIT_FUNC extern "C" void #define PyMODINIT_FUNC extern "C" void
#else #else
......
...@@ -73,6 +73,7 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS} ...@@ -73,6 +73,7 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
gc/gc_alloc.cpp gc/gc_alloc.cpp
gc/heap.cpp gc/heap.cpp
runtime/bool.cpp runtime/bool.cpp
runtime/builtin_modules/ast.cpp
runtime/builtin_modules/builtins.cpp runtime/builtin_modules/builtins.cpp
runtime/builtin_modules/gc.cpp runtime/builtin_modules/gc.cpp
runtime/builtin_modules/pyston.cpp runtime/builtin_modules/pyston.cpp
......
...@@ -845,7 +845,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { ...@@ -845,7 +845,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
} }
InternedStringPool& ScopingAnalysis::getInternedStrings() { InternedStringPool& ScopingAnalysis::getInternedStrings() {
return interned_strings; return *interned_strings;
} }
ScopeInfo* ScopingAnalysis::analyzeSubtree(AST* node) { ScopeInfo* ScopingAnalysis::analyzeSubtree(AST* node) {
...@@ -889,19 +889,25 @@ ScopeInfo* ScopingAnalysis::getScopeInfoForNode(AST* node) { ...@@ -889,19 +889,25 @@ ScopeInfo* ScopingAnalysis::getScopeInfoForNode(AST* node) {
return analyzeSubtree(node); return analyzeSubtree(node);
} }
ScopingAnalysis::ScopingAnalysis(AST_Module* m) ScopingAnalysis::ScopingAnalysis(AST* ast, bool globals_from_module)
: parent_module(m), interned_strings(*m->interned_strings.get()), globals_from_module(true) { : parent_module(NULL), globals_from_module(globals_from_module) {
scopes[m] = new ModuleScopeInfo(); switch (ast->type) {
} case AST_TYPE::Module:
assert(globals_from_module);
ScopingAnalysis::ScopingAnalysis(AST_Expression* e, bool globals_from_module) scopes[ast] = new ModuleScopeInfo();
: interned_strings(*e->interned_strings.get()), globals_from_module(globals_from_module) { interned_strings = static_cast<AST_Module*>(ast)->interned_strings.get();
// It's an expression, so it can't have a `global` statement parent_module = static_cast<AST_Module*>(ast);
scopes[e] = new EvalExprScopeInfo(globals_from_module); break;
} case AST_TYPE::Expression:
scopes[ast] = new EvalExprScopeInfo(globals_from_module);
ScopingAnalysis::ScopingAnalysis(AST_Suite* s, bool globals_from_module) interned_strings = static_cast<AST_Expression*>(ast)->interned_strings.get();
: interned_strings(*s->interned_strings.get()), globals_from_module(globals_from_module) { break;
scopes[s] = new EvalExprScopeInfo(s, globals_from_module); case AST_TYPE::Suite:
scopes[ast] = new EvalExprScopeInfo(ast, globals_from_module);
interned_strings = static_cast<AST_Suite*>(ast)->interned_strings.get();
break;
default:
RELEASE_ASSERT(0, "%d", ast->type);
}
} }
} }
...@@ -151,7 +151,7 @@ public: ...@@ -151,7 +151,7 @@ public:
private: private:
std::unordered_map<AST*, ScopeInfo*> scopes; std::unordered_map<AST*, ScopeInfo*> scopes;
AST_Module* parent_module; AST_Module* parent_module;
InternedStringPool& interned_strings; InternedStringPool* interned_strings;
std::unordered_map<AST*, AST*> scope_replacements; std::unordered_map<AST*, AST*> scope_replacements;
...@@ -170,9 +170,7 @@ public: ...@@ -170,9 +170,7 @@ public:
// a scope-node with a different node. // a scope-node with a different node.
void registerScopeReplacement(AST* original_node, AST* new_node); void registerScopeReplacement(AST* original_node, AST* new_node);
ScopingAnalysis(AST_Module* m); ScopingAnalysis(AST* ast, bool globals_from_module);
ScopingAnalysis(AST_Expression* e, bool globals_from_module);
ScopingAnalysis(AST_Suite* s, bool globals_from_module);
ScopeInfo* getScopeInfoForNode(AST* node); ScopeInfo* getScopeInfoForNode(AST* node);
InternedStringPool& getInternedStrings(); InternedStringPool& getInternedStrings();
......
...@@ -34,9 +34,9 @@ namespace pyston { ...@@ -34,9 +34,9 @@ namespace pyston {
DS_DEFINE_RWLOCK(codegen_rwlock); DS_DEFINE_RWLOCK(codegen_rwlock);
SourceInfo::SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, const std::vector<AST_stmt*>& body, SourceInfo::SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, std::vector<AST_stmt*> body, std::string fn)
std::string fn) : parent_module(m), scoping(scoping), ast(ast), cfg(NULL), liveness(NULL), fn(std::move(fn)),
: parent_module(m), scoping(scoping), ast(ast), cfg(NULL), liveness(NULL), fn(std::move(fn)), body(body) { body(std::move(body)) {
assert(this->fn.size()); assert(this->fn.size());
switch (ast->type) { switch (ast->type) {
......
...@@ -313,7 +313,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) { ...@@ -313,7 +313,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
RELEASE_ASSERT(fn, ""); RELEASE_ASSERT(fn, "");
bm->future_flags = getFutureFlags(m, fn); bm->future_flags = getFutureFlags(m, fn);
ScopingAnalysis* scoping = new ScopingAnalysis(m); ScopingAnalysis* scoping = new ScopingAnalysis(m, true);
std::unique_ptr<SourceInfo> si(new SourceInfo(bm, scoping, m, m->body, fn)); std::unique_ptr<SourceInfo> si(new SourceInfo(bm, scoping, m, m->body, fn));
bm->setattr("__doc__", si->getDocString(), NULL); bm->setattr("__doc__", si->getDocString(), NULL);
...@@ -353,38 +353,78 @@ Box* evalOrExec(CLFunction* cl, Box* globals, Box* boxedLocals) { ...@@ -353,38 +353,78 @@ Box* evalOrExec(CLFunction* cl, Box* globals, Box* boxedLocals) {
return astInterpretFunctionEval(cf, globals, boxedLocals); return astInterpretFunctionEval(cf, globals, boxedLocals);
} }
template <typename AST_Type> CLFunction* compileForEvalOrExec(AST* source, std::vector<AST_stmt*> body, std::string fn) {
CLFunction* compileForEvalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, std::string fn) {
LOCK_REGION(codegen_rwlock.asWrite()); LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for evalOrExec()"); Timer _t("for evalOrExec()");
ScopingAnalysis* scoping = new ScopingAnalysis(source, false); ScopingAnalysis* scoping = new ScopingAnalysis(source, false);
std::unique_ptr<SourceInfo> si(new SourceInfo(getCurrentModule(), scoping, source, body, std::move(fn))); std::unique_ptr<SourceInfo> si(new SourceInfo(getCurrentModule(), scoping, source, std::move(body), std::move(fn)));
CLFunction* cl_f = new CLFunction(0, 0, false, false, std::move(si)); CLFunction* cl_f = new CLFunction(0, 0, false, false, std::move(si));
return cl_f; return cl_f;
} }
static CLFunction* compileExec(llvm::StringRef source, llvm::StringRef fn) { // TODO: CPython parses execs as Modules, not as Suites. This is probably not too hard to change,
// but is non-trivial since we will later decide some things (ex in scoping_analysis) based off
// the type of the root ast node.
static AST_Suite* parseExec(llvm::StringRef source) {
// TODO error message if parse fails or if it isn't an expr // TODO error message if parse fails or if it isn't an expr
// TODO should have a cleaner interface that can parse the Expression directly // TODO should have a cleaner interface that can parse the Expression directly
// TODO this memory leaks // TODO this memory leaks
const char* code = source.data(); const char* code = source.data();
AST_Module* parsedModule = parse_string(code); AST_Module* parsedModule = parse_string(code);
AST_Suite* parsedSuite = new AST_Suite(std::move(parsedModule->interned_strings)); AST_Suite* parsedSuite = new AST_Suite(std::move(parsedModule->interned_strings));
parsedSuite->body = parsedModule->body; parsedSuite->body = std::move(parsedModule->body);
return parsedSuite;
}
static CLFunction* compileExec(AST_Suite* parsedSuite, llvm::StringRef fn) {
return compileForEvalOrExec(parsedSuite, parsedSuite->body, fn); return compileForEvalOrExec(parsedSuite, parsedSuite->body, fn);
} }
static AST_Expression* parseEval(llvm::StringRef source) {
const char* code = source.data();
// TODO error message if parse fails or if it isn't an expr
// TODO should have a cleaner interface that can parse the Expression directly
// TODO this memory leaks
// 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);
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, "");
AST_Expression* parsedExpr = new AST_Expression(std::move(parsedModule->interned_strings));
parsedExpr->body = static_cast<AST_Expr*>(parsedModule->body[0])->value;
return parsedExpr;
}
static CLFunction* compileEval(AST_Expression* parsedExpr, llvm::StringRef fn) {
// We need body (list of statements) to compile.
// Obtain this by simply making a single statement which contains the expression.
AST_Return* stmt = new AST_Return();
stmt->value = parsedExpr->body;
std::vector<AST_stmt*> body = { stmt };
return compileForEvalOrExec(parsedExpr, std::move(body), fn);
}
Box* compile(Box* source, Box* fn, Box* type, Box** _args) { Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
Box* flags = _args[0]; Box* flags = _args[0];
Box* dont_inherit = _args[0]; Box* dont_inherit = _args[1];
RELEASE_ASSERT(flags == boxInt(0), "");
RELEASE_ASSERT(dont_inherit == boxInt(0), ""); RELEASE_ASSERT(dont_inherit == boxInt(0), "");
RELEASE_ASSERT(flags->cls == int_cls, "");
int64_t iflags = static_cast<BoxedInt*>(flags)->n;
// source is allowed to be an AST, unicode, or anything that supports the buffer protocol // source is allowed to be an AST, unicode, or anything that supports the buffer protocol
if (source->cls == unicode_cls) { if (source->cls == unicode_cls) {
source = PyUnicode_AsUTF8String(source); source = PyUnicode_AsUTF8String(source);
...@@ -410,15 +450,47 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) { ...@@ -410,15 +450,47 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
llvm::StringRef filename_str = static_cast<BoxedString*>(fn)->s; llvm::StringRef filename_str = static_cast<BoxedString*>(fn)->s;
llvm::StringRef type_str = static_cast<BoxedString*>(type)->s; llvm::StringRef type_str = static_cast<BoxedString*>(type)->s;
RELEASE_ASSERT(isSubclass(source->cls, str_cls), ""); if (iflags & ~(/*PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_DONT_IMPLY_DEDENT | */ PyCF_ONLY_AST)) {
llvm::StringRef source_str = static_cast<BoxedString*>(source)->s; raiseExcHelper(ValueError, "compile(): unrecognised flags");
}
bool only_ast = (bool)(iflags & PyCF_ONLY_AST);
iflags &= ~PyCF_ONLY_AST;
RELEASE_ASSERT(iflags == 0, "");
AST* parsed;
if (PyAST_Check(source)) {
parsed = unboxAst(source);
} else {
RELEASE_ASSERT(isSubclass(source->cls, str_cls), "");
llvm::StringRef source_str = static_cast<BoxedString*>(source)->s;
if (type_str == "exec") {
parsed = parseExec(source_str);
} else if (type_str == "eval") {
parsed = parseEval(source_str);
} else if (type_str == "single") {
fatalOrError(NotImplemented, "unimplemented");
throwCAPIException();
} else {
raiseExcHelper(ValueError, "compile() arg 3 must be 'exec', 'eval' or 'single'");
}
}
if (only_ast)
return boxAst(parsed);
CLFunction* cl; CLFunction* cl;
if (type_str == "exec") { if (type_str == "exec") {
cl = compileExec(source_str, filename_str); // TODO: CPython parses execs as Modules
if (parsed->type != AST_TYPE::Suite)
raiseExcHelper(TypeError, "expected Suite node, got %s", boxAst(parsed)->cls->tp_name);
cl = compileExec(static_cast<AST_Suite*>(parsed), filename_str);
} else if (type_str == "eval") { } else if (type_str == "eval") {
fatalOrError(NotImplemented, "unimplemented"); if (parsed->type != AST_TYPE::Expression)
throwCAPIException(); raiseExcHelper(TypeError, "expected Expression node, got %s", boxAst(parsed)->cls->tp_name);
cl = compileEval(static_cast<AST_Expression*>(parsed), filename_str);
} else if (type_str == "single") { } else if (type_str == "single") {
fatalOrError(NotImplemented, "unimplemented"); fatalOrError(NotImplemented, "unimplemented");
throwCAPIException(); throwCAPIException();
...@@ -429,14 +501,30 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) { ...@@ -429,14 +501,30 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
return codeForCLFunction(cl); return codeForCLFunction(cl);
} }
Box* eval(Box* boxedCode) { Box* eval(Box* boxedCode, Box* globals, Box* locals) {
Box* boxedLocals = fastLocalsToBoxedLocals(); if (globals == None)
BoxedModule* module = getCurrentModule(); globals = NULL;
Box* globals = getGlobals();
if (locals == None)
locals = NULL;
if (locals == NULL) {
locals = globals;
}
if (locals == NULL) {
locals = fastLocalsToBoxedLocals();
}
if (globals == NULL)
globals = getGlobals();
BoxedModule* module = getCurrentModule();
if (globals && globals->cls == attrwrapper_cls && unwrapAttrWrapper(globals) == module) if (globals && globals->cls == attrwrapper_cls && unwrapAttrWrapper(globals) == module)
globals = module; globals = module;
assert(globals && (globals->cls == module_cls || globals->cls == dict_cls));
if (boxedCode->cls == unicode_cls) { if (boxedCode->cls == unicode_cls) {
boxedCode = PyUnicode_AsUTF8String(boxedCode); boxedCode = PyUnicode_AsUTF8String(boxedCode);
if (!boxedCode) if (!boxedCode)
...@@ -444,36 +532,16 @@ Box* eval(Box* boxedCode) { ...@@ -444,36 +532,16 @@ Box* eval(Box* boxedCode) {
// cf.cf_flags |= PyCF_SOURCE_IS_UTF8 // cf.cf_flags |= PyCF_SOURCE_IS_UTF8
} }
// TODO error message if parse fails or if it isn't an expr CLFunction* cl;
// TODO should have a cleaner interface that can parse the Expression directly if (boxedCode->cls == str_cls) {
// TODO this memory leaks AST_Expression* parsed = parseEval(static_cast<BoxedString*>(boxedCode)->s);
RELEASE_ASSERT(boxedCode->cls == str_cls, "%s", boxedCode->cls->tp_name); cl = compileEval(parsed, "<string>");
const char* code = static_cast<BoxedString*>(boxedCode)->s.data(); } else if (boxedCode->cls == code_cls) {
cl = clfunctionFromCode(boxedCode);
// Hack: we need to support things like `eval(" 2")`. } else {
// This is over-accepting since it will accept things like `eval("\n 2")` abort();
while (*code == ' ' || *code == '\t' || *code == '\n' || *code == '\r') }
code++; return evalOrExec(cl, globals, locals);
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, "");
AST_Expression* parsedExpr = new AST_Expression(std::move(parsedModule->interned_strings));
parsedExpr->body = static_cast<AST_Expr*>(parsedModule->body[0])->value;
// We need body (list of statements) to compile.
// Obtain this by simply making a single statement which contains the expression.
AST_Return* stmt = new AST_Return();
stmt->value = parsedExpr->body;
std::vector<AST_stmt*> body = { stmt };
assert(globals && (globals->cls == module_cls || globals->cls == dict_cls));
CLFunction* cl = compileForEvalOrExec(parsedExpr, body, "<string>");
return evalOrExec(cl, globals, boxedLocals);
} }
Box* exec(Box* boxedCode, Box* globals, Box* locals) { Box* exec(Box* boxedCode, Box* globals, Box* locals) {
...@@ -530,7 +598,8 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) { ...@@ -530,7 +598,8 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) {
CLFunction* cl; CLFunction* cl;
if (boxedCode->cls == str_cls) { if (boxedCode->cls == str_cls) {
cl = compileExec(static_cast<BoxedString*>(boxedCode)->s, "<string>"); AST_Suite* parsed = parseExec(static_cast<BoxedString*>(boxedCode)->s);
cl = compileExec(parsed, "<string>");
} else if (boxedCode->cls == code_cls) { } else if (boxedCode->cls == code_cls) {
cl = clfunctionFromCode(boxedCode); cl = clfunctionFromCode(boxedCode);
} else { } else {
......
...@@ -38,7 +38,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm); ...@@ -38,7 +38,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm);
CompiledFunction* cfForMachineFunctionName(const std::string&); CompiledFunction* cfForMachineFunctionName(const std::string&);
extern "C" Box* exec(Box* boxedCode, Box* globals, Box* locals); extern "C" Box* exec(Box* boxedCode, Box* globals, Box* locals);
extern "C" Box* eval(Box* boxedCode); extern "C" Box* eval(Box* boxedCode, Box* globals, Box* locals);
extern "C" Box* compile(Box* source, Box* filename, Box* mode, Box** _args /* flags, dont_inherit */); extern "C" Box* compile(Box* source, Box* filename, Box* mode, Box** _args /* flags, dont_inherit */);
} }
......
...@@ -261,7 +261,7 @@ public: ...@@ -261,7 +261,7 @@ public:
Box* getDocString(); Box* getDocString();
SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, const std::vector<AST_stmt*>& body, std::string fn); SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, std::vector<AST_stmt*> body, std::string fn);
}; };
typedef std::vector<CompiledFunction*> FunctionList; typedef std::vector<CompiledFunction*> FunctionList;
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <cmath>
#include <langinfo.h>
#include <sstream>
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "codegen/unwinding.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/file.h"
#include "runtime/inline/boxing.h"
#include "runtime/int.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
static BoxedClass* AST_cls;
class BoxedAST : public Box {
public:
AST* ast;
BoxedAST() {}
};
static std::unordered_map<int, BoxedClass*> type_to_cls;
Box* boxAst(AST* ast) {
assert(ast);
BoxedClass* cls = type_to_cls[ast->type];
assert(cls);
BoxedAST* rtn = new (cls) BoxedAST();
assert(rtn->cls == cls);
rtn->ast = ast;
return rtn;
}
AST* unboxAst(Box* b) {
assert(isSubclass(b->cls, AST_cls));
AST* rtn = static_cast<BoxedAST*>(b)->ast;
assert(rtn);
return rtn;
}
extern "C" int PyAST_Check(PyObject* o) noexcept {
return isSubclass(o->cls, AST_cls);
}
void setupAST() {
BoxedModule* ast_module = createModule("_ast", "__builtin__");
ast_module->giveAttr("PyCF_ONLY_AST", boxInt(PyCF_ONLY_AST));
// ::create takes care of registering the class as a GC root.
#define MAKE_CLS(name, base_cls) \
BoxedClass* name##_cls = BoxedHeapClass::create(type_cls, base_cls, /* gchandler = */ NULL, 0, 0, \
sizeof(BoxedAST), false, STRINGIFY(name)); \
ast_module->giveAttr(STRINGIFY(name), name##_cls); \
type_to_cls[AST_TYPE::name] = name##_cls; \
name##_cls->giveAttr("__module__", boxString("_ast")); \
name##_cls->freeze()
AST_cls
= BoxedHeapClass::create(type_cls, object_cls, /* gchandler = */ NULL, 0, 0, sizeof(BoxedAST), false, "AST");
// ::create takes care of registering the class as a GC root.
AST_cls->giveAttr("__module__", boxString("_ast"));
AST_cls->freeze();
// TODO(kmod) you can call the class constructors, such as "ast.AST()", so we need new/init
// TODO(kmod) there is more inheritance than "they all inherit from AST"
MAKE_CLS(alias, AST_cls);
MAKE_CLS(arguments, AST_cls);
MAKE_CLS(Assert, AST_cls);
MAKE_CLS(Assign, AST_cls);
MAKE_CLS(Attribute, AST_cls);
MAKE_CLS(AugAssign, AST_cls);
MAKE_CLS(BinOp, AST_cls);
MAKE_CLS(BoolOp, AST_cls);
MAKE_CLS(Call, AST_cls);
MAKE_CLS(ClassDef, AST_cls);
MAKE_CLS(Compare, AST_cls);
MAKE_CLS(comprehension, AST_cls);
MAKE_CLS(Delete, AST_cls);
MAKE_CLS(Dict, AST_cls);
MAKE_CLS(Exec, AST_cls);
MAKE_CLS(ExceptHandler, AST_cls);
MAKE_CLS(ExtSlice, AST_cls);
MAKE_CLS(Expr, AST_cls);
MAKE_CLS(For, AST_cls);
MAKE_CLS(FunctionDef, AST_cls);
MAKE_CLS(GeneratorExp, AST_cls);
MAKE_CLS(Global, AST_cls);
MAKE_CLS(If, AST_cls);
MAKE_CLS(IfExp, AST_cls);
MAKE_CLS(Import, AST_cls);
MAKE_CLS(ImportFrom, AST_cls);
MAKE_CLS(Index, AST_cls);
MAKE_CLS(keyword, AST_cls);
MAKE_CLS(Lambda, AST_cls);
MAKE_CLS(List, AST_cls);
MAKE_CLS(ListComp, AST_cls);
MAKE_CLS(Module, AST_cls);
MAKE_CLS(Num, AST_cls);
MAKE_CLS(Name, AST_cls);
MAKE_CLS(Pass, AST_cls);
MAKE_CLS(Pow, AST_cls);
MAKE_CLS(Print, AST_cls);
MAKE_CLS(Raise, AST_cls);
MAKE_CLS(Repr, AST_cls);
MAKE_CLS(Return, AST_cls);
MAKE_CLS(Slice, AST_cls);
MAKE_CLS(Str, AST_cls);
MAKE_CLS(Subscript, AST_cls);
MAKE_CLS(TryExcept, AST_cls);
MAKE_CLS(TryFinally, AST_cls);
MAKE_CLS(Tuple, AST_cls);
MAKE_CLS(UnaryOp, AST_cls);
MAKE_CLS(With, AST_cls);
MAKE_CLS(While, AST_cls);
MAKE_CLS(Yield, AST_cls);
MAKE_CLS(Store, AST_cls);
MAKE_CLS(Load, AST_cls);
MAKE_CLS(Param, AST_cls);
MAKE_CLS(Not, AST_cls);
MAKE_CLS(In, AST_cls);
MAKE_CLS(Is, AST_cls);
MAKE_CLS(IsNot, AST_cls);
MAKE_CLS(Or, AST_cls);
MAKE_CLS(And, AST_cls);
MAKE_CLS(Eq, AST_cls);
MAKE_CLS(NotEq, AST_cls);
MAKE_CLS(NotIn, AST_cls);
MAKE_CLS(GtE, AST_cls);
MAKE_CLS(Gt, AST_cls);
MAKE_CLS(Mod, AST_cls);
MAKE_CLS(Add, AST_cls);
MAKE_CLS(Continue, AST_cls);
MAKE_CLS(Lt, AST_cls);
MAKE_CLS(LtE, AST_cls);
MAKE_CLS(Break, AST_cls);
MAKE_CLS(Sub, AST_cls);
MAKE_CLS(Del, AST_cls);
MAKE_CLS(Mult, AST_cls);
MAKE_CLS(Div, AST_cls);
MAKE_CLS(USub, AST_cls);
MAKE_CLS(BitAnd, AST_cls);
MAKE_CLS(BitOr, AST_cls);
MAKE_CLS(BitXor, AST_cls);
MAKE_CLS(RShift, AST_cls);
MAKE_CLS(LShift, AST_cls);
MAKE_CLS(Invert, AST_cls);
MAKE_CLS(UAdd, AST_cls);
MAKE_CLS(FloorDiv, AST_cls);
MAKE_CLS(DictComp, AST_cls);
MAKE_CLS(Set, AST_cls);
MAKE_CLS(Ellipsis, AST_cls);
MAKE_CLS(Expression, AST_cls);
MAKE_CLS(SetComp, AST_cls);
MAKE_CLS(Suite, AST_cls);
#undef MAKE_CLS
// Uncommenting this makes `import ast` work, which may or may not be desired.
// For now it seems like making the import fail is better than having the module not work properly.
// ast_module->giveAttr("__version__", boxInt(82160));
}
}
...@@ -1211,8 +1211,9 @@ void setupBuiltins() { ...@@ -1211,8 +1211,9 @@ void setupBuiltins() {
PyType_Ready(&PyBuffer_Type); PyType_Ready(&PyBuffer_Type);
builtins_module->giveAttr("buffer", &PyBuffer_Type); builtins_module->giveAttr("buffer", &PyBuffer_Type);
builtins_module->giveAttr( builtins_module->giveAttr("eval",
"eval", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)eval, UNKNOWN, 1, 0, false, false), "eval")); new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)eval, UNKNOWN, 3, 2, false, false),
"eval", { NULL, NULL }));
builtins_module->giveAttr("callable", builtins_module->giveAttr("callable",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)callable, UNKNOWN, 1), "callable")); new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)callable, UNKNOWN, 1), "callable"));
......
...@@ -2323,6 +2323,7 @@ void setupRuntime() { ...@@ -2323,6 +2323,7 @@ void setupRuntime() {
setupGC(); setupGC();
setupImport(); setupImport();
setupPyston(); setupPyston();
setupAST();
PyType_Ready(&PyByteArrayIter_Type); PyType_Ready(&PyByteArrayIter_Type);
PyType_Ready(&PyCapsule_Type); PyType_Ready(&PyCapsule_Type);
......
...@@ -75,6 +75,7 @@ void setupBuiltins(); ...@@ -75,6 +75,7 @@ void setupBuiltins();
void setupPyston(); void setupPyston();
void setupThread(); void setupThread();
void setupImport(); void setupImport();
void setupAST();
void setupSysEnd(); void setupSysEnd();
BoxedDict* getSysModulesDict(); BoxedDict* getSysModulesDict();
...@@ -834,6 +835,9 @@ Box* unwrapAttrWrapper(Box* b); ...@@ -834,6 +835,9 @@ Box* unwrapAttrWrapper(Box* b);
Box* attrwrapperKeys(Box* b); Box* attrwrapperKeys(Box* b);
void attrwrapperDel(Box* b, const std::string& attr); void attrwrapperDel(Box* b, const std::string& attr);
Box* boxAst(AST* ast);
AST* unboxAst(Box* b);
#define SystemError ((BoxedClass*)PyExc_SystemError) #define SystemError ((BoxedClass*)PyExc_SystemError)
#define StopIteration ((BoxedClass*)PyExc_StopIteration) #define StopIteration ((BoxedClass*)PyExc_StopIteration)
#define NameError ((BoxedClass*)PyExc_NameError) #define NameError ((BoxedClass*)PyExc_NameError)
......
import _ast
def ast_parse(source, filename='<unknown>', mode='exec'):
return compile(source, filename, mode, _ast.PyCF_ONLY_AST)
# TODO(kmod) unfortunately we don't expose any of the data members yet, and we don't even display
# the types correctly, so just parse the code and make sure that we didn't crash
ast_parse("print 1")
ast_parse("print 1", "t.py", "exec")
ast_parse("1", "t.py", "eval")
c = compile(ast_parse("print 1", "t.py", "exec"), "u.py", "exec")
print c.co_filename
exec c
try:
c = compile(ast_parse("print 1", "t.py", "exec"), "u.py", "eval")
except Exception as e:
print type(e)
c = compile(ast_parse("print 2", "t.py", "exec"), "u.py", "exec")
print eval(c)
c = compile("a", "test.py", "eval")
print type(c), c.co_filename, c.co_name
print
a = 0
print eval(c)
print
a = 0
g = {'a':1}
print eval(c, g)
print
a = 0
g = {'a':1}
l = {'a':2}
print eval(c, g, l)
print
g = {}
exec """
c = compile("a", "test.py", "eval")
""" in g
a = 0
print eval(g['c'])
print
a = 0
g = {'a':1, '_c':c}
exec "print eval(_c)" in g
...@@ -27,7 +27,7 @@ TEST_F(AnalysisTest, augassign) { ...@@ -27,7 +27,7 @@ TEST_F(AnalysisTest, augassign) {
AST_Module* module = caching_parse_file(fn.c_str()); AST_Module* module = caching_parse_file(fn.c_str());
assert(module); assert(module);
ScopingAnalysis *scoping = new ScopingAnalysis(module); ScopingAnalysis *scoping = new ScopingAnalysis(module, true);
assert(module->body[0]->type == AST_TYPE::FunctionDef); assert(module->body[0]->type == AST_TYPE::FunctionDef);
AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]); AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);
...@@ -57,7 +57,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) { ...@@ -57,7 +57,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) {
AST_Module* module = caching_parse_file(fn.c_str()); AST_Module* module = caching_parse_file(fn.c_str());
assert(module); assert(module);
ScopingAnalysis *scoping = new ScopingAnalysis(module); ScopingAnalysis *scoping = new ScopingAnalysis(module, true);
assert(module->body[0]->type == AST_TYPE::FunctionDef); assert(module->body[0]->type == AST_TYPE::FunctionDef);
AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]); AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);
......
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