2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 using System
.Collections
;
32 using System
.Collections
.Generic
;
33 using Boo
.Lang
.Compiler
.Ast
;
34 using Boo
.Lang
.Compiler
.TypeSystem
;
36 namespace Boo
.Lang
.Compiler
.Steps
40 private int _loopDepth
;
42 private int _protectedBlockDepth
;
43 private int _exceptionHandlerDepth
;
45 private Stack
<TryStatement
> _tryBlocks
= new Stack
<TryStatement
>();
47 private List _labelReferences
= new List();
49 private Hashtable _labels
= new Hashtable();
54 _exceptionHandlerDepth
= 0;
56 _labelReferences
.Clear();
60 public void AddLabelReference(ReferenceExpression node
)
62 _labelReferences
.Add(node
);
65 public List LabelReferences
67 get { return _labelReferences; }
70 public void EnterTryBlock(TryStatement tryBlock
)
72 _tryBlocks
.Push(tryBlock
);
75 public void LeaveTryBlock()
80 public void EnterProtectedBlock()
82 ++_protectedBlockDepth
;
85 public void LeaveProtectedBlock()
87 --_protectedBlockDepth
;
90 public int TryBlockDepth
{
91 get { return _tryBlocks.Count; }
94 public IEnumerable
<TryStatement
> TryBlocks
{
95 get { return _tryBlocks; }
98 public int ProtectedBlockDepth
{
99 get { return _protectedBlockDepth; }
102 public void EnterExceptionHandler()
104 ++_exceptionHandlerDepth
;
107 public bool InExceptionHandler
109 get { return _exceptionHandlerDepth > 0; }
112 public void LeaveExceptionHandler()
114 --_exceptionHandlerDepth
;
117 public void EnterLoop()
124 get { return _loopDepth > 0; }
127 public void LeaveLoop()
132 public InternalLabel
ResolveLabel(string name
)
134 return (InternalLabel
)_labels
[name
];
137 public void AddLabel(InternalLabel label
)
139 _labels
.Add(label
.Name
, label
);
143 public class BranchChecking
: AbstractVisitorCompilerStep
145 private InternalMethod _currentMethod
;
147 private MethodBodyState _state
= new MethodBodyState();
149 public override void Run()
154 override public void OnTryStatement(TryStatement node
)
156 _state
.EnterTryBlock(node
);
157 _state
.EnterProtectedBlock();
158 Visit(node
.ProtectedBlock
);
159 _state
.LeaveProtectedBlock();
161 Visit(node
.ExceptionHandlers
);
163 Visit(node
.FailureBlock
);
165 Visit(node
.EnsureBlock
);
166 _state
.LeaveTryBlock();
169 override public void OnExceptionHandler(ExceptionHandler node
)
171 _state
.EnterExceptionHandler();
173 _state
.LeaveExceptionHandler();
176 override public void LeaveRaiseStatement(RaiseStatement node
)
178 if (node
.Exception
!= null) return;
179 if (_state
.InExceptionHandler
) return;
180 Error(CompilerErrorFactory
.ReRaiseOutsideExceptionHandler(node
));
183 public override void OnConstructor(Constructor node
)
188 public override void OnDestructor(Destructor node
)
193 override public void OnMethod(Method node
)
195 _currentMethod
= (InternalMethod
) node
.Entity
;
198 ResolveLabelReferences();
201 void ResolveLabelReferences()
203 foreach (ReferenceExpression reference
in _state
.LabelReferences
)
205 InternalLabel label
= _state
.ResolveLabel(reference
.Name
);
208 Error(reference
, CompilerErrorFactory
.NoSuchLabel(reference
, reference
.Name
));
212 reference
.Entity
= label
;
217 override public void OnWhileStatement(WhileStatement node
)
219 VisitLoop(node
.Block
);
222 private void VisitLoop(Block block
)
229 override public void OnForStatement(ForStatement node
)
231 VisitLoop(node
.Block
);
234 override public void OnLabelStatement(LabelStatement node
)
236 AstAnnotations
.SetTryBlockDepth(node
, _state
.TryBlockDepth
);
238 if (null == _state
.ResolveLabel(node
.Name
))
240 _state
.AddLabel(new InternalLabel(node
));
245 CompilerErrorFactory
.LabelAlreadyDefined(node
,
246 _currentMethod
.FullName
,
251 override public void OnYieldStatement(YieldStatement node
)
253 if (_state
.TryBlockDepth
== _state
.ProtectedBlockDepth
) {
254 // we are currently only in the protected blocks, not in any "except" or "ensure" blocks.
255 foreach (TryStatement tryBlock
in _state
.TryBlocks
) {
256 // only allow yield in the try part of try-ensure blocks, fail if it is a try-except block
257 if (tryBlock
.FailureBlock
!= null || tryBlock
.ExceptionHandlers
.Count
> 0) {
258 Error(CompilerErrorFactory
.YieldInsideTryExceptOrEnsureBlock(node
));
263 Error(CompilerErrorFactory
.YieldInsideTryExceptOrEnsureBlock(node
));
267 public override void OnMethodInvocationExpression(MethodInvocationExpression node
)
269 if (BuiltinFunction
.Switch
!= node
.Target
.Entity
) return;
271 for (int i
= 1; i
< node
.Arguments
.Count
; ++i
)
273 ReferenceExpression label
= (ReferenceExpression
)node
.Arguments
[i
];
274 _state
.AddLabelReference(label
);
278 override public void OnGotoStatement(GotoStatement node
)
280 AstAnnotations
.SetTryBlockDepth(node
, _state
.TryBlockDepth
);
282 _state
.AddLabelReference(node
.Label
);
285 override public void OnBreakStatement(BreakStatement node
)
290 override public void OnContinueStatement(ContinueStatement node
)
295 override public void OnBlockExpression(BlockExpression node
)
300 private void CheckInLoop(Statement node
)
304 Error(CompilerErrorFactory
.NoEnclosingLoop(node
));