diff --git a/Upsilon/BaseTypes/LuaTable.cs b/Upsilon/BaseTypes/LuaTable.cs index dbb340e..8d6fbdf 100644 --- a/Upsilon/BaseTypes/LuaTable.cs +++ b/Upsilon/BaseTypes/LuaTable.cs @@ -10,13 +10,6 @@ namespace Upsilon.BaseTypes private readonly Dictionary _map; public int EvaluatorIdentifier { get; } - public LuaTable(int scopeIdentifier) - { - EvaluatorIdentifier = scopeIdentifier; - _map = new Dictionary(); - _variableLookup = new Dictionary(); - } - public LuaTable(Dictionary map, int scopeIdentifier) { _map = map; diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 83fad21..f778a26 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -154,15 +154,13 @@ namespace Upsilon.Binder private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e) { - var name = e.Identifier.Name; - if (!Scope.TryGetVariable(name, true, out var functionObj)) + var expression = BindExpression(e.Identifier); + if (expression.Type != Type.Function && expression.Type != Type.Unknown) { - _diagnostics.LogUnknownVariable(e.Identifier.Span, name); - return new BoundLiteralExpression(new LuaNull()); + //TODO Better error + throw new Exception(); } - var function = (FunctionVariableSymbol) functionObj; - var parameters = ImmutableArray.CreateBuilder(); foreach (var expressionSyntax in e.Parameters) { @@ -170,27 +168,32 @@ namespace Upsilon.Binder parameters.Add(bound); } - if (!function.IsBound) + if (expression.Kind == BoundKind.VariableExpression) { - Scope = new BoundScope(Scope); - for (var index = 0; index < function.Parameters.Length; index++) + var variableExpression =(BoundVariableExpression) expression; + var function = (FunctionVariableSymbol)variableExpression.Variable; + if (!function.IsBound) { - var functionVariable = function.Parameters[index]; - var callingVariable = parameters[index]; - functionVariable.Type = callingVariable.Type; - Scope.SetVariable(functionVariable); - } + Scope = new BoundScope(Scope); + for (var index = 0; index < function.Parameters.Length; index++) + { + var functionVariable = function.Parameters[index]; + var callingVariable = parameters[index]; + functionVariable.Type = callingVariable.Type; + Scope.SetVariable(functionVariable); + } - var unboundFunctionStatement = _unboundFunctions[function]; - unboundFunctionStatement.Block = - (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock); - Scope = Scope.ParentScope; - function.IsBound = true; - _unboundFunctions.Remove(function); + var unboundFunctionStatement = _unboundFunctions[function]; + unboundFunctionStatement.Block = + (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock); + Scope = Scope.ParentScope; + function.IsBound = true; + _unboundFunctions.Remove(function); + } } //TODO: validate parameters - return new BoundFunctionCallExpression(function, parameters.ToImmutable()); + return new BoundFunctionCallExpression(expression, parameters.ToImmutable()); } private BoundExpression BindVariableExpression(VariableExpressionSyntax e) diff --git a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs index 9e0e1e2..8949f48 100644 --- a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs @@ -5,10 +5,10 @@ namespace Upsilon.Binder { public class BoundFunctionCallExpression : BoundExpression { - public FunctionVariableSymbol Identifier { get; } + public BoundExpression Identifier { get; } public ImmutableArray Parameters { get; } - public BoundFunctionCallExpression(FunctionVariableSymbol identifier, ImmutableArray parameters) + public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray parameters) { Identifier = identifier; Parameters = parameters; diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 532be44..8a6a5dd 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -278,14 +278,12 @@ namespace Upsilon.Evaluator private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression) { - var name = boundFunctionCallExpression.Identifier; - if (!Scope.TryGet(name, out var functionObj)) + var variable = EvaluateExpression(boundFunctionCallExpression.Identifier); + if (!(variable is LuaFunction function)) { - throw new Exception("Cannot find function: " + name.Name); + throw new Exception("Variable is not a function."); } - var function = (LuaFunction) functionObj; - var innerEvaluator = new Evaluator(_diagnostics, Scope); for (var i = 0; i < function.Parameters.Length; i++) { @@ -318,6 +316,13 @@ namespace Upsilon.Evaluator var value = EvaluateExpression(assignment.BoundExpression); dic.Add(key, value); } + else if (boundStatement.Kind == BoundKind.BoundFunctionStatement) + { + var function = (BoundFunctionStatement) boundStatement; + var key = function.Identifier; + var func = new LuaFunction(function.Parameters, function.Block); + dic.Add(key, func); + } else { innerEvaluator.EvaluateStatement(boundStatement); @@ -333,36 +338,16 @@ namespace Upsilon.Evaluator private LuaType EvaluateIndexExpression(BoundIndexExpression e) { - IIndexable index; - if (e.Identifier.Kind == BoundKind.VariableExpression) + var variable = EvaluateExpression(e.Identifier); + if (!(variable is IIndexable indexable)) { - 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(); + throw new Exception("Variable is not indexable."); } - var innerEvaluator = new Evaluator(_diagnostics, Scope, index.EvaluatorIdentifier); + var innerEvaluator = new Evaluator(_diagnostics, Scope, indexable.EvaluatorIdentifier); var indexer = innerEvaluator.EvaluateExpression(e.Index); - return index.Get(indexer.ToString(), Identifier); + return indexable.Get(indexer.ToString(), Identifier); } } } \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs index 2b29309..733815a 100644 --- a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs @@ -5,12 +5,12 @@ namespace Upsilon.Parser { public class FunctionCallExpressionSyntax : ExpressionSyntax { - public IdentifierToken Identifier { get; } + public ExpressionSyntax Identifier { get; } public SyntaxToken OpenParenthesis { get; } public ImmutableArray Parameters { get; } public SyntaxToken CloseParenthesis { get; } - public FunctionCallExpressionSyntax(IdentifierToken identifier, SyntaxToken openParenthesis, + public FunctionCallExpressionSyntax(ExpressionSyntax identifier, SyntaxToken openParenthesis, ImmutableArray parameters, SyntaxToken closeParenthesis) { Identifier = identifier; diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 594b346..c57d679 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -168,9 +168,12 @@ namespace Upsilon.Parser private ExpressionSyntax ParseExpression() { var expression = ParseBinaryExpression(); - while (Current.Kind == SyntaxKind.OpenBracket) + while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis) { - expression = ParseIndexExpression(expression); + if (Current.Kind == SyntaxKind.OpenBracket) + expression = ParseIndexExpression(expression); + else if (Current.Kind == SyntaxKind.OpenParenthesis) + expression = ParseFunctionCallExpression(expression); } return expression; } @@ -236,13 +239,8 @@ namespace Upsilon.Parser expression = ParseString(); break; case SyntaxKind.Identifier: - if (Next.Kind == SyntaxKind.OpenParenthesis) - expression = ParseFunctionCallExpression(); - else - { - var token = MatchToken(SyntaxKind.Identifier); - expression = new VariableExpressionSyntax((IdentifierToken) token); - } + var token = MatchToken(SyntaxKind.Identifier); + expression = new VariableExpressionSyntax((IdentifierToken) token); break; case SyntaxKind.OpenBrace: expression = ParseTable(); @@ -260,9 +258,8 @@ namespace Upsilon.Parser return expression; } - private ExpressionSyntax ParseFunctionCallExpression() + private ExpressionSyntax ParseFunctionCallExpression(ExpressionSyntax expression) { - var identifier = MatchToken(SyntaxKind.Identifier); var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis); var parameters = ImmutableArray.CreateBuilder(); while (Current.Kind != SyntaxKind.CloseParenthesis) @@ -274,7 +271,7 @@ namespace Upsilon.Parser } var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis); - return new FunctionCallExpressionSyntax((IdentifierToken) identifier, openParenthesis, + return new FunctionCallExpressionSyntax(expression, openParenthesis, parameters.ToImmutable(), closeParenthesis); } diff --git a/UpsilonTests/TableTests.cs b/UpsilonTests/TableTests.cs index 3c57738..8a43cad 100644 --- a/UpsilonTests/TableTests.cs +++ b/UpsilonTests/TableTests.cs @@ -83,13 +83,37 @@ return table[1][1][2] { const string input = @" table = { - function() test + function test() return 100 - end + end, val = 400, another = 10_000, } return table[""test""]() +"; + var script = new Script(input); + Assert.Empty(script.Diagnostics.Messages); + var evaluated = script.Evaluate(); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal(100, evaluated); + } + + [Fact] + public void DumbassTableFunctionNesting() + { + const string input = @" +table = { + function func() + return function func() + return { + function func() + return 100 + end + } + end + end, +} +return table[""func""]()()[1]() "; var script = new Script(input); Assert.Empty(script.Diagnostics.Messages);