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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
69 changes: 41 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
with:
ruby-version: ${{ env.RUBY_VERSION }}
bundler-cache: true
- run: bundle exec prspec compiler/spec/
- run: WORKERS="$(nproc)" bundle exec prspec compiler/spec/
# Collate parallel_rspec workers' resultsets into a single Cobertura
# XML before upload (each worker writes its own `RSpec-w<id>-<pid>`
# entry into coverage/.resultset.json; collate_coverage merges them
Expand Down Expand Up @@ -655,6 +655,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -699,14 +700,23 @@ jobs:
retention-days: 7

ruby-integration:
name: Ruby integration specs (builds binaries via clear)
name: Ruby integration specs shard ${{ matrix.shard }}/4
needs: changes
if: ${{ needs.changes.outputs.run_src == 'true' }}
runs-on: ubuntu-latest
env:
COVERAGE: "1" # Picked up by spec_helper + clear-CLI's coverage_bootstrap;
# makes integration-only files (clear_bin_spec, clear_fix_spec,
# vm_bg_capture, etc.) contribute to the Ruby flag on Codecov.
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2, 3]
# No COVERAGE here, deliberately. These specs shell out to `./clear`
# hundreds of times and COVERAGE=1 makes every one of those subprocesses
# boot SimpleCov and write a resultset at exit. Measured on a 2-core
# runner: c_ffi_integration_spec 3.1s -> 230.7s, and
# fixable_int_overflow_spec 1.1s -> 45.4s for ZERO examples. That tax,
# not the specs, is what made this job the pipeline's long pole. Ruby
# coverage comes from the unit job, transpile-tests, and the bc-lower
# shards.
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
Expand Down Expand Up @@ -735,30 +745,23 @@ jobs:
clear-build-${{ runner.os }}-zig${{ env.ZIG_VERSION }}-
# Build the register VM binary once, serially, before the suite fans
# out. bc_run.rb guards the build with an exclusive flock, so without
# this the first of 32 prspec workers builds it while the other 31
# block on the lock -- and a cache miss pays that cost inside the
# parallel run rather than ahead of it.
# this the first worker builds it while the rest block on the lock --
# and a cache miss pays that cost inside the parallel run rather than
# ahead of it.
- name: Warm the register VM binary
run: bundle exec ruby examples/minivm/bc_run.rb examples/minivm/arith.clear --run
- run: bundle exec prspec compiler/spec/ --tag integration
# Collate workers + clear-CLI subprocess resultsets into a single
# Cobertura XML, same as the unit job. Both unit and integration
# uploads use `flags: ruby` so Codecov merges them server-side
# into one Ruby coverage view.
- run: bundle exec ruby compiler/spec/collate_coverage.rb
- uses: actions/upload-artifact@v4
with:
name: ruby-coverage-integration
path: coverage/.resultset.json
include-hidden-files: true
retention-days: 7
- uses: codecov/codecov-action@v5
with:
files: ./coverage/coverage.xml
disable_search: true
flags: ruby
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
# Shard by spec file. Every shard restores the same clear-build cache,
# so each one reuses the Zig-compiled CLEAR runtime rather than
# re-analysing it per program.
- name: Run integration shard
run: |
mapfile -t files < <(
grep -rl ':integration' compiler/spec --include='*_spec.rb' | sort |
awk -v s=${{ matrix.shard }} 'NR % 4 == s'
)
if [ ${#files[@]} -eq 0 ]; then echo "shard ${{ matrix.shard }}: no files"; exit 0; fi
printf 'shard ${{ matrix.shard }}: %d files\n' "${#files[@]}"
WORKERS="$(nproc)" bundle exec prspec "${files[@]}" --tag integration

transpile-tests:
name: transpile-tests/ coverage (.clear via gen.rb)
Expand Down Expand Up @@ -1543,6 +1546,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1607,6 +1611,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1721,6 +1726,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1775,6 +1781,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1857,6 +1864,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1928,6 +1936,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -1977,6 +1986,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -2030,6 +2040,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
Expand Down Expand Up @@ -2068,6 +2079,7 @@ jobs:
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
Expand Down Expand Up @@ -2125,6 +2137,7 @@ jobs:
issues: write
pull-requests: write
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
with:
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ gems/**/target/**

# Self-host bootstrap build outputs (sources use explicit extensions).
compiler/src/ast/lexer
compiler/src/ast/parser

# Generated gem diagnostics and local analysis output.
gems/**/*.log
Expand All @@ -213,3 +212,10 @@ gems/fact-mine/target/
gems/hazard-contract/target/
gems/nil-kill/target/
kcov-bin/

# Generated Sorbet-stripped mirror of compiler/ruby (tools/sorbet_strip.rb)
compiler/.ruby-rbs/
# Transient stash used by tools/sorbet_strip_test.rb while it swaps trees
compiler/.ruby-original/
# Local Spinel fork used for the AOT experiment
tmp/spinel/
5 changes: 0 additions & 5 deletions .vscode/extensions/cheat-lang/syntaxes/clear.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,6 @@
},
"sigils": {
"patterns": [
{
"comment": "Explicit panic operator",
"name": "keyword.operator.panic.clear",
"match": "!!"
},
{
"comment": "Mutation suffix on identifiers (foo!, increment!) — must follow a word",
"name": "keyword.operator.mutation.clear",
Expand Down
1 change: 0 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ A new feature is an escape scenario if a frame-allocated value could be read aft
Reference docs: `mir-bugs.md` (known MIR violations), `alloc-bugs.md` (frame-then-promote gaps), `memory-safety.md` (full plan).

## Language Semantics

**Sigils:** `$` pipeline/interp, `&` mutation, `|>` SMOOTH (safe pipeline w/ error prop), `_` placeholder.

**Tense Sigils:** `!` = Error / Error handling, `?` = Option / nil handling, `~` = Stream / future handling.
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/concurrent/05_backpressure/bench.clear
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ FN main() RETURNS Void ->
acc = Acc{ value: 0 } @shared:locked;
t0 = timestampMs();

gen: ~?Int64[] = BG STREAM {
gen: [~]Int64 = BG STREAM {
MUTABLE i = 0;
WHILE i < 100_000 DO
YIELD i;
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/concurrent/08_pubsub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Total work: 10K x 64 x 2000 = 1.28 billion LCG iterations.
## Implementation

- **CLEAR**: publisher writes once to a `SplitStream` ring buffer. Each
subscriber `CLONE`s an independent cursor — zero message copying. Publisher
subscriber `KEEP`s an independent cursor — zero message copying. Publisher
blocks only when the slowest subscriber's cursor is a full buffer behind.
- **Go**: publisher loops over 64 buffered channels (cap 64), sending one
message per subscriber per iteration. Publisher blocks if any channel is
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/concurrent/08_pubsub/bench.clear
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ END
FN main() RETURNS Void ->
t0 = timestampMs();

msgs: ~?Msg[]@split = BG STREAM {
msgs: [~]@split Msg = BG STREAM {
FOR i IN (0 ..< 10_000) -> YIELD Msg{ seed: i };
};

MUTABLE futures: ~Int64[]@list = [];
FOR i IN (0 ..< 64) DO
subscriber_msgs: ~?Msg[]@split = CLONE msgs;
subscriber_msgs: [~]@split Msg = KEEP msgs;
&futures
.append(
BG {
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/concurrent/12_false_sharing/bench.clear
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ FN main() RETURNS !Void ->
MUTABLE wi = 0;
WHILE wi < workers DO
IF counters[wi] EXISTS AS ref0 THEN
ref = CLONE ref0;
ref = KEEP ref0;
&futures
.append(
BG {
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/concurrent/14_nested_lock/bench.clear
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ FN main() RETURNS Void ->
MUTABLE acct_refs: []Account@shared:locked = [];
WITH bank AS bk {
FOR i IN (0 ..< numAccounts) DO
IF bk.accounts[i] EXISTS AS account THEN &acct_refs.append(CLONE account); END
IF bk.accounts[i] EXISTS AS account THEN &acct_refs.append(KEEP account); END
END
}
MUTABLE total = 0;
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/concurrent/16_observables/bench.clear
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ FN main() RETURNS Void ->
n_writes = 2_000_000;
expected = (n_writes * (n_writes - 1)) / 2;

gen: ~?Int64[] = BG STREAM {
gen: [~]Int64 = BG STREAM {
MUTABLE i = 0;
WHILE i < n_writes DO
YIELD i;
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/server/01_tcp_kvstore/server.clear
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ FN handleClient(client: TCPClient, MUTABLE store: {String}String, MUTABLE counte
pos += len;
pos += 2;
IF ai == 0 THEN
arg0 = val;
arg0 = COPY val;
ELSE_IF ai == 1 THEN
arg1 = val;
arg1 = COPY val;
ELSE_IF ai == 2 THEN
arg2 = val;
arg2 = COPY val;
END
END
ai += 1;
Expand Down
Loading
Loading