Allow for blocks of statements, instead of only single statements
This commit is contained in:
parent
ec7a32240f
commit
e9391193bb
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.Parser;
|
||||
using Type = Upsilon.BaseTypes.Type;
|
||||
|
@ -16,9 +17,9 @@ namespace Upsilon.Binder
|
|||
_scope = new BoundScope(parentScope);
|
||||
}
|
||||
|
||||
public BoundScript BindScript(ScriptSyntax e)
|
||||
public BoundScript BindScript(BlockStatementSyntax e)
|
||||
{
|
||||
var bound = BindStatement(e.Statement);
|
||||
var bound = BindStatement(e);
|
||||
return new BoundScript(bound);
|
||||
}
|
||||
|
||||
|
@ -28,11 +29,13 @@ namespace Upsilon.Binder
|
|||
{
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return BindExpressionStatement((ExpressionStatementSyntax) s);
|
||||
case SyntaxKind.AssignmentExpression:
|
||||
case SyntaxKind.AssignmentStatement:
|
||||
return BindAssignmentStatement((AssignmentExpressionSyntax) s);
|
||||
case SyntaxKind.BlockStatement:
|
||||
return BindBlockStatement((BlockStatementSyntax) s);
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotImplementedException(s.Kind.ToString());
|
||||
}
|
||||
|
||||
public BoundExpression BindExpression(ExpressionSyntax e)
|
||||
|
@ -116,6 +119,18 @@ namespace Upsilon.Binder
|
|||
return BindExpression(e.Expression);
|
||||
}
|
||||
|
||||
private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
|
||||
{
|
||||
var name = e.Identifier.Name;
|
||||
if (!_scope.TryGetVariable(name, out var variable))
|
||||
{
|
||||
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
||||
return new BoundLiteralExpression(null, Type.Nil);
|
||||
}
|
||||
|
||||
return new BoundVariableExpression(variable);
|
||||
}
|
||||
|
||||
private BoundStatement BindExpressionStatement(ExpressionStatementSyntax s)
|
||||
{
|
||||
var exp = BindExpression(s.Expression);
|
||||
|
@ -148,16 +163,16 @@ namespace Upsilon.Binder
|
|||
return new BoundVariableAssignment(variable, boundExpression);
|
||||
}
|
||||
|
||||
private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
|
||||
{
|
||||
var name = e.Identifier.Name;
|
||||
if (!_scope.TryGetVariable(name, out var variable))
|
||||
{
|
||||
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
||||
return new BoundLiteralExpression(null, Type.Nil);
|
||||
}
|
||||
|
||||
return new BoundVariableExpression(variable);
|
||||
private BoundStatement BindBlockStatement(BlockStatementSyntax e)
|
||||
{
|
||||
var arr = ImmutableArray.CreateBuilder<BoundStatement>();
|
||||
foreach (var statementSyntax in e.Statements)
|
||||
{
|
||||
var bound = BindStatement(statementSyntax);
|
||||
arr.Add(bound);
|
||||
}
|
||||
return new BoundBlockStatement(arr.ToImmutable());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Immutable;
|
||||
|
||||
namespace Upsilon.Binder
|
||||
{
|
||||
public class BoundBlockStatement : BoundStatement
|
||||
{
|
||||
public BoundBlockStatement(ImmutableArray<BoundStatement> statements)
|
||||
{
|
||||
Statements = statements;
|
||||
}
|
||||
|
||||
public override BoundKind Kind => BoundKind.BoundBlockStatement;
|
||||
|
||||
public ImmutableArray<BoundStatement> Statements { get; }
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace Upsilon.Binder
|
|||
|
||||
// Statements
|
||||
BoundAssignmentStatement,
|
||||
BoundExpressionStatement
|
||||
BoundExpressionStatement,
|
||||
BoundBlockStatement
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
private readonly Diagnostics _diagnostics;
|
||||
private object _value;
|
||||
public Script Script { get; }
|
||||
private Script Script { get; }
|
||||
private readonly Dictionary<VariableSymbol, object> _variables = new Dictionary<VariableSymbol, object>();
|
||||
|
||||
public Evaluator(Script script, Diagnostics diagnostics)
|
||||
|
@ -37,12 +37,16 @@ namespace Upsilon.Evaluator
|
|||
case BoundKind.BoundAssignmentStatement:
|
||||
EvaluateAssignmentStatement((BoundVariableAssignment) e);
|
||||
break;
|
||||
case BoundKind.BoundBlockStatement:
|
||||
EvaluateBoundBlockStatement((BoundBlockStatement) e);
|
||||
break;
|
||||
default:
|
||||
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void EvaluateExpressionStatement(BoundExpressionStatement e)
|
||||
{
|
||||
_value = EvaluateExpression(e.Expression);
|
||||
|
@ -104,12 +108,11 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
}
|
||||
|
||||
private object EvaluateAssignmentStatement(BoundVariableAssignment e)
|
||||
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
||||
{
|
||||
var val = EvaluateExpression(e.BoundExpression);
|
||||
_variables[e.Variable] = val;
|
||||
_value = val;
|
||||
return val;
|
||||
}
|
||||
|
||||
private object EvaluateVariableExpression(BoundVariableExpression e)
|
||||
|
@ -117,5 +120,12 @@ namespace Upsilon.Evaluator
|
|||
return _variables[e.Variable];
|
||||
}
|
||||
|
||||
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
|
||||
{
|
||||
foreach (var boundStatement in boundBlockStatement.Statements)
|
||||
{
|
||||
EvaluateStatement(boundStatement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
private SourceText ScriptString { get; }
|
||||
private Evaluator Evaluator { get; }
|
||||
private readonly ScriptSyntax _parsed;
|
||||
private readonly BlockStatementSyntax _parsed;
|
||||
public Diagnostics Diagnostics { get; }
|
||||
private Binder.Binder Binder { get; }
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ namespace Upsilon.Parser
|
|||
_diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
public static ScriptSyntax Parse(string text, Diagnostics diagnostics)
|
||||
public static BlockStatementSyntax Parse(string text, Diagnostics diagnostics)
|
||||
{
|
||||
var tokens = Lexer.Lex(text, diagnostics);
|
||||
return new Parser(tokens, diagnostics).ParseScriptSyntax();
|
||||
return (BlockStatementSyntax) new Parser(tokens, diagnostics).ParseScriptSyntax();
|
||||
}
|
||||
|
||||
private SyntaxToken Current => Get(0);
|
||||
|
@ -47,11 +47,10 @@ namespace Upsilon.Parser
|
|||
return new SyntaxToken(kind, Current.Span.Start, "", null);
|
||||
}
|
||||
|
||||
public ScriptSyntax ParseScriptSyntax()
|
||||
public StatementSyntax ParseScriptSyntax()
|
||||
{
|
||||
var statement = ParseStatement();
|
||||
var eof = MatchToken(SyntaxKind.EndOfFile);
|
||||
return new ScriptSyntax(statement, eof);
|
||||
var statement = ParseBlockStatement();
|
||||
return statement;
|
||||
}
|
||||
|
||||
public StatementSyntax ParseStatement()
|
||||
|
@ -68,6 +67,18 @@ namespace Upsilon.Parser
|
|||
return ParseExpressionStatement();
|
||||
}
|
||||
|
||||
public StatementSyntax ParseBlockStatement()
|
||||
{
|
||||
var statements = ImmutableArray.CreateBuilder<StatementSyntax>();
|
||||
while (Current.Kind != SyntaxKind.EndKeyword && Current.Kind != SyntaxKind.EndOfFile)
|
||||
{
|
||||
var next = ParseStatement();
|
||||
statements.Add(next);
|
||||
}
|
||||
var endToken = NextToken();
|
||||
return new BlockStatementSyntax(statements.ToImmutable(), endToken);
|
||||
}
|
||||
|
||||
public ExpressionStatementSyntax ParseExpressionStatement()
|
||||
{
|
||||
var expression = ParseExpression();
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Upsilon.Parser
|
|||
Expression = expression;
|
||||
}
|
||||
|
||||
public override SyntaxKind Kind => SyntaxKind.AssignmentExpression;
|
||||
public override SyntaxKind Kind => SyntaxKind.AssignmentStatement;
|
||||
|
||||
public SyntaxToken LocalToken { get; }
|
||||
public IdentifierToken Identifier { get; }
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.Parser
|
||||
{
|
||||
public sealed class BlockStatementSyntax : StatementSyntax
|
||||
{
|
||||
public BlockStatementSyntax(ImmutableArray<StatementSyntax> statements, SyntaxToken endToken)
|
||||
{
|
||||
Statements = statements;
|
||||
EndToken = endToken;
|
||||
var first = statements.FirstOrDefault();
|
||||
if (first != null)
|
||||
Span = new TextSpan(first.Span.Start, endToken.Span.End);
|
||||
}
|
||||
|
||||
public ImmutableArray<StatementSyntax> Statements { get; }
|
||||
public SyntaxToken EndToken { get; }
|
||||
public override SyntaxKind Kind => SyntaxKind.BlockStatement;
|
||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||
{
|
||||
return Statements;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Upsilon.Parser
|
||||
{
|
||||
public class ScriptSyntax : StatementSyntax
|
||||
{
|
||||
public ScriptSyntax(StatementSyntax statement, SyntaxToken endOfFileToken)
|
||||
{
|
||||
Statement = statement;
|
||||
EndOfFileToken = endOfFileToken;
|
||||
}
|
||||
|
||||
public override SyntaxKind Kind => SyntaxKind.ScriptUnit;
|
||||
|
||||
public StatementSyntax Statement { get; }
|
||||
public SyntaxToken EndOfFileToken { get; }
|
||||
|
||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||
{
|
||||
yield return Statement;
|
||||
yield return EndOfFileToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ namespace Upsilon.Parser
|
|||
BinaryExpression,
|
||||
LiteralExpression,
|
||||
ParenthesizedExpression,
|
||||
AssignmentExpression,
|
||||
AssignmentStatement,
|
||||
VariableExpression,
|
||||
BadExpression,
|
||||
|
||||
|
@ -44,6 +44,7 @@ namespace Upsilon.Parser
|
|||
ScriptUnit,
|
||||
|
||||
// statements
|
||||
ExpressionStatement
|
||||
ExpressionStatement,
|
||||
BlockStatement
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue