A range type can be created in Amigo by two ways. For example
var x = new Range<char>('c'..'u');
or using the syntax sugar:
var x = 'c'..'u';
The class Range<R> is defined in the module system.am as
class Range<R>: IEnumerable { var FLow: R; var FHigh: R; fn constructor(L: R, H: R) { FLow = L; FHigh = H; } fn GetEnumerator(): RangeEnumerator { new RangeEnumerator(FLow as int, FHigh as int); } property Low: R => FLow; property High: R => FHigh; }
where class RangeEnumerator is:
class RangeEnumerator { var FLow, FHigh; var FCurrent; fn Reset() { FCurrent = FLow - 1; } fn MoveNext(): bool { FCurrent = FCurrent + 1; FCurrent <= FHigh; } fn GetCurrent() { FCurrent; } fn constructor (Low, High) { FLow = Low; FHigh = High; Reset(); } }
Class ArrayList already exists in the module system.am. It partially duplicates the functionality of the corresponding .Net class and simulates dynamic tuple.
Amigo language introduces dynamic arrays as typed ranged tuples:
class DynArray<T>: ArrayList { fn constructor(N) { base(); for (var I = 0; I < N; I++) Add(null); }; property this[I: int]: T { get => FItems[I]; set => FItems[I] = value; } }
Keyword this denotes default property. It introduces restriction for the type of array elements.
Instances of DynArray<T> can be created with using C# - like syntax:
var a: int[] = new int[5]; a[2] = 4; for (var x in a) println(x);
or more simple:
var a = new int[5];
In implementation, access to the array elements is done with the inline functions.
Let's consider ranged arrays (Pascal-like arrays) in Amigo. First of all, we are introducing the ranged tuples:
class RangedTuple<R>: IEnumerable { var FItems: Tuple; var FLow: R; var FHigh: R; bunch constructor { fn (Low: R, High: R) { FLow = Low; FHigh = High; FItems = new Tuple((FHigh as int) - (FLow as int) + 1); } , fn (AType) { FLow = low(AType) as R; FHigh = high(AType) as R; FItems = new Tuple((FHigh as int) - (FLow as int) + 1); } } fn GetEnumerator(): RangedTupleEnumerator { new RangedTupleEnumerator(FItems, FLow as int, FHigh as int); } property this[I: R] { get => FItems[(I as int) - (FLow as int)]; set => FItems[(I as int) - (FLow as int)] = value; } property Low => FLow; property High => FHigh; property Length => FItems.Length; }
Generic parameter R denotes a range type. Two overloaded constructors are joined in a bunch. Class RangedTupleEnumerator is:
class RangedTupleEnumerator { var A, I, L, H, FCurrent; fn Reset() { I = L - 1; } fn MoveNext(): bool { I++; I <= H; } fn GetCurrent() { A[I - L]; } fn constructor (A, L, H) { this.A = A; this.L = L; this.H = H; Reset(); } }
Now, we can introduce the ranged array (Pascal-like) array:
class RangedArray<R, T>: RangedTuple<R> { bunch constructor { fn (Low: R, High: R) { base(Low, High); } , fn (AType) { base(AType); } } property this[I: R]: T { get => FItems[(I as int) - (FLow as int)]; set => FItems[(I as int) - (FLow as int)] = value; } }
Class RangedArray<R, T> inherits class RangedTuple<R> and restricts access to the array elements.
It will be used in the implementation of the AmigoPascal. As Amigo engine provides cross-language integration, the module system.am will be used in AmigoPascal programs without changes.
In the Amigo language, the syntax sugar is available for the ranged arrays:
var A = new int[3..15]; for (var x in A) println(x);