Ordering of BoundBlock
- BoundBlock.Ordinal - Scope end
This commit is contained in:
Родитель
54b8d976e2
Коммит
1555bc73e7
|
@ -42,6 +42,28 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
internal set { _next = value; }
|
internal set { _next = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Topological order & scoping
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets block topological index.
|
||||||
|
/// Index is unique within the graph.
|
||||||
|
/// </summary>
|
||||||
|
public int Ordinal { get { return _ordinal; } internal set { _ordinal = value; } }
|
||||||
|
private int _ordinal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index of nearest block after the scope.
|
||||||
|
/// </summary>
|
||||||
|
public int ScopeTo { get { return _scopeTo; } internal set { _scopeTo = value; } }
|
||||||
|
private int _scopeTo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets value indicating <see cref="ScopeTo"/> is valid.
|
||||||
|
/// </summary>
|
||||||
|
public bool ScopeToValid => _scopeTo >= _ordinal;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
internal BoundBlock()
|
internal BoundBlock()
|
||||||
{
|
{
|
||||||
_statements = new List<BoundStatement>();
|
_statements = new List<BoundStatement>();
|
||||||
|
@ -150,7 +172,6 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
private readonly VariableName _variableName;
|
private readonly VariableName _variableName;
|
||||||
|
|
||||||
public CatchBlock(CatchItem item)
|
public CatchBlock(CatchItem item)
|
||||||
: base()
|
|
||||||
{
|
{
|
||||||
_typeRef = item.TypeRef;
|
_typeRef = item.TypeRef;
|
||||||
_variableName = item.Variable.VarName;
|
_variableName = item.Variable.VarName;
|
||||||
|
@ -177,7 +198,6 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
public bool IsDefault => _caseValue == null;
|
public bool IsDefault => _caseValue == null;
|
||||||
|
|
||||||
public CaseBlock(BoundExpression caseValue)
|
public CaseBlock(BoundExpression caseValue)
|
||||||
: base()
|
|
||||||
{
|
{
|
||||||
_caseValue = caseValue;
|
_caseValue = caseValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
private Dictionary<string, ControlFlowGraph.LabelBlockState> _labels;
|
private Dictionary<string, ControlFlowGraph.LabelBlockState> _labels;
|
||||||
private List<BreakTargetScope> _breakTargets;
|
private List<BreakTargetScope> _breakTargets;
|
||||||
private Stack<TryCatchEdge> _tryTargets;
|
private Stack<TryCatchEdge> _tryTargets;
|
||||||
|
private Stack<LocalScopeInfo> _scopes = new Stack<LocalScopeInfo>(1);
|
||||||
|
private int _index = 0;
|
||||||
|
|
||||||
public BoundBlock/*!*/Start { get; private set; }
|
public BoundBlock/*!*/Start { get; private set; }
|
||||||
public BoundBlock/*!*/Exit { get; private set; }
|
public BoundBlock/*!*/Exit { get; private set; }
|
||||||
|
@ -39,6 +41,34 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
public List<BoundBlock>/*!*/DeadBlocks { get { return _deadBlocks; } }
|
public List<BoundBlock>/*!*/DeadBlocks { get { return _deadBlocks; } }
|
||||||
private readonly List<BoundBlock>/*!*/_deadBlocks = new List<BoundBlock>();
|
private readonly List<BoundBlock>/*!*/_deadBlocks = new List<BoundBlock>();
|
||||||
|
|
||||||
|
#region LocalScope
|
||||||
|
|
||||||
|
private class LocalScopeInfo
|
||||||
|
{
|
||||||
|
public BoundBlock FirstBlock => _firstblock;
|
||||||
|
private BoundBlock _firstblock;
|
||||||
|
|
||||||
|
public LocalScopeInfo(BoundBlock firstBlock)
|
||||||
|
{
|
||||||
|
_firstblock = firstBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenScope(BoundBlock block)
|
||||||
|
{
|
||||||
|
_scopes.Push(new LocalScopeInfo(block));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseScope()
|
||||||
|
{
|
||||||
|
if (_scopes.Count == 0)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
_scopes.Pop().FirstBlock.ScopeTo = _index;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region BreakTargetScope
|
#region BreakTargetScope
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -56,22 +86,22 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BreakTargetScope GetBreakTarget(int level)
|
private BreakTargetScope GetBreakScope(int level)
|
||||||
{
|
{
|
||||||
if (level < 1) level = 1;
|
if (level < 1) level = 1; // PHP behavior
|
||||||
if (_breakTargets == null || _breakTargets.Count < level)
|
if (_breakTargets == null || _breakTargets.Count < level)
|
||||||
return default(BreakTargetScope);
|
return default(BreakTargetScope);
|
||||||
|
|
||||||
return _breakTargets[_breakTargets.Count - level];
|
return _breakTargets[_breakTargets.Count - level];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnterBreakTarget(BoundBlock breakBlock, BoundBlock continueBlock)
|
private void OpenBreakScope(BoundBlock breakBlock, BoundBlock continueBlock)
|
||||||
{
|
{
|
||||||
if (_breakTargets == null) _breakTargets = new List<BreakTargetScope>(1);
|
if (_breakTargets == null) _breakTargets = new List<BreakTargetScope>(1);
|
||||||
_breakTargets.Add(new BreakTargetScope(breakBlock, continueBlock));
|
_breakTargets.Add(new BreakTargetScope(breakBlock, continueBlock));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExitBreakTarget()
|
private void CloseBreakScope()
|
||||||
{
|
{
|
||||||
Debug.Assert(_breakTargets != null && _breakTargets.Count != 0);
|
Debug.Assert(_breakTargets != null && _breakTargets.Count != 0);
|
||||||
_breakTargets.RemoveAt(_breakTargets.Count - 1);
|
_breakTargets.RemoveAt(_breakTargets.Count - 1);
|
||||||
|
@ -81,21 +111,23 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
|
|
||||||
#region TryTargetScope
|
#region TryTargetScope
|
||||||
|
|
||||||
private TryCatchEdge GetTryTarget()
|
private TryCatchEdge CurrentTryScope
|
||||||
{
|
{
|
||||||
if (_tryTargets == null || _tryTargets.Count == 0)
|
get
|
||||||
return null;
|
{
|
||||||
|
return (_tryTargets != null && _tryTargets.Count != 0)
|
||||||
return _tryTargets.Peek();
|
? _tryTargets.Peek()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnterTryTarget(TryCatchEdge edge)
|
private void OpenTryScope(TryCatchEdge edge)
|
||||||
{
|
{
|
||||||
if (_tryTargets == null) _tryTargets = new Stack<TryCatchEdge>();
|
if (_tryTargets == null) _tryTargets = new Stack<TryCatchEdge>();
|
||||||
_tryTargets.Push(edge);
|
_tryTargets.Push(edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExitTryTarget()
|
private void CloeTryScope()
|
||||||
{
|
{
|
||||||
Debug.Assert(_tryTargets != null && _tryTargets.Count != 0);
|
Debug.Assert(_tryTargets != null && _tryTargets.Count != 0);
|
||||||
_tryTargets.Pop();
|
_tryTargets.Pop();
|
||||||
|
@ -115,10 +147,14 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
this.Start = new StartBlock();
|
this.Start = new StartBlock();
|
||||||
this.Exit = new ExitBlock();
|
this.Exit = new ExitBlock();
|
||||||
|
|
||||||
_current = this.Start;
|
_current = WithOpenScope(this.Start);
|
||||||
|
|
||||||
statements.ForEach(this.VisitElement);
|
statements.ForEach(this.VisitElement);
|
||||||
_current = Connect(_current, this.Exit);
|
_current = Connect(_current, this.Exit);
|
||||||
|
|
||||||
|
//
|
||||||
|
WithNewOrdinal(this.Exit);
|
||||||
|
CloseScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BuilderVisitor/*!*/Build(IList<Statement>/*!*/statements, SemanticsBinder/*!*/binder)
|
public static BuilderVisitor/*!*/Build(IList<Statement>/*!*/statements, SemanticsBinder/*!*/binder)
|
||||||
|
@ -144,7 +180,7 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
|
|
||||||
private BoundBlock/*!*/NewBlock()
|
private BoundBlock/*!*/NewBlock()
|
||||||
{
|
{
|
||||||
return new BoundBlock();
|
return WithNewOrdinal(new BoundBlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -153,14 +189,14 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private BoundBlock/*!*/NewDeadBlock()
|
private BoundBlock/*!*/NewDeadBlock()
|
||||||
{
|
{
|
||||||
var block = NewBlock();
|
var block = new BoundBlock();
|
||||||
_deadBlocks.Add(block);
|
_deadBlocks.Add(block);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CatchBlock/*!*/NewBlock(CatchItem item)
|
private CatchBlock/*!*/NewBlock(CatchItem item)
|
||||||
{
|
{
|
||||||
return new CatchBlock(item);
|
return WithNewOrdinal(new CatchBlock(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CaseBlock/*!*/NewBlock(SwitchItem item)
|
private CaseBlock/*!*/NewBlock(SwitchItem item)
|
||||||
|
@ -168,7 +204,7 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
var caseitem = item as CaseItem;
|
var caseitem = item as CaseItem;
|
||||||
BoundExpression caseValue = // null => DefaultItem
|
BoundExpression caseValue = // null => DefaultItem
|
||||||
(caseitem != null) ? _binder.BindExpression(caseitem.CaseVal) : null;
|
(caseitem != null) ? _binder.BindExpression(caseitem.CaseVal) : null;
|
||||||
return new CaseBlock(caseValue);
|
return WithNewOrdinal(new CaseBlock(caseValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundBlock/*!*/Connect(BoundBlock/*!*/source, BoundBlock/*!*/ifTarget, BoundBlock/*!*/elseTarget, Expression/*!*/condition)
|
private BoundBlock/*!*/Connect(BoundBlock/*!*/source, BoundBlock/*!*/ifTarget, BoundBlock/*!*/elseTarget, Expression/*!*/condition)
|
||||||
|
@ -203,6 +239,23 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets new block index.
|
||||||
|
/// </summary>
|
||||||
|
private int NewOrdinal() => _index++;
|
||||||
|
|
||||||
|
private T WithNewOrdinal<T>(T block) where T : BoundBlock
|
||||||
|
{
|
||||||
|
block.Ordinal = NewOrdinal();
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T WithOpenScope<T>(T block) where T : BoundBlock
|
||||||
|
{
|
||||||
|
OpenScope(block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Declaration Statements
|
#region Declaration Statements
|
||||||
|
@ -327,7 +380,7 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
var enumereeEdge = new ForeachEnumereeEdge(_current, move, _binder.BindExpression(x.Enumeree));
|
var enumereeEdge = new ForeachEnumereeEdge(_current, move, _binder.BindExpression(x.Enumeree));
|
||||||
|
|
||||||
// ContinueTarget:
|
// ContinueTarget:
|
||||||
EnterBreakTarget(end, move);
|
OpenBreakScope(end, move);
|
||||||
|
|
||||||
// ForeachMoveNextEdge : ConditionalEdge
|
// ForeachMoveNextEdge : ConditionalEdge
|
||||||
var moveEdge = new ForeachMoveNextEdge(move, body, end, enumereeEdge, x.KeyVariable, x.ValueVariable);
|
var moveEdge = new ForeachMoveNextEdge(move, body, end, enumereeEdge, x.KeyVariable, x.ValueVariable);
|
||||||
|
@ -337,16 +390,17 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
|
|
||||||
// Block
|
// Block
|
||||||
// { x.Body }
|
// { x.Body }
|
||||||
_current = body;
|
_current = WithOpenScope(WithNewOrdinal(body));
|
||||||
VisitElement(x.Body);
|
VisitElement(x.Body);
|
||||||
|
CloseScope();
|
||||||
// goto ContinueTarget;
|
// goto ContinueTarget;
|
||||||
Connect(_current, move);
|
Connect(_current, move);
|
||||||
|
|
||||||
// BreakTarget:
|
// BreakTarget:
|
||||||
ExitBreakTarget();
|
CloseBreakScope();
|
||||||
|
|
||||||
//
|
//
|
||||||
_current = end;
|
_current = WithNewOrdinal(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildForLoop(List<Expression> initExpr, List<Expression> condExpr, List<Expression> actionExpr, Statement/*!*/bodyStmt)
|
private void BuildForLoop(List<Expression> initExpr, List<Expression> condExpr, List<Expression> actionExpr, Statement/*!*/bodyStmt)
|
||||||
|
@ -363,37 +417,42 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
var body = NewBlock();
|
var body = NewBlock();
|
||||||
var cond = hasConditions ? NewBlock() : body;
|
var cond = hasConditions ? NewBlock() : body;
|
||||||
var action = hasActions ? NewBlock() : cond;
|
var action = hasActions ? NewBlock() : cond;
|
||||||
EnterBreakTarget(end, action);
|
OpenBreakScope(end, action);
|
||||||
|
|
||||||
// while (x.Codition) {
|
// while (x.Codition) {
|
||||||
_current = Connect(_current, cond);
|
_current = WithNewOrdinal(Connect(_current, cond));
|
||||||
if (hasConditions)
|
if (hasConditions)
|
||||||
{
|
{
|
||||||
if (condExpr.Count > 1)
|
if (condExpr.Count > 1)
|
||||||
condExpr.Take(condExpr.Count - 1).ForEach(expr => this.Add(new ExpressionStmt(expr.Span, expr)));
|
condExpr.Take(condExpr.Count - 1).ForEach(expr => this.Add(new ExpressionStmt(expr.Span, expr)));
|
||||||
_current = Connect(_current, body, end, condExpr.LastOrDefault());
|
_current = WithNewOrdinal(Connect(_current, body, end, condExpr.LastOrDefault()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_deadBlocks.Add(end);
|
_deadBlocks.Add(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenScope(_current);
|
||||||
|
|
||||||
// { x.Body }
|
// { x.Body }
|
||||||
VisitElement(bodyStmt);
|
VisitElement(bodyStmt);
|
||||||
// { x.Action }
|
// { x.Action }
|
||||||
if (hasActions)
|
if (hasActions)
|
||||||
{
|
{
|
||||||
_current = Connect(_current, action);
|
_current = WithNewOrdinal(Connect(_current, action));
|
||||||
actionExpr.ForEach(expr => this.Add(new ExpressionStmt(expr.Span, expr)));
|
actionExpr.ForEach(expr => this.Add(new ExpressionStmt(expr.Span, expr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CloseScope();
|
||||||
|
|
||||||
// }
|
// }
|
||||||
Connect(_current, cond);
|
Connect(_current, cond);
|
||||||
|
|
||||||
//
|
//
|
||||||
ExitBreakTarget();
|
CloseBreakScope();
|
||||||
|
|
||||||
//
|
//
|
||||||
_current = end;
|
_current = WithNewOrdinal(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitForStmt(ForStmt x)
|
public override void VisitForStmt(ForStmt x)
|
||||||
|
@ -427,7 +486,7 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
? ((IntLiteral)x.Expression).Value
|
? ((IntLiteral)x.Expression).Value
|
||||||
: 1;
|
: 1;
|
||||||
|
|
||||||
var brk = GetBreakTarget(level);
|
var brk = GetBreakScope(level);
|
||||||
var target = (x.Type == JumpStmt.Types.Break) ? brk.BreakTarget : brk.ContinueTarget;
|
var target = (x.Type == JumpStmt.Types.Break) ? brk.BreakTarget : brk.ContinueTarget;
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
|
@ -466,26 +525,34 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
Debug.Assert(i != 0 && elseBlock != null);
|
Debug.Assert(i != 0 && elseBlock != null);
|
||||||
var body = elseBlock;
|
var body = elseBlock;
|
||||||
elseBlock = end; // last ConditionalStmt
|
elseBlock = end; // last ConditionalStmt
|
||||||
_current = Connect(_current, body);
|
_current = WithNewOrdinal(Connect(_current, body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenScope(_current);
|
||||||
VisitElement(cond.Statement);
|
VisitElement(cond.Statement);
|
||||||
|
CloseScope();
|
||||||
|
|
||||||
Connect(_current, end);
|
Connect(_current, end);
|
||||||
_current = elseBlock;
|
_current = WithNewOrdinal(elseBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(_current == end);
|
Debug.Assert(_current == end);
|
||||||
|
_current.Ordinal = NewOrdinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitLabelStmt(LabelStmt x)
|
public override void VisitLabelStmt(LabelStmt x)
|
||||||
{
|
{
|
||||||
var/*!*/label = GetLabelBlock(x.Name.Value);
|
var/*!*/label = GetLabelBlock(x.Name.Value);
|
||||||
if ((label.Flags & ControlFlowGraph.LabelBlockFlags.Defined) != 0)
|
if ((label.Flags & ControlFlowGraph.LabelBlockFlags.Defined) != 0)
|
||||||
|
{
|
||||||
label.Flags |= ControlFlowGraph.LabelBlockFlags.Redefined; // label was defined already
|
label.Flags |= ControlFlowGraph.LabelBlockFlags.Redefined; // label was defined already
|
||||||
|
return; // ignore label redefinition
|
||||||
|
}
|
||||||
|
|
||||||
label.Flags |= ControlFlowGraph.LabelBlockFlags.Defined; // label is defined
|
label.Flags |= ControlFlowGraph.LabelBlockFlags.Defined; // label is defined
|
||||||
label.LabelSpan = x.Span;
|
label.LabelSpan = x.Span;
|
||||||
|
|
||||||
_current = Connect(_current, label.TargetBlock);
|
_current = WithNewOrdinal(Connect(_current, label.TargetBlock));
|
||||||
|
|
||||||
Add(x);
|
Add(x);
|
||||||
}
|
}
|
||||||
|
@ -513,19 +580,23 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
|
|
||||||
// SwitchEdge // Connects _current to cases
|
// SwitchEdge // Connects _current to cases
|
||||||
var edge = new SwitchEdge(_current, _binder.BindExpression(x.SwitchValue), cases.ToArray());
|
var edge = new SwitchEdge(_current, _binder.BindExpression(x.SwitchValue), cases.ToArray());
|
||||||
_current = cases[0];
|
_current = WithNewOrdinal(cases[0]);
|
||||||
|
|
||||||
EnterBreakTarget(end, end); // NOTE: inside switch, Continue ~ Break
|
OpenBreakScope(end, end); // NOTE: inside switch, Continue ~ Break
|
||||||
|
|
||||||
for (int i = 0; i < cases.Count; i++)
|
for (int i = 0; i < cases.Count; i++)
|
||||||
{
|
{
|
||||||
|
OpenScope(_current);
|
||||||
|
|
||||||
if (i < items.Length)
|
if (i < items.Length)
|
||||||
items[i].Statements.ForEach(VisitElement); // any break will connect block to end
|
items[i].Statements.ForEach(VisitElement); // any break will connect block to end
|
||||||
|
|
||||||
_current = Connect(_current, (i == cases.Count - 1) ? end : cases[i + 1]);
|
CloseScope();
|
||||||
|
|
||||||
|
_current = WithNewOrdinal(Connect(_current, (i == cases.Count - 1) ? end : cases[i + 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitBreakTarget();
|
CloseBreakScope();
|
||||||
|
|
||||||
Debug.Assert(_current == end);
|
Debug.Assert(_current == end);
|
||||||
}
|
}
|
||||||
|
@ -588,29 +659,34 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
var edge = new TryCatchEdge(_current, body, catchBlocks, finallyBlock);
|
var edge = new TryCatchEdge(_current, body, catchBlocks, finallyBlock);
|
||||||
|
|
||||||
// build try body
|
// build try body
|
||||||
EnterTryTarget(edge);
|
OpenTryScope(edge);
|
||||||
_current = body;
|
OpenScope(body);
|
||||||
|
_current = WithNewOrdinal(body);
|
||||||
x.Statements.ForEach(VisitElement);
|
x.Statements.ForEach(VisitElement);
|
||||||
ExitTryTarget();
|
CloseScope();
|
||||||
|
CloeTryScope();
|
||||||
_current = Connect(_current, finallyBlock ?? end);
|
_current = Connect(_current, finallyBlock ?? end);
|
||||||
|
|
||||||
// built catches
|
// built catches
|
||||||
for (int i = 0; i < catchBlocks.Length; i++)
|
for (int i = 0; i < catchBlocks.Length; i++)
|
||||||
{
|
{
|
||||||
_current = catchBlocks[i];
|
_current = WithOpenScope(WithNewOrdinal(catchBlocks[i]));
|
||||||
x.Catches[i].Statements.ForEach(VisitElement);
|
x.Catches[i].Statements.ForEach(VisitElement);
|
||||||
|
CloseScope();
|
||||||
_current = Connect(_current, finallyBlock ?? end);
|
_current = Connect(_current, finallyBlock ?? end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build finally
|
// build finally
|
||||||
if (finallyBlock != null)
|
if (finallyBlock != null)
|
||||||
{
|
{
|
||||||
_current = finallyBlock;
|
_current = WithOpenScope(WithNewOrdinal(finallyBlock));
|
||||||
x.FinallyItem.Statements.ForEach(VisitElement);
|
x.FinallyItem.Statements.ForEach(VisitElement);
|
||||||
|
CloseScope();
|
||||||
_current = Connect(_current, end);
|
_current = Connect(_current, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// _current == end
|
// _current == end
|
||||||
|
_current.Ordinal = NewOrdinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitWhileStmt(WhileStmt x)
|
public override void VisitWhileStmt(WhileStmt x)
|
||||||
|
@ -619,14 +695,16 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
{
|
{
|
||||||
var end = NewBlock();
|
var end = NewBlock();
|
||||||
var body = NewBlock();
|
var body = NewBlock();
|
||||||
EnterBreakTarget(end, body);
|
OpenBreakScope(end, body);
|
||||||
_current = Connect(_current, body);
|
_current = WithOpenScope(Connect(_current, body));
|
||||||
// do {
|
// do {
|
||||||
VisitElement(x.Body);
|
VisitElement(x.Body);
|
||||||
Connect(_current, body, end, x.CondExpr);
|
Connect(_current, body, end, x.CondExpr);
|
||||||
// } while (x.CondExpr)
|
// } while (x.CondExpr)
|
||||||
ExitBreakTarget();
|
CloseScope();
|
||||||
_current = end;
|
CloseBreakScope();
|
||||||
|
|
||||||
|
_current = WithNewOrdinal(end);
|
||||||
}
|
}
|
||||||
else if (x.LoopType == WhileStmt.Type.While)
|
else if (x.LoopType == WhileStmt.Type.While)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,7 @@ namespace Pchp.CodeAnalysis.Semantics.Graph
|
||||||
internal SimpleEdge(BoundBlock source, BoundBlock target)
|
internal SimpleEdge(BoundBlock source, BoundBlock target)
|
||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(source != target);
|
||||||
_target = target;
|
_target = target;
|
||||||
Connect(source);
|
Connect(source);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче