feat(release): SemVer + ludicc --version, changesets, and x release
The project had no versioning discipline: 0 tags, no CHANGELOG, no way for the compiler to report a version. Add a lightweight, native release flow. - Versioning: SemVer, with VERSION as the single source of truth. `ludicc --version` (and `ludic --version`) read it at runtime — so a bump touches one file and never reseeds the compiler. `x version` reports it too. - Changesets: one small Markdown file per user-facing change under changes/ (bump level + type + summary; see changes/README.md). This replaces "remember to edit the changelog" with a mergeable artifact, no Node changeset tool. - `x release [major|minor|patch] [--publish]`: fold the pending changesets into a new CHANGELOG.md section (grouped by type), bump VERSION, commit, and tag vX.Y.Z. The level defaults to the highest changeset bump. `--publish` also pushes and creates the Forgejo release with source + toolchain tarballs; tools/ci/forgejo_release.py is the small stdlib-Python HTTP glue for the release API (a native Http client is issue #6). Seed the initial changesets describing the shipped surface; the first `x release` turns them into the v0.1.0 CHANGELOG. Reseeded for the --version flag; C-free bootstrap fixpoint holds; suites 56 / 29 / 29 on macOS, 51 / 28 (+skips) on Linux CI, bootstrap-cfree byte-identical on both. Part of the repository-cleanup / DX pass (with #32, #34). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
709465cdd8
commit
fed80f2152
15 changed files with 787 additions and 293 deletions
|
|
@ -63,6 +63,27 @@ The stdlib lives in the runtime (`runtime/`) and is surfaced as namespaces
|
|||
3. Add or extend an example under `examples/` and a case in the test suite.
|
||||
4. Run `python3 tools/docgen/gen.py && python3 tools/docgen/check.py` — the
|
||||
check fails if any inventory symbol lacks a page or is still seed text.
|
||||
5. Add a **changeset** for the user-facing change: a small file under
|
||||
[`changes/`](changes/README.md) with a `bump:` level and a one-line summary.
|
||||
The next release folds it into `CHANGELOG.md`.
|
||||
|
||||
## Versioning & releases
|
||||
|
||||
The toolchain is versioned with [SemVer](https://semver.org); `VERSION` is the
|
||||
single source of truth and `ludicc --version` (or `x version`) reports it.
|
||||
|
||||
Releases are changeset-driven. Every user-facing change ships with a changeset
|
||||
(step 5 above). To cut a release:
|
||||
|
||||
```bash
|
||||
x release [major|minor|patch] # omit the level to derive it from the changesets
|
||||
```
|
||||
|
||||
That aggregates the pending changesets into a new `CHANGELOG.md` section, bumps
|
||||
`VERSION`, commits `chore(release): vX.Y.Z`, and tags it. Add `--publish` (with
|
||||
`FORGEJO_TOKEN` set) to also push and create the Forgejo release with source and
|
||||
toolchain tarballs. The tag doubles as the reproducible bootstrap point: the
|
||||
source archive plus its checked-in seed rebuild that exact toolchain.
|
||||
|
||||
## Conventions
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,10 @@ Ludic-written PNG/DEFLATE decoder — no zlib, no external dependency.
|
|||
The compiler self-hosts to a byte-exact fixpoint and rebuilds from its IR seed
|
||||
with no C compiler; the ECS runtime, windowed + headless 2D rendering, the event
|
||||
bus, the deterministic networking stack, scenes, and save/load are all in place
|
||||
and covered by `bin/x test`.
|
||||
and covered by `bin/x test`. CI gates every push and PR on the build, the test
|
||||
suites, and that C-free fixpoint. The toolchain is versioned with SemVer
|
||||
(`ludicc --version`); releases and the `CHANGELOG.md` are cut from changesets by
|
||||
`x release`.
|
||||
|
||||
Active work and proposals — the standard library, a fuller type system,
|
||||
rendering/animation/lighting extras, input, filesystem/IO, testing, and
|
||||
|
|
|
|||
1
VERSION
Normal file
1
VERSION
Normal file
|
|
@ -0,0 +1 @@
|
|||
0.0.0
|
||||
3
changes/0001-self-hosted-toolchain.md
Normal file
3
changes/0001-self-hosted-toolchain.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
Self-hosted, C-free toolchain — the compiler, runtime, task runner and editor tools are all written in Ludic and built from a checked-in LLVM-IR seed with clang alone; `x bootstrap-cfree` proves the compiler rebuilds itself byte-for-byte.
|
||||
3
changes/0002-namespaced-stdlib.md
Normal file
3
changes/0002-namespaced-stdlib.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
Namespaced standard library — Math, Text, List, Random, Time, Screen, Color, Ease, Collide, Memory, Vector, DateTime/Date/Duration/Clock, Unicode, Os, Fs/Path/Mime, Log, Noise, Hash, Crypto and Uuid, each deterministic where a game needs it.
|
||||
3
changes/0003-native-2d-backend.md
Normal file
3
changes/0003-native-2d-backend.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
Native 2D backend — an ECS core with a deterministic fixed-point (Q16.16) runtime, a windowed Cocoa target on macOS and a headless PPM renderer that runs anywhere.
|
||||
3
changes/0004-editor-tooling.md
Normal file
3
changes/0004-editor-tooling.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
Editor tooling — `ludic-fmt` (formatter) and `ludic-lsp` (language server), plus VS Code and JetBrains integrations, all built by the toolchain.
|
||||
3
changes/0005-ci.md
Normal file
3
changes/0005-ci.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: ci
|
||||
Continuous integration — Forgejo Actions workflows build the toolchain from the seed, run the regression + editor suites, assert the C-free bootstrap fixpoint, and lint commit messages on every push and pull request.
|
||||
3
changes/0006-versioning.md
Normal file
3
changes/0006-versioning.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
Versioning and releases — SemVer with `ludicc --version`, a changeset-driven `CHANGELOG.md`, and `x release` to bump, tag, and publish a Forgejo release with source and toolchain artifacts.
|
||||
25
changes/README.md
Normal file
25
changes/README.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Changesets
|
||||
|
||||
A **changeset** is one small Markdown file describing a single user-facing change,
|
||||
dropped in this directory. `x release` consumes every changeset here into a new
|
||||
`CHANGELOG.md` section, bumps `VERSION`, and deletes the consumed files.
|
||||
|
||||
## Format
|
||||
|
||||
```
|
||||
bump: minor
|
||||
type: feat
|
||||
One or more lines describing the change, in the past-agnostic imperative used in
|
||||
the changelog. Markdown is fine.
|
||||
```
|
||||
|
||||
- `bump:` — `major`, `minor`, or `patch` (SemVer). The release version is bumped
|
||||
by the **highest** level among the pending changesets (unless `x release <level>`
|
||||
overrides it).
|
||||
- `type:` — the Conventional Commit type (`feat`, `fix`, `perf`, `docs`, …); it
|
||||
becomes the bold prefix of the changelog bullet.
|
||||
|
||||
## Adding one
|
||||
|
||||
Create a file with a short, unique name, e.g. `changes/regex-namespace.md`. Any
|
||||
filename works except this `README.md`, which the release step always skips.
|
||||
|
|
@ -7499,32 +7499,37 @@ declare void @win_close()
|
|||
@.str7389 = private unnamed_addr constant [3 x i8] c"wb\00"
|
||||
@.str7390 = private unnamed_addr constant [7 x i8] c".ludic\00"
|
||||
@.str7391 = private unnamed_addr constant [2 x i8] c"/\00"
|
||||
@.str7392 = private unnamed_addr constant [6 x i8] c"ludic\00"
|
||||
@.str7393 = private unnamed_addr constant [11 x i8] c"--windowed\00"
|
||||
@.str7394 = private unnamed_addr constant [11 x i8] c"--headless\00"
|
||||
@.str7395 = private unnamed_addr constant [12 x i8] c"--emit-llvm\00"
|
||||
@.str7396 = private unnamed_addr constant [6 x i8] c"--fmt\00"
|
||||
@.str7397 = private unnamed_addr constant [13 x i8] c"--save-temps\00"
|
||||
@.str7398 = private unnamed_addr constant [6 x i8] c"--run\00"
|
||||
@.str7399 = private unnamed_addr constant [3 x i8] c"-o\00"
|
||||
@.str7400 = private unnamed_addr constant [31 x i8] c"ludicc: ignoring unknown flag \00"
|
||||
@.str7401 = private unnamed_addr constant [2 x i8] c"\0A\00"
|
||||
@.str7402 = private unnamed_addr constant [90 x i8] c"usage: ludicc <file.ludic> [-o out] [--windowed|--headless] [--emit-llvm] [--save-temps]\0A\00"
|
||||
@.str7403 = private unnamed_addr constant [27 x i8] c"ludicc: cannot open input\0A\00"
|
||||
@.str7404 = private unnamed_addr constant [16 x i8] c"/tmp/ludic-run-\00"
|
||||
@.str7405 = private unnamed_addr constant [10 x i8] c"mkdir -p \00"
|
||||
@.str7406 = private unnamed_addr constant [4 x i8] c".ll\00"
|
||||
@.str7407 = private unnamed_addr constant [25 x i8] c"ludicc: cannot write IR\0A\00"
|
||||
@.str7408 = private unnamed_addr constant [9 x i8] c"LUDIC_CC\00"
|
||||
@.str7409 = private unnamed_addr constant [6 x i8] c"clang\00"
|
||||
@.str7410 = private unnamed_addr constant [11 x i8] c"LUDIC_HOME\00"
|
||||
@.str7411 = private unnamed_addr constant [27 x i8] c" -O2 -Wno-override-module \00"
|
||||
@.str7412 = private unnamed_addr constant [24 x i8] c"runtime/native/cocoa.ll\00"
|
||||
@.str7413 = private unnamed_addr constant [2 x i8] c" \00"
|
||||
@.str7414 = private unnamed_addr constant [42 x i8] c" -framework Cocoa -Wl,-rpath,@loader_path\00"
|
||||
@.str7415 = private unnamed_addr constant [5 x i8] c" -o \00"
|
||||
@.str7416 = private unnamed_addr constant [7 x i8] c"rm -f \00"
|
||||
@.str7417 = private unnamed_addr constant [21 x i8] c"ludicc: link failed\0A\00"
|
||||
@.str7392 = private unnamed_addr constant [11 x i8] c"LUDIC_HOME\00"
|
||||
@.str7393 = private unnamed_addr constant [8 x i8] c"VERSION\00"
|
||||
@.str7394 = private unnamed_addr constant [24 x i8] c"ludic (version unknown)\00"
|
||||
@.str7395 = private unnamed_addr constant [7 x i8] c"ludic \00"
|
||||
@.str7396 = private unnamed_addr constant [6 x i8] c"ludic\00"
|
||||
@.str7397 = private unnamed_addr constant [10 x i8] c"--version\00"
|
||||
@.str7398 = private unnamed_addr constant [11 x i8] c"--windowed\00"
|
||||
@.str7399 = private unnamed_addr constant [11 x i8] c"--headless\00"
|
||||
@.str7400 = private unnamed_addr constant [12 x i8] c"--emit-llvm\00"
|
||||
@.str7401 = private unnamed_addr constant [6 x i8] c"--fmt\00"
|
||||
@.str7402 = private unnamed_addr constant [13 x i8] c"--save-temps\00"
|
||||
@.str7403 = private unnamed_addr constant [6 x i8] c"--run\00"
|
||||
@.str7404 = private unnamed_addr constant [3 x i8] c"-o\00"
|
||||
@.str7405 = private unnamed_addr constant [31 x i8] c"ludicc: ignoring unknown flag \00"
|
||||
@.str7406 = private unnamed_addr constant [2 x i8] c"\0A\00"
|
||||
@.str7407 = private unnamed_addr constant [90 x i8] c"usage: ludicc <file.ludic> [-o out] [--windowed|--headless] [--emit-llvm] [--save-temps]\0A\00"
|
||||
@.str7408 = private unnamed_addr constant [27 x i8] c"ludicc: cannot open input\0A\00"
|
||||
@.str7409 = private unnamed_addr constant [16 x i8] c"/tmp/ludic-run-\00"
|
||||
@.str7410 = private unnamed_addr constant [10 x i8] c"mkdir -p \00"
|
||||
@.str7411 = private unnamed_addr constant [4 x i8] c".ll\00"
|
||||
@.str7412 = private unnamed_addr constant [25 x i8] c"ludicc: cannot write IR\0A\00"
|
||||
@.str7413 = private unnamed_addr constant [9 x i8] c"LUDIC_CC\00"
|
||||
@.str7414 = private unnamed_addr constant [6 x i8] c"clang\00"
|
||||
@.str7415 = private unnamed_addr constant [11 x i8] c"LUDIC_HOME\00"
|
||||
@.str7416 = private unnamed_addr constant [27 x i8] c" -O2 -Wno-override-module \00"
|
||||
@.str7417 = private unnamed_addr constant [24 x i8] c"runtime/native/cocoa.ll\00"
|
||||
@.str7418 = private unnamed_addr constant [2 x i8] c" \00"
|
||||
@.str7419 = private unnamed_addr constant [42 x i8] c" -framework Cocoa -Wl,-rpath,@loader_path\00"
|
||||
@.str7420 = private unnamed_addr constant [5 x i8] c" -o \00"
|
||||
@.str7421 = private unnamed_addr constant [7 x i8] c"rm -f \00"
|
||||
@.str7422 = private unnamed_addr constant [21 x i8] c"ludicc: link failed\0A\00"
|
||||
define i32 @fn_str_eq(ptr %a, ptr %b) {
|
||||
entry:
|
||||
br label %loop
|
||||
|
|
@ -62186,6 +62191,135 @@ ret:
|
|||
ret void
|
||||
}
|
||||
|
||||
define ptr @fn_chomp(ptr %arg_s) {
|
||||
entry:
|
||||
%retval = alloca ptr
|
||||
%t0 = alloca ptr
|
||||
%t4 = alloca i32
|
||||
%t5 = alloca i32
|
||||
%t11 = alloca i32
|
||||
%t12 = alloca i32
|
||||
store ptr %arg_s, ptr %t0
|
||||
%t1 = load ptr, ptr %t0
|
||||
%t2 = call i64 @strlen(ptr %t1)
|
||||
%t3 = trunc i64 %t2 to i32
|
||||
store i32 %t3, ptr %t4
|
||||
br label %wcond0
|
||||
wcond0:
|
||||
%t6 = load i32, ptr %t4
|
||||
%t7 = icmp sgt i32 %t6, 0
|
||||
%t8 = zext i1 %t7 to i32
|
||||
%t9 = icmp ne i32 %t8, 0
|
||||
%t10 = zext i1 %t9 to i32
|
||||
store i32 %t10, ptr %t5
|
||||
br i1 %t9, label %sc3, label %scend4
|
||||
sc3:
|
||||
%t13 = load ptr, ptr %t0
|
||||
%t14 = load i32, ptr %t4
|
||||
%t15 = sub i32 %t14, 1
|
||||
%t16 = getelementptr inbounds i8, ptr %t13, i32 %t15
|
||||
%t17 = load i8, ptr %t16
|
||||
%t18 = zext i8 %t17 to i32
|
||||
%t19 = icmp eq i32 %t18, 10
|
||||
%t20 = zext i1 %t19 to i32
|
||||
%t21 = icmp ne i32 %t20, 0
|
||||
%t22 = zext i1 %t21 to i32
|
||||
store i32 %t22, ptr %t12
|
||||
br i1 %t21, label %scend6, label %sc5
|
||||
sc5:
|
||||
%t23 = load ptr, ptr %t0
|
||||
%t24 = load i32, ptr %t4
|
||||
%t25 = sub i32 %t24, 1
|
||||
%t26 = getelementptr inbounds i8, ptr %t23, i32 %t25
|
||||
%t27 = load i8, ptr %t26
|
||||
%t28 = zext i8 %t27 to i32
|
||||
%t29 = icmp eq i32 %t28, 13
|
||||
%t30 = zext i1 %t29 to i32
|
||||
%t31 = icmp ne i32 %t30, 0
|
||||
%t32 = zext i1 %t31 to i32
|
||||
store i32 %t32, ptr %t12
|
||||
br label %scend6
|
||||
scend6:
|
||||
%t33 = load i32, ptr %t12
|
||||
%t34 = icmp ne i32 %t33, 0
|
||||
%t35 = zext i1 %t34 to i32
|
||||
store i32 %t35, ptr %t11
|
||||
br i1 %t34, label %scend8, label %sc7
|
||||
sc7:
|
||||
%t36 = load ptr, ptr %t0
|
||||
%t37 = load i32, ptr %t4
|
||||
%t38 = sub i32 %t37, 1
|
||||
%t39 = getelementptr inbounds i8, ptr %t36, i32 %t38
|
||||
%t40 = load i8, ptr %t39
|
||||
%t41 = zext i8 %t40 to i32
|
||||
%t42 = icmp eq i32 %t41, 32
|
||||
%t43 = zext i1 %t42 to i32
|
||||
%t44 = icmp ne i32 %t43, 0
|
||||
%t45 = zext i1 %t44 to i32
|
||||
store i32 %t45, ptr %t11
|
||||
br label %scend8
|
||||
scend8:
|
||||
%t46 = load i32, ptr %t11
|
||||
%t47 = icmp ne i32 %t46, 0
|
||||
%t48 = zext i1 %t47 to i32
|
||||
store i32 %t48, ptr %t5
|
||||
br label %scend4
|
||||
scend4:
|
||||
%t49 = load i32, ptr %t5
|
||||
%t50 = icmp ne i32 %t49, 0
|
||||
br i1 %t50, label %wbody1, label %wend2
|
||||
wbody1:
|
||||
%t51 = load i32, ptr %t4
|
||||
%t52 = sub i32 %t51, 1
|
||||
store i32 %t52, ptr %t4
|
||||
br label %wcond0
|
||||
wend2:
|
||||
%t53 = load ptr, ptr %t0
|
||||
%t54 = load i32, ptr %t4
|
||||
%t55 = call ptr @fn_str_slice(ptr %t53, i32 0, i32 %t54)
|
||||
store ptr %t55, ptr %retval
|
||||
br label %ret
|
||||
ret:
|
||||
%t56 = load ptr, ptr %retval
|
||||
ret ptr %t56
|
||||
}
|
||||
|
||||
define void @fn_show_version() {
|
||||
entry:
|
||||
%t6 = alloca ptr
|
||||
%t10 = alloca ptr
|
||||
%t0 = load ptr, ptr @L_argv
|
||||
%t1 = getelementptr ptr, ptr %t0, i32 0
|
||||
%t2 = load ptr, ptr %t1
|
||||
%t3 = call ptr @fn_dir_of(ptr %t2)
|
||||
%t4 = call ptr @fn_getenv_or(ptr @.str7392, ptr %t3)
|
||||
%t5 = call ptr @fn_ensure_slash(ptr %t4)
|
||||
store ptr %t5, ptr %t6
|
||||
%t7 = load ptr, ptr %t6
|
||||
%t8 = call ptr @fn_path_join(ptr %t7, ptr @.str7393)
|
||||
%t9 = call ptr @fn_read_file(ptr %t8)
|
||||
store ptr %t9, ptr %t10
|
||||
%t11 = load ptr, ptr %t10
|
||||
%t12 = icmp eq ptr %t11, null
|
||||
%t13 = zext i1 %t12 to i32
|
||||
%t14 = icmp ne i32 %t13, 0
|
||||
br i1 %t14, label %then0, label %else1
|
||||
then0:
|
||||
call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr @.str7394)
|
||||
br label %ifend2
|
||||
else1:
|
||||
%t15 = load ptr, ptr %t10
|
||||
%t16 = call ptr @fn_chomp(ptr %t15)
|
||||
%t17 = call ptr @fn_str_concat(ptr @.str7395, ptr %t16)
|
||||
call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr %t17)
|
||||
br label %ifend2
|
||||
ifend2:
|
||||
call void @exit(i32 0)
|
||||
unreachable
|
||||
ret:
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %argc, ptr %argv) {
|
||||
entry:
|
||||
%retval = alloca i32
|
||||
|
|
@ -62198,20 +62332,20 @@ entry:
|
|||
%t6 = alloca i32
|
||||
%t13 = alloca i32
|
||||
%t23 = alloca ptr
|
||||
%t66 = alloca ptr
|
||||
%t84 = alloca ptr
|
||||
%t94 = alloca i32
|
||||
%t104 = alloca i32
|
||||
%t113 = alloca i32
|
||||
%t130 = alloca i32
|
||||
%t147 = alloca ptr
|
||||
%t159 = alloca ptr
|
||||
%t166 = alloca ptr
|
||||
%t173 = alloca ptr
|
||||
%t178 = alloca ptr
|
||||
%t183 = alloca ptr
|
||||
%t195 = alloca i32
|
||||
%t211 = alloca i32
|
||||
%t69 = alloca ptr
|
||||
%t87 = alloca ptr
|
||||
%t97 = alloca i32
|
||||
%t107 = alloca i32
|
||||
%t116 = alloca i32
|
||||
%t133 = alloca i32
|
||||
%t150 = alloca ptr
|
||||
%t162 = alloca ptr
|
||||
%t169 = alloca ptr
|
||||
%t176 = alloca ptr
|
||||
%t181 = alloca ptr
|
||||
%t186 = alloca ptr
|
||||
%t198 = alloca i32
|
||||
%t214 = alloca i32
|
||||
store i32 %argc, ptr @L_argc
|
||||
store ptr %argv, ptr @L_argv
|
||||
store i32 0, ptr %retval
|
||||
|
|
@ -62226,7 +62360,7 @@ entry:
|
|||
%t8 = getelementptr ptr, ptr %t7, i32 0
|
||||
%t9 = load ptr, ptr %t8
|
||||
%t10 = call ptr @fn_base_name(ptr %t9)
|
||||
%t11 = call i32 @fn_str_eq(ptr %t10, ptr @.str7392)
|
||||
%t11 = call i32 @fn_str_eq(ptr %t10, ptr @.str7396)
|
||||
%t12 = icmp ne i32 %t11, 0
|
||||
br i1 %t12, label %then0, label %ifend2
|
||||
then0:
|
||||
|
|
@ -62249,104 +62383,114 @@ wbody4:
|
|||
%t22 = load ptr, ptr %t21
|
||||
store ptr %t22, ptr %t23
|
||||
%t24 = load ptr, ptr %t23
|
||||
%t25 = call i32 @fn_str_eq(ptr %t24, ptr @.str7393)
|
||||
%t25 = call i32 @fn_str_eq(ptr %t24, ptr @.str7397)
|
||||
%t26 = icmp ne i32 %t25, 0
|
||||
br i1 %t26, label %then6, label %else7
|
||||
then6:
|
||||
store i32 1, ptr %t2
|
||||
call void @fn_show_version()
|
||||
br label %ifend8
|
||||
else7:
|
||||
%t27 = load ptr, ptr %t23
|
||||
%t28 = call i32 @fn_str_eq(ptr %t27, ptr @.str7394)
|
||||
%t28 = call i32 @fn_str_eq(ptr %t27, ptr @.str7398)
|
||||
%t29 = icmp ne i32 %t28, 0
|
||||
br i1 %t29, label %then9, label %else10
|
||||
then9:
|
||||
store i32 2, ptr %t2
|
||||
store i32 1, ptr %t2
|
||||
br label %ifend11
|
||||
else10:
|
||||
%t30 = load ptr, ptr %t23
|
||||
%t31 = call i32 @fn_str_eq(ptr %t30, ptr @.str7395)
|
||||
%t31 = call i32 @fn_str_eq(ptr %t30, ptr @.str7399)
|
||||
%t32 = icmp ne i32 %t31, 0
|
||||
br i1 %t32, label %then12, label %else13
|
||||
then12:
|
||||
store i32 1, ptr %t3
|
||||
store i32 2, ptr %t2
|
||||
br label %ifend14
|
||||
else13:
|
||||
%t33 = load ptr, ptr %t23
|
||||
%t34 = call i32 @fn_str_eq(ptr %t33, ptr @.str7396)
|
||||
%t34 = call i32 @fn_str_eq(ptr %t33, ptr @.str7400)
|
||||
%t35 = icmp ne i32 %t34, 0
|
||||
br i1 %t35, label %then15, label %else16
|
||||
then15:
|
||||
store i32 1, ptr %t4
|
||||
store i32 1, ptr %t3
|
||||
br label %ifend17
|
||||
else16:
|
||||
%t36 = load ptr, ptr %t23
|
||||
%t37 = call i32 @fn_str_eq(ptr %t36, ptr @.str7397)
|
||||
%t37 = call i32 @fn_str_eq(ptr %t36, ptr @.str7401)
|
||||
%t38 = icmp ne i32 %t37, 0
|
||||
br i1 %t38, label %then18, label %else19
|
||||
then18:
|
||||
store i32 1, ptr %t5
|
||||
store i32 1, ptr %t4
|
||||
br label %ifend20
|
||||
else19:
|
||||
%t39 = load ptr, ptr %t23
|
||||
%t40 = call i32 @fn_str_eq(ptr %t39, ptr @.str7398)
|
||||
%t40 = call i32 @fn_str_eq(ptr %t39, ptr @.str7402)
|
||||
%t41 = icmp ne i32 %t40, 0
|
||||
br i1 %t41, label %then21, label %else22
|
||||
then21:
|
||||
store i32 1, ptr %t6
|
||||
store i32 1, ptr %t5
|
||||
br label %ifend23
|
||||
else22:
|
||||
%t42 = load ptr, ptr %t23
|
||||
%t43 = call i32 @fn_str_eq(ptr %t42, ptr @.str7399)
|
||||
%t43 = call i32 @fn_str_eq(ptr %t42, ptr @.str7403)
|
||||
%t44 = icmp ne i32 %t43, 0
|
||||
br i1 %t44, label %then24, label %else25
|
||||
then24:
|
||||
%t45 = load i32, ptr %t13
|
||||
%t46 = add i32 %t45, 1
|
||||
store i32 %t46, ptr %t13
|
||||
%t47 = load i32, ptr %t13
|
||||
%t48 = load i32, ptr @L_argc
|
||||
%t49 = icmp slt i32 %t47, %t48
|
||||
%t50 = zext i1 %t49 to i32
|
||||
%t51 = icmp ne i32 %t50, 0
|
||||
br i1 %t51, label %then27, label %ifend29
|
||||
then27:
|
||||
%t52 = load i32, ptr %t13
|
||||
%t53 = load ptr, ptr @L_argv
|
||||
%t54 = getelementptr ptr, ptr %t53, i32 %t52
|
||||
%t55 = load ptr, ptr %t54
|
||||
store ptr %t55, ptr %t1
|
||||
br label %ifend29
|
||||
ifend29:
|
||||
store i32 1, ptr %t6
|
||||
br label %ifend26
|
||||
else25:
|
||||
%t56 = load ptr, ptr %t23
|
||||
%t57 = getelementptr inbounds i8, ptr %t56, i32 0
|
||||
%t58 = load i8, ptr %t57
|
||||
%t59 = zext i8 %t58 to i32
|
||||
%t60 = icmp eq i32 %t59, 45
|
||||
%t61 = zext i1 %t60 to i32
|
||||
%t62 = icmp ne i32 %t61, 0
|
||||
br i1 %t62, label %then30, label %else31
|
||||
%t45 = load ptr, ptr %t23
|
||||
%t46 = call i32 @fn_str_eq(ptr %t45, ptr @.str7404)
|
||||
%t47 = icmp ne i32 %t46, 0
|
||||
br i1 %t47, label %then27, label %else28
|
||||
then27:
|
||||
%t48 = load i32, ptr %t13
|
||||
%t49 = add i32 %t48, 1
|
||||
store i32 %t49, ptr %t13
|
||||
%t50 = load i32, ptr %t13
|
||||
%t51 = load i32, ptr @L_argc
|
||||
%t52 = icmp slt i32 %t50, %t51
|
||||
%t53 = zext i1 %t52 to i32
|
||||
%t54 = icmp ne i32 %t53, 0
|
||||
br i1 %t54, label %then30, label %ifend32
|
||||
then30:
|
||||
%t63 = load ptr, ptr %t23
|
||||
%t64 = call ptr @fn_str_concat(ptr @.str7400, ptr %t63)
|
||||
%t65 = call ptr @fn_str_concat(ptr %t64, ptr @.str7401)
|
||||
store ptr %t65, ptr %t66
|
||||
%t67 = load ptr, ptr @__stderrp
|
||||
%t68 = load ptr, ptr %t66
|
||||
%t69 = load ptr, ptr %t66
|
||||
%t70 = call i64 @strlen(ptr %t69)
|
||||
%t71 = trunc i64 %t70 to i32
|
||||
%t72 = zext i32 %t71 to i64
|
||||
%t73 = call i64 @fwrite(ptr %t68, i64 1, i64 %t72, ptr %t67)
|
||||
%t74 = trunc i64 %t73 to i32
|
||||
br label %ifend32
|
||||
else31:
|
||||
%t75 = load ptr, ptr %t23
|
||||
store ptr %t75, ptr %t0
|
||||
%t55 = load i32, ptr %t13
|
||||
%t56 = load ptr, ptr @L_argv
|
||||
%t57 = getelementptr ptr, ptr %t56, i32 %t55
|
||||
%t58 = load ptr, ptr %t57
|
||||
store ptr %t58, ptr %t1
|
||||
br label %ifend32
|
||||
ifend32:
|
||||
br label %ifend29
|
||||
else28:
|
||||
%t59 = load ptr, ptr %t23
|
||||
%t60 = getelementptr inbounds i8, ptr %t59, i32 0
|
||||
%t61 = load i8, ptr %t60
|
||||
%t62 = zext i8 %t61 to i32
|
||||
%t63 = icmp eq i32 %t62, 45
|
||||
%t64 = zext i1 %t63 to i32
|
||||
%t65 = icmp ne i32 %t64, 0
|
||||
br i1 %t65, label %then33, label %else34
|
||||
then33:
|
||||
%t66 = load ptr, ptr %t23
|
||||
%t67 = call ptr @fn_str_concat(ptr @.str7405, ptr %t66)
|
||||
%t68 = call ptr @fn_str_concat(ptr %t67, ptr @.str7406)
|
||||
store ptr %t68, ptr %t69
|
||||
%t70 = load ptr, ptr @__stderrp
|
||||
%t71 = load ptr, ptr %t69
|
||||
%t72 = load ptr, ptr %t69
|
||||
%t73 = call i64 @strlen(ptr %t72)
|
||||
%t74 = trunc i64 %t73 to i32
|
||||
%t75 = zext i32 %t74 to i64
|
||||
%t76 = call i64 @fwrite(ptr %t71, i64 1, i64 %t75, ptr %t70)
|
||||
%t77 = trunc i64 %t76 to i32
|
||||
br label %ifend35
|
||||
else34:
|
||||
%t78 = load ptr, ptr %t23
|
||||
store ptr %t78, ptr %t0
|
||||
br label %ifend35
|
||||
ifend35:
|
||||
br label %ifend29
|
||||
ifend29:
|
||||
br label %ifend26
|
||||
ifend26:
|
||||
br label %ifend23
|
||||
|
|
@ -62361,242 +62505,242 @@ ifend14:
|
|||
ifend11:
|
||||
br label %ifend8
|
||||
ifend8:
|
||||
%t76 = load i32, ptr %t13
|
||||
%t77 = add i32 %t76, 1
|
||||
store i32 %t77, ptr %t13
|
||||
%t79 = load i32, ptr %t13
|
||||
%t80 = add i32 %t79, 1
|
||||
store i32 %t80, ptr %t13
|
||||
br label %wcond3
|
||||
wend5:
|
||||
%t78 = load ptr, ptr %t0
|
||||
%t79 = icmp eq ptr %t78, null
|
||||
%t80 = zext i1 %t79 to i32
|
||||
%t81 = icmp ne i32 %t80, 0
|
||||
br i1 %t81, label %then33, label %ifend35
|
||||
then33:
|
||||
call void @fn_die(ptr @.str7402)
|
||||
br label %ifend35
|
||||
ifend35:
|
||||
%t82 = load ptr, ptr %t0
|
||||
%t83 = call ptr @fn_read_file(ptr %t82)
|
||||
store ptr %t83, ptr %t84
|
||||
%t85 = load ptr, ptr %t84
|
||||
%t86 = icmp eq ptr %t85, null
|
||||
%t87 = zext i1 %t86 to i32
|
||||
%t88 = icmp ne i32 %t87, 0
|
||||
br i1 %t88, label %then36, label %ifend38
|
||||
%t81 = load ptr, ptr %t0
|
||||
%t82 = icmp eq ptr %t81, null
|
||||
%t83 = zext i1 %t82 to i32
|
||||
%t84 = icmp ne i32 %t83, 0
|
||||
br i1 %t84, label %then36, label %ifend38
|
||||
then36:
|
||||
call void @fn_die(ptr @.str7403)
|
||||
call void @fn_die(ptr @.str7407)
|
||||
br label %ifend38
|
||||
ifend38:
|
||||
%t89 = load ptr, ptr %t0
|
||||
%t90 = call ptr @fn_dir_of(ptr %t89)
|
||||
store ptr %t90, ptr @g_cur_dir
|
||||
%t91 = load ptr, ptr %t84
|
||||
call void @fn_lex(ptr %t91)
|
||||
call void @fn_parse_program()
|
||||
%t92 = load i32, ptr %t4
|
||||
%t93 = icmp ne i32 %t92, 0
|
||||
br i1 %t93, label %then39, label %ifend41
|
||||
%t85 = load ptr, ptr %t0
|
||||
%t86 = call ptr @fn_read_file(ptr %t85)
|
||||
store ptr %t86, ptr %t87
|
||||
%t88 = load ptr, ptr %t87
|
||||
%t89 = icmp eq ptr %t88, null
|
||||
%t90 = zext i1 %t89 to i32
|
||||
%t91 = icmp ne i32 %t90, 0
|
||||
br i1 %t91, label %then39, label %ifend41
|
||||
then39:
|
||||
call void @fn_die(ptr @.str7408)
|
||||
br label %ifend41
|
||||
ifend41:
|
||||
%t92 = load ptr, ptr %t0
|
||||
%t93 = call ptr @fn_dir_of(ptr %t92)
|
||||
store ptr %t93, ptr @g_cur_dir
|
||||
%t94 = load ptr, ptr %t87
|
||||
call void @fn_lex(ptr %t94)
|
||||
call void @fn_parse_program()
|
||||
%t95 = load i32, ptr %t4
|
||||
%t96 = icmp ne i32 %t95, 0
|
||||
br i1 %t96, label %then42, label %ifend44
|
||||
then42:
|
||||
call void @exit(i32 0)
|
||||
unreachable
|
||||
ifend41:
|
||||
ifend44:
|
||||
call void @fn_maybe_splice_runtime()
|
||||
%t95 = load i32, ptr %t6
|
||||
%t96 = icmp ne i32 %t95, 0
|
||||
%t97 = zext i1 %t96 to i32
|
||||
store i32 %t97, ptr %t94
|
||||
br i1 %t96, label %scend43, label %sc42
|
||||
sc42:
|
||||
%t98 = load ptr, ptr %t1
|
||||
%t99 = icmp ne ptr %t98, null
|
||||
%t98 = load i32, ptr %t6
|
||||
%t99 = icmp ne i32 %t98, 0
|
||||
%t100 = zext i1 %t99 to i32
|
||||
%t101 = icmp ne i32 %t100, 0
|
||||
%t102 = zext i1 %t101 to i32
|
||||
store i32 %t102, ptr %t94
|
||||
br label %scend43
|
||||
scend43:
|
||||
%t103 = load i32, ptr %t94
|
||||
store i32 %t103, ptr %t104
|
||||
%t105 = load i32, ptr %t2
|
||||
%t106 = icmp eq i32 %t105, 1
|
||||
%t107 = zext i1 %t106 to i32
|
||||
%t108 = icmp ne i32 %t107, 0
|
||||
br i1 %t108, label %then44, label %else45
|
||||
then44:
|
||||
store i32 1, ptr @g_g_windowed
|
||||
br label %ifend46
|
||||
else45:
|
||||
%t109 = load i32, ptr %t2
|
||||
%t110 = icmp eq i32 %t109, 2
|
||||
%t111 = zext i1 %t110 to i32
|
||||
%t112 = icmp ne i32 %t111, 0
|
||||
br i1 %t112, label %then47, label %else48
|
||||
store i32 %t100, ptr %t97
|
||||
br i1 %t99, label %scend46, label %sc45
|
||||
sc45:
|
||||
%t101 = load ptr, ptr %t1
|
||||
%t102 = icmp ne ptr %t101, null
|
||||
%t103 = zext i1 %t102 to i32
|
||||
%t104 = icmp ne i32 %t103, 0
|
||||
%t105 = zext i1 %t104 to i32
|
||||
store i32 %t105, ptr %t97
|
||||
br label %scend46
|
||||
scend46:
|
||||
%t106 = load i32, ptr %t97
|
||||
store i32 %t106, ptr %t107
|
||||
%t108 = load i32, ptr %t2
|
||||
%t109 = icmp eq i32 %t108, 1
|
||||
%t110 = zext i1 %t109 to i32
|
||||
%t111 = icmp ne i32 %t110, 0
|
||||
br i1 %t111, label %then47, label %else48
|
||||
then47:
|
||||
store i32 0, ptr @g_g_windowed
|
||||
store i32 1, ptr @g_g_windowed
|
||||
br label %ifend49
|
||||
else48:
|
||||
%t114 = load i32, ptr %t104
|
||||
%t112 = load i32, ptr %t2
|
||||
%t113 = icmp eq i32 %t112, 2
|
||||
%t114 = zext i1 %t113 to i32
|
||||
%t115 = icmp ne i32 %t114, 0
|
||||
%t116 = zext i1 %t115 to i32
|
||||
store i32 %t116, ptr %t113
|
||||
br i1 %t115, label %sc50, label %scend51
|
||||
sc50:
|
||||
%t117 = call i32 @fn_has_systems()
|
||||
br i1 %t115, label %then50, label %else51
|
||||
then50:
|
||||
store i32 0, ptr @g_g_windowed
|
||||
br label %ifend52
|
||||
else51:
|
||||
%t117 = load i32, ptr %t107
|
||||
%t118 = icmp ne i32 %t117, 0
|
||||
%t119 = zext i1 %t118 to i32
|
||||
store i32 %t119, ptr %t113
|
||||
br label %scend51
|
||||
scend51:
|
||||
%t120 = load i32, ptr %t113
|
||||
store i32 %t120, ptr @g_g_windowed
|
||||
store i32 %t119, ptr %t116
|
||||
br i1 %t118, label %sc53, label %scend54
|
||||
sc53:
|
||||
%t120 = call i32 @fn_has_systems()
|
||||
%t121 = icmp ne i32 %t120, 0
|
||||
%t122 = zext i1 %t121 to i32
|
||||
store i32 %t122, ptr %t116
|
||||
br label %scend54
|
||||
scend54:
|
||||
%t123 = load i32, ptr %t116
|
||||
store i32 %t123, ptr @g_g_windowed
|
||||
br label %ifend52
|
||||
ifend52:
|
||||
br label %ifend49
|
||||
ifend49:
|
||||
br label %ifend46
|
||||
ifend46:
|
||||
call void @fn_emit_program()
|
||||
%t121 = load i32, ptr %t3
|
||||
%t122 = icmp ne i32 %t121, 0
|
||||
br i1 %t122, label %then52, label %ifend54
|
||||
then52:
|
||||
%t123 = load ptr, ptr %t1
|
||||
%t124 = call i32 @fn_ir_flush(ptr %t123)
|
||||
br label %ret
|
||||
ifend54:
|
||||
%t125 = load i32, ptr %t104
|
||||
%t126 = icmp eq i32 %t125, 0
|
||||
%t127 = zext i1 %t126 to i32
|
||||
%t128 = icmp ne i32 %t127, 0
|
||||
br i1 %t128, label %then55, label %ifend57
|
||||
%t124 = load i32, ptr %t3
|
||||
%t125 = icmp ne i32 %t124, 0
|
||||
br i1 %t125, label %then55, label %ifend57
|
||||
then55:
|
||||
%t129 = call i32 @fn_ir_flush(ptr null)
|
||||
%t126 = load ptr, ptr %t1
|
||||
%t127 = call i32 @fn_ir_flush(ptr %t126)
|
||||
br label %ret
|
||||
ifend57:
|
||||
%t131 = load i32, ptr %t6
|
||||
%t132 = icmp ne i32 %t131, 0
|
||||
%t133 = zext i1 %t132 to i32
|
||||
store i32 %t133, ptr %t130
|
||||
br i1 %t132, label %sc58, label %scend59
|
||||
sc58:
|
||||
%t134 = load ptr, ptr %t1
|
||||
%t135 = icmp eq ptr %t134, null
|
||||
%t128 = load i32, ptr %t107
|
||||
%t129 = icmp eq i32 %t128, 0
|
||||
%t130 = zext i1 %t129 to i32
|
||||
%t131 = icmp ne i32 %t130, 0
|
||||
br i1 %t131, label %then58, label %ifend60
|
||||
then58:
|
||||
%t132 = call i32 @fn_ir_flush(ptr null)
|
||||
br label %ret
|
||||
ifend60:
|
||||
%t134 = load i32, ptr %t6
|
||||
%t135 = icmp ne i32 %t134, 0
|
||||
%t136 = zext i1 %t135 to i32
|
||||
%t137 = icmp ne i32 %t136, 0
|
||||
%t138 = zext i1 %t137 to i32
|
||||
store i32 %t138, ptr %t130
|
||||
br label %scend59
|
||||
scend59:
|
||||
%t139 = load i32, ptr %t130
|
||||
store i32 %t136, ptr %t133
|
||||
br i1 %t135, label %sc61, label %scend62
|
||||
sc61:
|
||||
%t137 = load ptr, ptr %t1
|
||||
%t138 = icmp eq ptr %t137, null
|
||||
%t139 = zext i1 %t138 to i32
|
||||
%t140 = icmp ne i32 %t139, 0
|
||||
br i1 %t140, label %then60, label %ifend62
|
||||
then60:
|
||||
%t141 = load ptr, ptr %t0
|
||||
%t142 = call ptr @fn_base_name(ptr %t141)
|
||||
%t143 = call ptr @fn_strip_ludic(ptr %t142)
|
||||
%t144 = call ptr @fn_str_concat(ptr @.str7404, ptr %t143)
|
||||
store ptr %t144, ptr %t1
|
||||
br label %ifend62
|
||||
ifend62:
|
||||
%t145 = load ptr, ptr %t1
|
||||
%t146 = call ptr @fn_dir_of(ptr %t145)
|
||||
store ptr %t146, ptr %t147
|
||||
%t148 = load ptr, ptr %t147
|
||||
%t149 = call i64 @strlen(ptr %t148)
|
||||
%t150 = trunc i64 %t149 to i32
|
||||
%t151 = icmp sgt i32 %t150, 0
|
||||
%t152 = zext i1 %t151 to i32
|
||||
%t153 = icmp ne i32 %t152, 0
|
||||
br i1 %t153, label %then63, label %ifend65
|
||||
%t141 = zext i1 %t140 to i32
|
||||
store i32 %t141, ptr %t133
|
||||
br label %scend62
|
||||
scend62:
|
||||
%t142 = load i32, ptr %t133
|
||||
%t143 = icmp ne i32 %t142, 0
|
||||
br i1 %t143, label %then63, label %ifend65
|
||||
then63:
|
||||
%t154 = load ptr, ptr %t147
|
||||
%t155 = call ptr @fn_str_concat(ptr @.str7405, ptr %t154)
|
||||
%t156 = call i32 @system(ptr %t155)
|
||||
%t144 = load ptr, ptr %t0
|
||||
%t145 = call ptr @fn_base_name(ptr %t144)
|
||||
%t146 = call ptr @fn_strip_ludic(ptr %t145)
|
||||
%t147 = call ptr @fn_str_concat(ptr @.str7409, ptr %t146)
|
||||
store ptr %t147, ptr %t1
|
||||
br label %ifend65
|
||||
ifend65:
|
||||
%t157 = load ptr, ptr %t1
|
||||
%t158 = call ptr @fn_str_concat(ptr %t157, ptr @.str7406)
|
||||
store ptr %t158, ptr %t159
|
||||
%t160 = load ptr, ptr %t159
|
||||
%t161 = call i32 @fn_ir_flush(ptr %t160)
|
||||
%t162 = icmp eq i32 %t161, 0
|
||||
%t163 = zext i1 %t162 to i32
|
||||
%t164 = icmp ne i32 %t163, 0
|
||||
br i1 %t164, label %then66, label %ifend68
|
||||
%t148 = load ptr, ptr %t1
|
||||
%t149 = call ptr @fn_dir_of(ptr %t148)
|
||||
store ptr %t149, ptr %t150
|
||||
%t151 = load ptr, ptr %t150
|
||||
%t152 = call i64 @strlen(ptr %t151)
|
||||
%t153 = trunc i64 %t152 to i32
|
||||
%t154 = icmp sgt i32 %t153, 0
|
||||
%t155 = zext i1 %t154 to i32
|
||||
%t156 = icmp ne i32 %t155, 0
|
||||
br i1 %t156, label %then66, label %ifend68
|
||||
then66:
|
||||
call void @fn_die(ptr @.str7407)
|
||||
%t157 = load ptr, ptr %t150
|
||||
%t158 = call ptr @fn_str_concat(ptr @.str7410, ptr %t157)
|
||||
%t159 = call i32 @system(ptr %t158)
|
||||
br label %ifend68
|
||||
ifend68:
|
||||
%t165 = call ptr @fn_getenv_or(ptr @.str7408, ptr @.str7409)
|
||||
store ptr %t165, ptr %t166
|
||||
%t167 = load ptr, ptr @L_argv
|
||||
%t168 = getelementptr ptr, ptr %t167, i32 0
|
||||
%t169 = load ptr, ptr %t168
|
||||
%t170 = call ptr @fn_dir_of(ptr %t169)
|
||||
%t171 = call ptr @fn_getenv_or(ptr @.str7410, ptr %t170)
|
||||
%t172 = call ptr @fn_ensure_slash(ptr %t171)
|
||||
store ptr %t172, ptr %t173
|
||||
%t174 = load ptr, ptr %t166
|
||||
%t175 = call ptr @fn_str_concat(ptr %t174, ptr @.str7411)
|
||||
%t176 = load ptr, ptr %t159
|
||||
%t177 = call ptr @fn_str_concat(ptr %t175, ptr %t176)
|
||||
store ptr %t177, ptr %t178
|
||||
%t179 = load i32, ptr @g_g_windowed
|
||||
%t180 = icmp ne i32 %t179, 0
|
||||
br i1 %t180, label %then69, label %ifend71
|
||||
%t160 = load ptr, ptr %t1
|
||||
%t161 = call ptr @fn_str_concat(ptr %t160, ptr @.str7411)
|
||||
store ptr %t161, ptr %t162
|
||||
%t163 = load ptr, ptr %t162
|
||||
%t164 = call i32 @fn_ir_flush(ptr %t163)
|
||||
%t165 = icmp eq i32 %t164, 0
|
||||
%t166 = zext i1 %t165 to i32
|
||||
%t167 = icmp ne i32 %t166, 0
|
||||
br i1 %t167, label %then69, label %ifend71
|
||||
then69:
|
||||
%t181 = load ptr, ptr %t173
|
||||
%t182 = call ptr @fn_path_join(ptr %t181, ptr @.str7412)
|
||||
store ptr %t182, ptr %t183
|
||||
%t184 = load ptr, ptr %t178
|
||||
%t185 = call ptr @fn_str_concat(ptr %t184, ptr @.str7413)
|
||||
%t186 = load ptr, ptr %t183
|
||||
%t187 = call ptr @fn_str_concat(ptr %t185, ptr %t186)
|
||||
%t188 = call ptr @fn_str_concat(ptr %t187, ptr @.str7414)
|
||||
store ptr %t188, ptr %t178
|
||||
call void @fn_die(ptr @.str7412)
|
||||
br label %ifend71
|
||||
ifend71:
|
||||
%t189 = load ptr, ptr %t178
|
||||
%t190 = call ptr @fn_str_concat(ptr %t189, ptr @.str7415)
|
||||
%t191 = load ptr, ptr %t1
|
||||
%t192 = call ptr @fn_str_concat(ptr %t190, ptr %t191)
|
||||
store ptr %t192, ptr %t178
|
||||
%t193 = load ptr, ptr %t178
|
||||
%t194 = call i32 @system(ptr %t193)
|
||||
store i32 %t194, ptr %t195
|
||||
%t196 = load i32, ptr %t5
|
||||
%t197 = icmp eq i32 %t196, 0
|
||||
%t198 = zext i1 %t197 to i32
|
||||
%t199 = icmp ne i32 %t198, 0
|
||||
br i1 %t199, label %then72, label %ifend74
|
||||
%t168 = call ptr @fn_getenv_or(ptr @.str7413, ptr @.str7414)
|
||||
store ptr %t168, ptr %t169
|
||||
%t170 = load ptr, ptr @L_argv
|
||||
%t171 = getelementptr ptr, ptr %t170, i32 0
|
||||
%t172 = load ptr, ptr %t171
|
||||
%t173 = call ptr @fn_dir_of(ptr %t172)
|
||||
%t174 = call ptr @fn_getenv_or(ptr @.str7415, ptr %t173)
|
||||
%t175 = call ptr @fn_ensure_slash(ptr %t174)
|
||||
store ptr %t175, ptr %t176
|
||||
%t177 = load ptr, ptr %t169
|
||||
%t178 = call ptr @fn_str_concat(ptr %t177, ptr @.str7416)
|
||||
%t179 = load ptr, ptr %t162
|
||||
%t180 = call ptr @fn_str_concat(ptr %t178, ptr %t179)
|
||||
store ptr %t180, ptr %t181
|
||||
%t182 = load i32, ptr @g_g_windowed
|
||||
%t183 = icmp ne i32 %t182, 0
|
||||
br i1 %t183, label %then72, label %ifend74
|
||||
then72:
|
||||
%t200 = load ptr, ptr %t159
|
||||
%t201 = call ptr @fn_str_concat(ptr @.str7416, ptr %t200)
|
||||
%t202 = call i32 @system(ptr %t201)
|
||||
%t184 = load ptr, ptr %t176
|
||||
%t185 = call ptr @fn_path_join(ptr %t184, ptr @.str7417)
|
||||
store ptr %t185, ptr %t186
|
||||
%t187 = load ptr, ptr %t181
|
||||
%t188 = call ptr @fn_str_concat(ptr %t187, ptr @.str7418)
|
||||
%t189 = load ptr, ptr %t186
|
||||
%t190 = call ptr @fn_str_concat(ptr %t188, ptr %t189)
|
||||
%t191 = call ptr @fn_str_concat(ptr %t190, ptr @.str7419)
|
||||
store ptr %t191, ptr %t181
|
||||
br label %ifend74
|
||||
ifend74:
|
||||
%t203 = load i32, ptr %t195
|
||||
%t204 = icmp ne i32 %t203, 0
|
||||
%t205 = zext i1 %t204 to i32
|
||||
%t206 = icmp ne i32 %t205, 0
|
||||
br i1 %t206, label %then75, label %ifend77
|
||||
%t192 = load ptr, ptr %t181
|
||||
%t193 = call ptr @fn_str_concat(ptr %t192, ptr @.str7420)
|
||||
%t194 = load ptr, ptr %t1
|
||||
%t195 = call ptr @fn_str_concat(ptr %t193, ptr %t194)
|
||||
store ptr %t195, ptr %t181
|
||||
%t196 = load ptr, ptr %t181
|
||||
%t197 = call i32 @system(ptr %t196)
|
||||
store i32 %t197, ptr %t198
|
||||
%t199 = load i32, ptr %t5
|
||||
%t200 = icmp eq i32 %t199, 0
|
||||
%t201 = zext i1 %t200 to i32
|
||||
%t202 = icmp ne i32 %t201, 0
|
||||
br i1 %t202, label %then75, label %ifend77
|
||||
then75:
|
||||
call void @fn_die(ptr @.str7417)
|
||||
%t203 = load ptr, ptr %t162
|
||||
%t204 = call ptr @fn_str_concat(ptr @.str7421, ptr %t203)
|
||||
%t205 = call i32 @system(ptr %t204)
|
||||
br label %ifend77
|
||||
ifend77:
|
||||
%t207 = load i32, ptr %t6
|
||||
%t208 = icmp ne i32 %t207, 0
|
||||
br i1 %t208, label %then78, label %ifend80
|
||||
%t206 = load i32, ptr %t198
|
||||
%t207 = icmp ne i32 %t206, 0
|
||||
%t208 = zext i1 %t207 to i32
|
||||
%t209 = icmp ne i32 %t208, 0
|
||||
br i1 %t209, label %then78, label %ifend80
|
||||
then78:
|
||||
%t209 = load ptr, ptr %t1
|
||||
%t210 = call i32 @system(ptr %t209)
|
||||
store i32 %t210, ptr %t211
|
||||
%t212 = load i32, ptr %t211
|
||||
%t213 = lshr i32 %t212, 8
|
||||
%t214 = and i32 %t213, 255
|
||||
call void @exit(i32 %t214)
|
||||
unreachable
|
||||
call void @fn_die(ptr @.str7422)
|
||||
br label %ifend80
|
||||
ifend80:
|
||||
%t210 = load i32, ptr %t6
|
||||
%t211 = icmp ne i32 %t210, 0
|
||||
br i1 %t211, label %then81, label %ifend83
|
||||
then81:
|
||||
%t212 = load ptr, ptr %t1
|
||||
%t213 = call i32 @system(ptr %t212)
|
||||
store i32 %t213, ptr %t214
|
||||
%t215 = load i32, ptr %t214
|
||||
%t216 = lshr i32 %t215, 8
|
||||
%t217 = and i32 %t216, 255
|
||||
call void @exit(i32 %t217)
|
||||
unreachable
|
||||
ifend83:
|
||||
br label %ret
|
||||
ret:
|
||||
%t215 = load i32, ptr %retval
|
||||
ret i32 %t215
|
||||
%t218 = load i32, ptr %retval
|
||||
ret i32 %t218
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,24 @@ function die(msg: pointer) -> void {
|
|||
exit(1)
|
||||
}
|
||||
|
||||
# strip trailing newline/carriage-return/space (the VERSION file's trailing \n)
|
||||
function chomp(s: pointer) -> pointer {
|
||||
var n = len(s)
|
||||
while (n > 0) and ((s[n - 1] == 10) or (s[n - 1] == 13) or (s[n - 1] == 32)) { n = n - 1 }
|
||||
return s[0..n]
|
||||
}
|
||||
|
||||
# print "ludic <version>" and exit. The version is read at runtime from the
|
||||
# VERSION file next to LUDIC_HOME (the single source of truth a release bumps),
|
||||
# so a version change never requires reseeding the compiler.
|
||||
function show_version() -> void {
|
||||
let home = ensure_slash(getenv_or("LUDIC_HOME", dir_of(arg(0))))
|
||||
let v = read_file(path_join(home, "VERSION"))
|
||||
if (v == null) { print("ludic (version unknown)") }
|
||||
else { print(`ludic {chomp(v)}`) }
|
||||
exit(0)
|
||||
}
|
||||
|
||||
entry {
|
||||
var path = null
|
||||
var out = null
|
||||
|
|
@ -66,7 +84,8 @@ entry {
|
|||
var ai = 1
|
||||
while ai < arg_count() {
|
||||
let a = arg(ai)
|
||||
if (a == ("--windowed")) { want = 1 }
|
||||
if (a == ("--version")) { show_version() }
|
||||
else { if (a == ("--windowed")) { want = 1 }
|
||||
else { if (a == ("--headless")) { want = 2 }
|
||||
else { if (a == ("--emit-llvm")) { emit_ir = true }
|
||||
else { if (a == ("--fmt")) { fmt = true }
|
||||
|
|
@ -80,7 +99,7 @@ entry {
|
|||
let m = `ludicc: ignoring unknown flag {a}\n`
|
||||
file_write(file_stderr(), m, len(m))
|
||||
} else { path = a }
|
||||
} } } } } } }
|
||||
} } } } } } } }
|
||||
ai = ai + 1
|
||||
}
|
||||
|
||||
|
|
|
|||
107
tools/ci/forgejo_release.py
Normal file
107
tools/ci/forgejo_release.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Create a Forgejo release and attach build artifacts.
|
||||
|
||||
forgejo_release.py <tag> <body-file> <assets-dir>
|
||||
|
||||
Reads the access token from $FORGEJO_TOKEN. `x release --publish` calls this
|
||||
after it has pushed the tag; it is the one piece of the release flow that speaks
|
||||
HTTP, which the Ludic task runner cannot do yet (a native Http client is issue
|
||||
#6). Python stdlib only — no third-party deps — matching the docgen tooling.
|
||||
|
||||
Idempotent-ish: if the release for <tag> already exists it is reused, and each
|
||||
asset in <assets-dir> is uploaded (a duplicate name is skipped, not fatal).
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
API = "https://git.workshopsoft.io/api/v1/repos/workshopsoft/ludic"
|
||||
|
||||
|
||||
def token():
|
||||
t = os.environ.get("FORGEJO_TOKEN", "").strip()
|
||||
if not t:
|
||||
sys.exit("forgejo_release: FORGEJO_TOKEN is not set")
|
||||
return t
|
||||
|
||||
|
||||
def api(method, path, tok, data=None, headers=None, raw=False):
|
||||
url = API + path
|
||||
h = {"Authorization": "token " + tok}
|
||||
body = None
|
||||
if data is not None and not raw:
|
||||
h["Content-Type"] = "application/json"
|
||||
body = json.dumps(data).encode()
|
||||
elif raw:
|
||||
body = data
|
||||
h.update(headers or {})
|
||||
req = urllib.request.Request(url, data=body, headers=h, method=method)
|
||||
with urllib.request.urlopen(req) as r:
|
||||
return r.getcode(), json.loads(r.read().decode() or "null")
|
||||
|
||||
|
||||
def get_release_by_tag(tag, tok):
|
||||
try:
|
||||
_, rel = api("GET", "/releases/tags/" + tag, tok)
|
||||
return rel
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code == 404:
|
||||
return None
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
sys.exit(__doc__)
|
||||
tag, body_file, assets_dir = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
tok = token()
|
||||
|
||||
body = ""
|
||||
if os.path.exists(body_file):
|
||||
with open(body_file, encoding="utf-8") as fh:
|
||||
body = fh.read()
|
||||
|
||||
rel = get_release_by_tag(tag, tok)
|
||||
if rel is None:
|
||||
_, rel = api("POST", "/releases", tok, {
|
||||
"tag_name": tag,
|
||||
"name": tag,
|
||||
"body": body,
|
||||
"draft": False,
|
||||
"prerelease": tag.startswith("v0."),
|
||||
})
|
||||
print("created release", tag, "id", rel["id"])
|
||||
else:
|
||||
print("release", tag, "already exists (id %s); uploading assets" % rel["id"])
|
||||
|
||||
rid = rel["id"]
|
||||
existing = {a["name"] for a in (rel.get("assets") or [])}
|
||||
if os.path.isdir(assets_dir):
|
||||
for name in sorted(os.listdir(assets_dir)):
|
||||
if name in existing:
|
||||
print(" skip (exists):", name)
|
||||
continue
|
||||
path = os.path.join(assets_dir, name)
|
||||
if not os.path.isfile(path):
|
||||
continue
|
||||
with open(path, "rb") as fh:
|
||||
blob = fh.read()
|
||||
boundary = "----ludicrelease7f3b2a"
|
||||
payload = (
|
||||
("--%s\r\n" % boundary)
|
||||
+ ('Content-Disposition: form-data; name="attachment"; filename="%s"\r\n' % name)
|
||||
+ "Content-Type: application/octet-stream\r\n\r\n"
|
||||
).encode() + blob + ("\r\n--%s--\r\n" % boundary).encode()
|
||||
code, _ = api(
|
||||
"POST", "/releases/%s/assets?name=%s" % (rid, name), tok,
|
||||
data=payload, raw=True,
|
||||
headers={"Content-Type": "multipart/form-data; boundary=" + boundary},
|
||||
)
|
||||
print(" uploaded:", name, "(HTTP %d)" % code)
|
||||
print("done:", API + "/releases/tag/" + tag)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -17,6 +17,7 @@ program X {
|
|||
import "tools.ludic"
|
||||
import "selfhost_test.ludic"
|
||||
import "test.ludic"
|
||||
import "release.ludic"
|
||||
|
||||
function usage() -> void {
|
||||
print("x — the Ludic task runner (run from the repository root)")
|
||||
|
|
@ -35,6 +36,11 @@ program X {
|
|||
print(" x test-tools the editor-toolchain suite")
|
||||
print(" x golden regenerate selfhost/golden/renders.sha256 (review with git diff)")
|
||||
print("")
|
||||
print("release:")
|
||||
print(" x version print the toolchain version (ludicc --version)")
|
||||
print(" x release [major|minor|patch] [--publish]")
|
||||
print(" cut a release: CHANGELOG + VERSION bump + tag (+ Forgejo release)")
|
||||
print("")
|
||||
print("self-host internals:")
|
||||
print(" x selfhost-build [ludicc] [out] assemble + compile the self-host compiler")
|
||||
print(" x bootstrap the self-hosting fixpoint proof (seeded from bin/ludicc)")
|
||||
|
|
@ -75,6 +81,8 @@ program X {
|
|||
if (arg_count() < 5) { err("usage: x game-build <ludicc> <game.ludic> <out>\n"); exit(1) }
|
||||
exit(cmd_game_build(arg(2), arg(3), arg(4)))
|
||||
}
|
||||
if (cmd == "version") or (cmd == "--version") or (cmd == "-v") { exit(cmd_version()) }
|
||||
if (cmd == "release") { exit(cmd_release()) }
|
||||
if (cmd == "help") or (cmd == "--help") or (cmd == "-h") { usage(); exit(0) }
|
||||
|
||||
err(`x: unknown command '{cmd}'\n`)
|
||||
|
|
|
|||
148
tools/x/release.ludic
Normal file
148
tools/x/release.ludic
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# release.ludic — versioning + release cutting for the toolchain.
|
||||
#
|
||||
# x version print the toolchain version (from the VERSION file)
|
||||
# x release [level] cut a release: aggregate changes/ into CHANGELOG.md,
|
||||
# bump VERSION, commit, and tag vX.Y.Z. `level` is
|
||||
# major|minor|patch; omitted, it is derived from the
|
||||
# highest `bump:` among the pending changesets.
|
||||
# x release [level] --publish ...then push main + the tag and create a
|
||||
# Forgejo release with source + toolchain tarballs.
|
||||
# Needs FORGEJO_TOKEN in the environment.
|
||||
#
|
||||
# The scheme is SemVer. VERSION is the single source of truth (ludicc --version
|
||||
# reads it at runtime), so a bump touches one file and never reseeds the
|
||||
# compiler. Changesets live as one small Markdown file per change under changes/
|
||||
# (see changes/README.md); a release consumes them into a CHANGELOG.md section.
|
||||
|
||||
# the current version string, or a fallback when VERSION is absent
|
||||
function read_version_or(dflt: pointer) -> pointer {
|
||||
let v = capture_line("cat VERSION 2>/dev/null")
|
||||
if (v == "") { return dflt }
|
||||
return v
|
||||
}
|
||||
|
||||
# true when there is at least one pending changeset (changes/*.md, minus README)
|
||||
function has_changesets() -> bool {
|
||||
return capture_line("ls changes/*.md 2>/dev/null | grep -v '/README.md' | head -1") != ""
|
||||
}
|
||||
|
||||
# the highest bump level requested across the pending changesets ("" if none).
|
||||
# README.md is excluded — its format example carries a literal `bump:` line that
|
||||
# must not count as a real changeset.
|
||||
function highest_bump() -> pointer {
|
||||
if shq("grep -rhqE '^bump:[[:space:]]*major' --include='*.md' --exclude='README.md' changes 2>/dev/null") { return "major" }
|
||||
if shq("grep -rhqE '^bump:[[:space:]]*minor' --include='*.md' --exclude='README.md' changes 2>/dev/null") { return "minor" }
|
||||
if shq("grep -rhqE '^bump:[[:space:]]*patch' --include='*.md' --exclude='README.md' changes 2>/dev/null") { return "patch" }
|
||||
return ""
|
||||
}
|
||||
|
||||
# cur + a SemVer bump of `level` -> the next version string
|
||||
function compute_next(cur: pointer, level: pointer) -> pointer {
|
||||
let maj = capture_line(`printf '%s' '{cur}' | cut -d. -f1`)
|
||||
let min = capture_line(`printf '%s' '{cur}' | cut -d. -f2`)
|
||||
let pat = capture_line(`printf '%s' '{cur}' | cut -d. -f3`)
|
||||
if (level == "major") { let m2 = capture_line(`expr {maj} + 1`); return `{m2}.0.0` }
|
||||
if (level == "minor") { let n2 = capture_line(`expr {min} + 1`); return `{maj}.{n2}.0` }
|
||||
let p2 = capture_line(`expr {pat} + 1`)
|
||||
return `{maj}.{min}.{p2}`
|
||||
}
|
||||
|
||||
# x version — report the toolchain version. Prefer the compiler's own --version
|
||||
# (proving that path works); fall back to the file if ludicc is not built yet.
|
||||
function cmd_version() -> int {
|
||||
if is_exec("bin/ludicc") {
|
||||
run("LUDIC_HOME=. bin/ludicc --version")
|
||||
return 0
|
||||
}
|
||||
print(`ludic {read_version_or("(version unknown)")}`)
|
||||
return 0
|
||||
}
|
||||
|
||||
# assemble the CHANGELOG.md section for `ver` from the pending changesets into
|
||||
# /tmp/x_rel_section.md (header + one bullet per changeset, sorted by type).
|
||||
function build_section(ver: pointer) -> void {
|
||||
let date = capture_line("date +%Y-%m-%d")
|
||||
run(`printf '## v%s — %s\n\n' '{ver}' '{date}' > /tmp/x_rel_section.md`)
|
||||
# one bullet per changeset: "- **<type>**: <body>" (body = the non-header text)
|
||||
run("( for f in changes/*.md; do case \"$f\" in */README.md) continue;; esac; t=$(sed -n 's/^type:[[:space:]]*//p' \"$f\" | head -1); b=$(grep -vE '^(type|bump):' \"$f\" | sed '/^[[:space:]]*$/d' | tr '\\n' ' ' | sed 's/[[:space:]]*$//'); printf -- '- **%s**: %s\\n' \"$t\" \"$b\"; done | sort ) >> /tmp/x_rel_section.md")
|
||||
run("printf '\n' >> /tmp/x_rel_section.md")
|
||||
}
|
||||
|
||||
# prepend /tmp/x_rel_section.md into CHANGELOG.md, above the first existing
|
||||
# release section (or at the end of the header if this is the first release).
|
||||
function prepend_changelog() -> void {
|
||||
if not file_exists("CHANGELOG.md") {
|
||||
run("printf '# Changelog\n\nAll notable changes to the Ludic toolchain, newest first. Generated from the\nchangesets under changes/ by x release; do not edit released sections by hand.\n\n' > CHANGELOG.md")
|
||||
}
|
||||
let ln = capture_line("grep -n '^## ' CHANGELOG.md | head -1 | cut -d: -f1")
|
||||
if (ln == "") {
|
||||
run("cat CHANGELOG.md /tmp/x_rel_section.md > /tmp/x_rel_new.md")
|
||||
} else {
|
||||
run(`head -n $(expr {ln} - 1) CHANGELOG.md > /tmp/x_rel_new.md`)
|
||||
run("cat /tmp/x_rel_section.md >> /tmp/x_rel_new.md")
|
||||
run(`tail -n +{ln} CHANGELOG.md >> /tmp/x_rel_new.md`)
|
||||
}
|
||||
run("cp /tmp/x_rel_new.md CHANGELOG.md")
|
||||
}
|
||||
|
||||
# push main + the tag and create the Forgejo release with build artifacts.
|
||||
function publish_release(ver: pointer) -> int {
|
||||
let tok = getenv_or("FORGEJO_TOKEN", "")
|
||||
if (tok == "") { err("release --publish: set FORGEJO_TOKEN (a Forgejo access token)\n"); return 1 }
|
||||
if not shq("git push origin HEAD") { err("release: git push (main) failed\n"); return 1 }
|
||||
if not shq(`git push origin v{ver}`) { err("release: git push (tag) failed\n"); return 1 }
|
||||
# artifacts: a reproducible source+seed tarball, and the built macOS toolchain.
|
||||
run("mkdir -p dist")
|
||||
run(`git archive --format=tar.gz --prefix=ludic-{ver}/ -o dist/ludic-{ver}-src.tar.gz v{ver}`)
|
||||
if is_exec("bin/ludicc") {
|
||||
let plat = capture_line("uname -s | tr '[:upper:]' '[:lower:]'")
|
||||
let arch = capture_line("uname -m")
|
||||
run(`tar -czf dist/ludic-{ver}-{plat}-{arch}.tar.gz bin selfhost/ludicc.seed.ll VERSION`)
|
||||
}
|
||||
# the changelog section written by build_section is the release body
|
||||
if not shq(`FORGEJO_TOKEN='{tok}' python3 tools/ci/forgejo_release.py v{ver} /tmp/x_rel_section.md dist`) {
|
||||
err("release: creating the Forgejo release failed\n"); return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function cmd_release() -> int {
|
||||
# parse args: an optional level positional, and a --publish flag
|
||||
var level = ""
|
||||
var publish = false
|
||||
var ai = 2
|
||||
while ai < arg_count() {
|
||||
let a = arg(ai)
|
||||
if (a == "--publish") { publish = true }
|
||||
else { if (a == "major") or (a == "minor") or (a == "patch") { level = a }
|
||||
else { err(`release: unknown argument {a}\n`); return 1 } }
|
||||
ai = ai + 1
|
||||
}
|
||||
|
||||
if not has_changesets() {
|
||||
err("release: no changesets under changes/ — add one (see changes/README.md)\n"); return 1
|
||||
}
|
||||
if (level == "") { level = highest_bump() }
|
||||
if (level == "") { err("release: no bump: level in any changeset\n"); return 1 }
|
||||
|
||||
let cur = read_version_or("0.0.0")
|
||||
let ver = compute_next(cur, level)
|
||||
print(`releasing v{ver} ({level} bump from {cur})`)
|
||||
|
||||
build_section(ver)
|
||||
prepend_changelog()
|
||||
if not write_file("VERSION", `{ver}\n`) { err("release: cannot write VERSION\n"); return 1 }
|
||||
run("rm -f $(ls changes/*.md | grep -v '/README.md')")
|
||||
|
||||
# stage only the release artifacts — never a blanket `git add -A`, which would
|
||||
# sweep unrelated in-flight edits (this tree is worked on concurrently).
|
||||
if not shq("git add VERSION CHANGELOG.md changes") { err("release: git add failed\n"); return 1 }
|
||||
if not shq(`git commit -q -m 'chore(release): v{ver}'`) { err("release: git commit failed\n"); return 1 }
|
||||
if not shq(`git tag v{ver}`) { err("release: git tag failed (already exists?)\n"); return 1 }
|
||||
print(` committed + tagged v{ver}`)
|
||||
|
||||
if publish { return publish_release(ver) }
|
||||
print(` local release ready. publish with: FORGEJO_TOKEN=… x release {level} --publish`)
|
||||
print(` (or push: git push origin HEAD && git push origin v{ver})`)
|
||||
return 0
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue