Handle if else if (else) statements

This commit is contained in:
Deukhoofd 2018-11-13 15:15:44 +01:00
parent 56f3777053
commit b9aac52476
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
6 changed files with 120 additions and 26 deletions

View File

@ -105,7 +105,7 @@ namespace Upsilon.Binder
type = Type.Number; type = Type.Number;
outValue = new NumberLong(l); outValue = new NumberLong(l);
break; break;
case bool b: case bool _:
type = Type.Boolean; type = Type.Boolean;
outValue = value; outValue = value;
break; break;
@ -180,6 +180,12 @@ namespace Upsilon.Binder
{ {
var condition = BindExpressionStatement(e.Condition); var condition = BindExpressionStatement(e.Condition);
var block = BindBlockStatement(e.Block); var block = BindBlockStatement(e.Block);
if (e.NextElseIfStatement != null)
{
var nextElseIf = BindIfStatement(e.NextElseIfStatement);
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block,
(BoundIfStatement) nextElseIf);
}
if (e.ElseStatement == null) if (e.ElseStatement == null)
{ {
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block); return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block);

View File

@ -7,17 +7,25 @@ namespace Upsilon.Binder
Condition = condition; Condition = condition;
Block = block; Block = block;
} }
public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundElseStatement elseStatement) public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundElseStatement elseStatement)
{ {
Condition = condition; Condition = condition;
Block = block; Block = block;
ElseStatement = elseStatement; ElseStatement = elseStatement;
} }
public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundIfStatement nextElseIf)
{
Condition = condition;
Block = block;
NextElseIf = nextElseIf;
}
public override BoundKind Kind => BoundKind.BoundIfStatement; public override BoundKind Kind => BoundKind.BoundIfStatement;
public BoundExpressionStatement Condition { get; } public BoundExpressionStatement Condition { get; }
public BoundBlockStatement Block { get; } public BoundBlockStatement Block { get; }
public BoundIfStatement NextElseIf { get; }
public BoundElseStatement ElseStatement { get; } public BoundElseStatement ElseStatement { get; }
} }

View File

@ -138,6 +138,10 @@ namespace Upsilon.Evaluator
{ {
EvaluateBoundBlockStatement(boundBlockStatement.Block); EvaluateBoundBlockStatement(boundBlockStatement.Block);
} }
else if (boundBlockStatement.NextElseIf != null)
{
EvaluateBoundIfStatement(boundBlockStatement.NextElseIf);
}
else if (boundBlockStatement.ElseStatement != null) else if (boundBlockStatement.ElseStatement != null)
{ {
EvaluateBoundBlockStatement(boundBlockStatement.ElseStatement.Block); EvaluateBoundBlockStatement(boundBlockStatement.ElseStatement.Block);

View File

@ -68,11 +68,7 @@ namespace Upsilon.Parser
} }
if (Current.Kind == SyntaxKind.IfKeyword) if (Current.Kind == SyntaxKind.IfKeyword)
{ {
return ParseIfStatement(); return ParseIfStatement(SyntaxKind.IfKeyword);
}
if (Current.Kind == SyntaxKind.ElseKeyword)
{
Console.WriteLine("Here");
} }
return ParseExpressionStatement(); return ParseExpressionStatement();
@ -89,26 +85,32 @@ namespace Upsilon.Parser
return new BlockStatementSyntax(statements.ToImmutable()); return new BlockStatementSyntax(statements.ToImmutable());
} }
private StatementSyntax ParseIfStatement() private StatementSyntax ParseIfStatement(SyntaxKind requiredToken)
{ {
var ifToken = MatchToken(SyntaxKind.IfKeyword); var ifToken = MatchToken(requiredToken);
var condition = ParseExpressionStatement(); var condition = ParseExpressionStatement();
var thenToken = MatchToken(SyntaxKind.ThenKeyword); var thenToken = MatchToken(SyntaxKind.ThenKeyword);
var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword, SyntaxKind.ElseIfKeyword, SyntaxKind.ElseKeyword}); var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword, SyntaxKind.ElseIfKeyword, SyntaxKind.ElseKeyword});
var endToken = NextToken(); switch (Current.Kind)
switch (endToken.Kind)
{ {
case SyntaxKind.EndKeyword: case SyntaxKind.ElseIfKeyword:
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken); var nextElseIf =
new ElseIfStatementSyntax((IfStatementSyntax) ParseIfStatement(SyntaxKind.ElseIfKeyword));
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block,
nextElseIf);
case SyntaxKind.ElseKeyword: case SyntaxKind.ElseKeyword:
{ {
var elseToken = MatchToken(SyntaxKind.ElseKeyword);
var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword}); var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword});
var endEndToken = MatchToken(SyntaxKind.EndKeyword); var endEndToken = MatchToken(SyntaxKind.EndKeyword);
var elseStatement = new ElseStatementSyntax(endToken, (BlockStatementSyntax) elseBlock, endEndToken); var elseStatement = new ElseStatementSyntax(elseToken, (BlockStatementSyntax) elseBlock, endEndToken);
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, elseStatement); return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, elseStatement);
} }
case SyntaxKind.EndKeyword:
var endToken = MatchToken(SyntaxKind.EndKeyword);
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
default: default:
return null; throw new ArgumentOutOfRangeException();
} }
} }

