Upsilon/Upsilon/Binder/Binder.cs

607 lines
26 KiB
C#
Raw Normal View History

2018-11-11 17:12:42 +00:00
using System;
2018-11-15 19:13:53 +00:00
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Upsilon.BaseTypes;
2018-11-11 17:12:42 +00:00
using Upsilon.BaseTypes.Number;
using Upsilon.Parser;
using Type = Upsilon.BaseTypes.Type;
namespace Upsilon.Binder
{
internal class Binder : IDisposable
2018-11-11 17:12:42 +00:00
{
private Diagnostics _diagnostics;
public BoundScope Scope { get; private set; }
2018-11-11 17:12:42 +00:00
2018-11-19 11:49:48 +00:00
private Dictionary<string, UnboundFunctionExpression> _unboundFunctions =
new Dictionary<string, UnboundFunctionExpression>();
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
2018-11-11 17:12:42 +00:00
{
_diagnostics = diagnostics;
Scope = new BoundScope(variables, null);
2018-11-11 17:12:42 +00:00
}
private Binder(){}
internal static Binder CreateWithSetScope(Diagnostics diagnostics, BoundScope scope)
{
return new Binder {_diagnostics = diagnostics, Scope = scope};
}
public void Dispose()
{
Scope?.Dispose();
Scope = null;
_unboundFunctions.Clear();
}
public BoundScript BindScript(BlockStatementSyntax e)
2018-11-11 17:12:42 +00:00
{
var bound = BindStatement(e);
foreach (var unboundFunctionStatement in _unboundFunctions)
{
Scope = new BoundScope(Scope);
foreach (var valueParameter in unboundFunctionStatement.Value.Parameters)
{
Scope.AssignToNearest(valueParameter.VariableSymbol);
}
unboundFunctionStatement.Value.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
Scope = Scope.ParentScope;
}
2018-11-19 11:49:48 +00:00
_unboundFunctions = new Dictionary<string, UnboundFunctionExpression>();
return new BoundScript((BoundBlockStatement) bound, e.Span);
2018-11-11 17:12:42 +00:00
}
2018-11-15 14:51:05 +00:00
private BoundStatement BindStatement(StatementSyntax s)
{
switch (s.Kind)
{
case SyntaxKind.ExpressionStatement:
return BindExpressionStatement((ExpressionStatementSyntax) s);
case SyntaxKind.AssignmentStatement:
return BindAssignmentStatement((AssignmentStatementSyntax) s);
case SyntaxKind.BlockStatement:
return BindBlockStatement((BlockStatementSyntax) s);
2018-11-13 11:48:50 +00:00
case SyntaxKind.IfStatement:
return BindIfStatement((IfStatementSyntax) s);
2018-11-16 12:45:03 +00:00
case SyntaxKind.ReturnStatement:
return BindReturnStatement((ReturnStatementSyntax) s);
case SyntaxKind.FunctionAssignmentStatement:
return BindFunctionAssignmentStatement((FunctionAssignmentStatementSyntax) s);
2018-11-19 15:22:13 +00:00
case SyntaxKind.TableAssignmentStatement:
return BindTableAssignmentStatement((TableAssigmentStatementSyntax) s);
case SyntaxKind.MultiAssignmentStatement:
return BindMultiAssignmentStatement((MultiAssignmentStatementSyntax) s);
2018-11-23 13:38:45 +00:00
case SyntaxKind.NumericForStatement:
return BindNumericForStatement((NumericForStatementSyntax) s);
2018-11-23 17:18:07 +00:00
case SyntaxKind.GenericForStatement:
return BindGenericForStatement((GenericForStatementSyntax) s);
2018-11-23 14:27:48 +00:00
case SyntaxKind.BreakStatement:
return new BoundBreakStatement(s.Span);
}
throw new NotImplementedException(s.Kind.ToString());
}
2018-11-15 14:51:05 +00:00
private BoundExpression BindExpression(ExpressionSyntax e)
2018-11-11 17:12:42 +00:00
{
switch (e.Kind)
{
case SyntaxKind.UnaryExpression:
2018-11-11 18:56:53 +00:00
return BindUnaryExpression((UnaryExpressionSyntax) e);
2018-11-11 17:12:42 +00:00
case SyntaxKind.BinaryExpression:
return BindBinaryExpression((BinaryExpressionSyntax) e);
case SyntaxKind.LiteralExpression:
return BindLiteralExpression((LiteralExpressionSyntax) e);
case SyntaxKind.ParenthesizedExpression:
2018-11-11 19:00:06 +00:00
return BindParenthesizedExpression((ParenthesizedExpressionSyntax) e);
2018-11-11 17:12:42 +00:00
case SyntaxKind.VariableExpression:
2018-11-11 19:41:24 +00:00
return BindVariableExpression((VariableExpressionSyntax) e);
2018-11-15 19:13:53 +00:00
case SyntaxKind.FunctionCallExpression:
return BindFunctionCallExpression((FunctionCallExpressionSyntax) e);
2018-11-17 18:13:05 +00:00
case SyntaxKind.TableExpression:
return BindTableExpression((TableExpressionSyntax) e);
2018-11-18 13:18:24 +00:00
case SyntaxKind.IndexExpression:
return BindIndexExpression((IndexExpressionSyntax) e);
case SyntaxKind.FullStopIndexExpression:
return BindFullStopIndexExpression((FullStopIndexExpressionSyntax) e);
case SyntaxKind.FunctionExpression:
return BindFunctionExpression((FunctionExpressionSyntax) e);
2018-11-11 17:12:42 +00:00
case SyntaxKind.BadExpression:
break;
case SyntaxKind.ScriptUnit:
break;
default:
throw new ArgumentOutOfRangeException();
}
throw new NotImplementedException(e.Kind.ToString());
}
2018-11-11 18:56:53 +00:00
private BoundExpression BindUnaryExpression(UnaryExpressionSyntax e)
{
var inExp = BindExpression(e.Expression);
var op = BoundUnaryOperator.Bind(e.Operator.Kind, inExp.Type);
if (op == null)
{
_diagnostics.LogUnknownUnaryOperator(e.Span, e.Operator.Kind, inExp.Type);
return inExp;
}
return new BoundUnaryExpression(op, inExp, op.OutType, e.Span);
2018-11-11 18:56:53 +00:00
}
2018-11-11 17:12:42 +00:00
private BoundExpression BindBinaryExpression(BinaryExpressionSyntax e)
{
var left = BindExpression(e.Left);
var right = BindExpression(e.Right);
2018-11-11 18:56:53 +00:00
var op = BoundBinaryOperator.Bind(e.Operator.Kind, left.Type, right.Type);
2018-11-11 17:12:42 +00:00
if (op == null)
{
2018-11-11 18:56:53 +00:00
_diagnostics.LogUnknownBinaryOperator(e.Span, e.Operator.Kind, left.Type, right.Type);
2018-11-11 17:12:42 +00:00
return left;
}
return new BoundBinaryExpression(op, left, right, op.OutType, e.Span);
2018-11-11 17:12:42 +00:00
}
private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e)
{
var value = e.Value;
2018-11-23 17:18:07 +00:00
ScriptType outValue = null;
2018-11-11 17:12:42 +00:00
switch (value)
{
case double d:
2018-11-23 17:18:07 +00:00
outValue = new ScriptNumberDouble(d);
2018-11-11 17:12:42 +00:00
break;
2018-11-11 17:19:30 +00:00
case long l:
2018-11-23 17:18:07 +00:00
outValue = new ScriptNumberLong(l);
2018-11-11 17:19:30 +00:00
break;
case bool b:
2018-11-23 17:18:07 +00:00
outValue = new ScriptBoolean(b);
2018-11-11 17:12:42 +00:00
break;
2018-11-17 14:57:26 +00:00
case string s:
2018-11-23 17:18:07 +00:00
outValue = new ScriptString(s);
2018-11-17 14:57:26 +00:00
break;
2018-11-14 12:45:49 +00:00
case null:
2018-11-23 17:18:07 +00:00
outValue = new ScriptNull();
2018-11-14 12:45:49 +00:00
break;
2018-11-17 14:57:26 +00:00
2018-11-11 17:12:42 +00:00
default:
_diagnostics.LogUnknownType(e.Span);
break;
}
return new BoundLiteralExpression(outValue, e.Span);
2018-11-11 17:12:42 +00:00
}
2018-11-11 19:00:06 +00:00
2018-11-11 19:31:55 +00:00
private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntax e)
2018-11-11 19:00:06 +00:00
{
2018-11-11 19:31:55 +00:00
return BindExpression(e.Expression);
}
2018-11-15 19:13:53 +00:00
private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e)
{
2018-11-18 19:20:03 +00:00
var expression = BindExpression(e.Identifier);
if (expression.Type != Type.Function && expression.Type != Type.Unknown)
2018-11-15 19:13:53 +00:00
{
2018-11-18 19:20:03 +00:00
//TODO Better error
throw new Exception();
2018-11-15 19:13:53 +00:00
}
var parameters = ImmutableArray.CreateBuilder<BoundExpression>();
foreach (var expressionSyntax in e.Parameters)
{
var bound = BindExpression(expressionSyntax);
parameters.Add(bound);
}
2018-11-18 19:20:03 +00:00
if (expression.Kind == BoundKind.VariableExpression)
2018-11-15 19:13:53 +00:00
{
2018-11-18 19:20:03 +00:00
var variableExpression =(BoundVariableExpression) expression;
var function = (FunctionVariableSymbol)variableExpression.Variable.VariableSymbol;
2018-11-18 19:20:03 +00:00
if (!function.IsBound)
2018-11-15 19:13:53 +00:00
{
2018-11-18 19:20:03 +00:00
Scope = new BoundScope(Scope);
for (var index = 0; index < function.Parameters.Length; index++)
{
var functionVariable = function.Parameters[index];
var callingVariable = parameters[index];
functionVariable.Type = callingVariable.Type;
2018-11-24 11:42:54 +00:00
Scope.DefineLocalVariable(functionVariable);
2018-11-18 19:20:03 +00:00
}
2018-11-19 11:49:48 +00:00
var unboundFunctionStatement = _unboundFunctions[function.Name];
2018-11-18 19:20:03 +00:00
unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
Scope = Scope.ParentScope;
function.IsBound = true;
2018-11-19 11:49:48 +00:00
_unboundFunctions.Remove(function.Name);
2018-11-15 19:13:53 +00:00
}
}
//TODO: validate parameters
return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span);
2018-11-15 19:13:53 +00:00
}
private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
{
var name = e.Identifier.Name;
if (!Scope.TryGetVariable(name, true, out var variable))
{
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
return new BoundLiteralExpression(new ScriptNull(), e.Span);
}
var boundVariable = new BoundVariableSymbol(variable, e.Identifier.Span);
return new BoundVariableExpression(boundVariable, e.Span);
}
private BoundStatement BindExpressionStatement(ExpressionStatementSyntax s)
{
var exp = BindExpression(s.Expression);
return new BoundExpressionStatement(exp, s.Span);
}
private VariableSymbol TryBindVariable(string name, bool isLocal, BoundExpression assignment, string[] commentData)
2018-11-11 19:31:55 +00:00
{
if (name == "_")
return null;
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
2018-11-11 19:31:55 +00:00
{
if (assignment.Type == Type.Table)
{
var tableExpression = (BoundTableExpression) assignment;
variable = new TableVariableSymbol(name, tableExpression.ValueType, isLocal,
tableExpression.Expressions);
}
else
{
variable = new VariableSymbol(name, assignment.Type, isLocal);
}
2018-11-19 15:22:13 +00:00
variable.CommentValue = commentData;
if (isLocal)
2018-11-24 11:42:54 +00:00
Scope.DefineLocalVariable(variable);
else
2018-11-24 11:42:54 +00:00
Scope.AssignToNearest(variable);
}
else
{
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
if (assignment.Type != variable.Type)
2018-11-11 19:31:55 +00:00
{
if (variable.Type == Type.Nil || assignment.Type == Type.Nil)
{
variable.Type = assignment.Type;
}
else if (variable.Type == Type.Unknown)
2018-11-15 19:13:53 +00:00
{
variable.Type = assignment.Type;
}
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
{
v.Variable.VariableSymbol.Type = variable.Type;
2018-11-23 11:55:28 +00:00
}
else if (assignment.Type == Type.Unknown)
{
2018-11-15 19:13:53 +00:00
}
else
{
_diagnostics.LogCannotConvert(assignment.Type, variable.Type, assignment.Span);
return null;
}
2018-11-11 19:31:55 +00:00
}
}
return variable;
}
2018-11-11 19:31:55 +00:00
private BoundStatement BindAssignmentStatement(AssignmentStatementSyntax e)
{
if (e.Identifier.Kind == SyntaxKind.VariableExpression)
2018-11-19 15:22:13 +00:00
{
var variableExpression = (VariableExpressionSyntax) e.Identifier;
var name = variableExpression.Identifier.Name;
var boundExpression = BindExpression(e.Expression);
var isLocal = e.LocalToken != null;
var boundVariable = TryBindVariable(name, isLocal, boundExpression, e.CommentData);
if (boundVariable != null)
{
var variable = new BoundVariableSymbol(boundVariable, variableExpression.Span);
return new BoundVariableAssignment(variable, boundExpression, isLocal, e.Span);
}
2018-11-19 15:22:13 +00:00
}
return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull(), e.Span), e.Span);
2018-11-11 19:00:06 +00:00
}
2018-11-11 19:41:24 +00:00
private BoundStatement BindMultiAssignmentStatement(MultiAssignmentStatementSyntax s)
{
var ls = new List<VariableSymbol>();
var assignment = BindExpression(s.Expression);
var isLocal = s.LocalKeyword != null;
foreach (var identifierToken in s.Identifiers)
{
var boundVariable = TryBindVariable(identifierToken.Name, isLocal, assignment, null);
ls.Add(boundVariable);
}
return new BoundMultiAssignmentStatement(ls.ToImmutableArray(), assignment, s.Span);
}
private BoundStatement BindBlockStatement(BlockStatementSyntax e)
2018-11-11 19:41:24 +00:00
{
var arr = ImmutableArray.CreateBuilder<BoundStatement>();
foreach (var statementSyntax in e.Statements)
2018-11-11 19:41:24 +00:00
{
2018-11-15 14:51:05 +00:00
var bound = BindStatement(statementSyntax);
arr.Add(bound);
2018-11-11 19:41:24 +00:00
}
2018-11-15 14:51:05 +00:00
return new BoundBlockStatement(arr.ToImmutable(), e.Span);
2018-11-11 19:41:24 +00:00
}
2018-11-13 11:48:50 +00:00
private BoundStatement BindIfStatement(IfStatementSyntax e)
{
Scope = new BoundScope(Scope);
2018-11-13 11:48:50 +00:00
var condition = BindExpressionStatement(e.Condition);
var block = BindBlockStatement(e.Block);
Scope = Scope.ParentScope;
2018-11-13 14:15:44 +00:00
if (e.NextElseIfStatement != null)
{
var nextElseIf = BindIfStatement(e.NextElseIfStatement);
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block,
(BoundIfStatement) nextElseIf, e.Span);
2018-11-13 14:15:44 +00:00
}
2018-11-13 12:54:51 +00:00
if (e.ElseStatement == null)
{
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block, e.Span);
2018-11-13 12:54:51 +00:00
}
else
{
Scope = new BoundScope(Scope);
2018-11-13 12:54:51 +00:00
var elseBlock = BindBlockStatement(e.ElseStatement.Block);
var elseStatement = new BoundElseStatement((BoundBlockStatement) elseBlock, e.Span);
Scope = Scope.ParentScope;
2018-11-15 14:51:05 +00:00
2018-11-13 12:54:51 +00:00
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block,
elseStatement, e.Span);
2018-11-13 12:54:51 +00:00
}
2018-11-13 11:48:50 +00:00
}
2018-11-19 11:49:48 +00:00
private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e, string variableSymbol = null)
2018-11-15 14:51:05 +00:00
{
var innerScope = new BoundScope(Scope);
var parameters = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
foreach (var identifierToken in e.Parameters)
{
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
parameters.Add(new BoundVariableSymbol(vari, identifierToken.Span));
2018-11-24 11:42:54 +00:00
innerScope.DefineLocalVariable(vari);
}
if (parameters.Count == 0)
{
Scope = innerScope;
var block = BindBlockStatement(e.Block);
Scope = Scope.ParentScope;
var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block, e.Span);
return func;
}
else
{
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span);
2018-11-19 11:49:48 +00:00
if (variableSymbol == null)
{
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
}
else
{
_unboundFunctions.Add(variableSymbol, unbound);
}
return unbound;
}
}
private BoundStatement BindFunctionAssignmentStatement(FunctionAssignmentStatementSyntax e)
{
2018-11-15 14:51:05 +00:00
var name = e.Identifier.Name;
var isLocal = e.LocalToken != null;
var innerScope = new BoundScope(Scope);
2018-11-19 11:49:48 +00:00
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression, name);
2018-11-15 14:51:05 +00:00
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
2018-11-19 11:49:48 +00:00
foreach (var parameter in func.Parameters)
2018-11-15 14:51:05 +00:00
{
var vari = new VariableSymbol(parameter.VariableSymbol.Name, Type.Unknown, true);
2018-11-15 14:51:05 +00:00
parameters.Add(vari);
2018-11-24 11:42:54 +00:00
innerScope.DefineLocalVariable(vari);
2018-11-15 14:51:05 +00:00
}
var commentData = new List<string>();
if (e.CommentData != null)
{
commentData.AddRange(e.CommentData);
}
2018-11-19 11:49:48 +00:00
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
2018-11-15 14:51:05 +00:00
{
var functionVariable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable())
{
CommentValue = commentData.ToArray()
};
variable = functionVariable;
functionVariable.IsBound = !(func is UnboundFunctionExpression);
2018-11-15 14:51:05 +00:00
if (isLocal)
2018-11-24 11:42:54 +00:00
Scope.DefineLocalVariable(variable);
2018-11-15 14:51:05 +00:00
else
2018-11-24 11:42:54 +00:00
Scope.AssignToNearest(variable);
2018-11-15 14:51:05 +00:00
}
else
{
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
if (variable.Type != Type.Function)
{
if (variable.Type == Type.Nil )
{
variable.Type = Type.Function;
}
else
{
_diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span);
return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull(), e.Span), e.Span);
2018-11-15 14:51:05 +00:00
}
}
}
return new BoundFunctionAssignmentStatement(variable, func, e.Span);
2018-11-15 14:51:05 +00:00
}
2018-11-16 12:45:03 +00:00
private BoundStatement BindReturnStatement(ReturnStatementSyntax e)
{
var expression = BindExpression(e.Expression);
return new BoundReturnStatement(expression, e.Span);
2018-11-16 12:45:03 +00:00
}
2018-11-17 18:13:05 +00:00
private BoundExpression BindTableExpression(TableExpressionSyntax e)
{
var keyType = Type.Unknown;
var valueType = Type.Unknown;
var statements = ImmutableArray.CreateBuilder<BoundStatement>();
var s = Scope;
Scope = BoundScope.WithReadOnlyScope(s);
2018-11-17 18:13:05 +00:00
foreach (var expressionSyntax in e.Expressions)
{
var bound = BindStatement((StatementSyntax) expressionSyntax);
statements.Add(bound);
2018-11-17 18:13:05 +00:00
}
var innerVariables = Scope.Variables;
Scope = s;
return new BoundTableExpression(keyType, valueType, innerVariables, statements.ToImmutable(), e.Span);
2018-11-17 18:13:05 +00:00
}
2018-11-18 13:18:24 +00:00
private BoundExpression BindIndexExpression(IndexExpressionSyntax e)
{
var expression = BindExpression(e.Expression);
2018-11-18 13:18:24 +00:00
var index = BindExpression(e.Index);
2018-11-19 15:22:13 +00:00
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 ScriptNull(), e.Span);
2018-11-19 15:22:13 +00:00
}
2018-11-19 12:53:44 +00:00
switch (expression.Type)
{
case Type.Table:
if (expression.Kind == BoundKind.BoundTableExpression && index.Kind == BoundKind.BoundLiteralExpression)
{
var table = (BoundTableExpression)expression;
var realIndex = (BoundLiteralExpression) index;
var variable = table.Expressions[realIndex.Value.ToString()];
return new BoundIndexExpression(expression, index, variable.Type, e.Span);
}
return new BoundIndexExpression(expression, index, Type.Unknown, e.Span);
2018-11-19 12:53:44 +00:00
case Type.UserData:
case Type.Unknown:
return new BoundIndexExpression(expression, index, Type.Unknown, e.Span);
2018-11-19 12:53:44 +00:00
case Type.String when index.Type == Type.Number:
return new BoundIndexExpression(expression, index, Type.String, e.Span);
2018-11-19 12:53:44 +00:00
default:
2018-11-19 13:30:00 +00:00
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
return new BoundLiteralExpression(new ScriptNull(), e.Span);
2018-11-19 12:53:44 +00:00
}
2018-11-18 13:18:24 +00:00
}
2018-11-19 15:22:13 +00:00
private BoundExpression BindFullStopIndexExpression(FullStopIndexExpressionSyntax e)
{
var expression = BindExpression(e.Expression);
var index = e.Index.Name;
switch (expression.Type)
{
case Type.Table:
if (expression.Kind == BoundKind.BoundTableExpression)
{
var table = (BoundTableExpression)expression;
if (table.Expressions.TryGetValue(index, out var variable))
{
return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span);
}
_diagnostics.LogError($"No variable {index} found in table.", e.Span);
}
if (expression.Kind == BoundKind.VariableExpression)
{
var table = (BoundVariableExpression)expression;
var realTable = table.Variable;
var variableDic = ((TableVariableSymbol) realTable.VariableSymbol).Variables;
if (variableDic.TryGetValue(index, out var variable))
{
return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span);
}
_diagnostics.LogError($"No variable {index} found in table {realTable.VariableSymbol.Name}.",
e.Span);
}
return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span);
case Type.UserData:
case Type.Unknown:
return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span);
case Type.String:
return new BoundFullStopIndexExpression(expression, index, Type.String, e.Span);
default:
_diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span);
return new BoundLiteralExpression(new ScriptNull(), e.Span);
}
}
2018-11-19 15:22:13 +00:00
private BoundStatement BindTableAssignmentStatement(TableAssigmentStatementSyntax e)
{
BoundExpression indexableExpression;
if (e.TableExpression.Kind == SyntaxKind.IndexExpression)
indexableExpression = (BoundIndexExpression)BindExpression(e.TableExpression);
else
indexableExpression = (BoundFullStopIndexExpression)BindExpression(e.TableExpression);
2018-11-19 15:22:13 +00:00
var value = BindExpression(e.Expression);
return new BoundTableAssigmentStatement(indexableExpression, value, e.Span);
2018-11-19 15:22:13 +00:00
}
2018-11-23 13:38:45 +00:00
private BoundStatement BindNumericForStatement(NumericForStatementSyntax e)
{
var variableName = e.Identifier.Name;
Scope = new BoundScope(Scope);
var variable = new VariableSymbol(variableName, Type.Number, true);
2018-11-24 11:42:54 +00:00
Scope.DefineLocalVariable(variable);
2018-11-23 17:18:07 +00:00
var boundStart = BindExpression(e.StartExpression);
var boundStop = BindExpression(e.StopExpression);
BoundExpression boundStep = null;
2018-11-23 13:38:45 +00:00
if (e.StepExpression != null)
boundStep = BindExpression(e.StepExpression);
var block = BindBlockStatement((BlockStatementSyntax) e.Block);
Scope = Scope.ParentScope;
return new BoundNumericForStatement(variable, boundStart, boundStop, boundStep, (BoundBlockStatement) block,
e.Span);
2018-11-23 13:38:45 +00:00
}
2018-11-23 17:18:07 +00:00
private BoundStatement BindGenericForStatement(GenericForStatementSyntax e)
{
Scope = new BoundScope(Scope);
var array = ImmutableArray.CreateBuilder<VariableSymbol>();
foreach (var variableIdentifier in e.Variables)
{
var variable = new VariableSymbol(variableIdentifier.Name, Type.Unknown, true);
2018-11-24 11:42:54 +00:00
Scope.DefineLocalVariable(variable);
2018-11-23 17:18:07 +00:00
array.Add(variable);
}
var boundEnumerableExpression = BindExpression(e.EnumerableExpression);
var block = BindBlockStatement(e.Block);
return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block, e.Span);
2018-11-23 17:18:07 +00:00
}
2018-11-11 17:12:42 +00:00
}
}