More work on nesting
This commit is contained in:
parent
d8f7651de7
commit
dd9f5416a0
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue