From eb1eb81c1b3d71c5b1b5d1c00005c0f469839933 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 7 Dec 2018 19:17:49 +0100 Subject: [PATCH] Implements while loops --- Upsilon/Binder/Binder.cs | 12 ++++++ Upsilon/Binder/BoundKind.cs | 2 +- .../BoundStatements/BoundWhileStatement.cs | 33 +++++++++++++++++ Upsilon/Evaluator/Evaluator.cs | 15 ++++++++ Upsilon/Parser/Parser.cs | 15 ++++++++ .../StatementSyntax/WhileStatementSyntax.cs | 37 +++++++++++++++++++ Upsilon/Parser/SyntaxKeyWords.cs | 2 + Upsilon/Parser/SyntaxKind.cs | 6 ++- 8 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 Upsilon/Binder/BoundStatements/BoundWhileStatement.cs create mode 100644 Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 898aa7d..90f6109 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -95,6 +95,8 @@ namespace Upsilon.Binder return BindNumericForStatement((NumericForStatementSyntax) s); case SyntaxKind.GenericForStatement: return BindGenericForStatement((GenericForStatementSyntax) s); + case SyntaxKind.WhileStatement: + return BindWhileStatement((WhileStatementSyntax) s); case SyntaxKind.BreakStatement: return new BoundBreakStatement(s.Span); @@ -860,5 +862,15 @@ namespace Upsilon.Binder return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block, e.Span); } + + private BoundStatement BindWhileStatement(WhileStatementSyntax e) + { + Scope = new BoundScope(Scope); + var condition = BindExpression(e.Expression); + var block = BindBlockStatement((BlockStatementSyntax) e.Block); + + return new BoundWhileStatement(condition, block, e.Span); + } + } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index 4b0c16c..45a31ec 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -29,6 +29,6 @@ namespace Upsilon.Binder BoundNumericForStatement, BoundGenericForStatement, BoundBreakStatement, - + BoundWhileStatement } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs b/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs new file mode 100644 index 0000000..426baa4 --- /dev/null +++ b/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Upsilon.Text; + +namespace Upsilon.Binder +{ + internal class BoundWhileStatement : BoundStatement + { + public BoundExpression Condition { get; } + public BoundStatement Block { get; } + + public BoundWhileStatement(BoundExpression condition, BoundStatement block, TextSpan eSpan) + :base(eSpan) + { + Condition = condition; + Block = block; + } + + public override BoundKind Kind => BoundKind.BoundWhileStatement; + public override IEnumerable GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Condition.Span.Start && characterPosition <= Condition.Span.End) + foreach (var boundNode in Condition.GetNodeAtPosition(characterPosition)) + yield return boundNode; + + if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + yield return boundNode; + + yield return this; + } + } +} \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 57d66b5..16a1229 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -136,6 +136,7 @@ namespace Upsilon.Evaluator case BoundKind.BoundNumericForStatement: case BoundKind.BoundGenericForStatement: case BoundKind.BoundBreakStatement: + case BoundKind.BoundWhileStatement: EvaluateStatement((BoundStatement) b); break; default: @@ -180,6 +181,9 @@ namespace Upsilon.Evaluator case BoundKind.BoundGenericForStatement: EvaluateGenericForStatement((BoundGenericForStatement) e); break; + case BoundKind.BoundWhileStatement: + EvaluateWhileStatement((BoundWhileStatement) e); + break; default: EvaluateExpressionStatement((BoundExpressionStatement) e); break; @@ -664,5 +668,16 @@ namespace Upsilon.Evaluator } } } + + private void EvaluateWhileStatement(BoundWhileStatement e) + { + var innerEvaluator = new Evaluator(_diagnostics, Scope, _script); + + var block = (BoundBlockStatement) e.Block; + while ((ScriptBoolean)EvaluateExpression(e.Condition)) + { + innerEvaluator.EvaluateBoundBlockStatement(block); + } + } } } \ No newline at end of file diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 2b640ba..ea02522 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -90,6 +90,10 @@ namespace Upsilon.Parser { return ParseForStatement(); } + if (Current.Kind == SyntaxKind.WhileKeyword) + { + return ParseWhileStatement(); + } if (Current.Kind == SyntaxKind.BreakKeyword) { return new BreakStatementSyntax(NextToken()); @@ -196,6 +200,17 @@ namespace Upsilon.Parser doKeyword, (BlockStatementSyntax) block, endKeyword); } + private StatementSyntax ParseWhileStatement() + { + var whileToken = MatchToken(SyntaxKind.WhileKeyword); + var expression = ParseExpression(); + var doToken = MatchToken(SyntaxKind.DoKeyword); + var block = ParseBlockStatement(new[] {SyntaxKind.EndKeyword}); + var endKeyword = MatchToken(SyntaxKind.EndKeyword); + return new WhileStatementSyntax(whileToken, expression, doToken, block, endKeyword); + } + + private ExpressionSyntax ParseFunctionExpression() { var functionToken = MatchToken(SyntaxKind.FunctionKeyword); diff --git a/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs new file mode 100644 index 0000000..784d3be --- /dev/null +++ b/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Upsilon.Text; + +namespace Upsilon.Parser +{ + internal class WhileStatementSyntax : StatementSyntax + { + public SyntaxToken WhileToken { get; } + public ExpressionSyntax Expression { get; } + public SyntaxToken DoToken { get; } + public StatementSyntax Block { get; } + public SyntaxToken EndKeyword { get; } + + public WhileStatementSyntax(SyntaxToken whileToken, ExpressionSyntax expression, SyntaxToken doToken, + StatementSyntax block, SyntaxToken endKeyword) + { + WhileToken = whileToken; + Expression = expression; + DoToken = doToken; + Block = block; + EndKeyword = endKeyword; + + Span = new TextSpan(whileToken.Span.Start, endKeyword.Span.End); + } + + public override SyntaxKind Kind => SyntaxKind.WhileStatement; + public override IEnumerable ChildNodes() + { + yield return WhileToken; + yield return Expression; + yield return DoToken; + yield return Block; + yield return EndKeyword; + } + } +} \ No newline at end of file diff --git a/Upsilon/Parser/SyntaxKeyWords.cs b/Upsilon/Parser/SyntaxKeyWords.cs index 38add46..0d11134 100644 --- a/Upsilon/Parser/SyntaxKeyWords.cs +++ b/Upsilon/Parser/SyntaxKeyWords.cs @@ -36,6 +36,8 @@ namespace Upsilon.Parser return SyntaxKind.ReturnKeyword; case "for": return SyntaxKind.ForKeyword; + case "while": + return SyntaxKind.WhileKeyword; case "in": return SyntaxKind.InKeyword; case "do": diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index 9a9cf8f..9b9520a 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -33,6 +33,8 @@ namespace Upsilon.Parser LessEquals, Greater, GreaterEquals, + PercentSign, + RoofSign, // key words TrueKeyword, @@ -50,6 +52,7 @@ namespace Upsilon.Parser FunctionKeyword, ReturnKeyword, ForKeyword, + WhileKeyword, InKeyword, DoKeyword, BreakKeyword, @@ -87,7 +90,6 @@ namespace Upsilon.Parser NumericForStatement, BreakStatement, GenericForStatement, - PercentSign, - RoofSign + WhileStatement } } \ No newline at end of file