Lots of work on rewriting functions to allow more functionality

This commit is contained in:
Deukhoofd 2018-11-18 22:22:30 +01:00
parent dd9f5416a0
commit 860f2cc7e5
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
12 changed files with 203 additions and 107 deletions

View File

@ -13,8 +13,8 @@ namespace Upsilon.Binder
private readonly Diagnostics _diagnostics; private readonly Diagnostics _diagnostics;
public BoundScope Scope { get; private set; } public BoundScope Scope { get; private set; }
private Dictionary<FunctionVariableSymbol, UnboundFunctionStatement> _unboundFunctions = private Dictionary<FunctionVariableSymbol, UnboundFunctionExpression> _unboundFunctions =
new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>(); new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables) public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
{ {
@ -37,7 +37,7 @@ namespace Upsilon.Binder
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
unboundFunctionStatement.Key.IsBound = true; unboundFunctionStatement.Key.IsBound = true;
} }
_unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>(); _unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
return new BoundScript((BoundBlockStatement) bound); return new BoundScript((BoundBlockStatement) bound);
} }
@ -53,10 +53,10 @@ namespace Upsilon.Binder
return BindBlockStatement((BlockStatementSyntax) s); return BindBlockStatement((BlockStatementSyntax) s);
case SyntaxKind.IfStatement: case SyntaxKind.IfStatement:
return BindIfStatement((IfStatementSyntax) s); return BindIfStatement((IfStatementSyntax) s);
case SyntaxKind.FunctionStatement:
return BindFunctionStatement((FunctionStatementSyntax) s);
case SyntaxKind.ReturnStatement: case SyntaxKind.ReturnStatement:
return BindReturnStatement((ReturnStatementSyntax) s); return BindReturnStatement((ReturnStatementSyntax) s);
case SyntaxKind.FunctionAssignmentStatement:
return BindFunctionAssignmentStatement((FunctionAssignmentStatementSyntax) s);
} }
throw new NotImplementedException(s.Kind.ToString()); throw new NotImplementedException(s.Kind.ToString());
@ -82,6 +82,8 @@ namespace Upsilon.Binder
return BindTableExpression((TableExpressionSyntax) e); return BindTableExpression((TableExpressionSyntax) e);
case SyntaxKind.IndexExpression: case SyntaxKind.IndexExpression:
return BindIndexExpression((IndexExpressionSyntax) e); return BindIndexExpression((IndexExpressionSyntax) e);
case SyntaxKind.FunctionExpression:
return BindFunctionExpression((FunctionExpressionSyntax) e);
case SyntaxKind.BadExpression: case SyntaxKind.BadExpression:
break; break;
case SyntaxKind.ScriptUnit: case SyntaxKind.ScriptUnit:
@ -305,14 +307,44 @@ namespace Upsilon.Binder
} }
} }
private BoundStatement BindFunctionStatement(FunctionStatementSyntax e) private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e)
{ {
var innerScope = new BoundScope(Scope);
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
foreach (var identifierToken in e.Parameters)
{
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
parameters.Add(vari);
innerScope.SetVariable(vari);
}
if (parameters.Count == 0)
{
Scope = innerScope;
var block = BindBlockStatement(e.Block);
Scope = Scope.ParentScope;
var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block);
return func;
}
else
{
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block);
_unboundFunctions.Add(
new FunctionVariableSymbol(Guid.NewGuid().ToString(), Type.Unknown, true, parameters.ToImmutable()),
unbound);
return unbound;
}
}
private BoundStatement BindFunctionAssignmentStatement(FunctionAssignmentStatementSyntax e)
{
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression);
var name = e.Identifier.Name; var name = e.Identifier.Name;
var isLocal = e.LocalToken != null; var isLocal = e.LocalToken != null;
var innerScope = new BoundScope(Scope); var innerScope = new BoundScope(Scope);
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>(); var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
foreach (var identifierToken in e.Parameters) foreach (var identifierToken in func.Parameters)
{ {
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true); var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
parameters.Add(vari); parameters.Add(vari);
@ -339,26 +371,14 @@ namespace Upsilon.Binder
else else
{ {
_diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span); _diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span);
return new BoundExpressionStatement(null); return new BoundExpressionStatement(new BoundLiteralExpression(new LuaNull()));
} }
} }
} }
if (parameters.Count == 0) ((FunctionVariableSymbol) variable).IsBound = true;
{
Scope = innerScope; return new BoundFunctionAssignmentStatement(variable, func);
var block = BindBlockStatement(e.Block);
Scope = Scope.ParentScope;
((FunctionVariableSymbol) variable).IsBound = true;
var func = new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block);
return func;
}
else
{
var unbound = new UnboundFunctionStatement(variable, parameters.ToImmutable(), e.Block);
_unboundFunctions.Add((FunctionVariableSymbol) variable, unbound);
return unbound;
}
} }
private BoundStatement BindReturnStatement(ReturnStatementSyntax e) private BoundStatement BindReturnStatement(ReturnStatementSyntax e)

View File

@ -15,6 +15,6 @@ namespace Upsilon.Binder
} }
public override BoundKind Kind => BoundKind.BoundFunctionCallExpression; public override BoundKind Kind => BoundKind.BoundFunctionCallExpression;
public override Type Type => Type.Nil; public override Type Type => Type.Unknown;
} }
} }

View File

@ -18,8 +18,9 @@ namespace Upsilon.Binder
BoundBlockStatement, BoundBlockStatement,
BoundIfStatement, BoundIfStatement,
BoundElseStatement, BoundElseStatement,
BoundFunctionStatement, BoundFunctionExpression,
BoundPromise, BoundPromise,
BoundReturnStatement, BoundReturnStatement,
BoundFunctionAssignmentStatement
} }
} }

View File

@ -0,0 +1,34 @@
using System.Collections.Immutable;
using Upsilon.BaseTypes;
namespace Upsilon.Binder
{
public class BoundFunctionExpression : BoundExpression
{
public ImmutableArray<VariableSymbol> Parameters { get; }
public BoundBlockStatement Block { get; set; }
public BoundFunctionExpression(ImmutableArray<VariableSymbol> parameters, BoundBlockStatement block)
{
Parameters = parameters;
Block = block;
}
public override BoundKind Kind => BoundKind.BoundFunctionExpression;
public override Type Type => Type.Function;
}
public class BoundFunctionAssignmentStatement : BoundStatement
{
public VariableSymbol Variable { get; }
public BoundFunctionExpression Func { get; }
public BoundFunctionAssignmentStatement(VariableSymbol variable, BoundFunctionExpression func)
{
Variable = variable;
Func = func;
}
public override BoundKind Kind => BoundKind.BoundFunctionAssignmentStatement;
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Immutable;
namespace Upsilon.Binder
{
public class BoundFunctionStatement : BoundStatement
{
public VariableSymbol Identifier { get; }
public ImmutableArray<VariableSymbol> Parameters { get; }
public BoundBlockStatement Block { get; set; }
public BoundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters,
BoundBlockStatement block)
{
Identifier = identifier;
Parameters = parameters;
Block = block;
}
public override BoundKind Kind => BoundKind.BoundFunctionStatement;
}
}

View File

@ -3,10 +3,10 @@ using Upsilon.Parser;
namespace Upsilon.Binder namespace Upsilon.Binder
{ {
public class UnboundFunctionStatement : BoundFunctionStatement public class UnboundFunctionExpression : BoundFunctionExpression
{ {
public UnboundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters, public UnboundFunctionExpression(ImmutableArray<VariableSymbol> parameters,
BlockStatementSyntax unboundBlock) : base(identifier, parameters, null) BlockStatementSyntax unboundBlock) : base(parameters, null)
{ {
UnboundBlock = unboundBlock; UnboundBlock = unboundBlock;
} }

View File

@ -77,7 +77,9 @@ namespace Upsilon.Evaluator
case BoundKind.BoundUnaryExpression: case BoundKind.BoundUnaryExpression:
case BoundKind.VariableExpression: case BoundKind.VariableExpression:
case BoundKind.BoundFunctionCallExpression: case BoundKind.BoundFunctionCallExpression:
case BoundKind.BoundFunctionExpression:
case BoundKind.BoundTableExpression: case BoundKind.BoundTableExpression:
case BoundKind.BoundIndexExpression:
_lastValue = EvaluateExpression((BoundExpression) b); _lastValue = EvaluateExpression((BoundExpression) b);
break; break;
case BoundKind.BoundAssignmentStatement: case BoundKind.BoundAssignmentStatement:
@ -85,8 +87,9 @@ namespace Upsilon.Evaluator
case BoundKind.BoundBlockStatement: case BoundKind.BoundBlockStatement:
case BoundKind.BoundIfStatement: case BoundKind.BoundIfStatement:
case BoundKind.BoundElseStatement: case BoundKind.BoundElseStatement:
case BoundKind.BoundFunctionStatement: case BoundKind.BoundFunctionAssignmentStatement:
case BoundKind.BoundPromise: case BoundKind.BoundPromise:
case BoundKind.BoundReturnStatement:
EvaluateStatement((BoundStatement) b); EvaluateStatement((BoundStatement) b);
break; break;
default: default:
@ -110,15 +113,12 @@ namespace Upsilon.Evaluator
case BoundKind.BoundIfStatement: case BoundKind.BoundIfStatement:
EvaluateBoundIfStatement((BoundIfStatement) e); EvaluateBoundIfStatement((BoundIfStatement) e);
break; break;
case BoundKind.BoundFunctionStatement:
EvaluateBoundFunctionStatement((BoundFunctionStatement) e);
break;
case BoundKind.BoundPromise:
EvaluateUnboundFunctionStatement((UnboundFunctionStatement) e);
break;
case BoundKind.BoundReturnStatement: case BoundKind.BoundReturnStatement:
EvaluateReturnStatement((BoundReturnStatement) e); EvaluateReturnStatement((BoundReturnStatement) e);
break; break;
case BoundKind.BoundFunctionAssignmentStatement:
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
break;
default: default:
EvaluateExpressionStatement((BoundExpressionStatement) e); EvaluateExpressionStatement((BoundExpressionStatement) e);
break; break;
@ -149,6 +149,11 @@ namespace Upsilon.Evaluator
return EvaluateTableExpression((BoundTableExpression) e); return EvaluateTableExpression((BoundTableExpression) e);
case BoundKind.BoundIndexExpression: case BoundKind.BoundIndexExpression:
return EvaluateIndexExpression((BoundIndexExpression) e); return EvaluateIndexExpression((BoundIndexExpression) e);
case BoundKind.BoundFunctionExpression:
return EvaluateBoundFunctionStatement((BoundFunctionExpression) e);
case BoundKind.BoundPromise:
return EvaluateUnboundFunctionStatement((UnboundFunctionExpression) e);
break;
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -254,26 +259,25 @@ namespace Upsilon.Evaluator
_lastValue = innerEvaluator._lastValue; _lastValue = innerEvaluator._lastValue;
} }
private void EvaluateBoundFunctionStatement(BoundFunctionStatement boundFunctionStatement) private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e)
{ {
var func = new LuaFunction(boundFunctionStatement.Parameters, boundFunctionStatement.Block); var func = EvaluateBoundFunctionStatement(e.Func);
if (boundFunctionStatement.Identifier.Local) if (e.Variable.Local)
Scope.Set(boundFunctionStatement.Identifier, func); Scope.Set(e.Variable, func);
else else
{ Scope.SetGlobal(e.Variable, func);
Scope.SetGlobal(boundFunctionStatement.Identifier, func);
_lastValue = func;
}
} }
private void EvaluateUnboundFunctionStatement(UnboundFunctionStatement unboundFunctionStatement) private LuaType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression)
{ {
var func = new LuaFunction(unboundFunctionStatement.Parameters, unboundFunctionStatement.Block); var func = new LuaFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block);
if (unboundFunctionStatement.Identifier.Local) return func;
Scope.Set(unboundFunctionStatement.Identifier, func); }
else
Scope.SetGlobal(unboundFunctionStatement.Identifier, func);
private LuaType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression)
{
var func = new LuaFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block);
return func;
} }
private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression) private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression)
@ -281,7 +285,7 @@ namespace Upsilon.Evaluator
var variable = EvaluateExpression(boundFunctionCallExpression.Identifier); var variable = EvaluateExpression(boundFunctionCallExpression.Identifier);
if (!(variable is LuaFunction function)) if (!(variable is LuaFunction function))
{ {
throw new Exception("Variable is not a function."); throw new Exception($"Variable is not a function.");
} }
var innerEvaluator = new Evaluator(_diagnostics, Scope); var innerEvaluator = new Evaluator(_diagnostics, Scope);
@ -316,12 +320,19 @@ 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) else if (boundStatement.Kind == BoundKind.BoundFunctionExpression)
{ {
var function = (BoundFunctionStatement) boundStatement; var expressionStatement = (BoundExpressionStatement)boundStatement;
var key = function.Identifier; var function = (BoundFunctionExpression) expressionStatement.Expression;
var func = new LuaFunction(function.Parameters, function.Block); var func = new LuaFunction(function.Parameters, function.Block);
dic.Add(key, func); dic.Add(new VariableSymbol(currentPos.ToString(), func.Type, false), func);
}
else if (boundStatement.Kind == BoundKind.BoundFunctionAssignmentStatement)
{
var assignment = (BoundFunctionAssignmentStatement)boundStatement;
var key = assignment.Variable;
var value = EvaluateExpression(assignment.Func);
dic.Add(key, value);
} }
else else
{ {

View File

@ -3,24 +3,20 @@ using System.Collections.Immutable;
namespace Upsilon.Parser namespace Upsilon.Parser
{ {
public class FunctionStatementSyntax : StatementSyntax public class FunctionExpressionSyntax : ExpressionSyntax
{ {
public SyntaxToken LocalToken { get; }
public SyntaxToken FunctionToken { get; } public SyntaxToken FunctionToken { get; }
public IdentifierToken Identifier { get; }
public SyntaxToken OpenParenthesis { get; } public SyntaxToken OpenParenthesis { get; }
public ImmutableArray<IdentifierToken> Parameters { get; } public ImmutableArray<IdentifierToken> Parameters { get; }
public SyntaxToken CloseParenthesis { get; } public SyntaxToken CloseParenthesis { get; }
public BlockStatementSyntax Block { get; } public BlockStatementSyntax Block { get; }
public SyntaxToken EndToken { get; } public SyntaxToken EndToken { get; }
public FunctionStatementSyntax(SyntaxToken localToken, SyntaxToken functionToken, IdentifierToken identifier, public FunctionExpressionSyntax(SyntaxToken functionToken,
SyntaxToken openParenthesis, ImmutableArray<IdentifierToken> parameters, SyntaxToken closeParenthesis, SyntaxToken openParenthesis, ImmutableArray<IdentifierToken> parameters, SyntaxToken closeParenthesis,
BlockStatementSyntax block, SyntaxToken endToken) BlockStatementSyntax block, SyntaxToken endToken)
{ {
LocalToken = localToken;
FunctionToken = functionToken; FunctionToken = functionToken;
Identifier = identifier;
OpenParenthesis = openParenthesis; OpenParenthesis = openParenthesis;
Parameters = parameters; Parameters = parameters;
CloseParenthesis = closeParenthesis; CloseParenthesis = closeParenthesis;
@ -28,12 +24,10 @@ namespace Upsilon.Parser
EndToken = endToken; EndToken = endToken;
} }
public override SyntaxKind Kind => SyntaxKind.FunctionStatement; public override SyntaxKind Kind => SyntaxKind.FunctionExpression;
public override IEnumerable<SyntaxNode> ChildNodes() public override IEnumerable<SyntaxNode> ChildNodes()
{ {
yield return LocalToken;
yield return FunctionToken; yield return FunctionToken;
yield return Identifier;
yield return OpenParenthesis; yield return OpenParenthesis;
foreach (var identifierToken in Parameters) foreach (var identifierToken in Parameters)
{ {

View File

@ -70,19 +70,19 @@ namespace Upsilon.Parser
{ {
return ParseIfStatement(SyntaxKind.IfKeyword); return ParseIfStatement(SyntaxKind.IfKeyword);
} }
if (Current.Kind == SyntaxKind.FunctionKeyword)
{
return ParseFunctionStatement();
}
if (Current.Kind == SyntaxKind.LocalKeyword && Next.Kind == SyntaxKind.FunctionKeyword)
{
return ParseFunctionStatement();
}
if (Current.Kind == SyntaxKind.ReturnKeyword) if (Current.Kind == SyntaxKind.ReturnKeyword)
{ {
return ParseReturnStatement(); return ParseReturnStatement();
} }
if (Current.Kind == SyntaxKind.FunctionKeyword && Next.Kind != SyntaxKind.OpenParenthesis)
{
return ParseFunctionAssignmentStatement();
}
if (Current.Kind == SyntaxKind.LocalKeyword && Next.Kind == SyntaxKind.FunctionKeyword)
{
return ParseFunctionAssignmentStatement();
}
return ParseExpressionStatement(); return ParseExpressionStatement();
} }
@ -127,15 +127,9 @@ namespace Upsilon.Parser
} }
} }
private StatementSyntax ParseFunctionStatement() private ExpressionSyntax ParseFunctionExpression()
{ {
SyntaxToken localToken = null;
if (Current.Kind == SyntaxKind.LocalKeyword)
{
localToken = NextToken();
}
var functionToken = MatchToken(SyntaxKind.FunctionKeyword); var functionToken = MatchToken(SyntaxKind.FunctionKeyword);
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis); var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis);
var variableBuilder = ImmutableArray.CreateBuilder<IdentifierToken>(); var variableBuilder = ImmutableArray.CreateBuilder<IdentifierToken>();
while (Current.Kind != SyntaxKind.CloseParenthesis) while (Current.Kind != SyntaxKind.CloseParenthesis)
@ -146,12 +140,38 @@ namespace Upsilon.Parser
NextToken(); NextToken();
} }
var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis); var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis);
var block = ParseBlockStatement(new[] {SyntaxKind.EndKeyword}); var block = ParseBlockStatement(new[] {SyntaxKind.EndKeyword});
var endToken = MatchToken(SyntaxKind.EndKeyword); var endToken = MatchToken(SyntaxKind.EndKeyword);
return new FunctionStatementSyntax(localToken, functionToken, identifier, openParenthesis, return new FunctionExpressionSyntax(functionToken, openParenthesis,
variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken); variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken);
} }
private StatementSyntax ParseFunctionAssignmentStatement()
{
SyntaxToken localToken = null;
if (Current.Kind == SyntaxKind.LocalKeyword)
{
localToken = NextToken();
}
var functionToken = MatchToken(SyntaxKind.FunctionKeyword);
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis);
var variableBuilder = ImmutableArray.CreateBuilder<IdentifierToken>();
while (Current.Kind != SyntaxKind.CloseParenthesis)
{
var variableIdentifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
variableBuilder.Add(variableIdentifier);
if (Current.Kind == SyntaxKind.Comma)
NextToken();
}
var closeParenthesis = MatchToken(SyntaxKind.CloseParenthesis);
var block = ParseBlockStatement(new[] {SyntaxKind.EndKeyword});
var endToken = MatchToken(SyntaxKind.EndKeyword);
var functionExpression = new FunctionExpressionSyntax(functionToken, openParenthesis,
variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken);
return new FunctionAssignmentStatementSyntax(localToken, identifier, functionExpression);
}
private ExpressionStatementSyntax ParseExpressionStatement() private ExpressionStatementSyntax ParseExpressionStatement()
{ {
var expression = ParseExpression(); var expression = ParseExpression();
@ -167,7 +187,15 @@ namespace Upsilon.Parser
private ExpressionSyntax ParseExpression() private ExpressionSyntax ParseExpression()
{ {
var expression = ParseBinaryExpression(); ExpressionSyntax expression;
if (Current.Kind == SyntaxKind.FunctionKeyword && Next.Kind == SyntaxKind.OpenParenthesis)
{
expression = ParseFunctionExpression();
}
else
{
expression = ParseBinaryExpression();
}
while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis) while (Current.Kind == SyntaxKind.OpenBracket || Current.Kind == SyntaxKind.OpenParenthesis)
{ {
if (Current.Kind == SyntaxKind.OpenBracket) if (Current.Kind == SyntaxKind.OpenBracket)

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
namespace Upsilon.Parser
{
public class FunctionAssignmentStatementSyntax : StatementSyntax
{
public FunctionAssignmentStatementSyntax(SyntaxToken localToken, IdentifierToken identifier, FunctionExpressionSyntax functionExpression)
{
LocalToken = localToken;
Identifier = identifier;
FunctionExpression = functionExpression;
}
public SyntaxToken LocalToken { get; }
public IdentifierToken Identifier { get; }
public FunctionExpressionSyntax FunctionExpression { get; }
public override SyntaxKind Kind => SyntaxKind.FunctionAssignmentStatement;
public override IEnumerable<SyntaxNode> ChildNodes()
{
if (LocalToken != null)
yield return LocalToken;
yield return Identifier;
yield return FunctionExpression;
}
}
}

View File

@ -65,7 +65,8 @@ namespace Upsilon.Parser
IfStatement, IfStatement,
ElseIfStatement, ElseIfStatement,
ElseStatement, ElseStatement,
FunctionStatement, FunctionExpression,
ReturnStatement, ReturnStatement,
FunctionAssignmentStatement
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Xunit; using Xunit;
@ -104,9 +105,9 @@ return table[""test""]()
const string input = @" const string input = @"
table = { table = {
function func() function func()
return function func() return function()
return { return {
function func() function()
return 100 return 100
end end
} }