work on nested tables, will need some cleanup later
This commit is contained in:
parent
3d4e6380ea
commit
d8f7651de7
|
@ -387,24 +387,16 @@ namespace Upsilon.Binder
|
|||
|
||||
private BoundExpression BindIndexExpression(IndexExpressionSyntax e)
|
||||
{
|
||||
var name = e.Identifier.Name;
|
||||
if (!Scope.TryGetVariable(name, true, out var variable))
|
||||
var expression = BindExpression(e.Expression);
|
||||
if (expression.Type != Type.Table && expression.Type != Type.Unknown)
|
||||
{
|
||||
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
||||
//TODO: wrong type diagnostic
|
||||
throw new Exception(expression.Type.ToString());
|
||||
return new BoundLiteralExpression(new LuaNull());
|
||||
}
|
||||
|
||||
if (variable.Type != Type.Table)
|
||||
{
|
||||
//TODO better error message
|
||||
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
||||
return new BoundLiteralExpression(new LuaNull());
|
||||
}
|
||||
|
||||
var tableVariable = (TableVariableSymbol) variable;
|
||||
var outType = tableVariable.OutType;
|
||||
var index = BindExpression(e.Index);
|
||||
return new BoundIndexExpression(tableVariable, index, outType);
|
||||
return new BoundIndexExpression(expression, index, Type.Unknown);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,14 +5,14 @@ namespace Upsilon.Binder
|
|||
{
|
||||
public class BoundIndexExpression : BoundExpression
|
||||
{
|
||||
public BoundIndexExpression(TableVariableSymbol identifier, BoundExpression index, Type type)
|
||||
public BoundIndexExpression(BoundExpression identifier, BoundExpression index, Type type)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Index = index;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public TableVariableSymbol Identifier { get; }
|
||||
public BoundExpression Identifier { get; }
|
||||
public BoundExpression Index { get; }
|
||||
|
||||
public override BoundKind Kind => BoundKind.BoundIndexExpression;
|
||||
|
|
|
@ -333,20 +333,36 @@ namespace Upsilon.Evaluator
|
|||
|
||||
private LuaType EvaluateIndexExpression(BoundIndexExpression e)
|
||||
{
|
||||
if (!Scope.TryGet(e.Identifier, out var val))
|
||||
IIndexable index;
|
||||
if (e.Identifier.Kind == BoundKind.VariableExpression)
|
||||
{
|
||||
throw new Exception($"Cannot find variable: '{e.Identifier.Name}'");
|
||||
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();
|
||||
}
|
||||
|
||||
if (!(val is IIndexable indexable))
|
||||
{
|
||||
throw new Exception("Variable is not indexable.");
|
||||
}
|
||||
|
||||
var innerEvaluator = new Evaluator(_diagnostics, Scope, indexable.EvaluatorIdentifier);
|
||||
var indexer = EvaluateExpression(e.Index);
|
||||
|
||||
return indexable.Get(indexer.ToString(), Identifier);
|
||||
var innerEvaluator = new Evaluator(_diagnostics, Scope, index.EvaluatorIdentifier);
|
||||
var indexer = innerEvaluator.EvaluateExpression(e.Index);
|
||||
return index.Get(indexer.ToString(), Identifier);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,15 +4,15 @@ namespace Upsilon.Parser
|
|||
{
|
||||
public class IndexExpressionSyntax : ExpressionSyntax
|
||||
{
|
||||
public IdentifierToken Identifier { get; }
|
||||
public ExpressionSyntax Expression { get; }
|
||||
public SyntaxToken OpenBracket { get; }
|
||||
public ExpressionSyntax Index { get; }
|
||||
public SyntaxToken CloseBracket { get; }
|
||||
|
||||
public IndexExpressionSyntax(IdentifierToken identifier, SyntaxToken openBracket, ExpressionSyntax index,
|
||||
public IndexExpressionSyntax(ExpressionSyntax expression, SyntaxToken openBracket, ExpressionSyntax index,
|
||||
SyntaxToken closeBracket)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Expression = expression;
|
||||
OpenBracket = openBracket;
|
||||
Index = index;
|
||||
CloseBracket = closeBracket;
|
||||
|
@ -21,7 +21,7 @@ namespace Upsilon.Parser
|
|||
public override SyntaxKind Kind => SyntaxKind.IndexExpression;
|
||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||
{
|
||||
yield return Identifier;
|
||||
yield return Expression;
|
||||
yield return OpenBracket;
|
||||
yield return Index;
|
||||
yield return CloseBracket;
|
||||
|
|
|
@ -4,7 +4,8 @@ namespace Upsilon.Parser
|
|||
{
|
||||
public class IdentifierToken : SyntaxToken
|
||||
{
|
||||
public IdentifierToken(string name, int position, int length) : base(SyntaxKind.Identifier, position, name, null)
|
||||
public IdentifierToken(string name, int position)
|
||||
: base(SyntaxKind.Identifier, position, name, null)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace Upsilon.Parser
|
|||
var str = stringBuilder.ToString();
|
||||
if (kind == SyntaxKind.Identifier)
|
||||
{
|
||||
return new IdentifierToken(str, start, str.Length);
|
||||
return new IdentifierToken(str, start);
|
||||
}
|
||||
return new SyntaxToken(kind, start, str, null);
|
||||
}
|
||||
|
|
|
@ -167,7 +167,12 @@ namespace Upsilon.Parser
|
|||
|
||||
private ExpressionSyntax ParseExpression()
|
||||
{
|
||||
return ParseBinaryExpression();
|
||||
var expression = ParseBinaryExpression();
|
||||
while (Current.Kind == SyntaxKind.OpenBracket)
|
||||
{
|
||||
expression = ParseIndexExpression(expression);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private AssignmentExpressionSyntax ParseAssignmentExpression()
|
||||
|
@ -214,34 +219,45 @@ namespace Upsilon.Parser
|
|||
|
||||
private ExpressionSyntax ParsePrimaryExpression()
|
||||
{
|
||||
ExpressionSyntax expression;
|
||||
switch (Current.Kind)
|
||||
{
|
||||
case SyntaxKind.OpenParenthesis:
|
||||
return ParseParenthesizedExpression();
|
||||
expression = ParseParenthesizedExpression();
|
||||
break;
|
||||
case SyntaxKind.Number:
|
||||
return ParseNumber();
|
||||
expression = ParseNumber();
|
||||
break;
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
return ParseBoolean();
|
||||
expression = ParseBoolean();
|
||||
break;
|
||||
case SyntaxKind.String:
|
||||
return ParseString();
|
||||
expression = ParseString();
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
if (Next.Kind == SyntaxKind.OpenParenthesis)
|
||||
return ParseFunctionCallExpression();
|
||||
if (Next.Kind == SyntaxKind.OpenBracket)
|
||||
return ParseIndexExpression();
|
||||
var token = MatchToken(SyntaxKind.Identifier);
|
||||
return new VariableExpressionSyntax((IdentifierToken) token);
|
||||
expression = ParseFunctionCallExpression();
|
||||
else
|
||||
{
|
||||
var token = MatchToken(SyntaxKind.Identifier);
|
||||
expression = new VariableExpressionSyntax((IdentifierToken) token);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.OpenBrace:
|
||||
return ParseTable();
|
||||
expression = ParseTable();
|
||||
break;
|
||||
case SyntaxKind.NilKeyword:
|
||||
var nilToken = MatchToken(SyntaxKind.NilKeyword);
|
||||
return new LiteralExpressionSyntax(nilToken, null);
|
||||
expression = new LiteralExpressionSyntax(nilToken, null);
|
||||
break;
|
||||
default:
|
||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
||||
NextToken();
|
||||
return new BadExpressionSyntax();
|
||||
expression = new BadExpressionSyntax();
|
||||
break;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParseFunctionCallExpression()
|
||||
|
@ -262,13 +278,12 @@ namespace Upsilon.Parser
|
|||
parameters.ToImmutable(), closeParenthesis);
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParseIndexExpression()
|
||||
private ExpressionSyntax ParseIndexExpression(ExpressionSyntax expression)
|
||||
{
|
||||
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
|
||||
var openBracket = MatchToken(SyntaxKind.OpenBracket);
|
||||
var index = ParseExpression();
|
||||
var closeBracket = MatchToken(SyntaxKind.CloseBracket);
|
||||
return new IndexExpressionSyntax(identifier, openBracket, index, closeBracket);
|
||||
return new IndexExpressionSyntax(expression, openBracket, index, closeBracket);
|
||||
}
|
||||
|
||||
private ExpressionSyntax ParseParenthesizedExpression()
|
||||
|
|
|
@ -57,6 +57,27 @@ return table[""test""]
|
|||
Assert.Null(evaluated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedTables()
|
||||
{
|
||||
const string input = @"
|
||||
table = {
|
||||
{
|
||||
{
|
||||
100, 600, 900
|
||||
},
|
||||
{}
|
||||
}
|
||||
}
|
||||
return table[1][1][2]
|
||||
";
|
||||
var script = new Script(input);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var evaluated = script.Evaluate<long>();
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(600, evaluated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FunctionsInTable()
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Ycicle
|
|||
Console.ResetColor();
|
||||
continue;
|
||||
}
|
||||
//Console.WriteLine(script.PrettyPrintSyntaxTree());
|
||||
|
||||
var evaluate = script.Evaluate();
|
||||
if (script.Diagnostics.Messages.Count > 0)
|
||||
|
|
Loading…
Reference in New Issue