cpython/Python/Python-ast.c

10467 lines
345 KiB
C
Raw Normal View History

// File automatically generated by Parser/asdl_c.py.
#include "Python.h"
#include "pycore_ast.h"
#include "pycore_ast_state.h" // struct ast_state
#include "pycore_interp.h" // _PyInterpreterState.ast
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "structmember.h"
#include <stddef.h>
// Forward declaration
static int init_types(struct ast_state *state);
static struct ast_state*
get_ast_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
struct ast_state *state = &interp->ast;
if (!init_types(state)) {
return NULL;
}
return state;
}
void _PyAST_Fini(PyInterpreterState *interp)
{
struct ast_state *state = &interp->ast;
Py_CLEAR(state->AST_type);
Py_CLEAR(state->Add_singleton);
Py_CLEAR(state->Add_type);
Py_CLEAR(state->And_singleton);
Py_CLEAR(state->And_type);
Py_CLEAR(state->AnnAssign_type);
Py_CLEAR(state->Assert_type);
Py_CLEAR(state->Assign_type);
Py_CLEAR(state->AsyncFor_type);
Py_CLEAR(state->AsyncFunctionDef_type);
Py_CLEAR(state->AsyncWith_type);
Py_CLEAR(state->Attribute_type);
Py_CLEAR(state->AugAssign_type);
Py_CLEAR(state->Await_type);
Py_CLEAR(state->BinOp_type);
Py_CLEAR(state->BitAnd_singleton);
Py_CLEAR(state->BitAnd_type);
Py_CLEAR(state->BitOr_singleton);
Py_CLEAR(state->BitOr_type);
Py_CLEAR(state->BitXor_singleton);
Py_CLEAR(state->BitXor_type);
Py_CLEAR(state->BoolOp_type);
Py_CLEAR(state->Break_type);
Py_CLEAR(state->Call_type);
Py_CLEAR(state->ClassDef_type);
Py_CLEAR(state->Compare_type);
Py_CLEAR(state->Constant_type);
Py_CLEAR(state->Continue_type);
Py_CLEAR(state->Del_singleton);
Py_CLEAR(state->Del_type);
Py_CLEAR(state->Delete_type);
Py_CLEAR(state->DictComp_type);
Py_CLEAR(state->Dict_type);
Py_CLEAR(state->Div_singleton);
Py_CLEAR(state->Div_type);
Py_CLEAR(state->Eq_singleton);
Py_CLEAR(state->Eq_type);
Py_CLEAR(state->ExceptHandler_type);
Py_CLEAR(state->Expr_type);
Py_CLEAR(state->Expression_type);
Py_CLEAR(state->FloorDiv_singleton);
Py_CLEAR(state->FloorDiv_type);
Py_CLEAR(state->For_type);
Py_CLEAR(state->FormattedValue_type);
Py_CLEAR(state->FunctionDef_type);
Py_CLEAR(state->FunctionType_type);
Py_CLEAR(state->GeneratorExp_type);
Py_CLEAR(state->Global_type);
Py_CLEAR(state->GtE_singleton);
Py_CLEAR(state->GtE_type);
Py_CLEAR(state->Gt_singleton);
Py_CLEAR(state->Gt_type);
Py_CLEAR(state->IfExp_type);
Py_CLEAR(state->If_type);
Py_CLEAR(state->ImportFrom_type);
Py_CLEAR(state->Import_type);
Py_CLEAR(state->In_singleton);
Py_CLEAR(state->In_type);
Py_CLEAR(state->Interactive_type);
Py_CLEAR(state->Invert_singleton);
Py_CLEAR(state->Invert_type);
Py_CLEAR(state->IsNot_singleton);
Py_CLEAR(state->IsNot_type);
Py_CLEAR(state->Is_singleton);
Py_CLEAR(state->Is_type);
Py_CLEAR(state->JoinedStr_type);
Py_CLEAR(state->LShift_singleton);
Py_CLEAR(state->LShift_type);
Py_CLEAR(state->Lambda_type);
Py_CLEAR(state->ListComp_type);
Py_CLEAR(state->List_type);
Py_CLEAR(state->Load_singleton);
Py_CLEAR(state->Load_type);
Py_CLEAR(state->LtE_singleton);
Py_CLEAR(state->LtE_type);
Py_CLEAR(state->Lt_singleton);
Py_CLEAR(state->Lt_type);
Py_CLEAR(state->MatMult_singleton);
Py_CLEAR(state->MatMult_type);
Py_CLEAR(state->MatchAs_type);
Py_CLEAR(state->MatchOr_type);
Py_CLEAR(state->Match_type);
Py_CLEAR(state->Mod_singleton);
Py_CLEAR(state->Mod_type);
Py_CLEAR(state->Module_type);
Py_CLEAR(state->Mult_singleton);
Py_CLEAR(state->Mult_type);
Py_CLEAR(state->Name_type);
Py_CLEAR(state->NamedExpr_type);
Py_CLEAR(state->Nonlocal_type);
Py_CLEAR(state->NotEq_singleton);
Py_CLEAR(state->NotEq_type);
Py_CLEAR(state->NotIn_singleton);
Py_CLEAR(state->NotIn_type);
Py_CLEAR(state->Not_singleton);
Py_CLEAR(state->Not_type);
Py_CLEAR(state->Or_singleton);
Py_CLEAR(state->Or_type);
Py_CLEAR(state->Pass_type);
Py_CLEAR(state->Pow_singleton);
Py_CLEAR(state->Pow_type);
Py_CLEAR(state->RShift_singleton);
Py_CLEAR(state->RShift_type);
Py_CLEAR(state->Raise_type);
Py_CLEAR(state->Return_type);
Py_CLEAR(state->SetComp_type);
Py_CLEAR(state->Set_type);
Py_CLEAR(state->Slice_type);
Py_CLEAR(state->Starred_type);
Py_CLEAR(state->Store_singleton);
Py_CLEAR(state->Store_type);
Py_CLEAR(state->Sub_singleton);
Py_CLEAR(state->Sub_type);
Py_CLEAR(state->Subscript_type);
Py_CLEAR(state->Try_type);
Py_CLEAR(state->Tuple_type);
Py_CLEAR(state->TypeIgnore_type);
Py_CLEAR(state->UAdd_singleton);
Py_CLEAR(state->UAdd_type);
Py_CLEAR(state->USub_singleton);
Py_CLEAR(state->USub_type);
Py_CLEAR(state->UnaryOp_type);
Py_CLEAR(state->While_type);
Py_CLEAR(state->With_type);
Py_CLEAR(state->YieldFrom_type);
Py_CLEAR(state->Yield_type);
Py_CLEAR(state->__dict__);
Py_CLEAR(state->__doc__);
Py_CLEAR(state->__match_args__);
Py_CLEAR(state->__module__);
Py_CLEAR(state->_attributes);
Py_CLEAR(state->_fields);
Py_CLEAR(state->alias_type);
Py_CLEAR(state->annotation);
Py_CLEAR(state->arg);
Py_CLEAR(state->arg_type);
Py_CLEAR(state->args);
Py_CLEAR(state->argtypes);
Py_CLEAR(state->arguments_type);
Py_CLEAR(state->asname);
Py_CLEAR(state->ast);
Py_CLEAR(state->attr);
Py_CLEAR(state->bases);
Py_CLEAR(state->body);
Py_CLEAR(state->boolop_type);
Py_CLEAR(state->cases);
Py_CLEAR(state->cause);
Py_CLEAR(state->cmpop_type);
Py_CLEAR(state->col_offset);
Py_CLEAR(state->comparators);
Py_CLEAR(state->comprehension_type);
Py_CLEAR(state->context_expr);
Py_CLEAR(state->conversion);
Py_CLEAR(state->ctx);
Py_CLEAR(state->decorator_list);
Py_CLEAR(state->defaults);
Py_CLEAR(state->elt);
Py_CLEAR(state->elts);
Py_CLEAR(state->end_col_offset);
Py_CLEAR(state->end_lineno);
Py_CLEAR(state->exc);
Py_CLEAR(state->excepthandler_type);
Py_CLEAR(state->expr_context_type);
Py_CLEAR(state->expr_type);
Py_CLEAR(state->finalbody);
Py_CLEAR(state->format_spec);
Py_CLEAR(state->func);
Py_CLEAR(state->generators);
Py_CLEAR(state->guard);
Py_CLEAR(state->handlers);
Py_CLEAR(state->id);
Py_CLEAR(state->ifs);
Py_CLEAR(state->is_async);
Py_CLEAR(state->items);
Py_CLEAR(state->iter);
Py_CLEAR(state->key);
Py_CLEAR(state->keys);
Py_CLEAR(state->keyword_type);
Py_CLEAR(state->keywords);
Py_CLEAR(state->kind);
Py_CLEAR(state->kw_defaults);
Py_CLEAR(state->kwarg);
Py_CLEAR(state->kwonlyargs);
Py_CLEAR(state->left);
Py_CLEAR(state->level);
Py_CLEAR(state->lineno);
Py_CLEAR(state->lower);
Py_CLEAR(state->match_case_type);
Py_CLEAR(state->mod_type);
Py_CLEAR(state->module);
Py_CLEAR(state->msg);
Py_CLEAR(state->name);
Py_CLEAR(state->names);
Py_CLEAR(state->op);
Py_CLEAR(state->operand);
Py_CLEAR(state->operator_type);
Py_CLEAR(state->ops);
Py_CLEAR(state->optional_vars);
Py_CLEAR(state->orelse);
Py_CLEAR(state->pattern);
Py_CLEAR(state->patterns);
Py_CLEAR(state->posonlyargs);
Py_CLEAR(state->returns);
Py_CLEAR(state->right);
Py_CLEAR(state->simple);
Py_CLEAR(state->slice);
Py_CLEAR(state->step);
Py_CLEAR(state->stmt_type);
Py_CLEAR(state->subject);
Py_CLEAR(state->tag);
Py_CLEAR(state->target);
Py_CLEAR(state->targets);
Py_CLEAR(state->test);
Py_CLEAR(state->type);
Py_CLEAR(state->type_comment);
Py_CLEAR(state->type_ignore_type);
Py_CLEAR(state->type_ignores);
Py_CLEAR(state->unaryop_type);
Py_CLEAR(state->upper);
Py_CLEAR(state->value);
Py_CLEAR(state->values);
Py_CLEAR(state->vararg);
Py_CLEAR(state->withitem_type);
#if !defined(NDEBUG)
state->initialized = -1;
#else
state->initialized = 0;
#endif
}
static int init_identifiers(struct ast_state *state)
{
if ((state->__dict__ = PyUnicode_InternFromString("__dict__")) == NULL) return 0;
if ((state->__doc__ = PyUnicode_InternFromString("__doc__")) == NULL) return 0;
if ((state->__match_args__ = PyUnicode_InternFromString("__match_args__")) == NULL) return 0;
if ((state->__module__ = PyUnicode_InternFromString("__module__")) == NULL) return 0;
if ((state->_attributes = PyUnicode_InternFromString("_attributes")) == NULL) return 0;
if ((state->_fields = PyUnicode_InternFromString("_fields")) == NULL) return 0;
if ((state->annotation = PyUnicode_InternFromString("annotation")) == NULL) return 0;
if ((state->arg = PyUnicode_InternFromString("arg")) == NULL) return 0;
if ((state->args = PyUnicode_InternFromString("args")) == NULL) return 0;
if ((state->argtypes = PyUnicode_InternFromString("argtypes")) == NULL) return 0;
if ((state->asname = PyUnicode_InternFromString("asname")) == NULL) return 0;
if ((state->ast = PyUnicode_InternFromString("ast")) == NULL) return 0;
if ((state->attr = PyUnicode_InternFromString("attr")) == NULL) return 0;
if ((state->bases = PyUnicode_InternFromString("bases")) == NULL) return 0;
if ((state->body = PyUnicode_InternFromString("body")) == NULL) return 0;
if ((state->cases = PyUnicode_InternFromString("cases")) == NULL) return 0;
if ((state->cause = PyUnicode_InternFromString("cause")) == NULL) return 0;
if ((state->col_offset = PyUnicode_InternFromString("col_offset")) == NULL) return 0;
if ((state->comparators = PyUnicode_InternFromString("comparators")) == NULL) return 0;
if ((state->context_expr = PyUnicode_InternFromString("context_expr")) == NULL) return 0;
if ((state->conversion = PyUnicode_InternFromString("conversion")) == NULL) return 0;
if ((state->ctx = PyUnicode_InternFromString("ctx")) == NULL) return 0;
if ((state->decorator_list = PyUnicode_InternFromString("decorator_list")) == NULL) return 0;
if ((state->defaults = PyUnicode_InternFromString("defaults")) == NULL) return 0;
if ((state->elt = PyUnicode_InternFromString("elt")) == NULL) return 0;
if ((state->elts = PyUnicode_InternFromString("elts")) == NULL) return 0;
if ((state->end_col_offset = PyUnicode_InternFromString("end_col_offset")) == NULL) return 0;
if ((state->end_lineno = PyUnicode_InternFromString("end_lineno")) == NULL) return 0;
if ((state->exc = PyUnicode_InternFromString("exc")) == NULL) return 0;
if ((state->finalbody = PyUnicode_InternFromString("finalbody")) == NULL) return 0;
if ((state->format_spec = PyUnicode_InternFromString("format_spec")) == NULL) return 0;
if ((state->func = PyUnicode_InternFromString("func")) == NULL) return 0;
if ((state->generators = PyUnicode_InternFromString("generators")) == NULL) return 0;
if ((state->guard = PyUnicode_InternFromString("guard")) == NULL) return 0;
if ((state->handlers = PyUnicode_InternFromString("handlers")) == NULL) return 0;
if ((state->id = PyUnicode_InternFromString("id")) == NULL) return 0;
if ((state->ifs = PyUnicode_InternFromString("ifs")) == NULL) return 0;
if ((state->is_async = PyUnicode_InternFromString("is_async")) == NULL) return 0;
if ((state->items = PyUnicode_InternFromString("items")) == NULL) return 0;
if ((state->iter = PyUnicode_InternFromString("iter")) == NULL) return 0;
if ((state->key = PyUnicode_InternFromString("key")) == NULL) return 0;
if ((state->keys = PyUnicode_InternFromString("keys")) == NULL) return 0;
if ((state->keywords = PyUnicode_InternFromString("keywords")) == NULL) return 0;
if ((state->kind = PyUnicode_InternFromString("kind")) == NULL) return 0;
if ((state->kw_defaults = PyUnicode_InternFromString("kw_defaults")) == NULL) return 0;
if ((state->kwarg = PyUnicode_InternFromString("kwarg")) == NULL) return 0;
if ((state->kwonlyargs = PyUnicode_InternFromString("kwonlyargs")) == NULL) return 0;
if ((state->left = PyUnicode_InternFromString("left")) == NULL) return 0;
if ((state->level = PyUnicode_InternFromString("level")) == NULL) return 0;
if ((state->lineno = PyUnicode_InternFromString("lineno")) == NULL) return 0;
if ((state->lower = PyUnicode_InternFromString("lower")) == NULL) return 0;
if ((state->module = PyUnicode_InternFromString("module")) == NULL) return 0;
if ((state->msg = PyUnicode_InternFromString("msg")) == NULL) return 0;
if ((state->name = PyUnicode_InternFromString("name")) == NULL) return 0;
if ((state->names = PyUnicode_InternFromString("names")) == NULL) return 0;
if ((state->op = PyUnicode_InternFromString("op")) == NULL) return 0;
if ((state->operand = PyUnicode_InternFromString("operand")) == NULL) return 0;
if ((state->ops = PyUnicode_InternFromString("ops")) == NULL) return 0;
if ((state->optional_vars = PyUnicode_InternFromString("optional_vars")) == NULL) return 0;
if ((state->orelse = PyUnicode_InternFromString("orelse")) == NULL) return 0;
if ((state->pattern = PyUnicode_InternFromString("pattern")) == NULL) return 0;
if ((state->patterns = PyUnicode_InternFromString("patterns")) == NULL) return 0;
if ((state->posonlyargs = PyUnicode_InternFromString("posonlyargs")) == NULL) return 0;
if ((state->returns = PyUnicode_InternFromString("returns")) == NULL) return 0;
if ((state->right = PyUnicode_InternFromString("right")) == NULL) return 0;
if ((state->simple = PyUnicode_InternFromString("simple")) == NULL) return 0;
if ((state->slice = PyUnicode_InternFromString("slice")) == NULL) return 0;
if ((state->step = PyUnicode_InternFromString("step")) == NULL) return 0;
if ((state->subject = PyUnicode_InternFromString("subject")) == NULL) return 0;
if ((state->tag = PyUnicode_InternFromString("tag")) == NULL) return 0;
if ((state->target = PyUnicode_InternFromString("target")) == NULL) return 0;
if ((state->targets = PyUnicode_InternFromString("targets")) == NULL) return 0;
if ((state->test = PyUnicode_InternFromString("test")) == NULL) return 0;
if ((state->type = PyUnicode_InternFromString("type")) == NULL) return 0;
if ((state->type_comment = PyUnicode_InternFromString("type_comment")) == NULL) return 0;
if ((state->type_ignores = PyUnicode_InternFromString("type_ignores")) == NULL) return 0;
if ((state->upper = PyUnicode_InternFromString("upper")) == NULL) return 0;
if ((state->value = PyUnicode_InternFromString("value")) == NULL) return 0;
if ((state->values = PyUnicode_InternFromString("values")) == NULL) return 0;
if ((state->vararg = PyUnicode_InternFromString("vararg")) == NULL) return 0;
return 1;
};
GENERATE_ASDL_SEQ_CONSTRUCTOR(mod, mod_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(stmt, stmt_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(expr, expr_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(comprehension, comprehension_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(excepthandler, excepthandler_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(arguments, arguments_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(arg, arg_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(keyword, keyword_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(alias, alias_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(withitem, withitem_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(match_case, match_case_ty)
GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty)
static PyObject* ast2obj_mod(struct ast_state *state, void*);
static const char * const Module_fields[]={
"body",
"type_ignores",
};
static const char * const Interactive_fields[]={
"body",
};
static const char * const Expression_fields[]={
"body",
};
static const char * const FunctionType_fields[]={
"argtypes",
"returns",
};
static const char * const stmt_attributes[] = {
"lineno",
"col_offset",
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
"end_lineno",
"end_col_offset",
};
static PyObject* ast2obj_stmt(struct ast_state *state, void*);
static const char * const FunctionDef_fields[]={
"name",
"args",
"body",
"decorator_list",
"returns",
"type_comment",
};
static const char * const AsyncFunctionDef_fields[]={
"name",
"args",
"body",
"decorator_list",
"returns",
"type_comment",
};
static const char * const ClassDef_fields[]={
"name",
"bases",
"keywords",
"body",
"decorator_list",
};
static const char * const Return_fields[]={
"value",
};
static const char * const Delete_fields[]={
"targets",
};
static const char * const Assign_fields[]={
"targets",
"value",
"type_comment",
};
static const char * const AugAssign_fields[]={
"target",
"op",
"value",
};
static const char * const AnnAssign_fields[]={
"target",
"annotation",
"value",
"simple",
};
static const char * const For_fields[]={
"target",
"iter",
"body",
"orelse",
"type_comment",
};
static const char * const AsyncFor_fields[]={
"target",
"iter",
"body",
"orelse",
"type_comment",
};
static const char * const While_fields[]={
"test",
"body",
"orelse",
};
static const char * const If_fields[]={
"test",
"body",
"orelse",
};
static const char * const With_fields[]={
"items",
"body",
"type_comment",
};
static const char * const AsyncWith_fields[]={
"items",
"body",
"type_comment",
};
static const char * const Match_fields[]={
"subject",
"cases",
};
static const char * const Raise_fields[]={
"exc",
"cause",
};
static const char * const Try_fields[]={
"body",
"handlers",
"orelse",
"finalbody",
};
static const char * const Assert_fields[]={
"test",
"msg",
};
static const char * const Import_fields[]={
"names",
};
static const char * const ImportFrom_fields[]={
"module",
"names",
"level",
};
static const char * const Global_fields[]={
"names",
};
static const char * const Nonlocal_fields[]={
"names",
};
static const char * const Expr_fields[]={
"value",
};
static const char * const expr_attributes[] = {
"lineno",
"col_offset",
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
"end_lineno",
"end_col_offset",
};
static PyObject* ast2obj_expr(struct ast_state *state, void*);
static const char * const BoolOp_fields[]={
"op",
"values",
};
static const char * const NamedExpr_fields[]={
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
"target",
"value",
};
static const char * const BinOp_fields[]={
"left",
"op",
"right",
};
static const char * const UnaryOp_fields[]={
"op",
"operand",
};
static const char * const Lambda_fields[]={
"args",
"body",
};
static const char * const IfExp_fields[]={
"test",
"body",
"orelse",
};
static const char * const Dict_fields[]={
"keys",
"values",
};
static const char * const Set_fields[]={
"elts",
};
static const char * const ListComp_fields[]={
"elt",
"generators",
};
static const char * const SetComp_fields[]={
"elt",
"generators",
};
static const char * const DictComp_fields[]={
"key",
"value",
"generators",
Merged revisions 56154-56264 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r56155 | neal.norwitz | 2007-07-03 08:59:08 +0300 (Tue, 03 Jul 2007) | 1 line Get this test working after converting map to return an iterator ................ r56202 | neal.norwitz | 2007-07-09 04:30:09 +0300 (Mon, 09 Jul 2007) | 37 lines Merged revisions 56124-56201 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r56129 | georg.brandl | 2007-06-30 04:01:01 -0700 (Sat, 30 Jun 2007) | 2 lines Document smtp.SMTPAuthenticationError. ........ r56137 | georg.brandl | 2007-07-01 01:11:35 -0700 (Sun, 01 Jul 2007) | 2 lines Fix a few webbrowser.py problems. ........ r56143 | georg.brandl | 2007-07-02 04:54:28 -0700 (Mon, 02 Jul 2007) | 2 lines Remove duplicate sentence from alarm() doc. ........ r56170 | mark.hammond | 2007-07-03 19:03:10 -0700 (Tue, 03 Jul 2007) | 3 lines copy built files to the PCBuild directory, where tools like distutils or external build processes can find them. ........ r56176 | kurt.kaiser | 2007-07-05 15:03:39 -0700 (Thu, 05 Jul 2007) | 10 lines Many calls to tk.call involve an arglist containing a single tuple. Calls using METH_OLDARGS unpack this tuple; calls using METH_VARARG don't. Tcl's concatenation of args was affected; IDLE doesn't start. Modify Tkapp_Call() to unpack single tuple arglists. Bug 1733943 Ref http://mail.python.org/pipermail/python-checkins/2007-May/060454.html ........ r56177 | neal.norwitz | 2007-07-05 21:13:39 -0700 (Thu, 05 Jul 2007) | 1 line Fix typo in comment ........ ................ r56251 | neal.norwitz | 2007-07-11 10:01:01 +0300 (Wed, 11 Jul 2007) | 1 line Get working with map returning an iterator (had to fix whitespace too) ................ r56255 | thomas.wouters | 2007-07-11 13:41:37 +0300 (Wed, 11 Jul 2007) | 6 lines Clean up merge glitch or copy-paste error (the entire module was duplicated, except the first half even had some more copy-paste errors, referring to listcomps and genexps instead of setcomps) ................ r56256 | thomas.wouters | 2007-07-11 15:16:01 +0300 (Wed, 11 Jul 2007) | 14 lines Dict comprehensions. Still needs doc changes (like many python-3000 features ;-). It generates bytecode similar to: x = {} for k, v in (generator here): x[k] = v except there is no tuple-packing and -unpacking involved. Trivial measurement suggests it's significantly faster than dict(generator here) (in the order of 2 to 3 times as fast) but I have not done extensive measurements. ................ r56263 | guido.van.rossum | 2007-07-11 15:36:26 +0300 (Wed, 11 Jul 2007) | 3 lines Patch 1724999 by Ali Gholami Rudi -- avoid complaints about dict size change during iter in destroy call. ................
2007-07-11 10:09:30 -03:00
};
static const char * const GeneratorExp_fields[]={
"elt",
"generators",
};
static const char * const Await_fields[]={
"value",
};
static const char * const Yield_fields[]={
"value",
};
static const char * const YieldFrom_fields[]={
"value",
};
static const char * const Compare_fields[]={
"left",
"ops",
"comparators",
};
static const char * const Call_fields[]={
"func",
"args",
"keywords",
};
static const char * const FormattedValue_fields[]={
"value",
"conversion",
"format_spec",
};
static const char * const JoinedStr_fields[]={
"values",
};
static const char * const Constant_fields[]={
"value",
"kind",
};
static const char * const Attribute_fields[]={
"value",
"attr",
"ctx",
};
static const char * const Subscript_fields[]={
"value",
"slice",
"ctx",
};
static const char * const Starred_fields[]={
"value",
"ctx",
Merged revisions 55225-55227,55229-55269 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r55238 | guido.van.rossum | 2007-05-10 16:46:05 -0700 (Thu, 10 May 2007) | 9 lines Merged revisions 55227 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55227 | guido.van.rossum | 2007-05-10 10:20:15 -0700 (Thu, 10 May 2007) | 2 lines Fix a bug in test_c_api() that caused a negative refcount. ........ ................ r55246 | neal.norwitz | 2007-05-11 00:01:52 -0700 (Fri, 11 May 2007) | 1 line Remove commands.getstatus() it is obsolete. ................ r55248 | neal.norwitz | 2007-05-11 00:29:05 -0700 (Fri, 11 May 2007) | 2 lines Remove bsddb185 support. ................ r55249 | neal.norwitz | 2007-05-11 00:29:50 -0700 (Fri, 11 May 2007) | 1 line Remove bsddb185 module too ................ r55250 | neal.norwitz | 2007-05-11 00:32:13 -0700 (Fri, 11 May 2007) | 1 line bsddb185: Gotta remove from the file checked in, not Setup ................ r55251 | neal.norwitz | 2007-05-11 00:53:26 -0700 (Fri, 11 May 2007) | 1 line Remove obsolete IRIX modules (as much as I could find, there is probably more) ................ r55252 | neal.norwitz | 2007-05-11 00:55:35 -0700 (Fri, 11 May 2007) | 1 line Remove SGI turd. ................ r55254 | georg.brandl | 2007-05-11 03:11:01 -0700 (Fri, 11 May 2007) | 2 lines Add a case for set comprehensions to the "cannot assign to" switch. ................ r55255 | georg.brandl | 2007-05-11 03:11:25 -0700 (Fri, 11 May 2007) | 2 lines Fix wrong imports. ................ r55261 | georg.brandl | 2007-05-11 07:37:48 -0700 (Fri, 11 May 2007) | 2 lines Remove removed tex files. ................ r55262 | georg.brandl | 2007-05-11 08:28:41 -0700 (Fri, 11 May 2007) | 2 lines Commit PEP 3132 implementation. ................ r55264 | georg.brandl | 2007-05-11 08:50:19 -0700 (Fri, 11 May 2007) | 2 lines Check in the inevitable AST version number and format Py_ssize_t with %zd. ................ r55265 | neal.norwitz | 2007-05-11 09:12:22 -0700 (Fri, 11 May 2007) | 1 line Remove mention of os.popen* and popen2.* since these will be removed. ................ r55266 | neal.norwitz | 2007-05-11 09:19:57 -0700 (Fri, 11 May 2007) | 1 line Get doc to build again (almost, the doc is fine) ................ r55267 | neal.norwitz | 2007-05-11 09:21:02 -0700 (Fri, 11 May 2007) | 1 line Really get doc to build (remove use of string module) ................ r55269 | neal.norwitz | 2007-05-11 09:29:43 -0700 (Fri, 11 May 2007) | 1 line Add some notes to cleanup later ................
2007-05-11 13:50:42 -03:00
};
static const char * const Name_fields[]={
"id",
"ctx",
};
static const char * const List_fields[]={
"elts",
"ctx",
};
static const char * const Tuple_fields[]={
"elts",
"ctx",
};
static const char * const Slice_fields[]={
"lower",
"upper",
"step",
};
static const char * const MatchAs_fields[]={
"pattern",
"name",
};
static const char * const MatchOr_fields[]={
"patterns",
};
static PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty);
static PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty);
static PyObject* ast2obj_operator(struct ast_state *state, operator_ty);
static PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty);
static PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty);
static PyObject* ast2obj_comprehension(struct ast_state *state, void*);
static const char * const comprehension_fields[]={
"target",
"iter",
"ifs",
"is_async",
};
static const char * const excepthandler_attributes[] = {
"lineno",
"col_offset",
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
"end_lineno",
"end_col_offset",
};
static PyObject* ast2obj_excepthandler(struct ast_state *state, void*);
static const char * const ExceptHandler_fields[]={
"type",
"name",
"body",
};
static PyObject* ast2obj_arguments(struct ast_state *state, void*);
static const char * const arguments_fields[]={
"posonlyargs",
"args",
"vararg",
"kwonlyargs",
"kw_defaults",
"kwarg",
"defaults",
};
static PyObject* ast2obj_arg(struct ast_state *state, void*);
static const char * const arg_attributes[] = {
"lineno",
"col_offset",
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
"end_lineno",
"end_col_offset",
};
static const char * const arg_fields[]={
"arg",
"annotation",
"type_comment",
};
static PyObject* ast2obj_keyword(struct ast_state *state, void*);
static const char * const keyword_attributes[] = {
"lineno",
"col_offset",
"end_lineno",
"end_col_offset",
};
static const char * const keyword_fields[]={
"arg",
"value",
};
static PyObject* ast2obj_alias(struct ast_state *state, void*);
static const char * const alias_attributes[] = {
"lineno",
"col_offset",
"end_lineno",
"end_col_offset",
};
static const char * const alias_fields[]={
"name",
"asname",
};
static PyObject* ast2obj_withitem(struct ast_state *state, void*);
static const char * const withitem_fields[]={
"context_expr",
"optional_vars",
};
static PyObject* ast2obj_match_case(struct ast_state *state, void*);
static const char * const match_case_fields[]={
"pattern",
"guard",
"body",
};
static PyObject* ast2obj_type_ignore(struct ast_state *state, void*);
static const char * const TypeIgnore_fields[]={
"lineno",
"tag",
};
2012-03-12 13:46:44 -03:00
typedef struct {
PyObject_HEAD
2012-03-12 13:46:44 -03:00
PyObject *dict;
} AST_object;
2012-03-14 23:50:29 -03:00
static void
ast_dealloc(AST_object *self)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
2019-09-14 10:38:17 -03:00
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
2012-03-14 23:50:29 -03:00
Py_CLEAR(self->dict);
2019-09-14 10:38:17 -03:00
freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
assert(free_func != NULL);
free_func(self);
Py_DECREF(tp);
2012-03-14 23:50:29 -03:00
}
static int
ast_traverse(AST_object *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
Py_VISIT(self->dict);
return 0;
}
static int
ast_clear(AST_object *self)
{
Py_CLEAR(self->dict);
return 0;
}
static int
ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return -1;
}
Py_ssize_t i, numfields = 0;
int res = -1;
PyObject *key, *value, *fields;
if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
goto cleanup;
}
if (fields) {
numfields = PySequence_Size(fields);
if (numfields == -1) {
goto cleanup;
}
}
res = 0; /* if no error occurs, this stays 0 to the end */
if (numfields < PyTuple_GET_SIZE(args)) {
PyErr_Format(PyExc_TypeError, "%.400s constructor takes at most "
"%zd positional argument%s",
_PyType_Name(Py_TYPE(self)),
numfields, numfields == 1 ? "" : "s");
res = -1;
goto cleanup;
}
for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
/* cannot be reached when fields is NULL */
PyObject *name = PySequence_GetItem(fields, i);
if (!name) {
res = -1;
goto cleanup;
}
res = PyObject_SetAttr(self, name, PyTuple_GET_ITEM(args, i));
Py_DECREF(name);
if (res < 0) {
goto cleanup;
}
}
if (kw) {
i = 0; /* needed by PyDict_Next */
while (PyDict_Next(kw, &i, &key, &value)) {
int contains = PySequence_Contains(fields, key);
if (contains == -1) {
res = -1;
goto cleanup;
} else if (contains == 1) {
Py_ssize_t p = PySequence_Index(fields, key);
if (p == -1) {
res = -1;
goto cleanup;
}
if (p < PyTuple_GET_SIZE(args)) {
PyErr_Format(PyExc_TypeError,
"%.400s got multiple values for argument '%U'",
Py_TYPE(self)->tp_name, key);
res = -1;
goto cleanup;
}
}
res = PyObject_SetAttr(self, key, value);
if (res < 0) {
goto cleanup;
}
}
}
cleanup:
Py_XDECREF(fields);
return res;
}
Merged revisions 61440-61441,61443,61445-61448,61451-61452,61455-61457,61459-61464,61466-61467,61469-61470,61476-61477,61479,61481-61482,61485,61487,61490,61493-61494,61497,61499-61502,61505-61506,61508,61511-61514,61519,61521-61522,61530-61531,61533-61537,61541-61555,61557-61558,61561-61562,61566-61569,61572-61574,61578-61579,61583-61584,61588-61589,61592,61594,61598-61601,61603-61604,61607-61612,61617,61619-61620,61624,61626,61628-61630,61635-61638,61640-61643,61645,61648,61653-61655,61659-61662,61664,61666,61668-61671,61673,61675,61679-61680,61682,61685-61686,61689-61695,61697-61699,61701-61703,61706,61710,61713,61717,61723,61726-61730,61736,61738,61740,61742,61745-61752,61754-61760,61762-61764,61768,61770-61772,61774-61775,61784-61787,61789-61792,61794-61795,61797-61806,61808-61809,61811-61812,61814-61819,61824,61826-61833,61835-61840,61843-61845,61848,61850,61854-61862,61865-61866,61868,61872-61873,61876-61877,61883-61888,61890-61891,61893-61899,61901-61903,61905-61912,61914,61917,61920-61921,61927,61930,61932-61934,61939,61941-61942,61944-61951,61955,61960-61963,61980,61982-61983,61991,61994-61996,62001-62003,62008-62010,62016-62017,62022,62024,62027,62031-62034,62041,62045-62046,62048,62050-62051,62055-62066,62068-62074,62076-62078 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62048 | georg.brandl | 2008-03-29 23:53:55 -0700 (Sat, 29 Mar 2008) | 2 lines Adapt test_ast to the new ExceptHandler type. ........ r62050 | georg.brandl | 2008-03-30 00:09:22 -0700 (Sun, 30 Mar 2008) | 2 lines Convert test_ast to unittest and add a test for r62049. ........ r62051 | georg.brandl | 2008-03-30 12:00:49 -0700 (Sun, 30 Mar 2008) | 2 lines Make _fields attr for no fields consistent with _attributes attr. ........ r62059 | georg.brandl | 2008-03-30 13:20:39 -0700 (Sun, 30 Mar 2008) | 2 lines Make AST nodes pickleable. ........
2008-03-31 02:29:39 -03:00
/* Pickling support */
static PyObject *
ast_type_reduce(PyObject *self, PyObject *unused)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return NULL;
}
PyObject *dict;
if (_PyObject_LookupAttr(self, state->__dict__, &dict) < 0) {
return NULL;
Merged revisions 61440-61441,61443,61445-61448,61451-61452,61455-61457,61459-61464,61466-61467,61469-61470,61476-61477,61479,61481-61482,61485,61487,61490,61493-61494,61497,61499-61502,61505-61506,61508,61511-61514,61519,61521-61522,61530-61531,61533-61537,61541-61555,61557-61558,61561-61562,61566-61569,61572-61574,61578-61579,61583-61584,61588-61589,61592,61594,61598-61601,61603-61604,61607-61612,61617,61619-61620,61624,61626,61628-61630,61635-61638,61640-61643,61645,61648,61653-61655,61659-61662,61664,61666,61668-61671,61673,61675,61679-61680,61682,61685-61686,61689-61695,61697-61699,61701-61703,61706,61710,61713,61717,61723,61726-61730,61736,61738,61740,61742,61745-61752,61754-61760,61762-61764,61768,61770-61772,61774-61775,61784-61787,61789-61792,61794-61795,61797-61806,61808-61809,61811-61812,61814-61819,61824,61826-61833,61835-61840,61843-61845,61848,61850,61854-61862,61865-61866,61868,61872-61873,61876-61877,61883-61888,61890-61891,61893-61899,61901-61903,61905-61912,61914,61917,61920-61921,61927,61930,61932-61934,61939,61941-61942,61944-61951,61955,61960-61963,61980,61982-61983,61991,61994-61996,62001-62003,62008-62010,62016-62017,62022,62024,62027,62031-62034,62041,62045-62046,62048,62050-62051,62055-62066,62068-62074,62076-62078 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62048 | georg.brandl | 2008-03-29 23:53:55 -0700 (Sat, 29 Mar 2008) | 2 lines Adapt test_ast to the new ExceptHandler type. ........ r62050 | georg.brandl | 2008-03-30 00:09:22 -0700 (Sun, 30 Mar 2008) | 2 lines Convert test_ast to unittest and add a test for r62049. ........ r62051 | georg.brandl | 2008-03-30 12:00:49 -0700 (Sun, 30 Mar 2008) | 2 lines Make _fields attr for no fields consistent with _attributes attr. ........ r62059 | georg.brandl | 2008-03-30 13:20:39 -0700 (Sun, 30 Mar 2008) | 2 lines Make AST nodes pickleable. ........
2008-03-31 02:29:39 -03:00
}
if (dict) {
return Py_BuildValue("O()N", Py_TYPE(self), dict);
Merged revisions 61440-61441,61443,61445-61448,61451-61452,61455-61457,61459-61464,61466-61467,61469-61470,61476-61477,61479,61481-61482,61485,61487,61490,61493-61494,61497,61499-61502,61505-61506,61508,61511-61514,61519,61521-61522,61530-61531,61533-61537,61541-61555,61557-61558,61561-61562,61566-61569,61572-61574,61578-61579,61583-61584,61588-61589,61592,61594,61598-61601,61603-61604,61607-61612,61617,61619-61620,61624,61626,61628-61630,61635-61638,61640-61643,61645,61648,61653-61655,61659-61662,61664,61666,61668-61671,61673,61675,61679-61680,61682,61685-61686,61689-61695,61697-61699,61701-61703,61706,61710,61713,61717,61723,61726-61730,61736,61738,61740,61742,61745-61752,61754-61760,61762-61764,61768,61770-61772,61774-61775,61784-61787,61789-61792,61794-61795,61797-61806,61808-61809,61811-61812,61814-61819,61824,61826-61833,61835-61840,61843-61845,61848,61850,61854-61862,61865-61866,61868,61872-61873,61876-61877,61883-61888,61890-61891,61893-61899,61901-61903,61905-61912,61914,61917,61920-61921,61927,61930,61932-61934,61939,61941-61942,61944-61951,61955,61960-61963,61980,61982-61983,61991,61994-61996,62001-62003,62008-62010,62016-62017,62022,62024,62027,62031-62034,62041,62045-62046,62048,62050-62051,62055-62066,62068-62074,62076-62078 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62048 | georg.brandl | 2008-03-29 23:53:55 -0700 (Sat, 29 Mar 2008) | 2 lines Adapt test_ast to the new ExceptHandler type. ........ r62050 | georg.brandl | 2008-03-30 00:09:22 -0700 (Sun, 30 Mar 2008) | 2 lines Convert test_ast to unittest and add a test for r62049. ........ r62051 | georg.brandl | 2008-03-30 12:00:49 -0700 (Sun, 30 Mar 2008) | 2 lines Make _fields attr for no fields consistent with _attributes attr. ........ r62059 | georg.brandl | 2008-03-30 13:20:39 -0700 (Sun, 30 Mar 2008) | 2 lines Make AST nodes pickleable. ........
2008-03-31 02:29:39 -03:00
}
return Py_BuildValue("O()", Py_TYPE(self));
}
static PyMemberDef ast_type_members[] = {
{"__dictoffset__", T_PYSSIZET, offsetof(AST_object, dict), READONLY},
{NULL} /* Sentinel */
};
Merged revisions 61440-61441,61443,61445-61448,61451-61452,61455-61457,61459-61464,61466-61467,61469-61470,61476-61477,61479,61481-61482,61485,61487,61490,61493-61494,61497,61499-61502,61505-61506,61508,61511-61514,61519,61521-61522,61530-61531,61533-61537,61541-61555,61557-61558,61561-61562,61566-61569,61572-61574,61578-61579,61583-61584,61588-61589,61592,61594,61598-61601,61603-61604,61607-61612,61617,61619-61620,61624,61626,61628-61630,61635-61638,61640-61643,61645,61648,61653-61655,61659-61662,61664,61666,61668-61671,61673,61675,61679-61680,61682,61685-61686,61689-61695,61697-61699,61701-61703,61706,61710,61713,61717,61723,61726-61730,61736,61738,61740,61742,61745-61752,61754-61760,61762-61764,61768,61770-61772,61774-61775,61784-61787,61789-61792,61794-61795,61797-61806,61808-61809,61811-61812,61814-61819,61824,61826-61833,61835-61840,61843-61845,61848,61850,61854-61862,61865-61866,61868,61872-61873,61876-61877,61883-61888,61890-61891,61893-61899,61901-61903,61905-61912,61914,61917,61920-61921,61927,61930,61932-61934,61939,61941-61942,61944-61951,61955,61960-61963,61980,61982-61983,61991,61994-61996,62001-62003,62008-62010,62016-62017,62022,62024,62027,62031-62034,62041,62045-62046,62048,62050-62051,62055-62066,62068-62074,62076-62078 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62048 | georg.brandl | 2008-03-29 23:53:55 -0700 (Sat, 29 Mar 2008) | 2 lines Adapt test_ast to the new ExceptHandler type. ........ r62050 | georg.brandl | 2008-03-30 00:09:22 -0700 (Sun, 30 Mar 2008) | 2 lines Convert test_ast to unittest and add a test for r62049. ........ r62051 | georg.brandl | 2008-03-30 12:00:49 -0700 (Sun, 30 Mar 2008) | 2 lines Make _fields attr for no fields consistent with _attributes attr. ........ r62059 | georg.brandl | 2008-03-30 13:20:39 -0700 (Sun, 30 Mar 2008) | 2 lines Make AST nodes pickleable. ........
2008-03-31 02:29:39 -03:00
static PyMethodDef ast_type_methods[] = {
{"__reduce__", ast_type_reduce, METH_NOARGS, NULL},
{NULL}
};
2012-03-12 13:46:44 -03:00
static PyGetSetDef ast_type_getsets[] = {
{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
{NULL}
};
static PyType_Slot AST_type_slots[] = {
{Py_tp_dealloc, ast_dealloc},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_setattro, PyObject_GenericSetAttr},
{Py_tp_traverse, ast_traverse},
{Py_tp_clear, ast_clear},
{Py_tp_members, ast_type_members},
{Py_tp_methods, ast_type_methods},
{Py_tp_getset, ast_type_getsets},
{Py_tp_init, ast_type_init},
{Py_tp_alloc, PyType_GenericAlloc},
{Py_tp_new, PyType_GenericNew},
{Py_tp_free, PyObject_GC_Del},
{0, 0},
};
static PyType_Spec AST_type_spec = {
"ast.AST",
2012-03-12 13:46:44 -03:00
sizeof(AST_object),
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
AST_type_slots
};
static PyObject *
make_type(struct ast_state *state, const char *type, PyObject* base,
const char* const* fields, int num_fields, const char *doc)
{
PyObject *fnames, *result;
int i;
Merged revisions 61440-61441,61443,61445-61448,61451-61452,61455-61457,61459-61464,61466-61467,61469-61470,61476-61477,61479,61481-61482,61485,61487,61490,61493-61494,61497,61499-61502,61505-61506,61508,61511-61514,61519,61521-61522,61530-61531,61533-61537,61541-61555,61557-61558,61561-61562,61566-61569,61572-61574,61578-61579,61583-61584,61588-61589,61592,61594,61598-61601,61603-61604,61607-61612,61617,61619-61620,61624,61626,61628-61630,61635-61638,61640-61643,61645,61648,61653-61655,61659-61662,61664,61666,61668-61671,61673,61675,61679-61680,61682,61685-61686,61689-61695,61697-61699,61701-61703,61706,61710,61713,61717,61723,61726-61730,61736,61738,61740,61742,61745-61752,61754-61760,61762-61764,61768,61770-61772,61774-61775,61784-61787,61789-61792,61794-61795,61797-61806,61808-61809,61811-61812,61814-61819,61824,61826-61833,61835-61840,61843-61845,61848,61850,61854-61862,61865-61866,61868,61872-61873,61876-61877,61883-61888,61890-61891,61893-61899,61901-61903,61905-61912,61914,61917,61920-61921,61927,61930,61932-61934,61939,61941-61942,61944-61951,61955,61960-61963,61980,61982-61983,61991,61994-61996,62001-62003,62008-62010,62016-62017,62022,62024,62027,62031-62034,62041,62045-62046,62048,62050-62051,62055-62066,62068-62074,62076-62078 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62048 | georg.brandl | 2008-03-29 23:53:55 -0700 (Sat, 29 Mar 2008) | 2 lines Adapt test_ast to the new ExceptHandler type. ........ r62050 | georg.brandl | 2008-03-30 00:09:22 -0700 (Sun, 30 Mar 2008) | 2 lines Convert test_ast to unittest and add a test for r62049. ........ r62051 | georg.brandl | 2008-03-30 12:00:49 -0700 (Sun, 30 Mar 2008) | 2 lines Make _fields attr for no fields consistent with _attributes attr. ........ r62059 | georg.brandl | 2008-03-30 13:20:39 -0700 (Sun, 30 Mar 2008) | 2 lines Make AST nodes pickleable. ........
2008-03-31 02:29:39 -03:00
fnames = PyTuple_New(num_fields);
if (!fnames) return NULL;
for (i = 0; i < num_fields; i++) {
PyObject *field = PyUnicode_InternFromString(fields[i]);
if (!field) {
Py_DECREF(fnames);
return NULL;
}
PyTuple_SET_ITEM(fnames, i, field);
}
result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){OOOOOOOs}",
type, base,
state->_fields, fnames,
state->__match_args__, fnames,
state->__module__,
state->ast,
state->__doc__, doc);
Py_DECREF(fnames);
return result;
}
static int
add_attributes(struct ast_state *state, PyObject *type, const char * const *attrs, int num_fields)
{
int i, result;
PyObject *s, *l = PyTuple_New(num_fields);
if (!l)
return 0;
for (i = 0; i < num_fields; i++) {
s = PyUnicode_InternFromString(attrs[i]);
if (!s) {
Py_DECREF(l);
return 0;
}
PyTuple_SET_ITEM(l, i, s);
}
result = PyObject_SetAttr(type, state->_attributes, l) >= 0;
Py_DECREF(l);
return result;
}
/* Conversion AST -> Python */
static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject* (*func)(struct ast_state *state, void*))
{
Py_ssize_t i, n = asdl_seq_LEN(seq);
PyObject *result = PyList_New(n);
PyObject *value;
if (!result)
return NULL;
for (i = 0; i < n; i++) {
value = func(state, asdl_seq_GET_UNTYPED(seq, i));
if (!value) {
Py_DECREF(result);
return NULL;
}
PyList_SET_ITEM(result, i, value);
}
return result;
}
static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o)
{
if (!o)
o = Py_None;
Py_INCREF((PyObject*)o);
return (PyObject*)o;
}
#define ast2obj_constant ast2obj_object
#define ast2obj_identifier ast2obj_object
#define ast2obj_string ast2obj_object
static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), long b)
{
return PyLong_FromLong(b);
}
/* Conversion Python -> AST */
static int obj2ast_object(struct ast_state *Py_UNUSED(state), PyObject* obj, PyObject** out, PyArena* arena)
{
if (obj == Py_None)
obj = NULL;
if (obj) {
if (_PyArena_AddPyObject(arena, obj) < 0) {
*out = NULL;
return -1;
}
Py_INCREF(obj);
}
*out = obj;
return 0;
}
static int obj2ast_constant(struct ast_state *Py_UNUSED(state), PyObject* obj, PyObject** out, PyArena* arena)
{
if (_PyArena_AddPyObject(arena, obj) < 0) {
*out = NULL;
return -1;
}
Py_INCREF(obj);
*out = obj;
return 0;
}
static int obj2ast_identifier(struct ast_state *state, PyObject* obj, PyObject** out, PyArena* arena)
{
if (!PyUnicode_CheckExact(obj) && obj != Py_None) {
PyErr_SetString(PyExc_TypeError, "AST identifier must be of type str");
return 1;
}
return obj2ast_object(state, obj, out, arena);
}
static int obj2ast_string(struct ast_state *state, PyObject* obj, PyObject** out, PyArena* arena)
{
if (!PyUnicode_CheckExact(obj) && !PyBytes_CheckExact(obj)) {
PyErr_SetString(PyExc_TypeError, "AST string must be of type str");
return 1;
}
return obj2ast_object(state, obj, out, arena);
}
static int obj2ast_int(struct ast_state* Py_UNUSED(state), PyObject* obj, int* out, PyArena* arena)
{
int i;
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_ValueError, "invalid integer value: %R", obj);
return 1;
}
i = _PyLong_AsInt(obj);
if (i == -1 && PyErr_Occurred())
return 1;
*out = i;
return 0;
}
static int add_ast_fields(struct ast_state *state)
2008-10-24 20:11:02 -03:00
{
PyObject *empty_tuple;
2008-10-24 20:11:02 -03:00
empty_tuple = PyTuple_New(0);
if (!empty_tuple ||
PyObject_SetAttrString(state->AST_type, "_fields", empty_tuple) < 0 ||
PyObject_SetAttrString(state->AST_type, "__match_args__", empty_tuple) < 0 ||
PyObject_SetAttrString(state->AST_type, "_attributes", empty_tuple) < 0) {
2008-10-24 20:11:02 -03:00
Py_XDECREF(empty_tuple);
return -1;
}
Py_DECREF(empty_tuple);
return 0;
}
static int
init_types(struct ast_state *state)
{
// init_types() must not be called after _PyAST_Fini()
// has been called
assert(state->initialized >= 0);
if (state->initialized) {
return 1;
}
if (init_identifiers(state) < 0) {
return 0;
}
state->AST_type = PyType_FromSpec(&AST_type_spec);
if (!state->AST_type) {
return 0;
}
if (add_ast_fields(state) < 0) {
return 0;
}
state->mod_type = make_type(state, "mod", state->AST_type, NULL, 0,
"mod = Module(stmt* body, type_ignore* type_ignores)\n"
" | Interactive(stmt* body)\n"
" | Expression(expr body)\n"
" | FunctionType(expr* argtypes, expr returns)");
if (!state->mod_type) return 0;
if (!add_attributes(state, state->mod_type, NULL, 0)) return 0;
state->Module_type = make_type(state, "Module", state->mod_type,
Module_fields, 2,
"Module(stmt* body, type_ignore* type_ignores)");
if (!state->Module_type) return 0;
state->Interactive_type = make_type(state, "Interactive", state->mod_type,
Interactive_fields, 1,
"Interactive(stmt* body)");
if (!state->Interactive_type) return 0;
state->Expression_type = make_type(state, "Expression", state->mod_type,
Expression_fields, 1,
"Expression(expr body)");
if (!state->Expression_type) return 0;
state->FunctionType_type = make_type(state, "FunctionType",
state->mod_type, FunctionType_fields,
2,
"FunctionType(expr* argtypes, expr returns)");
if (!state->FunctionType_type) return 0;
state->stmt_type = make_type(state, "stmt", state->AST_type, NULL, 0,
"stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n"
" | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n"
" | ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n"
" | Return(expr? value)\n"
" | Delete(expr* targets)\n"
" | Assign(expr* targets, expr value, string? type_comment)\n"
" | AugAssign(expr target, operator op, expr value)\n"
" | AnnAssign(expr target, expr annotation, expr? value, int simple)\n"
" | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n"
" | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n"
" | While(expr test, stmt* body, stmt* orelse)\n"
" | If(expr test, stmt* body, stmt* orelse)\n"
" | With(withitem* items, stmt* body, string? type_comment)\n"
" | AsyncWith(withitem* items, stmt* body, string? type_comment)\n"
" | Match(expr subject, match_case* cases)\n"
" | Raise(expr? exc, expr? cause)\n"
" | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)\n"
" | Assert(expr test, expr? msg)\n"
" | Import(alias* names)\n"
" | ImportFrom(identifier? module, alias* names, int? level)\n"
" | Global(identifier* names)\n"
" | Nonlocal(identifier* names)\n"
" | Expr(expr value)\n"
" | Pass\n"
" | Break\n"
" | Continue");
if (!state->stmt_type) return 0;
if (!add_attributes(state, state->stmt_type, stmt_attributes, 4)) return 0;
if (PyObject_SetAttr(state->stmt_type, state->end_lineno, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->stmt_type, state->end_col_offset, Py_None) ==
-1)
return 0;
state->FunctionDef_type = make_type(state, "FunctionDef", state->stmt_type,
FunctionDef_fields, 6,
"FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)");
if (!state->FunctionDef_type) return 0;
if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) ==
-1)
return 0;
if (PyObject_SetAttr(state->FunctionDef_type, state->type_comment, Py_None)
== -1)
return 0;
state->AsyncFunctionDef_type = make_type(state, "AsyncFunctionDef",
state->stmt_type,
AsyncFunctionDef_fields, 6,
"AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)");
if (!state->AsyncFunctionDef_type) return 0;
if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None)
== -1)
return 0;
if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->type_comment,
Py_None) == -1)
return 0;
state->ClassDef_type = make_type(state, "ClassDef", state->stmt_type,
ClassDef_fields, 5,
"ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)");
if (!state->ClassDef_type) return 0;
state->Return_type = make_type(state, "Return", state->stmt_type,
Return_fields, 1,
"Return(expr? value)");
if (!state->Return_type) return 0;
if (PyObject_SetAttr(state->Return_type, state->value, Py_None) == -1)
return 0;
state->Delete_type = make_type(state, "Delete", state->stmt_type,
Delete_fields, 1,
"Delete(expr* targets)");
if (!state->Delete_type) return 0;
state->Assign_type = make_type(state, "Assign", state->stmt_type,
Assign_fields, 3,
"Assign(expr* targets, expr value, string? type_comment)");
if (!state->Assign_type) return 0;
if (PyObject_SetAttr(state->Assign_type, state->type_comment, Py_None) ==
-1)
return 0;
state->AugAssign_type = make_type(state, "AugAssign", state->stmt_type,
AugAssign_fields, 3,
"AugAssign(expr target, operator op, expr value)");
if (!state->AugAssign_type) return 0;
state->AnnAssign_type = make_type(state, "AnnAssign", state->stmt_type,
AnnAssign_fields, 4,
"AnnAssign(expr target, expr annotation, expr? value, int simple)");
if (!state->AnnAssign_type) return 0;
if (PyObject_SetAttr(state->AnnAssign_type, state->value, Py_None) == -1)
return 0;
state->For_type = make_type(state, "For", state->stmt_type, For_fields, 5,
"For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)");
if (!state->For_type) return 0;
if (PyObject_SetAttr(state->For_type, state->type_comment, Py_None) == -1)
return 0;
state->AsyncFor_type = make_type(state, "AsyncFor", state->stmt_type,
AsyncFor_fields, 5,
"AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)");
if (!state->AsyncFor_type) return 0;
if (PyObject_SetAttr(state->AsyncFor_type, state->type_comment, Py_None) ==
-1)
return 0;
state->While_type = make_type(state, "While", state->stmt_type,
While_fields, 3,
"While(expr test, stmt* body, stmt* orelse)");
if (!state->While_type) return 0;
state->If_type = make_type(state, "If", state->stmt_type, If_fields, 3,
"If(expr test, stmt* body, stmt* orelse)");
if (!state->If_type) return 0;
state->With_type = make_type(state, "With", state->stmt_type, With_fields,
3,
"With(withitem* items, stmt* body, string? type_comment)");
if (!state->With_type) return 0;
if (PyObject_SetAttr(state->With_type, state->type_comment, Py_None) == -1)
return 0;
state->AsyncWith_type = make_type(state, "AsyncWith", state->stmt_type,
AsyncWith_fields, 3,
"AsyncWith(withitem* items, stmt* body, string? type_comment)");
if (!state->AsyncWith_type) return 0;
if (PyObject_SetAttr(state->AsyncWith_type, state->type_comment, Py_None)
== -1)
return 0;
state->Match_type = make_type(state, "Match", state->stmt_type,
Match_fields, 2,
"Match(expr subject, match_case* cases)");
if (!state->Match_type) return 0;
state->Raise_type = make_type(state, "Raise", state->stmt_type,
Raise_fields, 2,
"Raise(expr? exc, expr? cause)");
if (!state->Raise_type) return 0;
if (PyObject_SetAttr(state->Raise_type, state->exc, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->Raise_type, state->cause, Py_None) == -1)
return 0;
state->Try_type = make_type(state, "Try", state->stmt_type, Try_fields, 4,
"Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)");
if (!state->Try_type) return 0;
state->Assert_type = make_type(state, "Assert", state->stmt_type,
Assert_fields, 2,
"Assert(expr test, expr? msg)");
if (!state->Assert_type) return 0;
if (PyObject_SetAttr(state->Assert_type, state->msg, Py_None) == -1)
return 0;
state->Import_type = make_type(state, "Import", state->stmt_type,
Import_fields, 1,
"Import(alias* names)");
if (!state->Import_type) return 0;
state->ImportFrom_type = make_type(state, "ImportFrom", state->stmt_type,
ImportFrom_fields, 3,
"ImportFrom(identifier? module, alias* names, int? level)");
if (!state->ImportFrom_type) return 0;
if (PyObject_SetAttr(state->ImportFrom_type, state->module, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->ImportFrom_type, state->level, Py_None) == -1)
return 0;
state->Global_type = make_type(state, "Global", state->stmt_type,
Global_fields, 1,
"Global(identifier* names)");
if (!state->Global_type) return 0;
state->Nonlocal_type = make_type(state, "Nonlocal", state->stmt_type,
Nonlocal_fields, 1,
"Nonlocal(identifier* names)");
if (!state->Nonlocal_type) return 0;
state->Expr_type = make_type(state, "Expr", state->stmt_type, Expr_fields,
1,
"Expr(expr value)");
if (!state->Expr_type) return 0;
state->Pass_type = make_type(state, "Pass", state->stmt_type, NULL, 0,
"Pass");
if (!state->Pass_type) return 0;
state->Break_type = make_type(state, "Break", state->stmt_type, NULL, 0,
"Break");
if (!state->Break_type) return 0;
state->Continue_type = make_type(state, "Continue", state->stmt_type, NULL,
0,
"Continue");
if (!state->Continue_type) return 0;
state->expr_type = make_type(state, "expr", state->AST_type, NULL, 0,
"expr = BoolOp(boolop op, expr* values)\n"
" | NamedExpr(expr target, expr value)\n"
" | BinOp(expr left, operator op, expr right)\n"
" | UnaryOp(unaryop op, expr operand)\n"
" | Lambda(arguments args, expr body)\n"
" | IfExp(expr test, expr body, expr orelse)\n"
" | Dict(expr* keys, expr* values)\n"
" | Set(expr* elts)\n"
" | ListComp(expr elt, comprehension* generators)\n"
" | SetComp(expr elt, comprehension* generators)\n"
" | DictComp(expr key, expr value, comprehension* generators)\n"
" | GeneratorExp(expr elt, comprehension* generators)\n"
" | Await(expr value)\n"
" | Yield(expr? value)\n"
" | YieldFrom(expr value)\n"
" | Compare(expr left, cmpop* ops, expr* comparators)\n"
" | Call(expr func, expr* args, keyword* keywords)\n"
" | FormattedValue(expr value, int? conversion, expr? format_spec)\n"
" | JoinedStr(expr* values)\n"
" | Constant(constant value, string? kind)\n"
" | Attribute(expr value, identifier attr, expr_context ctx)\n"
" | Subscript(expr value, expr slice, expr_context ctx)\n"
" | Starred(expr value, expr_context ctx)\n"
" | Name(identifier id, expr_context ctx)\n"
" | List(expr* elts, expr_context ctx)\n"
" | Tuple(expr* elts, expr_context ctx)\n"
" | Slice(expr? lower, expr? upper, expr? step)\n"
" | MatchAs(expr pattern, identifier name)\n"
" | MatchOr(expr* patterns)");
if (!state->expr_type) return 0;
if (!add_attributes(state, state->expr_type, expr_attributes, 4)) return 0;
if (PyObject_SetAttr(state->expr_type, state->end_lineno, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->expr_type, state->end_col_offset, Py_None) ==
-1)
return 0;
state->BoolOp_type = make_type(state, "BoolOp", state->expr_type,
BoolOp_fields, 2,
"BoolOp(boolop op, expr* values)");
if (!state->BoolOp_type) return 0;
state->NamedExpr_type = make_type(state, "NamedExpr", state->expr_type,
NamedExpr_fields, 2,
"NamedExpr(expr target, expr value)");
if (!state->NamedExpr_type) return 0;
state->BinOp_type = make_type(state, "BinOp", state->expr_type,
BinOp_fields, 3,
"BinOp(expr left, operator op, expr right)");
if (!state->BinOp_type) return 0;
state->UnaryOp_type = make_type(state, "UnaryOp", state->expr_type,
UnaryOp_fields, 2,
"UnaryOp(unaryop op, expr operand)");
if (!state->UnaryOp_type) return 0;
state->Lambda_type = make_type(state, "Lambda", state->expr_type,
Lambda_fields, 2,
"Lambda(arguments args, expr body)");
if (!state->Lambda_type) return 0;
state->IfExp_type = make_type(state, "IfExp", state->expr_type,
IfExp_fields, 3,
"IfExp(expr test, expr body, expr orelse)");
if (!state->IfExp_type) return 0;
state->Dict_type = make_type(state, "Dict", state->expr_type, Dict_fields,
2,
"Dict(expr* keys, expr* values)");
if (!state->Dict_type) return 0;
state->Set_type = make_type(state, "Set", state->expr_type, Set_fields, 1,
"Set(expr* elts)");
if (!state->Set_type) return 0;
state->ListComp_type = make_type(state, "ListComp", state->expr_type,
ListComp_fields, 2,
"ListComp(expr elt, comprehension* generators)");
if (!state->ListComp_type) return 0;
state->SetComp_type = make_type(state, "SetComp", state->expr_type,
SetComp_fields, 2,
"SetComp(expr elt, comprehension* generators)");
if (!state->SetComp_type) return 0;
state->DictComp_type = make_type(state, "DictComp", state->expr_type,
DictComp_fields, 3,
"DictComp(expr key, expr value, comprehension* generators)");
if (!state->DictComp_type) return 0;
state->GeneratorExp_type = make_type(state, "GeneratorExp",
state->expr_type, GeneratorExp_fields,
2,
"GeneratorExp(expr elt, comprehension* generators)");
if (!state->GeneratorExp_type) return 0;
state->Await_type = make_type(state, "Await", state->expr_type,
Await_fields, 1,
"Await(expr value)");
if (!state->Await_type) return 0;
state->Yield_type = make_type(state, "Yield", state->expr_type,
Yield_fields, 1,
"Yield(expr? value)");
if (!state->Yield_type) return 0;
if (PyObject_SetAttr(state->Yield_type, state->value, Py_None) == -1)
return 0;
state->YieldFrom_type = make_type(state, "YieldFrom", state->expr_type,
YieldFrom_fields, 1,
"YieldFrom(expr value)");
if (!state->YieldFrom_type) return 0;
state->Compare_type = make_type(state, "Compare", state->expr_type,
Compare_fields, 3,
"Compare(expr left, cmpop* ops, expr* comparators)");
if (!state->Compare_type) return 0;
state->Call_type = make_type(state, "Call", state->expr_type, Call_fields,
3,
"Call(expr func, expr* args, keyword* keywords)");
if (!state->Call_type) return 0;
state->FormattedValue_type = make_type(state, "FormattedValue",
state->expr_type,
FormattedValue_fields, 3,
"FormattedValue(expr value, int? conversion, expr? format_spec)");
if (!state->FormattedValue_type) return 0;
if (PyObject_SetAttr(state->FormattedValue_type, state->conversion,
Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->FormattedValue_type, state->format_spec,
Py_None) == -1)
return 0;
state->JoinedStr_type = make_type(state, "JoinedStr", state->expr_type,
JoinedStr_fields, 1,
"JoinedStr(expr* values)");
if (!state->JoinedStr_type) return 0;
state->Constant_type = make_type(state, "Constant", state->expr_type,
Constant_fields, 2,
"Constant(constant value, string? kind)");
if (!state->Constant_type) return 0;
if (PyObject_SetAttr(state->Constant_type, state->kind, Py_None) == -1)
return 0;
state->Attribute_type = make_type(state, "Attribute", state->expr_type,
Attribute_fields, 3,
"Attribute(expr value, identifier attr, expr_context ctx)");
if (!state->Attribute_type) return 0;
state->Subscript_type = make_type(state, "Subscript", state->expr_type,
Subscript_fields, 3,
"Subscript(expr value, expr slice, expr_context ctx)");
if (!state->Subscript_type) return 0;
state->Starred_type = make_type(state, "Starred", state->expr_type,
Starred_fields, 2,
"Starred(expr value, expr_context ctx)");
if (!state->Starred_type) return 0;
state->Name_type = make_type(state, "Name", state->expr_type, Name_fields,
2,
"Name(identifier id, expr_context ctx)");
if (!state->Name_type) return 0;
state->List_type = make_type(state, "List", state->expr_type, List_fields,
2,
"List(expr* elts, expr_context ctx)");
if (!state->List_type) return 0;
state->Tuple_type = make_type(state, "Tuple", state->expr_type,
Tuple_fields, 2,
"Tuple(expr* elts, expr_context ctx)");
if (!state->Tuple_type) return 0;
state->Slice_type = make_type(state, "Slice", state->expr_type,
Slice_fields, 3,
"Slice(expr? lower, expr? upper, expr? step)");
if (!state->Slice_type) return 0;
if (PyObject_SetAttr(state->Slice_type, state->lower, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->Slice_type, state->upper, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->Slice_type, state->step, Py_None) == -1)
return 0;
state->MatchAs_type = make_type(state, "MatchAs", state->expr_type,
MatchAs_fields, 2,
"MatchAs(expr pattern, identifier name)");
if (!state->MatchAs_type) return 0;
state->MatchOr_type = make_type(state, "MatchOr", state->expr_type,
MatchOr_fields, 1,
"MatchOr(expr* patterns)");
if (!state->MatchOr_type) return 0;
state->expr_context_type = make_type(state, "expr_context",
state->AST_type, NULL, 0,
"expr_context = Load | Store | Del");
if (!state->expr_context_type) return 0;
if (!add_attributes(state, state->expr_context_type, NULL, 0)) return 0;
state->Load_type = make_type(state, "Load", state->expr_context_type, NULL,
0,
"Load");
if (!state->Load_type) return 0;
state->Load_singleton = PyType_GenericNew((PyTypeObject *)state->Load_type,
NULL, NULL);
if (!state->Load_singleton) return 0;
state->Store_type = make_type(state, "Store", state->expr_context_type,
NULL, 0,
"Store");
if (!state->Store_type) return 0;
state->Store_singleton = PyType_GenericNew((PyTypeObject
*)state->Store_type, NULL, NULL);
if (!state->Store_singleton) return 0;
state->Del_type = make_type(state, "Del", state->expr_context_type, NULL, 0,
"Del");
if (!state->Del_type) return 0;
state->Del_singleton = PyType_GenericNew((PyTypeObject *)state->Del_type,
NULL, NULL);
if (!state->Del_singleton) return 0;
state->boolop_type = make_type(state, "boolop", state->AST_type, NULL, 0,
"boolop = And | Or");
if (!state->boolop_type) return 0;
if (!add_attributes(state, state->boolop_type, NULL, 0)) return 0;
state->And_type = make_type(state, "And", state->boolop_type, NULL, 0,
"And");
if (!state->And_type) return 0;
state->And_singleton = PyType_GenericNew((PyTypeObject *)state->And_type,
NULL, NULL);
if (!state->And_singleton) return 0;
state->Or_type = make_type(state, "Or", state->boolop_type, NULL, 0,
"Or");
if (!state->Or_type) return 0;
state->Or_singleton = PyType_GenericNew((PyTypeObject *)state->Or_type,
NULL, NULL);
if (!state->Or_singleton) return 0;
state->operator_type = make_type(state, "operator", state->AST_type, NULL,
0,
"operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv");
if (!state->operator_type) return 0;
if (!add_attributes(state, state->operator_type, NULL, 0)) return 0;
state->Add_type = make_type(state, "Add", state->operator_type, NULL, 0,
"Add");
if (!state->Add_type) return 0;
state->Add_singleton = PyType_GenericNew((PyTypeObject *)state->Add_type,
NULL, NULL);
if (!state->Add_singleton) return 0;
state->Sub_type = make_type(state, "Sub", state->operator_type, NULL, 0,
"Sub");
if (!state->Sub_type) return 0;
state->Sub_singleton = PyType_GenericNew((PyTypeObject *)state->Sub_type,
NULL, NULL);
if (!state->Sub_singleton) return 0;
state->Mult_type = make_type(state, "Mult", state->operator_type, NULL, 0,
"Mult");
if (!state->Mult_type) return 0;
state->Mult_singleton = PyType_GenericNew((PyTypeObject *)state->Mult_type,
NULL, NULL);
if (!state->Mult_singleton) return 0;
state->MatMult_type = make_type(state, "MatMult", state->operator_type,
NULL, 0,
"MatMult");
if (!state->MatMult_type) return 0;
state->MatMult_singleton = PyType_GenericNew((PyTypeObject
*)state->MatMult_type, NULL,
NULL);
if (!state->MatMult_singleton) return 0;
state->Div_type = make_type(state, "Div", state->operator_type, NULL, 0,
"Div");
if (!state->Div_type) return 0;
state->Div_singleton = PyType_GenericNew((PyTypeObject *)state->Div_type,
NULL, NULL);
if (!state->Div_singleton) return 0;
state->Mod_type = make_type(state, "Mod", state->operator_type, NULL, 0,
"Mod");
if (!state->Mod_type) return 0;
state->Mod_singleton = PyType_GenericNew((PyTypeObject *)state->Mod_type,
NULL, NULL);
if (!state->Mod_singleton) return 0;
state->Pow_type = make_type(state, "Pow", state->operator_type, NULL, 0,
"Pow");
if (!state->Pow_type) return 0;
state->Pow_singleton = PyType_GenericNew((PyTypeObject *)state->Pow_type,
NULL, NULL);
if (!state->Pow_singleton) return 0;
state->LShift_type = make_type(state, "LShift", state->operator_type, NULL,
0,
"LShift");
if (!state->LShift_type) return 0;
state->LShift_singleton = PyType_GenericNew((PyTypeObject
*)state->LShift_type, NULL,
NULL);
if (!state->LShift_singleton) return 0;
state->RShift_type = make_type(state, "RShift", state->operator_type, NULL,
0,
"RShift");
if (!state->RShift_type) return 0;
state->RShift_singleton = PyType_GenericNew((PyTypeObject
*)state->RShift_type, NULL,
NULL);
if (!state->RShift_singleton) return 0;
state->BitOr_type = make_type(state, "BitOr", state->operator_type, NULL, 0,
"BitOr");
if (!state->BitOr_type) return 0;
state->BitOr_singleton = PyType_GenericNew((PyTypeObject
*)state->BitOr_type, NULL, NULL);
if (!state->BitOr_singleton) return 0;
state->BitXor_type = make_type(state, "BitXor", state->operator_type, NULL,
0,
"BitXor");
if (!state->BitXor_type) return 0;
state->BitXor_singleton = PyType_GenericNew((PyTypeObject
*)state->BitXor_type, NULL,
NULL);
if (!state->BitXor_singleton) return 0;
state->BitAnd_type = make_type(state, "BitAnd", state->operator_type, NULL,
0,
"BitAnd");
if (!state->BitAnd_type) return 0;
state->BitAnd_singleton = PyType_GenericNew((PyTypeObject
*)state->BitAnd_type, NULL,
NULL);
if (!state->BitAnd_singleton) return 0;
state->FloorDiv_type = make_type(state, "FloorDiv", state->operator_type,
NULL, 0,
"FloorDiv");
if (!state->FloorDiv_type) return 0;
state->FloorDiv_singleton = PyType_GenericNew((PyTypeObject
*)state->FloorDiv_type, NULL,
NULL);
if (!state->FloorDiv_singleton) return 0;
state->unaryop_type = make_type(state, "unaryop", state->AST_type, NULL, 0,
"unaryop = Invert | Not | UAdd | USub");
if (!state->unaryop_type) return 0;
if (!add_attributes(state, state->unaryop_type, NULL, 0)) return 0;
state->Invert_type = make_type(state, "Invert", state->unaryop_type, NULL,
0,
"Invert");
if (!state->Invert_type) return 0;
state->Invert_singleton = PyType_GenericNew((PyTypeObject
*)state->Invert_type, NULL,
NULL);
if (!state->Invert_singleton) return 0;
state->Not_type = make_type(state, "Not", state->unaryop_type, NULL, 0,
"Not");
if (!state->Not_type) return 0;
state->Not_singleton = PyType_GenericNew((PyTypeObject *)state->Not_type,
NULL, NULL);
if (!state->Not_singleton) return 0;
state->UAdd_type = make_type(state, "UAdd", state->unaryop_type, NULL, 0,
"UAdd");
if (!state->UAdd_type) return 0;
state->UAdd_singleton = PyType_GenericNew((PyTypeObject *)state->UAdd_type,
NULL, NULL);
if (!state->UAdd_singleton) return 0;
state->USub_type = make_type(state, "USub", state->unaryop_type, NULL, 0,
"USub");
if (!state->USub_type) return 0;
state->USub_singleton = PyType_GenericNew((PyTypeObject *)state->USub_type,
NULL, NULL);
if (!state->USub_singleton) return 0;
state->cmpop_type = make_type(state, "cmpop", state->AST_type, NULL, 0,
"cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn");
if (!state->cmpop_type) return 0;
if (!add_attributes(state, state->cmpop_type, NULL, 0)) return 0;
state->Eq_type = make_type(state, "Eq", state->cmpop_type, NULL, 0,
"Eq");
if (!state->Eq_type) return 0;
state->Eq_singleton = PyType_GenericNew((PyTypeObject *)state->Eq_type,
NULL, NULL);
if (!state->Eq_singleton) return 0;
state->NotEq_type = make_type(state, "NotEq", state->cmpop_type, NULL, 0,
"NotEq");
if (!state->NotEq_type) return 0;
state->NotEq_singleton = PyType_GenericNew((PyTypeObject
*)state->NotEq_type, NULL, NULL);
if (!state->NotEq_singleton) return 0;
state->Lt_type = make_type(state, "Lt", state->cmpop_type, NULL, 0,
"Lt");
if (!state->Lt_type) return 0;
state->Lt_singleton = PyType_GenericNew((PyTypeObject *)state->Lt_type,
NULL, NULL);
if (!state->Lt_singleton) return 0;
state->LtE_type = make_type(state, "LtE", state->cmpop_type, NULL, 0,
"LtE");
if (!state->LtE_type) return 0;
state->LtE_singleton = PyType_GenericNew((PyTypeObject *)state->LtE_type,
NULL, NULL);
if (!state->LtE_singleton) return 0;
state->Gt_type = make_type(state, "Gt", state->cmpop_type, NULL, 0,
"Gt");
if (!state->Gt_type) return 0;
state->Gt_singleton = PyType_GenericNew((PyTypeObject *)state->Gt_type,
NULL, NULL);
if (!state->Gt_singleton) return 0;
state->GtE_type = make_type(state, "GtE", state->cmpop_type, NULL, 0,
"GtE");
if (!state->GtE_type) return 0;
state->GtE_singleton = PyType_GenericNew((PyTypeObject *)state->GtE_type,
NULL, NULL);
if (!state->GtE_singleton) return 0;
state->Is_type = make_type(state, "Is", state->cmpop_type, NULL, 0,
"Is");
if (!state->Is_type) return 0;
state->Is_singleton = PyType_GenericNew((PyTypeObject *)state->Is_type,
NULL, NULL);
if (!state->Is_singleton) return 0;
state->IsNot_type = make_type(state, "IsNot", state->cmpop_type, NULL, 0,
"IsNot");
if (!state->IsNot_type) return 0;
state->IsNot_singleton = PyType_GenericNew((PyTypeObject
*)state->IsNot_type, NULL, NULL);
if (!state->IsNot_singleton) return 0;
state->In_type = make_type(state, "In", state->cmpop_type, NULL, 0,
"In");
if (!state->In_type) return 0;
state->In_singleton = PyType_GenericNew((PyTypeObject *)state->In_type,
NULL, NULL);
if (!state->In_singleton) return 0;
state->NotIn_type = make_type(state, "NotIn", state->cmpop_type, NULL, 0,
"NotIn");
if (!state->NotIn_type) return 0;
state->NotIn_singleton = PyType_GenericNew((PyTypeObject
*)state->NotIn_type, NULL, NULL);
if (!state->NotIn_singleton) return 0;
state->comprehension_type = make_type(state, "comprehension",
state->AST_type,
comprehension_fields, 4,
"comprehension(expr target, expr iter, expr* ifs, int is_async)");
if (!state->comprehension_type) return 0;
if (!add_attributes(state, state->comprehension_type, NULL, 0)) return 0;
state->excepthandler_type = make_type(state, "excepthandler",
state->AST_type, NULL, 0,
"excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)");
if (!state->excepthandler_type) return 0;
if (!add_attributes(state, state->excepthandler_type,
excepthandler_attributes, 4)) return 0;
if (PyObject_SetAttr(state->excepthandler_type, state->end_lineno, Py_None)
== -1)
return 0;
if (PyObject_SetAttr(state->excepthandler_type, state->end_col_offset,
Py_None) == -1)
return 0;
state->ExceptHandler_type = make_type(state, "ExceptHandler",
state->excepthandler_type,
ExceptHandler_fields, 3,
"ExceptHandler(expr? type, identifier? name, stmt* body)");
if (!state->ExceptHandler_type) return 0;
if (PyObject_SetAttr(state->ExceptHandler_type, state->type, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->ExceptHandler_type, state->name, Py_None) == -1)
return 0;
state->arguments_type = make_type(state, "arguments", state->AST_type,
arguments_fields, 7,
"arguments(arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, arg? kwarg, expr* defaults)");
if (!state->arguments_type) return 0;
if (!add_attributes(state, state->arguments_type, NULL, 0)) return 0;
if (PyObject_SetAttr(state->arguments_type, state->vararg, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->arguments_type, state->kwarg, Py_None) == -1)
return 0;
state->arg_type = make_type(state, "arg", state->AST_type, arg_fields, 3,
"arg(identifier arg, expr? annotation, string? type_comment)");
if (!state->arg_type) return 0;
if (!add_attributes(state, state->arg_type, arg_attributes, 4)) return 0;
if (PyObject_SetAttr(state->arg_type, state->annotation, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->arg_type, state->type_comment, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->arg_type, state->end_lineno, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->arg_type, state->end_col_offset, Py_None) == -1)
return 0;
state->keyword_type = make_type(state, "keyword", state->AST_type,
keyword_fields, 2,
"keyword(identifier? arg, expr value)");
if (!state->keyword_type) return 0;
if (!add_attributes(state, state->keyword_type, keyword_attributes, 4))
return 0;
if (PyObject_SetAttr(state->keyword_type, state->arg, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->keyword_type, state->end_lineno, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->keyword_type, state->end_col_offset, Py_None)
== -1)
return 0;
state->alias_type = make_type(state, "alias", state->AST_type,
alias_fields, 2,
"alias(identifier name, identifier? asname)");
if (!state->alias_type) return 0;
if (!add_attributes(state, state->alias_type, alias_attributes, 4)) return
0;
if (PyObject_SetAttr(state->alias_type, state->asname, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->alias_type, state->end_lineno, Py_None) == -1)
return 0;
if (PyObject_SetAttr(state->alias_type, state->end_col_offset, Py_None) ==
-1)
return 0;
state->withitem_type = make_type(state, "withitem", state->AST_type,
withitem_fields, 2,
"withitem(expr context_expr, expr? optional_vars)");
if (!state->withitem_type) return 0;
if (!add_attributes(state, state->withitem_type, NULL, 0)) return 0;
if (PyObject_SetAttr(state->withitem_type, state->optional_vars, Py_None)
== -1)
return 0;
state->match_case_type = make_type(state, "match_case", state->AST_type,
match_case_fields, 3,
"match_case(expr pattern, expr? guard, stmt* body)");
if (!state->match_case_type) return 0;
if (!add_attributes(state, state->match_case_type, NULL, 0)) return 0;
if (PyObject_SetAttr(state->match_case_type, state->guard, Py_None) == -1)
return 0;
state->type_ignore_type = make_type(state, "type_ignore", state->AST_type,
NULL, 0,
"type_ignore = TypeIgnore(int lineno, string tag)");
if (!state->type_ignore_type) return 0;
if (!add_attributes(state, state->type_ignore_type, NULL, 0)) return 0;
state->TypeIgnore_type = make_type(state, "TypeIgnore",
state->type_ignore_type,
TypeIgnore_fields, 2,
"TypeIgnore(int lineno, string tag)");
if (!state->TypeIgnore_type) return 0;
state->initialized = 1;
return 1;
}
static int obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out,
PyArena* arena);
static int obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out,
PyArena* arena);
static int obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out,
PyArena* arena);
static int obj2ast_expr_context(struct ast_state *state, PyObject* obj,
expr_context_ty* out, PyArena* arena);
static int obj2ast_boolop(struct ast_state *state, PyObject* obj, boolop_ty*
out, PyArena* arena);
static int obj2ast_operator(struct ast_state *state, PyObject* obj,
operator_ty* out, PyArena* arena);
static int obj2ast_unaryop(struct ast_state *state, PyObject* obj, unaryop_ty*
out, PyArena* arena);
static int obj2ast_cmpop(struct ast_state *state, PyObject* obj, cmpop_ty* out,
PyArena* arena);
static int obj2ast_comprehension(struct ast_state *state, PyObject* obj,
comprehension_ty* out, PyArena* arena);
static int obj2ast_excepthandler(struct ast_state *state, PyObject* obj,
excepthandler_ty* out, PyArena* arena);
static int obj2ast_arguments(struct ast_state *state, PyObject* obj,
arguments_ty* out, PyArena* arena);
static int obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out,
PyArena* arena);
static int obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty*
out, PyArena* arena);
static int obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out,
PyArena* arena);
static int obj2ast_withitem(struct ast_state *state, PyObject* obj,
withitem_ty* out, PyArena* arena);
static int obj2ast_match_case(struct ast_state *state, PyObject* obj,
match_case_ty* out, PyArena* arena);
static int obj2ast_type_ignore(struct ast_state *state, PyObject* obj,
type_ignore_ty* out, PyArena* arena);
mod_ty
_PyAST_Module(asdl_stmt_seq * body, asdl_type_ignore_seq * type_ignores,
PyArena *arena)
{
mod_ty p;
p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Module_kind;
p->v.Module.body = body;
p->v.Module.type_ignores = type_ignores;
return p;
}
mod_ty
_PyAST_Interactive(asdl_stmt_seq * body, PyArena *arena)
{
mod_ty p;
p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Interactive_kind;
p->v.Interactive.body = body;
return p;
}
mod_ty
_PyAST_Expression(expr_ty body, PyArena *arena)
{
mod_ty p;
if (!body) {
PyErr_SetString(PyExc_ValueError,
"field 'body' is required for Expression");
return NULL;
}
p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Expression_kind;
p->v.Expression.body = body;
return p;
}
mod_ty
_PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena)
{
mod_ty p;
if (!returns) {
PyErr_SetString(PyExc_ValueError,
"field 'returns' is required for FunctionType");
return NULL;
}
p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = FunctionType_kind;
p->v.FunctionType.argtypes = argtypes;
p->v.FunctionType.returns = returns;
return p;
}
stmt_ty
_PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body,
asdl_expr_seq * decorator_list, expr_ty returns, string
type_comment, int lineno, int col_offset, int end_lineno,
int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field 'name' is required for FunctionDef");
return NULL;
}
if (!args) {
PyErr_SetString(PyExc_ValueError,
"field 'args' is required for FunctionDef");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = FunctionDef_kind;
p->v.FunctionDef.name = name;
p->v.FunctionDef.args = args;
p->v.FunctionDef.body = body;
p->v.FunctionDef.decorator_list = decorator_list;
p->v.FunctionDef.returns = returns;
p->v.FunctionDef.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq *
body, asdl_expr_seq * decorator_list, expr_ty returns,
string type_comment, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field 'name' is required for AsyncFunctionDef");
return NULL;
}
if (!args) {
PyErr_SetString(PyExc_ValueError,
"field 'args' is required for AsyncFunctionDef");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncFunctionDef_kind;
p->v.AsyncFunctionDef.name = name;
p->v.AsyncFunctionDef.args = args;
p->v.AsyncFunctionDef.body = body;
p->v.AsyncFunctionDef.decorator_list = decorator_list;
p->v.AsyncFunctionDef.returns = returns;
p->v.AsyncFunctionDef.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_ClassDef(identifier name, asdl_expr_seq * bases, asdl_keyword_seq *
keywords, asdl_stmt_seq * body, asdl_expr_seq * decorator_list,
int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field 'name' is required for ClassDef");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = ClassDef_kind;
p->v.ClassDef.name = name;
p->v.ClassDef.bases = bases;
p->v.ClassDef.keywords = keywords;
p->v.ClassDef.body = body;
p->v.ClassDef.decorator_list = decorator_list;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Return(expr_ty value, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Return_kind;
p->v.Return.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Delete_kind;
p->v.Delete.targets = targets;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Assign");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Assign_kind;
p->v.Assign.targets = targets;
p->v.Assign.value = value;
p->v.Assign.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for AugAssign");
return NULL;
}
if (!op) {
PyErr_SetString(PyExc_ValueError,
"field 'op' is required for AugAssign");
return NULL;
}
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for AugAssign");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AugAssign_kind;
p->v.AugAssign.target = target;
p->v.AugAssign.op = op;
p->v.AugAssign.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_AnnAssign(expr_ty target, expr_ty annotation, expr_ty value, int simple,
int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for AnnAssign");
return NULL;
}
if (!annotation) {
PyErr_SetString(PyExc_ValueError,
"field 'annotation' is required for AnnAssign");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AnnAssign_kind;
p->v.AnnAssign.target = target;
p->v.AnnAssign.annotation = annotation;
p->v.AnnAssign.value = value;
p->v.AnnAssign.simple = simple;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_For(expr_ty target, expr_ty iter, asdl_stmt_seq * body, asdl_stmt_seq *
orelse, string type_comment, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for For");
return NULL;
}
if (!iter) {
PyErr_SetString(PyExc_ValueError,
"field 'iter' is required for For");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = For_kind;
p->v.For.target = target;
p->v.For.iter = iter;
p->v.For.body = body;
p->v.For.orelse = orelse;
p->v.For.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_AsyncFor(expr_ty target, expr_ty iter, asdl_stmt_seq * body,
asdl_stmt_seq * orelse, string type_comment, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for AsyncFor");
return NULL;
}
if (!iter) {
PyErr_SetString(PyExc_ValueError,
"field 'iter' is required for AsyncFor");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncFor_kind;
p->v.AsyncFor.target = target;
p->v.AsyncFor.iter = iter;
p->v.AsyncFor.body = body;
p->v.AsyncFor.orelse = orelse;
p->v.AsyncFor.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_While(expr_ty test, asdl_stmt_seq * body, asdl_stmt_seq * orelse, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
if (!test) {
PyErr_SetString(PyExc_ValueError,
"field 'test' is required for While");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = While_kind;
p->v.While.test = test;
p->v.While.body = body;
p->v.While.orelse = orelse;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_If(expr_ty test, asdl_stmt_seq * body, asdl_stmt_seq * orelse, int
lineno, int col_offset, int end_lineno, int end_col_offset, PyArena
*arena)
{
stmt_ty p;
if (!test) {
PyErr_SetString(PyExc_ValueError,
"field 'test' is required for If");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = If_kind;
p->v.If.test = test;
p->v.If.body = body;
p->v.If.orelse = orelse;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_With(asdl_withitem_seq * items, asdl_stmt_seq * body, string
type_comment, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = With_kind;
p->v.With.items = items;
p->v.With.body = body;
p->v.With.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_AsyncWith(asdl_withitem_seq * items, asdl_stmt_seq * body, string
type_comment, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = AsyncWith_kind;
p->v.AsyncWith.items = items;
p->v.AsyncWith.body = body;
p->v.AsyncWith.type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Match(expr_ty subject, asdl_match_case_seq * cases, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!subject) {
PyErr_SetString(PyExc_ValueError,
"field 'subject' is required for Match");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Match_kind;
p->v.Match.subject = subject;
p->v.Match.cases = cases;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Raise_kind;
p->v.Raise.exc = exc;
p->v.Raise.cause = cause;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Try(asdl_stmt_seq * body, asdl_excepthandler_seq * handlers,
asdl_stmt_seq * orelse, asdl_stmt_seq * finalbody, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Try_kind;
p->v.Try.body = body;
p->v.Try.handlers = handlers;
p->v.Try.orelse = orelse;
p->v.Try.finalbody = finalbody;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!test) {
PyErr_SetString(PyExc_ValueError,
"field 'test' is required for Assert");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Assert_kind;
p->v.Assert.test = test;
p->v.Assert.msg = msg;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Import(asdl_alias_seq * names, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Import_kind;
p->v.Import.names = names;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_ImportFrom(identifier module, asdl_alias_seq * names, int level, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = ImportFrom_kind;
p->v.ImportFrom.module = module;
p->v.ImportFrom.names = names;
p->v.ImportFrom.level = level;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Global(asdl_identifier_seq * names, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Global_kind;
p->v.Global.names = names;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Nonlocal(asdl_identifier_seq * names, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Nonlocal_kind;
p->v.Nonlocal.names = names;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Expr(expr_ty value, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
stmt_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Expr");
return NULL;
}
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Expr_kind;
p->v.Expr.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Pass(int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Pass_kind;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Break(int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Break_kind;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
stmt_ty
_PyAST_Continue(int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Continue_kind;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_BoolOp(boolop_ty op, asdl_expr_seq * values, int lineno, int col_offset,
int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!op) {
PyErr_SetString(PyExc_ValueError,
"field 'op' is required for BoolOp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = BoolOp_kind;
p->v.BoolOp.op = op;
p->v.BoolOp.values = values;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
expr_ty
_PyAST_NamedExpr(expr_ty target, expr_ty value, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
{
expr_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for NamedExpr");
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
return NULL;
}
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for NamedExpr");
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (!p)
return NULL;
p->kind = NamedExpr_kind;
p->v.NamedExpr.target = target;
p->v.NamedExpr.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!left) {
PyErr_SetString(PyExc_ValueError,
"field 'left' is required for BinOp");
return NULL;
}
if (!op) {
PyErr_SetString(PyExc_ValueError,
"field 'op' is required for BinOp");
return NULL;
}
if (!right) {
PyErr_SetString(PyExc_ValueError,
"field 'right' is required for BinOp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = BinOp_kind;
p->v.BinOp.left = left;
p->v.BinOp.op = op;
p->v.BinOp.right = right;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!op) {
PyErr_SetString(PyExc_ValueError,
"field 'op' is required for UnaryOp");
return NULL;
}
if (!operand) {
PyErr_SetString(PyExc_ValueError,
"field 'operand' is required for UnaryOp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = UnaryOp_kind;
p->v.UnaryOp.op = op;
p->v.UnaryOp.operand = operand;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!args) {
PyErr_SetString(PyExc_ValueError,
"field 'args' is required for Lambda");
return NULL;
}
if (!body) {
PyErr_SetString(PyExc_ValueError,
"field 'body' is required for Lambda");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Lambda_kind;
p->v.Lambda.args = args;
p->v.Lambda.body = body;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!test) {
PyErr_SetString(PyExc_ValueError,
"field 'test' is required for IfExp");
return NULL;
}
if (!body) {
PyErr_SetString(PyExc_ValueError,
"field 'body' is required for IfExp");
return NULL;
}
if (!orelse) {
PyErr_SetString(PyExc_ValueError,
"field 'orelse' is required for IfExp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = IfExp_kind;
p->v.IfExp.test = test;
p->v.IfExp.body = body;
p->v.IfExp.orelse = orelse;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Dict(asdl_expr_seq * keys, asdl_expr_seq * values, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Dict_kind;
p->v.Dict.keys = keys;
p->v.Dict.values = values;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Set(asdl_expr_seq * elts, int lineno, int col_offset, int end_lineno,
int end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Set_kind;
p->v.Set.elts = elts;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_ListComp(expr_ty elt, asdl_comprehension_seq * generators, int lineno,
int col_offset, int end_lineno, int end_col_offset, PyArena
*arena)
{
expr_ty p;
if (!elt) {
PyErr_SetString(PyExc_ValueError,
"field 'elt' is required for ListComp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = ListComp_kind;
p->v.ListComp.elt = elt;
p->v.ListComp.generators = generators;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_SetComp(expr_ty elt, asdl_comprehension_seq * generators, int lineno,
int col_offset, int end_lineno, int end_col_offset, PyArena
*arena)
{
expr_ty p;
if (!elt) {
PyErr_SetString(PyExc_ValueError,
"field 'elt' is required for SetComp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = SetComp_kind;
p->v.SetComp.elt = elt;
p->v.SetComp.generators = generators;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
Merged revisions 56154-56264 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r56155 | neal.norwitz | 2007-07-03 08:59:08 +0300 (Tue, 03 Jul 2007) | 1 line Get this test working after converting map to return an iterator ................ r56202 | neal.norwitz | 2007-07-09 04:30:09 +0300 (Mon, 09 Jul 2007) | 37 lines Merged revisions 56124-56201 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r56129 | georg.brandl | 2007-06-30 04:01:01 -0700 (Sat, 30 Jun 2007) | 2 lines Document smtp.SMTPAuthenticationError. ........ r56137 | georg.brandl | 2007-07-01 01:11:35 -0700 (Sun, 01 Jul 2007) | 2 lines Fix a few webbrowser.py problems. ........ r56143 | georg.brandl | 2007-07-02 04:54:28 -0700 (Mon, 02 Jul 2007) | 2 lines Remove duplicate sentence from alarm() doc. ........ r56170 | mark.hammond | 2007-07-03 19:03:10 -0700 (Tue, 03 Jul 2007) | 3 lines copy built files to the PCBuild directory, where tools like distutils or external build processes can find them. ........ r56176 | kurt.kaiser | 2007-07-05 15:03:39 -0700 (Thu, 05 Jul 2007) | 10 lines Many calls to tk.call involve an arglist containing a single tuple. Calls using METH_OLDARGS unpack this tuple; calls using METH_VARARG don't. Tcl's concatenation of args was affected; IDLE doesn't start. Modify Tkapp_Call() to unpack single tuple arglists. Bug 1733943 Ref http://mail.python.org/pipermail/python-checkins/2007-May/060454.html ........ r56177 | neal.norwitz | 2007-07-05 21:13:39 -0700 (Thu, 05 Jul 2007) | 1 line Fix typo in comment ........ ................ r56251 | neal.norwitz | 2007-07-11 10:01:01 +0300 (Wed, 11 Jul 2007) | 1 line Get working with map returning an iterator (had to fix whitespace too) ................ r56255 | thomas.wouters | 2007-07-11 13:41:37 +0300 (Wed, 11 Jul 2007) | 6 lines Clean up merge glitch or copy-paste error (the entire module was duplicated, except the first half even had some more copy-paste errors, referring to listcomps and genexps instead of setcomps) ................ r56256 | thomas.wouters | 2007-07-11 15:16:01 +0300 (Wed, 11 Jul 2007) | 14 lines Dict comprehensions. Still needs doc changes (like many python-3000 features ;-). It generates bytecode similar to: x = {} for k, v in (generator here): x[k] = v except there is no tuple-packing and -unpacking involved. Trivial measurement suggests it's significantly faster than dict(generator here) (in the order of 2 to 3 times as fast) but I have not done extensive measurements. ................ r56263 | guido.van.rossum | 2007-07-11 15:36:26 +0300 (Wed, 11 Jul 2007) | 3 lines Patch 1724999 by Ali Gholami Rudi -- avoid complaints about dict size change during iter in destroy call. ................
2007-07-11 10:09:30 -03:00
expr_ty
_PyAST_DictComp(expr_ty key, expr_ty value, asdl_comprehension_seq *
generators, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
Merged revisions 56154-56264 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r56155 | neal.norwitz | 2007-07-03 08:59:08 +0300 (Tue, 03 Jul 2007) | 1 line Get this test working after converting map to return an iterator ................ r56202 | neal.norwitz | 2007-07-09 04:30:09 +0300 (Mon, 09 Jul 2007) | 37 lines Merged revisions 56124-56201 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r56129 | georg.brandl | 2007-06-30 04:01:01 -0700 (Sat, 30 Jun 2007) | 2 lines Document smtp.SMTPAuthenticationError. ........ r56137 | georg.brandl | 2007-07-01 01:11:35 -0700 (Sun, 01 Jul 2007) | 2 lines Fix a few webbrowser.py problems. ........ r56143 | georg.brandl | 2007-07-02 04:54:28 -0700 (Mon, 02 Jul 2007) | 2 lines Remove duplicate sentence from alarm() doc. ........ r56170 | mark.hammond | 2007-07-03 19:03:10 -0700 (Tue, 03 Jul 2007) | 3 lines copy built files to the PCBuild directory, where tools like distutils or external build processes can find them. ........ r56176 | kurt.kaiser | 2007-07-05 15:03:39 -0700 (Thu, 05 Jul 2007) | 10 lines Many calls to tk.call involve an arglist containing a single tuple. Calls using METH_OLDARGS unpack this tuple; calls using METH_VARARG don't. Tcl's concatenation of args was affected; IDLE doesn't start. Modify Tkapp_Call() to unpack single tuple arglists. Bug 1733943 Ref http://mail.python.org/pipermail/python-checkins/2007-May/060454.html ........ r56177 | neal.norwitz | 2007-07-05 21:13:39 -0700 (Thu, 05 Jul 2007) | 1 line Fix typo in comment ........ ................ r56251 | neal.norwitz | 2007-07-11 10:01:01 +0300 (Wed, 11 Jul 2007) | 1 line Get working with map returning an iterator (had to fix whitespace too) ................ r56255 | thomas.wouters | 2007-07-11 13:41:37 +0300 (Wed, 11 Jul 2007) | 6 lines Clean up merge glitch or copy-paste error (the entire module was duplicated, except the first half even had some more copy-paste errors, referring to listcomps and genexps instead of setcomps) ................ r56256 | thomas.wouters | 2007-07-11 15:16:01 +0300 (Wed, 11 Jul 2007) | 14 lines Dict comprehensions. Still needs doc changes (like many python-3000 features ;-). It generates bytecode similar to: x = {} for k, v in (generator here): x[k] = v except there is no tuple-packing and -unpacking involved. Trivial measurement suggests it's significantly faster than dict(generator here) (in the order of 2 to 3 times as fast) but I have not done extensive measurements. ................ r56263 | guido.van.rossum | 2007-07-11 15:36:26 +0300 (Wed, 11 Jul 2007) | 3 lines Patch 1724999 by Ali Gholami Rudi -- avoid complaints about dict size change during iter in destroy call. ................
2007-07-11 10:09:30 -03:00
{
expr_ty p;
if (!key) {
PyErr_SetString(PyExc_ValueError,
"field 'key' is required for DictComp");
return NULL;
}
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for DictComp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = DictComp_kind;
p->v.DictComp.key = key;
p->v.DictComp.value = value;
p->v.DictComp.generators = generators;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
Merged revisions 56154-56264 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r56155 | neal.norwitz | 2007-07-03 08:59:08 +0300 (Tue, 03 Jul 2007) | 1 line Get this test working after converting map to return an iterator ................ r56202 | neal.norwitz | 2007-07-09 04:30:09 +0300 (Mon, 09 Jul 2007) | 37 lines Merged revisions 56124-56201 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r56129 | georg.brandl | 2007-06-30 04:01:01 -0700 (Sat, 30 Jun 2007) | 2 lines Document smtp.SMTPAuthenticationError. ........ r56137 | georg.brandl | 2007-07-01 01:11:35 -0700 (Sun, 01 Jul 2007) | 2 lines Fix a few webbrowser.py problems. ........ r56143 | georg.brandl | 2007-07-02 04:54:28 -0700 (Mon, 02 Jul 2007) | 2 lines Remove duplicate sentence from alarm() doc. ........ r56170 | mark.hammond | 2007-07-03 19:03:10 -0700 (Tue, 03 Jul 2007) | 3 lines copy built files to the PCBuild directory, where tools like distutils or external build processes can find them. ........ r56176 | kurt.kaiser | 2007-07-05 15:03:39 -0700 (Thu, 05 Jul 2007) | 10 lines Many calls to tk.call involve an arglist containing a single tuple. Calls using METH_OLDARGS unpack this tuple; calls using METH_VARARG don't. Tcl's concatenation of args was affected; IDLE doesn't start. Modify Tkapp_Call() to unpack single tuple arglists. Bug 1733943 Ref http://mail.python.org/pipermail/python-checkins/2007-May/060454.html ........ r56177 | neal.norwitz | 2007-07-05 21:13:39 -0700 (Thu, 05 Jul 2007) | 1 line Fix typo in comment ........ ................ r56251 | neal.norwitz | 2007-07-11 10:01:01 +0300 (Wed, 11 Jul 2007) | 1 line Get working with map returning an iterator (had to fix whitespace too) ................ r56255 | thomas.wouters | 2007-07-11 13:41:37 +0300 (Wed, 11 Jul 2007) | 6 lines Clean up merge glitch or copy-paste error (the entire module was duplicated, except the first half even had some more copy-paste errors, referring to listcomps and genexps instead of setcomps) ................ r56256 | thomas.wouters | 2007-07-11 15:16:01 +0300 (Wed, 11 Jul 2007) | 14 lines Dict comprehensions. Still needs doc changes (like many python-3000 features ;-). It generates bytecode similar to: x = {} for k, v in (generator here): x[k] = v except there is no tuple-packing and -unpacking involved. Trivial measurement suggests it's significantly faster than dict(generator here) (in the order of 2 to 3 times as fast) but I have not done extensive measurements. ................ r56263 | guido.van.rossum | 2007-07-11 15:36:26 +0300 (Wed, 11 Jul 2007) | 3 lines Patch 1724999 by Ali Gholami Rudi -- avoid complaints about dict size change during iter in destroy call. ................
2007-07-11 10:09:30 -03:00
}
expr_ty
_PyAST_GeneratorExp(expr_ty elt, asdl_comprehension_seq * generators, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
expr_ty p;
if (!elt) {
PyErr_SetString(PyExc_ValueError,
"field 'elt' is required for GeneratorExp");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = GeneratorExp_kind;
p->v.GeneratorExp.elt = elt;
p->v.GeneratorExp.generators = generators;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Await(expr_ty value, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Await");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Await_kind;
p->v.Await.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Yield(expr_ty value, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Yield_kind;
p->v.Yield.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_YieldFrom(expr_ty value, int lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for YieldFrom");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = YieldFrom_kind;
p->v.YieldFrom.value = value;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Compare(expr_ty left, asdl_int_seq * ops, asdl_expr_seq * comparators,
int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
expr_ty p;
if (!left) {
PyErr_SetString(PyExc_ValueError,
"field 'left' is required for Compare");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Compare_kind;
p->v.Compare.left = left;
p->v.Compare.ops = ops;
p->v.Compare.comparators = comparators;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Call(expr_ty func, asdl_expr_seq * args, asdl_keyword_seq * keywords,
int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
expr_ty p;
if (!func) {
PyErr_SetString(PyExc_ValueError,
"field 'func' is required for Call");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Call_kind;
p->v.Call.func = func;
p->v.Call.args = args;
p->v.Call.keywords = keywords;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_FormattedValue(expr_ty value, int conversion, expr_ty format_spec, int
lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for FormattedValue");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = FormattedValue_kind;
p->v.FormattedValue.value = value;
p->v.FormattedValue.conversion = conversion;
p->v.FormattedValue.format_spec = format_spec;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_JoinedStr(asdl_expr_seq * values, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = JoinedStr_kind;
p->v.JoinedStr.values = values;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Constant(constant value, string kind, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Constant");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Constant_kind;
p->v.Constant.value = value;
p->v.Constant.kind = kind;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Attribute");
return NULL;
}
if (!attr) {
PyErr_SetString(PyExc_ValueError,
"field 'attr' is required for Attribute");
return NULL;
}
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for Attribute");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Attribute_kind;
p->v.Attribute.value = value;
p->v.Attribute.attr = attr;
p->v.Attribute.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Subscript(expr_ty value, expr_ty slice, expr_context_ty ctx, int lineno,
int col_offset, int end_lineno, int end_col_offset, PyArena
*arena)
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Subscript");
return NULL;
}
if (!slice) {
PyErr_SetString(PyExc_ValueError,
"field 'slice' is required for Subscript");
return NULL;
}
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for Subscript");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Subscript_kind;
p->v.Subscript.value = value;
p->v.Subscript.slice = slice;
p->v.Subscript.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
Merged revisions 55225-55227,55229-55269 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r55238 | guido.van.rossum | 2007-05-10 16:46:05 -0700 (Thu, 10 May 2007) | 9 lines Merged revisions 55227 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55227 | guido.van.rossum | 2007-05-10 10:20:15 -0700 (Thu, 10 May 2007) | 2 lines Fix a bug in test_c_api() that caused a negative refcount. ........ ................ r55246 | neal.norwitz | 2007-05-11 00:01:52 -0700 (Fri, 11 May 2007) | 1 line Remove commands.getstatus() it is obsolete. ................ r55248 | neal.norwitz | 2007-05-11 00:29:05 -0700 (Fri, 11 May 2007) | 2 lines Remove bsddb185 support. ................ r55249 | neal.norwitz | 2007-05-11 00:29:50 -0700 (Fri, 11 May 2007) | 1 line Remove bsddb185 module too ................ r55250 | neal.norwitz | 2007-05-11 00:32:13 -0700 (Fri, 11 May 2007) | 1 line bsddb185: Gotta remove from the file checked in, not Setup ................ r55251 | neal.norwitz | 2007-05-11 00:53:26 -0700 (Fri, 11 May 2007) | 1 line Remove obsolete IRIX modules (as much as I could find, there is probably more) ................ r55252 | neal.norwitz | 2007-05-11 00:55:35 -0700 (Fri, 11 May 2007) | 1 line Remove SGI turd. ................ r55254 | georg.brandl | 2007-05-11 03:11:01 -0700 (Fri, 11 May 2007) | 2 lines Add a case for set comprehensions to the "cannot assign to" switch. ................ r55255 | georg.brandl | 2007-05-11 03:11:25 -0700 (Fri, 11 May 2007) | 2 lines Fix wrong imports. ................ r55261 | georg.brandl | 2007-05-11 07:37:48 -0700 (Fri, 11 May 2007) | 2 lines Remove removed tex files. ................ r55262 | georg.brandl | 2007-05-11 08:28:41 -0700 (Fri, 11 May 2007) | 2 lines Commit PEP 3132 implementation. ................ r55264 | georg.brandl | 2007-05-11 08:50:19 -0700 (Fri, 11 May 2007) | 2 lines Check in the inevitable AST version number and format Py_ssize_t with %zd. ................ r55265 | neal.norwitz | 2007-05-11 09:12:22 -0700 (Fri, 11 May 2007) | 1 line Remove mention of os.popen* and popen2.* since these will be removed. ................ r55266 | neal.norwitz | 2007-05-11 09:19:57 -0700 (Fri, 11 May 2007) | 1 line Get doc to build again (almost, the doc is fine) ................ r55267 | neal.norwitz | 2007-05-11 09:21:02 -0700 (Fri, 11 May 2007) | 1 line Really get doc to build (remove use of string module) ................ r55269 | neal.norwitz | 2007-05-11 09:29:43 -0700 (Fri, 11 May 2007) | 1 line Add some notes to cleanup later ................
2007-05-11 13:50:42 -03:00
expr_ty
_PyAST_Starred(expr_ty value, expr_context_ty ctx, int lineno, int col_offset,
int end_lineno, int end_col_offset, PyArena *arena)
Merged revisions 55225-55227,55229-55269 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r55238 | guido.van.rossum | 2007-05-10 16:46:05 -0700 (Thu, 10 May 2007) | 9 lines Merged revisions 55227 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55227 | guido.van.rossum | 2007-05-10 10:20:15 -0700 (Thu, 10 May 2007) | 2 lines Fix a bug in test_c_api() that caused a negative refcount. ........ ................ r55246 | neal.norwitz | 2007-05-11 00:01:52 -0700 (Fri, 11 May 2007) | 1 line Remove commands.getstatus() it is obsolete. ................ r55248 | neal.norwitz | 2007-05-11 00:29:05 -0700 (Fri, 11 May 2007) | 2 lines Remove bsddb185 support. ................ r55249 | neal.norwitz | 2007-05-11 00:29:50 -0700 (Fri, 11 May 2007) | 1 line Remove bsddb185 module too ................ r55250 | neal.norwitz | 2007-05-11 00:32:13 -0700 (Fri, 11 May 2007) | 1 line bsddb185: Gotta remove from the file checked in, not Setup ................ r55251 | neal.norwitz | 2007-05-11 00:53:26 -0700 (Fri, 11 May 2007) | 1 line Remove obsolete IRIX modules (as much as I could find, there is probably more) ................ r55252 | neal.norwitz | 2007-05-11 00:55:35 -0700 (Fri, 11 May 2007) | 1 line Remove SGI turd. ................ r55254 | georg.brandl | 2007-05-11 03:11:01 -0700 (Fri, 11 May 2007) | 2 lines Add a case for set comprehensions to the "cannot assign to" switch. ................ r55255 | georg.brandl | 2007-05-11 03:11:25 -0700 (Fri, 11 May 2007) | 2 lines Fix wrong imports. ................ r55261 | georg.brandl | 2007-05-11 07:37:48 -0700 (Fri, 11 May 2007) | 2 lines Remove removed tex files. ................ r55262 | georg.brandl | 2007-05-11 08:28:41 -0700 (Fri, 11 May 2007) | 2 lines Commit PEP 3132 implementation. ................ r55264 | georg.brandl | 2007-05-11 08:50:19 -0700 (Fri, 11 May 2007) | 2 lines Check in the inevitable AST version number and format Py_ssize_t with %zd. ................ r55265 | neal.norwitz | 2007-05-11 09:12:22 -0700 (Fri, 11 May 2007) | 1 line Remove mention of os.popen* and popen2.* since these will be removed. ................ r55266 | neal.norwitz | 2007-05-11 09:19:57 -0700 (Fri, 11 May 2007) | 1 line Get doc to build again (almost, the doc is fine) ................ r55267 | neal.norwitz | 2007-05-11 09:21:02 -0700 (Fri, 11 May 2007) | 1 line Really get doc to build (remove use of string module) ................ r55269 | neal.norwitz | 2007-05-11 09:29:43 -0700 (Fri, 11 May 2007) | 1 line Add some notes to cleanup later ................
2007-05-11 13:50:42 -03:00
{
expr_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for Starred");
return NULL;
}
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for Starred");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Starred_kind;
p->v.Starred.value = value;
p->v.Starred.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
Merged revisions 55225-55227,55229-55269 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r55238 | guido.van.rossum | 2007-05-10 16:46:05 -0700 (Thu, 10 May 2007) | 9 lines Merged revisions 55227 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55227 | guido.van.rossum | 2007-05-10 10:20:15 -0700 (Thu, 10 May 2007) | 2 lines Fix a bug in test_c_api() that caused a negative refcount. ........ ................ r55246 | neal.norwitz | 2007-05-11 00:01:52 -0700 (Fri, 11 May 2007) | 1 line Remove commands.getstatus() it is obsolete. ................ r55248 | neal.norwitz | 2007-05-11 00:29:05 -0700 (Fri, 11 May 2007) | 2 lines Remove bsddb185 support. ................ r55249 | neal.norwitz | 2007-05-11 00:29:50 -0700 (Fri, 11 May 2007) | 1 line Remove bsddb185 module too ................ r55250 | neal.norwitz | 2007-05-11 00:32:13 -0700 (Fri, 11 May 2007) | 1 line bsddb185: Gotta remove from the file checked in, not Setup ................ r55251 | neal.norwitz | 2007-05-11 00:53:26 -0700 (Fri, 11 May 2007) | 1 line Remove obsolete IRIX modules (as much as I could find, there is probably more) ................ r55252 | neal.norwitz | 2007-05-11 00:55:35 -0700 (Fri, 11 May 2007) | 1 line Remove SGI turd. ................ r55254 | georg.brandl | 2007-05-11 03:11:01 -0700 (Fri, 11 May 2007) | 2 lines Add a case for set comprehensions to the "cannot assign to" switch. ................ r55255 | georg.brandl | 2007-05-11 03:11:25 -0700 (Fri, 11 May 2007) | 2 lines Fix wrong imports. ................ r55261 | georg.brandl | 2007-05-11 07:37:48 -0700 (Fri, 11 May 2007) | 2 lines Remove removed tex files. ................ r55262 | georg.brandl | 2007-05-11 08:28:41 -0700 (Fri, 11 May 2007) | 2 lines Commit PEP 3132 implementation. ................ r55264 | georg.brandl | 2007-05-11 08:50:19 -0700 (Fri, 11 May 2007) | 2 lines Check in the inevitable AST version number and format Py_ssize_t with %zd. ................ r55265 | neal.norwitz | 2007-05-11 09:12:22 -0700 (Fri, 11 May 2007) | 1 line Remove mention of os.popen* and popen2.* since these will be removed. ................ r55266 | neal.norwitz | 2007-05-11 09:19:57 -0700 (Fri, 11 May 2007) | 1 line Get doc to build again (almost, the doc is fine) ................ r55267 | neal.norwitz | 2007-05-11 09:21:02 -0700 (Fri, 11 May 2007) | 1 line Really get doc to build (remove use of string module) ................ r55269 | neal.norwitz | 2007-05-11 09:29:43 -0700 (Fri, 11 May 2007) | 1 line Add some notes to cleanup later ................
2007-05-11 13:50:42 -03:00
}
expr_ty
_PyAST_Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!id) {
PyErr_SetString(PyExc_ValueError,
"field 'id' is required for Name");
return NULL;
}
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for Name");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Name_kind;
p->v.Name.id = id;
p->v.Name.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_List(asdl_expr_seq * elts, expr_context_ty ctx, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for List");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = List_kind;
p->v.List.elts = elts;
p->v.List.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Tuple(asdl_expr_seq * elts, expr_context_ty ctx, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!ctx) {
PyErr_SetString(PyExc_ValueError,
"field 'ctx' is required for Tuple");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Tuple_kind;
p->v.Tuple.elts = elts;
p->v.Tuple.ctx = ctx;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_Slice(expr_ty lower, expr_ty upper, expr_ty step, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Slice_kind;
p->v.Slice.lower = lower;
p->v.Slice.upper = upper;
p->v.Slice.step = step;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_MatchAs(expr_ty pattern, identifier name, int lineno, int col_offset,
int end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
if (!pattern) {
PyErr_SetString(PyExc_ValueError,
"field 'pattern' is required for MatchAs");
return NULL;
}
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field 'name' is required for MatchAs");
return NULL;
}
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = MatchAs_kind;
p->v.MatchAs.pattern = pattern;
p->v.MatchAs.name = name;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
expr_ty
_PyAST_MatchOr(asdl_expr_seq * patterns, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
expr_ty p;
p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = MatchOr_kind;
p->v.MatchOr.patterns = patterns;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
comprehension_ty
_PyAST_comprehension(expr_ty target, expr_ty iter, asdl_expr_seq * ifs, int
is_async, PyArena *arena)
{
comprehension_ty p;
if (!target) {
PyErr_SetString(PyExc_ValueError,
"field 'target' is required for comprehension");
return NULL;
}
if (!iter) {
PyErr_SetString(PyExc_ValueError,
"field 'iter' is required for comprehension");
return NULL;
}
p = (comprehension_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->target = target;
p->iter = iter;
p->ifs = ifs;
p->is_async = is_async;
return p;
}
excepthandler_ty
_PyAST_ExceptHandler(expr_ty type, identifier name, asdl_stmt_seq * body, int
lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena)
{
excepthandler_ty p;
p = (excepthandler_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = ExceptHandler_kind;
p->v.ExceptHandler.type = type;
p->v.ExceptHandler.name = name;
p->v.ExceptHandler.body = body;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
arguments_ty
_PyAST_arguments(asdl_arg_seq * posonlyargs, asdl_arg_seq * args, arg_ty
vararg, asdl_arg_seq * kwonlyargs, asdl_expr_seq *
kw_defaults, arg_ty kwarg, asdl_expr_seq * defaults, PyArena
*arena)
{
arguments_ty p;
p = (arguments_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->posonlyargs = posonlyargs;
p->args = args;
p->vararg = vararg;
p->kwonlyargs = kwonlyargs;
p->kw_defaults = kw_defaults;
p->kwarg = kwarg;
p->defaults = defaults;
return p;
}
arg_ty
_PyAST_arg(identifier arg, expr_ty annotation, string type_comment, int lineno,
int col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
arg_ty p;
if (!arg) {
PyErr_SetString(PyExc_ValueError,
"field 'arg' is required for arg");
return NULL;
}
p = (arg_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->arg = arg;
p->annotation = annotation;
p->type_comment = type_comment;
p->lineno = lineno;
p->col_offset = col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
keyword_ty
_PyAST_keyword(identifier arg, expr_ty value, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
{
keyword_ty p;
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field 'value' is required for keyword");
return NULL;
}
p = (keyword_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->arg = arg;
p->value = value;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
alias_ty
_PyAST_alias(identifier name, identifier asname, int lineno, int col_offset,
int end_lineno, int end_col_offset, PyArena *arena)
{
alias_ty p;
if (!name) {
PyErr_SetString(PyExc_ValueError,
"field 'name' is required for alias");
return NULL;
}
p = (alias_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->name = name;
p->asname = asname;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
p->end_col_offset = end_col_offset;
return p;
}
withitem_ty
_PyAST_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena)
{
withitem_ty p;
if (!context_expr) {
PyErr_SetString(PyExc_ValueError,
"field 'context_expr' is required for withitem");
return NULL;
}
p = (withitem_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->context_expr = context_expr;
p->optional_vars = optional_vars;
return p;
}
match_case_ty
_PyAST_match_case(expr_ty pattern, expr_ty guard, asdl_stmt_seq * body, PyArena
*arena)
{
match_case_ty p;
if (!pattern) {
PyErr_SetString(PyExc_ValueError,
"field 'pattern' is required for match_case");
return NULL;
}
p = (match_case_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->pattern = pattern;
p->guard = guard;
p->body = body;
return p;
}
type_ignore_ty
_PyAST_TypeIgnore(int lineno, string tag, PyArena *arena)
{
type_ignore_ty p;
if (!tag) {
PyErr_SetString(PyExc_ValueError,
"field 'tag' is required for TypeIgnore");
return NULL;
}
p = (type_ignore_ty)_PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = TypeIgnore_kind;
p->v.TypeIgnore.lineno = lineno;
p->v.TypeIgnore.tag = tag;
return p;
}
PyObject*
ast2obj_mod(struct ast_state *state, void* _o)
{
mod_ty o = (mod_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
switch (o->kind) {
case Module_kind:
tp = (PyTypeObject *)state->Module_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Module.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Module.type_ignores,
ast2obj_type_ignore);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_ignores, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Interactive_kind:
tp = (PyTypeObject *)state->Interactive_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Interactive.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
break;
case Expression_kind:
tp = (PyTypeObject *)state->Expression_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Expression.body);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
break;
case FunctionType_kind:
tp = (PyTypeObject *)state->FunctionType_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.FunctionType.argtypes,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->argtypes, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.FunctionType.returns);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->returns, value) == -1)
goto failed;
Py_DECREF(value);
break;
}
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_stmt(struct ast_state *state, void* _o)
{
stmt_ty o = (stmt_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
switch (o->kind) {
case FunctionDef_kind:
tp = (PyTypeObject *)state->FunctionDef_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(state, o->v.FunctionDef.name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
value = ast2obj_arguments(state, o->v.FunctionDef.args);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->args, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.decorator_list,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
goto failed;
2006-03-01 20:31:27 -04:00
Py_DECREF(value);
value = ast2obj_expr(state, o->v.FunctionDef.returns);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->returns, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.FunctionDef.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case AsyncFunctionDef_kind:
tp = (PyTypeObject *)state->AsyncFunctionDef_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(state, o->v.AsyncFunctionDef.name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->args, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFunctionDef.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state,
(asdl_seq*)o->v.AsyncFunctionDef.decorator_list,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.AsyncFunctionDef.returns);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->returns, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.AsyncFunctionDef.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case ClassDef_kind:
tp = (PyTypeObject *)state->ClassDef_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(state, o->v.ClassDef.name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->bases, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.keywords,
ast2obj_keyword);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->keywords, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.decorator_list,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Return_kind:
tp = (PyTypeObject *)state->Return_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Return.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Delete_kind:
tp = (PyTypeObject *)state->Delete_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Delete.targets,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->targets, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Assign_kind:
tp = (PyTypeObject *)state->Assign_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Assign.targets,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->targets, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Assign.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.Assign.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case AugAssign_kind:
tp = (PyTypeObject *)state->AugAssign_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.AugAssign.target);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_operator(state, o->v.AugAssign.op);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->op, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.AugAssign.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case AnnAssign_kind:
tp = (PyTypeObject *)state->AnnAssign_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.AnnAssign.target);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.AnnAssign.annotation);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->annotation, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.AnnAssign.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->v.AnnAssign.simple);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->simple, value) == -1)
goto failed;
Py_DECREF(value);
break;
case For_kind:
tp = (PyTypeObject *)state->For_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.For.target);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.For.iter);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->iter, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.For.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.For.orelse, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.For.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case AsyncFor_kind:
tp = (PyTypeObject *)state->AsyncFor_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.AsyncFor.target);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.AsyncFor.iter);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->iter, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.orelse,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.AsyncFor.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case While_kind:
tp = (PyTypeObject *)state->While_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.While.test);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->test, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.While.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.While.orelse, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
break;
case If_kind:
tp = (PyTypeObject *)state->If_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.If.test);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->test, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.If.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.If.orelse, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
break;
case With_kind:
tp = (PyTypeObject *)state->With_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.With.items,
ast2obj_withitem);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->items, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.With.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.With.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case AsyncWith_kind:
tp = (PyTypeObject *)state->AsyncWith_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.items,
ast2obj_withitem);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->items, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.AsyncWith.type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Match_kind:
tp = (PyTypeObject *)state->Match_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Match.subject);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->subject, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Match.cases,
ast2obj_match_case);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->cases, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Raise_kind:
tp = (PyTypeObject *)state->Raise_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Raise.exc);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->exc, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Raise.cause);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->cause, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Try_kind:
tp = (PyTypeObject *)state->Try_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Try.body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Try.handlers,
ast2obj_excepthandler);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->handlers, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Try.orelse, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Try.finalbody,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->finalbody, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Assert_kind:
tp = (PyTypeObject *)state->Assert_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Assert.test);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->test, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Assert.msg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->msg, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Import_kind:
tp = (PyTypeObject *)state->Import_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Import.names,
ast2obj_alias);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->names, value) == -1)
goto failed;
Py_DECREF(value);
break;
case ImportFrom_kind:
tp = (PyTypeObject *)state->ImportFrom_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(state, o->v.ImportFrom.module);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->module, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ImportFrom.names,
ast2obj_alias);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->names, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->v.ImportFrom.level);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->level, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Global_kind:
tp = (PyTypeObject *)state->Global_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Global.names,
ast2obj_identifier);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->names, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Nonlocal_kind:
tp = (PyTypeObject *)state->Nonlocal_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Nonlocal.names,
ast2obj_identifier);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->names, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Expr_kind:
tp = (PyTypeObject *)state->Expr_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Expr.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Pass_kind:
tp = (PyTypeObject *)state->Pass_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
break;
case Break_kind:
tp = (PyTypeObject *)state->Break_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
break;
case Continue_kind:
tp = (PyTypeObject *)state->Continue_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
break;
}
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_expr(struct ast_state *state, void* _o)
{
expr_ty o = (expr_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
switch (o->kind) {
case BoolOp_kind:
tp = (PyTypeObject *)state->BoolOp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_boolop(state, o->v.BoolOp.op);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->op, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.BoolOp.values,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->values, value) == -1)
goto failed;
Py_DECREF(value);
break;
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
case NamedExpr_kind:
tp = (PyTypeObject *)state->NamedExpr_type;
result = PyType_GenericNew(tp, NULL, NULL);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (!result) goto failed;
value = ast2obj_expr(state, o->v.NamedExpr.target);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.NamedExpr.value);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
goto failed;
Py_DECREF(value);
break;
case BinOp_kind:
tp = (PyTypeObject *)state->BinOp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.BinOp.left);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->left, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_operator(state, o->v.BinOp.op);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->op, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.BinOp.right);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->right, value) == -1)
goto failed;
Py_DECREF(value);
break;
case UnaryOp_kind:
tp = (PyTypeObject *)state->UnaryOp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_unaryop(state, o->v.UnaryOp.op);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->op, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.UnaryOp.operand);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->operand, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Lambda_kind:
tp = (PyTypeObject *)state->Lambda_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_arguments(state, o->v.Lambda.args);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->args, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Lambda.body);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
break;
case IfExp_kind:
tp = (PyTypeObject *)state->IfExp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.IfExp.test);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->test, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.IfExp.body);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.IfExp.orelse);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->orelse, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Dict_kind:
tp = (PyTypeObject *)state->Dict_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Dict.keys, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->keys, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Dict.values, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->values, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Set_kind:
tp = (PyTypeObject *)state->Set_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Set.elts, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elts, value) == -1)
goto failed;
Py_DECREF(value);
break;
case ListComp_kind:
tp = (PyTypeObject *)state->ListComp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.ListComp.elt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elt, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ListComp.generators,
ast2obj_comprehension);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->generators, value) == -1)
goto failed;
Py_DECREF(value);
break;
case SetComp_kind:
tp = (PyTypeObject *)state->SetComp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.SetComp.elt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elt, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.SetComp.generators,
ast2obj_comprehension);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->generators, value) == -1)
goto failed;
Py_DECREF(value);
break;
case DictComp_kind:
tp = (PyTypeObject *)state->DictComp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.DictComp.key);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->key, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.DictComp.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.DictComp.generators,
ast2obj_comprehension);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->generators, value) == -1)
goto failed;
Py_DECREF(value);
break;
case GeneratorExp_kind:
tp = (PyTypeObject *)state->GeneratorExp_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.GeneratorExp.elt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elt, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.GeneratorExp.generators,
ast2obj_comprehension);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->generators, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Await_kind:
tp = (PyTypeObject *)state->Await_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Await.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Yield_kind:
tp = (PyTypeObject *)state->Yield_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Yield.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case YieldFrom_kind:
tp = (PyTypeObject *)state->YieldFrom_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.YieldFrom.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Compare_kind:
tp = (PyTypeObject *)state->Compare_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Compare.left);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->left, value) == -1)
goto failed;
Py_DECREF(value);
{
Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops);
value = PyList_New(n);
if (!value) goto failed;
for(i = 0; i < n; i++)
PyList_SET_ITEM(value, i, ast2obj_cmpop(state, (cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i)));
}
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ops, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Compare.comparators,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->comparators, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Call_kind:
tp = (PyTypeObject *)state->Call_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Call.func);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->func, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Call.args, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->args, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.Call.keywords,
ast2obj_keyword);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->keywords, value) == -1)
goto failed;
Py_DECREF(value);
break;
case FormattedValue_kind:
tp = (PyTypeObject *)state->FormattedValue_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.FormattedValue.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->v.FormattedValue.conversion);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->conversion, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.FormattedValue.format_spec);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->format_spec, value) == -1)
goto failed;
Py_DECREF(value);
break;
case JoinedStr_kind:
tp = (PyTypeObject *)state->JoinedStr_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.JoinedStr.values,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->values, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Constant_kind:
tp = (PyTypeObject *)state->Constant_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_constant(state, o->v.Constant.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.Constant.kind);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->kind, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Attribute_kind:
tp = (PyTypeObject *)state->Attribute_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Attribute.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_identifier(state, o->v.Attribute.attr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->attr, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.Attribute.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Subscript_kind:
tp = (PyTypeObject *)state->Subscript_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Subscript.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Subscript.slice);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->slice, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.Subscript.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Starred_kind:
tp = (PyTypeObject *)state->Starred_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Starred.value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.Starred.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Name_kind:
tp = (PyTypeObject *)state->Name_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_identifier(state, o->v.Name.id);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->id, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.Name.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case List_kind:
tp = (PyTypeObject *)state->List_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.List.elts, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elts, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.List.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Tuple_kind:
tp = (PyTypeObject *)state->Tuple_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.Tuple.elts, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->elts, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr_context(state, o->v.Tuple.ctx);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ctx, value) == -1)
goto failed;
Py_DECREF(value);
break;
case Slice_kind:
tp = (PyTypeObject *)state->Slice_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.Slice.lower);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lower, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Slice.upper);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->upper, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->v.Slice.step);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->step, value) == -1)
goto failed;
Py_DECREF(value);
break;
case MatchAs_kind:
tp = (PyTypeObject *)state->MatchAs_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.MatchAs.pattern);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->pattern, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_identifier(state, o->v.MatchAs.name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
break;
case MatchOr_kind:
tp = (PyTypeObject *)state->MatchOr_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_list(state, (asdl_seq*)o->v.MatchOr.patterns,
ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->patterns, value) == -1)
goto failed;
Py_DECREF(value);
break;
}
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty o)
{
switch(o) {
case Load:
Py_INCREF(state->Load_singleton);
return state->Load_singleton;
case Store:
Py_INCREF(state->Store_singleton);
return state->Store_singleton;
case Del:
Py_INCREF(state->Del_singleton);
return state->Del_singleton;
}
Py_UNREACHABLE();
}
PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty o)
{
switch(o) {
case And:
Py_INCREF(state->And_singleton);
return state->And_singleton;
case Or:
Py_INCREF(state->Or_singleton);
return state->Or_singleton;
}
Py_UNREACHABLE();
}
PyObject* ast2obj_operator(struct ast_state *state, operator_ty o)
{
switch(o) {
case Add:
Py_INCREF(state->Add_singleton);
return state->Add_singleton;
case Sub:
Py_INCREF(state->Sub_singleton);
return state->Sub_singleton;
case Mult:
Py_INCREF(state->Mult_singleton);
return state->Mult_singleton;
case MatMult:
Py_INCREF(state->MatMult_singleton);
return state->MatMult_singleton;
case Div:
Py_INCREF(state->Div_singleton);
return state->Div_singleton;
case Mod:
Py_INCREF(state->Mod_singleton);
return state->Mod_singleton;
case Pow:
Py_INCREF(state->Pow_singleton);
return state->Pow_singleton;
case LShift:
Py_INCREF(state->LShift_singleton);
return state->LShift_singleton;
case RShift:
Py_INCREF(state->RShift_singleton);
return state->RShift_singleton;
case BitOr:
Py_INCREF(state->BitOr_singleton);
return state->BitOr_singleton;
case BitXor:
Py_INCREF(state->BitXor_singleton);
return state->BitXor_singleton;
case BitAnd:
Py_INCREF(state->BitAnd_singleton);
return state->BitAnd_singleton;
case FloorDiv:
Py_INCREF(state->FloorDiv_singleton);
return state->FloorDiv_singleton;
}
Py_UNREACHABLE();
}
PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty o)
{
switch(o) {
case Invert:
Py_INCREF(state->Invert_singleton);
return state->Invert_singleton;
case Not:
Py_INCREF(state->Not_singleton);
return state->Not_singleton;
case UAdd:
Py_INCREF(state->UAdd_singleton);
return state->UAdd_singleton;
case USub:
Py_INCREF(state->USub_singleton);
return state->USub_singleton;
}
Py_UNREACHABLE();
}
PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty o)
{
switch(o) {
case Eq:
Py_INCREF(state->Eq_singleton);
return state->Eq_singleton;
case NotEq:
Py_INCREF(state->NotEq_singleton);
return state->NotEq_singleton;
case Lt:
Py_INCREF(state->Lt_singleton);
return state->Lt_singleton;
case LtE:
Py_INCREF(state->LtE_singleton);
return state->LtE_singleton;
case Gt:
Py_INCREF(state->Gt_singleton);
return state->Gt_singleton;
case GtE:
Py_INCREF(state->GtE_singleton);
return state->GtE_singleton;
case Is:
Py_INCREF(state->Is_singleton);
return state->Is_singleton;
case IsNot:
Py_INCREF(state->IsNot_singleton);
return state->IsNot_singleton;
case In:
Py_INCREF(state->In_singleton);
return state->In_singleton;
case NotIn:
Py_INCREF(state->NotIn_singleton);
return state->NotIn_singleton;
}
Py_UNREACHABLE();
}
PyObject*
ast2obj_comprehension(struct ast_state *state, void* _o)
{
comprehension_ty o = (comprehension_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->comprehension_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_expr(state, o->target);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->target, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->iter);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->iter, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->ifs, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->ifs, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->is_async);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->is_async, value) == -1)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_excepthandler(struct ast_state *state, void* _o)
{
excepthandler_ty o = (excepthandler_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
switch (o->kind) {
case ExceptHandler_kind:
tp = (PyTypeObject *)state->ExceptHandler_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(state, o->v.ExceptHandler.type);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_identifier(state, o->v.ExceptHandler.name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->v.ExceptHandler.body,
ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
break;
}
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_arguments(struct ast_state *state, void* _o)
{
arguments_ty o = (arguments_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->arguments_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_list(state, (asdl_seq*)o->posonlyargs, ast2obj_arg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->posonlyargs, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->args, ast2obj_arg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->args, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_arg(state, o->vararg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->vararg, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->kwonlyargs, ast2obj_arg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->kwonlyargs, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->kw_defaults, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->kw_defaults, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_arg(state, o->kwarg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->kwarg, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->defaults, ast2obj_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->defaults, value) == -1)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_arg(struct ast_state *state, void* _o)
{
arg_ty o = (arg_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->arg_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_identifier(state, o->arg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->arg, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->annotation);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->annotation, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->type_comment);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->type_comment, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_keyword(struct ast_state *state, void* _o)
{
keyword_ty o = (keyword_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->keyword_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_identifier(state, o->arg);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->arg, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->value, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_alias(struct ast_state *state, void* _o)
{
alias_ty o = (alias_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->alias_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_identifier(state, o->name);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_identifier(state, o->asname);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->asname, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->col_offset, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
goto failed;
Py_DECREF(value);
value = ast2obj_int(state, o->end_col_offset);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_withitem(struct ast_state *state, void* _o)
{
withitem_ty o = (withitem_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->withitem_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_expr(state, o->context_expr);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->context_expr, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->optional_vars);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->optional_vars, value) == -1)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_match_case(struct ast_state *state, void* _o)
{
match_case_ty o = (match_case_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
tp = (PyTypeObject *)state->match_case_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) return NULL;
value = ast2obj_expr(state, o->pattern);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->pattern, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, o->guard);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->guard, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(state, (asdl_seq*)o->body, ast2obj_stmt);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->body, value) == -1)
goto failed;
Py_DECREF(value);
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
PyObject*
ast2obj_type_ignore(struct ast_state *state, void* _o)
{
type_ignore_ty o = (type_ignore_ty)_o;
PyObject *result = NULL, *value = NULL;
PyTypeObject *tp;
if (!o) {
Py_RETURN_NONE;
}
switch (o->kind) {
case TypeIgnore_kind:
tp = (PyTypeObject *)state->TypeIgnore_type;
result = PyType_GenericNew(tp, NULL, NULL);
if (!result) goto failed;
value = ast2obj_int(state, o->v.TypeIgnore.lineno);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->lineno, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_string(state, o->v.TypeIgnore.tag);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->tag, value) == -1)
goto failed;
Py_DECREF(value);
break;
}
return result;
failed:
Py_XDECREF(value);
Py_XDECREF(result);
return NULL;
}
int
obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena)
{
int isinstance;
PyObject *tmp = NULL;
PyObject *tp;
if (obj == Py_None) {
*out = NULL;
return 0;
}
tp = state->Module_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_stmt_seq* body;
asdl_type_ignore_seq* type_ignores;
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_ignores, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"type_ignores\" missing from Module");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Module field \"type_ignores\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
type_ignores = _Py_asdl_type_ignore_seq_new(len, arena);
if (type_ignores == NULL) goto failed;
for (i = 0; i < len; i++) {
type_ignore_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_type_ignore(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Module field \"type_ignores\" changed size during iteration");
goto failed;
}
asdl_seq_SET(type_ignores, i, val);
}
Py_CLEAR(tmp);
}
*out = _PyAST_Module(body, type_ignores, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Interactive_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_stmt_seq* body;
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Interactive(body, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Expression_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty body;
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &body, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Expression(body, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->FunctionType_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* argtypes;
expr_ty returns;
if (_PyObject_LookupAttr(obj, state->argtypes, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"argtypes\" missing from FunctionType");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "FunctionType field \"argtypes\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
argtypes = _Py_asdl_expr_seq_new(len, arena);
if (argtypes == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "FunctionType field \"argtypes\" changed size during iteration");
goto failed;
}
asdl_seq_SET(argtypes, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"returns\" missing from FunctionType");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &returns, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_FunctionType(argtypes, returns, arena);
if (*out == NULL) goto failed;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj);
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena*
arena)
{
int isinstance;
PyObject *tmp = NULL;
PyObject *tp;
int lineno;
int col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
int end_lineno;
int end_col_offset;
if (obj == Py_None) {
*out = NULL;
return 0;
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
tp = state->FunctionDef_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier name;
arguments_ty args;
asdl_stmt_seq* body;
asdl_expr_seq* decorator_list;
expr_ty returns;
string type_comment;
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef");
return 1;
}
else {
int res;
res = obj2ast_arguments(state, tmp, &args, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
decorator_list = _Py_asdl_expr_seq_new(len, arena);
if (decorator_list == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration");
goto failed;
}
asdl_seq_SET(decorator_list, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
returns = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &returns, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_FunctionDef(name, args, body, decorator_list, returns,
type_comment, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->AsyncFunctionDef_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier name;
arguments_ty args;
asdl_stmt_seq* body;
asdl_expr_seq* decorator_list;
expr_ty returns;
string type_comment;
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from AsyncFunctionDef");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from AsyncFunctionDef");
return 1;
}
else {
int res;
res = obj2ast_arguments(state, tmp, &args, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
decorator_list = _Py_asdl_expr_seq_new(len, arena);
if (decorator_list == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"decorator_list\" changed size during iteration");
goto failed;
}
asdl_seq_SET(decorator_list, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
returns = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &returns, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_AsyncFunctionDef(name, args, body, decorator_list,
returns, type_comment, lineno,
col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->ClassDef_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier name;
asdl_expr_seq* bases;
asdl_keyword_seq* keywords;
asdl_stmt_seq* body;
asdl_expr_seq* decorator_list;
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->bases, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
bases = _Py_asdl_expr_seq_new(len, arena);
if (bases == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration");
goto failed;
}
asdl_seq_SET(bases, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
keywords = _Py_asdl_keyword_seq_new(len, arena);
if (keywords == NULL) goto failed;
for (i = 0; i < len; i++) {
keyword_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_keyword(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"keywords\" changed size during iteration");
goto failed;
}
asdl_seq_SET(keywords, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
decorator_list = _Py_asdl_expr_seq_new(len, arena);
if (decorator_list == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration");
goto failed;
}
asdl_seq_SET(decorator_list, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_ClassDef(name, bases, keywords, body, decorator_list,
lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Return_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
value = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Return(value, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Delete_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* targets;
if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
targets = _Py_asdl_expr_seq_new(len, arena);
if (targets == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration");
goto failed;
}
asdl_seq_SET(targets, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Delete(targets, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Assign_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* targets;
expr_ty value;
string type_comment;
if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
targets = _Py_asdl_expr_seq_new(len, arena);
if (targets == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration");
goto failed;
}
asdl_seq_SET(targets, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_Assign(targets, value, type_comment, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->AugAssign_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
operator_ty op;
expr_ty value;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign");
return 1;
}
else {
int res;
res = obj2ast_operator(state, tmp, &op, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_AugAssign(target, op, value, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->AnnAssign_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
expr_ty annotation;
expr_ty value;
int simple;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AnnAssign");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"annotation\" missing from AnnAssign");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &annotation, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
value = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->simple, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"simple\" missing from AnnAssign");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &simple, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_AnnAssign(target, annotation, value, simple, lineno,
col_offset, end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->For_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
expr_ty iter;
asdl_stmt_seq* body;
asdl_stmt_seq* orelse;
string type_comment;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &iter, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_stmt_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration");
goto failed;
}
asdl_seq_SET(orelse, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_For(target, iter, body, orelse, type_comment, lineno,
col_offset, end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->AsyncFor_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
expr_ty iter;
asdl_stmt_seq* body;
asdl_stmt_seq* orelse;
string type_comment;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AsyncFor");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from AsyncFor");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &iter, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFor field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncFor field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_stmt_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"orelse\" changed size during iteration");
goto failed;
}
asdl_seq_SET(orelse, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_AsyncFor(target, iter, body, orelse, type_comment,
lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->While_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty test;
asdl_stmt_seq* body;
asdl_stmt_seq* orelse;
if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &test, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_stmt_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration");
goto failed;
}
asdl_seq_SET(orelse, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_While(test, body, orelse, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->If_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty test;
asdl_stmt_seq* body;
asdl_stmt_seq* orelse;
if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &test, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_stmt_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration");
goto failed;
}
asdl_seq_SET(orelse, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_If(test, body, orelse, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->With_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_withitem_seq* items;
asdl_stmt_seq* body;
string type_comment;
if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
items = _Py_asdl_withitem_seq_new(len, arena);
if (items == NULL) goto failed;
for (i = 0; i < len; i++) {
withitem_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_withitem(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "With field \"items\" changed size during iteration");
goto failed;
}
asdl_seq_SET(items, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_With(items, body, type_comment, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->AsyncWith_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_withitem_seq* items;
asdl_stmt_seq* body;
string type_comment;
if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncWith field \"items\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
items = _Py_asdl_withitem_seq_new(len, arena);
if (items == NULL) goto failed;
for (i = 0; i < len; i++) {
withitem_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_withitem(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"items\" changed size during iteration");
goto failed;
}
asdl_seq_SET(items, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "AsyncWith field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_AsyncWith(items, body, type_comment, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Match_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty subject;
asdl_match_case_seq* cases;
if (_PyObject_LookupAttr(obj, state->subject, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"subject\" missing from Match");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &subject, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->cases, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"cases\" missing from Match");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Match field \"cases\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
cases = _Py_asdl_match_case_seq_new(len, arena);
if (cases == NULL) goto failed;
for (i = 0; i < len; i++) {
match_case_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_match_case(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Match field \"cases\" changed size during iteration");
goto failed;
}
asdl_seq_SET(cases, i, val);
}
Py_CLEAR(tmp);
}
*out = _PyAST_Match(subject, cases, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Raise_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty exc;
expr_ty cause;
if (_PyObject_LookupAttr(obj, state->exc, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
exc = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &exc, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->cause, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
cause = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &cause, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Raise(exc, cause, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Try_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_stmt_seq* body;
asdl_excepthandler_seq* handlers;
asdl_stmt_seq* orelse;
asdl_stmt_seq* finalbody;
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Try field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
handlers = _Py_asdl_excepthandler_seq_new(len, arena);
if (handlers == NULL) goto failed;
for (i = 0; i < len; i++) {
excepthandler_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_excepthandler(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Try field \"handlers\" changed size during iteration");
goto failed;
}
asdl_seq_SET(handlers, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
orelse = _Py_asdl_stmt_seq_new(len, arena);
if (orelse == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Try field \"orelse\" changed size during iteration");
goto failed;
}
asdl_seq_SET(orelse, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
finalbody = _Py_asdl_stmt_seq_new(len, arena);
if (finalbody == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Try field \"finalbody\" changed size during iteration");
goto failed;
}
asdl_seq_SET(finalbody, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Try(body, handlers, orelse, finalbody, lineno,
col_offset, end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Assert_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty test;
expr_ty msg;
if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &test, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->msg, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
msg = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &msg, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Assert(test, msg, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Import_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_alias_seq* names;
if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
names = _Py_asdl_alias_seq_new(len, arena);
if (names == NULL) goto failed;
for (i = 0; i < len; i++) {
alias_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_alias(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration");
goto failed;
}
asdl_seq_SET(names, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Import(names, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->ImportFrom_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier module;
asdl_alias_seq* names;
int level;
if (_PyObject_LookupAttr(obj, state->module, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
module = NULL;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &module, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
names = _Py_asdl_alias_seq_new(len, arena);
if (names == NULL) goto failed;
for (i = 0; i < len; i++) {
alias_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_alias(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration");
goto failed;
}
asdl_seq_SET(names, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->level, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
level = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &level, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_ImportFrom(module, names, level, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Global_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_identifier_seq* names;
if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
names = _Py_asdl_identifier_seq_new(len, arena);
if (names == NULL) goto failed;
for (i = 0; i < len; i++) {
identifier val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_identifier(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration");
goto failed;
}
asdl_seq_SET(names, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Global(names, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Nonlocal_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_identifier_seq* names;
if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
names = _Py_asdl_identifier_seq_new(len, arena);
if (names == NULL) goto failed;
for (i = 0; i < len; i++) {
identifier val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_identifier(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Nonlocal field \"names\" changed size during iteration");
goto failed;
}
asdl_seq_SET(names, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Nonlocal(names, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Expr_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Expr(value, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Pass_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = _PyAST_Pass(lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Break_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = _PyAST_Break(lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Continue_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = _PyAST_Continue(lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj);
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena*
arena)
{
int isinstance;
PyObject *tmp = NULL;
PyObject *tp;
int lineno;
int col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
int end_lineno;
int end_col_offset;
if (obj == Py_None) {
*out = NULL;
return 0;
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
tp = state->BoolOp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
boolop_ty op;
asdl_expr_seq* values;
if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp");
return 1;
}
else {
int res;
res = obj2ast_boolop(state, tmp, &op, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
values = _Py_asdl_expr_seq_new(len, arena);
if (values == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration");
goto failed;
}
asdl_seq_SET(values, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_BoolOp(op, values, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->NamedExpr_type;
isinstance = PyObject_IsInstance(obj, tp);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty target;
expr_ty value;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from NamedExpr");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NamedExpr");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_NamedExpr(target, value, lineno, col_offset, end_lineno,
end_col_offset, arena);
bpo-35224: PEP 572 Implementation (#10497) * Add tokenization of := - Add token to Include/token.h. Add token to documentation in Doc/library/token.rst. - Run `./python Lib/token.py` to regenerate Lib/token.py. - Update Parser/tokenizer.c: add case to handle `:=`. * Add initial usage of := in grammar. * Update Python.asdl to match the grammar updates. Regenerated Include/Python-ast.h and Python/Python-ast.c * Update AST and compiler files in Python/ast.c and Python/compile.c. Basic functionality, this isn't scoped properly * Regenerate Lib/symbol.py using `./python Lib/symbol.py` * Tests - Fix failing tests in test_parser.py due to changes in token numbers for internal representation * Tests - Add simple test for := token * Tests - Add simple tests for named expressions using expr and suite * Tests - Update number of levels for nested expressions to prevent stack overflow * Update symbol table to handle NamedExpr * Update Grammar to allow assignment expressions in if statements. Regenerate Python/graminit.c accordingly using `make regen-grammar` * Tests - Add additional tests for named expressions in RoundtripLegalSyntaxTestCase, based on examples and information directly from PEP 572 Note: failing tests are currently commented out (4 out of 24 tests currently fail) * Tests - Add temporary syntax test failure tests in test_parser.py Note: There is an outstanding TODO for this -- syntax tests need to be moved to a different file (presumably test_syntax.py), but this is covering what needs to be tested at the moment, and it's more convenient to run a single test for the time being * Add support for allowing assignment expressions as function argument annotations. Uncomment tests for these cases because they all pass now! * Tests - Move existing syntax tests out of test_parser.py and into test_named_expressions.py. Refactor syntax tests to use unittest * Add TargetScopeError exception to extend SyntaxError Note: This simply creates the TargetScopeError exception, it is not yet used anywhere * Tests - Update tests per PEP 572 Continue refactoring test suite: The named expression test suite now checks for any invalid cases that throw exceptions (no longer limited to SyntaxErrors), assignment tests to ensure that variables are properly assigned, and scope tests to ensure that variable availability and values are correct Note: - There are still tests that are marked to skip, as they are not yet implemented - There are approximately 300 lines of the PEP that have not yet been addressed, though these may be deferred * Documentation - Small updates to XXX/todo comments - Remove XXX from child description in ast.c - Add comment with number of previously supported nested expressions for 3.7.X in test_parser.py * Fix assert in seq_for_testlist() * Cleanup - Denote "Not implemented -- No keyword args" on failing test case. Fix PEP8 error for blank lines at beginning of test classes in test_parser.py * Tests - Wrap all file opens in `with...as` to ensure files are closed * WIP: handle f(a := 1) * Tests and Cleanup - No longer skips keyword arg test. Keyword arg test now uses a simpler test case and does not rely on an external file. Remove print statements from ast.c * Tests - Refactor last remaining test case that relied on on external file to use a simpler test case without the dependency * Tests - Add better description of remaning skipped tests. Add test checking scope when using assignment expression in a function argument * Tests - Add test for nested comprehension, testing value and scope. Fix variable name in skipped comprehension scope test * Handle restriction of LHS for named expressions - can only assign to LHS of type NAME. Specifically, restrict assignment to tuples This adds an alternative set_context specifically for named expressions, set_namedexpr_context. Thus, context is now set differently for standard assignment versus assignment for named expressions in order to handle restrictions. * Tests - Update negative test case for assigning to lambda to match new error message. Add negative test case for assigning to tuple * Tests - Reorder test cases to group invalid syntax cases and named assignment target errors * Tests - Update test case for named expression in function argument - check that result and variable are set correctly * Todo - Add todo for TargetScopeError based on Guido's comment (https://github.com/python/cpython/commit/2b3acd37bdfc2d35e5094228c6684050d2aa8b0a#r30472562) * Tests - Add named expression tests for assignment operator in function arguments Note: One of two tests are skipped, as function arguments are currently treating an assignment expression inside of parenthesis as one child, which does not properly catch the named expression, nor does it count arguments properly * Add NamedStore to expr_context. Regenerate related code with `make regen-ast` * Add usage of NamedStore to ast_for_named_expr in ast.c. Update occurances of checking for Store to also handle NamedStore where appropriate * Add ste_comprehension to _symtable_entry to track if the namespace is a comprehension. Initialize ste_comprehension to 0. Set set_comprehension to 1 in symtable_handle_comprehension * s/symtable_add_def/symtable_add_def_helper. Add symtable_add_def to handle grabbing st->st_cur and passing it to symtable_add_def_helper. This now allows us to call the original code from symtable_add_def by instead calling symtable_add_def_helper with a different ste. * Refactor symtable_record_directive to take lineno and col_offset as arguments instead of stmt_ty. This allows symtable_record_directive to be used for stmt_ty and expr_ty * Handle elevating scope for named expressions in comprehensions. * Handle error for usage of named expression inside a class block * Tests - No longer skip scope tests. Add additional scope tests * Cleanup - Update error message for named expression within a comprehension within a class. Update comments. Add assert for symtable_extend_namedexpr_scope to validate that we always find at least a ModuleScope if we don't find a Class or FunctionScope * Cleanup - Add missing case for NamedStore in expr_context_name. Remove unused var in set_namedexpr_content * Refactor - Consolidate set_context and set_namedexpr_context to reduce duplicated code. Special cases for named expressions are handled by checking if ctx is NamedStore * Cleanup - Add additional use cases for ast_for_namedexpr in usage comment. Fix multiple blank lines in test_named_expressions * Tests - Remove unnecessary test case. Renumber test case function names * Remove TargetScopeError for now. Will add back if needed * Cleanup - Small comment nit for consistency * Handle positional argument check with named expression * Add TargetScopeError exception definition. Add documentation for TargetScopeError in c-api docs. Throw TargetScopeError instead of SyntaxError when using a named expression in a comprehension within a class scope * Increase stack size for parser by 200. This is a minimal change (approx. 5kb) and should not have an impact on any systems. Update parser test to allow 99 nested levels again * Add TargetScopeError to exception_hierarchy.txt for test_baseexception.py_ * Tests - Major update for named expression tests, both in test_named_expressions and test_parser - Add test for TargetScopeError - Add tests for named expressions in comprehension scope and edge cases - Add tests for named expressions in function arguments (declarations and call sites) - Reorganize tests to group them more logically * Cleanup - Remove unnecessary comment * Cleanup - Comment nitpicks * Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0) - Add check for LHS types to detect a parenthesis then a name (see note) - Add test for this scenario - Update tests for changed error message for named assignment to a tuple (also, see note) Note: This caused issues with the previous error handling for named assignment to a LHS that contained an expression, such as a tuple. Thus, the check for the LHS of a named expression must be changed to be more specific if we wish to maintain the previous error messages * Cleanup - Wrap lines more strictly in test file * Revert "Explicitly disallow assignment expressions to a name inside parentheses, e.g.: ((x) := 0)" This reverts commit f1531400ca7d7a2d148830c8ac703f041740896d. * Add NEWS.d entry * Tests - Fix error in test_pickle.test_exceptions by adding TargetScopeError to list of exceptions * Tests - Update error message tests to reflect improved messaging convention (s/can't/cannot) * Remove cases that cannot be reached in compile.c. Small linting update. * Update Grammar/Tokens to add COLONEQUAL. Regenerate all files * Update TargetScopeError PRE_INIT and POST_INIT, as this was purposefully left out when fixing rebase conflicts * Add NamedStore back and regenerate files * Pass along line number and end col info for named expression * Simplify News entry * Fix compiler warning and explicity mark fallthrough
2019-01-24 19:49:56 -04:00
if (*out == NULL) goto failed;
return 0;
}
tp = state->BinOp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty left;
operator_ty op;
expr_ty right;
if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &left, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp");
return 1;
}
else {
int res;
res = obj2ast_operator(state, tmp, &op, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->right, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &right, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_BinOp(left, op, right, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->UnaryOp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
unaryop_ty op;
expr_ty operand;
if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp");
return 1;
}
else {
int res;
res = obj2ast_unaryop(state, tmp, &op, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->operand, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &operand, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_UnaryOp(op, operand, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Lambda_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
arguments_ty args;
expr_ty body;
if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda");
return 1;
}
else {
int res;
res = obj2ast_arguments(state, tmp, &args, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &body, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Lambda(args, body, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->IfExp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty test;
expr_ty body;
expr_ty orelse;
if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &test, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &body, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &orelse, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_IfExp(test, body, orelse, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Dict_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* keys;
asdl_expr_seq* values;
if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
keys = _Py_asdl_expr_seq_new(len, arena);
if (keys == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration");
goto failed;
}
asdl_seq_SET(keys, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
values = _Py_asdl_expr_seq_new(len, arena);
if (values == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration");
goto failed;
}
asdl_seq_SET(values, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Dict(keys, values, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Set_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* elts;
if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
elts = _Py_asdl_expr_seq_new(len, arena);
if (elts == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration");
goto failed;
}
asdl_seq_SET(elts, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Set(elts, lineno, col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->ListComp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty elt;
asdl_comprehension_seq* generators;
if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &elt, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
generators = _Py_asdl_comprehension_seq_new(len, arena);
if (generators == NULL) goto failed;
for (i = 0; i < len; i++) {
comprehension_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_comprehension(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration");
goto failed;
}
asdl_seq_SET(generators, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_ListComp(elt, generators, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->SetComp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty elt;
asdl_comprehension_seq* generators;
if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &elt, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
generators = _Py_asdl_comprehension_seq_new(len, arena);
if (generators == NULL) goto failed;
for (i = 0; i < len; i++) {
comprehension_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_comprehension(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration");
goto failed;
}
asdl_seq_SET(generators, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_SetComp(elt, generators, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->DictComp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty key;
expr_ty value;
asdl_comprehension_seq* generators;
if (_PyObject_LookupAttr(obj, state->key, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &key, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
generators = _Py_asdl_comprehension_seq_new(len, arena);
if (generators == NULL) goto failed;
for (i = 0; i < len; i++) {
comprehension_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_comprehension(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration");
goto failed;
}
asdl_seq_SET(generators, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_DictComp(key, value, generators, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->GeneratorExp_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty elt;
asdl_comprehension_seq* generators;
if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &elt, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
generators = _Py_asdl_comprehension_seq_new(len, arena);
if (generators == NULL) goto failed;
for (i = 0; i < len; i++) {
comprehension_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_comprehension(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration");
goto failed;
}
asdl_seq_SET(generators, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_GeneratorExp(elt, generators, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Await_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Await");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_Await(value, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Yield_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
value = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Yield(value, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->YieldFrom_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_YieldFrom(value, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Compare_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty left;
asdl_int_seq* ops;
asdl_expr_seq* comparators;
if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &left, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ops, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
ops = _Py_asdl_int_seq_new(len, arena);
if (ops == NULL) goto failed;
for (i = 0; i < len; i++) {
cmpop_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_cmpop(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration");
goto failed;
}
asdl_seq_SET(ops, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->comparators, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
comparators = _Py_asdl_expr_seq_new(len, arena);
if (comparators == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration");
goto failed;
}
asdl_seq_SET(comparators, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Compare(left, ops, comparators, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Call_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty func;
asdl_expr_seq* args;
asdl_keyword_seq* keywords;
if (_PyObject_LookupAttr(obj, state->func, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &func, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
args = _Py_asdl_expr_seq_new(len, arena);
if (args == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration");
goto failed;
}
asdl_seq_SET(args, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
keywords = _Py_asdl_keyword_seq_new(len, arena);
if (keywords == NULL) goto failed;
for (i = 0; i < len; i++) {
keyword_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_keyword(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration");
goto failed;
}
asdl_seq_SET(keywords, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Call(func, args, keywords, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->FormattedValue_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
int conversion;
expr_ty format_spec;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from FormattedValue");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->conversion, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
conversion = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &conversion, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->format_spec, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
format_spec = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &format_spec, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_FormattedValue(value, conversion, format_spec, lineno,
col_offset, end_lineno, end_col_offset,
arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->JoinedStr_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* values;
if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from JoinedStr");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "JoinedStr field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
values = _Py_asdl_expr_seq_new(len, arena);
if (values == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "JoinedStr field \"values\" changed size during iteration");
goto failed;
}
asdl_seq_SET(values, i, val);
}
Py_CLEAR(tmp);
}
*out = _PyAST_JoinedStr(values, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Constant_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
constant value;
string kind;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Constant");
return 1;
}
else {
int res;
res = obj2ast_constant(state, tmp, &value, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->kind, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
kind = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &kind, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_Constant(value, kind, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Attribute_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
identifier attr;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->attr, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &attr, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Attribute(value, attr, ctx, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Subscript_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
expr_ty slice;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->slice, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &slice, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Subscript(value, slice, ctx, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Starred_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty value;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Starred(value, ctx, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Name_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
identifier id;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->id, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &id, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_Name(id, ctx, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->List_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* elts;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
elts = _Py_asdl_expr_seq_new(len, arena);
if (elts == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration");
goto failed;
}
asdl_seq_SET(elts, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
2009-12-12 21:24:58 -04:00
}
*out = _PyAST_List(elts, ctx, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Tuple_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* elts;
expr_context_ty ctx;
if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
elts = _Py_asdl_expr_seq_new(len, arena);
if (elts == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration");
goto failed;
}
asdl_seq_SET(elts, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple");
return 1;
}
else {
int res;
res = obj2ast_expr_context(state, tmp, &ctx, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Tuple(elts, ctx, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->Slice_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty lower;
expr_ty upper;
expr_ty step;
if (_PyObject_LookupAttr(obj, state->lower, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
lower = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &lower, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->upper, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
upper = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &upper, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->step, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
step = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &step, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_Slice(lower, upper, step, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->MatchAs_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty pattern;
identifier name;
if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"pattern\" missing from MatchAs");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &pattern, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from MatchAs");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_MatchAs(pattern, name, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
tp = state->MatchOr_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
asdl_expr_seq* patterns;
if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchOr");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "MatchOr field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
patterns = _Py_asdl_expr_seq_new(len, arena);
if (patterns == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "MatchOr field \"patterns\" changed size during iteration");
goto failed;
}
asdl_seq_SET(patterns, i, val);
}
Py_CLEAR(tmp);
}
*out = _PyAST_MatchOr(patterns, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj);
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_expr_context(struct ast_state *state, PyObject* obj, expr_context_ty*
out, PyArena* arena)
{
int isinstance;
isinstance = PyObject_IsInstance(obj, state->Load_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Load;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Store_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Store;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Del_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Del;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj);
return 1;
}
int
obj2ast_boolop(struct ast_state *state, PyObject* obj, boolop_ty* out, PyArena*
arena)
{
int isinstance;
isinstance = PyObject_IsInstance(obj, state->And_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = And;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Or_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Or;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj);
return 1;
}
int
obj2ast_operator(struct ast_state *state, PyObject* obj, operator_ty* out,
PyArena* arena)
{
int isinstance;
isinstance = PyObject_IsInstance(obj, state->Add_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Add;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Sub_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Sub;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Mult_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Mult;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->MatMult_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = MatMult;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Div_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Div;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Mod_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Mod;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Pow_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Pow;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->LShift_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = LShift;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->RShift_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = RShift;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->BitOr_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = BitOr;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->BitXor_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = BitXor;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->BitAnd_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = BitAnd;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->FloorDiv_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = FloorDiv;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj);
return 1;
}
int
obj2ast_unaryop(struct ast_state *state, PyObject* obj, unaryop_ty* out,
PyArena* arena)
{
int isinstance;
isinstance = PyObject_IsInstance(obj, state->Invert_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Invert;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Not_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Not;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->UAdd_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = UAdd;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->USub_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = USub;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj);
return 1;
}
int
obj2ast_cmpop(struct ast_state *state, PyObject* obj, cmpop_ty* out, PyArena*
arena)
{
int isinstance;
isinstance = PyObject_IsInstance(obj, state->Eq_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Eq;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->NotEq_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = NotEq;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Lt_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Lt;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->LtE_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = LtE;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Gt_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Gt;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->GtE_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = GtE;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->Is_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = Is;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->IsNot_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = IsNot;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->In_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = In;
return 0;
}
isinstance = PyObject_IsInstance(obj, state->NotIn_type);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
*out = NotIn;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj);
return 1;
}
int
obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty*
out, PyArena* arena)
{
PyObject* tmp = NULL;
expr_ty target;
expr_ty iter;
asdl_expr_seq* ifs;
int is_async;
if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &target, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &iter, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->ifs, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
ifs = _Py_asdl_expr_seq_new(len, arena);
if (ifs == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration");
goto failed;
}
asdl_seq_SET(ifs, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->is_async, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"is_async\" missing from comprehension");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &is_async, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_comprehension(target, iter, ifs, is_async, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty*
out, PyArena* arena)
{
int isinstance;
PyObject *tmp = NULL;
PyObject *tp;
int lineno;
int col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
int end_lineno;
int end_col_offset;
if (obj == Py_None) {
*out = NULL;
return 0;
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
tp = state->ExceptHandler_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
expr_ty type;
identifier name;
asdl_stmt_seq* body;
if (_PyObject_LookupAttr(obj, state->type, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &type, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
name = NULL;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_ExceptHandler(type, name, body, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj);
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out,
PyArena* arena)
{
PyObject* tmp = NULL;
asdl_arg_seq* posonlyargs;
asdl_arg_seq* args;
arg_ty vararg;
asdl_arg_seq* kwonlyargs;
asdl_expr_seq* kw_defaults;
arg_ty kwarg;
asdl_expr_seq* defaults;
if (_PyObject_LookupAttr(obj, state->posonlyargs, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"posonlyargs\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"posonlyargs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
posonlyargs = _Py_asdl_arg_seq_new(len, arena);
if (posonlyargs == NULL) goto failed;
for (i = 0; i < len; i++) {
arg_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_arg(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"posonlyargs\" changed size during iteration");
goto failed;
}
asdl_seq_SET(posonlyargs, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
args = _Py_asdl_arg_seq_new(len, arena);
if (args == NULL) goto failed;
for (i = 0; i < len; i++) {
arg_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_arg(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration");
goto failed;
}
asdl_seq_SET(args, i, val);
}
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->vararg, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
vararg = NULL;
}
else {
int res;
res = obj2ast_arg(state, tmp, &vararg, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->kwonlyargs, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
kwonlyargs = _Py_asdl_arg_seq_new(len, arena);
if (kwonlyargs == NULL) goto failed;
for (i = 0; i < len; i++) {
arg_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_arg(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"kwonlyargs\" changed size during iteration");
goto failed;
}
asdl_seq_SET(kwonlyargs, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->kw_defaults, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
kw_defaults = _Py_asdl_expr_seq_new(len, arena);
if (kw_defaults == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"kw_defaults\" changed size during iteration");
goto failed;
}
asdl_seq_SET(kw_defaults, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->kwarg, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
kwarg = NULL;
}
else {
int res;
res = obj2ast_arg(state, tmp, &kwarg, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->defaults, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
defaults = _Py_asdl_expr_seq_new(len, arena);
if (defaults == NULL) goto failed;
for (i = 0; i < len; i++) {
expr_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_expr(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration");
goto failed;
}
asdl_seq_SET(defaults, i, val);
}
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults,
kwarg, defaults, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena)
{
PyObject* tmp = NULL;
identifier arg;
expr_ty annotation;
string type_comment;
int lineno;
int col_offset;
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
int end_lineno;
int end_col_offset;
if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &arg, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
annotation = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &annotation, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
type_comment = NULL;
}
else {
int res;
res = obj2ast_string(state, tmp, &type_comment, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from arg");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from arg");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
bpo-33416: Add end positions to Python AST (GH-11605) The majority of this PR is tediously passing `end_lineno` and `end_col_offset` everywhere. Here are non-trivial points: * It is not possible to reconstruct end positions in AST "on the fly", some information is lost after an AST node is constructed, so we need two more attributes for every AST node `end_lineno` and `end_col_offset`. * I add end position information to both CST and AST. Although it may be technically possible to avoid adding end positions to CST, the code becomes more cumbersome and less efficient. * Since the end position is not known for non-leaf CST nodes while the next token is added, this requires a bit of extra care (see `_PyNode_FinalizeEndPos`). Unless I made some mistake, the algorithm should be linear. * For statements, I "trim" the end position of suites to not include the terminal newlines and dedent (this seems to be what people would expect), for example in ```python class C: pass pass ``` the end line and end column for the class definition is (2, 8). * For `end_col_offset` I use the common Python convention for indexing, for example for `pass` the `end_col_offset` is 4 (not 3), so that `[0:4]` gives one the source code that corresponds to the node. * I added a helper function `ast.get_source_segment()`, to get source text segment corresponding to a given AST node. It is also useful for testing. An (inevitable) downside of this PR is that AST now takes almost 25% more memory. I think however it is probably justified by the benefits.
2019-01-22 07:18:22 -04:00
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_arg(arg, annotation, type_comment, lineno, col_offset,
end_lineno, end_col_offset, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out,
PyArena* arena)
{
PyObject* tmp = NULL;
identifier arg;
expr_ty value;
int lineno;
int col_offset;
int end_lineno;
int end_col_offset;
if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
arg = NULL;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &arg, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &value, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from keyword");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from keyword");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_keyword(arg, value, lineno, col_offset, end_lineno,
end_col_offset, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena*
arena)
{
PyObject* tmp = NULL;
identifier name;
identifier asname;
int lineno;
int col_offset;
int end_lineno;
int end_col_offset;
if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias");
return 1;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &name, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->asname, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
asname = NULL;
}
else {
int res;
res = obj2ast_identifier(state, tmp, &asname, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from alias");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from alias");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &col_offset, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_lineno = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
end_col_offset = 0;
}
else {
int res;
res = obj2ast_int(state, tmp, &end_col_offset, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_alias(name, asname, lineno, col_offset, end_lineno,
end_col_offset, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out,
PyArena* arena)
{
PyObject* tmp = NULL;
expr_ty context_expr;
expr_ty optional_vars;
if (_PyObject_LookupAttr(obj, state->context_expr, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &context_expr, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->optional_vars, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
optional_vars = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &optional_vars, arena);
if (res != 0) goto failed;
2013-07-26 19:03:47 -03:00
Py_CLEAR(tmp);
}
*out = _PyAST_withitem(context_expr, optional_vars, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out,
PyArena* arena)
{
PyObject* tmp = NULL;
expr_ty pattern;
expr_ty guard;
asdl_stmt_seq* body;
if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"pattern\" missing from match_case");
return 1;
}
else {
int res;
res = obj2ast_expr(state, tmp, &pattern, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->guard, &tmp) < 0) {
return 1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
guard = NULL;
}
else {
int res;
res = obj2ast_expr(state, tmp, &guard, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from match_case");
return 1;
}
else {
int res;
Py_ssize_t len;
Py_ssize_t i;
if (!PyList_Check(tmp)) {
PyErr_Format(PyExc_TypeError, "match_case field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
goto failed;
}
len = PyList_GET_SIZE(tmp);
body = _Py_asdl_stmt_seq_new(len, arena);
if (body == NULL) goto failed;
for (i = 0; i < len; i++) {
stmt_ty val;
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
Py_INCREF(tmp2);
res = obj2ast_stmt(state, tmp2, &val, arena);
Py_DECREF(tmp2);
if (res != 0) goto failed;
if (len != PyList_GET_SIZE(tmp)) {
PyErr_SetString(PyExc_RuntimeError, "match_case field \"body\" changed size during iteration");
goto failed;
}
asdl_seq_SET(body, i, val);
}
Py_CLEAR(tmp);
}
*out = _PyAST_match_case(pattern, guard, body, arena);
return 0;
failed:
Py_XDECREF(tmp);
return 1;
}
int
obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty*
out, PyArena* arena)
{
int isinstance;
PyObject *tmp = NULL;
PyObject *tp;
if (obj == Py_None) {
*out = NULL;
return 0;
}
tp = state->TypeIgnore_type;
isinstance = PyObject_IsInstance(obj, tp);
if (isinstance == -1) {
return 1;
}
if (isinstance) {
int lineno;
string tag;
if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from TypeIgnore");
return 1;
}
else {
int res;
res = obj2ast_int(state, tmp, &lineno, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
if (_PyObject_LookupAttr(obj, state->tag, &tmp) < 0) {
return 1;
}
if (tmp == NULL) {
PyErr_SetString(PyExc_TypeError, "required field \"tag\" missing from TypeIgnore");
return 1;
}
else {
int res;
res = obj2ast_string(state, tmp, &tag, arena);
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_TypeIgnore(lineno, tag, arena);
if (*out == NULL) goto failed;
return 0;
}
PyErr_Format(PyExc_TypeError, "expected some sort of type_ignore, but got %R", obj);
failed:
Py_XDECREF(tmp);
return 1;
}
static int
astmodule_exec(PyObject *m)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return -1;
}
if (PyModule_AddObjectRef(m, "AST", state->AST_type) < 0) {
return -1;
}
if (PyModule_AddIntMacro(m, PyCF_ALLOW_TOP_LEVEL_AWAIT) < 0) {
return -1;
}
if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) {
return -1;
}
if (PyModule_AddIntMacro(m, PyCF_TYPE_COMMENTS) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "mod", state->mod_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Module", state->Module_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Interactive", state->Interactive_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Expression", state->Expression_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "FunctionType", state->FunctionType_type) < 0)
{
return -1;
}
if (PyModule_AddObjectRef(m, "stmt", state->stmt_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "FunctionDef", state->FunctionDef_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "AsyncFunctionDef",
state->AsyncFunctionDef_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "ClassDef", state->ClassDef_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Return", state->Return_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Delete", state->Delete_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Assign", state->Assign_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "AugAssign", state->AugAssign_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "AnnAssign", state->AnnAssign_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "For", state->For_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "AsyncFor", state->AsyncFor_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "While", state->While_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "If", state->If_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "With", state->With_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "AsyncWith", state->AsyncWith_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Match", state->Match_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Raise", state->Raise_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Try", state->Try_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Assert", state->Assert_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Import", state->Import_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "ImportFrom", state->ImportFrom_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Global", state->Global_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Nonlocal", state->Nonlocal_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Expr", state->Expr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Pass", state->Pass_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Break", state->Break_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Continue", state->Continue_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "expr", state->expr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "BoolOp", state->BoolOp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "NamedExpr", state->NamedExpr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "BinOp", state->BinOp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "UnaryOp", state->UnaryOp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Lambda", state->Lambda_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "IfExp", state->IfExp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Dict", state->Dict_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Set", state->Set_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "ListComp", state->ListComp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SetComp", state->SetComp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "DictComp", state->DictComp_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "GeneratorExp", state->GeneratorExp_type) < 0)
{
return -1;
}
if (PyModule_AddObjectRef(m, "Await", state->Await_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Yield", state->Yield_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "YieldFrom", state->YieldFrom_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Compare", state->Compare_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Call", state->Call_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "FormattedValue", state->FormattedValue_type)
< 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "JoinedStr", state->JoinedStr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Constant", state->Constant_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Attribute", state->Attribute_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Subscript", state->Subscript_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Starred", state->Starred_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Name", state->Name_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "List", state->List_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Tuple", state->Tuple_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Slice", state->Slice_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "MatchAs", state->MatchAs_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "MatchOr", state->MatchOr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "expr_context", state->expr_context_type) < 0)
{
return -1;
}
if (PyModule_AddObjectRef(m, "Load", state->Load_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Store", state->Store_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Del", state->Del_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "boolop", state->boolop_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "And", state->And_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Or", state->Or_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "operator", state->operator_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Add", state->Add_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Sub", state->Sub_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Mult", state->Mult_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "MatMult", state->MatMult_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Div", state->Div_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Mod", state->Mod_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Pow", state->Pow_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "LShift", state->LShift_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "RShift", state->RShift_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "BitOr", state->BitOr_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "BitXor", state->BitXor_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "BitAnd", state->BitAnd_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "FloorDiv", state->FloorDiv_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "unaryop", state->unaryop_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Invert", state->Invert_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Not", state->Not_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "UAdd", state->UAdd_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "USub", state->USub_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "cmpop", state->cmpop_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Eq", state->Eq_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "NotEq", state->NotEq_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Lt", state->Lt_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "LtE", state->LtE_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Gt", state->Gt_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "GtE", state->GtE_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Is", state->Is_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "IsNot", state->IsNot_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "In", state->In_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "NotIn", state->NotIn_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "comprehension", state->comprehension_type) <
0) {
return -1;
}
if (PyModule_AddObjectRef(m, "excepthandler", state->excepthandler_type) <
0) {
return -1;
}
if (PyModule_AddObjectRef(m, "ExceptHandler", state->ExceptHandler_type) <
0) {
return -1;
}
if (PyModule_AddObjectRef(m, "arguments", state->arguments_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "arg", state->arg_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "keyword", state->keyword_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "alias", state->alias_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "withitem", state->withitem_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "match_case", state->match_case_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "type_ignore", state->type_ignore_type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "TypeIgnore", state->TypeIgnore_type) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot astmodule_slots[] = {
{Py_mod_exec, astmodule_exec},
{0, NULL}
};
static struct PyModuleDef _astmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_ast",
// The _ast module uses a per-interpreter state (PyInterpreterState.ast)
.m_size = 0,
.m_slots = astmodule_slots,
};
PyMODINIT_FUNC
PyInit__ast(void)
{
return PyModuleDef_Init(&_astmodule);
}
PyObject* PyAST_mod2obj(mod_ty t)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return NULL;
}
return ast2obj_mod(state, t);
}
/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
{
const char * const req_name[] = {"Module", "Expression", "Interactive"};
2009-12-12 21:24:58 -04:00
int isinstance;
2014-02-10 23:41:40 -04:00
if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
return NULL;
}
struct ast_state *state = get_ast_state();
if (state == NULL) {
return NULL;
}
PyObject *req_type[3];
req_type[0] = state->Module_type;
req_type[1] = state->Expression_type;
req_type[2] = state->Interactive_type;
2014-02-10 23:41:40 -04:00
assert(0 <= mode && mode <= 2);
2009-12-12 21:24:58 -04:00
isinstance = PyObject_IsInstance(ast, req_type[mode]);
if (isinstance == -1)
return NULL;
if (!isinstance) {
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
req_name[mode], _PyType_Name(Py_TYPE(ast)));
return NULL;
}
mod_ty res = NULL;
if (obj2ast_mod(state, ast, &res, arena) != 0)
return NULL;
else
return res;
}
int PyAST_Check(PyObject* obj)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return -1;
}
return PyObject_IsInstance(obj, state->AST_type);
}