Handle if statements
This commit is contained in:
parent
e5ac28bacf
commit
1aee448999
|
@ -33,6 +33,8 @@ namespace Upsilon.Binder
|
||||||
return BindAssignmentStatement((AssignmentExpressionSyntax) s);
|
return BindAssignmentStatement((AssignmentExpressionSyntax) s);
|
||||||
case SyntaxKind.BlockStatement:
|
case SyntaxKind.BlockStatement:
|
||||||
return BindBlockStatement((BlockStatementSyntax) s);
|
return BindBlockStatement((BlockStatementSyntax) s);
|
||||||
|
case SyntaxKind.IfStatement:
|
||||||
|
return BindIfStatement((IfStatementSyntax) s);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(s.Kind.ToString());
|
throw new NotImplementedException(s.Kind.ToString());
|
||||||
|
@ -173,5 +175,13 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
return new BoundBlockStatement(arr.ToImmutable());
|
return new BoundBlockStatement(arr.ToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BoundStatement BindIfStatement(IfStatementSyntax e)
|
||||||
|
{
|
||||||
|
var condition = BindExpressionStatement(e.Condition);
|
||||||
|
var block = BindBlockStatement(e.Block);
|
||||||
|
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundIfStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block)
|
||||||
|
{
|
||||||
|
Condition = condition;
|
||||||
|
Block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundIfStatement;
|
||||||
|
|
||||||
|
public BoundExpressionStatement Condition { get; }
|
||||||
|
public BoundBlockStatement Block { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ namespace Upsilon.Binder
|
||||||
// Statements
|
// Statements
|
||||||
BoundAssignmentStatement,
|
BoundAssignmentStatement,
|
||||||
BoundExpressionStatement,
|
BoundExpressionStatement,
|
||||||
BoundBlockStatement
|
BoundBlockStatement,
|
||||||
|
BoundIfStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,9 +25,9 @@ namespace Upsilon
|
||||||
Log(DiagnosticLevel.Error, message, location);
|
Log(DiagnosticLevel.Error, message, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogBadCharacter(TextSpan location)
|
public void LogBadCharacter(TextSpan location, SyntaxKind expectedToken)
|
||||||
{
|
{
|
||||||
LogError($"Invalid character found", location);
|
LogError($"Invalid character found. Expected: '{expectedToken}'", location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogUnknownVariable(TextSpan span, string variable)
|
public void LogUnknownVariable(TextSpan span, string variable)
|
||||||
|
|
|
@ -40,6 +40,9 @@ namespace Upsilon.Evaluator
|
||||||
case BoundKind.BoundBlockStatement:
|
case BoundKind.BoundBlockStatement:
|
||||||
EvaluateBoundBlockStatement((BoundBlockStatement) e);
|
EvaluateBoundBlockStatement((BoundBlockStatement) e);
|
||||||
break;
|
break;
|
||||||
|
case BoundKind.BoundIfStatement:
|
||||||
|
EvaluateBoundIfStatement((BoundIfStatement) e);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
||||||
break;
|
break;
|
||||||
|
@ -127,5 +130,14 @@ namespace Upsilon.Evaluator
|
||||||
EvaluateStatement(boundStatement);
|
EvaluateStatement(boundStatement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement)
|
||||||
|
{
|
||||||
|
var condition = EvaluateExpression(boundBlockStatement.Condition.Expression);
|
||||||
|
if ((bool) condition)
|
||||||
|
{
|
||||||
|
EvaluateBoundBlockStatement(boundBlockStatement.Block);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ namespace Upsilon.Evaluator
|
||||||
ScriptString = new SourceText(scriptString);
|
ScriptString = new SourceText(scriptString);
|
||||||
Diagnostics = new Diagnostics(ScriptString);
|
Diagnostics = new Diagnostics(ScriptString);
|
||||||
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
||||||
|
if (variables == null)
|
||||||
|
variables = new Dictionary<VariableSymbol, object>();
|
||||||
Binder = new Binder.Binder(new BoundScope(variables, null), Diagnostics);
|
Binder = new Binder.Binder(new BoundScope(variables, null), Diagnostics);
|
||||||
Evaluator = new Evaluator(this, Diagnostics, variables);
|
Evaluator = new Evaluator(this, Diagnostics, variables);
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace Upsilon.Parser
|
||||||
default:
|
default:
|
||||||
if (char.IsLetter(Current))
|
if (char.IsLetter(Current))
|
||||||
return LexIdentifierOrKeyword();
|
return LexIdentifierOrKeyword();
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1));
|
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
||||||
return new SyntaxToken(SyntaxKind.BadToken, _position, "", null);
|
return new SyntaxToken(SyntaxKind.BadToken, _position, "", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
if (hasDecimalPoint)
|
if (hasDecimalPoint)
|
||||||
{
|
{
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1));
|
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Number);
|
||||||
return new SyntaxToken(SyntaxKind.BadToken, _position, "", null);
|
return new SyntaxToken(SyntaxKind.BadToken, _position, "", null);
|
||||||
}
|
}
|
||||||
hasDecimalPoint = true;
|
hasDecimalPoint = true;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
|
@ -43,13 +44,14 @@ namespace Upsilon.Parser
|
||||||
if (Current.Kind == kind)
|
if (Current.Kind == kind)
|
||||||
return NextToken();
|
return NextToken();
|
||||||
|
|
||||||
_diagnostics.LogBadCharacter(Current.Span);
|
_diagnostics.LogBadCharacter(Current.Span, kind);
|
||||||
return new SyntaxToken(kind, Current.Span.Start, "", null);
|
return new SyntaxToken(kind, Current.Span.Start, "", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementSyntax ParseScriptSyntax()
|
public StatementSyntax ParseScriptSyntax()
|
||||||
{
|
{
|
||||||
var statement = ParseBlockStatement();
|
var statement = ParseBlockStatement();
|
||||||
|
MatchToken(SyntaxKind.EndOfFile);
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +65,10 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
return ParseAssignmentExpression();
|
return ParseAssignmentExpression();
|
||||||
}
|
}
|
||||||
|
if (Current.Kind == SyntaxKind.IfKeyword)
|
||||||
|
{
|
||||||
|
return ParseIfStatement();
|
||||||
|
}
|
||||||
|
|
||||||
return ParseExpressionStatement();
|
return ParseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
@ -75,8 +81,17 @@ namespace Upsilon.Parser
|
||||||
var next = ParseStatement();
|
var next = ParseStatement();
|
||||||
statements.Add(next);
|
statements.Add(next);
|
||||||
}
|
}
|
||||||
var endToken = NextToken();
|
return new BlockStatementSyntax(statements.ToImmutable());
|
||||||
return new BlockStatementSyntax(statements.ToImmutable(), endToken);
|
}
|
||||||
|
|
||||||
|
public StatementSyntax ParseIfStatement()
|
||||||
|
{
|
||||||
|
var ifToken = MatchToken(SyntaxKind.IfKeyword);
|
||||||
|
var condition = ParseExpressionStatement();
|
||||||
|
var thenToken = MatchToken(SyntaxKind.ThenKeyword);
|
||||||
|
var block = ParseBlockStatement();
|
||||||
|
var endToken = MatchToken(SyntaxKind.EndKeyword);
|
||||||
|
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionStatementSyntax ParseExpressionStatement()
|
public ExpressionStatementSyntax ParseExpressionStatement()
|
||||||
|
@ -147,7 +162,7 @@ namespace Upsilon.Parser
|
||||||
var token = MatchToken(SyntaxKind.Identifier);
|
var token = MatchToken(SyntaxKind.Identifier);
|
||||||
return new VariableExpressionSyntax((IdentifierToken) token);
|
return new VariableExpressionSyntax((IdentifierToken) token);
|
||||||
default:
|
default:
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1));
|
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
||||||
NextToken();
|
NextToken();
|
||||||
return new BadExpressionSyntax();
|
return new BadExpressionSyntax();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,16 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public sealed class BlockStatementSyntax : StatementSyntax
|
public sealed class BlockStatementSyntax : StatementSyntax
|
||||||
{
|
{
|
||||||
public BlockStatementSyntax(ImmutableArray<StatementSyntax> statements, SyntaxToken endToken)
|
public BlockStatementSyntax(ImmutableArray<StatementSyntax> statements)
|
||||||
{
|
{
|
||||||
Statements = statements;
|
Statements = statements;
|
||||||
EndToken = endToken;
|
|
||||||
var first = statements.FirstOrDefault();
|
var first = statements.FirstOrDefault();
|
||||||
if (first != null)
|
var last = statements.LastOrDefault();
|
||||||
Span = new TextSpan(first.Span.Start, endToken.Span.End);
|
if (first != null && last != null)
|
||||||
|
Span = new TextSpan(first.Span.Start, last.Span.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<StatementSyntax> Statements { get; }
|
public ImmutableArray<StatementSyntax> Statements { get; }
|
||||||
public SyntaxToken EndToken { get; }
|
|
||||||
public override SyntaxKind Kind => SyntaxKind.BlockStatement;
|
public override SyntaxKind Kind => SyntaxKind.BlockStatement;
|
||||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Text;
|
||||||
|
|
||||||
|
namespace Upsilon.Parser
|
||||||
|
{
|
||||||
|
public sealed class IfStatementSyntax : StatementSyntax
|
||||||
|
{
|
||||||
|
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
|
||||||
|
BlockStatementSyntax block, SyntaxToken endToken)
|
||||||
|
{
|
||||||
|
IfToken = ifToken;
|
||||||
|
Condition = condition;
|
||||||
|
ThenToken = thenToken;
|
||||||
|
Block = block;
|
||||||
|
EndToken = endToken;
|
||||||
|
|
||||||
|
Span = new TextSpan(ifToken.Span.Start, endToken.Span.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SyntaxToken IfToken { get; }
|
||||||
|
public ExpressionStatementSyntax Condition { get; }
|
||||||
|
public SyntaxToken ThenToken { get; }
|
||||||
|
public BlockStatementSyntax Block { get; }
|
||||||
|
public SyntaxToken EndToken { get; }
|
||||||
|
|
||||||
|
public override SyntaxKind Kind => SyntaxKind.IfStatement;
|
||||||
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
|
{
|
||||||
|
yield return IfToken;
|
||||||
|
yield return Condition;
|
||||||
|
yield return ThenToken;
|
||||||
|
yield return Block;
|
||||||
|
yield return EndToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,10 @@ namespace Upsilon.Parser
|
||||||
return SyntaxKind.LocalKeyword;
|
return SyntaxKind.LocalKeyword;
|
||||||
case "end":
|
case "end":
|
||||||
return SyntaxKind.EndKeyword;
|
return SyntaxKind.EndKeyword;
|
||||||
|
case "if":
|
||||||
|
return SyntaxKind.IfKeyword;
|
||||||
|
case "then":
|
||||||
|
return SyntaxKind.ThenKeyword;
|
||||||
default:
|
default:
|
||||||
return SyntaxKind.Identifier;
|
return SyntaxKind.Identifier;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ namespace Upsilon.Parser
|
||||||
OrKeyword,
|
OrKeyword,
|
||||||
LocalKeyword,
|
LocalKeyword,
|
||||||
EndKeyword,
|
EndKeyword,
|
||||||
|
IfKeyword,
|
||||||
|
ThenKeyword,
|
||||||
|
|
||||||
Identifier,
|
Identifier,
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@ namespace Upsilon.Parser
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
BlockStatement
|
BlockStatement,
|
||||||
|
IfStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace UpsilonTests
|
||||||
|
{
|
||||||
|
public class IfTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void BasicIfTest()
|
||||||
|
{
|
||||||
|
var input = "if true then val = true end";
|
||||||
|
var script = new Script(input);
|
||||||
|
Assert.Empty(script.Diagnostics.Messages);
|
||||||
|
var actual = script.Evaluate<bool>();
|
||||||
|
Assert.True(actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,8 +47,9 @@ namespace Yc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||||
Console.WriteLine(evaluate);
|
Console.WriteLine(evaluate);
|
||||||
//variables = parsed.Variables;
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue