diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 7c30107..48ca93d 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.Parser; @@ -253,8 +252,7 @@ namespace Upsilon.Binder if (assignment.Type == Type.Table) { var tableExpression = (BoundTableExpression) assignment; - variable = new TableVariableSymbol(name, tableExpression.ValueType, isLocal, - tableExpression.Expressions); + variable = new TableVariableSymbol(name, isLocal, tableExpression.Expressions); } else { @@ -470,23 +468,31 @@ namespace Upsilon.Binder private BoundExpression BindTableExpression(TableExpressionSyntax e) { - var keyType = Type.Unknown; - var valueType = Type.Unknown; var statements = ImmutableArray.CreateBuilder(); var s = Scope; Scope = BoundScope.WithReadOnlyScope(s); + var innerVariables = new Dictionary(); + var current = 0; + foreach (var expressionSyntax in e.Expressions) { var bound = BindStatement((StatementSyntax) expressionSyntax); + if (bound.Kind == BoundKind.BoundExpressionStatement) + { + var boundExpression = (BoundExpressionStatement)bound; + current++; + innerVariables.Add(current.ToString(), + new VariableSymbol(current.ToString(), boundExpression.Expression.Type, false)); + } statements.Add(bound); } - var innerVariables = Scope.Variables; + innerVariables = innerVariables.Union(Scope.Variables).ToDictionary(k => k.Key, v => v.Value); Scope = s; - return new BoundTableExpression(keyType, valueType, innerVariables, statements.ToImmutable(), e.Span); + return new BoundTableExpression(innerVariables, statements.ToImmutable(), e.Span); } - private BoundExpression BindIndexExpression(IndexExpressionSyntax e) + private BoundExpression BindIndexExpression(IndexExpressionSyntax e, bool isAssignment = false) { var expression = BindExpression(e.Expression); @@ -499,12 +505,37 @@ namespace Upsilon.Binder switch (expression.Type) { case Type.Table: + if (isAssignment) + { + return new BoundIndexExpression(expression, index, Type.Unknown, e.Span); + } if (expression.Kind == BoundKind.BoundTableExpression && index.Kind == BoundKind.BoundLiteralExpression) { - var table = (BoundTableExpression)expression; + var table = (BoundTableExpression)expression; + var realIndex = (BoundLiteralExpression) index; + var variableDic = table.Expressions; + if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable)) + { + return new BoundIndexExpression(expression, index, variable.Type, e.Span); + } + + _diagnostics.LogError($"No variable '{realIndex.Value}' found in table.", + e.Span); + } + else if (expression.Kind == BoundKind.VariableExpression && + index.Kind == BoundKind.BoundLiteralExpression) + { + var table = (BoundVariableExpression)expression; + var realTable = table.Variable; var realIndex = (BoundLiteralExpression) index; - var variable = table.Expressions[realIndex.Value.ToString()]; - return new BoundIndexExpression(expression, index, variable.Type, e.Span); + var variableDic = ((TableVariableSymbol) realTable.VariableSymbol).Variables; + if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable)) + { + return new BoundIndexExpression(expression, index, variable.Type, e.Span); + } + + _diagnostics.LogError($"No variable '{realIndex.Value}' found in table '{realTable.VariableSymbol.Name}'.", + e.Span); } return new BoundIndexExpression(expression, index, Type.Unknown, e.Span); case Type.UserData: @@ -518,13 +549,17 @@ namespace Upsilon.Binder } } - private BoundExpression BindFullStopIndexExpression(FullStopIndexExpressionSyntax e) + private BoundExpression BindFullStopIndexExpression(FullStopIndexExpressionSyntax e, bool isAssignment = false) { var expression = BindExpression(e.Expression); var index = e.Index.Name; switch (expression.Type) { case Type.Table: + if (isAssignment) + { + return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); + } if (expression.Kind == BoundKind.BoundTableExpression) { var table = (BoundTableExpression)expression; @@ -532,7 +567,7 @@ namespace Upsilon.Binder { return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span); } - _diagnostics.LogError($"No variable {index} found in table.", e.Span); + _diagnostics.LogError($"No variable '{index}' found in table.", e.Span); } if (expression.Kind == BoundKind.VariableExpression) { @@ -544,7 +579,7 @@ namespace Upsilon.Binder return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span); } - _diagnostics.LogError($"No variable {index} found in table {realTable.VariableSymbol.Name}.", + _diagnostics.LogError($"No variable '{index}' found in table '{realTable.VariableSymbol.Name}'.", e.Span); } return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); @@ -562,12 +597,41 @@ namespace Upsilon.Binder private BoundStatement BindTableAssignmentStatement(TableAssigmentStatementSyntax e) { BoundExpression indexableExpression; - if (e.TableExpression.Kind == SyntaxKind.IndexExpression) - indexableExpression = (BoundIndexExpression)BindExpression(e.TableExpression); - else - indexableExpression = (BoundFullStopIndexExpression)BindExpression(e.TableExpression); - var value = BindExpression(e.Expression); + + if (e.TableExpression.Kind == SyntaxKind.IndexExpression) + { + var indexable = + (BoundIndexExpression) BindIndexExpression((IndexExpressionSyntax) e.TableExpression, true); + + if (indexable.Identifier.Kind == BoundKind.VariableExpression && + indexable.Index.Kind == BoundKind.BoundLiteralExpression) + { + var variable = (BoundVariableExpression)indexable.Identifier; + var index = (BoundLiteralExpression)indexable.Index; + ((TableVariableSymbol)variable.Variable.VariableSymbol).Variables.Add(index.Value.ToString(), + new VariableSymbol(index.Value.ToString(), value.Type, false)); + } + indexableExpression = indexable; + } + else + { + var indexable = + (BoundFullStopIndexExpression) BindFullStopIndexExpression( + (FullStopIndexExpressionSyntax) e.TableExpression, true); + + if (indexable.Expression.Kind == BoundKind.VariableExpression) + { + var variable = (BoundVariableExpression)indexable.Expression; + if (variable.Type == Type.Table) + { + ((TableVariableSymbol)variable.Variable.VariableSymbol).Variables.Add(indexable.Index, + new VariableSymbol(indexable.Index, value.Type, false)); + } + } + indexableExpression = indexable; + } + return new BoundTableAssigmentStatement(indexableExpression, value, e.Span); } diff --git a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs index c901c9e..23f1887 100644 --- a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs @@ -7,11 +7,9 @@ namespace Upsilon.Binder { public class BoundTableExpression : BoundExpression { - public BoundTableExpression(Type keyType, Type valueType, Dictionary expressions, + public BoundTableExpression(Dictionary expressions, ImmutableArray statements, TextSpan span) : base(span) { - KeyType = keyType; - ValueType = valueType; Expressions = expressions; Statements = statements; } @@ -30,8 +28,6 @@ namespace Upsilon.Binder public override Type Type => Type.Table; - public Type KeyType { get; } - public Type ValueType { get; } public Dictionary Expressions { get; } public ImmutableArray Statements { get; } diff --git a/Upsilon/Binder/VariableSymbol.cs b/Upsilon/Binder/VariableSymbol.cs index c527588..eaac21e 100644 --- a/Upsilon/Binder/VariableSymbol.cs +++ b/Upsilon/Binder/VariableSymbol.cs @@ -34,13 +34,11 @@ namespace Upsilon.Binder public class TableVariableSymbol : VariableSymbol { - public Type OutType { get; } public Dictionary Variables { get; } - public TableVariableSymbol(string name, Type outType, bool local, Dictionary variables) + public TableVariableSymbol(string name, bool local, Dictionary variables) :base (name, Type.Table, local) { - OutType = outType; Variables = variables; } }