Lots of work on rewriting functions to allow more functionality
This commit is contained in:
parent
dd9f5416a0
commit
860f2cc7e5
|
@ -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)
|
|
||||||
{
|
|
||||||
Scope = innerScope;
|
|
||||||
var block = BindBlockStatement(e.Block);
|
|
||||||
Scope = Scope.ParentScope;
|
|
||||||
((FunctionVariableSymbol) variable).IsBound = true;
|
((FunctionVariableSymbol) variable).IsBound = true;
|
||||||
var func = new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block);
|
|
||||||
return func;
|
return new BoundFunctionAssignmentStatement(variable, 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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,8 +18,9 @@ namespace Upsilon.Binder
|
||||||
BoundBlockStatement,
|
BoundBlockStatement,
|
||||||
BoundIfStatement,
|
BoundIfStatement,
|
||||||
BoundElseStatement,
|
BoundElseStatement,
|
||||||
BoundFunctionStatement,
|
BoundFunctionExpression,
|
||||||
BoundPromise,
|
BoundPromise,
|
||||||
BoundReturnStatement,
|
BoundReturnStatement,
|
||||||
|
BoundFunctionAssignmentStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
|
@ -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,7 +127,26 @@ namespace Upsilon.Parser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StatementSyntax ParseFunctionStatement()
|
private ExpressionSyntax ParseFunctionExpression()
|
||||||
|
{
|
||||||
|
var functionToken = MatchToken(SyntaxKind.FunctionKeyword);
|
||||||
|
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);
|
||||||
|
return new FunctionExpressionSyntax(functionToken, openParenthesis,
|
||||||
|
variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatementSyntax ParseFunctionAssignmentStatement()
|
||||||
{
|
{
|
||||||
SyntaxToken localToken = null;
|
SyntaxToken localToken = null;
|
||||||
if (Current.Kind == SyntaxKind.LocalKeyword)
|
if (Current.Kind == SyntaxKind.LocalKeyword)
|
||||||
|
@ -148,8 +167,9 @@ namespace Upsilon.Parser
|
||||||
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,
|
var functionExpression = new FunctionExpressionSyntax(functionToken, openParenthesis,
|
||||||
variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken);
|
variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken);
|
||||||
|
return new FunctionAssignmentStatementSyntax(localToken, identifier, functionExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionStatementSyntax ParseExpressionStatement()
|
private ExpressionStatementSyntax ParseExpressionStatement()
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,7 +65,8 @@ namespace Upsilon.Parser
|
||||||
IfStatement,
|
IfStatement,
|
||||||
ElseIfStatement,
|
ElseIfStatement,
|
||||||
ElseStatement,
|
ElseStatement,
|
||||||
FunctionStatement,
|
FunctionExpression,
|
||||||
ReturnStatement,
|
ReturnStatement,
|
||||||
|
FunctionAssignmentStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue