From df8c7b99c9830178df18bf5401db595fc85e9749 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Tue, 20 Nov 2018 14:05:34 +0100 Subject: [PATCH] Made indexable also work with full stop index --- Upsilon/Binder/Binder.cs | 30 ++++++++++++++- .../BoundExpressions/BoundIndexExpression.cs | 15 ++++++++ Upsilon/Binder/BoundKind.cs | 3 +- .../BoundTableAssigmentStatement.cs | 4 +- Upsilon/Evaluator/Evaluator.cs | 38 ++++++++++++++++--- .../ExpressionSyntax/IndexExpressionSyntax.cs | 22 +++++++++++ Upsilon/Parser/Lexer.cs | 2 + Upsilon/Parser/Parser.cs | 25 ++++++++++-- Upsilon/Parser/SyntaxKind.cs | 4 +- Ycicle/Program.cs | 2 +- 10 files changed, 130 insertions(+), 15 deletions(-) diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 8a94205..30ce4c6 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.Parser; +using Upsilon.Text; using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Binder @@ -83,6 +84,8 @@ namespace Upsilon.Binder return BindTableExpression((TableExpressionSyntax) e); case SyntaxKind.IndexExpression: return BindIndexExpression((IndexExpressionSyntax) e); + case SyntaxKind.FullStopIndexExpression: + return BindFullStopIndexExpression((FullStopIndexExpressionSyntax) e); case SyntaxKind.FunctionExpression: return BindFunctionExpression((FunctionExpressionSyntax) e); case SyntaxKind.BadExpression: @@ -452,11 +455,34 @@ namespace Upsilon.Binder } } + private BoundExpression BindFullStopIndexExpression(FullStopIndexExpressionSyntax e) + { + var expression = BindExpression(e.Expression); + var index = e.Index.Name; + switch (expression.Type) + { + case Type.Table: + case Type.UserData: + case Type.Unknown: + return new BoundFullStopIndexExpression(expression, index); + case Type.String: + return new BoundFullStopIndexExpression(expression, index); + default: + _diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span); + return new BoundLiteralExpression(new LuaNull()); + } + } + private BoundStatement BindTableAssignmentStatement(TableAssigmentStatementSyntax e) { - var tableIndexExpression = (BoundIndexExpression)BindExpression(e.TableExpression); + BoundExpression indexableExpression; + if (e.TableExpression.Kind == SyntaxKind.IndexExpression) + indexableExpression = (BoundIndexExpression)BindExpression(e.TableExpression); + else + indexableExpression = (BoundFullStopIndexExpression)BindExpression(e.TableExpression); + var value = BindExpression(e.Expression); - return new BoundTableAssigmentStatement(tableIndexExpression, value); + return new BoundTableAssigmentStatement(indexableExpression, value); } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs index 5d6e8c3..7c1b6a9 100644 --- a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs @@ -18,4 +18,19 @@ namespace Upsilon.Binder public override BoundKind Kind => BoundKind.BoundIndexExpression; public override Type Type { get; } } + + public class BoundFullStopIndexExpression : BoundExpression + { + public BoundExpression Expression { get; } + public string Index { get; } + + public BoundFullStopIndexExpression(BoundExpression expression, string index) + { + Expression = expression; + Index = index; + } + + public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression; + public override Type Type => Type.Unknown; + } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index 14be700..2228a90 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -22,6 +22,7 @@ namespace Upsilon.Binder BoundPromise, BoundReturnStatement, BoundFunctionAssignmentStatement, - BoundTableAssigmentStatement + BoundTableAssigmentStatement, + BoundFullstopIndexExpression } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs index 025a2ee..a578afa 100644 --- a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs @@ -2,10 +2,10 @@ namespace Upsilon.Binder { public class BoundTableAssigmentStatement : BoundStatement { - public BoundIndexExpression TableIndexExpression { get; } + public BoundExpression TableIndexExpression { get; } public BoundExpression Value { get; } - public BoundTableAssigmentStatement(BoundIndexExpression tableIndexExpression, BoundExpression value) + public BoundTableAssigmentStatement(BoundExpression tableIndexExpression, BoundExpression value) { TableIndexExpression = tableIndexExpression; Value = value; diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 02b1659..7c074c6 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -71,6 +71,7 @@ namespace Upsilon.Evaluator case BoundKind.BoundFunctionExpression: case BoundKind.BoundTableExpression: case BoundKind.BoundIndexExpression: + case BoundKind.BoundFullstopIndexExpression: _lastValue = EvaluateExpression((BoundExpression) b); break; case BoundKind.BoundAssignmentStatement: @@ -148,6 +149,8 @@ namespace Upsilon.Evaluator return EvaluateBoundFunctionStatement((BoundFunctionExpression) e); case BoundKind.BoundPromise: return EvaluateUnboundFunctionStatement((UnboundFunctionExpression) e); + case BoundKind.BoundFullstopIndexExpression: + return EvaluateFullStopIndexExpression((BoundFullStopIndexExpression) e); default: throw new NotImplementedException(); } @@ -343,16 +346,41 @@ namespace Upsilon.Evaluator { scope = scopeOwner.EvaluationScope; } - - var evaluator = new Evaluator(_diagnostics, scope); - var indexer = evaluator.EvaluateExpression(e.Index); + var indexer = EvaluateExpression(e.Index); return indexable.Get(indexer.ToString(), scope); } + private LuaType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e) + { + var variable = EvaluateExpression(e.Expression); + if (!(variable is IIndexable indexable)) + { + throw new Exception("Variable is not indexable."); + } + + var scope = Scope; + if (variable is IScopeOwner scopeOwner) + { + scope = scopeOwner.EvaluationScope; + } + + return indexable.Get(e.Index, scope); + } private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e) { - var table = EvaluateExpression(e.TableIndexExpression.Identifier); - var index = EvaluateExpression(e.TableIndexExpression.Index); + LuaType table; + LuaType index; + if (e.TableIndexExpression.Kind == BoundKind.BoundIndexExpression) + { + table = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Identifier); + index = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Index); + } + else + { + table = EvaluateExpression(((BoundFullStopIndexExpression)e.TableIndexExpression).Expression); + index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToLuaType(); + } + var value = EvaluateExpression(e.Value); if (!(table is IIndexable indexable)) { diff --git a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs index 61111e3..f429461 100644 --- a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs @@ -27,4 +27,26 @@ namespace Upsilon.Parser yield return CloseBracket; } } + + public class FullStopIndexExpressionSyntax : ExpressionSyntax + { + public ExpressionSyntax Expression { get; } + public SyntaxToken FullStop { get; } + public IdentifierToken Index { get; } + + public FullStopIndexExpressionSyntax(ExpressionSyntax expression, SyntaxToken fullStop, IdentifierToken index) + { + Expression = expression; + FullStop = fullStop; + Index = index; + } + + public override SyntaxKind Kind => SyntaxKind.FullStopIndexExpression; + public override IEnumerable ChildNodes() + { + yield return Expression; + yield return FullStop; + yield return Index; + } + } } \ No newline at end of file diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index e5e87c3..d8b62d0 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -74,6 +74,8 @@ namespace Upsilon.Parser return new SyntaxToken(SyntaxKind.OpenBracket, _position, "[", null); case ']': return new SyntaxToken(SyntaxKind.CloseBracket, _position, "]", null); + case '.': + return new SyntaxToken(SyntaxKind.FullStop, _position, ".", null); case ',': return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); case '"': diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index e0dc927..4b09347 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -178,6 +178,10 @@ namespace Upsilon.Parser { return ParseTableAssignmentExpression(expression); } + if (expression.Kind == SyntaxKind.FullStopIndexExpression && Current.Kind == SyntaxKind.Equals) + { + return ParseTableAssignmentExpression(expression); + } return new ExpressionStatementSyntax(expression); } @@ -199,12 +203,15 @@ namespace Upsilon.Parser { expression = ParseBinaryExpression(); } - while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis) + while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis || + Current.Kind == SyntaxKind.FullStop) { if (Current.Kind == SyntaxKind.OpenBracket) expression = ParseIndexExpression(expression); else if (Current.Kind == SyntaxKind.OpenParenthesis) expression = ParseFunctionCallExpression(expression); + else if (Current.Kind == SyntaxKind.FullStop) + expression = ParseFullStopIndexExpression(expression); } return expression; } @@ -317,12 +324,24 @@ namespace Upsilon.Parser private ExpressionSyntax ParseIndexExpression(ExpressionSyntax expression) { - var openBracket = MatchToken(SyntaxKind.OpenBracket); - var index = ParseExpression(); + var openBracket = MatchToken(SyntaxKind.OpenBracket); + var index = ParseExpression(); var closeBracket = MatchToken(SyntaxKind.CloseBracket); return new IndexExpressionSyntax(expression, openBracket, index, closeBracket); } + private ExpressionSyntax ParseFullStopIndexExpression(ExpressionSyntax expression) + { + var fullStop = MatchToken(SyntaxKind.FullStop); + var index = MatchToken(SyntaxKind.Identifier); + if (index is IdentifierToken identifier) + { + return new FullStopIndexExpressionSyntax(expression, fullStop, identifier); + } + _diagnostics.LogBadCharacter(expression.Span, SyntaxKind.Identifier); + return new BadExpressionSyntax(); + } + private ExpressionSyntax ParseParenthesizedExpression() { var l = MatchToken(SyntaxKind.OpenParenthesis); diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index 2ed9f88..f16ace0 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -21,6 +21,7 @@ namespace Upsilon.Parser Tilde, TildeEquals, Comma, + FullStop, String, OpenBrace, CloseBrace, @@ -56,6 +57,7 @@ namespace Upsilon.Parser BadExpression, TableExpression, IndexExpression, + FullStopIndexExpression, // script unit ScriptUnit, @@ -69,6 +71,6 @@ namespace Upsilon.Parser FunctionExpression, ReturnStatement, FunctionAssignmentStatement, - TableAssignmentStatement + TableAssignmentStatement, } } \ No newline at end of file diff --git a/Ycicle/Program.cs b/Ycicle/Program.cs index 46c05d8..bc72ed7 100644 --- a/Ycicle/Program.cs +++ b/Ycicle/Program.cs @@ -32,7 +32,7 @@ namespace Ycicle continue; } //Console.WriteLine(script.PrettyPrintSyntaxTree()); - var evaluate = script.Evaluate(); + var evaluate = script.Evaluate(); if (script.Diagnostics.Messages.Count > 0) {