diff --git a/Upsilon/BaseTypes/ScriptIterator.cs b/Upsilon/BaseTypes/ScriptIterator.cs new file mode 100644 index 0000000..abf9d76 --- /dev/null +++ b/Upsilon/BaseTypes/ScriptIterator.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using Upsilon.BaseTypes.ScriptTypeInterfaces; + +namespace Upsilon.BaseTypes +{ + internal abstract class ScriptIterator : ScriptType, IIterable + { + public IIterable BaseIterator { get; } + public override Type Type => Type.Table; + + public ScriptIterator(IIterable baseIterator) + { + BaseIterator = baseIterator; + } + + public override object ToCSharpObject() + { + return GetEnumerator(); + } + + public override System.Type GetCSharpType() + { + return typeof(IEnumerator); + } + + public ScriptType GetValueFromIndex(ScriptType index) + { + throw new InvalidOperationException(); + } + + public abstract IEnumerator GetEnumerator(); + + } + + internal class UpTillNullPairsScriptIterator : ScriptIterator + { + public UpTillNullPairsScriptIterator(IIterable baseIterator) : base(baseIterator) + { + } + + public override IEnumerator GetEnumerator() + { + using(var baseEnumerator = BaseIterator.GetEnumerator()) + { + while (baseEnumerator.MoveNext()) + { + var key = baseEnumerator.Current; + if (key == null) + break; + var value = BaseIterator.GetValueFromIndex(key); + if (value == null) + break; + yield return new SimpleScriptTable(new List(){key, value}); + } + } + } + } + + internal class PairsScriptIterator : ScriptIterator + { + public PairsScriptIterator(IIterable baseIterator) : base(baseIterator) + { + } + + public override IEnumerator GetEnumerator() + { + using(var baseEnumerator = BaseIterator.GetEnumerator()) + { + while (baseEnumerator.MoveNext()) + { + var key = baseEnumerator.Current; + var value = BaseIterator.GetValueFromIndex(key); + yield return new SimpleScriptTable(new List(){key, value}); + } + } + } + } + +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/ScriptTable.cs b/Upsilon/BaseTypes/ScriptTable.cs index 15cbbe2..abbbcea 100644 --- a/Upsilon/BaseTypes/ScriptTable.cs +++ b/Upsilon/BaseTypes/ScriptTable.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Upsilon.BaseTypes.ScriptTypeInterfaces; @@ -44,16 +45,25 @@ namespace Upsilon.BaseTypes EvaluationScope.CreateLocal(new VariableSymbol(s, value.Type, false), value); } - public IEnumerator<(string Key, ScriptType value)> GetEnumerator() + public ScriptType GetValueFromIndex(ScriptType index) + { + if (EvaluationScope.TryGet(index.ToString(), out var result)) + { + return result; + } + throw new Exception($"Can't find key '{index}' in table."); + } + + public IEnumerator GetEnumerator() { return Enumerator(); } - private IEnumerator<(string Key, ScriptType value)> Enumerator() + private IEnumerator Enumerator() { foreach (var variable in EvaluationScope.Variables) { - yield return (variable.Key, variable.Value); + yield return variable.Key.ToScriptType(); } } } diff --git a/Upsilon/BaseTypes/ScriptTypeInterfaces/IITerable.cs b/Upsilon/BaseTypes/ScriptTypeInterfaces/IITerable.cs index d76f82f..715152e 100644 --- a/Upsilon/BaseTypes/ScriptTypeInterfaces/IITerable.cs +++ b/Upsilon/BaseTypes/ScriptTypeInterfaces/IITerable.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; +using Upsilon.Evaluator; namespace Upsilon.BaseTypes.ScriptTypeInterfaces { internal interface IIterable { - IEnumerator<(string Key, ScriptType value)> GetEnumerator(); + ScriptType GetValueFromIndex(ScriptType index); + IEnumerator GetEnumerator(); } } \ No newline at end of file diff --git a/Upsilon/BaseTypes/SimpleScriptTable.cs b/Upsilon/BaseTypes/SimpleScriptTable.cs index ae1697b..e2faac7 100644 --- a/Upsilon/BaseTypes/SimpleScriptTable.cs +++ b/Upsilon/BaseTypes/SimpleScriptTable.cs @@ -38,6 +38,8 @@ namespace Upsilon.BaseTypes return _objects[i]; } + public ScriptType this[int index] => _objects[index]; + public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value) { throw new System.NotImplementedException(); diff --git a/Upsilon/BaseTypes/UserData/ListUserData.cs b/Upsilon/BaseTypes/UserData/ListUserData.cs index 387d88d..5a6c1bf 100644 --- a/Upsilon/BaseTypes/UserData/ListUserData.cs +++ b/Upsilon/BaseTypes/UserData/ListUserData.cs @@ -1,5 +1,7 @@ +using System; using System.Collections; using System.Collections.Generic; +using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.Evaluator; using Upsilon.Text; @@ -51,9 +53,18 @@ namespace Upsilon.BaseTypes.UserData return List.GetType(); } - public IEnumerator<(string Key, ScriptType value)> GetEnumerator() + public ScriptType GetValueFromIndex(ScriptType index) { - throw new System.NotImplementedException(); + var num = (ScriptNumberLong)index; + return List[(int) num.Value].ToScriptType(); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < List.Count; i++) + { + yield return new ScriptNumberLong(i); + } } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 8d8a3f9..6b0006e 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -548,11 +548,17 @@ namespace Upsilon.Evaluator { while (enumerator.MoveNext()) { - var (key, value) = enumerator.Current; + var current = enumerator.Current; + if (current == null || current.Type != Type.Table) + { + throw new Exception($"Can't assign result value with type '{current.Type}' to multiple values"); + } + + var table = (SimpleScriptTable)current; if (e.Variables[0].Name != "_") - innerEvaluator.Scope.CreateLocal(e.Variables[0], key.ToScriptType()); + innerEvaluator.Scope.CreateLocal(e.Variables[0], table[0].ToScriptType()); if (e.Variables[1].Name != "_") - innerEvaluator.Scope.CreateLocal(e.Variables[1], value); + innerEvaluator.Scope.CreateLocal(e.Variables[1], table[1]); innerEvaluator.EvaluateBoundBlockStatement((BoundBlockStatement) e.Block); if (innerEvaluator.HasBroken) break; diff --git a/Upsilon/StandardLibraries/BasicFunctions.cs b/Upsilon/StandardLibraries/BasicFunctions.cs index 645c775..0c415f8 100644 --- a/Upsilon/StandardLibraries/BasicFunctions.cs +++ b/Upsilon/StandardLibraries/BasicFunctions.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.ScriptTypeInterfaces; -using Type = Upsilon.BaseTypes.Type; // ReSharper disable UnusedMember.Global // ReSharper disable MemberCanBePrivate.Global @@ -28,11 +26,18 @@ namespace Upsilon.StandardLibraries } [StandardLibraryScriptFunction("ipairs")] + public IIterable UpTillNullPairs(IIterable table) + { + return new UpTillNullPairsScriptIterator(table); + } + + [StandardLibraryScriptFunction("pairs")] public IIterable Pairs(IIterable table) { - return table; + return new PairsScriptIterator(table); } + [StandardLibraryScriptFunction("tonumber")] public ScriptNumber ToNumber(ScriptString obj) { diff --git a/UpsilonTests/GeneralTests/ForLoopTests.cs b/UpsilonTests/GeneralTests/ForLoopTests.cs index b6b647c..6e9bf9e 100644 --- a/UpsilonTests/GeneralTests/ForLoopTests.cs +++ b/UpsilonTests/GeneralTests/ForLoopTests.cs @@ -85,7 +85,7 @@ return a const string input = @" arr = {100, 56, 28} value = 0 -for key, val in arr do +for key, val in ipairs(arr) do value = value + val end return value @@ -103,7 +103,7 @@ return value const string input = @" arr = {100, 56, 28} value = 0 -for key, val in arr do +for key, val in ipairs(arr) do local keyInt = tonumber(key) value = value + keyInt end diff --git a/UpsilonTests/GeneralTests/FunctionTests.cs b/UpsilonTests/GeneralTests/FunctionTests.cs index 3e5e708..32c8501 100644 --- a/UpsilonTests/GeneralTests/FunctionTests.cs +++ b/UpsilonTests/GeneralTests/FunctionTests.cs @@ -206,7 +206,7 @@ end const string input = @" arr = {100, 56, 28} value = 0 -for key, val in arr do +for key, val in ipairs(arr) do value = value + tonumber(key) end return value diff --git a/UpsilonTests/GeneralTests/ScopeTests.cs b/UpsilonTests/GeneralTests/ScopeTests.cs index b308e2f..d8c9ebe 100644 --- a/UpsilonTests/GeneralTests/ScopeTests.cs +++ b/UpsilonTests/GeneralTests/ScopeTests.cs @@ -51,7 +51,7 @@ b = a const string input = @" arr = {100, 56, 28} local value = 0 -for key, val in arr do +for key, val in ipairs(arr) do value = value + val end return value