Implements break statement

This commit is contained in:
Deukhoofd 2018-11-23 15:27:48 +01:00
parent d2c14d213c
commit 2db4d0607e
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
10 changed files with 76 additions and 13 deletions

View File

@ -70,6 +70,8 @@ namespace Upsilon.Binder
return BindMultiAssignmentStatement((MultiAssignmentStatementSyntax) s); return BindMultiAssignmentStatement((MultiAssignmentStatementSyntax) s);
case SyntaxKind.NumericForStatement: case SyntaxKind.NumericForStatement:
return BindNumericForStatement((NumericForStatementSyntax) s); return BindNumericForStatement((NumericForStatementSyntax) s);
case SyntaxKind.BreakStatement:
return new BoundBreakStatement();
} }
throw new NotImplementedException(s.Kind.ToString()); throw new NotImplementedException(s.Kind.ToString());

View File

@ -11,6 +11,7 @@ namespace Upsilon.Binder
BoundFunctionCallExpression, BoundFunctionCallExpression,
BoundTableExpression, BoundTableExpression,
BoundIndexExpression, BoundIndexExpression,
BoundFunctionExpression,
// Statements // Statements
BoundAssignmentStatement, BoundAssignmentStatement,
@ -18,13 +19,13 @@ namespace Upsilon.Binder
BoundBlockStatement, BoundBlockStatement,
BoundIfStatement, BoundIfStatement,
BoundElseStatement, BoundElseStatement,
BoundFunctionExpression,
BoundPromise, BoundPromise,
BoundReturnStatement, BoundReturnStatement,
BoundFunctionAssignmentStatement, BoundFunctionAssignmentStatement,
BoundTableAssigmentStatement, BoundTableAssigmentStatement,
BoundFullstopIndexExpression, BoundFullstopIndexExpression,
BoundMultiAssignmentStatement, BoundMultiAssignmentStatement,
BoundNumericForStatement BoundNumericForStatement,
BoundBreakStatement
} }
} }

View File

@ -0,0 +1,7 @@
namespace Upsilon.Binder
{
public class BoundBreakStatement : BoundStatement
{
public override BoundKind Kind => BoundKind.BoundBreakStatement;
}
}

View File

@ -17,6 +17,7 @@ namespace Upsilon.Evaluator
private LuaType _returnValue; private LuaType _returnValue;
internal EvaluationScope Scope { get; private set; } internal EvaluationScope Scope { get; private set; }
private bool HasReturned { get; set; } private bool HasReturned { get; set; }
private bool HasBroken { get; set; }
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables) internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
{ {
@ -132,6 +133,9 @@ namespace Upsilon.Evaluator
case BoundKind.BoundNumericForStatement: case BoundKind.BoundNumericForStatement:
EvaluateNumericForStatement((BoundNumericForStatement) e); EvaluateNumericForStatement((BoundNumericForStatement) e);
break; break;
case BoundKind.BoundBreakStatement:
HasBroken = true;
return;
default: default:
EvaluateExpressionStatement((BoundExpressionStatement) e); EvaluateExpressionStatement((BoundExpressionStatement) e);
break; break;
@ -332,30 +336,27 @@ namespace Upsilon.Evaluator
{ {
if (HasReturned) if (HasReturned)
return; return;
if (HasBroken)
return;
EvaluateStatement(boundStatement); EvaluateStatement(boundStatement);
} }
} }
private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement) private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement)
{ {
var innerEvaluator = new Evaluator(_diagnostics, Scope); var condition = EvaluateExpression(boundBlockStatement.Condition.Expression);
var condition = innerEvaluator.EvaluateExpression(boundBlockStatement.Condition.Expression);
if ((LuaBoolean) condition) if ((LuaBoolean) condition)
{ {
innerEvaluator.EvaluateStatement(boundBlockStatement.Block); EvaluateStatement(boundBlockStatement.Block);
} }
else if (boundBlockStatement.NextElseIf != null) else if (boundBlockStatement.NextElseIf != null)
{ {
innerEvaluator.EvaluateStatement(boundBlockStatement.NextElseIf); EvaluateStatement(boundBlockStatement.NextElseIf);
} }
else if (boundBlockStatement.ElseStatement != null) else if (boundBlockStatement.ElseStatement != null)
{ {
innerEvaluator.EvaluateStatement(boundBlockStatement.ElseStatement.Block); EvaluateStatement(boundBlockStatement.ElseStatement.Block);
} }
HasReturned = innerEvaluator.HasReturned;
if (HasReturned)
_returnValue = innerEvaluator._returnValue;
_lastValue = innerEvaluator._lastValue;
} }
private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e) private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e)
@ -508,6 +509,8 @@ namespace Upsilon.Evaluator
for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step) for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step)
{ {
innerEvaluator.EvaluateBoundBlockStatement(e.Block); innerEvaluator.EvaluateBoundBlockStatement(e.Block);
if (innerEvaluator.HasBroken)
break;
} }
} }
else if (step < 0) else if (step < 0)
@ -515,6 +518,8 @@ namespace Upsilon.Evaluator
for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step) for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step)
{ {
innerEvaluator.EvaluateBoundBlockStatement(e.Block); innerEvaluator.EvaluateBoundBlockStatement(e.Block);
if (innerEvaluator.HasBroken)
break;
} }
} }
} }

