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)
|
private BoundExpression BindIndexExpression(IndexExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var name = e.Identifier.Name;
|
var expression = BindExpression(e.Expression);
|
||||||
if (!Scope.TryGetVariable(name, true, out var variable))
|
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());
|
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);
|
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 class BoundIndexExpression : BoundExpression
|
||||||
{
|
{
|
||||||
public BoundIndexExpression(TableVariableSymbol identifier, BoundExpression index, Type type)
|
public BoundIndexExpression(BoundExpression identifier, BoundExpression index, Type type)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Index = index;
|
Index = index;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableVariableSymbol Identifier { get; }
|
public BoundExpression Identifier { get; }
|
||||||
public BoundExpression Index { get; }
|
public BoundExpression Index { get; }
|
||||||
|
|
||||||
public override BoundKind Kind => BoundKind.BoundIndexExpression;
|
public override BoundKind Kind => BoundKind.BoundIndexExpression;
|
||||||
|
|
|
@ -333,20 +333,36 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
private LuaType EvaluateIndexExpression(BoundIndexExpression e)
|
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))
|
if (!(val is IIndexable indexable))
|
||||||
{
|
{
|
||||||
throw new Exception("Variable is not 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();
|
||||||
|
}
|
||||||
|
|
||||||
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 class IndexExpressionSyntax : ExpressionSyntax
|
||||||
{
|
{
|
||||||
public IdentifierToken Identifier { get; }
|
public ExpressionSyntax Expression { get; }
|
||||||
public SyntaxToken OpenBracket { get; }
|
public SyntaxToken OpenBracket { get; }
|
||||||
public ExpressionSyntax Index { get; }
|
public ExpressionSyntax Index { get; }
|
||||||
public SyntaxToken CloseBracket { get; }
|
public SyntaxToken CloseBracket { get; }
|
||||||
|
|
||||||
public IndexExpressionSyntax(IdentifierToken identifier, SyntaxToken openBracket, ExpressionSyntax index,
|
public IndexExpressionSyntax(ExpressionSyntax expression, SyntaxToken openBracket, ExpressionSyntax index,
|
||||||
SyntaxToken closeBracket)
|
SyntaxToken closeBracket)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Expression = expression;
|
||||||
OpenBracket = openBracket;
|
OpenBracket = openBracket;
|
||||||
Index = index;
|
Index = index;
|
||||||
CloseBracket = closeBracket;
|
CloseBracket = closeBracket;
|
||||||
|
@ -21,7 +21,7 @@ namespace Upsilon.Parser
|
||||||
public override SyntaxKind Kind => SyntaxKind.IndexExpression;
|
public override SyntaxKind Kind => SyntaxKind.IndexExpression;
|
||||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
{
|
{
|
||||||
yield return Identifier;
|
yield return Expression;
|
||||||
yield return OpenBracket;
|
yield return OpenBracket;
|
||||||
yield return Index;
|
yield return Index;
|
||||||
yield return CloseBracket;
|
yield return CloseBracket;
|
||||||
|
|
|
@ -4,7 +4,8 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public class IdentifierToken : SyntaxToken
|
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;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ namespace Upsilon.Parser
|
||||||
var str = stringBuilder.ToString();
|
var str = stringBuilder.ToString();
|
||||||
if (kind == SyntaxKind.Identifier)
|
if (kind == SyntaxKind.Identifier)
|
||||||
{
|
{
|
||||||
return new IdentifierToken(str, start, str.Length);
|
return new IdentifierToken(str, start);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(kind, start, str, null);
|
return new SyntaxToken(kind, start, str, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,12 @@ namespace Upsilon.Parser
|
||||||
|
|
||||||
private ExpressionSyntax ParseExpression()
|
private ExpressionSyntax ParseExpression()
|
||||||
{
|
{
|
||||||
return ParseBinaryExpression();
|
var expression = ParseBinaryExpression();
|
||||||
|
while (Current.Kind == SyntaxKind.OpenBracket)
|
||||||
|
{
|
||||||
|
expression = ParseIndexExpression(expression);
|
||||||
|
}
|
||||||
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssignmentExpressionSyntax ParseAssignmentExpression()
|
private AssignmentExpressionSyntax ParseAssignmentExpression()
|
||||||
|
@ -214,34 +219,45 @@ namespace Upsilon.Parser
|
||||||
|
|
||||||
private ExpressionSyntax ParsePrimaryExpression()
|
private ExpressionSyntax ParsePrimaryExpression()
|
||||||
{
|
{
|
||||||
|
ExpressionSyntax expression;
|
||||||
switch (Current.Kind)
|
switch (Current.Kind)
|
||||||
{
|
{
|
||||||
case SyntaxKind.OpenParenthesis:
|
case SyntaxKind.OpenParenthesis:
|
||||||
return ParseParenthesizedExpression();
|
expression = ParseParenthesizedExpression();
|
||||||
|
break;
|
||||||
case SyntaxKind.Number:
|
case SyntaxKind.Number:
|
||||||
return ParseNumber();
|
expression = ParseNumber();
|
||||||
|
break;
|
||||||
case SyntaxKind.TrueKeyword:
|
case SyntaxKind.TrueKeyword:
|
||||||
case SyntaxKind.FalseKeyword:
|
case SyntaxKind.FalseKeyword:
|
||||||
return ParseBoolean();
|
expression = ParseBoolean();
|
||||||
|
break;
|
||||||
case SyntaxKind.String:
|
case SyntaxKind.String:
|
||||||
return ParseString();
|
expression = ParseString();
|
||||||
|
break;
|
||||||
case SyntaxKind.Identifier:
|
case SyntaxKind.Identifier:
|
||||||
if (Next.Kind == SyntaxKind.OpenParenthesis)
|
if (Next.Kind == SyntaxKind.OpenParenthesis)
|
||||||
return ParseFunctionCallExpression();
|
expression = ParseFunctionCallExpression();
|
||||||
if (Next.Kind == SyntaxKind.OpenBracket)
|
else
|
||||||
return ParseIndexExpression();
|
{
|
||||||
var token = MatchToken(SyntaxKind.Identifier);
|
var token = MatchToken(SyntaxKind.Identifier);
|
||||||
return new VariableExpressionSyntax((IdentifierToken) token);
|
expression = new VariableExpressionSyntax((IdentifierToken) token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SyntaxKind.OpenBrace:
|
case SyntaxKind.OpenBrace:
|
||||||
return ParseTable();
|
expression = ParseTable();
|
||||||
|
break;
|
||||||
case SyntaxKind.NilKeyword:
|
case SyntaxKind.NilKeyword:
|
||||||
var nilToken = MatchToken(SyntaxKind.NilKeyword);
|
var nilToken = MatchToken(SyntaxKind.NilKeyword);
|
||||||
return new LiteralExpressionSyntax(nilToken, null);
|
expression = new LiteralExpressionSyntax(nilToken, null);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
_diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier);
|
||||||
NextToken();
|
NextToken();
|
||||||
return new BadExpressionSyntax();
|
expression = new BadExpressionSyntax();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseFunctionCallExpression()
|
private ExpressionSyntax ParseFunctionCallExpression()
|
||||||
|
@ -262,13 +278,12 @@ namespace Upsilon.Parser
|
||||||
parameters.ToImmutable(), closeParenthesis);
|
parameters.ToImmutable(), closeParenthesis);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseIndexExpression()
|
private ExpressionSyntax ParseIndexExpression(ExpressionSyntax expression)
|
||||||
{
|
{
|
||||||
var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier);
|
|
||||||
var openBracket = MatchToken(SyntaxKind.OpenBracket);
|
var openBracket = MatchToken(SyntaxKind.OpenBracket);
|
||||||
var index = ParseExpression();
|
var index = ParseExpression();
|
||||||
var closeBracket = MatchToken(SyntaxKind.CloseBracket);
|
var closeBracket = MatchToken(SyntaxKind.CloseBracket);
|
||||||
return new IndexExpressionSyntax(identifier, openBracket, index, closeBracket);
|
return new IndexExpressionSyntax(expression, openBracket, index, closeBracket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseParenthesizedExpression()
|
private ExpressionSyntax ParseParenthesizedExpression()
|
||||||
|
|
|
@ -57,6 +57,27 @@ return table[""test""]
|
||||||
Assert.Null(evaluated);
|
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]
|
[Fact]
|
||||||
public void FunctionsInTable()
|
public void FunctionsInTable()
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Ycicle
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//Console.WriteLine(script.PrettyPrintSyntaxTree());
|
||||||
|
|
||||||
var evaluate = script.Evaluate();
|
var evaluate = script.Evaluate();
|
||||||
if (script.Diagnostics.Messages.Count > 0)
|
if (script.Diagnostics.Messages.Count > 0)
|
||||||
|
|
Loading…
Reference in New Issue