Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ jobs:
# would have. Pinned rather than floating: a green run should mean this
# code passed against a known compiler, not against whatever was newest
# that morning.
- name: Install twill v1.8.0
- name: Install twill v1.9.0
run: |
curl -fsSL -o twill \
https://github.com/twill-lang/twill/releases/download/v1.8.0/twill-v1.8.0-linux-amd64
https://github.com/twill-lang/twill/releases/download/v1.9.0/twill-v1.9.0-linux-amd64
chmod +x twill
./twill --version

Expand Down
21 changes: 12 additions & 9 deletions docs/needs.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,18 @@ itself.

**Would improve:** `src/strutil.tw`, `src/manifest.tw`, `src/lockfile.tw`,
`src/resolve.tw`
**Status:** **half delivered** (twill 1.7). The half that was a language
question is answered: a function may be passed to a systems-mode function, with
a `fn(Str, Str) -> Bool` parameter type, and it checks and runs.

There is still no generic sort builtin, and there are still four near-identical
insertion sorts in this source, one per element type, differing only in the
comparison. They are correct and small, and having four of them is still four
times as many places for the ordering that the lockfile depends on to go wrong.
A comparison-taking sort can be written in twill now. Nobody has written it.
**Status: delivered in twill 1.9.0, and all four are gone.** `sort` orders a
list of numbers or strings and takes a comparison, so each of these is now one
call: strings straight through, deps and lockfile entries by `compare_str` on
the name, versions by `semver.compare`.

The half that was a language question was answered in 1.7, when a function
became something a systems-mode function could take. What was missing after that
was a sort willing to accept one, and the entry's own complaint was the right
one to fix: four near-identical insertion sorts differing only in the comparison
is four times as many places for the ordering the lockfile depends on to go
wrong. The builtin is stable, which is what makes a re-rendered lockfile produce
no diff.

### 13. A `sha256` builtin

Expand Down
2 changes: 1 addition & 1 deletion spool.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ entry = "src/commands.tw"
# this source was written against. spool has no notion of a toolchain dependency,
# so it is declared as an ordinary git dependency, the same way every other
# package in the ecosystem declares it.
twill = { version = "^1.8.0", git = "https://github.com/twill-lang/twill" }
twill = { version = "^1.9.0", git = "https://github.com/twill-lang/twill" }
26 changes: 6 additions & 20 deletions src/lockfile.tw
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,12 @@ fn has(l: Lock, name: Str) -> Bool {
}
}

fn sort_entries(entries: Arr[Entry]) -> Arr[Entry] {
let out: Arr[Entry] = []
let i = 0
while i < len(entries) {
push(out, entries[i])
i = i + 1
}
let j = 1
while j < len(out) {
let cur = out[j]
let k = j - 1
while k >= 0 and s.compare_str(out[k].name, cur.name) > 0 {
out[k + 1] = out[k]
k = k - 1
}
out[k + 1] = cur
j = j + 1
}
out
}
# Ordered by name through the builtin's comparison (twill 1.9.0), and stable, so
# a lockfile's line order is a function of its contents and a re-render produces
# no diff.
fn sort_entries(entries: Arr[Entry]) -> Arr[Entry] =
sort(entries, fn(a: Entry, b: Entry) -> Bool { s.compare_str(a.name, b.name) < 0 })


# render builds into a Bytes. Six concatenations per package against a string
# that already holds every package before it is quadratic in the size of the
Expand Down
8 changes: 7 additions & 1 deletion src/manifest.tw
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,13 @@ fn has_dep(m: Manifest, name: Str) -> Bool {
}
}

# sort_deps is an insertion sort by name. Dependency lists are tens of entries
# sort_deps orders by name through the builtin's comparison (twill 1.9.0). It
# was an insertion sort; the comparison is the same one, `compare_str` on the
# name, and the builtin is stable, so two deps that somehow share a name keep
# the order the manifest gave them.
fn sort_deps(deps: Arr[Dep]) -> Arr[Dep] =
sort(deps, fn(a: Dep, b: Dep) -> Bool { s.compare_str(a.name, b.name) < 0 })

# at most, so the quadratic cost is invisible next to reading the file.
fn sort_deps(deps: Arr[Dep]) -> Arr[Dep] {
let out: Arr[Dep] = []
Expand Down
25 changes: 5 additions & 20 deletions src/resolve.tw
Original file line number Diff line number Diff line change
Expand Up @@ -225,23 +225,8 @@ fn unsatisfiable(name: Str, joined: Str, versions: Arr[semver.Version]) -> Str {
+ "; available: " + s.join(have, ", ")
}

fn sort_versions(vs: Arr[semver.Version]) -> Arr[semver.Version] {
let out: Arr[semver.Version] = []
let i = 0
while i < len(vs) {
push(out, vs[i])
i = i + 1
}
let j = 1
while j < len(out) {
let cur = out[j]
let k = j - 1
while k >= 0 and semver.compare(out[k], cur) > 0 {
out[k + 1] = out[k]
k = k - 1
}
out[k + 1] = cur
j = j + 1
}
out
}
# Ascending by semver, through the builtin's comparison (twill 1.9.0). The
# comparison is semver's own, which is the point: a version order is not a
# string order, and 1.10.0 sorts after 1.9.0 rather than before it.
fn sort_versions(vs: Arr[semver.Version]) -> Arr[semver.Version] =
sort(vs, fn(a: semver.Version, b: semver.Version) -> Bool { semver.compare(a, b) < 0 })
11 changes: 7 additions & 4 deletions src/strutil.tw
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,13 @@ fn compare_str(a: Str, b: Str) -> I64 {
0
}

# sort_strs is an insertion sort. The inputs are dependency lists, tens of
# entries at most, so the quadratic cost is invisible and the implementation is
# short enough to be obviously correct. That trade would be wrong at any scale
# spool is likely to reach.
# sort_strs is the builtin, which has ordered a list of strings since twill
# 1.5.1 and a list of anything since 1.9.0. It was an insertion sort here, on
# the honest grounds that dependency lists are tens of entries and the quadratic
# cost is invisible; the argument for deleting it is not speed, it is that a
# sort nobody has to read is better than a short one they do.
fn sort_strs(xs: Arr[Str]) -> Arr[Str] = sort(xs)

fn sort_strs(xs: Arr[Str]) -> Arr[Str] {
let out: Arr[Str] = []
let i = 0
Expand Down
Loading