Upsilon/Upsilon/BaseTypes/UserData/ListUserData.cs

154 lines
4.7 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.BoundTypes;
using Upsilon.Evaluator;
using Upsilon.Exceptions;
using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData
{
internal class ListUserData : ScriptType, IUserData, IIterable, ILengthType
{
public IList List { get; }
public string TypeName { get; }
public ListUserData(IList list)
{
List = list;
var type = list.GetType();
System.Type elementType;
if (type.IsArray)
{
elementType = type.GetElementType();
TypeName = BoundTypeHandler.GetTypeName(elementType);
}
else
{
elementType = type.GetGenericArguments()[0];
TypeName = BoundTypeHandler.GetTypeName(elementType);
}
if (TypeName == null)
{
Type = new CompositeTypeContainer(new TypeContainer[] {BaseTypes.Type.Number, new UndefinedUserDataTypeContainer(elementType)}
.ToImmutableArray());
}
else
{
Type = new CompositeTypeContainer(new TypeContainer[] {BaseTypes.Type.Number, new TypeContainer(TypeName)}
.ToImmutableArray());
}
}
public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{
int i;
if (index.Type == BaseTypes.Type.String)
{
var str = (ScriptString)index;
i = int.Parse(str.Value) - 1;
}
else if (index.Type == BaseTypes.Type.Number)
{
var ind = (Number.ScriptNumberLong) index;
i = (int) ind.Value - 1;
}
else
{
return null;
}
return List[i].ToScriptType();
}
public void Set(Diagnostics diagnostics, TextSpan span, ScriptType scriptIndex, ScriptType value)
{
var index = -1;
if (scriptIndex.Type == BaseTypes.Type.Number || scriptIndex.Type == BaseTypes.Type.Unknown)
{
index = Convert.ToInt32(scriptIndex.ToCSharpObject());
}
else if (scriptIndex.Type == BaseTypes.Type.String)
{
index = int.Parse(((ScriptString) scriptIndex).Value);
}
else
{
throw new ScriptRuntimeException(null,
$"Tried indexing a CSharp list with a value that's not an integer. Value: {scriptIndex.ToCSharpObject()}",
span, diagnostics.ScriptString.GetSpan(span));
}
index--;
if (index > List.Count)
{
throw new Exception(
$"Tried adding an item to a list at position {index}, but list is only of length {List.Count}");
}
if (index == List.Count)
{
List.Add(value.ToCSharpObject());
}
else
{
List[index] = value.ToCSharpObject();
}
}
public override TypeContainer Type { get; }
public override object ToCSharpObject()
{
return List;
}
public override System.Type GetCSharpType()
{
return List.GetType();
}
public ScriptType GetValueFromIndex(ScriptType index)
{
var num = (ScriptNumberLong)index;
return List[(int) num.Value].ToScriptType();
}
public IEnumerator<ScriptType> GetScriptEnumerator()
{
for (int i = 0; i < List.Count; i++)
{
yield return new ScriptNumberLong(i);
}
}
public ScriptNumberLong Length()
{
return new ScriptNumberLong(List.Count);
}
protected bool Equals(ListUserData other)
{
return List.Equals(other.List);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() == List.GetType())
{
return List.Equals(obj);
}
if (obj.GetType() != this.GetType()) return false;
return Equals((ListUserData) obj);
}
public override string ToString()
{
return string.Join(", ", List);
}
}
}