179 lines
5.4 KiB
C#
179 lines
5.4 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;
|
|
}
|
|
|
|
if (i < 0 || i >= List.Count)
|
|
{
|
|
diagnostics.LogError($"Index out of bounds, index: '{i}'", span);
|
|
return new ScriptNull();
|
|
}
|
|
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 EvaluationException(null,
|
|
$"Tried indexing a CSharp list with a value that's not an integer. Value: {scriptIndex.ToCSharpObject()}.",
|
|
span);
|
|
}
|
|
|
|
index--;
|
|
if (index > List.Count)
|
|
{
|
|
throw new EvaluationException(null,
|
|
$"Tried adding an item to a list at position {index}, but list is only of length {List.Count}.", span);
|
|
}
|
|
if (index == List.Count)
|
|
{
|
|
if (!List.IsFixedSize)
|
|
{
|
|
List.Add(value.ToCSharpObject());
|
|
}
|
|
else
|
|
{
|
|
throw new EvaluationException(null,
|
|
$"Tried adding an item to a list at position {index}, but list is of fixed size.", span);
|
|
}
|
|
}
|
|
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 bool Contains(ScriptType obj)
|
|
{
|
|
var cSharpObj = obj.ToCSharpObject();
|
|
return List.Contains(cSharpObj);
|
|
}
|
|
|
|
public void Delete(ScriptType key)
|
|
{
|
|
List.Remove(key.ToCSharpObject());
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
} |