26
26
package com .oracle .graal .python .nodes .statement ;
27
27
28
28
import static com .oracle .graal .python .runtime .exception .PythonErrorType .TypeError ;
29
- import static com .oracle .graal .python .runtime .exception .PythonErrorType .ZeroDivisionError ;
30
29
31
30
import com .oracle .graal .python .builtins .objects .PNone ;
32
31
import com .oracle .graal .python .builtins .objects .function .PKeyword ;
33
- import com .oracle .graal .python .builtins .objects .function .PythonCallable ;
34
32
import com .oracle .graal .python .builtins .objects .object .PythonObject ;
35
33
import com .oracle .graal .python .nodes .PNode ;
36
34
import com .oracle .graal .python .nodes .argument .CreateArgumentsNode ;
37
35
import com .oracle .graal .python .nodes .attributes .GetAttributeNode ;
38
36
import com .oracle .graal .python .nodes .call .CallDispatchNode ;
37
+ import com .oracle .graal .python .nodes .datamodel .IsCallableNode ;
39
38
import com .oracle .graal .python .nodes .expression .CastToBooleanNode ;
40
39
import com .oracle .graal .python .nodes .frame .WriteNode ;
41
40
import com .oracle .graal .python .runtime .exception .PException ;
42
- import com .oracle .truffle .api .CompilerDirectives ;
41
+ import com .oracle .truffle .api .dsl . Cached ;
43
42
import com .oracle .truffle .api .dsl .NodeChild ;
44
43
import com .oracle .truffle .api .dsl .NodeChildren ;
45
44
import com .oracle .truffle .api .dsl .Specialization ;
46
45
import com .oracle .truffle .api .frame .VirtualFrame ;
47
- import com .oracle .truffle .api .nodes .UnexpectedResultException ;
48
46
49
47
@ NodeChildren ({@ NodeChild (value = "withContext" , type = PNode .class )})
50
48
public abstract class WithNode extends StatementNode {
@@ -55,7 +53,7 @@ public abstract class WithNode extends StatementNode {
55
53
@ Child private GetAttributeNode exitGetter ;
56
54
@ Child private CallDispatchNode enterDispatch ;
57
55
@ Child private CallDispatchNode exitDispatch ;
58
- @ Child private CastToBooleanNode exitResultIsTrueish ;
56
+ @ Child private CastToBooleanNode toBooleanNode ;
59
57
@ Child private CreateArgumentsNode createArgs ;
60
58
61
59
protected WithNode (PNode targetNode , PNode body ) {
@@ -65,7 +63,7 @@ protected WithNode(PNode targetNode, PNode body) {
65
63
this .exitGetter = GetAttributeNode .create ();
66
64
this .enterDispatch = CallDispatchNode .create ("__enter__" );
67
65
this .exitDispatch = CallDispatchNode .create ("__enter__" );
68
- this .exitResultIsTrueish = CastToBooleanNode .createIfTrueNode ();
66
+ this .toBooleanNode = CastToBooleanNode .createIfTrueNode ();
69
67
this .createArgs = CreateArgumentsNode .create ();
70
68
}
71
69
@@ -93,62 +91,53 @@ public PNode getTargetNode() {
93
91
}
94
92
95
93
@ Specialization
96
- protected Object runWith (VirtualFrame frame , PythonObject withObject ) {
94
+ protected Object runWith (VirtualFrame frame , PythonObject withObject ,
95
+ @ Cached ("create()" ) IsCallableNode isCallableNode ,
96
+ @ Cached ("create()" ) IsCallableNode isExitCallableNode ) {
97
+
97
98
boolean gotException = false ;
98
99
Object enterCallable = enterGetter .execute (withObject , "__enter__" );
99
100
Object exitCallable = exitGetter .execute (withObject , "__exit__" );
100
- try {
101
- applyValues ( frame , enterDispatch . executeCall ( PythonCallable . expect ( enterCallable ), createArgs . execute ( withObject ), new PKeyword [ 0 ]));
102
- } catch ( UnexpectedResultException e1 ) {
103
- CompilerDirectives . transferToInterpreter ();
104
- throw raise (TypeError , "%s is not callable" , e1 . getResult () );
101
+
102
+ if ( isCallableNode . execute ( enterCallable )) {
103
+ applyValues ( frame , enterDispatch . executeCall ( enterCallable , createArgs . execute ( withObject ), new PKeyword [ 0 ]));
104
+ } else {
105
+ throw raise (TypeError , "%p is not callable" , enterCallable );
105
106
}
107
+
106
108
try {
107
109
body .execute (frame );
108
- } catch (RuntimeException exception ) {
109
- CompilerDirectives .transferToInterpreter ();
110
+ } catch (PException exception ) {
110
111
gotException = true ;
111
- return handleException (withObject , exception );
112
+ return handleException (withObject , exception , isExitCallableNode );
112
113
} finally {
113
114
if (!gotException ) {
114
- try {
115
- return exitDispatch .executeCall (PythonCallable .expect (exitCallable ), createArgs .execute (withObject , PNone .NONE , PNone .NONE , PNone .NONE ),
116
- new PKeyword [0 ]);
117
- } catch (UnexpectedResultException e1 ) {
118
- CompilerDirectives .transferToInterpreter ();
119
- throw raise (TypeError , "%s is not callable" , e1 .getResult ());
115
+ if (isExitCallableNode .execute (exitCallable )) {
116
+ exitDispatch .executeCall (exitCallable , createArgs .execute (withObject , PNone .NONE , PNone .NONE , PNone .NONE ), new PKeyword [0 ]);
117
+ } else {
118
+ throw raise (TypeError , "%p is not callable" , exitCallable );
120
119
}
121
120
}
122
121
}
123
- assert false ;
124
- return null ;
122
+ return PNone .NONE ;
125
123
}
126
124
127
- private Object handleException (PythonObject withObject , RuntimeException e ) {
128
- RuntimeException exception = e ;
129
- PythonCallable exitCallable = null ;
130
- try {
131
- exitCallable = PythonCallable .expect (exitGetter .execute (withObject , "__exit__" ));
132
- } catch (UnexpectedResultException e1 ) {
133
- CompilerDirectives .transferToInterpreter ();
134
- throw raise (TypeError , "%s is not callable" , e1 .getResult ());
135
- }
136
- if (exception instanceof ArithmeticException && exception .getMessage ().endsWith ("divide by zero" )) {
137
- // TODO: no ArithmeticExceptions should propagate outside of operations
138
- exception = raise (ZeroDivisionError , "division by zero" );
125
+ private Object handleException (PythonObject withObject , PException e , IsCallableNode isExitCallableNode ) {
126
+ Object exitCallable = exitGetter .execute (withObject , "__exit__" );
127
+ if (!isExitCallableNode .execute (exitCallable )) {
128
+ throw raise (TypeError , "%p is not callable" , exitCallable );
139
129
}
140
- if (exception instanceof PException ) {
141
- PException pException = (PException ) exception ;
142
- pException .getExceptionObject ().reifyException ();
143
- Object type = pException .getType ();
144
- Object value = pException .getExceptionObject ();
145
- Object trace = pException .getExceptionObject ().getTraceback (factory ());
146
- Object returnValue = exitDispatch .executeCall (exitCallable , createArgs .execute (withObject , type , value , trace ), new PKeyword [0 ]);
147
- // Corner cases:
148
- if (exitResultIsTrueish .executeWith (returnValue )) {
149
- return returnValue ;
150
- }
130
+
131
+ e .getExceptionObject ().reifyException ();
132
+ Object type = e .getType ();
133
+ Object value = e .getExceptionObject ();
134
+ Object trace = e .getExceptionObject ().getTraceback (factory ());
135
+ Object returnValue = exitDispatch .executeCall (exitCallable , createArgs .execute (withObject , type , value , trace ), new PKeyword [0 ]);
136
+ // If exit handler returns 'true', suppress
137
+ if (toBooleanNode .executeWith (returnValue )) {
138
+ return PNone .NONE ;
151
139
}
152
- throw exception ;
140
+ // else re-raise exception
141
+ throw e ;
153
142
}
154
143
}
0 commit comments