Handle if else if (else) statements
This commit is contained in:
parent
56f3777053
commit
b9aac52476
|
@ -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);
|
||||||
|
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue