diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 65597b6..83fad21 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -387,24 +387,16 @@ namespace Upsilon.Binder private BoundExpression BindIndexExpression(IndexExpressionSyntax e) { - var name = e.Identifier.Name; - if (!Scope.TryGetVariable(name, true, out var variable)) + var expression = BindExpression(e.Expression); + if (expression.Type != Type.Table && expression.Type != Type.Unknown) { - _diagnostics.LogUnknownVariable(e.Identifier.Span, name); + //TODO: wrong type diagnostic + throw new Exception(expression.Type.ToString()); return new BoundLiteralExpression(new LuaNull()); } - if (variable.Type != Type.Table) - { - //TODO better error message - _diagnostics.LogUnknownVariable(e.Identifier.Span, name); - return new BoundLiteralExpression(new LuaNull()); - } - - var tableVariable = (TableVariableSymbol) variable; - var outType = tableVariable.OutType; var index = BindExpression(e.Index); - return new BoundIndexExpression(tableVariable, index, outType); + return new BoundIndexExpression(expression, index, Type.Unknown); } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs index 3655265..5d6e8c3 100644 --- a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs @@ -5,14 +5,14 @@ namespace Upsilon.Binder { public class BoundIndexExpression : BoundExpression { - public BoundIndexExpression(TableVariableSymbol identifier, BoundExpression index, Type type) + public BoundIndexExpression(BoundExpression identifier, BoundExpression index, Type type) { Identifier = identifier; Index = index; Type = type; } - public TableVariableSymbol Identifier { get; } + public BoundExpression Identifier { get; } public BoundExpression Index { get; } public override BoundKind Kind => BoundKind.BoundIndexExpression; diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 5411bc1..532be44 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -333,20 +333,36 @@ namespace Upsilon.Evaluator private LuaType EvaluateIndexExpression(BoundIndexExpression e) { - if (!Scope.TryGet(e.Identifier, out var val)) + IIndexable index; + if (e.Identifier.Kind == BoundKind.VariableExpression) { - throw new Exception($"Cannot find variable: '{e.Identifier.Name}'"); + var variableExpression = (BoundVariableExpression) e.Identifier; + var variable = variableExpression.Variable; + if (!Scope.TryGet(variable, out var val)) + { + throw new Exception($"Cannot find variable: '{variable.Name}'"); + } + + if (!(val is IIndexable indexable)) + { + throw new Exception("Variable is not indexable."); + } + index = indexable; + } + else if (e.Identifier.Kind == BoundKind.BoundIndexExpression) + { + var indexExpression = (BoundIndexExpression)e.Identifier; + index = (IIndexable) EvaluateIndexExpression(indexExpression); + } + else + { + throw new Exception(); } - if (!(val is IIndexable indexable)) - { - throw new Exception("Variable is not indexable."); - } - var innerEvaluator = new Evaluator(_diagnostics, Scope, indexable.EvaluatorIdentifier); - var indexer = EvaluateExpression(e.Index); - - return indexable.Get(indexer.ToString(), Identifier); + var innerEvaluator = new Evaluator(_diagnostics, Scope, index.EvaluatorIdentifier); + var indexer = innerEvaluator.EvaluateExpression(e.Index); + return index.Get(indexer.ToString(), Identifier); } } } \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs index 2f8dab2..61111e3 100644 --- a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs @@ -4,15 +4,15 @@ namespace Upsilon.Parser { public class IndexExpressionSyntax : ExpressionSyntax { - public IdentifierToken Identifier { get; } + public ExpressionSyntax Expression { get; } public SyntaxToken OpenBracket { get; } public ExpressionSyntax Index { get; } public SyntaxToken CloseBracket { get; } - public IndexExpressionSyntax(IdentifierToken identifier, SyntaxToken openBracket, ExpressionSyntax index, + public IndexExpressionSyntax(ExpressionSyntax expression, SyntaxToken openBracket, ExpressionSyntax index, SyntaxToken closeBracket) { - Identifier = identifier; + Expression = expression; OpenBracket = openBracket; Index = index; CloseBracket = closeBracket; @@ -21,7 +21,7 @@ namespace Upsilon.Parser public override SyntaxKind Kind => SyntaxKind.IndexExpression; public override IEnumerable ChildNodes() { - yield return Identifier; + yield return Expression; yield return OpenBracket; yield return Index; yield return CloseBracket; diff --git a/Upsilon/Parser/IdentifierToken.cs b/Upsilon/Parser/IdentifierToken.cs index 7e306c9..67620de 100644 --- a/Upsilon/Parser/IdentifierToken.cs +++ b/Upsilon/Parser/IdentifierToken.cs @@ -4,7 +4,8 @@ namespace Upsilon.Parser { public class IdentifierToken : SyntaxToken { - public IdentifierToken(string name, int position, int length) : base(SyntaxKind.Identifier, position, name, null) + public IdentifierToken(string name, int position) + : base(SyntaxKind.Identifier, position, name, null) { Name = name; } diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index 7498e9d..e5e87c3 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -166,7 +166,7 @@ namespace Upsilon.Parser var str = stringBuilder.ToString(); if (kind == SyntaxKind.Identifier) { - return new IdentifierToken(str, start, str.Length); + return new IdentifierToken(str, start); } return new SyntaxToken(kind, start, str, null); } diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index de8f21e..594b346 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -167,7 +167,12 @@ namespace Upsilon.Parser private ExpressionSyntax ParseExpression() { - return ParseBinaryExpression(); + var expression = ParseBinaryExpression(); + while (Current.Kind == SyntaxKind.OpenBracket) + { + expression = ParseIndexExpression(expression); + } + return expression; } private AssignmentExpressionSyntax ParseAssignmentExpression() @@ -214,34 +219,45 @@ namespace Upsilon.Parser private ExpressionSyntax ParsePrimaryExpression() { + ExpressionSyntax expression; switch (Current.Kind) { case SyntaxKind.OpenParenthesis: - return ParseParenthesizedExpression(); + expression = ParseParenthesizedExpression(); + break; case SyntaxKind.Number: - return ParseNumber(); + expression = ParseNumber(); + break; case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: - return ParseBoolean(); + expression = ParseBoolean(); + break; case SyntaxKind.String: - return ParseString(); + expression = ParseString(); + break; case SyntaxKind.Identifier: if (Next.Kind == SyntaxKind.OpenParenthesis) - return ParseFunctionCallExpression(); - if (Next.Kind == SyntaxKind.OpenBracket) - return ParseIndexExpression(); - var token = MatchToken(SyntaxKind.Identifier); - return new VariableExpressionSyntax((IdentifierToken) token); + expression = ParseFunctionCallExpression(); + else + { + var token = MatchToken(SyntaxKind.Identifier); + expression = new VariableExpressionSyntax((IdentifierToken) token); + } + break; case SyntaxKind.OpenBrace: - return ParseTable(); + expression = ParseTable(); + break; case SyntaxKind.NilKeyword: var nilToken = MatchToken(SyntaxKind.NilKeyword); - return new LiteralExpressionSyntax(nilToken, null); + expression = new LiteralExpressionSyntax(nilToken, null); + break; default: _diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier); NextToken(); - return new BadExpressionSyntax(); + expression = new BadExpressionSyntax(); + break; } + return expression; } private ExpressionSyntax ParseFunctionCallExpression() @@ -262,13 +278,12 @@ namespace Upsilon.Parser parameters.ToImmutable(), closeParenthesis); } - private ExpressionSyntax ParseIndexExpression() + private ExpressionSyntax ParseIndexExpression(ExpressionSyntax expression) { - var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier); var openBracket = MatchToken(SyntaxKind.OpenBracket); var index = ParseExpression(); var closeBracket = MatchToken(SyntaxKind.CloseBracket); - return new IndexExpressionSyntax(identifier, openBracket, index, closeBracket); + return new IndexExpressionSyntax(expression, openBracket, index, closeBracket); } private ExpressionSyntax ParseParenthesizedExpression() diff --git a/UpsilonTests/TableTests.cs b/UpsilonTests/TableTests.cs index 6c76c1d..3c57738 100644 --- a/UpsilonTests/TableTests.cs +++ b/UpsilonTests/TableTests.cs @@ -57,6 +57,27 @@ return table[""test""] Assert.Null(evaluated); } + [Fact] + public void NestedTables() + { + const string input = @" +table = { + { + { + 100, 600, 900 + }, + {} + } +} +return table[1][1][2] +"; + var script = new Script(input); + Assert.Empty(script.Diagnostics.Messages); + var evaluated = script.Evaluate(); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal(600, evaluated); + } + [Fact] public void FunctionsInTable() { diff --git a/Ycicle/Program.cs b/Ycicle/Program.cs index 1ec7170..ba447d4 100644 --- a/Ycicle/Program.cs +++ b/Ycicle/Program.cs @@ -31,6 +31,7 @@ namespace Ycicle Console.ResetColor(); continue; } + //Console.WriteLine(script.PrettyPrintSyntaxTree()); var evaluate = script.Evaluate(); if (script.Diagnostics.Messages.Count > 0)