More work on nesting

This commit is contained in:
Deukhoofd 2018-11-18 20:20:03 +01:00
parent d8f7651de7
commit dd9f5416a0
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
7 changed files with 78 additions and 76 deletions

View File

@ -10,13 +10,6 @@ namespace Upsilon.BaseTypes
private readonly Dictionary<VariableSymbol, LuaType> _map;
public int EvaluatorIdentifier { get; }
public LuaTable(int scopeIdentifier)
{
EvaluatorIdentifier = scopeIdentifier;
_map = new Dictionary<VariableSymbol, LuaType>();
_variableLookup = new Dictionary<string, VariableSymbol>();
}
public LuaTable(Dictionary<VariableSymbol, LuaType> map, int scopeIdentifier)
{
_map = map;

View File

@ -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<BoundExpression>();
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)

View File

@ -5,10 +5,10 @@ namespace Upsilon.Binder
{
public class BoundFunctionCallExpression : BoundExpression
{
public FunctionVariableSymbol Identifier { get; }
public BoundExpression Identifier { get; }
public ImmutableArray<BoundExpression> Parameters { get; }
public BoundFunctionCallExpression(FunctionVariableSymbol identifier, ImmutableArray<BoundExpression> parameters)
public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters)
{
Identifier = identifier;
Parameters = parameters;

View File

@ -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);
}
}
}

View File

@ -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<ExpressionSyntax> Parameters { get; }
public SyntaxToken CloseParenthesis { get; }
public FunctionCallExpressionSyntax(IdentifierToken identifier, SyntaxToken openParenthesis,
public FunctionCallExpressionSyntax(ExpressionSyntax identifier, SyntaxToken openParenthesis,
ImmutableArray<ExpressionSyntax> parameters, SyntaxToken closeParenthesis)
{
Identifier = identifier;

View File

@ -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<ExpressionSyntax>();
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);
}

View File

@ -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<long>();
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);