Commit 244c7b90 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #535 from undingen/decorator

Add support for compile('single') and func.__globals__/func.func_globals
parents 15e6f7d6 31aa93b1
......@@ -360,12 +360,30 @@ CLFunction* compileForEvalOrExec(AST* source, std::vector<AST_stmt*> body, std::
// 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) {
static AST_Suite* parseExec(llvm::StringRef source, bool interactive = false) {
// 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
const char* code = source.data();
AST_Module* parsedModule = parse_string(code);
if (interactive) {
for (int i = 0; i < parsedModule->body.size(); ++i) {
AST_stmt* s = parsedModule->body[i];
if (s->type != AST_TYPE::Expr)
continue;
AST_Expr* expr = (AST_Expr*)s;
AST_Print* print = new AST_Print;
print->lineno = expr->lineno;
print->col_offset = expr->col_offset;
print->dest = NULL;
print->nl = true;
print->values.push_back(expr->value);
parsedModule->body[i] = print;
}
}
AST_Suite* parsedSuite = new AST_Suite(std::move(parsedModule->interned_strings));
parsedSuite->body = std::move(parsedModule->body);
return parsedSuite;
......@@ -462,8 +480,7 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
} else if (type_str == "eval") {
parsed = parseEval(source_str);
} else if (type_str == "single") {
fatalOrError(NotImplemented, "unimplemented");
throwCAPIException();
parsed = parseExec(source_str, true);
} else {
raiseExcHelper(ValueError, "compile() arg 3 must be 'exec', 'eval' or 'single'");
}
......@@ -473,7 +490,7 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
return boxAst(parsed);
CLFunction* cl;
if (type_str == "exec") {
if (type_str == "exec" || type_str == "single") {
// TODO: CPython parses execs as Modules
if (parsed->type != AST_TYPE::Suite)
raiseExcHelper(TypeError, "expected Suite node, got %s", boxAst(parsed)->cls->tp_name);
......@@ -482,9 +499,6 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
if (parsed->type != AST_TYPE::Expression)
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") {
fatalOrError(NotImplemented, "unimplemented");
throwCAPIException();
} else {
raiseExcHelper(ValueError, "compile() arg 3 must be 'exec', 'eval' or 'single'");
}
......
......@@ -848,6 +848,17 @@ static Box* functionDefaults(Box* self, void*) {
return BoxedTuple::create(func->ndefaults, &func->defaults->elts[0]);
}
static Box* functionGlobals(Box* self, void*) {
assert(self->cls == function_cls);
BoxedFunction* func = static_cast<BoxedFunction*>(self);
if (func->globals) {
assert(!func->f->source || !func->f->source->scoping->areGlobalsFromModule());
return func->globals;
}
assert(func->f->source);
return getattr(func->f->source->parent_module, "__dict__");
}
static void functionSetDefaults(Box* b, Box* v, void*) {
RELEASE_ASSERT(v, "can't delete __defaults__");
......@@ -2451,6 +2462,7 @@ void setupRuntime() {
offsetof(BoxedFunction, modname), false));
function_cls->giveAttr(
"__doc__", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedFunction, doc), false));
function_cls->giveAttr("__globals__", new (pyston_getset_cls) BoxedGetsetDescriptor(functionGlobals, NULL, NULL));
function_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)functionGet, UNKNOWN, 3)));
function_cls->giveAttr("__call__",
new BoxedFunction(boxRTFunction((void*)functionCall, UNKNOWN, 1, 0, true, true)));
......@@ -2461,6 +2473,7 @@ void setupRuntime() {
function_cls->giveAttr("func_defaults",
new (pyston_getset_cls) BoxedGetsetDescriptor(functionDefaults, functionSetDefaults, NULL));
function_cls->giveAttr("__defaults__", function_cls->getattr("func_defaults"));
function_cls->giveAttr("func_globals", function_cls->getattr("__globals__"));
function_cls->freeze();
builtin_function_or_method_cls->giveAttr(
......
......@@ -26,3 +26,7 @@ a = 0
g = {'_c':c}
exec "exec _c" in g
print a, sorted(g.keys())
print
c = compile("a = 1; b = 2; a - b; b - a; c = a - b; c; print c", "test.py", "single")
exec c
......@@ -40,3 +40,11 @@ except TypeError as e:
def func_without_defaults():
pass
print repr(func_without_defaults.__defaults__)
print func_without_defaults.func_globals == globals()
import os
print os.renames.__globals__ == os.__dict__
print os.renames.__globals__ == globals()
d = {}
exec "def foo(): pass" in d
print d["foo"].func_globals == d
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