using System.Collections.Generic; using Upsilon.BaseTypes; using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.Evaluator; using Upsilon.Exceptions; using Upsilon.Parser; using Upsilon.Text; namespace Upsilon.Binder { public class BoundIndexExpression : BoundExpression { public BoundIndexExpression(BoundExpression identifier, BoundExpression index, TypeContainer type, TextSpan span) : base(span) { Identifier = identifier; Index = index; ValueType = type; } public BoundExpression Identifier { get; } public BoundExpression Index { get; } public override BoundKind Kind => BoundKind.BoundIndexExpression; public override IEnumerable GetChildren() { yield return Identifier; yield return Index; } public override TypeContainer ValueType { get; } internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state) { var variable = Identifier.Evaluate(scope, diagnostics, ref state); if (variable.Type == Type.Nil) { throw new EvaluationException(state.Script.FileName, $"Nil variable can't be indexed", Span); } if (!(variable is IIndexable indexable)) { throw new EvaluationException(state.Script.FileName, $"Variable of type '{variable.Type}' is not indexable.", Span); } var innerScope = scope; if (variable is IScopeOwner scopeOwner) { innerScope = scopeOwner.EvaluationScope; } if (variable.Type == Type.Unknown) { throw new EvaluationException(state.Script.FileName, $"Variable of type '{variable.Type}' is not a registered type, and can't be indexed.", Span); } if (variable.Type == Type.UserData && variable.Type is UndefinedUserDataTypeContainer userDataTypeContainer) { throw new EvaluationException(state.Script.FileName, $"Variable of type '{userDataTypeContainer.UserData}' is not a registered type, and can't be indexed.", Span); } var indexer = Index.Evaluate(scope, diagnostics, ref state); return indexable.Get(diagnostics, Span, indexer, innerScope); } } public class BoundFullStopIndexExpression : BoundExpression { public BoundExpression Expression { get; } public string Index { get; } public BoundFullStopIndexExpression(BoundExpression expression, string index, TypeContainer type, TextSpan span) : base(span) { Expression = expression; Index = index; ValueType = type; } public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression; public override IEnumerable GetChildren() { yield return Expression; } public override TypeContainer ValueType { get; } internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state) { var variable = Expression.Evaluate(scope, diagnostics, ref state); if (variable.Type == Type.Nil) { throw new EvaluationException(state.Script.FileName, $"Nil variable can't be indexed", Span); } if (!(variable is IIndexable indexable)) { throw new EvaluationException(state.Script.FileName, $"Variable of type '{variable.Type}' is not indexable.", Span); } if (variable.Type == Type.UserData && variable.Type is UndefinedUserDataTypeContainer userDataTypeContainer) { throw new EvaluationException(state.Script.FileName, $"Variable of type '{userDataTypeContainer.UserData}' is not a registered type, and can't be indexed.", Span); } var innerScope = scope; if (variable is IScopeOwner scopeOwner) { innerScope = scopeOwner.EvaluationScope; } return indexable.Get(diagnostics, Span, Index.ToScriptType(), innerScope); } } }