Commit 5ca576ed authored by Tim Peters's avatar Tim Peters

Merging the gen-branch into the main line, at Guido's direction. Yay!

Bugfix candidate in inspect.py:  it was referencing "self" outside of
a method.
parent 1dad6a86
...@@ -43,10 +43,11 @@ augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' ...@@ -43,10 +43,11 @@ augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>='
print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] ) print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
del_stmt: 'del' exprlist del_stmt: 'del' exprlist
pass_stmt: 'pass' pass_stmt: 'pass'
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
break_stmt: 'break' break_stmt: 'break'
continue_stmt: 'continue' continue_stmt: 'continue'
return_stmt: 'return' [testlist] return_stmt: 'return' [testlist]
yield_stmt: 'yield' testlist
raise_stmt: 'raise' [test [',' test [',' test]]] raise_stmt: 'raise' [test [',' test [',' test]]]
import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*) import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
import_as_name: NAME [NAME NAME] import_as_name: NAME [NAME NAME]
......
...@@ -33,6 +33,7 @@ typedef struct { ...@@ -33,6 +33,7 @@ typedef struct {
#define CO_VARARGS 0x0004 #define CO_VARARGS 0x0004
#define CO_VARKEYWORDS 0x0008 #define CO_VARKEYWORDS 0x0008
#define CO_NESTED 0x0010 #define CO_NESTED 0x0010
#define CO_GENERATOR 0x0020
extern DL_IMPORT(PyTypeObject) PyCode_Type; extern DL_IMPORT(PyTypeObject) PyCode_Type;
......
...@@ -21,6 +21,8 @@ typedef struct _frame { ...@@ -21,6 +21,8 @@ typedef struct _frame {
PyObject *f_globals; /* global symbol table (PyDictObject) */ PyObject *f_globals; /* global symbol table (PyDictObject) */
PyObject *f_locals; /* local symbol table (PyDictObject) */ PyObject *f_locals; /* local symbol table (PyDictObject) */
PyObject **f_valuestack; /* points after the last local */ PyObject **f_valuestack; /* points after the last local */
PyObject **f_stackbottom; /* points to the last item on the stack if
frame has yielded. */
PyObject *f_trace; /* Trace function */ PyObject *f_trace; /* Trace function */
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
PyThreadState *f_tstate; PyThreadState *f_tstate;
......
...@@ -18,47 +18,48 @@ ...@@ -18,47 +18,48 @@
#define break_stmt 273 #define break_stmt 273
#define continue_stmt 274 #define continue_stmt 274
#define return_stmt 275 #define return_stmt 275
#define raise_stmt 276 #define yield_stmt 276
#define import_stmt 277 #define raise_stmt 277
#define import_as_name 278 #define import_stmt 278
#define dotted_as_name 279 #define import_as_name 279
#define dotted_name 280 #define dotted_as_name 280
#define global_stmt 281 #define dotted_name 281
#define exec_stmt 282 #define global_stmt 282
#define assert_stmt 283 #define exec_stmt 283
#define compound_stmt 284 #define assert_stmt 284
#define if_stmt 285 #define compound_stmt 285
#define while_stmt 286 #define if_stmt 286
#define for_stmt 287 #define while_stmt 287
#define try_stmt 288 #define for_stmt 288
#define except_clause 289 #define try_stmt 289
#define suite 290 #define except_clause 290
#define test 291 #define suite 291
#define and_test 292 #define test 292
#define not_test 293 #define and_test 293
#define comparison 294 #define not_test 294
#define comp_op 295 #define comparison 295
#define expr 296 #define comp_op 296
#define xor_expr 297 #define expr 297
#define and_expr 298 #define xor_expr 298
#define shift_expr 299 #define and_expr 299
#define arith_expr 300 #define shift_expr 300
#define term 301 #define arith_expr 301
#define factor 302 #define term 302
#define power 303 #define factor 303
#define atom 304 #define power 304
#define listmaker 305 #define atom 305
#define lambdef 306 #define listmaker 306
#define trailer 307 #define lambdef 307
#define subscriptlist 308 #define trailer 308
#define subscript 309 #define subscriptlist 309
#define sliceop 310 #define subscript 310
#define exprlist 311 #define sliceop 311
#define testlist 312 #define exprlist 312
#define dictmaker 313 #define testlist 313
#define classdef 314 #define dictmaker 314
#define arglist 315 #define classdef 315
#define argument 316 #define arglist 316
#define list_iter 317 #define argument 317
#define list_for 318 #define list_iter 318
#define list_if 319 #define list_for 319
#define list_if 320
...@@ -71,6 +71,7 @@ extern "C" { ...@@ -71,6 +71,7 @@ extern "C" {
#define RETURN_VALUE 83 #define RETURN_VALUE 83
#define IMPORT_STAR 84 #define IMPORT_STAR 84
#define EXEC_STMT 85 #define EXEC_STMT 85
#define YIELD_VALUE 86
#define POP_BLOCK 87 #define POP_BLOCK 87
#define END_FINALLY 88 #define END_FINALLY 88
......
...@@ -46,6 +46,7 @@ typedef struct _symtable_entry { ...@@ -46,6 +46,7 @@ typedef struct _symtable_entry {
int ste_nested; /* true if scope is nested */ int ste_nested; /* true if scope is nested */
int ste_child_free; /* true if a child scope has free variables, int ste_child_free; /* true if a child scope has free variables,
including free refs to globals */ including free refs to globals */
int ste_generator; /* true if namespace is a generator */
int ste_opt_lineno; /* lineno of last exec or import * */ int ste_opt_lineno; /* lineno of last exec or import * */
struct symtable *ste_table; struct symtable *ste_table;
} PySymtableEntryObject; } PySymtableEntryObject;
......
...@@ -223,6 +223,7 @@ def_op('LOAD_LOCALS', 82) ...@@ -223,6 +223,7 @@ def_op('LOAD_LOCALS', 82)
def_op('RETURN_VALUE', 83) def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84) def_op('IMPORT_STAR', 84)
def_op('EXEC_STMT', 85) def_op('EXEC_STMT', 85)
def_op('YIELD_STMT', 86)
def_op('POP_BLOCK', 87) def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88) def_op('END_FINALLY', 88)
......
...@@ -349,32 +349,28 @@ class ListReader: ...@@ -349,32 +349,28 @@ class ListReader:
return self.lines[i] return self.lines[i]
else: return '' else: return ''
class EndOfBlock(Exception): pass def getblock(lines):
"""Extract the block of code at the top of the given list of lines."""
class BlockFinder:
"""Provide a tokeneater() method to detect the end of a code block.""" indent = 0
def __init__(self): started = 0
self.indent = 0 last = 0
self.started = 0 tokens = tokenize.generate_tokens(ListReader(lines).readline)
self.last = 0
for (type, token, (srow, scol), (erow, ecol), line) in tokens:
def tokeneater(self, type, token, (srow, scol), (erow, ecol), line): if not started:
if not self.started: if type == tokenize.NAME:
if type == tokenize.NAME: self.started = 1 started = 1
elif type == tokenize.NEWLINE: elif type == tokenize.NEWLINE:
self.last = srow last = srow
elif type == tokenize.INDENT: elif type == tokenize.INDENT:
self.indent = self.indent + 1 indent = indent + 1
elif type == tokenize.DEDENT: elif type == tokenize.DEDENT:
self.indent = self.indent - 1 indent = indent - 1
if self.indent == 0: raise EndOfBlock, self.last if indent == 0:
return lines[:last]
def getblock(lines): else:
"""Extract the block of code at the top of the given list of lines.""" raise ValueError, "unable to find block"
try:
tokenize.tokenize(ListReader(lines).readline, BlockFinder().tokeneater)
except EndOfBlock, eob:
return lines[:eob.args[0]]
def getsourcelines(object): def getsourcelines(object):
"""Return a list of source lines and starting line number for an object. """Return a list of source lines and starting line number for an object.
......
...@@ -77,9 +77,8 @@ def check(file): ...@@ -77,9 +77,8 @@ def check(file):
if verbose > 1: if verbose > 1:
print "checking", `file`, "..." print "checking", `file`, "..."
reset_globals()
try: try:
tokenize.tokenize(f.readline, tokeneater) process_tokens(tokenize.generate_tokens(f.readline))
except tokenize.TokenError, msg: except tokenize.TokenError, msg:
errprint("%s: Token Error: %s" % (`file`, str(msg))) errprint("%s: Token Error: %s" % (`file`, str(msg)))
...@@ -244,28 +243,19 @@ def format_witnesses(w): ...@@ -244,28 +243,19 @@ def format_witnesses(w):
prefix = prefix + "s" prefix = prefix + "s"
return prefix + " " + string.join(firsts, ', ') return prefix + " " + string.join(firsts, ', ')
# The collection of globals, the reset_globals() function, and the # Need Guido's enhancement
# tokeneater() function, depend on which version of tokenize is assert hasattr(tokenize, 'NL'), "tokenize module too old"
# in use.
if hasattr(tokenize, 'NL'): def process_tokens(tokens,
# take advantage of Guido's patch!
indents = []
check_equal = 0
def reset_globals():
global indents, check_equal
check_equal = 0
indents = [Whitespace("")]
def tokeneater(type, token, start, end, line,
INDENT=tokenize.INDENT, INDENT=tokenize.INDENT,
DEDENT=tokenize.DEDENT, DEDENT=tokenize.DEDENT,
NEWLINE=tokenize.NEWLINE, NEWLINE=tokenize.NEWLINE,
JUNK=(tokenize.COMMENT, tokenize.NL) ): JUNK=(tokenize.COMMENT, tokenize.NL)):
global indents, check_equal
indents = [Whitespace("")]
check_equal = 0
for (type, token, start, end, line) in tokens:
if type == NEWLINE: if type == NEWLINE:
# a program statement, or ENDMARKER, will eventually follow, # a program statement, or ENDMARKER, will eventually follow,
# after some (possibly empty) run of tokens of the form # after some (possibly empty) run of tokens of the form
...@@ -311,62 +301,6 @@ if hasattr(tokenize, 'NL'): ...@@ -311,62 +301,6 @@ if hasattr(tokenize, 'NL'):
msg = "indent not equal e.g. " + format_witnesses(witness) msg = "indent not equal e.g. " + format_witnesses(witness)
raise NannyNag(start[0], msg, line) raise NannyNag(start[0], msg, line)
else:
# unpatched version of tokenize
nesting_level = 0
indents = []
check_equal = 0
def reset_globals():
global nesting_level, indents, check_equal
nesting_level = check_equal = 0
indents = [Whitespace("")]
def tokeneater(type, token, start, end, line,
INDENT=tokenize.INDENT,
DEDENT=tokenize.DEDENT,
NEWLINE=tokenize.NEWLINE,
COMMENT=tokenize.COMMENT,
OP=tokenize.OP):
global nesting_level, indents, check_equal
if type == INDENT:
check_equal = 0
thisguy = Whitespace(token)
if not indents[-1].less(thisguy):
witness = indents[-1].not_less_witness(thisguy)
msg = "indent not greater e.g. " + format_witnesses(witness)
raise NannyNag(start[0], msg, line)
indents.append(thisguy)
elif type == DEDENT:
del indents[-1]
elif type == NEWLINE:
if nesting_level == 0:
check_equal = 1
elif type == COMMENT:
pass
elif check_equal:
check_equal = 0
thisguy = Whitespace(line)
if not indents[-1].equal(thisguy):
witness = indents[-1].not_equal_witness(thisguy)
msg = "indent not equal e.g. " + format_witnesses(witness)
raise NannyNag(start[0], msg, line)
if type == OP and token in ('{', '[', '('):
nesting_level = nesting_level + 1
elif type == OP and token in ('}', ']', ')'):
if nesting_level == 0:
raise NannyNag(start[0],
"unbalanced bracket '" + token + "'",
line)
nesting_level = nesting_level - 1
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -111,7 +111,12 @@ def tokenize(readline, tokeneater=printtoken): ...@@ -111,7 +111,12 @@ def tokenize(readline, tokeneater=printtoken):
except StopTokenizing: except StopTokenizing:
pass pass
# backwards compatible interface, probably not used
def tokenize_loop(readline, tokeneater): def tokenize_loop(readline, tokeneater):
for token_info in generate_tokens(readline):
apply(tokeneater, token_info)
def generate_tokens(readline):
lnum = parenlev = continued = 0 lnum = parenlev = continued = 0
namechars, numchars = string.letters + '_', string.digits namechars, numchars = string.letters + '_', string.digits
contstr, needcont = '', 0 contstr, needcont = '', 0
...@@ -129,12 +134,12 @@ def tokenize_loop(readline, tokeneater): ...@@ -129,12 +134,12 @@ def tokenize_loop(readline, tokeneater):
endmatch = endprog.match(line) endmatch = endprog.match(line)
if endmatch: if endmatch:
pos = end = endmatch.end(0) pos = end = endmatch.end(0)
tokeneater(STRING, contstr + line[:end], yield (STRING, contstr + line[:end],
strstart, (lnum, end), contline + line) strstart, (lnum, end), contline + line)
contstr, needcont = '', 0 contstr, needcont = '', 0
contline = None contline = None
elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n':
tokeneater(ERRORTOKEN, contstr + line, yield (ERRORTOKEN, contstr + line,
strstart, (lnum, len(line)), contline) strstart, (lnum, len(line)), contline)
contstr = '' contstr = ''
contline = None contline = None
...@@ -156,16 +161,16 @@ def tokenize_loop(readline, tokeneater): ...@@ -156,16 +161,16 @@ def tokenize_loop(readline, tokeneater):
if pos == max: break if pos == max: break
if line[pos] in '#\r\n': # skip comments or blank lines if line[pos] in '#\r\n': # skip comments or blank lines
tokeneater((NL, COMMENT)[line[pos] == '#'], line[pos:], yield ((NL, COMMENT)[line[pos] == '#'], line[pos:],
(lnum, pos), (lnum, len(line)), line) (lnum, pos), (lnum, len(line)), line)
continue continue
if column > indents[-1]: # count indents or dedents if column > indents[-1]: # count indents or dedents
indents.append(column) indents.append(column)
tokeneater(INDENT, line[:pos], (lnum, 0), (lnum, pos), line) yield (INDENT, line[:pos], (lnum, 0), (lnum, pos), line)
while column < indents[-1]: while column < indents[-1]:
indents = indents[:-1] indents = indents[:-1]
tokeneater(DEDENT, '', (lnum, pos), (lnum, pos), line) yield (DEDENT, '', (lnum, pos), (lnum, pos), line)
else: # continued statement else: # continued statement
if not line: if not line:
...@@ -181,12 +186,12 @@ def tokenize_loop(readline, tokeneater): ...@@ -181,12 +186,12 @@ def tokenize_loop(readline, tokeneater):
if initial in numchars or \ if initial in numchars or \
(initial == '.' and token != '.'): # ordinary number (initial == '.' and token != '.'): # ordinary number
tokeneater(NUMBER, token, spos, epos, line) yield (NUMBER, token, spos, epos, line)
elif initial in '\r\n': elif initial in '\r\n':
tokeneater(parenlev > 0 and NL or NEWLINE, yield (parenlev > 0 and NL or NEWLINE,
token, spos, epos, line) token, spos, epos, line)
elif initial == '#': elif initial == '#':
tokeneater(COMMENT, token, spos, epos, line) yield (COMMENT, token, spos, epos, line)
elif token in ("'''", '"""', # triple-quoted elif token in ("'''", '"""', # triple-quoted
"r'''", 'r"""', "R'''", 'R"""', "r'''", 'r"""', "R'''", 'R"""',
"u'''", 'u"""', "U'''", 'U"""', "u'''", 'u"""', "U'''", 'U"""',
...@@ -197,7 +202,7 @@ def tokenize_loop(readline, tokeneater): ...@@ -197,7 +202,7 @@ def tokenize_loop(readline, tokeneater):
if endmatch: # all on one line if endmatch: # all on one line
pos = endmatch.end(0) pos = endmatch.end(0)
token = line[start:pos] token = line[start:pos]
tokeneater(STRING, token, spos, (lnum, pos), line) yield (STRING, token, spos, (lnum, pos), line)
else: else:
strstart = (lnum, start) # multiple lines strstart = (lnum, start) # multiple lines
contstr = line[start:] contstr = line[start:]
...@@ -216,23 +221,23 @@ def tokenize_loop(readline, tokeneater): ...@@ -216,23 +221,23 @@ def tokenize_loop(readline, tokeneater):
contline = line contline = line
break break
else: # ordinary string else: # ordinary string
tokeneater(STRING, token, spos, epos, line) yield (STRING, token, spos, epos, line)
elif initial in namechars: # ordinary name elif initial in namechars: # ordinary name
tokeneater(NAME, token, spos, epos, line) yield (NAME, token, spos, epos, line)
elif initial == '\\': # continued stmt elif initial == '\\': # continued stmt
continued = 1 continued = 1
else: else:
if initial in '([{': parenlev = parenlev + 1 if initial in '([{': parenlev = parenlev + 1
elif initial in ')]}': parenlev = parenlev - 1 elif initial in ')]}': parenlev = parenlev - 1
tokeneater(OP, token, spos, epos, line) yield (OP, token, spos, epos, line)
else: else:
tokeneater(ERRORTOKEN, line[pos], yield (ERRORTOKEN, line[pos],
(lnum, pos), (lnum, pos+1), line) (lnum, pos), (lnum, pos+1), line)
pos = pos + 1 pos = pos + 1
for indent in indents[1:]: # pop remaining indent levels for indent in indents[1:]: # pop remaining indent levels
tokeneater(DEDENT, '', (lnum, 0), (lnum, 0), '') yield (DEDENT, '', (lnum, 0), (lnum, 0), '')
tokeneater(ENDMARKER, '', (lnum, 0), (lnum, 0), '') yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '')
if __name__ == '__main__': # testing if __name__ == '__main__': # testing
import sys import sys
......
...@@ -67,6 +67,7 @@ frame_dealloc(PyFrameObject *f) ...@@ -67,6 +67,7 @@ frame_dealloc(PyFrameObject *f)
{ {
int i, slots; int i, slots;
PyObject **fastlocals; PyObject **fastlocals;
PyObject **p;
Py_TRASHCAN_SAFE_BEGIN(f) Py_TRASHCAN_SAFE_BEGIN(f)
/* Kill all local variables */ /* Kill all local variables */
...@@ -76,6 +77,10 @@ frame_dealloc(PyFrameObject *f) ...@@ -76,6 +77,10 @@ frame_dealloc(PyFrameObject *f)
Py_XDECREF(*fastlocals); Py_XDECREF(*fastlocals);
} }
/* Free stack */
for (p = f->f_valuestack; p < f->f_stackbottom; p++) {
Py_XDECREF(*p);
}
Py_XDECREF(f->f_back); Py_XDECREF(f->f_back);
Py_XDECREF(f->f_code); Py_XDECREF(f->f_code);
Py_XDECREF(f->f_builtins); Py_XDECREF(f->f_builtins);
...@@ -221,6 +226,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, ...@@ -221,6 +226,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
f->f_localsplus[extras] = NULL; f->f_localsplus[extras] = NULL;
f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees); f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees);
f->f_stackbottom = f->f_valuestack;
return f; return f;
} }
......
This diff is collapsed.
...@@ -2634,6 +2634,17 @@ com_return_stmt(struct compiling *c, node *n) ...@@ -2634,6 +2634,17 @@ com_return_stmt(struct compiling *c, node *n)
if (!c->c_infunction) { if (!c->c_infunction) {
com_error(c, PyExc_SyntaxError, "'return' outside function"); com_error(c, PyExc_SyntaxError, "'return' outside function");
} }
if (c->c_flags & CO_GENERATOR) {
if (NCH(n) > 1) {
com_error(c, PyExc_SyntaxError,
"'return' with argument inside generator");
}
com_addoparg(c, LOAD_CONST,
com_addconst(c, PyExc_StopIteration));
com_push(c, 1);
com_addoparg(c, RAISE_VARARGS, 1);
}
else {
if (NCH(n) < 2) { if (NCH(n) < 2) {
com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
com_push(c, 1); com_push(c, 1);
...@@ -2641,6 +2652,19 @@ com_return_stmt(struct compiling *c, node *n) ...@@ -2641,6 +2652,19 @@ com_return_stmt(struct compiling *c, node *n)
else else
com_node(c, CHILD(n, 1)); com_node(c, CHILD(n, 1));
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
}
com_pop(c, 1);
}
static void
com_yield_stmt(struct compiling *c, node *n)
{
REQ(n, yield_stmt); /* 'yield' testlist */
if (!c->c_infunction) {
com_error(c, PyExc_SyntaxError, "'yield' outside function");
}
com_node(c, CHILD(n, 1));
com_addbyte(c, YIELD_VALUE);
com_pop(c, 1); com_pop(c, 1);
} }
...@@ -3455,6 +3479,9 @@ com_node(struct compiling *c, node *n) ...@@ -3455,6 +3479,9 @@ com_node(struct compiling *c, node *n)
case return_stmt: case return_stmt:
com_return_stmt(c, n); com_return_stmt(c, n);
break; break;
case yield_stmt:
com_yield_stmt(c, n);
break;
case raise_stmt: case raise_stmt:
com_raise_stmt(c, n); com_raise_stmt(c, n);
break; break;
...@@ -3674,10 +3701,19 @@ compile_funcdef(struct compiling *c, node *n) ...@@ -3674,10 +3701,19 @@ compile_funcdef(struct compiling *c, node *n)
c->c_infunction = 1; c->c_infunction = 1;
com_node(c, CHILD(n, 4)); com_node(c, CHILD(n, 4));
c->c_infunction = 0; c->c_infunction = 0;
if (c->c_flags & CO_GENERATOR) {
com_addoparg(c, LOAD_CONST,
com_addconst(c, PyExc_StopIteration));
com_push(c, 1);
com_addoparg(c, RAISE_VARARGS, 1);
com_pop(c, 1);
}
else {
com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
com_push(c, 1); com_push(c, 1);
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
com_pop(c, 1); com_pop(c, 1);
}
} }
static void static void
...@@ -4342,6 +4378,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste, ...@@ -4342,6 +4378,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
{ {
if (c->c_future && c->c_future->ff_nested_scopes) if (c->c_future && c->c_future->ff_nested_scopes)
c->c_flags |= CO_NESTED; c->c_flags |= CO_NESTED;
if (ste->ste_generator)
c->c_flags |= CO_GENERATOR;
if (ste->ste_type != TYPE_MODULE) if (ste->ste_type != TYPE_MODULE)
c->c_flags |= CO_NEWLOCALS; c->c_flags |= CO_NEWLOCALS;
if (ste->ste_type == TYPE_FUNCTION) { if (ste->ste_type == TYPE_FUNCTION) {
...@@ -4900,6 +4938,10 @@ symtable_node(struct symtable *st, node *n) ...@@ -4900,6 +4938,10 @@ symtable_node(struct symtable *st, node *n)
case del_stmt: case del_stmt:
symtable_assign(st, CHILD(n, 1), 0); symtable_assign(st, CHILD(n, 1), 0);
break; break;
case yield_stmt:
st->st_cur->ste_generator = 1;
n = CHILD(n, 1);
goto loop;
case expr_stmt: case expr_stmt:
if (NCH(n) == 1) if (NCH(n) == 1)
n = CHILD(n, 0); n = CHILD(n, 0);
......
This diff is collapsed.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define TYPE_NULL '0' #define TYPE_NULL '0'
#define TYPE_NONE 'N' #define TYPE_NONE 'N'
#define TYPE_STOPITER 'S'
#define TYPE_ELLIPSIS '.' #define TYPE_ELLIPSIS '.'
#define TYPE_INT 'i' #define TYPE_INT 'i'
#define TYPE_INT64 'I' #define TYPE_INT64 'I'
...@@ -120,6 +121,9 @@ w_object(PyObject *v, WFILE *p) ...@@ -120,6 +121,9 @@ w_object(PyObject *v, WFILE *p)
else if (v == Py_None) { else if (v == Py_None) {
w_byte(TYPE_NONE, p); w_byte(TYPE_NONE, p);
} }
else if (v == PyExc_StopIteration) {
w_byte(TYPE_STOPITER, p);
}
else if (v == Py_Ellipsis) { else if (v == Py_Ellipsis) {
w_byte(TYPE_ELLIPSIS, p); w_byte(TYPE_ELLIPSIS, p);
} }
...@@ -376,6 +380,10 @@ r_object(RFILE *p) ...@@ -376,6 +380,10 @@ r_object(RFILE *p)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
case TYPE_STOPITER:
Py_INCREF(PyExc_StopIteration);
return PyExc_StopIteration;
case TYPE_ELLIPSIS: case TYPE_ELLIPSIS:
Py_INCREF(Py_Ellipsis); Py_INCREF(Py_Ellipsis);
return Py_Ellipsis; return Py_Ellipsis;
......
...@@ -69,6 +69,7 @@ PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno) ...@@ -69,6 +69,7 @@ PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno)
else else
ste->ste_nested = 0; ste->ste_nested = 0;
ste->ste_child_free = 0; ste->ste_child_free = 0;
ste->ste_generator = 0;
if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
goto fail; goto fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment