Skip to content

Commit

Permalink
feat(stdlib): Add toList, fromList, toArray, fromArray to Sta…
Browse files Browse the repository at this point in the history
…ck (#2198)

Co-authored-by: Oscar Spencer <[email protected]>
  • Loading branch information
spotandjake and ospencer authored Jan 2, 2025
1 parent 1179c91 commit b815bcd
Show file tree
Hide file tree
Showing 3 changed files with 518 additions and 1 deletion.
66 changes: 66 additions & 0 deletions compiler/test/stdlib/stack.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down Expand Up @@ -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)
}
171 changes: 170 additions & 1 deletion stdlib/stack.gr
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ abstract record Stack<a> {
*
* @param size: The initial storage size of the stack
* @returns An empty stack
*
*
* @since v0.6.0
*/
provide let make = (size=16) => {
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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), }
}
}
Loading

0 comments on commit b815bcd

Please sign in to comment.