Skip to content

Commit fe1541c

Browse files
authored
Add generator_stop (#1147)
1 parent 54ee753 commit fe1541c

11 files changed

Lines changed: 93 additions & 8 deletions

File tree

Src/IronPython/Compiler/Ast/FunctionDefinition.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ internal override int KwOnlyArgCount {
124124
/// </summary>
125125
public bool IsGenerator { get; set; }
126126

127+
internal bool GeneratorStop { get; set; }
128+
127129
/// <summary>
128130
/// Called by parser to mark that this function can set sys.exc_info().
129131
/// An alternative technique would be to just walk the body after the parse and look for a except block.
@@ -181,6 +183,10 @@ internal override FunctionAttributes Flags {
181183
fa |= FunctionAttributes.Generator;
182184
}
183185

186+
if (GeneratorStop) {
187+
fa |= FunctionAttributes.GeneratorStop;
188+
}
189+
184190
return fa;
185191
}
186192
}

Src/IronPython/Compiler/Ast/PythonAst.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ internal override Microsoft.Scripting.Ast.LightLambdaExpression GetLambda() {
317317

318318
#region Public API
319319

320+
internal bool GeneratorStop {
321+
get {
322+
return (_languageFeatures & ModuleOptions.GeneratorStop) != 0;
323+
}
324+
}
325+
320326
public Statement Body {
321327
get { return _body; }
322328
}

Src/IronPython/Compiler/Parser.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ private Expression ParseYieldExpression() {
583583
FunctionDefinition current = CurrentFunction;
584584
if (current != null) {
585585
current.IsGenerator = true;
586+
current.GeneratorStop = GeneratorStop;
586587
}
587588

588589
var start = GetStart();
@@ -889,6 +890,9 @@ private FromImportStatement ParseFromImportStmt() {
889890
// Ignored in Python 3
890891
} else if (name == "unicode_literals") {
891892
// Ignored in Python 3
893+
} else if (name == "generator_stop") {
894+
// New in 3.5, mandatory in 3.7
895+
_languageFeatures |= ModuleOptions.GeneratorStop;
892896
} else if (name == "nested_scopes") {
893897
} else if (name == "generators") {
894898
} else {
@@ -2500,6 +2504,7 @@ private Expression ParseGeneratorExpression(Expression expr) {
25002504
Parameter parameter = new Parameter("__gen_$_parm__", 0);
25012505
FunctionDefinition func = new FunctionDefinition(fname, new Parameter[] { parameter }, root);
25022506
func.IsGenerator = true;
2507+
func.GeneratorStop = GeneratorStop;
25032508
func.SetLoc(_globalParent, root.StartIndex, GetEnd());
25042509
func.HeaderIndex = root.EndIndex;
25052510

@@ -3159,6 +3164,8 @@ private Token EatEndOfInput() {
31593164
return PythonOps.BadSourceEncodingError(message, lineNum, _sourceUnit.Path);
31603165
}
31613166

3167+
private bool GeneratorStop => (_languageFeatures & ModuleOptions.GeneratorStop) == ModuleOptions.GeneratorStop;
3168+
31623169
private void StartParsing() {
31633170
if (_parsingStarted)
31643171
throw new InvalidOperationException("Parsing already started. Use Restart to start again.");

Src/IronPython/Compiler/PythonCompilerOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ public int[] InitialIndent {
5555
}
5656
}
5757

58+
internal bool GeneratorStop {
59+
get {
60+
return (_module & ModuleOptions.GeneratorStop) != 0;
61+
}
62+
set {
63+
if (value) _module |= ModuleOptions.GeneratorStop;
64+
else _module &= ~ModuleOptions.GeneratorStop;
65+
}
66+
}
67+
5868
public bool Verbatim {
5969
get {
6070
return (_module & ModuleOptions.Verbatim) != 0;

Src/IronPython/Modules/Builtin.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,9 @@ internal static PythonCompilerOptions GetRuntimeGeneratedCodeCompilerOptions(Cod
16421642
if ((cflags & CompileFlags.CO_FUTURE_UNICODE_LITERALS) != 0) {
16431643
// Ignored since Python 3
16441644
}
1645+
if ((cflags & CompileFlags.CO_FUTURE_GENERATOR_STOP) != 0) {
1646+
langFeat |= ModuleOptions.GeneratorStop;
1647+
}
16451648
pco.Module |= langFeat;
16461649

16471650
// The options created this way never creates
@@ -1662,7 +1665,7 @@ private static CompileFlags GetCompilerFlags(int flags) {
16621665
CompileFlags cflags = (CompileFlags)flags;
16631666
if ((cflags & ~(CompileFlags.CO_NESTED | CompileFlags.CO_GENERATOR_ALLOWED | CompileFlags.CO_FUTURE_DIVISION | CompileFlags.CO_DONT_IMPLY_DEDENT |
16641667
CompileFlags.CO_FUTURE_ABSOLUTE_IMPORT | CompileFlags.CO_FUTURE_WITH_STATEMENT | CompileFlags.CO_FUTURE_PRINT_FUNCTION |
1665-
CompileFlags.CO_FUTURE_UNICODE_LITERALS | CompileFlags.CO_FUTURE_BARRY_AS_BDFL)) != 0) {
1668+
CompileFlags.CO_FUTURE_UNICODE_LITERALS | CompileFlags.CO_FUTURE_BARRY_AS_BDFL | CompileFlags.CO_FUTURE_GENERATOR_STOP)) != 0) {
16661669
throw PythonOps.ValueError("unrecognized flags");
16671670
}
16681671

Src/IronPython/Runtime/CompileFlags.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
namespace IronPython.Runtime {
88
[Flags]
99
public enum CompileFlags {
10-
CO_NESTED = 0x0010, // nested_scopes
11-
CO_DONT_IMPLY_DEDENT = 0x0200, // report errors if statement isn't dedented.
12-
CO_GENERATOR_ALLOWED = 0x1000, // generators
13-
CO_FUTURE_DIVISION = 0x2000, // division
14-
CO_FUTURE_ABSOLUTE_IMPORT = 0x4000, // absolute imports by default
10+
CO_NESTED = 0x0010, // nested_scopes
11+
CO_DONT_IMPLY_DEDENT = 0x0200, // report errors if statement isn't dedented
12+
CO_GENERATOR_ALLOWED = 0x1000, // generators
13+
CO_FUTURE_DIVISION = 0x2000, // division
14+
CO_FUTURE_ABSOLUTE_IMPORT = 0x4000, // perform absolute imports by default
1515
CO_FUTURE_WITH_STATEMENT = 0x8000, // with statement
1616
CO_FUTURE_PRINT_FUNCTION = 0x10000, // print function
1717
CO_FUTURE_UNICODE_LITERALS = 0x20000, // default unicode literals
18-
CO_FUTURE_BARRY_AS_BDFL = 0x40000, //
18+
CO_FUTURE_BARRY_AS_BDFL = 0x40000, //
19+
CO_FUTURE_GENERATOR_STOP = 0x80000, // StopIteration becomes RuntimeError in generators
1920
}
2021
}

Src/IronPython/Runtime/FunctionAttributes.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ public enum FunctionAttributes {
2929
/// IronPython specific: Set if the function includes a try/finally block.
3030
/// </summary>
3131
ContainsTryFinally = 0x8000,
32+
GeneratorStop = 0x80000, // TODO: delete me in 3.7
3233
}
3334
}

Src/IronPython/Runtime/Generator.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ private object NextWorker() {
427427
FinalValue = CurrentValue;
428428
CurrentValue = OperationFailed.Value;
429429
}
430+
} catch (StopIterationException e) {
431+
if (GeneratorStop) {
432+
var stopIterationError = e.GetPythonException();
433+
throw PythonExceptions.CreatePythonThrowable(PythonExceptions.RuntimeError, "generator raised StopIteration")
434+
.CreateClrExceptionWithCause(stopIterationError, stopIterationError, true);
435+
} else {
436+
throw;
437+
}
430438
} finally {
431439
// A generator restores the sys.exc_info() status after each yield point.
432440
PythonOps.CurrentExceptionState = _state.PrevException;
@@ -561,6 +569,8 @@ internal bool ContainsTryFinally {
561569
}
562570
}
563571

572+
private bool GeneratorStop => (_function.Flags & FunctionAttributes.GeneratorStop) != 0;
573+
564574
#endregion
565575

566576
#region ICodeFormattable Members

Src/IronPython/Runtime/ModuleOptions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public enum ModuleOptions {
5353
/// <summary>
5454
/// Generated code should support light exceptions
5555
/// </summary>
56-
LightThrow = 0x8000
56+
LightThrow = 0x8000,
57+
GeneratorStop = 0x10000,
5758
}
5859
}

Src/StdLib/Lib/__future__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"print_function",
5757
"unicode_literals",
5858
"barry_as_FLUFL",
59+
"generator_stop",
5960
]
6061

6162
__all__ = ["all_feature_names"] + all_feature_names
@@ -72,6 +73,7 @@
7273
CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function
7374
CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals
7475
CO_FUTURE_BARRY_AS_BDFL = 0x40000
76+
CO_FUTURE_GENERATOR_STOP = 0x80000 # StopIteration becomes RuntimeError in generators
7577

7678
class _Feature:
7779
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -132,3 +134,7 @@ def __repr__(self):
132134
barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2),
133135
(3, 9, 0, "alpha", 0),
134136
CO_FUTURE_BARRY_AS_BDFL)
137+
138+
generator_stop = _Feature((3, 5, 0, "beta", 1),
139+
(3, 7, 0, "alpha", 0),
140+
CO_FUTURE_GENERATOR_STOP)

0 commit comments

Comments
 (0)