View File

@ -91,6 +91,10 @@ namespace Upsilon.Parser
{ {
return ParseForStatement(); return ParseForStatement();
} }
if (Current.Kind == SyntaxKind.BreakKeyword)
{
return new BreakStatementSyntax(NextToken());
}
return ParseExpressionStatement(); return ParseExpressionStatement();
} }

View File

@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace Upsilon.Parser
{
public class BreakStatementSyntax : StatementSyntax
{
public SyntaxToken BreakKeyword { get; }
public BreakStatementSyntax(SyntaxToken breakKeyword)
{
BreakKeyword = breakKeyword;
}
public override SyntaxKind Kind => SyntaxKind.BreakStatement;
public override IEnumerable<SyntaxNode> ChildNodes()
{
yield return BreakKeyword;
}
}
}

View File

@ -40,6 +40,8 @@ namespace Upsilon.Parser
return SyntaxKind.InKeyword; return SyntaxKind.InKeyword;
case "do": case "do":
return SyntaxKind.DoKeyword; return SyntaxKind.DoKeyword;
case "break":
return SyntaxKind.BreakKeyword;
default: default:
return SyntaxKind.Identifier; return SyntaxKind.Identifier;
} }

View File

@ -46,6 +46,7 @@ namespace Upsilon.Parser
ForKeyword, ForKeyword,
InKeyword, InKeyword,
DoKeyword, DoKeyword,
BreakKeyword,
Identifier, Identifier,
@ -76,6 +77,7 @@ namespace Upsilon.Parser
ReturnStatement, ReturnStatement,
FunctionAssignmentStatement, FunctionAssignmentStatement,
TableAssignmentStatement, TableAssignmentStatement,
NumericForStatement NumericForStatement,
BreakStatement
} }
} }

View File

@ -59,5 +59,25 @@ return a";
Assert.Equal(15, result); Assert.Equal(15, result);
} }
[Fact]
public void NumericForLoopBreakTest()
{
const string input = @"
a = 0
for i=0,10 do
a = a + i
if i == 5 then
break
end
end
return a
";
var script = new Script(input, BoundScope, StaticScope);
Assert.Empty(script.Diagnostics.Messages);
var result = script.Evaluate<long>();
Assert.Empty(script.Diagnostics.Messages);
Assert.Equal(15, result);
}
} }
} }

View File

@ -14,9 +14,10 @@ namespace UpsilonTests.GeneralTests
{ {
const string input = @" const string input = @"
a = 10 a = 10
if true then function testFunc()
local a = 100 local a = 100
end end
testFunc()
"; ";
var script = new Script(input, BoundScope, StaticScope); var script = new Script(input, BoundScope, StaticScope);
Assert.Empty(script.Diagnostics.Messages); Assert.Empty(script.Diagnostics.Messages);