smalltalk: quicksort classic program + 9 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -142,4 +142,81 @@
|
||||
(st-test "EightQueens init sets size 8"
|
||||
(evp "^ EightQueens new init size") 8)
|
||||
|
||||
;; ── quicksort.st ─────────────────────────────────────────────────────
|
||||
(define
|
||||
quicksort-source
|
||||
"Object subclass: #Quicksort
|
||||
instanceVariableNames: ''!
|
||||
|
||||
!Quicksort methodsFor: 'sort'!
|
||||
sort: arr ^ self sort: arr from: 1 to: arr size!
|
||||
|
||||
sort: arr from: low to: high
|
||||
| p |
|
||||
low < high ifTrue: [
|
||||
p := self partition: arr from: low to: high.
|
||||
self sort: arr from: low to: p - 1.
|
||||
self sort: arr from: p + 1 to: high].
|
||||
^ arr!
|
||||
|
||||
partition: arr from: low to: high
|
||||
| pivot i tmp |
|
||||
pivot := arr at: high.
|
||||
i := low - 1.
|
||||
low to: high - 1 do: [:j |
|
||||
(arr at: j) <= pivot ifTrue: [
|
||||
i := i + 1.
|
||||
tmp := arr at: i.
|
||||
arr at: i put: (arr at: j).
|
||||
arr at: j put: tmp]].
|
||||
tmp := arr at: i + 1.
|
||||
arr at: i + 1 put: (arr at: high).
|
||||
arr at: high put: tmp.
|
||||
^ i + 1! !")
|
||||
|
||||
(smalltalk-load quicksort-source)
|
||||
|
||||
(st-test "Quicksort class registered" (st-class-exists? "Quicksort") true)
|
||||
|
||||
(st-test "qsort small array"
|
||||
(evp "^ Quicksort new sort: #(3 1 2)")
|
||||
(list 1 2 3))
|
||||
|
||||
(st-test "qsort with duplicates"
|
||||
(evp "^ Quicksort new sort: #(3 1 4 1 5 9 2 6 5 3 5)")
|
||||
(list 1 1 2 3 3 4 5 5 5 6 9))
|
||||
|
||||
(st-test "qsort already-sorted"
|
||||
(evp "^ Quicksort new sort: #(1 2 3 4 5)")
|
||||
(list 1 2 3 4 5))
|
||||
|
||||
(st-test "qsort reverse-sorted"
|
||||
(evp "^ Quicksort new sort: #(9 7 5 3 1)")
|
||||
(list 1 3 5 7 9))
|
||||
|
||||
(st-test "qsort single element"
|
||||
(evp "^ Quicksort new sort: #(42)")
|
||||
(list 42))
|
||||
|
||||
(st-test "qsort empty"
|
||||
(evp "^ Quicksort new sort: #()")
|
||||
(list))
|
||||
|
||||
(st-test "qsort negatives"
|
||||
(evp "^ Quicksort new sort: #(-3 -1 -7 0 2)")
|
||||
(list -7 -3 -1 0 2))
|
||||
|
||||
(st-test "qsort all-equal"
|
||||
(evp "^ Quicksort new sort: #(5 5 5 5)")
|
||||
(list 5 5 5 5))
|
||||
|
||||
(st-test "qsort sorts in place (returns same array)"
|
||||
(evp
|
||||
"| arr q |
|
||||
arr := #(4 2 1 3).
|
||||
q := Quicksort new.
|
||||
q sort: arr.
|
||||
^ arr")
|
||||
(list 1 2 3 4))
|
||||
|
||||
(list st-test-pass st-test-fail)
|
||||
|
||||
31
lib/smalltalk/tests/programs/quicksort.st
Normal file
31
lib/smalltalk/tests/programs/quicksort.st
Normal file
@@ -0,0 +1,31 @@
|
||||
"Quicksort — Lomuto partition. Sorts an Array in place. Classic-corpus
|
||||
program for the Smalltalk-on-SX runtime."
|
||||
|
||||
Object subclass: #Quicksort
|
||||
instanceVariableNames: ''!
|
||||
|
||||
!Quicksort methodsFor: 'sort'!
|
||||
sort: arr ^ self sort: arr from: 1 to: arr size!
|
||||
|
||||
sort: arr from: low to: high
|
||||
| p |
|
||||
low < high ifTrue: [
|
||||
p := self partition: arr from: low to: high.
|
||||
self sort: arr from: low to: p - 1.
|
||||
self sort: arr from: p + 1 to: high].
|
||||
^ arr!
|
||||
|
||||
partition: arr from: low to: high
|
||||
| pivot i tmp |
|
||||
pivot := arr at: high.
|
||||
i := low - 1.
|
||||
low to: high - 1 do: [:j |
|
||||
(arr at: j) <= pivot ifTrue: [
|
||||
i := i + 1.
|
||||
tmp := arr at: i.
|
||||
arr at: i put: (arr at: j).
|
||||
arr at: j put: tmp]].
|
||||
tmp := arr at: i + 1.
|
||||
arr at: i + 1 put: (arr at: high).
|
||||
arr at: high put: tmp.
|
||||
^ i + 1! !
|
||||
@@ -72,7 +72,7 @@ Core mapping:
|
||||
- [x] Escape past returned-from method raises (the SX-level analogue of `BlockContext>>cannotReturn:`). Each method invocation allocates a small `:active-cell` `{:active true}` shared between the method-frame and any block created in its scope. `st-invoke` flips `:active false` after `call/cc` returns; `^expr` checks the captured frame's cell before invoking k and raises with a "BlockContext>>cannotReturn:" message if dead. Verified by `lib/smalltalk/tests/cannot_return.sx` (5 tests using SX `guard` to catch the raise). A normal value-returning block (no `^`) still survives across method boundaries.
|
||||
- [ ] Classic programs in `lib/smalltalk/tests/programs/`:
|
||||
- [x] `eight-queens.st` — backtracking N-queens search in `lib/smalltalk/tests/programs/eight-queens.st`. The `.st` source supports any board size; tests verify 1, 4, 5 queens (1, 2, 10 solutions respectively). 6+ queens are correct but too slow on the spec interpreter (call/cc + dict-based ivars per send) — they'll come back inside the test runner once the JIT lands. The 8-queens canonical case will run in production.
|
||||
- [ ] `quicksort.st`
|
||||
- [x] `quicksort.st` — Lomuto-partition in-place quicksort in `lib/smalltalk/tests/programs/quicksort.st`. Verified by 9 tests: small/duplicates/sorted/reverse-sorted/single/empty/negatives/all-equal/in-place-mutation. Exercises Array `at:`/`at:put:` mutation, recursion, `to:do:` over varying ranges.
|
||||
- [ ] `mandelbrot.st`
|
||||
- [ ] `life.st` (Conway's Life, glider gun)
|
||||
- [x] `fibonacci.st` (recursive + Array-memoised) — `lib/smalltalk/tests/programs/fibonacci.st`. Loaded from chunk-format source by new `smalltalk-load` helper; verified by 13 tests in `lib/smalltalk/tests/programs.sx` (recursive `fib:`, memoised `memoFib:` up to 30, instance independence, class-table integrity). Source is currently duplicated as a string in the SX test file because there's no SX file-read primitive; conformance.sh will dedupe by piping the .st file directly.
|
||||
@@ -108,6 +108,7 @@ Core mapping:
|
||||
|
||||
_Newest first. Agent appends on every commit._
|
||||
|
||||
- 2026-04-25: classic-corpus #3 quicksort (`tests/programs/quicksort.st`, 9 tests). Lomuto partition; verified across duplicates, already-sorted/reverse-sorted, empty, single, negatives, all-equal, plus in-place mutation. 385/385 total.
|
||||
- 2026-04-25: classic-corpus #2 eight-queens (`tests/programs/eight-queens.st`, 5 tests). Backtracking search; verified for boards of size 1, 4, 5. Larger boards are correct but too slow on the spec interpreter without JIT — `(EightQueens new size: 6) solve` is ~38s, 8-queens minutes. 382/382 total.
|
||||
- 2026-04-25: classic-corpus #1 fibonacci (`tests/programs/fibonacci.st` + `tests/programs.sx`, 13 tests). Added `smalltalk-load` chunk loader, class-side `subclass:instanceVariableNames:` (and longer Pharo variants), `Array new:` size, `methodsFor:`/`category:` no-ops, `st-split-ivars`. 377/377 total.
|
||||
- 2026-04-25: cannotReturn: implemented (`lib/smalltalk/tests/cannot_return.sx`, 5 tests). Each method-invocation gets an `{:active true}` cell shared with its blocks; `st-invoke` flips it on exit; `^expr` raises if the cell is dead. Tests use SX `guard` to catch the raise. Non-`^` blocks unaffected. 364/364 total.
|
||||
|
||||
Reference in New Issue
Block a user