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; private readonly Dictionary<VariableSymbol, LuaType> _map;
public int EvaluatorIdentifier { get; } 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) public LuaTable(Dictionary<VariableSymbol, LuaType> map, int scopeIdentifier)
{ {
_map = map; _map = map;

View File

@ -154,15 +154,13 @@ namespace Upsilon.Binder
private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e) private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e)
{ {
var name = e.Identifier.Name; var expression = BindExpression(e.Identifier);
if (!Scope.TryGetVariable(name, true, out var functionObj)) if (expression.Type != Type.Function && expression.Type != Type.Unknown)
{ {
_diagnostics.LogUnknownVariable(e.Identifier.Span, name); //TODO Better error
return new BoundLiteralExpression(new LuaNull()); throw new Exception();
} }
var function = (FunctionVariableSymbol) functionObj;
var parameters = ImmutableArray.CreateBuilder<BoundExpression>(); var parameters = ImmutableArray.CreateBuilder<BoundExpression>();
foreach (var expressionSyntax in e.Parameters) foreach (var expressionSyntax in e.Parameters)
{ {
@ -170,6 +168,10 @@ namespace Upsilon.Binder
parameters.Add(bound); parameters.Add(bound);
} }
if (expression.Kind == BoundKind.VariableExpression)
{
var variableExpression =(BoundVariableExpression) expression;
var function = (FunctionVariableSymbol)variableExpression.Variable;
if (!function.IsBound) if (!function.IsBound)
{ {
Scope = new BoundScope(Scope); Scope = new BoundScope(Scope);
@ -188,9 +190,10 @@ namespace Upsilon.Binder
function.IsBound = true; function.IsBound = true;
_unboundFunctions.Remove(function); _unboundFunctions.Remove(function);
} }
}
//TODO: validate parameters //TODO: validate parameters
return new BoundFunctionCallExpression(function, parameters.ToImmutable()); return new BoundFunctionCallExpression(expression, parameters.ToImmutable());
} }
private BoundExpression BindVariableExpression(VariableExpressionSyntax e) private BoundExpression BindVariableExpression(VariableExpressionSyntax e)

View File

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

View File

@ -278,14 +278,12 @@ namespace Upsilon.Evaluator
private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression) private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression)
{ {
var name = boundFunctionCallExpression.Identifier; var variable = EvaluateExpression(boundFunctionCallExpression.Identifier);
if (!Scope.TryGet(name, out var functionObj)) 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); var innerEvaluator = new Evaluator(_diagnostics, Scope);
for (var i = 0; i < function.Parameters.Length; i++) for (var i = 0; i < function.Parameters.Length; i++)
{ {
@ -318,6 +316,13 @@ namespace Upsilon.Evaluator
var value = EvaluateExpression(assignment.BoundExpression); var value = EvaluateExpression(assignment.BoundExpression);
dic.Add(key, value); 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 else
{ {
innerEvaluator.EvaluateStatement(boundStatement); innerEvaluator.EvaluateStatement(boundStatement);
@ -333,36 +338,16 @@ namespace Upsilon.Evaluator
private LuaType EvaluateIndexExpression(BoundIndexExpression e) private LuaType EvaluateIndexExpression(BoundIndexExpression e)
{ {
IIndexable index; var variable = EvaluateExpression(e.Identifier);
if (e.Identifier.Kind == BoundKind.VariableExpression) 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."); 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();
}
var innerEvaluator = new Evaluator(_diagnostics, Scope, index.EvaluatorIdentifier); var innerEvaluator = new Evaluator(_diagnostics, Scope, indexable.EvaluatorIdentifier);
var indexer = innerEvaluator.EvaluateExpression(e.Index); 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 class FunctionCallExpressionSyntax : ExpressionSyntax
{ {
public IdentifierToken Identifier { get; } public ExpressionSyntax Identifier { get; }
public SyntaxToken OpenParenthesis { get; } public SyntaxToken OpenParenthesis { get; }
public ImmutableArray<ExpressionSyntax> Parameters { get; } public ImmutableArray<ExpressionSyntax> Parameters { get; }
public SyntaxToken CloseParenthesis { get; } public SyntaxToken CloseParenthesis { get; }
public FunctionCallExpressionSyntax(IdentifierToken identifier, SyntaxToken openParenthesis, public FunctionCallExpressionSyntax(ExpressionSyntax identifier, SyntaxToken openParenthesis,
ImmutableArray<ExpressionSyntax> parameters, SyntaxToken closeParenthesis) ImmutableArray<ExpressionSyntax> parameters, SyntaxToken closeParenthesis)
{ {
Identifier = identifier; Identifier = identifier;

View File

@ -168,9 +168,12 @@ namespace Upsilon.Parser
private ExpressionSyntax ParseExpression() private ExpressionSyntax ParseExpression()
{ {
var expression = ParseBinaryExpression(); var expression = ParseBinaryExpression();
while (Current.Kind == SyntaxKind.OpenBracket) while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis)
{ {
if (Current.Kind == SyntaxKind.OpenBracket)
expression = ParseIndexExpression(expression); expression = ParseIndexExpression(expression);
else if (Current.Kind == SyntaxKind.OpenParenthesis)
expression = ParseFunctionCallExpression(expression);
} }
return expression; return expression;
} }
@ -236,13 +239,8 @@ namespace Upsilon.Parser
expression = ParseString(); expression = ParseString();
break; break;
case SyntaxKind.Identifier: case SyntaxKind.Identifier:
if (Next.Kind == SyntaxKind.OpenParenthesis)
expression = ParseFunctionCallExpression();
else
{
var token = MatchToken(SyntaxKind.Identifier); var token = MatchToken(SyntaxKind.Identifier);
expression = new VariableExpressionSyntax((IdentifierToken) token); expression = new VariableExpressionSyntax((IdentifierToken) token);
}
break; break;
case SyntaxKind.OpenBrace: case SyntaxKind.OpenBrace:
expression = ParseTable(); expression = ParseTable();
@ -260,9 +258,8 @@ namespace Upsilon.Parser
return expression; return expression;
} }
private ExpressionSyntax ParseFunctionCallExpression() private ExpressionSyntax ParseFunctionCallExpression(ExpressionSyntax expression)
{ {
var identifier = MatchToken(SyntaxKind.Identifier);
var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis); var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis);
var parameters = ImmutableArray.CreateBuilder<ExpressionSyntax>(); var parameters = ImmutableArray.CreateBuilder<ExpressionSyntax>();
while (Current.Kind != SyntaxKind.CloseParenthesis) while (Current.Kind != SyntaxKind.CloseParenthesis)
@ -274,7 +271,7 @@ namespace Upsilon.Parser
} }
var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis); var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis);
return new FunctionCallExpressionSyntax((IdentifierToken) identifier, openParenthesis, return new FunctionCallExpressionSyntax(expression, openParenthesis,
parameters.ToImmutable(), closeParenthesis); parameters.ToImmutable(), closeParenthesis);
} }

View File

@ -83,13 +83,37 @@ return table[1][1][2]
{ {
const string input = @" const string input = @"
table = { table = {
function() test function test()
return 100 return 100
end end,
val = 400, val = 400,
another = 10_000, another = 10_000,
} }
return table[""test""]() 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); var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages); Assert.Empty(script.Diagnostics.Messages);