Adds assignment to tables
This commit is contained in:
parent
f4ae57c550
commit
7d551b6313
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Upsilon.Binder;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes
|
namespace Upsilon.BaseTypes
|
||||||
|
@ -28,5 +29,10 @@ namespace Upsilon.BaseTypes
|
||||||
}
|
}
|
||||||
return new LuaNull();
|
return new LuaNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Set(string s, LuaType obj)
|
||||||
|
{
|
||||||
|
EvaluationScope.Set(new VariableSymbol(s, obj.Type, false), obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -56,6 +56,8 @@ namespace Upsilon.Binder
|
||||||
return BindReturnStatement((ReturnStatementSyntax) s);
|
return BindReturnStatement((ReturnStatementSyntax) s);
|
||||||
case SyntaxKind.FunctionAssignmentStatement:
|
case SyntaxKind.FunctionAssignmentStatement:
|
||||||
return BindFunctionAssignmentStatement((FunctionAssignmentStatementSyntax) s);
|
return BindFunctionAssignmentStatement((FunctionAssignmentStatementSyntax) s);
|
||||||
|
case SyntaxKind.TableAssignmentStatement:
|
||||||
|
return BindTableAssignmentStatement((TableAssigmentStatementSyntax) s);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(s.Kind.ToString());
|
throw new NotImplementedException(s.Kind.ToString());
|
||||||
|
@ -217,7 +219,10 @@ namespace Upsilon.Binder
|
||||||
|
|
||||||
private BoundStatement BindAssignmentStatement(AssignmentExpressionSyntax e)
|
private BoundStatement BindAssignmentStatement(AssignmentExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var name = e.Identifier.Name;
|
if (e.Identifier.Kind == SyntaxKind.VariableExpression)
|
||||||
|
{
|
||||||
|
var variableExpression = (VariableExpressionSyntax) e.Identifier;
|
||||||
|
var name = variableExpression.Identifier.Name;
|
||||||
var boundExpression = BindExpression(e.Expression);
|
var boundExpression = BindExpression(e.Expression);
|
||||||
|
|
||||||
var isLocal = e.LocalToken != null;
|
var isLocal = e.LocalToken != null;
|
||||||
|
@ -232,6 +237,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
variable = new VariableSymbol(name, boundExpression.Type, isLocal);
|
variable = new VariableSymbol(name, boundExpression.Type, isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLocal)
|
if (isLocal)
|
||||||
Scope.SetVariable(variable);
|
Scope.SetVariable(variable);
|
||||||
else
|
else
|
||||||
|
@ -265,6 +271,14 @@ namespace Upsilon.Binder
|
||||||
return new BoundVariableAssignment(variable, boundExpression);
|
return new BoundVariableAssignment(variable, boundExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.Identifier.Kind == SyntaxKind.IndexExpression)
|
||||||
|
{
|
||||||
|
throw new Exception("this");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BoundExpressionStatement(new BoundLiteralExpression(new LuaNull()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private BoundStatement BindBlockStatement(BlockStatementSyntax e)
|
private BoundStatement BindBlockStatement(BlockStatementSyntax e)
|
||||||
{
|
{
|
||||||
|
@ -419,6 +433,11 @@ namespace Upsilon.Binder
|
||||||
var expression = BindExpression(e.Expression);
|
var expression = BindExpression(e.Expression);
|
||||||
|
|
||||||
var index = BindExpression(e.Index);
|
var index = BindExpression(e.Index);
|
||||||
|
if (index.Type != Type.Number && index.Type != Type.String && index.Type != Type.Unknown)
|
||||||
|
{
|
||||||
|
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
|
||||||
|
return new BoundLiteralExpression(new LuaNull());
|
||||||
|
}
|
||||||
switch (expression.Type)
|
switch (expression.Type)
|
||||||
{
|
{
|
||||||
case Type.Table:
|
case Type.Table:
|
||||||
|
@ -432,5 +451,12 @@ namespace Upsilon.Binder
|
||||||
return new BoundLiteralExpression(new LuaNull());
|
return new BoundLiteralExpression(new LuaNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BoundStatement BindTableAssignmentStatement(TableAssigmentStatementSyntax e)
|
||||||
|
{
|
||||||
|
var tableIndexExpression = (BoundIndexExpression)BindExpression(e.TableExpression);
|
||||||
|
var value = BindExpression(e.Expression);
|
||||||
|
return new BoundTableAssigmentStatement(tableIndexExpression, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ namespace Upsilon.Binder
|
||||||
BoundFunctionExpression,
|
BoundFunctionExpression,
|
||||||
BoundPromise,
|
BoundPromise,
|
||||||
BoundReturnStatement,
|
BoundReturnStatement,
|
||||||
BoundFunctionAssignmentStatement
|
BoundFunctionAssignmentStatement,
|
||||||
|
BoundTableAssigmentStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundTableAssigmentStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundIndexExpression TableIndexExpression { get; }
|
||||||
|
public BoundExpression Value { get; }
|
||||||
|
|
||||||
|
public BoundTableAssigmentStatement(BoundIndexExpression tableIndexExpression, BoundExpression value)
|
||||||
|
{
|
||||||
|
TableIndexExpression = tableIndexExpression;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundTableAssigmentStatement;
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,10 @@ namespace Upsilon
|
||||||
{
|
{
|
||||||
LogError($"Invalid character found. Expected: '{expectedToken}'", location);
|
LogError($"Invalid character found. Expected: '{expectedToken}'", location);
|
||||||
}
|
}
|
||||||
|
public void LogBadCharacter(TextSpan location)
|
||||||
|
{
|
||||||
|
LogError($"Invalid character found.", location);
|
||||||
|
}
|
||||||
|
|
||||||
public void LogUnknownVariable(TextSpan span, string variable)
|
public void LogUnknownVariable(TextSpan span, string variable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,26 +15,17 @@ namespace Upsilon.Evaluator
|
||||||
private LuaType _returnValue;
|
private LuaType _returnValue;
|
||||||
internal EvaluationScope Scope { get; }
|
internal EvaluationScope Scope { get; }
|
||||||
private bool HasReturned { get; set; }
|
private bool HasReturned { get; set; }
|
||||||
public int Identifier { get; }
|
|
||||||
|
|
||||||
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
|
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
|
||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
Scope = new EvaluationScope(variables);
|
Scope = new EvaluationScope(variables);
|
||||||
Identifier = new Random().Next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Evaluator(Diagnostics diagnostics, EvaluationScope parentScope)
|
private Evaluator(Diagnostics diagnostics, EvaluationScope parentScope)
|
||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
Scope = new EvaluationScope(parentScope);
|
Scope = new EvaluationScope(parentScope);
|
||||||
Identifier = new Random().Next();
|
|
||||||
}
|
|
||||||
private Evaluator(Diagnostics diagnostics, EvaluationScope parentScope, int identifier)
|
|
||||||
{
|
|
||||||
_diagnostics = diagnostics;
|
|
||||||
Scope = new EvaluationScope(parentScope);
|
|
||||||
Identifier = identifier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaType Evaluate(BoundScript e)
|
public LuaType Evaluate(BoundScript e)
|
||||||
|
@ -90,6 +81,7 @@ namespace Upsilon.Evaluator
|
||||||
case BoundKind.BoundFunctionAssignmentStatement:
|
case BoundKind.BoundFunctionAssignmentStatement:
|
||||||
case BoundKind.BoundPromise:
|
case BoundKind.BoundPromise:
|
||||||
case BoundKind.BoundReturnStatement:
|
case BoundKind.BoundReturnStatement:
|
||||||
|
case BoundKind.BoundTableAssigmentStatement:
|
||||||
EvaluateStatement((BoundStatement) b);
|
EvaluateStatement((BoundStatement) b);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -119,6 +111,9 @@ namespace Upsilon.Evaluator
|
||||||
case BoundKind.BoundFunctionAssignmentStatement:
|
case BoundKind.BoundFunctionAssignmentStatement:
|
||||||
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
|
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
|
||||||
break;
|
break;
|
||||||
|
case BoundKind.BoundTableAssigmentStatement:
|
||||||
|
EvaluateTableAssignmentStatement((BoundTableAssigmentStatement) e);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
||||||
break;
|
break;
|
||||||
|
@ -354,5 +349,19 @@ namespace Upsilon.Evaluator
|
||||||
var indexer = evaluator.EvaluateExpression(e.Index);
|
var indexer = evaluator.EvaluateExpression(e.Index);
|
||||||
return indexable.Get(indexer.ToString(), scope);
|
return indexable.Get(indexer.ToString(), scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
||||||
|
{
|
||||||
|
var table = EvaluateExpression(e.TableIndexExpression.Identifier);
|
||||||
|
var index = EvaluateExpression(e.TableIndexExpression.Index);
|
||||||
|
var value = EvaluateExpression(e.Value);
|
||||||
|
if (table.Type != Type.Table)
|
||||||
|
{
|
||||||
|
throw new Exception("Not a table");
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = (LuaTable) table;
|
||||||
|
t.Set(index.ToString(), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -83,7 +83,6 @@ namespace Upsilon.Parser
|
||||||
return ParseFunctionAssignmentStatement();
|
return ParseFunctionAssignmentStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return ParseExpressionStatement();
|
return ParseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +108,7 @@ namespace Upsilon.Parser
|
||||||
case SyntaxKind.ElseIfKeyword:
|
case SyntaxKind.ElseIfKeyword:
|
||||||
var nextElseIf =
|
var nextElseIf =
|
||||||
new ElseIfStatementSyntax((IfStatementSyntax) ParseIfStatement(SyntaxKind.ElseIfKeyword));
|
new ElseIfStatementSyntax((IfStatementSyntax) ParseIfStatement(SyntaxKind.ElseIfKeyword));
|
||||||
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block,
|
return new IfStatementSyntax(ifToken, (ExpressionStatementSyntax) condition, thenToken, (BlockStatementSyntax) block,
|
||||||
nextElseIf);
|
nextElseIf);
|
||||||
case SyntaxKind.ElseKeyword:
|
case SyntaxKind.ElseKeyword:
|
||||||
{
|
{
|
||||||
|
@ -117,11 +116,11 @@ namespace Upsilon.Parser
|
||||||
var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword});
|
var elseBlock = ParseBlockStatement(new[]{SyntaxKind.EndKeyword});
|
||||||
var endEndToken = MatchToken(SyntaxKind.EndKeyword);
|
var endEndToken = MatchToken(SyntaxKind.EndKeyword);
|
||||||
var elseStatement = new ElseStatementSyntax(elseToken, (BlockStatementSyntax) elseBlock, endEndToken);
|
var elseStatement = new ElseStatementSyntax(elseToken, (BlockStatementSyntax) elseBlock, endEndToken);
|
||||||
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, elseStatement);
|
return new IfStatementSyntax(ifToken, (ExpressionStatementSyntax) condition, thenToken, (BlockStatementSyntax) block, elseStatement);
|
||||||
}
|
}
|
||||||
case SyntaxKind.EndKeyword:
|
case SyntaxKind.EndKeyword:
|
||||||
var endToken = MatchToken(SyntaxKind.EndKeyword);
|
var endToken = MatchToken(SyntaxKind.EndKeyword);
|
||||||
return new IfStatementSyntax(ifToken, condition, thenToken, (BlockStatementSyntax) block, endToken);
|
return new IfStatementSyntax(ifToken, (ExpressionStatementSyntax) condition, thenToken, (BlockStatementSyntax) block, endToken);
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -172,9 +171,13 @@ namespace Upsilon.Parser
|
||||||
return new FunctionAssignmentStatementSyntax(localToken, identifier, functionExpression);
|
return new FunctionAssignmentStatementSyntax(localToken, identifier, functionExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionStatementSyntax ParseExpressionStatement()
|
private StatementSyntax ParseExpressionStatement()
|
||||||
{
|
{
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression();
|
||||||
|
if (expression.Kind == SyntaxKind.IndexExpression && Current.Kind == SyntaxKind.Equals)
|
||||||
|
{
|
||||||
|
return ParseTableAssignmentExpression(expression);
|
||||||
|
}
|
||||||
return new ExpressionStatementSyntax(expression);
|
return new ExpressionStatementSyntax(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,12 +216,21 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
localKeyword = MatchToken(SyntaxKind.LocalKeyword);
|
localKeyword = MatchToken(SyntaxKind.LocalKeyword);
|
||||||
}
|
}
|
||||||
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
|
|
||||||
|
var identifier = ParseExpression();
|
||||||
var assignmentToken = MatchToken(SyntaxKind.Equals);
|
var assignmentToken = MatchToken(SyntaxKind.Equals);
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression();
|
||||||
return new AssignmentExpressionSyntax(localKeyword, identifier, assignmentToken, expression);
|
return new AssignmentExpressionSyntax(localKeyword, identifier, assignmentToken, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StatementSyntax ParseTableAssignmentExpression(ExpressionSyntax tableExpression)
|
||||||
|
{
|
||||||
|
var assignmentToken = MatchToken(SyntaxKind.Equals);
|
||||||
|
var expression = ParseExpression();
|
||||||
|
return new TableAssigmentStatementSyntax(tableExpression, assignmentToken, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private ExpressionSyntax ParseBinaryExpression(SyntaxKindPrecedence.Precedence parentPrecedence = SyntaxKindPrecedence.Precedence.None)
|
private ExpressionSyntax ParseBinaryExpression(SyntaxKindPrecedence.Precedence parentPrecedence = SyntaxKindPrecedence.Precedence.None)
|
||||||
{
|
{
|
||||||
ExpressionSyntax left;
|
ExpressionSyntax left;
|
||||||
|
@ -278,7 +290,7 @@ namespace Upsilon.Parser
|
||||||
expression = new LiteralExpressionSyntax(nilToken, null);
|
expression = new LiteralExpressionSyntax(nilToken, null);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
_diagnostics.LogBadCharacter(new TextSpan(_position, 1));
|
||||||
NextToken();
|
NextToken();
|
||||||
expression = new BadExpressionSyntax();
|
expression = new BadExpressionSyntax();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,11 +5,11 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public sealed class AssignmentExpressionSyntax : StatementSyntax
|
public sealed class AssignmentExpressionSyntax : StatementSyntax
|
||||||
{
|
{
|
||||||
public AssignmentExpressionSyntax(SyntaxToken localToken, IdentifierToken identifier, SyntaxToken equalsToken,
|
public AssignmentExpressionSyntax(SyntaxToken localToken, ExpressionSyntax identifyExpression, SyntaxToken equalsToken,
|
||||||
ExpressionSyntax expression)
|
ExpressionSyntax expression)
|
||||||
{
|
{
|
||||||
LocalToken = localToken;
|
LocalToken = localToken;
|
||||||
Identifier = identifier;
|
Identifier = identifyExpression;
|
||||||
EqualsToken = equalsToken;
|
EqualsToken = equalsToken;
|
||||||
Expression = expression;
|
Expression = expression;
|
||||||
var start = LocalToken?.Span.Start ?? Identifier.Span.Start;
|
var start = LocalToken?.Span.Start ?? Identifier.Span.Start;
|
||||||
|
@ -19,7 +19,7 @@ namespace Upsilon.Parser
|
||||||
public override SyntaxKind Kind => SyntaxKind.AssignmentStatement;
|
public override SyntaxKind Kind => SyntaxKind.AssignmentStatement;
|
||||||
|
|
||||||
public SyntaxToken LocalToken { get; }
|
public SyntaxToken LocalToken { get; }
|
||||||
public IdentifierToken Identifier { get; }
|
public ExpressionSyntax Identifier { get; }
|
||||||
public SyntaxToken EqualsToken { get; }
|
public SyntaxToken EqualsToken { get; }
|
||||||
public ExpressionSyntax Expression { get; }
|
public ExpressionSyntax Expression { get; }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Upsilon.Parser
|
||||||
|
{
|
||||||
|
public class TableAssigmentStatementSyntax : StatementSyntax
|
||||||
|
{
|
||||||
|
public ExpressionSyntax TableExpression { get; }
|
||||||
|
public SyntaxToken AssignmentToken { get; }
|
||||||
|
public ExpressionSyntax Expression { get; }
|
||||||
|
|
||||||
|
public TableAssigmentStatementSyntax(ExpressionSyntax tableExpression, SyntaxToken assignmentToken,
|
||||||
|
ExpressionSyntax expression)
|
||||||
|
{
|
||||||
|
TableExpression = tableExpression;
|
||||||
|
AssignmentToken = assignmentToken;
|
||||||
|
Expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SyntaxKind Kind => SyntaxKind.TableAssignmentStatement;
|
||||||
|
|
||||||
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
|
{
|
||||||
|
yield return TableExpression;
|
||||||
|
yield return AssignmentToken;
|
||||||
|
yield return Expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
namespace Upsilon.Parser
|
namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public enum SyntaxKind
|
public enum SyntaxKind
|
||||||
|
@ -67,6 +68,7 @@ namespace Upsilon.Parser
|
||||||
ElseStatement,
|
ElseStatement,
|
||||||
FunctionExpression,
|
FunctionExpression,
|
||||||
ReturnStatement,
|
ReturnStatement,
|
||||||
FunctionAssignmentStatement
|
FunctionAssignmentStatement,
|
||||||
|
TableAssignmentStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -153,6 +153,21 @@ table = {
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
return table[1]()
|
return table[1]()
|
||||||
|
";
|
||||||
|
var script = new Script(input);
|
||||||
|
Assert.Empty(script.Diagnostics.Messages);
|
||||||
|
var evaluated = script.Evaluate<long>();
|
||||||
|
Assert.Empty(script.Diagnostics.Messages);
|
||||||
|
Assert.Equal(400, evaluated);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AssignToTable()
|
||||||
|
{
|
||||||
|
const string input = @"
|
||||||
|
table = {}
|
||||||
|
table[1] = 400
|
||||||
|
return table[1]
|
||||||
";
|
";
|
||||||
var script = new Script(input);
|
var script = new Script(input);
|
||||||
Assert.Empty(script.Diagnostics.Messages);
|
Assert.Empty(script.Diagnostics.Messages);
|
||||||
|
|
Loading…
Reference in New Issue