Skip to content

Commit 478d8a6

Browse files
authored
Merge pull request #73795 from kavon/expand-swiftskell-2
Test: add `List.reverse` and deinit testing to Swiftskell
2 parents 7ad32b0 + fb79bd2 commit 478d8a6

File tree

2 files changed

+68
-23
lines changed

2 files changed

+68
-23
lines changed

test/Inputs/Swiftskell.swift

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,20 @@ public protocol Generator: ~Copyable {
5555
func next() -> Maybe<Element>
5656
}
5757

58+
/// Eager assertion function, to avoid autoclosures.
59+
public func check(_ result: Bool, _ string: String? = nil,
60+
_ file: String = #file, _ line: Int = #line) {
61+
if result { return }
62+
var msg = "assertion failure (\(file):\(line))"
63+
if let extra = string {
64+
msg += ":\t" + extra
65+
}
66+
fatalError(msg)
67+
}
68+
5869
// MARK: Tuples
5970
public enum Pair<L: ~Copyable, R: ~Copyable>: ~Copyable {
60-
case elms(L, R)
71+
case pair(L, R)
6172
}
6273
extension Pair: Copyable where L: Copyable, R: Copyable {}
6374

@@ -153,6 +164,8 @@ public struct Box<Wrapped: ~Copyable>: ~Copyable {
153164

154165

155166
/// MARK: Data.List
167+
///
168+
/// A singly-linked list
156169
public enum List<Element: ~Copyable>: ~Copyable {
157170
case cons(Element, Box<List<Element>>)
158171
case empty
@@ -168,7 +181,7 @@ public enum List<Element: ~Copyable>: ~Copyable {
168181
/// Pure Iteration
169182
extension List where Element: ~Copyable {
170183
/// Performs forward iteration through the list, accumulating a result value.
171-
/// Returns f(xn,...,f(x2, f(x1, init))...), or init if the list is empty.
184+
/// Returns f(xn,...,f(x2, f(x1, init))...), or `init` if the list is empty.
172185
public borrowing func foldl<Out>(
173186
init initial: consuming Out,
174187
_ f: (borrowing Element, consuming Out) -> Out) -> Out
@@ -185,7 +198,7 @@ extension List where Element: ~Copyable {
185198
}
186199

187200
/// Performs reverse iteration through the list, accumulating a result value.
188-
/// Returns f(x1, f(x2,...,f(xn, init)...)) or init if the list is empty.
201+
/// Returns f(x1, f(x2,...,f(xn, init)...)) or `init` if the list is empty.
189202
public borrowing func foldr<Out>(
190203
init initial: consuming Out,
191204
_ f: (borrowing Element, consuming Out) -> Out) -> Out
@@ -228,30 +241,52 @@ extension List where Element: ~Copyable {
228241
/// Basic utilities
229242
extension List where Element: ~Copyable {
230243
/// Is this list empty?
231-
public borrowing func empty() -> Bool {
232-
switch self {
233-
case .empty: return true
234-
case .cons(_, _): return false
244+
///
245+
/// Complexity: O(1)
246+
public var isEmpty: Bool {
247+
borrowing get {
248+
switch self {
249+
case .empty: true
250+
case .cons(_, _): false
251+
}
235252
}
236253
}
237254

238255
/// How many elements are in this list?
256+
///
257+
/// Complexity: O(n)
239258
public borrowing func length() -> Int {
240259
return foldl(init: 0) { $1 + 1 }
241260
}
242261

243262
/// Pop the first element off the list, if present.
263+
///
264+
/// Complexity: O(1)
244265
public consuming func pop() -> Optional<Pair<Element, List<Element>>> {
245266
switch consume self {
246267
case .empty: .none
247-
case let .cons(elm, tail): .elms(elm, tail.take())
268+
case let .cons(elm, tail): .pair(elm, tail.take())
248269
}
249270
}
250271

251-
/// Push an element onto the list.
272+
/// Push an element onto the front of the list.
273+
///
274+
/// Complexity: O(1)
252275
public consuming func push(_ newHead: consuming Element) -> List<Element> {
253276
return List(newHead, self)
254277
}
278+
279+
/// Produces a new list that is the reverse of this list.
280+
///
281+
/// Complexity: O(n)
282+
public consuming func reverse() -> List<Element> {
283+
var new = List<Element>()
284+
while case let .pair(head, tail) = pop() {
285+
new = new.push(head)
286+
self = tail
287+
}
288+
return new
289+
}
255290
}
256291

257292
extension List: Show where Element: Show & ~Copyable {

test/Interpreter/moveonly_swiftskell.swift

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,22 @@
1414
// RUN: -module-name E -o %t/E %target-rpath(%t)
1515
// RUN: %target-codesign %t/E
1616
// RUN: %target-codesign %t/%target-library-name(Swiftskell)
17-
// RUN: %target-run %t/E %t/%target-library-name(Swiftskell) | %FileCheck %s
17+
// RUN: %target-run %t/E %t/%target-library-name(Swiftskell) \
18+
// RUN: | %FileCheck %s --implicit-check-not destroy
1819

1920
// REQUIRES: executable_test
2021

2122
import Swiftskell
2223

23-
/// assertion function
24-
func check(_ result: Bool, _ string: String? = nil, _ line: Int = #line) {
25-
if result { return }
26-
var msg = "assertion failure (line \(line))"
27-
if let extra = string {
28-
msg += ":\t" + extra
29-
}
30-
fatalError(msg)
31-
}
32-
3324
/// Basic noncopyable type for testing.
3425
struct File: ~Copyable, Show {
3526
let id: Int
3627
init(_ id: Int) {
3728
self.id = id
3829
}
3930
func show() -> String { return id.show() }
31+
32+
deinit { print("destroying file \(id)") }
4033
}
4134

4235

@@ -51,14 +44,31 @@ func testListBasic() {
5144
var items = List<File>(length: 5) { .init($0) }
5245
print(items.show()) // CHECK: [0, 1, 2, 3, 4, ]
5346
check(items.length() == 5)
54-
check(!items.empty())
47+
check(!items.isEmpty)
48+
49+
items = List<File>(length: 5) { .init($0) }
50+
// CHECK: destroying file 4
51+
// CHECK: destroying file 3
52+
// CHECK: destroying file 2
53+
// CHECK: destroying file 1
54+
// CHECK: destroying file 0
55+
56+
items = items.reverse()
57+
check(items.length() == 5)
58+
print(items.show()) // CHECK: [4, 3, 2, 1, 0, ]
5559

5660
items = .empty
61+
// CHECK: destroying file 0
62+
// CHECK: destroying file 1
63+
// CHECK: destroying file 2
64+
// CHECK: destroying file 3
65+
// CHECK: destroying file 4
66+
5767
check(items.length() == 0)
58-
check(items.empty())
68+
check(items.isEmpty)
5969

6070
let nums = List<Int>().push(7).push(7).push(3)
6171
print(nums.show()) // CHECK: [7, 7, 3, ]
6272

63-
73+
6474
}

0 commit comments

Comments
 (0)