diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 2889067..7d5eb4c 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -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(); + foreach (var statementSyntax in e.Statements) + { + var bound = BindStatement(statementSyntax); + arr.Add(bound); + } + return new BoundBlockStatement(arr.ToImmutable()); } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundBlockStatement.cs b/Upsilon/Binder/BoundBlockStatement.cs new file mode 100644 index 0000000..beecbbb --- /dev/null +++ b/Upsilon/Binder/BoundBlockStatement.cs @@ -0,0 +1,16 @@ +using System.Collections.Immutable; + +namespace Upsilon.Binder +{ + public class BoundBlockStatement : BoundStatement + { + public BoundBlockStatement(ImmutableArray statements) + { + Statements = statements; + } + + public override BoundKind Kind => BoundKind.BoundBlockStatement; + + public ImmutableArray Statements { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index c724c28..c7d05bc 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -11,6 +11,7 @@ namespace Upsilon.Binder // Statements BoundAssignmentStatement, - BoundExpressionStatement + BoundExpressionStatement, + BoundBlockStatement } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 0f1c1e8..c345205 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -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 _variables = new Dictionary(); 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); + } + } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 9b00a95..ad96311 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -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; } diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index b02f282..8682642 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -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(); + 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(); diff --git a/Upsilon/Parser/StatementSyntax/AssignmentExpressionSyntax.cs b/Upsilon/Parser/StatementSyntax/AssignmentExpressionSyntax.cs index 1e941da..9eed395 100644 --- a/Upsilon/Parser/StatementSyntax/AssignmentExpressionSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/AssignmentExpressionSyntax.cs @@ -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; } diff --git a/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs new file mode 100644 index 0000000..f4f30c6 --- /dev/null +++ b/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs @@ -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 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 Statements { get; } + public SyntaxToken EndToken { get; } + public override SyntaxKind Kind => SyntaxKind.BlockStatement; + public override IEnumerable ChildNodes() + { + return Statements; + } + } +} \ No newline at end of file diff --git a/Upsilon/Parser/StatementSyntax/ScriptSyntax.cs b/Upsilon/Parser/StatementSyntax/ScriptSyntax.cs deleted file mode 100644 index 8b45ca4..0000000 --- a/Upsilon/Parser/StatementSyntax/ScriptSyntax.cs +++ /dev/null @@ -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 ChildNodes() - { - yield return Statement; - yield return EndOfFileToken; - } - } -} \ No newline at end of file diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index 95479fa..6d33808 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -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 } } \ No newline at end of file