Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix continue and goto #1282

Merged
merged 6 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,13 @@ private void ReverseStackItems(int count)

#region LabelsAndTargets

private JumpTarget AddLabel(ILabelSymbol symbol, bool checkTryStack)
private JumpTarget AddLabel(ILabelSymbol symbol)
{
if (!_labels.TryGetValue(symbol, out JumpTarget? target))
{
target = new JumpTarget();
_labels.Add(symbol, target);
}
if (checkTryStack && _tryStack.TryPeek(out ExceptionHandling? result) && result.State != ExceptionHandlingState.Finally)
{
result.Labels.Add(symbol);
}
return target;
}

Expand Down
11 changes: 11 additions & 0 deletions src/Neo.Compiler.CSharp/MethodConvert/Statement/BlockStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ internal partial class MethodConvert
/// </example>
private void ConvertBlockStatement(SemanticModel model, BlockSyntax syntax)
{
StatementContext sc = new(syntax);
_generalStatementStack.Push(sc);
foreach (StatementSyntax label in syntax.Statements)
if (label is LabeledStatementSyntax l)
{
ILabelSymbol symbol = (ILabelSymbol)model.GetDeclaredSymbol(l)!;
JumpTarget target = AddLabel(symbol);
sc.AddLabel(symbol, target);
}
_blockSymbols.Push(new List<ILocalSymbol>());
using (InsertSequencePoint(syntax.OpenBraceToken))
AddInstruction(OpCode.NOP);
Expand All @@ -53,6 +62,8 @@ private void ConvertBlockStatement(SemanticModel model, BlockSyntax syntax)
AddInstruction(OpCode.NOP);
foreach (ILocalSymbol symbol in _blockSymbols.Pop())
RemoveLocalVariable(symbol);
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}
}
}
38 changes: 34 additions & 4 deletions src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Neo.VM;
using System.Collections.Generic;
using System.Linq;

namespace Neo.Compiler
{
Expand Down Expand Up @@ -44,10 +46,38 @@ internal partial class MethodConvert
private void ConvertBreakStatement(BreakStatementSyntax syntax)
{
using (InsertSequencePoint(syntax))
if (_tryStack.TryPeek(out ExceptionHandling? result) && result.BreakTargetCount == 0)
Jump(OpCode.ENDTRY_L, _breakTargets.Peek());
else
Jump(OpCode.JMP_L, _breakTargets.Peek());
{
JumpTarget? breakTarget = null;
List<StatementContext> visitedTry = []; // from shallow to deep
foreach (StatementContext sc in _generalStatementStack)
{// start from the deepest context
// find the final break target
if (sc.BreakTarget != null)
{
breakTarget = sc.BreakTarget;
break;
}
// stage the try stacks on the way
if (sc.StatementSyntax is TryStatementSyntax)
visitedTry.Add(sc);
}
if (breakTarget == null)
// break is not handled
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Cannot find what to break. " +
$"If not syntax error, this is probably a compiler bug. " +
$"Check whether the compiler is leaving out a push into {nameof(_generalStatementStack)}.");

foreach (StatementContext sc in visitedTry)
// start from the most external try
// internal try should ENDTRY, targeting the correct external break target
breakTarget = sc.AddEndTry(breakTarget);

Jump(OpCode.JMP_L, breakTarget);
// We could use ENDTRY if current statement calling `break` is a try statement,
// but this job can be done by the optimizer
// Note that, do not Jump(OpCode.ENDTRY_L, breakTarget) here,
// because the breakTarget here is already an ENDTRY_L for current try stack.
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ private void ConvertIteratorForEachStatement(SemanticModel model, ForEachStateme
byte elementIndex = AddLocalVariable(elementSymbol);
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
using (InsertSequencePoint(syntax.ForEachKeyword))
{
ConvertExpression(model, syntax.Expression);
Expand All @@ -97,6 +99,8 @@ private void ConvertIteratorForEachStatement(SemanticModel model, ForEachStateme
RemoveLocalVariable(elementSymbol);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}

/// <summary>
Expand Down Expand Up @@ -151,6 +155,8 @@ private void ConvertIteratorForEachVariableStatement(SemanticModel model, ForEac
byte iteratorIndex = AddAnonymousVariable();
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
using (InsertSequencePoint(syntax.ForEachKeyword))
{
ConvertExpression(model, syntax.Expression);
Expand Down Expand Up @@ -190,6 +196,8 @@ private void ConvertIteratorForEachVariableStatement(SemanticModel model, ForEac
RemoveLocalVariable(symbol);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}

/// <summary>
Expand Down Expand Up @@ -220,6 +228,8 @@ private void ConvertArrayForEachStatement(SemanticModel model, ForEachStatementS
byte elementIndex = AddLocalVariable(elementSymbol);
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
using (InsertSequencePoint(syntax.ForEachKeyword))
{
ConvertExpression(model, syntax.Expression);
Expand Down Expand Up @@ -255,6 +265,8 @@ private void ConvertArrayForEachStatement(SemanticModel model, ForEachStatementS
RemoveLocalVariable(elementSymbol);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}

/// <summary>
Expand Down Expand Up @@ -284,6 +296,8 @@ private void ConvertArrayForEachVariableStatement(SemanticModel model, ForEachVa
byte iIndex = AddAnonymousVariable();
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
using (InsertSequencePoint(syntax.ForEachKeyword))
{
ConvertExpression(model, syntax.Expression);
Expand Down Expand Up @@ -334,6 +348,8 @@ private void ConvertArrayForEachVariableStatement(SemanticModel model, ForEachVa
RemoveLocalVariable(symbol);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Neo.VM;
using System.Collections.Generic;

namespace Neo.Compiler
{
Expand Down Expand Up @@ -42,10 +43,38 @@ internal partial class MethodConvert
private void ConvertContinueStatement(ContinueStatementSyntax syntax)
{
using (InsertSequencePoint(syntax))
if (_tryStack.TryPeek(out ExceptionHandling? result) && result.ContinueTargetCount == 0)
Jump(OpCode.ENDTRY_L, _continueTargets.Peek());
else
Jump(OpCode.JMP_L, _continueTargets.Peek());
{
JumpTarget? continueTarget = null;
List<StatementContext> visitedTry = []; // from shallow to deep
foreach (StatementContext sc in _generalStatementStack)
{// start from the deepest context
// find the final continue target
if (sc.ContinueTarget != null)
{
continueTarget = sc.ContinueTarget;
break;
}
// stage the try stacks on the way
if (sc.StatementSyntax is TryStatementSyntax)
visitedTry.Add(sc);
}
if (continueTarget == null)
// continue is not handled
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Cannot find what to continue. " +
$"If not syntax error, this is probably a compiler bug. " +
$"Check whether the compiler is leaving out a push into {nameof(_generalStatementStack)}.");

foreach (StatementContext sc in visitedTry)
// start from the most external try
// internal try should ENDTRY, targeting the correct external continue target
continueTarget = sc.AddEndTry(continueTarget);

Jump(OpCode.JMP_L, continueTarget);
// We could use ENDTRY if current statement calling `continue` is a try statement,
// but this job can be done by the optimizer
// Note that, do not Jump(OpCode.ENDTRY_L, continueTarget) here,
// because the continueTarget here is already an ENDTRY_L for current try stack.
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ private void ConvertDoStatement(SemanticModel model, DoStatementSyntax syntax)
JumpTarget breakTarget = new();
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
startTarget.Instruction = AddInstruction(OpCode.NOP);
ConvertStatement(model, syntax.Statement);
continueTarget.Instruction = AddInstruction(OpCode.NOP);
Expand All @@ -56,6 +58,8 @@ private void ConvertDoStatement(SemanticModel model, DoStatementSyntax syntax)
breakTarget.Instruction = AddInstruction(OpCode.NOP);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ private void ConvertForStatement(SemanticModel model, ForStatementSyntax syntax)
JumpTarget breakTarget = new();
PushContinueTarget(continueTarget);
PushBreakTarget(breakTarget);
StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget);
_generalStatementStack.Push(sc);
foreach (var (variable, symbol) in variables)
{
byte variableIndex = AddLocalVariable(symbol);
Expand Down Expand Up @@ -99,6 +101,8 @@ private void ConvertForStatement(SemanticModel model, ForStatementSyntax syntax)
RemoveLocalVariable(symbol);
PopContinueTarget();
PopBreakTarget();
if (_generalStatementStack.Pop() != sc)
throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug.");
}
}
}
Loading
Loading