From b815bcd17fe083846b1b8aac94fd0ceffca544cc Mon Sep 17 00:00:00 2001 From: Spotandjake <40705786+spotandjake@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:44:05 -0500 Subject: [PATCH] feat(stdlib): Add `toList`, `fromList`, `toArray`, `fromArray` to Stack (#2198) Co-authored-by: Oscar Spencer --- compiler/test/stdlib/stack.test.gr | 66 +++++++ stdlib/stack.gr | 171 ++++++++++++++++- stdlib/stack.md | 282 +++++++++++++++++++++++++++++ 3 files changed, 518 insertions(+), 1 deletion(-) diff --git a/compiler/test/stdlib/stack.test.gr b/compiler/test/stdlib/stack.test.gr index 8f56a3ae9..0bbcd1116 100644 --- a/compiler/test/stdlib/stack.test.gr +++ b/compiler/test/stdlib/stack.test.gr @@ -56,6 +56,44 @@ let stack2 = Stack.make(size=1) Stack.push(0, stack2) assert stack == stack2 +// Stack.toList +let s = Stack.make() +assert Stack.toList(s) == [] +Stack.push(1, s) +Stack.push(2, s) +Stack.push(3, s) +assert Stack.toList(s) == [3, 2, 1] +Stack.pop(s) +assert Stack.toList(s) == [2, 1] + +// Stack.fromList +let s = Stack.fromList([3, 2, 1]) +assert Stack.pop(s) == Some(3) +assert Stack.pop(s) == Some(2) +assert Stack.pop(s) == Some(1) +assert Stack.pop(s) == None +let s = Stack.fromList([]) +assert Stack.pop(s) == None + +// Stack.toArray +let s = Stack.make() +assert Stack.toArray(s) == [>] +Stack.push(1, s) +Stack.push(2, s) +Stack.push(3, s) +assert Stack.toArray(s) == [> 3, 2, 1] +Stack.pop(s) +assert Stack.toArray(s) == [> 2, 1] + +// Stack.fromArray +let s = Stack.fromArray([> 3, 2, 1]) +assert Stack.pop(s) == Some(3) +assert Stack.pop(s) == Some(2) +assert Stack.pop(s) == Some(1) +assert Stack.pop(s) == None +let s = Stack.fromArray([>]) +assert Stack.pop(s) == None + module Immutable { use Stack.{ module Immutable as Stack } @@ -90,4 +128,32 @@ module Immutable { assert Stack.size(Stack.empty) == 0 assert Stack.size(sampleStack) == 3 assert Stack.size(Stack.pop(Stack.pop(sampleStack))) == 1 + + // Stack.toList + let stack = Stack.empty + let stack = Stack.push(1, stack) + let stack = Stack.push(2, stack) + assert Stack.toList(stack) == [2, 1] + + // Stack.fromList + let stack = Stack.fromList([2, 1]) + assert Stack.peek(stack) == Some(2) + let stack = Stack.pop(stack) + assert Stack.peek(stack) == Some(1) + let stack = Stack.pop(stack) + assert Stack.isEmpty(stack) + + // Stack.toArray + let stack = Stack.empty + let stack = Stack.push(1, stack) + let stack = Stack.push(2, stack) + assert Stack.toArray(stack) == [> 2, 1] + + // Stack.fromArray + let stack = Stack.fromArray([> 2, 1]) + assert Stack.peek(stack) == Some(2) + let stack = Stack.pop(stack) + assert Stack.peek(stack) == Some(1) + let stack = Stack.pop(stack) + assert Stack.isEmpty(stack) } diff --git a/stdlib/stack.gr b/stdlib/stack.gr index 2c5112de7..d50282643 100644 --- a/stdlib/stack.gr +++ b/stdlib/stack.gr @@ -30,7 +30,7 @@ abstract record Stack { * * @param size: The initial storage size of the stack * @returns An empty stack - * + * * @since v0.6.0 */ provide let make = (size=16) => { @@ -134,6 +134,95 @@ provide let copy = stack => { { size, array: Array.copy(array) } } +/** + * Creates a list containing the elements of a stack. + * + * @param stack: The stack to convert + * @returns A list containing all stack values + * + * @example + * let stack = Stack.make() + * Stack.push(1, stack) + * Stack.push(2, stack) + * assert Stack.toList(stack) == [2, 1] + * + * @since v0.7.0 + */ +provide let toList = stack => { + let size = stack.size + List.init(size, i => match (stack.array[size - i - 1]) { + Some(v) => v, + None => fail "Impossible: None in stack bounds on toList", + }) +} + +/** + * Creates a stack from a list. + * + * @param list: The list to convert + * @returns A stack containing all list values + * + * @example + * let stack = Stack.fromList([3, 2, 1]) + * assert Stack.pop(stack) == Some(3) + * assert Stack.pop(stack) == Some(2) + * assert Stack.pop(stack) == Some(1) + * assert Stack.pop(stack) == None + * + * @since v0.7.0 + */ +provide let fromList = list => { + let stack = make(size=List.length(list)) + List.forEach(v => push(v, stack), List.reverse(list)) + stack +} + +/** + * Creates an array containing the elements of a stack. + * + * @param stack: The stack to convert + * @returns An array containing all stack values + * + * @example + * let stack = Stack.make() + * Stack.push(1, stack) + * Stack.push(2, stack) + * assert Stack.toArray(stack) == [> 2, 1] + * + * @since v0.7.0 + */ +provide let toArray = stack => { + let size = stack.size + Array.init(size, i => match (stack.array[size - i - 1]) { + Some(v) => v, + None => fail "Impossible: None in stack bounds on toList", + }) +} + +/** + * Creates a stack from an array. + * + * @param arr: The array to convert + * @returns A stack containing all array values + * + * @example + * let s = Stack.fromArray([> 3, 2, 1]) + * assert Stack.pop(s) == Some(3) + * assert Stack.pop(s) == Some(2) + * assert Stack.pop(s) == Some(1) + * assert Stack.pop(s) == None + * + * @since v0.7.0 + */ +provide let fromArray = arr => { + let arrLen = Array.length(arr) + let stack = make(size=arrLen) + for (let mut i = arrLen - 1; i >= 0; i -= 1) { + push(arr[i], stack) + } + stack +} + /** * An immutable stack implementation. */ @@ -237,4 +326,84 @@ provide module Immutable { { data } => List.length(data), } } + + /** + * Creates a list containing the elements of a stack. + * + * @param stack: The stack to convert + * @returns A list containing all stack values + * + * @example + * use Stack.{ module Immutable as Stack } + * let stack = Stack.empty + * let stack = Stack.push(1, stack) + * let stack = Stack.push(2, stack) + * assert Stack.toList(stack) == [2, 1] + * + * @since v0.7.0 + */ + provide let toList = stack => { + stack.data + } + + /** + * Creates a stack from a list. + * + * @param list: The list to convert + * @returns A stack containing all list values + * + * @example + * use Stack.{ module Immutable as Stack } + * let stack = Stack.fromList([2, 1]) + * assert Stack.peek(stack) == Some(2) + * let stack = Stack.pop(stack) + * assert Stack.peek(stack) == Some(1) + * let stack = Stack.pop(stack) + * assert Stack.isEmpty(stack) + * + * @since v0.7.0 + */ + provide let fromList = list => { + { data: list, } + } + + /** + * Creates an array containing the elements of a stack. + * + * @param stack: The stack to convert + * @returns An array containing all stack values + * + * @example + * use Stack.{ module Immutable as Stack } + * let stack = Stack.empty + * let stack = Stack.push(1, stack) + * let stack = Stack.push(2, stack) + * assert Stack.toArray(stack) == [> 2, 1] + * + * @since v0.7.0 + */ + provide let toArray = stack => { + Array.fromList(stack.data) + } + + /** + * Creates a stack from an array. + * + * @param arr: The array to convert + * @returns A stack containing all array values + * + * @example + * use Stack.{ module Immutable as Stack } + * let stack = Stack.fromArray([> 2, 1]) + * assert Stack.peek(stack) == Some(2) + * let stack = Stack.pop(stack) + * assert Stack.peek(stack) == Some(1) + * let stack = Stack.pop(stack) + * assert Stack.isEmpty(stack) + * + * @since v0.7.0 + */ + provide let fromArray = arr => { + { data: Array.toList(arr), } + } } diff --git a/stdlib/stack.md b/stdlib/stack.md index 145cc55ef..946e833dd 100644 --- a/stdlib/stack.md +++ b/stdlib/stack.md @@ -225,6 +225,144 @@ Returns: |----|-----------| |`Stack`|A new stack containing the elements from the input| +### Stack.**toList** + +
+Added in next +No other changes yet. +
+ +```grain +toList : (stack: Stack
) => List +``` + +Creates a list containing the elements of a stack. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`stack`|`Stack`|The stack to convert| + +Returns: + +|type|description| +|----|-----------| +|`List`|A list containing all stack values| + +Examples: + +```grain +let stack = Stack.make() +Stack.push(1, stack) +Stack.push(2, stack) +assert Stack.toList(stack) == [2, 1] +``` + +### Stack.**fromList** + +
+Added in next +No other changes yet. +
+ +```grain +fromList : (list: List
) => Stack +``` + +Creates a stack from a list. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`list`|`List`|The list to convert| + +Returns: + +|type|description| +|----|-----------| +|`Stack`|A stack containing all list values| + +Examples: + +```grain +let stack = Stack.fromList([3, 2, 1]) +assert Stack.pop(stack) == Some(3) +assert Stack.pop(stack) == Some(2) +assert Stack.pop(stack) == Some(1) +assert Stack.pop(stack) == None +``` + +### Stack.**toArray** + +
+Added in next +No other changes yet. +
+ +```grain +toArray : (stack: Stack
) => Array +``` + +Creates an array containing the elements of a stack. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`stack`|`Stack`|The stack to convert| + +Returns: + +|type|description| +|----|-----------| +|`Array`|An array containing all stack values| + +Examples: + +```grain +let stack = Stack.make() +Stack.push(1, stack) +Stack.push(2, stack) +assert Stack.toArray(stack) == [> 2, 1] +``` + +### Stack.**fromArray** + +
+Added in next +No other changes yet. +
+ +```grain +fromArray : (arr: Array
) => Stack +``` + +Creates a stack from an array. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`arr`|`Array`|The array to convert| + +Returns: + +|type|description| +|----|-----------| +|`Stack`|A stack containing all array values| + +Examples: + +```grain +let s = Stack.fromArray([> 3, 2, 1]) +assert Stack.pop(s) == Some(3) +assert Stack.pop(s) == Some(2) +assert Stack.pop(s) == Some(1) +assert Stack.pop(s) == None +``` + ## Stack.Immutable An immutable stack implementation. @@ -427,3 +565,147 @@ Returns: |----|-----------| |`Number`|The count of the items in the stack| +#### Stack.Immutable.**toList** + +
+Added in next +No other changes yet. +
+ +```grain +toList : (stack: ImmutableStack
) => List +``` + +Creates a list containing the elements of a stack. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`stack`|`ImmutableStack`|The stack to convert| + +Returns: + +|type|description| +|----|-----------| +|`List`|A list containing all stack values| + +Examples: + +```grain +use Stack.{ module Immutable as Stack } +let stack = Stack.empty +let stack = Stack.push(1, stack) +let stack = Stack.push(2, stack) +assert Stack.toList(stack) == [2, 1] +``` + +#### Stack.Immutable.**fromList** + +
+Added in next +No other changes yet. +
+ +```grain +fromList : (list: List
) => ImmutableStack +``` + +Creates a stack from a list. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`list`|`List`|The list to convert| + +Returns: + +|type|description| +|----|-----------| +|`ImmutableStack`|A stack containing all list values| + +Examples: + +```grain +use Stack.{ module Immutable as Stack } +let stack = Stack.fromList([2, 1]) +assert Stack.peek(stack) == Some(2) +let stack = Stack.pop(stack) +assert Stack.peek(stack) == Some(1) +let stack = Stack.pop(stack) +assert Stack.isEmpty(stack) +``` + +#### Stack.Immutable.**toArray** + +
+Added in next +No other changes yet. +
+ +```grain +toArray : (stack: ImmutableStack
) => Array +``` + +Creates an array containing the elements of a stack. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`stack`|`ImmutableStack`|The stack to convert| + +Returns: + +|type|description| +|----|-----------| +|`Array`|An array containing all stack values| + +Examples: + +```grain +use Stack.{ module Immutable as Stack } +let stack = Stack.empty +let stack = Stack.push(1, stack) +let stack = Stack.push(2, stack) +assert Stack.toArray(stack) == [> 2, 1] +``` + +#### Stack.Immutable.**fromArray** + +
+Added in next +No other changes yet. +
+ +```grain +fromArray : (arr: Array
) => ImmutableStack +``` + +Creates a stack from an array. + +Parameters: + +|param|type|description| +|-----|----|-----------| +|`arr`|`Array`|The array to convert| + +Returns: + +|type|description| +|----|-----------| +|`ImmutableStack`|A stack containing all array values| + +Examples: + +```grain +use Stack.{ module Immutable as Stack } +let stack = Stack.fromArray([> 2, 1]) +assert Stack.peek(stack) == Some(2) +let stack = Stack.pop(stack) +assert Stack.peek(stack) == Some(1) +let stack = Stack.pop(stack) +assert Stack.isEmpty(stack) +``` +