2018-11-11 17:12:42 +00:00
|
|
|
using System;
|
2018-11-15 19:13:53 +00:00
|
|
|
using System.Collections.Generic;
|
2018-11-12 16:45:50 +00:00
|
|
|
using System.Collections.Immutable;
|
2018-11-14 12:09:01 +00:00
|
|
|
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
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
internal class Binder
|
2018-11-11 17:12:42 +00:00
|
|
|
{
|
|
|
|
private readonly Diagnostics _diagnostics;
|
2018-11-17 11:40:28 +00:00
|
|
|
public BoundScope Scope { get; private set; }
|
2018-11-11 17:12:42 +00:00
|
|
|
|
2018-11-15 19:48:52 +00:00
|
|
|
private Dictionary<FunctionVariableSymbol, UnboundFunctionStatement> _unboundFunctions =
|
|
|
|
new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>();
|
|
|
|
|
2018-11-17 12:05:08 +00:00
|
|
|
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
|
2018-11-11 17:12:42 +00:00
|
|
|
{
|
|
|
|
_diagnostics = diagnostics;
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = new BoundScope(variables, null);
|
2018-11-11 17:12:42 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
public BoundScript BindScript(BlockStatementSyntax e)
|
2018-11-11 17:12:42 +00:00
|
|
|
{
|
2018-11-12 16:45:50 +00:00
|
|
|
var bound = BindStatement(e);
|
2018-11-15 19:54:44 +00:00
|
|
|
foreach (var unboundFunctionStatement in _unboundFunctions)
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = new BoundScope(Scope);
|
2018-11-15 19:54:44 +00:00
|
|
|
foreach (var valueParameter in unboundFunctionStatement.Value.Parameters)
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetVariable(valueParameter);
|
2018-11-15 19:54:44 +00:00
|
|
|
}
|
|
|
|
unboundFunctionStatement.Value.Block =
|
|
|
|
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = Scope.ParentScope;
|
2018-11-15 19:54:44 +00:00
|
|
|
unboundFunctionStatement.Key.IsBound = true;
|
|
|
|
}
|
|
|
|
_unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>();
|
2018-11-16 13:46:12 +00:00
|
|
|
return new BoundScript((BoundBlockStatement) bound);
|
2018-11-11 17:12:42 +00:00
|
|
|
}
|
|
|
|
|
2018-11-15 14:51:05 +00:00
|
|
|
private BoundStatement BindStatement(StatementSyntax s)
|
2018-11-12 15:21:59 +00:00
|
|
|
{
|
|
|
|
switch (s.Kind)
|
|
|
|
{
|
|
|
|
case SyntaxKind.ExpressionStatement:
|
|
|
|
return BindExpressionStatement((ExpressionStatementSyntax) s);
|
2018-11-12 16:45:50 +00:00
|
|
|
case SyntaxKind.AssignmentStatement:
|
2018-11-12 15:21:59 +00:00
|
|
|
return BindAssignmentStatement((AssignmentExpressionSyntax) s);
|
2018-11-12 16:45:50 +00:00
|
|
|
case SyntaxKind.BlockStatement:
|
|
|
|
return BindBlockStatement((BlockStatementSyntax) s);
|
2018-11-13 11:48:50 +00:00
|
|
|
case SyntaxKind.IfStatement:
|
|
|
|
return BindIfStatement((IfStatementSyntax) s);
|
2018-11-15 14:51:05 +00:00
|
|
|
case SyntaxKind.FunctionStatement:
|
|
|
|
return BindFunctionStatement((FunctionStatementSyntax) s);
|
2018-11-16 12:45:03 +00:00
|
|
|
case SyntaxKind.ReturnStatement:
|
|
|
|
return BindReturnStatement((ReturnStatementSyntax) s);
|
2018-11-12 15:21:59 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
throw new NotImplementedException(s.Kind.ToString());
|
2018-11-12 15:21:59 +00:00
|
|
|
}
|
|
|
|
|
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-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);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e)
|
|
|
|
{
|
|
|
|
var value = e.Value;
|
2018-11-14 12:09:01 +00:00
|
|
|
LuaType outValue = null;
|
2018-11-11 17:12:42 +00:00
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case double d:
|
|
|
|
outValue = new NumberDouble(d);
|
|
|
|
break;
|
2018-11-11 17:19:30 +00:00
|
|
|
case long l:
|
|
|
|
outValue = new NumberLong(l);
|
|
|
|
break;
|
2018-11-14 12:09:01 +00:00
|
|
|
case bool b:
|
2018-11-14 12:10:24 +00:00
|
|
|
outValue = new LuaBoolean(b);
|
2018-11-11 17:12:42 +00:00
|
|
|
break;
|
2018-11-17 14:57:26 +00:00
|
|
|
case string s:
|
|
|
|
outValue = new LuaString(s);
|
|
|
|
break;
|
2018-11-14 12:45:49 +00:00
|
|
|
case null:
|
|
|
|
outValue = new LuaNull();
|
|
|
|
break;
|
2018-11-17 14:57:26 +00:00
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
default:
|
|
|
|
_diagnostics.LogUnknownType(e.Span);
|
|
|
|
break;
|
|
|
|
}
|
2018-11-14 12:45:49 +00:00
|
|
|
return new BoundLiteralExpression(outValue);
|
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)
|
|
|
|
{
|
|
|
|
var name = e.Identifier.Name;
|
2018-11-17 11:40:28 +00:00
|
|
|
if (!Scope.TryGetVariable(name, true, out var functionObj))
|
2018-11-15 19:13:53 +00:00
|
|
|
{
|
|
|
|
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
|
|
|
return new BoundLiteralExpression(new LuaNull());
|
|
|
|
}
|
|
|
|
|
|
|
|
var function = (FunctionVariableSymbol) functionObj;
|
|
|
|
|
|
|
|
var parameters = ImmutableArray.CreateBuilder<BoundExpression>();
|
|
|
|
foreach (var expressionSyntax in e.Parameters)
|
|
|
|
{
|
|
|
|
var bound = BindExpression(expressionSyntax);
|
|
|
|
parameters.Add(bound);
|
|
|
|
}
|
|
|
|
|
2018-11-15 19:48:52 +00:00
|
|
|
if (!function.IsBound)
|
2018-11-15 19:13:53 +00:00
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = new BoundScope(Scope);
|
2018-11-15 19:48:52 +00:00
|
|
|
for (var index = 0; index < function.Parameters.Length; index++)
|
2018-11-15 19:13:53 +00:00
|
|
|
{
|
2018-11-15 19:48:52 +00:00
|
|
|
var functionVariable = function.Parameters[index];
|
|
|
|
var callingVariable = parameters[index];
|
|
|
|
functionVariable.Type = callingVariable.Type;
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetVariable(functionVariable);
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
2018-11-15 19:48:52 +00:00
|
|
|
|
2018-11-16 13:46:12 +00:00
|
|
|
var unboundFunctionStatement = _unboundFunctions[function];
|
|
|
|
unboundFunctionStatement.Block =
|
|
|
|
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = Scope.ParentScope;
|
2018-11-15 19:48:52 +00:00
|
|
|
function.IsBound = true;
|
|
|
|
_unboundFunctions.Remove(function);
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: validate parameters
|
2018-11-16 13:11:27 +00:00
|
|
|
return new BoundFunctionCallExpression(function, parameters.ToImmutable());
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
|
|
|
|
{
|
|
|
|
var name = e.Identifier.Name;
|
2018-11-17 11:40:28 +00:00
|
|
|
if (!Scope.TryGetVariable(name, true, out var variable))
|
2018-11-12 16:45:50 +00:00
|
|
|
{
|
|
|
|
_diagnostics.LogUnknownVariable(e.Identifier.Span, name);
|
2018-11-14 12:45:49 +00:00
|
|
|
return new BoundLiteralExpression(new LuaNull());
|
2018-11-12 16:45:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new BoundVariableExpression(variable);
|
|
|
|
}
|
|
|
|
|
2018-11-12 15:21:59 +00:00
|
|
|
private BoundStatement BindExpressionStatement(ExpressionStatementSyntax s)
|
|
|
|
{
|
|
|
|
var exp = BindExpression(s.Expression);
|
|
|
|
return new BoundExpressionStatement(exp);
|
|
|
|
}
|
|
|
|
|
|
|
|
private BoundStatement BindAssignmentStatement(AssignmentExpressionSyntax e)
|
2018-11-11 19:31:55 +00:00
|
|
|
{
|
|
|
|
var name = e.Identifier.Name;
|
|
|
|
var boundExpression = BindExpression(e.Expression);
|
|
|
|
|
2018-11-14 15:39:52 +00:00
|
|
|
var isLocal = e.LocalToken != null;
|
2018-11-17 11:40:28 +00:00
|
|
|
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
2018-11-11 19:31:55 +00:00
|
|
|
{
|
2018-11-14 15:39:52 +00:00
|
|
|
variable = new VariableSymbol(name, boundExpression.Type, isLocal);
|
|
|
|
if (isLocal)
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetVariable(variable);
|
2018-11-11 19:31:55 +00:00
|
|
|
else
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetGlobalVariable(variable);
|
2018-11-11 19:31:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-14 12:58:12 +00:00
|
|
|
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
2018-11-14 16:10:06 +00:00
|
|
|
if (boundExpression.Type != variable.Type)
|
2018-11-11 19:31:55 +00:00
|
|
|
{
|
2018-11-14 12:58:12 +00:00
|
|
|
if (variable.Type == Type.Nil || boundExpression.Type == Type.Nil)
|
|
|
|
{
|
|
|
|
variable.Type = boundExpression.Type;
|
|
|
|
}
|
2018-11-15 19:13:53 +00:00
|
|
|
else if (variable.Type == Type.Unknown)
|
|
|
|
{
|
|
|
|
variable.Type = boundExpression.Type;
|
|
|
|
}
|
|
|
|
else if (boundExpression.Type == Type.Unknown && boundExpression is BoundVariableExpression v)
|
|
|
|
{
|
|
|
|
v.Variable.Type = variable.Type;
|
|
|
|
}
|
2018-11-14 12:58:12 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
_diagnostics.LogCannotConvert(boundExpression.Type, variable.Type, e.Span);
|
|
|
|
return new BoundExpressionStatement(boundExpression);
|
|
|
|
}
|
2018-11-11 19:31:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 15:21:59 +00:00
|
|
|
return new BoundVariableAssignment(variable, boundExpression);
|
2018-11-11 19:00:06 +00:00
|
|
|
}
|
2018-11-11 19:41:24 +00:00
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
|
|
|
|
private BoundStatement BindBlockStatement(BlockStatementSyntax e)
|
2018-11-11 19:41:24 +00:00
|
|
|
{
|
2018-11-12 16:45:50 +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);
|
2018-11-12 16:45:50 +00:00
|
|
|
arr.Add(bound);
|
2018-11-11 19:41:24 +00:00
|
|
|
}
|
2018-11-15 14:51:05 +00:00
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
return new BoundBlockStatement(arr.ToImmutable());
|
2018-11-11 19:41:24 +00:00
|
|
|
}
|
2018-11-13 11:48:50 +00:00
|
|
|
|
|
|
|
private BoundStatement BindIfStatement(IfStatementSyntax e)
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = new BoundScope(Scope);
|
2018-11-13 11:48:50 +00:00
|
|
|
var condition = BindExpressionStatement(e.Condition);
|
|
|
|
var block = BindBlockStatement(e.Block);
|
2018-11-17 11:40:28 +00:00
|
|
|
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);
|
|
|
|
}
|
2018-11-13 12:54:51 +00:00
|
|
|
if (e.ElseStatement == null)
|
|
|
|
{
|
|
|
|
return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = new BoundScope(Scope);
|
2018-11-13 12:54:51 +00:00
|
|
|
var elseBlock = BindBlockStatement(e.ElseStatement.Block);
|
|
|
|
var elseStatement = new BoundElseStatement((BoundBlockStatement) elseBlock);
|
2018-11-17 11:40:28 +00:00
|
|
|
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);
|
|
|
|
}
|
2018-11-13 11:48:50 +00:00
|
|
|
}
|
|
|
|
|
2018-11-15 14:51:05 +00:00
|
|
|
private BoundStatement BindFunctionStatement(FunctionStatementSyntax e)
|
|
|
|
{
|
|
|
|
var name = e.Identifier.Name;
|
|
|
|
var isLocal = e.LocalToken != null;
|
|
|
|
|
2018-11-17 11:40:28 +00:00
|
|
|
var innerScope = new BoundScope(Scope);
|
2018-11-15 14:51:05 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-11-17 11:40:28 +00:00
|
|
|
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
2018-11-15 14:51:05 +00:00
|
|
|
{
|
|
|
|
variable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable());
|
|
|
|
if (isLocal)
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetVariable(variable);
|
2018-11-15 14:51:05 +00:00
|
|
|
else
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope.SetGlobalVariable(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(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 19:48:52 +00:00
|
|
|
if (parameters.Count == 0)
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = innerScope;
|
2018-11-15 19:48:52 +00:00
|
|
|
var block = BindBlockStatement(e.Block);
|
2018-11-17 11:40:28 +00:00
|
|
|
Scope = Scope.ParentScope;
|
2018-11-15 19:48:52 +00:00
|
|
|
((FunctionVariableSymbol) variable).IsBound = true;
|
2018-11-16 13:46:12 +00:00
|
|
|
var func = new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block);
|
|
|
|
return func;
|
2018-11-15 19:48:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var unbound = new UnboundFunctionStatement(variable, parameters.ToImmutable(), e.Block);
|
|
|
|
_unboundFunctions.Add((FunctionVariableSymbol) variable, unbound);
|
|
|
|
return unbound;
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2018-11-17 18:13:05 +00:00
|
|
|
private BoundExpression BindTableExpression(TableExpressionSyntax e)
|
|
|
|
{
|
|
|
|
var keyType = Type.Unknown;
|
|
|
|
var valueType = Type.Unknown;
|
|
|
|
var currentKey = 0;
|
|
|
|
var dictionary = new Dictionary<string, BoundExpression>();
|
|
|
|
foreach (var expressionSyntax in e.Expressions)
|
|
|
|
{
|
|
|
|
if (expressionSyntax.Kind == SyntaxKind.AssignmentStatement)
|
|
|
|
{
|
|
|
|
var assignment = (AssignmentExpressionSyntax) expressionSyntax;
|
|
|
|
var key = assignment.Identifier.Name;
|
|
|
|
if (keyType == Type.Unknown)
|
|
|
|
keyType = Type.String;
|
|
|
|
if (dictionary.ContainsKey(key))
|
|
|
|
{
|
|
|
|
// TODO: Log
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var bound = BindExpression(assignment.Expression);
|
|
|
|
if (valueType == Type.Unknown)
|
|
|
|
valueType = bound.Type;
|
|
|
|
dictionary.Add(key, bound);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var expression = (ExpressionSyntax) expressionSyntax;
|
|
|
|
currentKey++;
|
|
|
|
if (dictionary.ContainsKey(currentKey.ToString()))
|
|
|
|
{
|
|
|
|
// TODO: Log
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (keyType == Type.Unknown)
|
|
|
|
keyType = Type.Number;
|
|
|
|
var bound = BindExpression(expression);
|
|
|
|
if (valueType == Type.Unknown)
|
|
|
|
valueType = bound.Type;
|
|
|
|
dictionary.Add(currentKey.ToString(), bound);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new BoundTableExpression(keyType, valueType, dictionary);
|
|
|
|
}
|
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
}
|
|
|
|
}
|