Handle if else statements
This commit is contained in:
parent
1aee448999
commit
56f3777053
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes.Number
|
namespace Upsilon.BaseTypes.Number
|
||||||
|
@ -21,5 +22,10 @@ namespace Upsilon.BaseTypes.Number
|
||||||
{
|
{
|
||||||
return Value.ToString(CultureInfo.InvariantCulture);
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static explicit operator long(NumberLong n)
|
||||||
|
{
|
||||||
|
return n.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -180,8 +180,18 @@ 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.ElseStatement == null)
|
||||||
|
{
|
||||||
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block);
|
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var elseBlock = BindBlockStatement(e.ElseStatement.Block);
|
||||||
|
var elseStatement = new BoundElseStatement((BoundBlockStatement) elseBlock);
|
||||||
|
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block,
|
||||||
|
elseStatement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,10 +7,29 @@ namespace Upsilon.Binder
|
||||||
Condition = condition;
|
Condition = condition;
|
||||||
Block = block;
|
Block = block;
|
||||||
}
|
}
|
||||||
|
public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundElseStatement elseStatement)
|
||||||
|
{
|
||||||
|
Condition = condition;
|
||||||
|
Block = block;
|
||||||
|
ElseStatement = elseStatement;
|
||||||
|
}
|
||||||
|
|
||||||
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 BoundElseStatement ElseStatement { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundElseStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundBlockStatement Block { get; }
|
||||||
|
|
||||||
|
public BoundElseStatement(BoundBlockStatement block)
|
||||||
|
{
|
||||||
|
Block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundElseStatement;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ namespace Upsilon.Binder
|
||||||
BoundAssignmentStatement,
|
BoundAssignmentStatement,
|
||||||
BoundExpressionStatement,
|
BoundExpressionStatement,
|
||||||
BoundBlockStatement,
|
BoundBlockStatement,
|
||||||
BoundIfStatement
|
BoundIfStatement,
|
||||||
|
BoundElseStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -138,6 +138,10 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
EvaluateBoundBlockStatement(boundBlockStatement.Block);
|
EvaluateBoundBlockStatement(boundBlockStatement.Block);
|
||||||
}
|
}
|
||||||
|
else if (boundBlockStatement.ElseStatement != null)
|
||||||
|
{
|
||||||
|
EvaluateBoundBlockStatement(boundBlockStatement.ElseStatement.Block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Parser
|
namespace Upsilon.Parser
|
||||||
|
@ -48,14 +49,14 @@ namespace Upsilon.Parser
|
||||||
return new SyntaxToken(kind, Current.Span.Start, "", null);
|
return new SyntaxToken(kind, Current.Span.Start, "", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementSyntax ParseScriptSyntax()
|
private StatementSyntax ParseScriptSyntax()
|
||||||
{
|
{
|
||||||
var statement = ParseBlockStatement();
|
var statement = ParseBlockStatement(new []{SyntaxKind.EndOfFile});
|
||||||
MatchToken(SyntaxKind.EndOfFile);
|
MatchToken(SyntaxKind.EndOfFile);
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementSyntax ParseStatement()
|
private StatementSyntax ParseStatement()
|
||||||
{
|
{
|
||||||
if (Current.Kind == SyntaxKind.Identifier && Next.Kind == SyntaxKind.Equals)
|
if (Current.Kind == SyntaxKind.Identifier && Next.Kind == SyntaxKind.Equals)
|
||||||
{
|
{
|
||||||
|
@ -69,14 +70,18 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
return ParseIfStatement();
|
return ParseIfStatement();
|
||||||
}
|
}
|
||||||
|
if (Current.Kind == SyntaxKind.ElseKeyword)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Here");
|
||||||
|
}
|
||||||
|
|
||||||
return ParseExpressionStatement();
|
return ParseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementSyntax ParseBlockStatement()
|
private StatementSyntax ParseBlockStatement(SyntaxKind[] endTokens)
|
||||||
{
|
{
|
||||||
var statements = ImmutableArray.CreateBuilder<StatementSyntax>();
|
var statements = ImmutableArray.CreateBuilder<StatementSyntax>();
|
||||||
while (Current.Kind != SyntaxKind.EndKeyword && Current.Kind != SyntaxKind.EndOfFile)
|
while (!endTokens.Contains(Current.Kind))
|
||||||
{
|
{
|
||||||
var next = ParseStatement();
|
var next = ParseStatement();
|
||||||
statements.Add(next);
|
statements.Add(next);
|
||||||
|
@ -84,23 +89,36 @@ namespace Upsilon.Parser
|
||||||
return new BlockStatementSyntax(statements.ToImmutable());
|
return new BlockStatementSyntax(statements.ToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementSyntax ParseIfStatement()
|
private StatementSyntax ParseIfStatement()
|
||||||
{
|
{
|
||||||
var ifToken = MatchToken(SyntaxKind.IfKeyword);
|
var ifToken = MatchToken(SyntaxKind.IfKeyword);
|
||||||
var condition = ParseExpressionStatement();
|
var condition = ParseExpressionStatement();
|
||||||
var thenToken = MatchToken(SyntaxKind.ThenKeyword);
|
var thenToken = MatchToken(SyntaxKind.ThenKeyword);
|
||||||
var block = ParseBlockStatement();
|
var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword, SyntaxKind.ElseIfKeyword, SyntaxKind.ElseKeyword});
|
||||||
var endToken = MatchToken(SyntaxKind.EndKeyword);
|
var endToken = NextToken();
|
||||||
|
switch (endToken.Kind)
|
||||||
|
{
|
||||||
|
case SyntaxKind.EndKeyword:
|
||||||
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
|
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
|
||||||
|
case SyntaxKind.ElseKeyword:
|
||||||
|
{
|
||||||
|
var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword});
|
||||||
|
var endEndToken = MatchToken(SyntaxKind.EndKeyword);
|
||||||
|
var elseStatement = new ElseStatementSyntax(endToken, (BlockStatementSyntax) elseBlock, endEndToken);
|
||||||
|
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, elseStatement);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionStatementSyntax ParseExpressionStatement()
|
private ExpressionStatementSyntax ParseExpressionStatement()
|
||||||
{
|
{
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression();
|
||||||
return new ExpressionStatementSyntax(expression);
|
return new ExpressionStatementSyntax(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionSyntax ParseExpression()
|
private ExpressionSyntax ParseExpression()
|
||||||
{
|
{
|
||||||
return ParseBinaryExpression();
|
return ParseBinaryExpression();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,24 @@ namespace Upsilon.Parser
|
||||||
Span = new TextSpan(ifToken.Span.Start, endToken.Span.End);
|
Span = new TextSpan(ifToken.Span.Start, endToken.Span.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
|
||||||
|
BlockStatementSyntax block, ElseStatementSyntax elseStatement)
|
||||||
|
{
|
||||||
|
IfToken = ifToken;
|
||||||
|
Condition = condition;
|
||||||
|
ThenToken = thenToken;
|
||||||
|
Block = block;
|
||||||
|
ElseStatement = elseStatement;
|
||||||
|
|
||||||
|
Span = new TextSpan(ifToken.Span.Start, elseStatement.Span.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SyntaxToken IfToken { get; }
|
public SyntaxToken IfToken { get; }
|
||||||
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 SyntaxToken EndToken { get; }
|
public SyntaxToken EndToken { get; }
|
||||||
|
|
||||||
public override SyntaxKind Kind => SyntaxKind.IfStatement;
|
public override SyntaxKind Kind => SyntaxKind.IfStatement;
|
||||||
|
@ -31,6 +44,31 @@ namespace Upsilon.Parser
|
||||||
yield return Condition;
|
yield return Condition;
|
||||||
yield return ThenToken;
|
yield return ThenToken;
|
||||||
yield return Block;
|
yield return Block;
|
||||||
|
if (EndToken != null)
|
||||||
|
yield return EndToken;
|
||||||
|
if (ElseStatement != null)
|
||||||
|
yield return ElseStatement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ElseStatementSyntax : StatementSyntax
|
||||||
|
{
|
||||||
|
public SyntaxToken ElseToken { get; }
|
||||||
|
public BlockStatementSyntax Block { get; }
|
||||||
|
public SyntaxToken EndToken { get; }
|
||||||
|
|
||||||
|
public ElseStatementSyntax(SyntaxToken elseToken, BlockStatementSyntax block, SyntaxToken endToken)
|
||||||
|
{
|
||||||
|
ElseToken = elseToken;
|
||||||
|
Block = block;
|
||||||
|
EndToken = endToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SyntaxKind Kind => SyntaxKind.ElseStatement;
|
||||||
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
|
{
|
||||||
|
yield return ElseToken;
|
||||||
|
yield return Block;
|
||||||
yield return EndToken;
|
yield return EndToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ namespace Upsilon.Parser
|
||||||
return SyntaxKind.IfKeyword;
|
return SyntaxKind.IfKeyword;
|
||||||
case "then":
|
case "then":
|
||||||
return SyntaxKind.ThenKeyword;
|
return SyntaxKind.ThenKeyword;
|
||||||
|
case "elseif":
|
||||||
|
return SyntaxKind.ElseIfKeyword;
|
||||||
|
case "else":
|
||||||
|
return SyntaxKind.ElseKeyword;
|
||||||
default:
|
default:
|
||||||
return SyntaxKind.Identifier;
|
return SyntaxKind.Identifier;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ namespace Upsilon.Parser
|
||||||
EndKeyword,
|
EndKeyword,
|
||||||
IfKeyword,
|
IfKeyword,
|
||||||
ThenKeyword,
|
ThenKeyword,
|
||||||
|
ElseIfKeyword,
|
||||||
|
ElseKeyword,
|
||||||
|
|
||||||
Identifier,
|
Identifier,
|
||||||
|
|
||||||
|
@ -48,6 +50,8 @@ namespace Upsilon.Parser
|
||||||
// statements
|
// statements
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
BlockStatement,
|
BlockStatement,
|
||||||
IfStatement
|
IfStatement,
|
||||||
|
ElseIfStatement,
|
||||||
|
ElseStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ namespace Upsilon.Text
|
||||||
length += start;
|
length += start;
|
||||||
start = 0;
|
start = 0;
|
||||||
};
|
};
|
||||||
|
if (start >= _text.Length)
|
||||||
|
return string.Empty;
|
||||||
if (start + length >= _text.Length) length = _text.Length - start;
|
if (start + length >= _text.Length) length = _text.Length - start;
|
||||||
return _text.Substring(start, length);
|
return _text.Substring(start, length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -14,5 +15,24 @@ namespace UpsilonTests
|
||||||
var actual = script.Evaluate<bool>();
|
var actual = script.Evaluate<bool>();
|
||||||
Assert.True(actual);
|
Assert.True(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("true", 3, 8, 3)]
|
||||||
|
[InlineData("false", 3, 8, 8)]
|
||||||
|
[InlineData("5 == 5", 500, 349, 500)]
|
||||||
|
public void BasicIfElseTests(string condition, int in1, int in2, long expected)
|
||||||
|
{
|
||||||
|
var input =
|
||||||
|
$@"
|
||||||
|
if {condition} then
|
||||||
|
val = {in1}
|
||||||
|
else
|
||||||
|
val = {in2}
|
||||||
|
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