Handle if else statements

This commit is contained in:
Deukhoofd 2018-11-13 13:54:51 +01:00
parent 1aee448999
commit 56f3777053
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
11 changed files with 142 additions and 16 deletions

View File

@ -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;
}
} }
} }

View File

@ -180,7 +180,17 @@ namespace Upsilon.Binder
{ {
var condition = BindExpressionStatement(e.Condition); var condition = BindExpressionStatement(e.Condition);
var block = BindBlockStatement(e.Block); var block = BindBlockStatement(e.Block);
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block); if (e.ElseStatement == null)
{
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);
}
} }
} }

View File

@ -5,12 +5,31 @@ namespace Upsilon.Binder
public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block) public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block)
{ {
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;
} }
} }

View File

@ -13,6 +13,7 @@ namespace Upsilon.Binder
BoundAssignmentStatement, BoundAssignmentStatement,
BoundExpressionStatement, BoundExpressionStatement,
BoundBlockStatement, BoundBlockStatement,
BoundIfStatement BoundIfStatement,
BoundElseStatement
} }
} }

View File

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

View File

@ -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();
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken); switch (endToken.Kind)
{
case SyntaxKind.EndKeyword:
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();
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }

View File

@ -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
} }
} }

View File

@ -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);
} }

View File

@ -1,3 +1,4 @@
using Upsilon.BaseTypes.Number;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Xunit; using Xunit;
@ -8,11 +9,30 @@ namespace UpsilonTests
[Fact] [Fact]
public void BasicIfTest() public void BasicIfTest()
{ {
var input = "if true then val = true end"; var input = "if true then val = true end";
var script = new Script(input); var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages); Assert.Empty(script.Diagnostics.Messages);
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);
}
} }
} }