View File

@ -1,9 +1,12 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.Parser namespace Upsilon.Parser
{ {
public sealed class IfStatementSyntax : StatementSyntax public class IfStatementSyntax : StatementSyntax
{ {
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
BlockStatementSyntax block, SyntaxToken endToken) BlockStatementSyntax block, SyntaxToken endToken)
@ -14,7 +17,6 @@ namespace Upsilon.Parser
Block = block; Block = block;
EndToken = endToken; EndToken = endToken;
Span = new TextSpan(ifToken.Span.Start, endToken.Span.End);
} }
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
@ -26,7 +28,16 @@ namespace Upsilon.Parser
Block = block; Block = block;
ElseStatement = elseStatement; ElseStatement = elseStatement;
Span = new TextSpan(ifToken.Span.Start, elseStatement.Span.End); }
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
BlockStatementSyntax block, ElseIfStatementSyntax nextElseIfStatement)
{
IfToken = ifToken;
Condition = condition;
ThenToken = thenToken;
Block = block;
NextElseIfStatement = nextElseIfStatement;
} }
@ -34,7 +45,8 @@ namespace Upsilon.Parser
public ExpressionStatementSyntax Condition { get; } public ExpressionStatementSyntax Condition { get; }
public SyntaxToken ThenToken { get; } public SyntaxToken ThenToken { get; }
public BlockStatementSyntax Block { get; } public BlockStatementSyntax Block { get; }
public ElseStatementSyntax ElseStatement { get; } public ElseIfStatementSyntax NextElseIfStatement { get; protected set; }
public ElseStatementSyntax ElseStatement { get; protected set; }
public SyntaxToken EndToken { get; } public SyntaxToken EndToken { get; }
public override SyntaxKind Kind => SyntaxKind.IfStatement; public override SyntaxKind Kind => SyntaxKind.IfStatement;
@ -44,13 +56,54 @@ namespace Upsilon.Parser
yield return Condition; yield return Condition;
yield return ThenToken; yield return ThenToken;
yield return Block; yield return Block;
if (EndToken != null) if (NextElseIfStatement != null)
yield return EndToken; yield return NextElseIfStatement;
if (ElseStatement != null) if (ElseStatement != null)
yield return ElseStatement; yield return ElseStatement;
if (EndToken != null)
yield return EndToken;
} }
} }
public sealed class ElseIfStatementSyntax : IfStatementSyntax
{
public SyntaxToken ElseIfToken => IfToken;
public override SyntaxKind Kind => SyntaxKind.ElseIfStatement;
public override IEnumerable<SyntaxNode> ChildNodes()
{
yield return ElseIfToken;
yield return Condition;
yield return ThenToken;
yield return Block;
}
public ElseIfStatementSyntax(IfStatementSyntax s)
:base(s.IfToken, s.Condition, s.ThenToken, s.Block, s.EndToken)
{
NextElseIfStatement = s.NextElseIfStatement;
ElseStatement = s.ElseStatement;
}
public ElseIfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
BlockStatementSyntax block, SyntaxToken endToken) : base(ifToken, condition, thenToken, block, endToken)
{
}
public ElseIfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
BlockStatementSyntax block, ElseStatementSyntax elseStatement) : base(ifToken, condition, thenToken, block,
elseStatement)
{
}
public ElseIfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
BlockStatementSyntax block, ElseIfStatementSyntax nextElseIfStatement) : base(ifToken, condition, thenToken,
block, nextElseIfStatement)
{
}
}
public sealed class ElseStatementSyntax : StatementSyntax public sealed class ElseStatementSyntax : StatementSyntax
{ {
public SyntaxToken ElseToken { get; } public SyntaxToken ElseToken { get; }

View File

@ -34,5 +34,26 @@ end";
var actual = (long)(NumberLong)script.Evaluate(); var actual = (long)(NumberLong)script.Evaluate();
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }
[Theory]
[InlineData("true", "false", 3, 8, 5, 3)]
[InlineData("false", "true", 3, 8, 5, 8)]
public void BasicIfElseIfElseTests(string condition1, string condition2, int in1, int in2, int in3, long expected)
{
var input =
$@"
if {condition1} then
val = {in1}
elseif {condition2} then
val = {in2}
else
val = {in3}
end";
var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages);
var actual = (long)(NumberLong)script.Evaluate();
Assert.Equal(expected, actual);
}
} }
} }