Compare commits
No commits in common. "main" and "1.0.0-beta.10" have entirely different histories.
main
...
1.0.0-beta
@ -1,57 +0,0 @@
|
|||||||
# 1.0.0-beta.11 Local Package API Documentation
|
|
||||||
|
|
||||||
Status: release scope for `1.0.0-beta.11`.
|
|
||||||
|
|
||||||
`1.0.0-beta.11` extends the beta.10 API discovery lane. The release keeps the
|
|
||||||
`1.0.0-beta` source-language and runtime baseline unchanged while making local
|
|
||||||
package and module documentation show the public API surface users need to
|
|
||||||
review.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Extend `glagol doc <file|project|workspace> -o <dir>` so generated Markdown
|
|
||||||
includes deterministic exported/public API sections for local source files,
|
|
||||||
projects, packages, and workspaces.
|
|
||||||
- Render exact exported function signatures with parameter names, parameter
|
|
||||||
types, and return types.
|
|
||||||
- Render exported struct field names and field types.
|
|
||||||
- Render exported enum variant names and payload types for payloadless and
|
|
||||||
current single-payload variants.
|
|
||||||
- Keep non-exported functions, structs, enums, tests, and `(type ...)` aliases
|
|
||||||
out of the public API sections.
|
|
||||||
- Normalize module-local concrete aliases before rendering public types, so
|
|
||||||
private names such as `VecI32`, `OptionString`, or `ResultU64` do not leak
|
|
||||||
into local package/module public docs.
|
|
||||||
- Update README, language docs, compiler docs, and the post-beta roadmap to
|
|
||||||
describe the beta11 documentation contract clearly.
|
|
||||||
|
|
||||||
## Public Contract
|
|
||||||
|
|
||||||
The generated local documentation is a beta API discovery aid. It exposes what
|
|
||||||
the current local module/package export lists make public, with concrete public
|
|
||||||
types after alias normalization.
|
|
||||||
|
|
||||||
The public API sections are deterministic and suitable for human review, but
|
|
||||||
they are not a stable machine-readable Markdown schema. Headings, anchors, file
|
|
||||||
names, and surrounding prose remain beta-scoped unless a later release freezes
|
|
||||||
them explicitly.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no stable Markdown schema
|
|
||||||
- no stable stdlib/API compatibility freeze
|
|
||||||
- no LSP server or watch mode
|
|
||||||
- no SARIF or daemon protocol
|
|
||||||
- no diagnostics schema policy
|
|
||||||
- no executable generics
|
|
||||||
- no maps or sets
|
|
||||||
- no re-exports, glob imports, or hierarchical modules
|
|
||||||
- no package registry semantics
|
|
||||||
- no new compiler-known runtime names
|
|
||||||
- no runtime helper or ABI/layout changes
|
|
||||||
|
|
||||||
## Checks
|
|
||||||
|
|
||||||
Focused checks for this slice:
|
|
||||||
|
|
||||||
- `git diff --check -- README.md docs/POST_BETA_ROADMAP.md docs/language/ROADMAP.md docs/language/RELEASE_NOTES.md docs/language/SPEC-v1.md docs/compiler/ROADMAP.md docs/compiler/RELEASE_NOTES.md .llm/BETA_11_LOCAL_PACKAGE_API_DOCUMENTATION.md`
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
# 1.0.0-beta.12 Concrete Vector Query And Prefix Parity
|
|
||||||
|
|
||||||
Status: release scope for `1.0.0-beta.12`.
|
|
||||||
|
|
||||||
`1.0.0-beta.12` is a source-authored standard-library/helper parity release for
|
|
||||||
current concrete vectors. It keeps the `1.0.0-beta` source language, typed core,
|
|
||||||
runtime, ABI/layout, and compiler-known `std.vec.*` runtime names unchanged.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Add `count_of`, `starts_with`, `without_prefix`, `ends_with`, and
|
|
||||||
`without_suffix` to `std.vec_i64`.
|
|
||||||
- Add `count_of` to `std.vec_f64`.
|
|
||||||
- Keep helpers ordinary Slovo source over the existing concrete vector runtime
|
|
||||||
names, equality, `len`, `at`, and already staged recursive helpers.
|
|
||||||
- Extend explicit source-helper project coverage for repeated `count_of`
|
|
||||||
results and prefix/suffix empty, mismatch, exact, and longer-than-input
|
|
||||||
cases where applicable.
|
|
||||||
- Bump the Glagol package version to `1.0.0-beta.12`.
|
|
||||||
- Update README, language docs, compiler docs, and the post-beta roadmap.
|
|
||||||
|
|
||||||
## Public Contract
|
|
||||||
|
|
||||||
The helper additions are concrete-family helpers:
|
|
||||||
|
|
||||||
- `std.vec_i64.count_of(values,target)` counts `i64` elements equal to
|
|
||||||
`target`.
|
|
||||||
- `std.vec_i64.starts_with(values,prefix)` and
|
|
||||||
`std.vec_i64.ends_with(values,suffix)` treat empty prefixes/suffixes and
|
|
||||||
exact full-vector matches as true, reject mismatches, and reject longer
|
|
||||||
prefix/suffix inputs.
|
|
||||||
- `std.vec_i64.without_prefix(values,prefix)` and
|
|
||||||
`std.vec_i64.without_suffix(values,suffix)` return the unmatched original
|
|
||||||
vector or the remaining vector after a match.
|
|
||||||
- `std.vec_f64.count_of(values,target)` counts `f64` elements equal to
|
|
||||||
`target`.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no source-language syntax change
|
|
||||||
- no typed-core or lowering change
|
|
||||||
- no runtime implementation change
|
|
||||||
- no new compiler-known stdlib or runtime names
|
|
||||||
- no executable generics or generic stdlib dispatch
|
|
||||||
- no maps or sets
|
|
||||||
- no iterators
|
|
||||||
- no mutable vector operations
|
|
||||||
- no slice/view APIs
|
|
||||||
- no ABI/layout stability promise
|
|
||||||
- no performance claim
|
|
||||||
- no stable stdlib/API freeze
|
|
||||||
|
|
||||||
## Checks
|
|
||||||
|
|
||||||
Focused checks for this slice:
|
|
||||||
|
|
||||||
- `cargo test --manifest-path compiler/Cargo.toml --test standard_vec_i64_source_helpers_alpha --test standard_vec_f64_source_helpers_alpha`
|
|
||||||
- `cargo fmt --manifest-path compiler/Cargo.toml --check`
|
|
||||||
- `git diff --check -- compiler/tests/standard_vec_i64_source_helpers_alpha.rs compiler/tests/standard_vec_f64_source_helpers_alpha.rs compiler/Cargo.toml compiler/Cargo.lock README.md docs/POST_BETA_ROADMAP.md docs/language/ROADMAP.md docs/language/RELEASE_NOTES.md docs/language/SPEC-v1.md docs/compiler/ROADMAP.md docs/compiler/RELEASE_NOTES.md .llm/BETA_12_CONCRETE_VECTOR_QUERY_AND_PREFIX_PARITY.md`
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
# 1.0.0-beta.13 Diagnostic Catalog And Schema Policy
|
|
||||||
|
|
||||||
Status: release scope for `1.0.0-beta.13`.
|
|
||||||
|
|
||||||
`1.0.0-beta.13` is a docs/tooling-only policy slice for the existing
|
|
||||||
diagnostic surface. It keeps the `1.0.0-beta` source language, typed core,
|
|
||||||
runtime, standard library, compiler CLI, diagnostic output shape, ABI/layout,
|
|
||||||
and compiler-known runtime names unchanged.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Add `docs/language/DIAGNOSTICS.md` as the beta policy for
|
|
||||||
`slovo.diagnostic` version `1`.
|
|
||||||
- Document the S-expression and JSON relationship.
|
|
||||||
- Document required and optional fields, severity/source/range/related-span
|
|
||||||
semantics, JSON-line discipline, source-less diagnostics, and
|
|
||||||
artifact-manifest diagnostic metadata.
|
|
||||||
- Define diagnostic compatibility and migration classes.
|
|
||||||
- Inventory the current diagnostic codes covered by
|
|
||||||
`compiler/tests/diagnostics_contract.rs` and the matching `.diag` snapshots.
|
|
||||||
- Update README, language roadmap, language spec, release notes, migration
|
|
||||||
policy, and post-beta roadmap to introduce beta13 and link the diagnostics
|
|
||||||
policy.
|
|
||||||
|
|
||||||
## Acceptance
|
|
||||||
|
|
||||||
- `docs/language/DIAGNOSTICS.md` names schema `slovo.diagnostic` and version
|
|
||||||
`1`.
|
|
||||||
- The document is clear that S-expression diagnostics and JSON diagnostics are
|
|
||||||
encodings of the same data model.
|
|
||||||
- JSON diagnostics are documented as one object per line on stderr, without an
|
|
||||||
array wrapper or pretty-printing requirement.
|
|
||||||
- Source-less diagnostics are documented without inventing fake source spans.
|
|
||||||
- Artifact manifests are documented as carrying diagnostic schema version,
|
|
||||||
diagnostic encoding, and diagnostic stream metadata, not a second diagnostic
|
|
||||||
schema.
|
|
||||||
- Human prose is documented as beta-flexible, while machine fields, codes,
|
|
||||||
schema/version markers, ranges, JSON-line discipline, and golden fixture
|
|
||||||
shape are compatibility-sensitive.
|
|
||||||
- The code catalog is concise and derived from the current golden diagnostics
|
|
||||||
contract.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no source-language syntax change
|
|
||||||
- no typed-core, lowering, runtime, stdlib, or ABI/layout change
|
|
||||||
- no diagnostic-output shape change
|
|
||||||
- no LSP server, watch mode, SARIF, daemon protocol, or debug adapter
|
|
||||||
- no stable Markdown schema
|
|
||||||
- no stable `1.0.0` diagnostics freeze
|
|
||||||
- no source-map, DWARF, or LLVM debug metadata contract
|
|
||||||
- no compiler-emitted diagnostic catalog artifact
|
|
||||||
- no release publication, tag, push, or version publication work
|
|
||||||
|
|
||||||
## Expected Controller Verification
|
|
||||||
|
|
||||||
- Review the policy for consistency with `compiler/src/diag.rs`,
|
|
||||||
`compiler/src/main.rs`, `compiler/tests/diagnostics_contract.rs`, and the
|
|
||||||
current `.diag` snapshots.
|
|
||||||
- Confirm the catalog count matches the current contract: 358 snapshots and
|
|
||||||
114 unique diagnostic codes.
|
|
||||||
- Run lightweight docs checks:
|
|
||||||
- `git diff --check -- README.md docs/POST_BETA_ROADMAP.md docs/language/DIAGNOSTICS.md docs/language/MIGRATION_POLICY.md docs/language/SPEC-v1.md docs/language/ROADMAP.md docs/language/RELEASE_NOTES.md .llm/BETA_13_DIAGNOSTIC_CATALOG_AND_SCHEMA_POLICY.md`
|
|
||||||
- run an `rg` check for stale beta12-only current-stage phrasing across the
|
|
||||||
same touched docs
|
|
||||||
- Do not commit, tag, push, or run release publication from this worker scope.
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
# 1.0.0-beta.14 Benchmark Suite Catalog And Metadata Gate
|
|
||||||
|
|
||||||
Status: release scope for `1.0.0-beta.14`.
|
|
||||||
|
|
||||||
`1.0.0-beta.14` is a docs/tooling metadata slice for the existing benchmark
|
|
||||||
suite. It keeps the `1.0.0-beta` source language, typed core, runtime,
|
|
||||||
standard library, API surface, compiler diagnostics, diagnostic output shape,
|
|
||||||
ABI/layout behavior, and compiler-known runtime names unchanged.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Add `benchmarks/README.md` as the top-level benchmark suite catalog.
|
|
||||||
- Document `python3 benchmarks/runner.py --suite-list` as the non-JSON suite
|
|
||||||
inventory command.
|
|
||||||
- Document `python3 benchmarks/runner.py --suite-list --json` as the beta
|
|
||||||
tooling metadata form for the same inventory.
|
|
||||||
- Record the current suite inventory:
|
|
||||||
`math-loop`, `branch-loop`, `parse-loop`, `array-index-loop`,
|
|
||||||
`string-eq-loop`, `array-struct-field-loop`,
|
|
||||||
`enum-struct-payload-loop`, `vec-i32-index-loop`,
|
|
||||||
`vec-string-eq-loop`, and `json-quote-loop`.
|
|
||||||
- Document that benchmark timings are local-machine evidence only.
|
|
||||||
- Update README, language roadmap, language spec, release notes, post-beta
|
|
||||||
roadmap, and this release contract to introduce beta14.
|
|
||||||
|
|
||||||
## Acceptance
|
|
||||||
|
|
||||||
- Public docs name current release/stage `1.0.0-beta.14`.
|
|
||||||
- `benchmarks/README.md` explains both root suite-list commands:
|
|
||||||
`python3 benchmarks/runner.py --suite-list` and
|
|
||||||
`python3 benchmarks/runner.py --suite-list --json`.
|
|
||||||
- The suite catalog lists the current benchmark suite inventory without adding
|
|
||||||
or removing benchmark kernels.
|
|
||||||
- The suite catalog verifies required scaffold files for each suite:
|
|
||||||
`benchmark.json`, `run.py`, `slovo.toml`, and `src/main.slo`.
|
|
||||||
- The docs say timing output is local-machine evidence only and do not publish
|
|
||||||
timing numbers.
|
|
||||||
- The JSON suite listing is described as beta tooling metadata, not a stable
|
|
||||||
public schema.
|
|
||||||
- Explicit exclusions include no new benchmark kernels, no timing publication,
|
|
||||||
no performance thresholds, no stable JSON schema, no source-language change,
|
|
||||||
no runtime change, no stdlib/API change, no diagnostic-output change, and no
|
|
||||||
ABI/layout change.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no new benchmark kernels or implementation language slots
|
|
||||||
- no benchmark timing publication
|
|
||||||
- no release performance threshold
|
|
||||||
- no stable JSON schema or stable benchmark metadata compatibility promise
|
|
||||||
- no source-language syntax, typed-core, lowering, runtime, stdlib, or API
|
|
||||||
change
|
|
||||||
- no compiler diagnostic or diagnostic-output shape change
|
|
||||||
- no ABI/layout or optimizer guarantee
|
|
||||||
- no worker-owned release publication work before controller review and gates
|
|
||||||
|
|
||||||
## Expected Controller Verification
|
|
||||||
|
|
||||||
- Run lightweight docs checks:
|
|
||||||
- `git diff --check -- README.md benchmarks/README.md docs/POST_BETA_ROADMAP.md docs/language/SPEC-v1.md docs/language/ROADMAP.md docs/language/RELEASE_NOTES.md .llm/BETA_14_BENCHMARK_SUITE_CATALOG_AND_METADATA_GATE.md`
|
|
||||||
- run an `rg` check for stale beta13-only current-stage phrasing across the
|
|
||||||
same touched docs
|
|
||||||
- Smoke the metadata commands:
|
|
||||||
- `python3 benchmarks/runner.py --suite-list`
|
|
||||||
- `python3 benchmarks/runner.py --suite-list --json`
|
|
||||||
- Run focused compiler/tooling checks:
|
|
||||||
- `cargo test --test benchmark_suite_catalog_beta14`
|
|
||||||
- `cargo test --test benchmark_math_loop_scaffold`
|
|
||||||
- Do not commit, tag, push, or run release publication from this worker scope.
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
# 1.0.0-beta.15 Reserved Generic Collection Boundary Hardening And Collection Ledger
|
|
||||||
|
|
||||||
Status: release scope for `1.0.0-beta.15`.
|
|
||||||
|
|
||||||
`1.0.0-beta.15` is a docs/design and compiler-boundary hardening slice for
|
|
||||||
the existing concrete collection and value-family surface. It keeps the
|
|
||||||
`1.0.0-beta` source language, typed core, runtime, standard-library/API
|
|
||||||
surface, diagnostic output shape, diagnostic codes, diagnostic schema,
|
|
||||||
benchmark metadata schema, ABI/layout behavior, compiler-known runtime names,
|
|
||||||
and performance claims unchanged while rewording reserved generic/map/set
|
|
||||||
diagnostic prose away from beta.9-specific text.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Add `docs/language/COLLECTIONS.md` as the collection/value-family ledger.
|
|
||||||
- Inventory the current concrete vector, option, result, and related
|
|
||||||
option/result-returning facade surfaces by linking to
|
|
||||||
`docs/language/STDLIB_API.md` instead of duplicating generated counts.
|
|
||||||
- Record design pressure from duplicated concrete vector, option, and result
|
|
||||||
helper families.
|
|
||||||
- Define prerequisites before executable generics, generic aliases, maps,
|
|
||||||
sets, iterators, mutable vectors, and slice/view APIs can be promoted.
|
|
||||||
- Record current unsupported diagnostics as boundary evidence, not behavior
|
|
||||||
changes.
|
|
||||||
- Centralize reserved generic/collection diagnostics for lowerer, formatter,
|
|
||||||
and checker paths in `compiler/src/reserved.rs`.
|
|
||||||
- Reword affected reserved-boundary snapshots from `beta.9` to current-beta
|
|
||||||
wording while preserving codes, schema, spans, expected/found values, hints,
|
|
||||||
and output shape.
|
|
||||||
- Add focused `reserved_generic_collection_beta15` coverage and run it from
|
|
||||||
`scripts/release-gate.sh`.
|
|
||||||
- Update README, post-beta roadmap, language/compiler roadmaps, language spec,
|
|
||||||
release notes, compiler release notes, and this release contract to introduce
|
|
||||||
beta15.
|
|
||||||
|
|
||||||
## Acceptance
|
|
||||||
|
|
||||||
- Public docs name current release/stage `1.0.0-beta.15`.
|
|
||||||
- `docs/language/COLLECTIONS.md` links to `docs/language/STDLIB_API.md` for
|
|
||||||
exact public helper signatures and does not duplicate generated helper
|
|
||||||
counts.
|
|
||||||
- The ledger inventories the current concrete collection/value-family surface:
|
|
||||||
five concrete vector modules, concrete option families, concrete result
|
|
||||||
families, and option/result-returning host/parsing facades.
|
|
||||||
- The ledger records why repeated concrete vector/option/result facades create
|
|
||||||
design pressure for later generic work.
|
|
||||||
- The ledger defines promotion prerequisites for executable generics, generic
|
|
||||||
aliases, maps, sets, iterators, mutable vectors, and slice/view APIs.
|
|
||||||
- The docs state that current unsupported diagnostics are boundaries, that
|
|
||||||
beta15 rewords only reserved-boundary diagnostic prose, and that beta15 does
|
|
||||||
not change diagnostic output shape, codes, schema, spans, expected/found
|
|
||||||
values, or hints.
|
|
||||||
- Focused compiler tests prove `check`, `fmt --check`, and project-root
|
|
||||||
`check` reject reserved generic/map/set surfaces with stage-neutral current
|
|
||||||
beta wording.
|
|
||||||
- Explicit exclusions include no source-language change, no runtime change, no
|
|
||||||
stdlib/API surface change, no diagnostic output shape/code/schema change, no
|
|
||||||
benchmark metadata schema change, no ABI/layout change, no performance
|
|
||||||
claim, and no stable API freeze.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no executable generics, traits, inference, monomorphization, or generic
|
|
||||||
stdlib dispatch
|
|
||||||
- no generic aliases or parameterized aliases
|
|
||||||
- no map or set semantics
|
|
||||||
- no iterator API
|
|
||||||
- no mutable vector API
|
|
||||||
- no slice/view API
|
|
||||||
- no new compiler-known runtime names or helper symbols
|
|
||||||
- no standard-library/API addition, removal, rename, or stable freeze
|
|
||||||
- no diagnostic output shape, code, schema, span, expected/found, or hint change
|
|
||||||
- no diagnostic policy change beyond reserved-boundary prose rewording
|
|
||||||
- no benchmark metadata schema change
|
|
||||||
- no source-language syntax, typed-core, lowering, runtime, ABI/layout, or
|
|
||||||
optimizer change
|
|
||||||
- no performance threshold or cross-machine performance claim
|
|
||||||
- no worker-owned release publication work before controller review and gates
|
|
||||||
|
|
||||||
## Expected Controller Verification
|
|
||||||
|
|
||||||
- Run lightweight docs checks:
|
|
||||||
- `git diff --check -- README.md docs/POST_BETA_ROADMAP.md docs/language/ROADMAP.md docs/language/SPEC-v1.md docs/language/RELEASE_NOTES.md docs/language/COLLECTIONS.md .llm/BETA_15_RESERVED_GENERIC_COLLECTION_BOUNDARY_HARDENING.md`
|
|
||||||
- run an `rg` check for stale beta14-only current-stage phrasing across the
|
|
||||||
same touched docs
|
|
||||||
- Run focused compiler checks:
|
|
||||||
- `cargo test --test reserved_generic_collection_beta15`
|
|
||||||
- `cargo test --test diagnostics_contract`
|
|
||||||
- `cargo test --test formatter`
|
|
||||||
- `cargo test --test project_mode`
|
|
||||||
- `rg -n "not supported in beta\\.9" compiler/src tests`
|
|
||||||
- Do not commit, tag, push, or run release publication from this worker scope.
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
# 1.0.0-beta.16 String Scanning And Token Boundary Foundation
|
|
||||||
|
|
||||||
Status: combined Slovo/Glagol release scope for `1.0.0-beta.16`.
|
|
||||||
|
|
||||||
`1.0.0-beta.16` adds the first explicit string scanning and token-boundary
|
|
||||||
source facades to `std.string`: byte access, substring extraction, and
|
|
||||||
prefix/suffix checks over the current runtime string representation. The
|
|
||||||
release also promotes the matching compiler-known runtime names through the C
|
|
||||||
runtime, LLVM lowering, source fallback evaluator, diagnostics inventory,
|
|
||||||
local facade fixtures, and release-gate coverage.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Add `byte_at_result ((value string) (index i32)) -> (result i32 i32)` to
|
|
||||||
`lib/std/string.slo`.
|
|
||||||
- Add `slice_result ((value string) (start i32) (count i32)) -> (result string i32)`
|
|
||||||
to `lib/std/string.slo`.
|
|
||||||
- Add `starts_with ((value string) (prefix string)) -> bool` to
|
|
||||||
`lib/std/string.slo`.
|
|
||||||
- Add `ends_with ((value string) (suffix string)) -> bool` to
|
|
||||||
`lib/std/string.slo`.
|
|
||||||
- Mirror those source facades in
|
|
||||||
`examples/projects/std-layout-local-string/src/string.slo`.
|
|
||||||
- Extend the local and explicit `std.string` examples with success and ordinary
|
|
||||||
failure checks for the four helpers.
|
|
||||||
- Promote matching Glagol runtime entries for `std.string.byte_at_result`,
|
|
||||||
`std.string.slice_result`, `std.string.starts_with`, and
|
|
||||||
`std.string.ends_with`.
|
|
||||||
- Add LLVM declarations and lowering for the four promoted runtime names.
|
|
||||||
- Add C runtime implementations for byte access, byte slicing, prefix checks,
|
|
||||||
and suffix checks.
|
|
||||||
- Extend the source fallback test runner behavior for those names.
|
|
||||||
- Add focused beta16 compiler coverage for lowering, hosted runtime execution,
|
|
||||||
and source fallback execution.
|
|
||||||
- Extend diagnostics snapshots for arity, type, context, shadowing, and richer
|
|
||||||
unsupported string-scanning names.
|
|
||||||
- Extend standard-library source-search and local-facade fixtures plus
|
|
||||||
promotion-gate inventory alignment.
|
|
||||||
- Update README, `lib/std/README.md`, post-beta roadmap, language roadmap,
|
|
||||||
release notes, v1 spec, generated stdlib API, compiler docs, release gate,
|
|
||||||
and standard-runtime catalog for beta16.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
- Helpers are byte-oriented over bytes before the trailing NUL in current
|
|
||||||
runtime strings.
|
|
||||||
- `byte_at_result` returns `ok byte` for a valid zero-based byte index and
|
|
||||||
`err 1` for invalid indexes.
|
|
||||||
- `slice_result` returns `ok text` for a valid byte range and `err 1` for
|
|
||||||
invalid ranges.
|
|
||||||
- `slice_result` allocation failure may follow the existing string allocation
|
|
||||||
trap policy.
|
|
||||||
- `starts_with` and `ends_with` perform byte prefix/suffix checks; empty
|
|
||||||
prefix and suffix match.
|
|
||||||
|
|
||||||
## Explicit Non-Scope
|
|
||||||
|
|
||||||
- no Unicode scalar, grapheme, display-width, locale, normalization, or
|
|
||||||
case-folding promise
|
|
||||||
- no JSON parser
|
|
||||||
- no object or array parser
|
|
||||||
- no tokenizer/scanner object API
|
|
||||||
- no language slice/view syntax or borrowed substring view
|
|
||||||
- no mutable strings or string containers
|
|
||||||
- no stable stdlib/API freeze
|
|
||||||
- no stable ABI/layout or ownership guarantee for returned string allocations
|
|
||||||
- no performance claim
|
|
||||||
- no maps, sets, generic collections, or recursive JSON value support
|
|
||||||
- no worker-owned commit, tag, push, or publication before controller gates
|
|
||||||
|
|
||||||
## Expected Verification
|
|
||||||
|
|
||||||
- `cargo fmt --check`
|
|
||||||
- `cargo test --test standard_string_scanning_beta16`
|
|
||||||
- `cargo test --test diagnostics_contract`
|
|
||||||
- `cargo test --test standard_string_source_fallback_helpers_alpha`
|
|
||||||
- `cargo test --test standard_core_facade_source_search_alpha`
|
|
||||||
- `cargo test --test string_runtime`
|
|
||||||
- `cargo test --test promotion_gate -- --ignored`
|
|
||||||
- `cargo test`
|
|
||||||
- `git diff --check`
|
|
||||||
- stale current-stage scan for `1.0.0-beta.15`
|
|
||||||
- public-text scan for local usernames, local filesystem paths, and private host
|
|
||||||
publication references
|
|
||||||
- final `./scripts/release-gate.sh` after commit and generated catalog sync
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
# 1.0.0-beta.17 JSON Primitive Scalar Parsing Foundation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
Slovo-facing `1.0.0-beta.17` adds narrow `std.json` facade names for primitive
|
|
||||||
scalar token parsing:
|
|
||||||
|
|
||||||
- `parse_bool_value_result ((token string)) -> (result bool i32)`
|
|
||||||
- `parse_i32_value_result ((token string)) -> (result i32 i32)`
|
|
||||||
- `parse_u32_value_result ((token string)) -> (result u32 i32)`
|
|
||||||
- `parse_i64_value_result ((token string)) -> (result i64 i32)`
|
|
||||||
- `parse_u64_value_result ((token string)) -> (result u64 i32)`
|
|
||||||
- `parse_f64_value_result ((token string)) -> (result f64 i32)`
|
|
||||||
- `parse_null_value_result ((token string)) -> (result bool i32)`
|
|
||||||
|
|
||||||
The construction surface from `1.0.0-beta.7` remains intact: the existing 24
|
|
||||||
JSON construction exports are still present.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
These helpers parse one already-isolated primitive scalar token. Success
|
|
||||||
returns `ok payload`; ordinary parse failure returns `err 1`.
|
|
||||||
`parse_null_value_result` returns `ok true` only for exact `null` and `err 1`
|
|
||||||
otherwise.
|
|
||||||
|
|
||||||
Numeric and boolean conversion is intentionally concrete and result-returning.
|
|
||||||
The promoted numeric and boolean helpers consume a whole JSON primitive token:
|
|
||||||
no leading/trailing whitespace, no leading `+`, no leading-zero integer form
|
|
||||||
except `0`, and no non-finite f64 values. `parse_f64_value_result` accepts the
|
|
||||||
current JSON-number grammar subset implemented by the runtime, including
|
|
||||||
exponent notation. This slice does not freeze a stable API or ABI.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This is not full JSON parsing. It does not add `parse_string`, `parse_object`,
|
|
||||||
`parse_array`, `parse_value`, tokenizers, recursive `JsonValue`, maps/sets,
|
|
||||||
generic parse APIs, whitespace-tolerant document parsing, schema validation,
|
|
||||||
streaming, Unicode escape handling, stable API freeze, stable ABI/layout, or
|
|
||||||
performance claims.
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
# 1.0.0-beta.18 JSON String Token Parsing Foundation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
Slovo-facing `1.0.0-beta.18` adds one narrow `std.json` facade name for JSON
|
|
||||||
string token parsing:
|
|
||||||
|
|
||||||
- `parse_string_value_result ((token string)) -> (result string i32)`
|
|
||||||
|
|
||||||
The helper is a thin source wrapper over the promoted compiler/runtime name
|
|
||||||
`std.json.parse_string_value_result`. The existing JSON construction helpers
|
|
||||||
from `1.0.0-beta.7` and primitive scalar parse helpers from `1.0.0-beta.17`
|
|
||||||
remain intact.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
`parse_string_value_result` consumes one already-isolated ASCII JSON string
|
|
||||||
token. The token must start and end with quotes and must not include leading or
|
|
||||||
trailing whitespace outside those quotes. Success returns `ok decoded_text`;
|
|
||||||
ordinary parse failure returns `err 1`.
|
|
||||||
|
|
||||||
The token parser decodes the simple JSON escapes `\"`, `\\`, `\/`, `\b`,
|
|
||||||
`\f`, `\n`, `\r`, and `\t`. It rejects raw control bytes, bad escapes,
|
|
||||||
unterminated strings, trailing bytes after the closing quote, raw non-ASCII,
|
|
||||||
and all `\uXXXX` escapes for this slice.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This is not full JSON parsing. It does not add object parsing, array parsing,
|
|
||||||
recursive `JsonValue`, tokenizer APIs, generic parse APIs,
|
|
||||||
whitespace-tolerant document parsing, streaming decoders or encoders, schema
|
|
||||||
validation, Unicode escape decoding or normalization, embedded NUL policy,
|
|
||||||
stable API freeze, stable ABI/layout, or performance claims.
|
|
||||||
|
|
||||||
## Gate-Supporting Compiler Hardening
|
|
||||||
|
|
||||||
The beta18 release also includes a bounded `glagol test` stack hardening fix:
|
|
||||||
test execution runs on a worker thread with a 16 MiB stack. This is not a new
|
|
||||||
language feature. It keeps deep source-authored stdlib fixtures gateable through
|
|
||||||
normal `glagol test` behavior instead of host process stack overflow, and is
|
|
||||||
covered by the promotion gate's stdlib fixture test execution.
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
# 1.0.0-beta.19 Test Discovery And User-Project Conformance Foundation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.19` is a compiler/tooling and conformance slice. It does
|
|
||||||
not change the Slovo source language or standard library surface.
|
|
||||||
|
|
||||||
Add deterministic list-only test discovery for:
|
|
||||||
|
|
||||||
- `glagol test --list <file|project|workspace>`
|
|
||||||
- `glagol --run-tests --list <file>` for the legacy single-file path
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
List mode must reuse the same checked front-end path as normal test execution:
|
|
||||||
parse, lower, type-check, resolve project/workspace inputs, discover tests, and
|
|
||||||
apply `--filter <substring>`.
|
|
||||||
|
|
||||||
The command then lists discovered/selected tests without evaluating test bodies.
|
|
||||||
It must not execute runtime calls from test bodies, mutate files through test
|
|
||||||
logic, open sockets through test logic, or otherwise trigger user test
|
|
||||||
side-effects.
|
|
||||||
|
|
||||||
Ordering must remain deterministic and match current test execution discovery:
|
|
||||||
|
|
||||||
- single-file tests keep source order
|
|
||||||
- project tests keep existing module/package discovery order
|
|
||||||
- workspace tests keep existing workspace/package discovery order
|
|
||||||
|
|
||||||
Normal `glagol test` behavior and output remain unchanged unless `--list` is
|
|
||||||
present. Invalid files, projects, and workspaces still fail through the
|
|
||||||
existing diagnostic path.
|
|
||||||
|
|
||||||
## Output Shape
|
|
||||||
|
|
||||||
The initial output format is beta tooling. It should be stable enough for local
|
|
||||||
release-gate tests, but it is not a frozen public schema.
|
|
||||||
|
|
||||||
The output should make selected, skipped, total discovered, and filter state
|
|
||||||
visible. A concise text shape is enough; a stable JSON/event stream is out of
|
|
||||||
scope for this slice.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- source-language syntax
|
|
||||||
- runtime helper names
|
|
||||||
- JSON expansion
|
|
||||||
- parallel test execution
|
|
||||||
- retries
|
|
||||||
- tags or groups
|
|
||||||
- coverage reports
|
|
||||||
- event streams
|
|
||||||
- stable artifact-manifest schema freeze
|
|
||||||
- stable Markdown schema freeze
|
|
||||||
- LSP or watch behavior
|
|
||||||
- SARIF or daemon protocols
|
|
||||||
- package registries
|
|
||||||
- semver solving
|
|
||||||
- performance claims
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `glagol test --list <file.slo>` lists checked/discovered tests without
|
|
||||||
executing bodies.
|
|
||||||
- `glagol test --list <project>` and workspace inputs preserve current
|
|
||||||
project/workspace ordering.
|
|
||||||
- `glagol --run-tests --list <file.slo>` works for the legacy single-file path.
|
|
||||||
- `--filter <substring>` marks/selects the same tests as normal filtered
|
|
||||||
execution while avoiding body evaluation.
|
|
||||||
- Normal `glagol test` output stays byte-stable for existing covered cases.
|
|
||||||
- Invalid inputs still emit existing diagnostics.
|
|
||||||
- Docs describe beta19 as a released tooling/conformance slice.
|
|
||||||
- Release-gate coverage includes the focused beta19 test-discovery suite.
|
|
||||||
|
|
||||||
## Suggested Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test test_discovery_beta19
|
|
||||||
cargo test --test project_mode
|
|
||||||
cargo test --test cli_v1_1
|
|
||||||
cargo test --test diagnostics_schema_beta13
|
|
||||||
cargo test
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# 1.0.0-beta.20 String Search And ASCII Trim Foundation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.20` is a standard-library and compiler-gate slice. It does not
|
|
||||||
change source-language syntax, runtime C, compiler-known runtime names, or
|
|
||||||
ABI/layout policy.
|
|
||||||
|
|
||||||
The release adds source-authored `std.string` helpers:
|
|
||||||
|
|
||||||
- `contains ((value string) (needle string)) -> bool`
|
|
||||||
- `index_of_option ((value string) (needle string)) -> (option i32)`
|
|
||||||
- `last_index_of_option ((value string) (needle string)) -> (option i32)`
|
|
||||||
- `trim_ascii_start ((value string)) -> string`
|
|
||||||
- `trim_ascii_end ((value string)) -> string`
|
|
||||||
- `trim_ascii ((value string)) -> string`
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
Search is byte-oriented over the current runtime string representation.
|
|
||||||
`index_of_option` returns the first zero-based byte offset for a matching
|
|
||||||
needle, `last_index_of_option` returns the last zero-based byte offset, and
|
|
||||||
`contains` is true when `index_of_option` returns `some`.
|
|
||||||
|
|
||||||
Empty needles are valid:
|
|
||||||
|
|
||||||
- `index_of_option value ""` returns `some 0`
|
|
||||||
- `last_index_of_option value ""` returns `some (len value)`
|
|
||||||
- `contains value ""` returns `true`
|
|
||||||
|
|
||||||
Missing needles return `none`.
|
|
||||||
|
|
||||||
ASCII trim removes only these byte values from the requested edges:
|
|
||||||
|
|
||||||
- `9` horizontal tab
|
|
||||||
- `10` line feed
|
|
||||||
- `11` vertical tab
|
|
||||||
- `12` form feed
|
|
||||||
- `13` carriage return
|
|
||||||
- `32` space
|
|
||||||
|
|
||||||
The helpers compose over already-promoted string primitives:
|
|
||||||
|
|
||||||
- `std.string.len`
|
|
||||||
- `std.string.byte_at_result`
|
|
||||||
- `std.string.slice_result`
|
|
||||||
- `std.string.starts_with`
|
|
||||||
- `std.string.ends_with`
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- compiler-known `std.string.*` runtime names for the new helpers
|
|
||||||
- runtime C helper implementations
|
|
||||||
- source-language syntax
|
|
||||||
- Unicode scalar, grapheme, display-width, or normalization semantics
|
|
||||||
- case folding or locale-sensitive search
|
|
||||||
- regular expressions
|
|
||||||
- tokenizer/parser APIs
|
|
||||||
- mutable strings
|
|
||||||
- language slice/view syntax
|
|
||||||
- stable string ABI/layout
|
|
||||||
- stable allocation ownership rules
|
|
||||||
- stable standard-library compatibility
|
|
||||||
- performance claims
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `lib/std/string.slo` exports all six helpers.
|
|
||||||
- Explicit `std.string` import examples exercise contains, first/last search,
|
|
||||||
missing needles, empty needles, leading trim, trailing trim, full trim,
|
|
||||||
all-whitespace trim, and no-trim cases.
|
|
||||||
- Local `std-layout-local-string` examples mirror the public helper surface.
|
|
||||||
- Focused compiler coverage verifies the helpers are source-authored and that
|
|
||||||
direct compiler-known runtime calls for the new names remain unsupported.
|
|
||||||
- `scripts/release-gate.sh` runs the focused beta20 test.
|
|
||||||
- Generated standard-library API documentation includes the new signatures.
|
|
||||||
|
|
||||||
## Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test standard_string_search_trim_beta20
|
|
||||||
cargo test --test standard_string_source_fallback_helpers_alpha
|
|
||||||
cargo test --test standard_string_scanning_beta16
|
|
||||||
cargo test
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
# 1.0.0-beta.21 JSON Document Scalar Parsing Foundation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.21` is a standard-library and compiler-gate slice. It adds
|
|
||||||
source-authored `std.json` helpers for scalar JSON documents while keeping
|
|
||||||
source-language syntax, runtime C, compiler-known runtime names, and ABI/layout
|
|
||||||
policy unchanged.
|
|
||||||
|
|
||||||
The release adds:
|
|
||||||
|
|
||||||
- `parse_string_document_result ((document string)) -> (result string i32)`
|
|
||||||
- `parse_bool_document_result ((document string)) -> (result bool i32)`
|
|
||||||
- `parse_i32_document_result ((document string)) -> (result i32 i32)`
|
|
||||||
- `parse_u32_document_result ((document string)) -> (result u32 i32)`
|
|
||||||
- `parse_i64_document_result ((document string)) -> (result i64 i32)`
|
|
||||||
- `parse_u64_document_result ((document string)) -> (result u64 i32)`
|
|
||||||
- `parse_f64_document_result ((document string)) -> (result f64 i32)`
|
|
||||||
- `parse_null_document_result ((document string)) -> (result bool i32)`
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
Each helper trims ASCII whitespace around the whole input document with
|
|
||||||
`std.string.trim_ascii`, then delegates to the already released exact
|
|
||||||
value-token parser for that scalar family.
|
|
||||||
|
|
||||||
Leading and trailing ASCII whitespace around one scalar document is accepted.
|
|
||||||
Trailing non-whitespace remains an ordinary parse failure and returns `err 1`
|
|
||||||
through the underlying exact parser.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- compiler-known `std.json.*_document_result` runtime names
|
|
||||||
- private `__glagol_json_*document*` runtime symbols
|
|
||||||
- runtime C helper implementations
|
|
||||||
- source-language syntax
|
|
||||||
- object or array parsing
|
|
||||||
- recursive `JsonValue`
|
|
||||||
- tokenizer/parser objects
|
|
||||||
- maps, sets, executable generics, or generic collections
|
|
||||||
- streaming parsers or encoders
|
|
||||||
- Unicode escape decoding beyond the existing string-token helper
|
|
||||||
- embedded NUL policy
|
|
||||||
- stable JSON APIs
|
|
||||||
- stable ABI/layout
|
|
||||||
- stable standard-library compatibility
|
|
||||||
- performance claims
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `lib/std/json.slo` exports all eight document scalar helpers.
|
|
||||||
- Explicit `std.json` import examples exercise trimmed whitespace success,
|
|
||||||
no-whitespace success, and trailing non-whitespace failure.
|
|
||||||
- Local `std-layout-local-json` examples mirror the public helper surface with
|
|
||||||
an explicit local `string` dependency for `trim_ascii`.
|
|
||||||
- Focused compiler coverage verifies the helpers are source-authored and that
|
|
||||||
direct compiler-known runtime calls for the new names remain unsupported.
|
|
||||||
- `scripts/release-gate.sh` runs the focused beta21 test.
|
|
||||||
- Generated standard-library API documentation includes the new signatures.
|
|
||||||
|
|
||||||
## Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test standard_json_document_scalar_parsing_beta21
|
|
||||||
cargo test --test standard_json_source_facade_alpha
|
|
||||||
cargo test --test promotion_gate
|
|
||||||
cargo test
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
# 1.0.0-beta.22 Run Manifest And Execution Report Hardening
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.22` is a compiler/tooling evidence-hardening slice for
|
|
||||||
`glagol run --manifest`. It keeps the Slovo source language, typed core,
|
|
||||||
runtime capabilities, standard-library surface, compiler-known runtime names,
|
|
||||||
ABI/layout policy, and package behavior unchanged.
|
|
||||||
|
|
||||||
The release adds an additive run-report block to run-mode artifact manifests
|
|
||||||
so manifest evidence can record:
|
|
||||||
|
|
||||||
- process exit status for the invoked program
|
|
||||||
- captured stdout from the run
|
|
||||||
- captured stderr from the run
|
|
||||||
- forwarded program arguments passed through `glagol run`
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
When `glagol run --manifest <path>` completes far enough to write an artifact
|
|
||||||
manifest, the manifest should include run execution evidence in addition to the
|
|
||||||
existing schema marker, command, mode, success, diagnostics metadata, primary
|
|
||||||
output, and artifacts fields.
|
|
||||||
|
|
||||||
The run-report data describes the native executable invocation performed by
|
|
||||||
`glagol run`, not a new source-language or runtime feature. Captured stdout
|
|
||||||
and stderr are evidence fields for tooling and release-gate review; they do
|
|
||||||
not redefine ordinary terminal behavior. Forwarded args are recorded so
|
|
||||||
fixtures can distinguish compiler arguments from user-program arguments.
|
|
||||||
|
|
||||||
The block is additive beta tooling metadata. It is not a stable public schema
|
|
||||||
freeze and does not bump `slovo.artifact-manifest` version `1`.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- source-language syntax
|
|
||||||
- standard-library helpers
|
|
||||||
- compiler-known `std.*` runtime names
|
|
||||||
- runtime C capabilities
|
|
||||||
- package, workspace, import, or registry behavior
|
|
||||||
- stable artifact-manifest schema freeze
|
|
||||||
- stable Markdown schema freeze
|
|
||||||
- LSP, watch, SARIF, or daemon protocols
|
|
||||||
- performance claims
|
|
||||||
- stable ABI/layout
|
|
||||||
- beta maturity beyond the existing `1.0.0-beta` line
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `glagol run --manifest <path>` writes an artifact manifest with an additive
|
|
||||||
run-report block after executing a supported program.
|
|
||||||
- The run report records exit status, captured stdout, captured stderr, and
|
|
||||||
forwarded args.
|
|
||||||
- Existing manifest fields and schema/version markers remain compatible with
|
|
||||||
the beta artifact-manifest contract.
|
|
||||||
- Non-run modes do not need run-report metadata.
|
|
||||||
- Documentation describes beta22 as tooling/CLI evidence hardening only.
|
|
||||||
- Release notes and roadmaps state that beta22 does not add language or
|
|
||||||
stdlib features and does not freeze the manifest schema.
|
|
||||||
|
|
||||||
## Suggested Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test run_manifest_beta22
|
|
||||||
cargo test --test cli_v1_1
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
git diff --check
|
|
||||||
```
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
# 1.0.0-beta.23 Standard Library Stability Tier Ledger And Catalog Alignment
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.23` is a documentation/catalog clarity slice for the standard
|
|
||||||
library. It adds a public stability-tier ledger and aligns the surrounding
|
|
||||||
README, roadmap, release-note, and specification text with the generated API
|
|
||||||
catalog boundary.
|
|
||||||
|
|
||||||
This release does not change the source language, typed core, runtime
|
|
||||||
capabilities, standard-library helper surface, compiler-known runtime names,
|
|
||||||
ABI/layout policy, or package behavior. It does change generated catalog
|
|
||||||
output and release-gate checks so tier metadata is visible and enforced.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
The public standard-library docs use exactly these tier labels:
|
|
||||||
|
|
||||||
- `beta-supported`
|
|
||||||
- `experimental`
|
|
||||||
- `internal`
|
|
||||||
|
|
||||||
The generated `docs/language/STDLIB_API.md` catalog remains the exact exported
|
|
||||||
signature inventory generated from `lib/std/*.slo`. The new
|
|
||||||
`docs/language/STDLIB_TIERS.md` ledger records maturity and stability
|
|
||||||
expectations for those helpers and surrounding standard-library domains.
|
|
||||||
|
|
||||||
Experimental domains in the beta23 ledger include JSON, loopback networking,
|
|
||||||
random/time, and filesystem resource-handle helpers. Concrete vector modules
|
|
||||||
remain beta-supported concrete lanes; they are not a generic collections
|
|
||||||
freeze and do not imply executable generics, maps, sets, iterators, mutable
|
|
||||||
vectors, slice/view APIs, runtime collection changes, or stable ABI/layout.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- source-language syntax
|
|
||||||
- standard-library helpers
|
|
||||||
- compiler-known `std.*` runtime names
|
|
||||||
- runtime C capabilities
|
|
||||||
- package, workspace, import, or registry behavior
|
|
||||||
- stable standard-library/API compatibility freeze
|
|
||||||
- stable manifest schema freeze
|
|
||||||
- stable Markdown schema freeze
|
|
||||||
- stable ABI/layout
|
|
||||||
- performance claims
|
|
||||||
- beta maturity beyond the existing `1.0.0-beta` line
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `docs/language/STDLIB_TIERS.md` defines the public tier labels and their
|
|
||||||
current meaning.
|
|
||||||
- The tier ledger marks JSON, loopback networking, random/time, and filesystem
|
|
||||||
resource-handle helpers as experimental domains.
|
|
||||||
- The tier ledger records concrete vector modules as beta-supported concrete
|
|
||||||
lanes without claiming generic collection stability.
|
|
||||||
- README, `lib/std/README.md`, language release notes, language roadmap,
|
|
||||||
post-beta roadmap, and the v1 spec link or describe the tier ledger.
|
|
||||||
- Documentation states beta23 is docs/catalog tooling clarity only and does
|
|
||||||
not add language, stdlib, runtime, stable schema, or stable API behavior.
|
|
||||||
- The generated API catalog emits tier metadata, and the release gate checks
|
|
||||||
that experimental tiers remain represented.
|
|
||||||
|
|
||||||
## Suggested Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node --check scripts/render-stdlib-api-doc.js
|
|
||||||
node --check scripts/check-stdlib-api-tiers.js
|
|
||||||
./scripts/render-stdlib-api-doc.sh
|
|
||||||
./scripts/check-stdlib-api-tiers.js
|
|
||||||
git diff --check
|
|
||||||
```
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
# 1.0.0-beta.24 Package Manifest Identity And Dependency Discipline
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.24` is a package/workspace discipline hardening slice for local
|
|
||||||
manifest diagnostics. It tightens how package manifest identity and local
|
|
||||||
dependency tables are reported when users write ambiguous or invalid manifest
|
|
||||||
keys.
|
|
||||||
|
|
||||||
This release changes diagnostics only. It does not change the Slovo source
|
|
||||||
language, typed core, runtime behavior, standard-library helper surface,
|
|
||||||
compiler-known runtime names, package graph semantics, ABI/layout policy, or
|
|
||||||
artifact/Markdown schema stability guarantees.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
The beta package model remains a closed local workspace model:
|
|
||||||
|
|
||||||
- package manifests declare `[package]` identity metadata and optional
|
|
||||||
`[dependencies]` local path records
|
|
||||||
- dependency keys name local packages and must match the target package name
|
|
||||||
- dependency paths remain local path records under the existing workspace and
|
|
||||||
package boundary checks
|
|
||||||
|
|
||||||
The beta24 diagnostic hardening makes these manifest errors explicit:
|
|
||||||
|
|
||||||
- duplicate keys in package manifests report `PackageManifestInvalid`
|
|
||||||
- invalid dependency keys report `InvalidPackageDependencyName`
|
|
||||||
- duplicate dependency keys report `DuplicatePackageDependencyName`
|
|
||||||
|
|
||||||
These diagnostics are part of the beta package/workspace discipline surface.
|
|
||||||
They do not promote a package manager, resolver, lockfile, registry, publish
|
|
||||||
flow, or stable package ABI/layout.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- remote registry behavior
|
|
||||||
- lockfiles
|
|
||||||
- semantic-version solving
|
|
||||||
- package publishing
|
|
||||||
- optional, dev, target, or feature-gated dependencies
|
|
||||||
- build scripts or package archives
|
|
||||||
- stable package ABI/layout
|
|
||||||
- stable package manager behavior
|
|
||||||
- source-language syntax or semantics
|
|
||||||
- runtime behavior or runtime C capabilities
|
|
||||||
- standard-library helpers or stdlib behavior
|
|
||||||
- compiler-known `std.*` runtime names
|
|
||||||
- stable artifact-manifest or Markdown schema guarantees
|
|
||||||
- performance claims
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- `docs/language/PACKAGES.md` documents duplicate package-manifest keys,
|
|
||||||
invalid dependency keys, and duplicate dependency keys as explicit beta
|
|
||||||
diagnostics.
|
|
||||||
- Language and compiler release notes describe beta24 as package manifest
|
|
||||||
identity/dependency diagnostic hardening only.
|
|
||||||
- Language and compiler roadmaps record beta24 as a local package/workspace
|
|
||||||
diagnostics slice with all registry, lockfile, semver, publishing,
|
|
||||||
optional/dev/target dependency, ABI/layout, language, runtime, and stdlib
|
|
||||||
work deferred.
|
|
||||||
- README and the post-beta roadmap identify `1.0.0-beta.24` as the current
|
|
||||||
package/workspace discipline hardening slice.
|
|
||||||
- Glagol is versioned as `1.0.0-beta.24`.
|
|
||||||
- `compiler/tests/package_workspace_discipline_beta24.rs` covers the focused
|
|
||||||
package manifest/dependency diagnostics and a positive local dependency
|
|
||||||
workspace.
|
|
||||||
- `scripts/release-gate.sh` runs the focused beta24 test.
|
|
||||||
|
|
||||||
## Suggested Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git diff --check
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test package_workspace_discipline_beta24
|
|
||||||
```
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
# 1.0.0-beta.25 User Project Conformance Matrix
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
`1.0.0-beta.25` is a tooling/conformance evidence slice for ordinary
|
|
||||||
project and workspace usage. It adds a deterministic user-project conformance
|
|
||||||
matrix over the existing checked examples under `examples/projects/` and
|
|
||||||
`examples/workspaces/`.
|
|
||||||
|
|
||||||
The matrix is stable-readiness evidence for the beta toolchain. It records
|
|
||||||
which existing user-shaped example projects and workspaces are expected to
|
|
||||||
pass `glagol check`, `glagol test --list`, and stable `glagol test` execution
|
|
||||||
through ordinary Glagol entry points.
|
|
||||||
|
|
||||||
At release time the matrix covers all 43 top-level fixture roots with
|
|
||||||
`slovo.toml` under those inventories and 655 discovered tests. Environment
|
|
||||||
fixtures run with deterministic in-test environment values so host shell state
|
|
||||||
does not decide the result.
|
|
||||||
|
|
||||||
This release changes tooling evidence only. It does not change the Slovo
|
|
||||||
source language, typed core, runtime behavior, standard-library helper
|
|
||||||
surface, compiler-known runtime names, package-manager behavior, package graph
|
|
||||||
semantics, registry behavior, lockfile behavior, semver behavior, ABI/layout
|
|
||||||
policy, stable schema policy, or performance policy.
|
|
||||||
|
|
||||||
## Contract
|
|
||||||
|
|
||||||
The conformance matrix is deterministic and repository-local:
|
|
||||||
|
|
||||||
- inputs are every top-level `slovo.toml` fixture under the existing
|
|
||||||
`examples/projects/` and `examples/workspaces/` directories
|
|
||||||
- entries are sorted by stable repository-relative path
|
|
||||||
- each entry names the example kind, path, and ordinary project/workspace
|
|
||||||
test count covered by the matrix
|
|
||||||
- fixture inventory drift must fail the focused matrix test until the matrix
|
|
||||||
and release evidence are updated deliberately
|
|
||||||
- generated evidence must not depend on wall-clock time, host-specific
|
|
||||||
absolute paths, random ordering, or network access
|
|
||||||
- matrix output is beta readiness evidence, not a frozen public schema
|
|
||||||
|
|
||||||
The matrix is intended to answer whether normal beta users can exercise the
|
|
||||||
current example projects and workspaces through the documented toolchain. It
|
|
||||||
does not promote new language forms, new standard-library helpers, new runtime
|
|
||||||
capabilities, new package manager behavior, or new compatibility guarantees.
|
|
||||||
|
|
||||||
## Non-Scope
|
|
||||||
|
|
||||||
This scope does not add:
|
|
||||||
|
|
||||||
- source-language syntax or semantics
|
|
||||||
- typed-core changes
|
|
||||||
- standard-library helpers or stdlib behavior changes
|
|
||||||
- compiler-known `std.*` runtime names
|
|
||||||
- runtime behavior or runtime C capabilities
|
|
||||||
- package manager behavior
|
|
||||||
- remote registry behavior
|
|
||||||
- lockfiles
|
|
||||||
- semantic-version solving
|
|
||||||
- package publishing
|
|
||||||
- optional, dev, target, or feature-gated dependencies
|
|
||||||
- stable package ABI/layout
|
|
||||||
- stable artifact-manifest, Markdown, JSON, or conformance-matrix schema
|
|
||||||
guarantees
|
|
||||||
- performance thresholds, performance claims, or timing publication
|
|
||||||
- LSP/watch, SARIF, daemon, coverage, retry, tag/group, or event-stream
|
|
||||||
protocols
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- README names `1.0.0-beta.25` as the current release and describes the
|
|
||||||
user-project conformance matrix as tooling/readiness evidence only.
|
|
||||||
- Language and compiler release notes describe beta25 as a
|
|
||||||
tooling/conformance evidence slice over existing `examples/projects/` and
|
|
||||||
`examples/workspaces/`.
|
|
||||||
- Language and compiler roadmaps record beta25 as the current
|
|
||||||
stable-readiness evidence slice while keeping language, stdlib, runtime,
|
|
||||||
package-manager, stable-schema, and performance work deferred.
|
|
||||||
- The post-beta roadmap records beta25 under tooling/release hardening.
|
|
||||||
- Glagol is versioned as `1.0.0-beta.25`.
|
|
||||||
- `compiler/tests/user_project_conformance_beta25.rs` covers all 43 top-level
|
|
||||||
project/workspace fixture roots and 655 discovered tests.
|
|
||||||
- Fixture inventory drift is checked against discovered top-level
|
|
||||||
`slovo.toml` roots.
|
|
||||||
- `scripts/release-gate.sh` runs the focused beta25 matrix test.
|
|
||||||
- No compiler, runtime, standard-library, package-manager, registry, lockfile,
|
|
||||||
semver, ABI/layout, stable-schema, or performance claim is introduced by
|
|
||||||
the documentation.
|
|
||||||
|
|
||||||
## Suggested Gates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git diff --check
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test user_project_conformance_beta25
|
|
||||||
```
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
# 1.0.0-beta.11 Release Review
|
|
||||||
|
|
||||||
Status: ready for publication after the controller release gate.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
No blocking issues remain after controller follow-up. The original workspace
|
|
||||||
package API leak was reproduced, fixed, and covered by a regression test before
|
|
||||||
publication.
|
|
||||||
|
|
||||||
## Resolved Finding
|
|
||||||
|
|
||||||
- Workspace package API docs originally included compiler-loaded standard
|
|
||||||
library modules when a workspace package imported `std.option`.
|
|
||||||
- Controller fix: workspace package API rendering now filters package modules
|
|
||||||
to the package source root before collecting public API sections, matching
|
|
||||||
the existing project-mode local-root behavior. Ordinary module summaries can
|
|
||||||
still show loaded standard-library modules, but package API sections no
|
|
||||||
longer present those modules as package-owned API.
|
|
||||||
- Regression added:
|
|
||||||
`doc_workspace_package_api_excludes_loaded_std_modules`.
|
|
||||||
|
|
||||||
## Scope Checked
|
|
||||||
|
|
||||||
- `compiler/src/docgen.rs` adds per-module public API sections and package API
|
|
||||||
sections, renders exported function signatures, struct fields, enum variants,
|
|
||||||
and normalizes module-local aliases before public rendering.
|
|
||||||
- `compiler/tests/doc_api_beta11.rs` covers file, project, workspace scaffold,
|
|
||||||
workspace packages importing `std.*`, alias normalization, non-exported
|
|
||||||
function omission, and byte-identical repeat generation for a file input.
|
|
||||||
- README, compiler/language roadmaps, release notes, SPEC-v1, `STDLIB_API.md`,
|
|
||||||
and the beta11 `.llm` contract include the main deferrals: no stable Markdown
|
|
||||||
schema, no stable stdlib/API compatibility freeze, no LSP/watch, no
|
|
||||||
SARIF/daemon protocol, no diagnostics schema policy, no executable generics,
|
|
||||||
no maps/sets, no re-exports/globs/hierarchical modules, and no registry
|
|
||||||
semantics.
|
|
||||||
- Version bumps in `compiler/Cargo.toml` and `compiler/Cargo.lock` move
|
|
||||||
`glagol` from `1.0.0-beta.10` to `1.0.0-beta.11`.
|
|
||||||
|
|
||||||
## Test Coverage Notes
|
|
||||||
|
|
||||||
- Workspace packages that import `std.*` are now covered by a focused
|
|
||||||
regression that verifies package API excludes loaded standard-library
|
|
||||||
modules and helpers.
|
|
||||||
- Determinism is asserted byte-for-byte only for file docs. Project and
|
|
||||||
workspace determinism are indirectly exercised by sorted rendering but not
|
|
||||||
protected by repeat-generation tests.
|
|
||||||
- Non-export filtering is asserted for functions and aliases. There is no
|
|
||||||
explicit negative test for non-exported structs, non-exported enums, or tests
|
|
||||||
appearing in public API sections.
|
|
||||||
- Alias normalization is covered for file/module docs, but not for project or
|
|
||||||
workspace package API fixtures.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
- `cargo fmt --check`: passed.
|
|
||||||
- `cargo check`: passed.
|
|
||||||
- `cargo test --test doc_api_beta11`: passed, 6 tests.
|
|
||||||
- `cargo test --test dx_v1_7`: passed, 13 tests.
|
|
||||||
- `cargo test --test symbols_beta10`: passed, 4 tests.
|
|
||||||
- `cargo test --test promotion_gate`: passed, 1 unignored test.
|
|
||||||
- `git diff --check`: passed.
|
|
||||||
- Stale beta10 current-release/version scan over README, docs, `.llm`, and
|
|
||||||
compiler package metadata: no matches.
|
|
||||||
- Private/local publication text scan over README, docs, scripts, compiler
|
|
||||||
source/tests, lib, examples, benchmarks, tests, and `.llm`: no matches.
|
|
||||||
- `node scripts/render-stdlib-api-doc.js`: passed and refreshed the catalog
|
|
||||||
release wording to `1.0.0-beta.11`.
|
|
||||||
- Manual workspace std-import doc generation after the fix: package API no
|
|
||||||
longer includes loaded standard-library modules.
|
|
||||||
- `./scripts/release-gate.sh`: passed docs, generated stdlib API catalog
|
|
||||||
consistency, private-publication text checks, formatter checks, the full cargo
|
|
||||||
test suite, ignored promotion checks, binary smoke, and LLVM smoke.
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
# 1.0.0-beta.12 Release Review
|
|
||||||
|
|
||||||
Status: ready for publication after controller release gate.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
No blocking issues found in the current beta12 worktree. The slice is correctly
|
|
||||||
framed as concrete vector source-helper parity and can proceed to the final
|
|
||||||
publication gate.
|
|
||||||
|
|
||||||
## Scope Checked
|
|
||||||
|
|
||||||
- `lib/std/vec_i64.slo` exports and implements `count_of`, `starts_with`,
|
|
||||||
`without_prefix`, `ends_with`, and `without_suffix` as ordinary source
|
|
||||||
helpers over the existing `std.vec.i64` runtime wrappers and staged helper
|
|
||||||
surface.
|
|
||||||
- `lib/std/vec_f64.slo` exports and implements `count_of` as an ordinary
|
|
||||||
source helper; the existing f64 prefix/suffix helpers remain aligned.
|
|
||||||
- Local fixture copies, explicit `std.vec_i64` and `std.vec_f64` examples, and
|
|
||||||
mirrored language-doc examples import and exercise the new helpers.
|
|
||||||
- Focused helper tests, source-search tests, and promotion-gate inventories now
|
|
||||||
require the new exports and expected `20 test(s) passed` fixture output.
|
|
||||||
- README, roadmaps, release notes, SPEC-v1, regenerated `STDLIB_API.md`, the
|
|
||||||
beta12 `.llm` scope note, and the compiler package version bump align on the
|
|
||||||
`1.0.0-beta.12` concrete vector query and prefix parity scope.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blockers.
|
|
||||||
|
|
||||||
- Helper semantics match the existing concrete lanes: exact equality counts,
|
|
||||||
empty prefix/suffix success, longer input rejection, mismatch rejection, exact
|
|
||||||
removal to empty, and unmatched removal returning the original vector.
|
|
||||||
- Release-facing text keeps the scope narrow: no source-language, runtime,
|
|
||||||
typed-core, compiler-known stdlib/runtime-name, generic dispatch, map/set,
|
|
||||||
iterator, mutable-vector, slice/view, ABI/layout, performance, or stable
|
|
||||||
stdlib/API-freeze claim.
|
|
||||||
- `STDLIB_API.md` is consistent with the current `lib/std` sources: 578
|
|
||||||
exported helper signatures total, with 36 each for `std.vec_i64` and
|
|
||||||
`std.vec_f64`.
|
|
||||||
- Publication hygiene review found no beta12 private local path leakage in the
|
|
||||||
touched release-facing text.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
- `cargo test --manifest-path compiler/Cargo.toml --test standard_vec_i64_source_helpers_alpha --test standard_vec_f64_source_helpers_alpha --test standard_vec_i64_source_search_alpha --test standard_vec_f64_source_search_alpha`: passed.
|
|
||||||
- `cargo fmt --manifest-path compiler/Cargo.toml --check`: passed.
|
|
||||||
- `git diff --check`: passed.
|
|
||||||
- `STDLIB_API.md` was regenerated in an isolated copy and compared against the
|
|
||||||
worktree copy: no diff.
|
|
||||||
|
|
||||||
- `./scripts/release-gate.sh`: passed after the beta12 release commit, including
|
|
||||||
docs/API freshness, `cargo fmt --check`, full `cargo test`, ignored promotion
|
|
||||||
gates, binary smoke, and LLVM smoke.
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
# 1.0.0-beta.13 Release Review
|
|
||||||
|
|
||||||
Status: ready for publication after controller release gate.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
No blockers after controller catalog-count reconciliation.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings remain.
|
|
||||||
|
|
||||||
Controller reconciliation note: the initial review used `rg -o -h ...` for the
|
|
||||||
catalog count. On the local ripgrep version, `-h` prints help instead of
|
|
||||||
meaning "no filename", so that command mixed help text with diagnostic codes.
|
|
||||||
Using `--no-filename` gives the correct inventory: 358 `.diag` snapshots and
|
|
||||||
114 unique `(code ...)` values. The Current Golden Catalog table matches that
|
|
||||||
114-code snapshot set.
|
|
||||||
|
|
||||||
## Scope Checked
|
|
||||||
|
|
||||||
- Public docs in scope: `README.md`, `docs/POST_BETA_ROADMAP.md`,
|
|
||||||
`docs/language/DIAGNOSTICS.md`, `docs/language/MIGRATION_POLICY.md`,
|
|
||||||
`docs/language/SPEC-v1.md`, `docs/language/ROADMAP.md`,
|
|
||||||
`docs/language/RELEASE_NOTES.md`, `docs/compiler/ROADMAP.md`,
|
|
||||||
`docs/compiler/RELEASE_NOTES.md`, `docs/language/STDLIB_API.md`, and
|
|
||||||
`.llm/BETA_13_DIAGNOSTIC_CATALOG_AND_SCHEMA_POLICY.md`.
|
|
||||||
- Compiler/tooling in scope: `compiler/src/diag.rs`, `compiler/src/main.rs`,
|
|
||||||
`compiler/tests/diagnostics_schema_beta13.rs`,
|
|
||||||
`compiler/tests/diagnostics_contract.rs`, `scripts/release-gate.sh`,
|
|
||||||
`compiler/Cargo.toml`, and `compiler/Cargo.lock`.
|
|
||||||
- The compiler diff keeps diagnostic output shape limited to centralizing
|
|
||||||
`slovo.diagnostic` schema name/version constants and reusing the version in
|
|
||||||
artifact manifest diagnostics metadata.
|
|
||||||
- `docs/language/DIAGNOSTICS.md` describes the current S-expression and JSON
|
|
||||||
diagnostic shape, newline-delimited JSON stderr behavior, source-less JSON
|
|
||||||
`file:null` and `span:null`, artifact-manifest diagnostic metadata,
|
|
||||||
compatibility/migration classes, and explicit deferrals.
|
|
||||||
- Release-facing stage wording consistently points at `1.0.0-beta.13` as the
|
|
||||||
current stage and post-beta13 work as the next scope. Focused private-path
|
|
||||||
and stale current-stage beta12 checks found no matches.
|
|
||||||
|
|
||||||
## Verification Commands And Results
|
|
||||||
|
|
||||||
- `cargo fmt --check`: passed.
|
|
||||||
- `cargo test --test diagnostics_schema_beta13`: passed, 3 tests.
|
|
||||||
- `cargo test --test diagnostics_contract current_negative_cases_match_machine_diagnostic_snapshots`:
|
|
||||||
passed, 1 test.
|
|
||||||
- `git diff --check`: passed.
|
|
||||||
- `rg -o 'snapshot: "\\.\\./tests/[^"]+\\.diag"' compiler/tests/diagnostics_contract.rs | wc -l`:
|
|
||||||
`358`.
|
|
||||||
- `rg --files tests | rg '\\.diag$' | wc -l`: `358`.
|
|
||||||
- `rg --no-filename -o '\\(code [A-Za-z][A-Za-z0-9]*\\)' tests/*.diag | sed -E 's/^\\(code ([^)]+)\\)$/\\1/' | sort -u | wc -l`:
|
|
||||||
`114`.
|
|
||||||
- Comparing the unique snapshot code set with the Current Golden Catalog code
|
|
||||||
set produced no differences, confirming the catalog table itself matches the
|
|
||||||
114-code snapshot set.
|
|
||||||
- Focused `rg` check for private/local paths and stale current-stage beta12
|
|
||||||
release wording in the scoped public docs produced no matches.
|
|
||||||
|
|
||||||
- `./scripts/release-gate.sh`: passed after the beta13 release commit,
|
|
||||||
including docs/API freshness, the focused beta13 diagnostics schema test,
|
|
||||||
`cargo fmt --check`, full `cargo test`, ignored promotion gates, binary
|
|
||||||
smoke, and LLVM smoke.
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
# 1.0.0-beta.14 Release Review
|
|
||||||
|
|
||||||
Status: ready for publication after controller release gate.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
No blocking findings found for the benchmark suite catalog and metadata gate.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
Non-blocking note: `compiler/tests/benchmark_suite_catalog_beta14.rs` verifies
|
|
||||||
byte-stable JSON, the current 10 benchmark names/directories, top-level counts,
|
|
||||||
required scaffold-file status, missing-file lists, checksum metadata presence,
|
|
||||||
timing mode strings, and implementation slot names. The current runner output
|
|
||||||
also includes `run_args`, `source_stem`, and per-implementation source paths.
|
|
||||||
If those fields become contractual in a later release, the focused gate should
|
|
||||||
parse the JSON and assert them per benchmark.
|
|
||||||
|
|
||||||
## Scope Checked
|
|
||||||
|
|
||||||
- Public release docs in scope: `README.md`, `benchmarks/README.md`,
|
|
||||||
`docs/POST_BETA_ROADMAP.md`, `docs/language/SPEC-v1.md`,
|
|
||||||
`docs/language/ROADMAP.md`, `docs/language/RELEASE_NOTES.md`,
|
|
||||||
`docs/compiler/ROADMAP.md`, `docs/compiler/RELEASE_NOTES.md`, and
|
|
||||||
`.llm/BETA_14_BENCHMARK_SUITE_CATALOG_AND_METADATA_GATE.md`.
|
|
||||||
- Tooling and tests in scope: `benchmarks/runner.py`,
|
|
||||||
`compiler/tests/benchmark_suite_catalog_beta14.rs`,
|
|
||||||
`compiler/tests/benchmark_math_loop_scaffold.rs`,
|
|
||||||
`scripts/release-gate.sh`, `compiler/Cargo.toml`, and
|
|
||||||
`compiler/Cargo.lock`.
|
|
||||||
- Release-facing current-stage wording points at `1.0.0-beta.14`. Remaining
|
|
||||||
beta13 references are historical beta13 diagnostics/release notes, the
|
|
||||||
existing `diagnostics_schema_beta13` gate, or older review/contract files.
|
|
||||||
- Benchmark docs and runner output consistently keep timing local-machine-only,
|
|
||||||
do not publish timing numbers, do not define performance thresholds, and do
|
|
||||||
not claim a stable benchmark JSON schema.
|
|
||||||
- The top-level catalog documents the current 10 suites and all suite-list
|
|
||||||
commands. Relative links to `benchmarks/README.md` resolve from the files
|
|
||||||
that introduce them.
|
|
||||||
- The runner preserves per-suite `run.py --list --json` behavior and adds root
|
|
||||||
`benchmarks/runner.py --suite-list` and `--suite-list --json` metadata.
|
|
||||||
- `scripts/release-gate.sh` now runs `cargo test --test
|
|
||||||
benchmark_suite_catalog_beta14` before the full compiler test suite.
|
|
||||||
- Cargo package version and lockfile version both read `1.0.0-beta.14`.
|
|
||||||
- Focused private/local publication text scan found no machine-local paths,
|
|
||||||
private checkout/user names, private remotes, or local IP text in the reviewed
|
|
||||||
release surface.
|
|
||||||
|
|
||||||
## Verification Commands And Results
|
|
||||||
|
|
||||||
- `python3 benchmarks/runner.py --suite-list --json`: passed. Output reported
|
|
||||||
`benchmark_count: 10`, `implementation_slots: 60`, status `ok`, cold/hot
|
|
||||||
timing modes, required scaffold-file status with no missing files, checksum
|
|
||||||
metadata, runtime args, implementation source paths, and the local-only
|
|
||||||
timing disclaimer.
|
|
||||||
- `python3 benchmarks/runner.py --suite-list`: passed.
|
|
||||||
- `python3 benchmarks/math-loop/run.py --list --json`: passed, confirming the
|
|
||||||
existing per-benchmark list mode still works through the shared runner.
|
|
||||||
- `python3 benchmarks/math-loop/run.py --suite-list --json`: passed, confirming
|
|
||||||
suite listing also resolves correctly through a per-benchmark wrapper.
|
|
||||||
- `cargo test --test benchmark_suite_catalog_beta14`: passed, 1 test.
|
|
||||||
- `cargo test --test benchmark_math_loop_scaffold`: passed, 1 test.
|
|
||||||
- `git diff --check`: passed.
|
|
||||||
- `git diff --check -- README.md benchmarks/README.md docs/POST_BETA_ROADMAP.md docs/language/SPEC-v1.md docs/language/ROADMAP.md docs/language/RELEASE_NOTES.md .llm/BETA_14_BENCHMARK_SUITE_CATALOG_AND_METADATA_GATE.md`:
|
|
||||||
passed.
|
|
||||||
- `bash -n scripts/release-gate.sh`: passed.
|
|
||||||
- `cargo fmt --check`: passed.
|
|
||||||
- Focused `rg` stale-current-stage scan for beta13 current release/stage wording
|
|
||||||
in the touched release docs produced no matches.
|
|
||||||
- Focused `rg` private/local publication text scan over README, docs,
|
|
||||||
benchmarks, `.llm`, compiler tests, and scripts produced no matches.
|
|
||||||
|
|
||||||
The full `./scripts/release-gate.sh` was not run during this review; the
|
|
||||||
focused beta14 gate coverage and requested lightweight checks passed.
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
# 1.0.0-beta.15 Release Review
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
- Ready for controller release gate. The beta15 candidate consistently scopes
|
|
||||||
this release as reserved generic collection boundary hardening plus a
|
|
||||||
collection ledger, without promoting executable generics, maps, sets,
|
|
||||||
generic stdlib dispatch, runtime names, ABI/layout, or stable API behavior.
|
|
||||||
- Evidence: the release contract preserves diagnostic shape/codes/schema while
|
|
||||||
allowing reserved-boundary prose rewording
|
|
||||||
(`.llm/BETA_15_RESERVED_GENERIC_COLLECTION_BOUNDARY_HARDENING.md:5`,
|
|
||||||
`.llm/BETA_15_RESERVED_GENERIC_COLLECTION_BOUNDARY_HARDENING.md:27`,
|
|
||||||
`.llm/BETA_15_RESERVED_GENERIC_COLLECTION_BOUNDARY_HARDENING.md:49`),
|
|
||||||
public docs describe the same boundary
|
|
||||||
(`README.md:86`, `docs/language/COLLECTIONS.md:12`,
|
|
||||||
`docs/language/COLLECTIONS.md:113`), and compiler docs mirror the
|
|
||||||
centralized-diagnostic scope (`docs/compiler/RELEASE_NOTES.md:28`,
|
|
||||||
`docs/compiler/ROADMAP.md:64`).
|
|
||||||
- Evidence: reserved diagnostic construction is centralized in
|
|
||||||
`compiler/src/reserved.rs:9`, `compiler/src/reserved.rs:62`,
|
|
||||||
`compiler/src/reserved.rs:77`, `compiler/src/reserved.rs:92`, and
|
|
||||||
`compiler/src/reserved.rs:107`; lowerer, formatter, and checker paths import
|
|
||||||
those helpers at `compiler/src/lower.rs:12`,
|
|
||||||
`compiler/src/formatter.rs:6`, and `compiler/src/check.rs:10`.
|
|
||||||
- Evidence: release gate wiring includes the focused beta15 test at
|
|
||||||
`scripts/release-gate.sh:68`, and the version bump is present in
|
|
||||||
`compiler/Cargo.toml:3` and `compiler/Cargo.lock:7`.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
- `cargo fmt --check`: passed.
|
|
||||||
- `cargo test --test reserved_generic_collection_beta15`: passed, 1 test.
|
|
||||||
- `cargo test --test diagnostics_contract`: passed, 1 test.
|
|
||||||
- `cargo test --test formatter`: passed, 16 tests.
|
|
||||||
- `cargo test --test project_mode`: passed, 36 tests.
|
|
||||||
- `rg -n "not supported in beta\\.9" compiler/src tests`: passed, no matches.
|
|
||||||
- `git diff --check`: passed.
|
|
||||||
|
|
||||||
Additional review scans:
|
|
||||||
|
|
||||||
- Current-stage stale beta14 scan across README/docs/.llm/Cargo metadata:
|
|
||||||
passed, no current-stage matches.
|
|
||||||
- Private/local publication text scan across README, docs, scripts, compiler
|
|
||||||
sources/tests, lib, examples, benchmarks, tests, and `.llm`: passed, no
|
|
||||||
matches.
|
|
||||||
|
|
||||||
## Residual Risk
|
|
||||||
|
|
||||||
Full release gate was not run by this reviewer because the requested scope was
|
|
||||||
focused review-only. Controller should still run `./scripts/release-gate.sh`
|
|
||||||
after accepting the candidate and before tagging/publishing.
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
# 1.0.0-beta.16 Release Review
|
|
||||||
|
|
||||||
Scope: `1.0.0-beta.16 String Scanning And Token Boundary Foundation`
|
|
||||||
|
|
||||||
Final verdict: ready for controller commit and final publication gate. I found no remaining blocking findings in the current worktree.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
Previously reported blockers are resolved:
|
|
||||||
|
|
||||||
- The unignored `promotion_gate_artifacts_are_aligned` stack overflow is fixed. The beta16 string runtime handlers are now extracted in `compiler/src/test_runner.rs` and dispatched from the runtime-symbol branch without re-entering the old recursive path in a way that overflows the vec_i32 import fixture.
|
|
||||||
- `.llm/BETA_16_STRING_SCANNING_AND_TOKEN_BOUNDARY_FOUNDATION.md` is now a combined Slovo/Glagol release scope rather than Slovo-side-only.
|
|
||||||
- `lib/std/README.md` now documents `byte_at_result`, `slice_result`, `starts_with`, `ends_with`, and the beta16 non-scope boundaries.
|
|
||||||
|
|
||||||
## Scope Confirmation
|
|
||||||
|
|
||||||
Confirmed: the beta16 candidate adds byte-oriented `std.string.byte_at_result`, `std.string.slice_result`, `std.string.starts_with`, and `std.string.ends_with`, with matching source facades, runtime entries, LLVM lowering, C runtime behavior, test-runner behavior, diagnostics inventory, examples, docs, release-gate coverage, and version bump.
|
|
||||||
|
|
||||||
Confirmed no beta16 claim for JSON parser, Unicode scalar/grapheme/display-width semantics, language-level slice/view syntax or borrowed substring views, generic collections, maps/sets, stable ABI/layout, stable stdlib/API freeze, tokenizers, object/array parsing, mutable strings, or performance claims. Matches for those terms are deferrals or explicit non-scope statements.
|
|
||||||
|
|
||||||
`docs/language/STDLIB_API.md` reflects the generated beta16 surface as 582 exported helper signatures total, with `std.string` at 30 exports including the four beta16 helpers.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
Passed:
|
|
||||||
|
|
||||||
- `cargo fmt --check`
|
|
||||||
- `cargo test --test standard_string_scanning_beta16`
|
|
||||||
- `cargo test --test diagnostics_contract`
|
|
||||||
- `cargo test --test standard_string_source_fallback_helpers_alpha`
|
|
||||||
- `cargo test --test standard_core_facade_source_search_alpha`
|
|
||||||
- `cargo test --test string_runtime`
|
|
||||||
- `cargo test --test promotion_gate -- --ignored`
|
|
||||||
- `cargo test --test promotion_gate promotion_gate_artifacts_are_aligned`
|
|
||||||
- `cargo test`
|
|
||||||
- `cargo test --test diagnostics_schema_beta13`
|
|
||||||
- `cargo test --test benchmark_suite_catalog_beta14`
|
|
||||||
- `cargo test --test reserved_generic_collection_beta15`
|
|
||||||
- `cargo test --test binary_smoke -- --ignored`
|
|
||||||
- `cargo test --test llvm_smoke -- --ignored`
|
|
||||||
- `bash -n scripts/install.sh`
|
|
||||||
- `bash -n scripts/render-stdlib-api-doc.sh`
|
|
||||||
- `scripts/render-stdlib-api-doc.sh`
|
|
||||||
- `git diff --check`
|
|
||||||
- stale current-stage beta15 scan
|
|
||||||
- local/private publication text scan across source/docs/tests/.llm
|
|
||||||
- required PDF artifact existence check
|
|
||||||
- `pdftotext` plus local/private publication text scan across required PDFs
|
|
||||||
|
|
||||||
Not run:
|
|
||||||
|
|
||||||
- Full `./scripts/release-gate.sh` before commit. The script intentionally requires the generated `docs/language/STDLIB_API.md` diff to already be committed, so running it on this dirty release candidate would produce a known false failure. Its cargo, shell syntax, generated-catalog, private-text, PDF, binary-smoke, and LLVM-smoke components were run manually above. Run the full script after committing beta16 and before tagging.
|
|
||||||
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
# 1.0.0-beta.17 Release Review
|
|
||||||
|
|
||||||
Scope: `1.0.0-beta.17 JSON Primitive Scalar Parsing Foundation`
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
Ready after controller follow-up. The source facade, runtime lowering,
|
|
||||||
test-runner behavior, examples, generated API catalog, focused gates, full
|
|
||||||
`cargo test`, and release diagnostics are coherent for the beta17 scope.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
### P2 - Resolved: unsupported standard-library diagnostics omitted the beta17 promoted JSON names
|
|
||||||
|
|
||||||
`compiler/src/std_runtime.rs:259` through `compiler/src/std_runtime.rs:299`
|
|
||||||
register the six promoted beta17 helpers:
|
|
||||||
|
|
||||||
- `std.json.parse_bool_value_result`
|
|
||||||
- `std.json.parse_i32_value_result`
|
|
||||||
- `std.json.parse_u32_value_result`
|
|
||||||
- `std.json.parse_i64_value_result`
|
|
||||||
- `std.json.parse_u64_value_result`
|
|
||||||
- `std.json.parse_f64_value_result`
|
|
||||||
|
|
||||||
`compiler/src/std_runtime.rs:875` hard-coded the
|
|
||||||
`UnsupportedStandardLibraryCall.expected` text with only
|
|
||||||
`std.json.quote_string` in the JSON family. A user who called an unsupported
|
|
||||||
`std.*` name would receive stale guidance that omitted the newly supported
|
|
||||||
beta17 helpers.
|
|
||||||
|
|
||||||
Controller resolution: the six beta17 `std.json.parse_*_value_result` names
|
|
||||||
are now present in the expected supported-call list, and
|
|
||||||
`compiler/tests/standard_json_scalar_parsing_beta17.rs` includes
|
|
||||||
`unsupported_json_diagnostics_list_beta17_promoted_scalar_parsers` to fail if
|
|
||||||
that user-facing guidance drifts again.
|
|
||||||
|
|
||||||
No P0/P1/P2 runtime, source-facade, grammar, lowering, diagnostics, or
|
|
||||||
release-gate wiring findings remain open.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
Inspected:
|
|
||||||
|
|
||||||
- `lib/std/json.slo` and both JSON example fixtures.
|
|
||||||
- `compiler/src/std_runtime.rs`, `compiler/src/llvm.rs`, and
|
|
||||||
`compiler/src/test_runner.rs`.
|
|
||||||
- `runtime/runtime.c`.
|
|
||||||
- `compiler/tests/standard_json_scalar_parsing_beta17.rs`,
|
|
||||||
`compiler/tests/standard_json_source_facade_alpha.rs`, and
|
|
||||||
`compiler/tests/promotion_gate.rs`.
|
|
||||||
- `scripts/release-gate.sh`, version bump, release notes, roadmaps, spec,
|
|
||||||
standard-runtime docs, and generated `docs/language/STDLIB_API.md`.
|
|
||||||
|
|
||||||
Ran:
|
|
||||||
|
|
||||||
- `git -C slovo diff --check` - passed.
|
|
||||||
- `cargo fmt --check` - passed.
|
|
||||||
- `cargo test --test standard_json_scalar_parsing_beta17` - passed, 5/5.
|
|
||||||
- `cargo test --test standard_json_source_facade_alpha` - passed, 2/2.
|
|
||||||
- `cargo test --test standard_json` - passed, 4/4.
|
|
||||||
- `cargo test --test diagnostics_contract` - passed, 1/1.
|
|
||||||
- `cargo test --test promotion_gate` - passed, 1/1 with 2 ignored.
|
|
||||||
- `cargo test --test promotion_gate -- --ignored` - passed, 2/2.
|
|
||||||
- `cargo test` - passed.
|
|
||||||
- Controller follow-up `cargo test --test standard_json_scalar_parsing_beta17`
|
|
||||||
- passed after the diagnostic inventory fix.
|
|
||||||
|
|
||||||
Not run:
|
|
||||||
|
|
||||||
- Full `./scripts/release-gate.sh`; run it after final controller cleanup. Its
|
|
||||||
core `cargo test`, fmt, promotion, and beta17-focused components were
|
|
||||||
covered above, but the full script also runs documentation/private-text
|
|
||||||
checks and ignored binary/LLVM smoke gates.
|
|
||||||
|
|
||||||
## Residual Risks And Non-Scope Confirmation
|
|
||||||
|
|
||||||
Confirmed in-scope behavior:
|
|
||||||
|
|
||||||
- `std.json.parse_bool_value_result`, numeric concrete
|
|
||||||
`parse_*_value_result` helpers, and source-only `parse_null_value_result`
|
|
||||||
are present in `lib/std/json.slo` and mirrored by the local JSON fixture.
|
|
||||||
- Promoted bool/numeric helpers lower to private runtime symbols and have
|
|
||||||
matching test-runner and hosted-runtime behavior.
|
|
||||||
- Primitive JSON token checks reject whitespace, leading `+`, leading-zero
|
|
||||||
forms such as `01`/`01.0`, negative unsigned integers, overflow, and
|
|
||||||
non-finite f64 results. Exponent f64 is accepted. `-0` is accepted
|
|
||||||
consistently as a JSON-valid number token, not treated as a leading-zero
|
|
||||||
form.
|
|
||||||
- `parse_null_value_result` remains source-only; no compiler-known null parser
|
|
||||||
was introduced.
|
|
||||||
|
|
||||||
Confirmed non-scope:
|
|
||||||
|
|
||||||
- No JSON string parser, object parser, array parser, recursive `JsonValue`,
|
|
||||||
tokenizer, schema validator, stream parser, Unicode escape parser, map/set
|
|
||||||
surface, stable ABI/layout claim, stable API freeze, or performance claim is
|
|
||||||
introduced by this candidate.
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
# Beta 18 Release Review: JSON String Token Parsing Foundation
|
|
||||||
|
|
||||||
Reviewer: beta18 release reviewer
|
|
||||||
Date: 2026-05-23
|
|
||||||
Repo: Slovo monorepo
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
### Blocking: unrelated test-runner stack wrapper drift is present in the beta18 worktree
|
|
||||||
|
|
||||||
- `compiler/src/main.rs:27`
|
|
||||||
- `compiler/src/main.rs:30`
|
|
||||||
- `compiler/src/main.rs:57`
|
|
||||||
|
|
||||||
The dirty worktree includes a broad `Mode::RunTests` execution change that imports
|
|
||||||
`std::thread`, defines a 16 MiB test-runner stack size, and runs every `glagol test`
|
|
||||||
invocation inside a spawned thread. That is not part of the documented beta18 JSON
|
|
||||||
string-token parsing scope and is not covered by the beta18 release notes, runtime
|
|
||||||
contract, `.llm/BETA_18_JSON_STRING_TOKEN_PARSING_FOUNDATION.md`, or a targeted test
|
|
||||||
that justifies changing CLI execution behavior.
|
|
||||||
|
|
||||||
This is release-blocking for beta18 as scoped. Either remove this drift from the
|
|
||||||
beta18 release, or promote it into an explicit separate scope with release notes,
|
|
||||||
docs, tests for panic/reporting behavior, and a clear reason for changing the
|
|
||||||
test-runner resource model.
|
|
||||||
|
|
||||||
## Non-Blocking Observations
|
|
||||||
|
|
||||||
- The JSON string-token parser surface is coherent across `lib/std/json.slo`,
|
|
||||||
`examples/projects/std-layout-local-json/src/json.slo`, compiler runtime
|
|
||||||
registration, LLVM lowering, test-runner emulation, hosted C runtime, generated
|
|
||||||
standard-library API docs, and source-facade examples.
|
|
||||||
- The promoted signature is consistently `(string) -> (result string i32)`.
|
|
||||||
- The documented contract is narrow and explicit: one isolated ASCII JSON string
|
|
||||||
token, exact quotes, simple JSON escapes, `err 1` for ordinary parse failure,
|
|
||||||
and deferred Unicode/full JSON parsing.
|
|
||||||
- `docs/compiler/RELEASE_NOTES.md:81` still says beta17 did not implement JSON
|
|
||||||
string parsing. That appears historical and scoped to the beta17 section, not a
|
|
||||||
stale beta18 claim.
|
|
||||||
|
|
||||||
## Verification Run
|
|
||||||
|
|
||||||
Passed:
|
|
||||||
|
|
||||||
- `cargo fmt --check`
|
|
||||||
- `cargo test --test standard_json_string_parsing_beta18`
|
|
||||||
- `cargo test --test standard_json_scalar_parsing_beta17`
|
|
||||||
- `cargo test --test standard_json_source_facade_alpha`
|
|
||||||
- `cargo test --test promotion_gate`
|
|
||||||
- `cargo test --test diagnostics_contract`
|
|
||||||
- `cargo test`
|
|
||||||
- `git diff --check`
|
|
||||||
- `git grep -nE '(/home/[[:alnum:]_.-]+|sanjin[0-9]+|[0-9]{1,3}\.64\.0\.1|git\.hermeticum\.io)' -- README.md CONTRIBUTING.md docs scripts compiler lib examples benchmarks tests .llm`
|
|
||||||
|
|
||||||
Not run:
|
|
||||||
|
|
||||||
- `./scripts/release-gate.sh`; the controller should run the full release gate
|
|
||||||
after resolving the blocking drift and committing generated docs/source changes,
|
|
||||||
because the gate intentionally checks generated `docs/language/STDLIB_API.md`,
|
|
||||||
ignored promotion gates, binary smoke, and LLVM smoke.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
Not release-ready yet because of the unrelated `compiler/src/main.rs` test-runner
|
|
||||||
stack wrapper drift. The beta18 JSON string-token parsing implementation itself did
|
|
||||||
not show blocking defects in this review, and the focused plus full Rust test stack
|
|
||||||
passed.
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# Beta 18 Release Review Disposition
|
|
||||||
|
|
||||||
Reviewer file: `.llm/reviews/BETA_18_RELEASE_REVIEW.md`
|
|
||||||
|
|
||||||
## Blocking Finding Disposition
|
|
||||||
|
|
||||||
The reviewer correctly flagged `compiler/src/main.rs` test-runner stack/thread
|
|
||||||
hardening as release drift while it was undocumented. The controller kept the
|
|
||||||
change because `cargo test --test promotion_gate` reproduced a host stack
|
|
||||||
overflow in `std-layout-local-vec_i32` without it, making the release gate
|
|
||||||
unreliable.
|
|
||||||
|
|
||||||
Resolution:
|
|
||||||
|
|
||||||
- `docs/compiler/RELEASE_NOTES.md` now lists the bounded worker-stack behavior
|
|
||||||
in the `1.0.0-beta.18` summary.
|
|
||||||
- `docs/compiler/ROADMAP.md` now records the same behavior as beta18
|
|
||||||
test-runner hardening.
|
|
||||||
- `.llm/BETA_18_JSON_STRING_TOKEN_PARSING_FOUNDATION.md` now marks it as
|
|
||||||
gate-supporting compiler hardening, not a new language feature.
|
|
||||||
- `cargo test --test promotion_gate` passes after the fix and failed with host
|
|
||||||
stack overflow before the fix.
|
|
||||||
|
|
||||||
Verdict after disposition: release may proceed if the full gate stack passes.
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
# 1.0.0-beta.19 Release Review
|
|
||||||
|
|
||||||
Scope: Test Discovery And User-Project Conformance Foundation
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
The implementation matches the beta19 contract at the release-blocking level:
|
|
||||||
`glagol test --list <file|project|workspace>` and legacy
|
|
||||||
`glagol --run-tests --list <file>` route through checked discovery, avoid test
|
|
||||||
body evaluation, preserve the existing discovery ordering, honor
|
|
||||||
`--filter <substring>`, keep ordinary test output unchanged, and are wired into
|
|
||||||
the release gate through `cargo test --test test_discovery_beta19`.
|
|
||||||
|
|
||||||
## Non-Blocking Notes
|
|
||||||
|
|
||||||
- Resolved during controller integration: unfiltered list output now prints the
|
|
||||||
same summary suffix as filtered list output, including `total_discovered`,
|
|
||||||
`selected`, `passed`, `failed`, `skipped`, and `filter none`.
|
|
||||||
- Resolved during controller integration: the grammar typo in
|
|
||||||
`docs/POST_BETA_ROADMAP.md` was corrected.
|
|
||||||
|
|
||||||
## Verification Notes
|
|
||||||
|
|
||||||
Inspected:
|
|
||||||
|
|
||||||
- Working tree status and beta19 diff across CLI parsing/dispatch, project test
|
|
||||||
mode, test-runner listing, focused tests, docs, version files, and
|
|
||||||
`scripts/release-gate.sh`.
|
|
||||||
- Contract drift against
|
|
||||||
`.llm/BETA_19_TEST_DISCOVERY_AND_CONFORMANCE.md`,
|
|
||||||
`docs/language/SPEC-v1.md`, release notes, roadmaps, and README beta scope.
|
|
||||||
- Cached diff status; no cached beta19 changes were present.
|
|
||||||
|
|
||||||
Read-only checks run:
|
|
||||||
|
|
||||||
- `git diff --check` - passed.
|
|
||||||
- `git diff --cached --check` - passed.
|
|
||||||
- Stale-version scan for beta18/beta19 references - no blocking stale current
|
|
||||||
release references found.
|
|
||||||
- Conflict-marker and trailing-whitespace scans for the untracked beta19
|
|
||||||
contract/test files - passed.
|
|
||||||
|
|
||||||
Not run:
|
|
||||||
|
|
||||||
- `cargo fmt --check`, focused cargo tests, full `cargo test`, and
|
|
||||||
`./scripts/release-gate.sh`; those commands write build artifacts, and this
|
|
||||||
review was constrained to read-only commands except for the review file.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
Release-ready from this review. No blocking beta19 issues remain in the current
|
|
||||||
working tree diff. The controller should still run the focused beta19 test suite
|
|
||||||
and full release gate before tagging.
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
# 1.0.0-beta.20 Release Review
|
|
||||||
|
|
||||||
Scope: String Search And ASCII Trim Foundation
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
The beta20 diff matches the documented release contract at the
|
|
||||||
release-blocking level. `lib/std/string.slo:1` exports all six new helpers, and
|
|
||||||
the implementations remain ordinary source helpers over the existing string
|
|
||||||
facade primitives: first search at `lib/std/string.slo:30`, last search at
|
|
||||||
`lib/std/string.slo:47`, `contains` at `lib/std/string.slo:64`, and ASCII trim
|
|
||||||
at `lib/std/string.slo:71`. The local mirror in
|
|
||||||
`examples/projects/std-layout-local-string/src/string.slo:1` exposes the same
|
|
||||||
surface without changing the public contract shape.
|
|
||||||
|
|
||||||
The example coverage is explicit and scoped correctly. The standard import
|
|
||||||
example covers present, missing, empty-needle, first/last index, leading trim,
|
|
||||||
trailing trim, full trim, all-whitespace trim, and no-trim cases at
|
|
||||||
`examples/projects/std-import-string/src/main.slo:204`; the documentation copy
|
|
||||||
matches at `docs/language/examples/projects/std-import-string/src/main.slo:204`;
|
|
||||||
the local fixture mirrors the same behavior at
|
|
||||||
`examples/projects/std-layout-local-string/src/main.slo:204`.
|
|
||||||
|
|
||||||
The compiler gate coverage is aligned with the non-scope. The focused beta20
|
|
||||||
test builds an explicit `std.string` import fixture at
|
|
||||||
`compiler/tests/standard_string_search_trim_beta20.rs:47`, asserts the helpers
|
|
||||||
are source-authored at `compiler/tests/standard_string_search_trim_beta20.rs:178`,
|
|
||||||
and rejects direct compiler-known runtime calls for the new names. The existing
|
|
||||||
local-string fallback test now expects and inventories the new helpers at
|
|
||||||
`compiler/tests/standard_string_source_fallback_helpers_alpha.rs:8` and
|
|
||||||
`compiler/tests/standard_string_source_fallback_helpers_alpha.rs:24`.
|
|
||||||
The repo-root standard-source import gate and promotion gate are also aligned at
|
|
||||||
`compiler/tests/standard_core_facade_source_search_alpha.rs:8`,
|
|
||||||
`compiler/tests/standard_core_facade_source_search_alpha.rs:33`,
|
|
||||||
`compiler/tests/promotion_gate.rs:1318`, and
|
|
||||||
`compiler/tests/promotion_gate.rs:7368`.
|
|
||||||
|
|
||||||
## Contract Drift
|
|
||||||
|
|
||||||
No blocking contract drift found.
|
|
||||||
|
|
||||||
The README, language release notes, language roadmap, v1 spec, compiler release
|
|
||||||
notes, compiler roadmap, post-beta roadmap, stdlib README, and beta20 `.llm`
|
|
||||||
contract all describe the same narrow surface: byte-oriented search, empty
|
|
||||||
needle behavior, ASCII-only trimming over bytes `9`, `10`, `11`, `12`, `13`,
|
|
||||||
and `32`, no new compiler-known runtime names, no runtime C work, no new source
|
|
||||||
syntax, and no Unicode, regex, tokenizer, mutable-string, stable ABI/layout, or
|
|
||||||
stable stdlib/API claims. Representative anchors: `README.md:144`,
|
|
||||||
`docs/language/RELEASE_NOTES.md:39`, `docs/language/ROADMAP.md:80`,
|
|
||||||
`docs/language/SPEC-v1.md:232`, `docs/compiler/RELEASE_NOTES.md:15`,
|
|
||||||
`docs/compiler/ROADMAP.md:100`, `docs/POST_BETA_ROADMAP.md:111`,
|
|
||||||
`lib/std/README.md:233`, and
|
|
||||||
`.llm/BETA_20_STRING_SEARCH_AND_ASCII_TRIM_FOUNDATION.md:1`.
|
|
||||||
|
|
||||||
The version and generated catalog updates are coherent: `compiler/Cargo.toml:3`
|
|
||||||
and `compiler/Cargo.lock` are bumped to `1.0.0-beta.20`,
|
|
||||||
`docs/language/STDLIB_API.md:18` reports 596 exported signatures, and
|
|
||||||
`docs/language/STDLIB_API.md:486` lists 36 `std.string` signatures including
|
|
||||||
the six beta20 helpers. `scripts/release-gate.sh:73` wires the focused beta20
|
|
||||||
test into the release gate.
|
|
||||||
|
|
||||||
## Verification Notes
|
|
||||||
|
|
||||||
Inspected:
|
|
||||||
|
|
||||||
- Working tree diff and untracked beta20 contract/test files for std source,
|
|
||||||
explicit std/local examples, docs, compiler tests, generated catalog, version
|
|
||||||
bump, and release-gate integration.
|
|
||||||
- Contract drift against README, language roadmap/spec/release notes, compiler
|
|
||||||
roadmap/release notes, post-beta roadmap, stdlib README, and the beta20 `.llm`
|
|
||||||
contract.
|
|
||||||
- Sibling `glagol` repository status; no sibling worktree changes were present.
|
|
||||||
|
|
||||||
Read-only checks run:
|
|
||||||
|
|
||||||
- `git diff --check` - passed.
|
|
||||||
- `git diff --cached --check` - passed.
|
|
||||||
- `bash -n scripts/release-gate.sh` - passed.
|
|
||||||
- `cargo fmt --check --manifest-path compiler/Cargo.toml` - passed.
|
|
||||||
- Local/private publication text scan over source/docs/tests/.llm with build
|
|
||||||
artifacts excluded - passed.
|
|
||||||
|
|
||||||
Not run:
|
|
||||||
|
|
||||||
- Focused cargo tests, full `cargo test`, and `./scripts/release-gate.sh`.
|
|
||||||
Those commands write build/generated artifacts, and this review was
|
|
||||||
constrained to read-only commands except for the review file.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
Release-ready from this review. No blocking beta20 issues remain in the current
|
|
||||||
working tree diff. The controller should still run the focused beta20 test stack
|
|
||||||
and full release gate before tagging.
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
# 1.0.0-beta.21 Glagol Implementation Notes
|
|
||||||
|
|
||||||
Scope: JSON Document Scalar Parsing Foundation.
|
|
||||||
|
|
||||||
This Glagol-side slice prepares compiler/test/release-gate coverage for the
|
|
||||||
source-authored `std.json` document scalar helpers:
|
|
||||||
|
|
||||||
- `parse_string_document_result`
|
|
||||||
- `parse_bool_document_result`
|
|
||||||
- `parse_i32_document_result`
|
|
||||||
- `parse_u32_document_result`
|
|
||||||
- `parse_i64_document_result`
|
|
||||||
- `parse_u64_document_result`
|
|
||||||
- `parse_f64_document_result`
|
|
||||||
- `parse_null_document_result`
|
|
||||||
|
|
||||||
The focused beta21 test uses an explicit `std.json` import, checks/formats/tests
|
|
||||||
the imported helpers, requires the helpers to exist in `lib/std/json.slo`, and
|
|
||||||
asserts that no `std.json.parse_*_document_result` compiler-known calls or
|
|
||||||
private `__glagol_json_*document*` runtime symbols are introduced.
|
|
||||||
|
|
||||||
The JSON source-facade and promotion-gate inventories are updated to match the
|
|
||||||
Slovo-side source/export/example work, which adds three JSON document scalar
|
|
||||||
fixture tests and raises local and explicit `std.json` fixture output from 9 to
|
|
||||||
12 tests.
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
# 1.0.0-beta.21 Release Review
|
|
||||||
|
|
||||||
Scope: JSON Document Scalar Parsing Foundation.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking findings.
|
|
||||||
|
|
||||||
The uncommitted beta21 candidate matches the release contract:
|
|
||||||
|
|
||||||
- `lib/std/json.slo` exports all eight source-authored
|
|
||||||
`parse_*_document_result` helpers.
|
|
||||||
- Each document helper trims the whole input with `trim_ascii`, then delegates
|
|
||||||
to the existing exact scalar value-token parser for the matching family.
|
|
||||||
- Direct compiler-known `std.json.parse_*_document_result` calls are not
|
|
||||||
introduced, and no private `__glagol_json_*document*` runtime symbol is
|
|
||||||
introduced.
|
|
||||||
- The explicit `std.json` example imports repo-root `std.json` and covers
|
|
||||||
trimmed success, plain success, trailing non-whitespace failure, scalar
|
|
||||||
token parsing, fields, arrays, objects, and 12 tests.
|
|
||||||
- The local JSON example imports local `json`, the local `json` fixture imports
|
|
||||||
local `string (trim_ascii)`, and it mirrors the same 12-test coverage.
|
|
||||||
- Compiler coverage includes the focused beta21 test, JSON facade inventory,
|
|
||||||
promotion-gate alignment, release-gate wiring, package version bump, and the
|
|
||||||
generated standard-library API catalog signatures.
|
|
||||||
- Release docs describe `1.0.0-beta.21` as released, and the source/docs scan
|
|
||||||
did not find local/private publication text.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
Commands run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git diff --check
|
|
||||||
git diff --cached --check
|
|
||||||
bash -n scripts/release-gate.sh
|
|
||||||
cargo fmt --check --manifest-path compiler/Cargo.toml
|
|
||||||
cargo test --test standard_json_document_scalar_parsing_beta21
|
|
||||||
cargo test --test standard_json_source_facade_alpha
|
|
||||||
cargo test --test promotion_gate -- promotion_gate_artifacts_are_aligned
|
|
||||||
```
|
|
||||||
|
|
||||||
Results:
|
|
||||||
|
|
||||||
- `standard_json_document_scalar_parsing_beta21`: 2 passed.
|
|
||||||
- `standard_json_source_facade_alpha`: 2 passed.
|
|
||||||
- `promotion_gate_artifacts_are_aligned`: 1 passed.
|
|
||||||
- Formatting, shell syntax, and diff whitespace checks passed.
|
|
||||||
- Targeted stale-release/private-text scans over source/docs paths passed.
|
|
||||||
|
|
||||||
Not run by design for this review: full `cargo test`, ignored smoke tests, and
|
|
||||||
the full release gate.
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
# Beta22 Release Review
|
|
||||||
|
|
||||||
Verdict: PASS with notes.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking or non-blocking findings in the reviewed scope.
|
|
||||||
|
|
||||||
## Scope Reviewed
|
|
||||||
|
|
||||||
- `compiler/src/main.rs` run manifest rendering and exit behavior.
|
|
||||||
- `compiler/tests/run_manifest_beta22.rs` focused coverage.
|
|
||||||
- `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md` beta22 contract and suggested gates.
|
|
||||||
- `README.md`, `docs/compiler/RELEASE_NOTES.md`, `docs/compiler/ROADMAP.md`, `docs/language/RELEASE_NOTES.md`, `docs/language/ROADMAP.md`, and `docs/language/SPEC-v1.md` release claims.
|
|
||||||
- `scripts/release-gate.sh` inclusion.
|
|
||||||
|
|
||||||
## Acceptance Checklist
|
|
||||||
|
|
||||||
- PASS: `glagol run --manifest <path>` writes additive run execution evidence after a supported program executes. The run path captures child stdout/stderr/status before manifest rendering and exits with the child status in `compiler/src/main.rs:892` through `compiler/src/main.rs:918`; rendering emits `(run-report ...)` in `compiler/src/main.rs:2162` through `compiler/src/main.rs:2188`.
|
|
||||||
- PASS: Run-report records exit status, captured stdout, captured stderr, and forwarded args. Tests cover success stdout and args in `compiler/tests/run_manifest_beta22.rs:10` through `compiler/tests/run_manifest_beta22.rs:60`, and nonzero exit plus stderr preservation in `compiler/tests/run_manifest_beta22.rs:62` through `compiler/tests/run_manifest_beta22.rs:128`.
|
|
||||||
- PASS: Existing manifest fields and schema/version markers remain compatible. The new path passes `Some(run_report)` only through the run-specific wrapper in `compiler/src/main.rs:2019` through `compiler/src/main.rs:2043`; the renderer still emits `slovo.artifact-manifest` version `1` in `compiler/src/main.rs:2067` through `compiler/src/main.rs:2069`.
|
|
||||||
- PASS: Source failures do not receive fake run evidence. The focused test asserts no run-report for a type failure in `compiler/tests/run_manifest_beta22.rs:130` through `compiler/tests/run_manifest_beta22.rs:161`.
|
|
||||||
- PASS: Non-run modes are outside the run-report requirement. Existing foreign-import/project manifest wrappers pass `None` for the run-report slot in `compiler/src/main.rs:1992` through `compiler/src/main.rs:2017`; beta22 docs state this explicitly in `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:58` and `docs/compiler/RELEASE_NOTES.md:35`.
|
|
||||||
- PASS: Documentation does not overclaim language, stdlib, runtime, package, ABI, or stable manifest-schema changes. Representative deferrals are present in `README.md:172` through `README.md:178`, `docs/compiler/ROADMAP.md:118` through `docs/compiler/ROADMAP.md:124`, `docs/language/RELEASE_NOTES.md:52` through `docs/language/RELEASE_NOTES.md:62`, `docs/language/ROADMAP.md:99` through `docs/language/ROADMAP.md:106`, and `docs/language/SPEC-v1.md:260` through `docs/language/SPEC-v1.md:267`.
|
|
||||||
- PASS: The beta22 contract suggested gate names match the implemented focused test and release gate. `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:63` through `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:71` lists `cargo test --test run_manifest_beta22`; `scripts/release-gate.sh:75` includes the same focused test.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
Ran:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo test --test run_manifest_beta22
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: passed, 3 tests passed.
|
|
||||||
|
|
||||||
Recommended before release tag:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --check
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
git diff --check
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: the focused hosted-run tests depend on Clang discovery, matching existing project patterns. In this local run they executed and passed rather than skipping.
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
# Beta23 Release Review
|
|
||||||
|
|
||||||
Verdict: PASS with notes.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking or non-blocking findings in the reviewed scope.
|
|
||||||
|
|
||||||
## Scope Reviewed
|
|
||||||
|
|
||||||
- `scripts/render-stdlib-api-doc.js` tier rendering.
|
|
||||||
- `scripts/check-stdlib-api-tiers.js` tier gate.
|
|
||||||
- `scripts/release-gate.sh` integration.
|
|
||||||
- Generated `docs/language/STDLIB_API.md`.
|
|
||||||
- `docs/language/STDLIB_TIERS.md`, README, release notes, roadmaps, and spec updates.
|
|
||||||
- Compiler package version bump and compiler release documentation.
|
|
||||||
|
|
||||||
## Acceptance Checklist
|
|
||||||
|
|
||||||
- PASS: `docs/language/STDLIB_TIERS.md` defines the public tier labels and explains the current beta meaning. See `docs/language/STDLIB_TIERS.md:21` through `docs/language/STDLIB_TIERS.md:25`.
|
|
||||||
- PASS: The tier ledger marks JSON, loopback networking, random/time, and filesystem resource-handle helpers as experimental domains. See `docs/language/STDLIB_TIERS.md:46` through `docs/language/STDLIB_TIERS.md:49`.
|
|
||||||
- PASS: The tier ledger records concrete vector modules as beta-supported concrete lanes without claiming generic collection stability. See `docs/language/STDLIB_TIERS.md:44`.
|
|
||||||
- PASS: The generated API catalog emits tier metadata and summary counts. See `docs/language/STDLIB_API.md:6` through `docs/language/STDLIB_API.md:24`.
|
|
||||||
- PASS: Generated catalog classification matches the beta23 contract: filesystem handle helpers are experimental in `docs/language/STDLIB_API.md:115` through `docs/language/STDLIB_API.md:119`; `std.json`, `std.net`, `std.random`, and `std.time` are experimental in `docs/language/STDLIB_API.md:195` through `docs/language/STDLIB_API.md:240`, `docs/language/STDLIB_API.md:294` through `docs/language/STDLIB_API.md:308`, `docs/language/STDLIB_API.md:425` through `docs/language/STDLIB_API.md:432`, and `docs/language/STDLIB_API.md:540` through `docs/language/STDLIB_API.md:547`.
|
|
||||||
- PASS: Concrete vector modules retain explicit no-generic-collection-freeze notes in generated output. Representative coverage is `docs/language/STDLIB_API.md:549` through `docs/language/STDLIB_API.md:554`, with the same note repeated for the other concrete `std.vec_*` modules.
|
|
||||||
- PASS: The renderer implements the tier map and emits per-module/per-helper tiers. See `scripts/render-stdlib-api-doc.js:12` through `scripts/render-stdlib-api-doc.js:46`, `scripts/render-stdlib-api-doc.js:245` through `scripts/render-stdlib-api-doc.js:263`, and `scripts/render-stdlib-api-doc.js:297` through `scripts/render-stdlib-api-doc.js:330`.
|
|
||||||
- PASS: The tier gate checks stale wording, summary tier definitions, experimental module/helper coverage, and vector boundary notes. See `scripts/check-stdlib-api-tiers.js:47` through `scripts/check-stdlib-api-tiers.js:80`.
|
|
||||||
- PASS: `scripts/release-gate.sh` runs syntax checks for both tier scripts and executes the tier checker after catalog rendering. See `scripts/release-gate.sh:12` through `scripts/release-gate.sh:16`.
|
|
||||||
- PASS: README, `lib/std/README.md`, language release notes, language roadmap, post-beta roadmap, and v1 spec link or describe the tier ledger and non-scope. Representative references: `README.md:69` through `README.md:79`, `lib/std/README.md:174` through `lib/std/README.md:184`, `docs/language/RELEASE_NOTES.md:53` through `docs/language/RELEASE_NOTES.md:69`, `docs/language/ROADMAP.md:109` through `docs/language/ROADMAP.md:119`, `docs/POST_BETA_ROADMAP.md:121` through `docs/POST_BETA_ROADMAP.md:132`, and `docs/language/SPEC-v1.md:268` through `docs/language/SPEC-v1.md:279`.
|
|
||||||
- PASS: Documentation states beta23 is documentation/catalog tooling clarity only and does not add language, stdlib, runtime, stable schema, ABI/layout, or stable API behavior. See `docs/language/STDLIB_TIERS.md:10` through `docs/language/STDLIB_TIERS.md:15` and `docs/language/STDLIB_TIERS.md:52` through `docs/language/STDLIB_TIERS.md:68`.
|
|
||||||
- PASS: Compiler package version and compiler release docs are aligned to `1.0.0-beta.23`. See `compiler/Cargo.toml:3`, `compiler/Cargo.lock:7`, `docs/compiler/RELEASE_NOTES.md:15` through `docs/compiler/RELEASE_NOTES.md:43`, and `docs/compiler/ROADMAP.md:126` through `docs/compiler/ROADMAP.md:132`.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
Ran:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node --check scripts/render-stdlib-api-doc.js
|
|
||||||
node --check scripts/check-stdlib-api-tiers.js
|
|
||||||
./scripts/check-stdlib-api-tiers.js
|
|
||||||
git diff --check
|
|
||||||
rg -n '^- `experimental`' docs/language/STDLIB_API.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: all focused checks passed. The `rg` inspection confirmed 58 experimental helper signatures across the expected filesystem-handle, JSON, loopback networking, random, and time surfaces.
|
|
||||||
|
|
||||||
Recommended before release tag:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/render-stdlib-api-doc.sh
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: run the full release gate after the generated catalog changes are staged or committed; the gate intentionally fails if `docs/language/STDLIB_API.md` has unstaged generated-doc drift.
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
# Beta24 Release Review
|
|
||||||
|
|
||||||
Verdict: PASS.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking or non-blocking findings in the reviewed scope.
|
|
||||||
|
|
||||||
## Scope Reviewed
|
|
||||||
|
|
||||||
- `compiler/src/project.rs` package manifest diagnostics.
|
|
||||||
- `compiler/tests/package_workspace_discipline_beta24.rs`.
|
|
||||||
- `scripts/release-gate.sh` beta24 focused gate entry.
|
|
||||||
- `compiler/Cargo.toml` and `compiler/Cargo.lock` version bump.
|
|
||||||
- `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md`.
|
|
||||||
- README, language package/diagnostic/release/roadmap docs, compiler release/roadmap docs, and post-beta roadmap updates.
|
|
||||||
|
|
||||||
## Acceptance Checklist
|
|
||||||
|
|
||||||
- PASS: Duplicate package manifest keys now use package-scoped diagnostics through `set_manifest_key(..., "PackageManifestInvalid", "package")` for package identity keys. See `compiler/src/project.rs:1505` through `compiler/src/project.rs:1545` and `compiler/src/project.rs:1752` through `compiler/src/project.rs:1771`.
|
|
||||||
- PASS: Invalid dependency keys are rejected before graph validation with `InvalidPackageDependencyName`. See `compiler/src/project.rs:1556` through `compiler/src/project.rs:1572`.
|
|
||||||
- PASS: Duplicate dependency keys are rejected before graph validation with `DuplicatePackageDependencyName`, and invalid/duplicate dependency records are not added to the dependency graph. See `compiler/src/project.rs:1573` through `compiler/src/project.rs:1593`.
|
|
||||||
- PASS: Existing local-path-only dependency parsing and later dependency key/name matching remain in place. See `compiler/src/project.rs:1594` through `compiler/src/project.rs:1601`, `compiler/src/project.rs:1743` through `compiler/src/project.rs:1749`, and `compiler/src/project.rs:2970` through `compiler/src/project.rs:3005`.
|
|
||||||
- PASS: Focused tests cover duplicate package keys, invalid dependency keys, duplicate dependency keys, and a clean local dependency workspace. See `compiler/tests/package_workspace_discipline_beta24.rs:11` through `compiler/tests/package_workspace_discipline_beta24.rs:109`.
|
|
||||||
- PASS: `scripts/release-gate.sh` runs the beta24 focused test before full `cargo test`. See `scripts/release-gate.sh:68` through `scripts/release-gate.sh:82`.
|
|
||||||
- PASS: The compiler package version is aligned to `1.0.0-beta.24` in both Cargo files. See `compiler/Cargo.toml:3` and `compiler/Cargo.lock:7`.
|
|
||||||
- PASS: The beta24 contract defines diagnostics-only scope, explicit non-scope, acceptance criteria, and focused gates. See `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md:5` through `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md:79`.
|
|
||||||
- PASS: README identifies `1.0.0-beta.24` as current and describes the package manifest/dependency diagnostic hardening scope without claiming package-manager, runtime, language, or stdlib changes. See `README.md:9` and `README.md:27` through `README.md:50`.
|
|
||||||
- PASS: `docs/language/PACKAGES.md` documents duplicate package manifest keys, invalid dependency keys, and duplicate dependency keys as beta package/workspace diagnostics. See `docs/language/PACKAGES.md:59` through `docs/language/PACKAGES.md:73` and `docs/language/PACKAGES.md:111` through `docs/language/PACKAGES.md:130`.
|
|
||||||
- PASS: `docs/language/DIAGNOSTICS.md` includes the new package/workspace diagnostic codes in the project/workspace catalog. See `docs/language/DIAGNOSTICS.md:240` through `docs/language/DIAGNOSTICS.md:279`.
|
|
||||||
- PASS: Language and compiler release notes describe beta24 as package manifest identity/dependency diagnostic hardening only. See `docs/language/RELEASE_NOTES.md:44` through `docs/language/RELEASE_NOTES.md:68` and `docs/compiler/RELEASE_NOTES.md:15` through `docs/compiler/RELEASE_NOTES.md:42`.
|
|
||||||
- PASS: Language/compiler roadmaps and post-beta roadmap mark beta24 as the current local package/workspace diagnostics slice with registry, lockfile, semver, publishing, optional/dev/target dependencies, ABI/layout, language, runtime, and stdlib work deferred. See `docs/language/ROADMAP.md:11` through `docs/language/ROADMAP.md:33`, `docs/compiler/ROADMAP.md:24` through `docs/compiler/ROADMAP.md:38`, `docs/compiler/ROADMAP.md:722` through `docs/compiler/ROADMAP.md:728`, and `docs/POST_BETA_ROADMAP.md:185` through `docs/POST_BETA_ROADMAP.md:191`.
|
|
||||||
|
|
||||||
## Verification Commands
|
|
||||||
|
|
||||||
Ran:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git diff --check
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test package_workspace_discipline_beta24
|
|
||||||
cargo test --test project_mode workspace_package_boundaries_are_diagnostics
|
|
||||||
cargo test --test project_mode
|
|
||||||
rg -n "beta\\.23|beta23|beta\\.24|beta24|1\\.0\\.0-beta\\.2[0-9]|current|Release state|Last updated" README.md docs/language/PACKAGES.md docs/language/DIAGNOSTICS.md docs/language/RELEASE_NOTES.md docs/language/ROADMAP.md docs/compiler/RELEASE_NOTES.md docs/compiler/ROADMAP.md docs/POST_BETA_ROADMAP.md .llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md compiler/Cargo.toml compiler/Cargo.lock scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: all executed checks passed. The focused beta24 test reported 4 passed tests. The full `project_mode` suite reported 36 passed tests.
|
|
||||||
|
|
||||||
## Final Gate Disposition
|
|
||||||
|
|
||||||
After this review, the controller ran the full release gate:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: PASS. The gate completed docs/catalog checks, focused beta13-beta24
|
|
||||||
tests, full `cargo test`, ignored promotion smoke, ignored binary smoke, and
|
|
||||||
ignored LLVM smoke.
|
|
||||||
|
|
||||||
## Residual Risks
|
|
||||||
|
|
||||||
- No release-blocking residual risks remain. The release gate regenerated and
|
|
||||||
checked the standard-library API catalog; publication PDFs were not
|
|
||||||
regenerated because this slice does not touch paper sources, and the gate
|
|
||||||
verified that the required PDF artifacts are present.
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
# Beta25 Release Review
|
|
||||||
|
|
||||||
Verdict: PASS.
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
No blocking or non-blocking findings in the re-reviewed scope.
|
|
||||||
|
|
||||||
The prior blocking finding is resolved. `compiler/tests/user_project_conformance_beta25.rs` now covers all 43 top-level fixture roots currently discovered under `examples/projects/` and `examples/workspaces/`: 41 project fixtures plus 2 workspace fixtures. The test also asserts the matrix length, total discovered-test count, sorted path order, and exact inventory completeness against discovered top-level `slovo.toml` fixture roots.
|
|
||||||
|
|
||||||
## Acceptance Checklist
|
|
||||||
|
|
||||||
- PASS: The conformance matrix covers every current top-level `slovo.toml` fixture root under `examples/projects/` and `examples/workspaces/`.
|
|
||||||
- PASS: `assert_matrix_inventory()` asserts the 43-root count, 655 discovered tests, sorted repository-relative path order, exact discovered fixture inventory, and the full expected path/test/run matrix.
|
|
||||||
- PASS: The test runs `glagol check`, `glagol test --list`, and stable `glagol test` for every matrix entry.
|
|
||||||
- PASS: Deterministic env fixture handling is wired through `configure_conformance_env()`: expected env variables are set to stable values and intentionally-missing env variables are removed before each Glagol command.
|
|
||||||
- PASS: `scripts/release-gate.sh` still runs `cargo test --test user_project_conformance_beta25`.
|
|
||||||
- PASS: `compiler/Cargo.toml` and `compiler/Cargo.lock` both version `glagol` as `1.0.0-beta.25`.
|
|
||||||
- PASS: README, release notes, roadmaps, and the beta25 matrix doc continue to frame the release as tooling/conformance evidence without claiming language, runtime, stdlib, package-manager, stable-schema, ABI/layout, or performance changes.
|
|
||||||
|
|
||||||
## Verification Commands
|
|
||||||
|
|
||||||
Ran:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status --short
|
|
||||||
git diff --stat
|
|
||||||
sed -n '1,620p' compiler/tests/user_project_conformance_beta25.rs
|
|
||||||
find examples/projects -mindepth 2 -maxdepth 2 -name slovo.toml -printf '%h\n'
|
|
||||||
find examples/workspaces -mindepth 2 -maxdepth 2 -name slovo.toml -printf '%h\n'
|
|
||||||
find examples/projects -mindepth 2 -maxdepth 2 -name slovo.toml -printf '.' | wc -c
|
|
||||||
find examples/workspaces -mindepth 2 -maxdepth 2 -name slovo.toml -printf '.' | wc -c
|
|
||||||
rg -n "assert_eq!\(MATRIX\.len\(\), 43|discover_fixture_paths|configure_conformance_env|GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT|GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT" compiler/tests/user_project_conformance_beta25.rs
|
|
||||||
git diff --check
|
|
||||||
cargo fmt --check
|
|
||||||
cargo test --test user_project_conformance_beta25
|
|
||||||
```
|
|
||||||
|
|
||||||
Results:
|
|
||||||
|
|
||||||
- `git diff --check`: PASS.
|
|
||||||
- `cargo fmt --check`: PASS.
|
|
||||||
- `cargo test --test user_project_conformance_beta25`: PASS, 1 test passed.
|
|
||||||
- Fixture inventory counts: 41 top-level project roots and 2 top-level workspace roots.
|
|
||||||
- Matrix inventory assertion: covers 43 roots and 655 discovered tests.
|
|
||||||
|
|
||||||
## Residual Risks
|
|
||||||
|
|
||||||
No release-blocking residual risks remain for this slice.
|
|
||||||
|
|
||||||
## Final Gate Disposition
|
|
||||||
|
|
||||||
The controller reran the full release gate after staging the generated
|
|
||||||
`docs/language/STDLIB_API.md` beta25 catalog update:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/release-gate.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: PASS. The gate reported:
|
|
||||||
|
|
||||||
```text
|
|
||||||
release gate passed: docs, stdlib API catalog, fmt, tests, promotion, binary, and LLVM smoke checks completed
|
|
||||||
```
|
|
||||||
386
README.md
386
README.md
@ -6,7 +6,7 @@ This repository is the canonical public monorepo for the language design,
|
|||||||
standard library source, compiler, runtime, examples, benchmarks, and technical
|
standard library source, compiler, runtime, examples, benchmarks, and technical
|
||||||
documents.
|
documents.
|
||||||
|
|
||||||
Current release: `1.0.0-beta.25`.
|
Current release: `1.0.0-beta.10`.
|
||||||
|
|
||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
@ -24,34 +24,17 @@ scripts/ local release and document tooling
|
|||||||
|
|
||||||
## Beta Scope
|
## Beta Scope
|
||||||
|
|
||||||
`1.0.0-beta.25` keeps the `1.0.0-beta` language baseline, includes the
|
`1.0.0-beta.10` keeps the `1.0.0-beta` language baseline, includes the
|
||||||
`1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2`
|
`1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2`
|
||||||
runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library
|
runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library
|
||||||
stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics
|
stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics
|
||||||
bundle, the `1.0.0-beta.5` local package/workspace discipline bundle, and the
|
bundle, the `1.0.0-beta.5` local package/workspace discipline bundle, and the
|
||||||
`1.0.0-beta.6` loopback networking foundation, plus the `1.0.0-beta.7`
|
`1.0.0-beta.6` loopback networking foundation, plus the `1.0.0-beta.7`
|
||||||
serialization/data-interchange foundation and the `1.0.0-beta.8` concrete type
|
serialization/data-interchange foundation and the `1.0.0-beta.8` concrete type
|
||||||
alias foundation, the `1.0.0-beta.9` collection alias unification and
|
alias foundation, and the `1.0.0-beta.9` collection alias unification and
|
||||||
generic reservation slice, the `1.0.0-beta.10` developer-experience API
|
generic reservation slice, plus the `1.0.0-beta.10` developer-experience API
|
||||||
discovery slice, and the `1.0.0-beta.11` local package API documentation
|
discovery slice. The language baseline supports practical local
|
||||||
slice, plus the `1.0.0-beta.12` concrete vector query and prefix parity
|
command-line, file, and loopback-network programs with:
|
||||||
slice, the `1.0.0-beta.13` diagnostic catalog and schema policy slice, the
|
|
||||||
`1.0.0-beta.14` benchmark suite catalog and metadata gate, and the
|
|
||||||
`1.0.0-beta.15` reserved generic collection boundary hardening and collection
|
|
||||||
ledger, the `1.0.0-beta.16` string scanning and token boundary foundation,
|
|
||||||
the `1.0.0-beta.17` JSON primitive scalar parsing foundation, the
|
|
||||||
`1.0.0-beta.18` JSON string token parsing foundation, the
|
|
||||||
`1.0.0-beta.19` test discovery and user-project conformance foundation, the
|
|
||||||
`1.0.0-beta.20` string search and ASCII trim foundation, and the
|
|
||||||
`1.0.0-beta.21` JSON document scalar parsing foundation, plus the
|
|
||||||
`1.0.0-beta.22` run manifest and execution report hardening slice, and the
|
|
||||||
`1.0.0-beta.23` standard-library stability tier ledger and catalog alignment
|
|
||||||
slice, and the `1.0.0-beta.24` package manifest identity and local dependency
|
|
||||||
diagnostic hardening slice, plus the `1.0.0-beta.25` user-project
|
|
||||||
conformance matrix evidence slice.
|
|
||||||
|
|
||||||
The language baseline supports practical local command-line, file, and
|
|
||||||
loopback-network programs with:
|
|
||||||
|
|
||||||
- modules, explicit imports, packages, and local workspaces
|
- modules, explicit imports, packages, and local workspaces
|
||||||
- `new`, `check`, `fmt`, `test`, `doc`, `symbols`, `build`, `run`, and
|
- `new`, `check`, `fmt`, `test`, `doc`, `symbols`, `build`, `run`, and
|
||||||
@ -63,176 +46,27 @@ loopback-network programs with:
|
|||||||
- explicit `std/*.slo` imports from `lib/std`, installed `share/slovo/std`, or
|
- explicit `std/*.slo` imports from `lib/std`, installed `share/slovo/std`, or
|
||||||
`SLOVO_STD_PATH`
|
`SLOVO_STD_PATH`
|
||||||
- beta-scoped loopback TCP handles through `std.net`
|
- beta-scoped loopback TCP handles through `std.net`
|
||||||
- JSON string quoting, compact JSON text construction, primitive scalar token
|
- JSON string quoting and compact JSON text construction through `std.json`
|
||||||
parsing, ASCII JSON string-token parsing, and scalar JSON document parsing
|
|
||||||
through `std.json`
|
|
||||||
- byte-oriented string search and ASCII edge trimming through `std.string`
|
|
||||||
- hosted native builds through LLVM IR, Clang, and `runtime/runtime.c`
|
- hosted native builds through LLVM IR, Clang, and `runtime/runtime.c`
|
||||||
|
|
||||||
The generated standard-library API catalog is a beta discovery aid: it lists
|
The generated standard-library API catalog is a beta discovery aid: it lists
|
||||||
exported helper signatures from `lib/std/*.slo`, normalizes module-local
|
exported helper signatures from `lib/std/*.slo`, normalizes module-local
|
||||||
concrete aliases such as `VecI32` and `ResultU64` to their concrete public
|
concrete aliases such as `VecI32` and `ResultU64` to their concrete public
|
||||||
types, and omits non-exported helpers and `(type ...)` aliases.
|
types, and omits non-exported helpers and `(type ...)` aliases.
|
||||||
The companion
|
|
||||||
[`docs/language/STDLIB_TIERS.md`](docs/language/STDLIB_TIERS.md) ledger
|
|
||||||
defines the public tier labels `beta-supported`, `experimental`, and
|
|
||||||
`internal`, marks JSON, loopback networking, random/time, and filesystem
|
|
||||||
resource-handle helpers as experimental domains, and keeps concrete vector
|
|
||||||
modules as beta-supported concrete lanes rather than a generic collections
|
|
||||||
freeze.
|
|
||||||
`glagol symbols <file.slo|project|workspace>` emits deterministic
|
`glagol symbols <file.slo|project|workspace>` emits deterministic
|
||||||
editor-facing S-expression metadata for modules, imports, exports, aliases,
|
editor-facing S-expression metadata for modules, imports, exports, aliases,
|
||||||
structs, enums, functions, tests, source spans, and workspace package names.
|
structs, enums, functions, tests, source spans, and workspace package names.
|
||||||
`glagol doc <file|project|workspace> -o <dir>` now includes deterministic public
|
|
||||||
API sections for local package and module documentation: exact exported
|
|
||||||
function signatures, exported struct fields, exported enum variants and payload
|
|
||||||
types, non-export filtering, and module-local alias normalization.
|
|
||||||
The `1.0.0-beta.22` tooling slice adds an additive run-report block to
|
|
||||||
`glagol run --manifest` artifact manifests so local evidence can record the
|
|
||||||
program exit status, captured stdout, captured stderr, and forwarded program
|
|
||||||
arguments. This is beta CLI evidence hardening only: it does not add language
|
|
||||||
or stdlib features and does not freeze the artifact-manifest schema.
|
|
||||||
The `1.0.0-beta.12` vector parity slice adds source-authored helper coverage
|
|
||||||
only: `std.vec_i64` gains `count_of`, `starts_with`, `without_prefix`,
|
|
||||||
`ends_with`, and `without_suffix`, while `std.vec_f64` gains `count_of`.
|
|
||||||
The `1.0.0-beta.13` diagnostics slice documents the beta
|
|
||||||
`slovo.diagnostic` version `1` policy in
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](docs/language/DIAGNOSTICS.md): the
|
|
||||||
S-expression/JSON relationship, required and optional fields, JSON-line
|
|
||||||
discipline, source-less diagnostics, manifest diagnostic metadata,
|
|
||||||
compatibility and migration classes, and the current golden diagnostic code
|
|
||||||
catalog.
|
|
||||||
The `1.0.0-beta.14` benchmark metadata slice documents the existing benchmark
|
|
||||||
suite catalog in [`benchmarks/README.md`](benchmarks/README.md). It explains
|
|
||||||
`python3 benchmarks/runner.py --suite-list` for the human-readable suite
|
|
||||||
inventory and `python3 benchmarks/runner.py --suite-list --json` for beta
|
|
||||||
tooling metadata, with required scaffold-file verification for each current
|
|
||||||
suite. Benchmark timings remain local-machine evidence only; the JSON field
|
|
||||||
set is not a stable public schema.
|
|
||||||
The `1.0.0-beta.15` collection ledger and reserved diagnostic hardening slice
|
|
||||||
adds
|
|
||||||
[`docs/language/COLLECTIONS.md`](docs/language/COLLECTIONS.md) as the
|
|
||||||
docs/design ledger for current concrete collection and value-family
|
|
||||||
boundaries. It links to the generated
|
|
||||||
[`docs/language/STDLIB_API.md`](docs/language/STDLIB_API.md) catalog for exact
|
|
||||||
public helper signatures, records design pressure from duplicated concrete
|
|
||||||
vector/option/result families, defines prerequisites before executable
|
|
||||||
generics, generic aliases, maps, sets, iterators, mutable vectors, or
|
|
||||||
slice/view APIs can be promoted, and treats current unsupported diagnostics as
|
|
||||||
boundaries. It rewords affected reserved-boundary diagnostics from
|
|
||||||
beta.9-specific text to current-beta wording while preserving diagnostic
|
|
||||||
codes, schema, spans, expected/found values, hints, and output shape. It
|
|
||||||
changes no source language, runtime, stdlib/API surface, benchmark metadata
|
|
||||||
schema, ABI/layout behavior, or performance claim.
|
|
||||||
The `1.0.0-beta.16` string scanning and token boundary foundation adds
|
|
||||||
source facades and explicit examples for `std.string.byte_at_result`,
|
|
||||||
`std.string.slice_result`, `std.string.starts_with`, and
|
|
||||||
`std.string.ends_with`. These helpers are byte-oriented over the current
|
|
||||||
NUL-terminated runtime string representation; invalid indexes and ranges return
|
|
||||||
`err 1`, and substring allocation failure follows the existing string
|
|
||||||
allocation trap policy. This release does not promise Unicode scalar,
|
|
||||||
grapheme, display-width, or locale semantics; does not add full JSON parsing,
|
|
||||||
object/array parsing, tokenizers, a language slice/view feature, or a stable
|
|
||||||
stdlib/API freeze.
|
|
||||||
|
|
||||||
The `1.0.0-beta.17` JSON primitive scalar parsing foundation adds
|
Still deferred before stable: executable generics, maps/sets, broad package
|
||||||
result-returning `std.json.parse_*_value_result` helpers for booleans,
|
registry semantics, DNS/TLS/async networking, LSP/watch/debug-adapter
|
||||||
concrete numeric primitives, and exact `null` only. Numeric and boolean parse
|
guarantees, stable ABI and layout, runtime changes for generic collections,
|
||||||
helpers consume one isolated JSON primitive token: no leading/trailing
|
and a stable standard-library compatibility freeze.
|
||||||
whitespace, no leading `+`, no leading-zero integer form except `0`, and no
|
|
||||||
non-finite f64 values. This is not full JSON parsing: object/array parsing,
|
|
||||||
tokenizers, recursive `JsonValue`, document parsing beyond the beta21 scalar
|
|
||||||
document helpers, schema validation, streaming, Unicode escape handling,
|
|
||||||
stable ABI/layout, and a stable stdlib/API freeze remain deferred.
|
|
||||||
|
|
||||||
The `1.0.0-beta.18` JSON string token parsing foundation adds
|
The next likely language slice after `1.0.0-beta.10` should continue from the
|
||||||
`std.json.parse_string_value_result` as a thin source facade over the matching
|
developer-experience and reserved generic/collection diagnostics without
|
||||||
promoted runtime name. It consumes one already-isolated ASCII JSON string token
|
claiming executable generics, maps, sets, traits, inference,
|
||||||
with exact quotes and no leading/trailing whitespace, decodes the simple JSON
|
monomorphization, iterators, ABI stability, runtime changes, or a
|
||||||
escapes `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, and `\t`, and returns
|
standard-library API freeze until the contract and gates are explicit.
|
||||||
`err 1` for ordinary parse failure. Complete JSON document parsing beyond the
|
|
||||||
beta21 scalar document helpers, object/array parsing, tokenizer APIs, Unicode
|
|
||||||
escape decoding/normalization, embedded NUL policy, stable ABI/layout, and a
|
|
||||||
stable stdlib/API freeze remain deferred.
|
|
||||||
|
|
||||||
The `1.0.0-beta.19` test discovery and user-project conformance foundation
|
|
||||||
adds `glagol test --list <file|project|workspace>` plus legacy
|
|
||||||
`glagol --run-tests --list <file>` support for listing checked and discovered
|
|
||||||
tests without executing test bodies. The list mode preserves existing file,
|
|
||||||
project, and workspace test ordering, honors `--filter <substring>`, and
|
|
||||||
remains beta tooling rather than a stable output schema.
|
|
||||||
|
|
||||||
The `1.0.0-beta.20` string search and ASCII trim foundation adds
|
|
||||||
`std.string.contains`, `std.string.index_of_option`,
|
|
||||||
`std.string.last_index_of_option`, `std.string.trim_ascii_start`,
|
|
||||||
`std.string.trim_ascii_end`, and `std.string.trim_ascii` as ordinary source
|
|
||||||
helpers over the existing byte string primitives. Search is byte-oriented,
|
|
||||||
empty needles match at the first index and at `(len value)` for last search,
|
|
||||||
and ASCII trimming removes only bytes `9`, `10`, `11`, `12`, `13`, and `32`.
|
|
||||||
|
|
||||||
The `1.0.0-beta.21` JSON document scalar parsing foundation adds
|
|
||||||
source-authored `std.json.parse_*_document_result` helpers for string, bool,
|
|
||||||
`i32`, `u32`, `i64`, `u64`, `f64`, and exact `null` scalar JSON documents.
|
|
||||||
Each helper trims ASCII whitespace around the whole document with
|
|
||||||
`std.string.trim_ascii`, then delegates to the already released exact JSON
|
|
||||||
value-token parser for that scalar family. This scope does not add new
|
|
||||||
compiler-known runtime names, object/array parsing, recursive `JsonValue`,
|
|
||||||
tokenizer objects, maps/sets, streaming, Unicode escape decoding beyond the
|
|
||||||
existing string-token behavior, embedded NUL policy, stable ABI/layout, or a
|
|
||||||
stable stdlib/API freeze.
|
|
||||||
|
|
||||||
The `1.0.0-beta.22` run manifest and execution report hardening slice extends
|
|
||||||
`glagol run --manifest` artifact manifests with additive run-report evidence:
|
|
||||||
the executed program's exit status, captured stdout, captured stderr, and
|
|
||||||
forwarded user-program arguments. This release does not add source-language
|
|
||||||
syntax, standard-library helpers, compiler-known runtime names, runtime
|
|
||||||
capabilities, package behavior, stable artifact-manifest schema guarantees,
|
|
||||||
stable ABI/layout, or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
The `1.0.0-beta.23` standard-library stability tier ledger and catalog
|
|
||||||
alignment slice adds the public
|
|
||||||
[`STDLIB_TIERS.md`](docs/language/STDLIB_TIERS.md) maturity ledger beside the
|
|
||||||
generated [`STDLIB_API.md`](docs/language/STDLIB_API.md) signature catalog.
|
|
||||||
It is documentation/catalog tooling clarity only: no source-language syntax,
|
|
||||||
stdlib helpers, compiler-known runtime names, runtime behavior, stable manifest
|
|
||||||
schema, stable Markdown schema, stable ABI/layout, or stable stdlib/API freeze
|
|
||||||
changes. The generated catalog and release gate now expose and check tier
|
|
||||||
metadata.
|
|
||||||
|
|
||||||
The `1.0.0-beta.24` package manifest identity and local dependency discipline
|
|
||||||
slice tightens local manifest diagnostics only: duplicate package manifest
|
|
||||||
keys, invalid dependency keys, and duplicate dependency keys are explicit beta
|
|
||||||
package/workspace diagnostics. It does not add remote registries, lockfiles,
|
|
||||||
semantic-version solving, package publishing, optional/dev/target
|
|
||||||
dependencies, stable package ABI/layout, source-language changes, runtime
|
|
||||||
changes, or standard-library changes.
|
|
||||||
|
|
||||||
The `1.0.0-beta.25` user-project conformance matrix slice adds deterministic
|
|
||||||
tooling/readiness evidence over the existing `examples/projects/` and
|
|
||||||
`examples/workspaces/` inventories. It currently covers all 43 top-level
|
|
||||||
fixture roots and 655 discovered tests through ordinary `check`,
|
|
||||||
`test --list`, and stable `test` entry points. The matrix is for ordinary
|
|
||||||
project and workspace usage evidence only: it does not add source-language
|
|
||||||
syntax or semantics, standard-library helpers, runtime behavior, package
|
|
||||||
manager or registry behavior, lockfile behavior, semantic-version solving,
|
|
||||||
stable schema guarantees, or performance claims.
|
|
||||||
|
|
||||||
Still deferred before stable: executable generics, generic aliases, maps/sets,
|
|
||||||
broad package registry semantics, stable artifact-manifest schema, stable
|
|
||||||
Markdown schema, stable conformance-matrix schema, stable stdlib/API
|
|
||||||
compatibility freeze, DNS/TLS/async networking, LSP/watch guarantees, SARIF
|
|
||||||
and daemon protocols, stable `1.0.0`
|
|
||||||
diagnostics freeze,
|
|
||||||
re-exports/globs/hierarchical modules, mutable vectors, slice/view APIs,
|
|
||||||
iterators, additional compiler-known runtime names, stable ABI and layout,
|
|
||||||
performance claims, stable benchmark JSON metadata schema, and runtime changes
|
|
||||||
for generic collections.
|
|
||||||
|
|
||||||
The beta19 tooling scope is deliberately tooling-only. It does not add parallel
|
|
||||||
test execution, retries, tags/groups, coverage reports, event streams, stable
|
|
||||||
manifest or Markdown schema guarantees, LSP/watch behavior, SARIF/daemon
|
|
||||||
protocols, JSON expansion, runtime helper names, source-language syntax,
|
|
||||||
remote package registries, semver solving, or performance claims.
|
|
||||||
|
|
||||||
## Build And Test
|
## Build And Test
|
||||||
|
|
||||||
@ -352,31 +186,6 @@ package/dependency summary, new workspace templates declare
|
|||||||
local-package rules. Remote registries, lockfiles, semantic-version solving,
|
local-package rules. Remote registries, lockfiles, semantic-version solving,
|
||||||
package publishing, and stable package ABI/layout remain deferred.
|
package publishing, and stable package ABI/layout remain deferred.
|
||||||
|
|
||||||
## 1.0.0-beta.24 Package Manifest Identity And Dependency Discipline
|
|
||||||
|
|
||||||
The `1.0.0-beta.24` release keeps the local package model closed and local. It
|
|
||||||
hardens diagnostics for manifest identity/dependency mistakes only: duplicate
|
|
||||||
package manifest keys, invalid dependency keys, and duplicate dependency keys
|
|
||||||
are reported explicitly.
|
|
||||||
|
|
||||||
This scope does not add a remote registry, lockfile, semantic-version solver,
|
|
||||||
package publishing flow, optional/dev/target dependencies, stable package
|
|
||||||
ABI/layout, source-language behavior, runtime behavior, or standard-library
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
## 1.0.0-beta.25 User Project Conformance Matrix
|
|
||||||
|
|
||||||
The `1.0.0-beta.25` release adds deterministic tooling evidence for the
|
|
||||||
existing user-shaped examples under `examples/projects/` and
|
|
||||||
`examples/workspaces/`. The conformance matrix is sorted by repository path and
|
|
||||||
records ordinary `check`, `test --list`, and stable `test` behavior for all
|
|
||||||
43 top-level fixture roots and 655 discovered tests.
|
|
||||||
|
|
||||||
This scope is stable-readiness evidence only. It adds no source-language
|
|
||||||
change, standard-library helper change, runtime behavior change, package
|
|
||||||
manager or registry behavior, lockfile behavior, semantic-version solving,
|
|
||||||
stable schema freeze, or performance claim.
|
|
||||||
|
|
||||||
## 1.0.0-beta.6 Networking Foundation
|
## 1.0.0-beta.6 Networking Foundation
|
||||||
|
|
||||||
The `1.0.0-beta.6` release adds a narrow blocking loopback TCP foundation:
|
The `1.0.0-beta.6` release adds a narrow blocking loopback TCP foundation:
|
||||||
@ -401,11 +210,9 @@ The `1.0.0-beta.7` release adds a narrow JSON text-construction foundation:
|
|||||||
- explicit std/local JSON example projects and a `json-quote-loop` benchmark
|
- explicit std/local JSON example projects and a `json-quote-loop` benchmark
|
||||||
scaffold
|
scaffold
|
||||||
|
|
||||||
This is not a complete JSON library. Full parsing beyond primitive scalar
|
This is not a complete JSON library. Full parsing, recursive JSON values,
|
||||||
tokens and the ASCII JSON string-token helper, object/array parsing,
|
maps/sets, streaming encoders, schema validation, Unicode normalization, and a
|
||||||
recursive JSON values, maps/sets, streaming encoders or decoders, schema
|
stable data-interchange API freeze remain deferred.
|
||||||
validation, Unicode normalization, and a stable data-interchange API freeze
|
|
||||||
remain deferred.
|
|
||||||
|
|
||||||
## 1.0.0-beta.8 Concrete Type Alias Foundation
|
## 1.0.0-beta.8 Concrete Type Alias Foundation
|
||||||
|
|
||||||
@ -454,167 +261,12 @@ add executable generics, maps, sets, new runtime helpers, new compiler-known
|
|||||||
runtime names, ABI/layout guarantees, an LSP server, watch mode, or a stable
|
runtime names, ABI/layout guarantees, an LSP server, watch mode, or a stable
|
||||||
standard-library API freeze.
|
standard-library API freeze.
|
||||||
|
|
||||||
## 1.0.0-beta.11 Local Package API Documentation
|
|
||||||
|
|
||||||
The `1.0.0-beta.11` release extends the beta.10 API discovery lane to local
|
|
||||||
package and module documentation. `glagol doc <file|project|workspace> -o <dir>`
|
|
||||||
includes deterministic exported/public API sections for local modules and
|
|
||||||
workspace packages.
|
|
||||||
|
|
||||||
Those sections list exact exported function signatures, exported struct fields,
|
|
||||||
and exported enum variants with payload types. They omit non-exported
|
|
||||||
functions, structs, enums, tests, and aliases from the public API surface, and
|
|
||||||
they normalize module-local concrete aliases before rendering public types.
|
|
||||||
|
|
||||||
This remains beta API discovery. It does not freeze the Markdown schema, create
|
|
||||||
a stable stdlib/API compatibility freeze, add LSP/watch behavior, define
|
|
||||||
SARIF or daemon protocols, set diagnostics schema policy, implement executable
|
|
||||||
generics, maps, or sets, add re-exports, globs, or hierarchical modules, or
|
|
||||||
define package registry semantics.
|
|
||||||
|
|
||||||
## 1.0.0-beta.12 Concrete Vector Query And Prefix Parity
|
|
||||||
|
|
||||||
The `1.0.0-beta.12` release is a source-authored stdlib/helper parity update
|
|
||||||
for concrete vectors. It adds `count_of`, `starts_with`, `without_prefix`,
|
|
||||||
`ends_with`, and `without_suffix` to `std.vec_i64`, and adds `count_of` to
|
|
||||||
`std.vec_f64`, matching the already staged concrete helper style.
|
|
||||||
|
|
||||||
This release does not change the source language, runtime, compiler-known
|
|
||||||
`std.vec.*` names, ABI/layout contract, or performance contract. Generics,
|
|
||||||
maps/sets, iterators, mutable vectors, slice/view APIs, new runtime helper
|
|
||||||
names, stable stdlib API freeze, and broader collection abstractions remain
|
|
||||||
deferred.
|
|
||||||
|
|
||||||
## 1.0.0-beta.13 Diagnostic Catalog And Schema Policy
|
|
||||||
|
|
||||||
The `1.0.0-beta.13` release is a docs/tooling policy update for the existing
|
|
||||||
diagnostic surface. It adds
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](docs/language/DIAGNOSTICS.md) as the beta
|
|
||||||
policy for `slovo.diagnostic` version `1`.
|
|
||||||
|
|
||||||
The policy documents the S-expression and JSON encodings, required and optional
|
|
||||||
machine fields, severity/source/range/related-span semantics, JSON-line
|
|
||||||
discipline, source-less diagnostics, artifact-manifest diagnostic metadata,
|
|
||||||
compatibility and migration classes, and the current code catalog covered by
|
|
||||||
the golden diagnostics contract.
|
|
||||||
|
|
||||||
This release does not change the source language, runtime, stdlib API,
|
|
||||||
diagnostic output shape, compiler CLI, LSP/watch behavior, SARIF/daemon
|
|
||||||
protocols, stable Markdown schema, or stable `1.0.0` diagnostics freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.16 String Scanning And Token Boundary Foundation
|
|
||||||
|
|
||||||
The `1.0.0-beta.16` release adds the first explicit byte-oriented string
|
|
||||||
scanning and token-boundary helpers to the `std.string` source facade:
|
|
||||||
`byte_at_result`, `slice_result`, `starts_with`, and `ends_with`.
|
|
||||||
|
|
||||||
The helpers operate over the current NUL-terminated runtime string bytes before
|
|
||||||
the trailing NUL. `byte_at_result` and `slice_result` return `err 1` for
|
|
||||||
ordinary invalid indexes or ranges. `slice_result` returns a runtime-owned
|
|
||||||
string on success; allocation failure may trap with the existing string
|
|
||||||
allocation policy.
|
|
||||||
|
|
||||||
This release does not add Unicode scalar, grapheme, display-width, or locale
|
|
||||||
semantics; full JSON parsing; object/array parsing; tokenizer APIs; a language
|
|
||||||
slice/view feature; mutable strings; stable ABI/layout; or a stable stdlib/API
|
|
||||||
freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.20 String Search And ASCII Trim Foundation
|
|
||||||
|
|
||||||
The `1.0.0-beta.20` scope extends the source-authored `std.string` facade
|
|
||||||
with byte-oriented search and ASCII trim helpers:
|
|
||||||
`contains`, `index_of_option`, `last_index_of_option`, `trim_ascii_start`,
|
|
||||||
`trim_ascii_end`, and `trim_ascii`.
|
|
||||||
|
|
||||||
This scope adds no compiler-known runtime names. It does not claim Unicode
|
|
||||||
scalar, grapheme, case-folding, locale, regex, tokenizer, mutable string,
|
|
||||||
language slice/view, stable ABI/layout, or stable stdlib/API semantics.
|
|
||||||
|
|
||||||
## 1.0.0-beta.21 JSON Document Scalar Parsing Foundation
|
|
||||||
|
|
||||||
The `1.0.0-beta.21` scope extends `std.json` with source-authored
|
|
||||||
whole-document scalar helpers:
|
|
||||||
`parse_string_document_result`, `parse_bool_document_result`,
|
|
||||||
`parse_i32_document_result`, `parse_u32_document_result`,
|
|
||||||
`parse_i64_document_result`, `parse_u64_document_result`,
|
|
||||||
`parse_f64_document_result`, and `parse_null_document_result`.
|
|
||||||
|
|
||||||
The helpers accept leading and trailing ASCII whitespace around a single
|
|
||||||
scalar document by composing with `std.string.trim_ascii`; trailing
|
|
||||||
non-whitespace still fails through the existing exact value-token parsers.
|
|
||||||
|
|
||||||
This scope does not add object/array parsing, recursive JSON values, parser
|
|
||||||
objects, maps/sets, streaming, Unicode escape decoding beyond the existing
|
|
||||||
string-token behavior, embedded NUL policy, new compiler-known runtime names,
|
|
||||||
stable ABI/layout, or stable stdlib/API semantics.
|
|
||||||
|
|
||||||
## 1.0.0-beta.22 Run Manifest And Execution Report Hardening
|
|
||||||
|
|
||||||
The `1.0.0-beta.22` scope hardens `glagol run --manifest` evidence by adding
|
|
||||||
an additive run-report block to run-mode artifact manifests. The block records
|
|
||||||
the executed program's exit status, captured stdout, captured stderr, and
|
|
||||||
forwarded program arguments.
|
|
||||||
|
|
||||||
This is tooling/CLI evidence work only. It does not add language syntax,
|
|
||||||
stdlib helpers, compiler-known runtime names, runtime C capabilities, package
|
|
||||||
or import behavior, stable artifact-manifest schema guarantees, stable
|
|
||||||
ABI/layout, or stable stdlib/API semantics.
|
|
||||||
|
|
||||||
## 1.0.0-beta.15 Reserved Generic Collection Boundary Hardening And Collection Ledger
|
|
||||||
|
|
||||||
The `1.0.0-beta.15` release documents the current concrete collection and
|
|
||||||
value-family boundary. It adds
|
|
||||||
[`docs/language/COLLECTIONS.md`](docs/language/COLLECTIONS.md), which links to
|
|
||||||
the generated
|
|
||||||
[`docs/language/STDLIB_API.md`](docs/language/STDLIB_API.md) catalog instead
|
|
||||||
of duplicating generated helper counts.
|
|
||||||
|
|
||||||
The ledger inventories concrete vector, option, result, and related
|
|
||||||
option/result-returning facade surfaces; records the design pressure from
|
|
||||||
duplicated concrete vector/option/result helpers; and defines prerequisites
|
|
||||||
before executable generics, generic aliases, maps, sets, iterators, mutable
|
|
||||||
vectors, or slice/view APIs can be promoted.
|
|
||||||
|
|
||||||
Current unsupported diagnostics are documented as release boundaries, not as
|
|
||||||
new behavior. This release does not change the source language, runtime,
|
|
||||||
stdlib/API surface, diagnostic output shape/codes/schema, benchmark metadata
|
|
||||||
schema, compiler ABI/layout behavior, or performance claims, and it does not
|
|
||||||
create a stable stdlib/API freeze. It does reword affected reserved-boundary
|
|
||||||
diagnostic messages from beta.9-specific text to current-beta wording while
|
|
||||||
preserving diagnostic codes, schema, spans, expected/found values, hints, and
|
|
||||||
output shape.
|
|
||||||
|
|
||||||
## 1.0.0-beta.14 Benchmark Suite Catalog And Metadata Gate
|
|
||||||
|
|
||||||
The `1.0.0-beta.14` release documents the existing benchmark suite catalog as
|
|
||||||
beta-scoped metadata tooling. It adds
|
|
||||||
[`benchmarks/README.md`](benchmarks/README.md) with the current ten-suite
|
|
||||||
inventory, local evidence policy, suite-list commands, and exclusions.
|
|
||||||
|
|
||||||
The root suite catalog commands are:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 benchmarks/runner.py --suite-list
|
|
||||||
python3 benchmarks/runner.py --suite-list --json
|
|
||||||
```
|
|
||||||
|
|
||||||
The non-JSON listing is for local review. The JSON listing is beta tooling
|
|
||||||
metadata for local gates and adapters, not a stable public schema.
|
|
||||||
|
|
||||||
This release does not add benchmark kernels, publish timing numbers, define
|
|
||||||
performance thresholds, change the source language, runtime, stdlib/API
|
|
||||||
surface, diagnostic output, compiler ABI/layout behavior, or make cross-machine
|
|
||||||
performance claims.
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [Language Manifest](docs/language/MANIFEST.md)
|
- [Language Manifest](docs/language/MANIFEST.md)
|
||||||
- [Language Specification](docs/language/SPEC-v1.md)
|
- [Language Specification](docs/language/SPEC-v1.md)
|
||||||
- [Diagnostics Policy](docs/language/DIAGNOSTICS.md)
|
|
||||||
- [Local Package And Workspace Guide](docs/language/PACKAGES.md)
|
- [Local Package And Workspace Guide](docs/language/PACKAGES.md)
|
||||||
- [Standard Library API Catalog](docs/language/STDLIB_API.md)
|
- [Standard Library API Catalog](docs/language/STDLIB_API.md)
|
||||||
- [Collection Ledger](docs/language/COLLECTIONS.md)
|
|
||||||
- [Benchmark Suite Catalog](benchmarks/README.md)
|
|
||||||
- [Compiler Manifest](docs/compiler/GLAGOL_COMPILER_MANIFEST.md)
|
- [Compiler Manifest](docs/compiler/GLAGOL_COMPILER_MANIFEST.md)
|
||||||
- [Post-Beta Roadmap](docs/POST_BETA_ROADMAP.md)
|
- [Post-Beta Roadmap](docs/POST_BETA_ROADMAP.md)
|
||||||
- [Slovo Whitepaper](docs/papers/SLOVO_WHITEPAPER.md)
|
- [Slovo Whitepaper](docs/papers/SLOVO_WHITEPAPER.md)
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
# Slovo Benchmark Suite Catalog
|
|
||||||
|
|
||||||
Release stage: `1.0.0-beta.14`.
|
|
||||||
|
|
||||||
The benchmark suite is beta-scoped local tooling. It catalogs deterministic
|
|
||||||
same-machine comparison scaffolds for Slovo and sibling implementations. It
|
|
||||||
does not publish benchmark results, set performance thresholds, define optimizer
|
|
||||||
claims, or create cross-machine comparisons.
|
|
||||||
|
|
||||||
## Suite Listing
|
|
||||||
|
|
||||||
From the repository root, list the suite catalog for humans:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 benchmarks/runner.py --suite-list
|
|
||||||
```
|
|
||||||
|
|
||||||
List the same catalog as beta tooling metadata:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 benchmarks/runner.py --suite-list --json
|
|
||||||
```
|
|
||||||
|
|
||||||
The non-JSON listing is for local review. The JSON listing is for local gates
|
|
||||||
and tooling adapters that need the current suite inventory. The JSON field set
|
|
||||||
is not a stable public schema; it may change during beta releases.
|
|
||||||
Both forms verify the required scaffold files for each suite:
|
|
||||||
`benchmark.json`, `run.py`, `slovo.toml`, and `src/main.slo`.
|
|
||||||
|
|
||||||
Each suite still owns its local metadata and run commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 benchmarks/<suite>/run.py --list
|
|
||||||
python3 benchmarks/<suite>/run.py --list --json
|
|
||||||
python3 benchmarks/<suite>/run.py --dry-run
|
|
||||||
```
|
|
||||||
|
|
||||||
## Current Suites
|
|
||||||
|
|
||||||
All current suites provide Slovo, C, Rust, Python, Clojure, and Common
|
|
||||||
Lisp/SBCL source slots. Missing local toolchains are skipped by the per-suite
|
|
||||||
runner where possible.
|
|
||||||
|
|
||||||
| Suite | Focus | Base checksum | Hot-loop checksum | Runtime args |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| `math-loop` | arithmetic and scalar accumulation | `5000001` | `50000001` | none |
|
|
||||||
| `branch-loop` | deterministic branch-heavy integer loop | `1185071` | `220775` | none |
|
|
||||||
| `parse-loop` | repeated signed decimal `i32` parsing | `345000001` | `450000001` | `12345` |
|
|
||||||
| `array-index-loop` | immutable fixed-array indexing | `3875007` | `38750007` | none |
|
|
||||||
| `string-eq-loop` | fixed string lookup and equality | `4600001` | `46000001` | `omega` |
|
|
||||||
| `array-struct-field-loop` | fixed-array access through an immutable struct field | `3875011` | `38750011` | none |
|
|
||||||
| `enum-struct-payload-loop` | enum payload matching with struct and array access | `3500013` | `35000013` | none |
|
|
||||||
| `vec-i32-index-loop` | runtime-owned `(vec i32)` indexing | `3875007` | `38750007` | none |
|
|
||||||
| `vec-string-eq-loop` | runtime-owned `(vec string)` lookup and equality | `4600001` | `46000001` | `omega` |
|
|
||||||
| `json-quote-loop` | compact JSON string quoting | `15000001` | `150000001` | `slo"vo\path` |
|
|
||||||
|
|
||||||
The base loop count is `1000000` for every current suite. The hot-loop count is
|
|
||||||
`10000000` for every current suite. The runner supplies loop counts and runtime
|
|
||||||
arguments at execution time so native compilers cannot fold the work into a
|
|
||||||
constant answer.
|
|
||||||
|
|
||||||
## Local Evidence Only
|
|
||||||
|
|
||||||
Benchmark output is local-machine evidence only:
|
|
||||||
|
|
||||||
- cold-process mode measures execution after each implementation has been built
|
|
||||||
once; it does not include compile time
|
|
||||||
- hot-loop mode is startup-amortized local evidence and reports total time plus
|
|
||||||
normalized timing for the base loop count
|
|
||||||
- Clojure timings include JVM and Clojure startup
|
|
||||||
- Common Lisp timings include SBCL script startup
|
|
||||||
- reported timings depend on the local CPU, OS, compiler versions, toolchain
|
|
||||||
availability, thermal/load state, and runner configuration
|
|
||||||
|
|
||||||
This catalog intentionally publishes no timing numbers.
|
|
||||||
|
|
||||||
## Exclusions
|
|
||||||
|
|
||||||
`1.0.0-beta.14` does not add benchmark kernels, publish timings, define
|
|
||||||
performance thresholds, define a stable JSON schema, change the Slovo source
|
|
||||||
language, change runtime behavior, change standard-library or API contracts,
|
|
||||||
change diagnostic output, change ABI/layout behavior, or make cross-machine
|
|
||||||
performance claims.
|
|
||||||
@ -18,12 +18,6 @@ from typing import Callable
|
|||||||
|
|
||||||
TIMING_SCOPE = "local-machine comparison only"
|
TIMING_SCOPE = "local-machine comparison only"
|
||||||
TIMING_MODES = ["cold-process", "hot-loop"]
|
TIMING_MODES = ["cold-process", "hot-loop"]
|
||||||
SUITE_NAME = "glagol-local-benchmark-suite"
|
|
||||||
LOCAL_TIMING_DISCLAIMER = (
|
|
||||||
"Local timing comparison only; not a published benchmark result and not a cross-machine performance claim."
|
|
||||||
)
|
|
||||||
REQUIRED_BENCHMARK_FILES = ["benchmark.json", "run.py", "slovo.toml", "src/main.slo"]
|
|
||||||
EXPECTED_IMPLEMENTATION_NAMES = ["slovo", "c", "rust", "python", "clojure", "common_lisp"]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -58,14 +52,6 @@ class Implementation:
|
|||||||
|
|
||||||
|
|
||||||
def main(root: Path, argv: list[str]) -> int:
|
def main(root: Path, argv: list[str]) -> int:
|
||||||
if any(arg == "--suite-list" for arg in argv):
|
|
||||||
return main_suite(root, argv)
|
|
||||||
if not (root / "benchmark.json").is_file():
|
|
||||||
parser = argparse.ArgumentParser(description="Shared local Glagol benchmark runner.")
|
|
||||||
parser.add_argument("--suite-list", action="store_true", help="list suite metadata and exit")
|
|
||||||
parser.add_argument("--json", action="store_true", help="emit JSON for --suite-list")
|
|
||||||
parser.error("run from a benchmark run.py, or pass --suite-list at the benchmark suite root")
|
|
||||||
|
|
||||||
spec = read_spec(root)
|
spec = read_spec(root)
|
||||||
implementations = available_implementations(root, spec)
|
implementations = available_implementations(root, spec)
|
||||||
parser = argparse.ArgumentParser(description=f"Run local {spec.name} timing comparisons.")
|
parser = argparse.ArgumentParser(description=f"Run local {spec.name} timing comparisons.")
|
||||||
@ -103,25 +89,6 @@ def main(root: Path, argv: list[str]) -> int:
|
|||||||
return 1 if any(result["status"] == "failed" for result in results) else 0
|
return 1 if any(result["status"] == "failed" for result in results) else 0
|
||||||
|
|
||||||
|
|
||||||
def main_suite(root: Path, argv: list[str]) -> int:
|
|
||||||
parser = argparse.ArgumentParser(description="List local Glagol benchmark suite metadata.")
|
|
||||||
parser.add_argument("--suite-list", action="store_true", help="list suite metadata and exit")
|
|
||||||
parser.add_argument("--json", action="store_true", help="emit JSON for suite metadata")
|
|
||||||
args = parser.parse_args(argv)
|
|
||||||
if not args.suite_list:
|
|
||||||
parser.error("pass --suite-list to list benchmark suite metadata")
|
|
||||||
|
|
||||||
suite_root = resolve_suite_root(root)
|
|
||||||
emit_suite_list(build_suite_catalog(suite_root), args.json)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_suite_root(root: Path) -> Path:
|
|
||||||
if (root / "benchmark.json").is_file():
|
|
||||||
return root.parent
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
def read_spec(root: Path) -> BenchmarkSpec:
|
def read_spec(root: Path) -> BenchmarkSpec:
|
||||||
data = json.loads((root / "benchmark.json").read_text(encoding="utf-8"))
|
data = json.loads((root / "benchmark.json").read_text(encoding="utf-8"))
|
||||||
loop_count = int(data["loop_count"])
|
loop_count = int(data["loop_count"])
|
||||||
@ -311,143 +278,6 @@ def select_implementations(implementations: list[Implementation], names: list[st
|
|||||||
return [impl for impl in implementations if impl.name in selected_names]
|
return [impl for impl in implementations if impl.name in selected_names]
|
||||||
|
|
||||||
|
|
||||||
def build_suite_catalog(suite_root: Path) -> dict[str, object]:
|
|
||||||
benchmarks: list[dict[str, object]] = []
|
|
||||||
implementation_slot_count = 0
|
|
||||||
missing_required_files: list[str] = []
|
|
||||||
missing_implementation_slots: list[str] = []
|
|
||||||
|
|
||||||
for root in suite_benchmark_roots(suite_root):
|
|
||||||
spec = read_spec(root)
|
|
||||||
implementations = available_implementations(root, spec)
|
|
||||||
implementation_slot_count += len(implementations)
|
|
||||||
benchmark = suite_benchmark_metadata(suite_root, root, spec, implementations)
|
|
||||||
benchmarks.append(benchmark)
|
|
||||||
|
|
||||||
directory = str(benchmark["directory"])
|
|
||||||
for required_file in benchmark["required_files"]:
|
|
||||||
assert isinstance(required_file, dict)
|
|
||||||
if required_file["status"] != "present":
|
|
||||||
missing_required_files.append(f"{directory}/{required_file['path']}")
|
|
||||||
|
|
||||||
present_implementations = {
|
|
||||||
str(implementation["name"])
|
|
||||||
for implementation in benchmark["implementation_slots"]
|
|
||||||
if isinstance(implementation, dict)
|
|
||||||
}
|
|
||||||
for expected in EXPECTED_IMPLEMENTATION_NAMES:
|
|
||||||
if expected not in present_implementations:
|
|
||||||
missing_implementation_slots.append(f"{directory}:{expected}")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"suite": SUITE_NAME,
|
|
||||||
"timing_scope": TIMING_SCOPE,
|
|
||||||
"timing_modes": TIMING_MODES,
|
|
||||||
"timing_disclaimer": LOCAL_TIMING_DISCLAIMER,
|
|
||||||
"benchmark_count": len(benchmarks),
|
|
||||||
"benchmarks": benchmarks,
|
|
||||||
"verification": {
|
|
||||||
"status": "ok" if not missing_required_files and not missing_implementation_slots else "incomplete",
|
|
||||||
"benchmark_metadata_files": len(benchmarks),
|
|
||||||
"required_files": len(benchmarks) * len(REQUIRED_BENCHMARK_FILES),
|
|
||||||
"missing_required_files": missing_required_files,
|
|
||||||
"implementation_slots": implementation_slot_count,
|
|
||||||
"expected_implementation_slots": len(benchmarks) * len(EXPECTED_IMPLEMENTATION_NAMES),
|
|
||||||
"missing_implementation_slots": missing_implementation_slots,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def suite_benchmark_roots(suite_root: Path) -> list[Path]:
|
|
||||||
return sorted(
|
|
||||||
[path for path in suite_root.iterdir() if path.is_dir() and (path / "benchmark.json").is_file()],
|
|
||||||
key=lambda path: path.name,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def suite_benchmark_metadata(
|
|
||||||
suite_root: Path,
|
|
||||||
root: Path,
|
|
||||||
spec: BenchmarkSpec,
|
|
||||||
implementations: list[Implementation],
|
|
||||||
) -> dict[str, object]:
|
|
||||||
return {
|
|
||||||
"name": spec.name,
|
|
||||||
"directory": str(root.relative_to(suite_root)),
|
|
||||||
"source_stem": spec.source_stem,
|
|
||||||
"timing_modes": TIMING_MODES,
|
|
||||||
"loop_count_source": "stdin",
|
|
||||||
"loop_count": spec.loop_count,
|
|
||||||
"hot_loop_count": spec.hot_loop_count,
|
|
||||||
"expected_checksum": spec.expected_checksum,
|
|
||||||
"hot_expected_checksum": spec.hot_expected_checksum,
|
|
||||||
"required_files": [
|
|
||||||
{
|
|
||||||
"path": relative,
|
|
||||||
"status": "present" if (root / relative).is_file() else "missing",
|
|
||||||
}
|
|
||||||
for relative in REQUIRED_BENCHMARK_FILES
|
|
||||||
],
|
|
||||||
"checksum_metadata": {
|
|
||||||
"cold_process": {
|
|
||||||
"expected_checksum": spec.expected_checksum,
|
|
||||||
"stdin": spec.stdin_text,
|
|
||||||
},
|
|
||||||
"hot_loop": {
|
|
||||||
"expected_checksum": spec.hot_expected_checksum,
|
|
||||||
"stdin": spec.hot_stdin_text,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"run_args": spec.run_args,
|
|
||||||
"implementation_slots": [
|
|
||||||
{
|
|
||||||
"name": impl.name,
|
|
||||||
"language": impl.language,
|
|
||||||
"source": str(impl.source.relative_to(suite_root)),
|
|
||||||
}
|
|
||||||
for impl in implementations
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def emit_suite_list(metadata: dict[str, object], as_json: bool) -> None:
|
|
||||||
if as_json:
|
|
||||||
print(json.dumps(metadata, indent=2, sort_keys=True))
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"{metadata['suite']}: {metadata['timing_scope']}")
|
|
||||||
print(str(metadata["timing_disclaimer"]))
|
|
||||||
print(f"benchmark_count={metadata['benchmark_count']}")
|
|
||||||
print(f"timing_modes={','.join(TIMING_MODES)}")
|
|
||||||
verification = metadata["verification"]
|
|
||||||
assert isinstance(verification, dict)
|
|
||||||
print(f"verification_status={verification['status']}")
|
|
||||||
print(f"required_files={verification['required_files']}")
|
|
||||||
print(f"implementation_slots={verification['implementation_slots']}")
|
|
||||||
print("benchmarks:")
|
|
||||||
for benchmark in metadata["benchmarks"]:
|
|
||||||
assert isinstance(benchmark, dict)
|
|
||||||
print(
|
|
||||||
" {name} ({directory}): loop_count={loop_count} hot_loop_count={hot_loop_count} "
|
|
||||||
"expected_checksum={expected_checksum} hot_expected_checksum={hot_expected_checksum}".format(
|
|
||||||
name=benchmark["name"],
|
|
||||||
directory=benchmark["directory"],
|
|
||||||
loop_count=benchmark["loop_count"],
|
|
||||||
hot_loop_count=benchmark["hot_loop_count"],
|
|
||||||
expected_checksum=benchmark["expected_checksum"],
|
|
||||||
hot_expected_checksum=benchmark["hot_expected_checksum"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
print(" required_files:")
|
|
||||||
for required_file in benchmark["required_files"]:
|
|
||||||
assert isinstance(required_file, dict)
|
|
||||||
print(f" {required_file['path']}: {required_file['status']}")
|
|
||||||
print(" implementations:")
|
|
||||||
for implementation in benchmark["implementation_slots"]:
|
|
||||||
assert isinstance(implementation, dict)
|
|
||||||
print(f" {implementation['name']}: {implementation['language']} ({implementation['source']})")
|
|
||||||
|
|
||||||
|
|
||||||
def emit_list(root: Path, spec: BenchmarkSpec, implementations: list[Implementation], as_json: bool) -> None:
|
def emit_list(root: Path, spec: BenchmarkSpec, implementations: list[Implementation], as_json: bool) -> None:
|
||||||
metadata = {
|
metadata = {
|
||||||
"benchmark": spec.name,
|
"benchmark": spec.name,
|
||||||
@ -690,7 +520,3 @@ def shlex_quote(value: str) -> str:
|
|||||||
if value and all(char.isalnum() or char in "/._:-" for char in value):
|
if value and all(char.isalnum() or char in "/._:-" for char in value):
|
||||||
return value
|
return value
|
||||||
return "'" + value.replace("'", "'\"'\"'") + "'"
|
return "'" + value.replace("'", "'\"'\"'") + "'"
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main(Path(__file__).resolve().parent, sys.argv[1:]))
|
|
||||||
|
|||||||
2
compiler/Cargo.lock
generated
2
compiler/Cargo.lock
generated
@ -4,4 +4,4 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glagol"
|
name = "glagol"
|
||||||
version = "1.0.0-beta.25"
|
version = "1.0.0-beta.10"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "glagol"
|
name = "glagol"
|
||||||
version = "1.0.0-beta.25"
|
version = "1.0.0-beta.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Glagol, the first compiler for the Slovo language"
|
description = "Glagol, the first compiler for the Slovo language"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
@ -6,9 +6,7 @@ use crate::{
|
|||||||
StructDecl, StructInitField, Test, TypeAliasDecl,
|
StructDecl, StructInitField, Test, TypeAliasDecl,
|
||||||
},
|
},
|
||||||
diag::Diagnostic,
|
diag::Diagnostic,
|
||||||
lower,
|
lower, std_runtime,
|
||||||
reserved::{is_generic_type_parameter_name, unsupported_generic_type_parameter},
|
|
||||||
std_runtime,
|
|
||||||
token::Span,
|
token::Span,
|
||||||
types::Type,
|
types::Type,
|
||||||
unsafe_ops,
|
unsafe_ops,
|
||||||
@ -5539,6 +5537,25 @@ fn check_vector_type(file: &str, ty: &Type, span: Span) -> Result<(), Diagnostic
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_type_parameter(file: &str, span: Span, name: &str) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeParameter",
|
||||||
|
format!(
|
||||||
|
"generic type parameter `{}` is reserved but not supported in beta.9",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("concrete supported type")
|
||||||
|
.found(name.to_string())
|
||||||
|
.hint("use a concrete promoted type such as `i32`, `string`, or `(vec i32)`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_generic_type_parameter_name(name: &str) -> bool {
|
||||||
|
name.len() == 1 && name.bytes().all(|byte| byte.is_ascii_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
fn array_index_range(len: usize) -> String {
|
fn array_index_range(len: usize) -> String {
|
||||||
if len == 1 {
|
if len == 1 {
|
||||||
"0".to_string()
|
"0".to_string()
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use crate::token::Span;
|
use crate::token::Span;
|
||||||
|
|
||||||
pub const DIAGNOSTIC_SCHEMA_NAME: &str = "slovo.diagnostic";
|
|
||||||
pub const DIAGNOSTIC_SCHEMA_VERSION: u32 = 1;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum Severity {
|
pub enum Severity {
|
||||||
Error,
|
Error,
|
||||||
@ -187,8 +184,8 @@ impl Diagnostic {
|
|||||||
) -> String {
|
) -> String {
|
||||||
let source = source_for(&self.file).unwrap_or("");
|
let source = source_for(&self.file).unwrap_or("");
|
||||||
let mut parts = vec![
|
let mut parts = vec![
|
||||||
format!(" (schema {})", DIAGNOSTIC_SCHEMA_NAME),
|
" (schema slovo.diagnostic)".to_string(),
|
||||||
format!(" (version {})", DIAGNOSTIC_SCHEMA_VERSION),
|
" (version 1)".to_string(),
|
||||||
format!(" (severity {})", self.severity.as_str()),
|
format!(" (severity {})", self.severity.as_str()),
|
||||||
format!(" (code {})", self.code),
|
format!(" (code {})", self.code),
|
||||||
format!(" (message {})", render_string(&self.message)),
|
format!(" (message {})", render_string(&self.message)),
|
||||||
@ -313,8 +310,8 @@ fn render_json_diagnostic<'a>(
|
|||||||
related: impl Iterator<Item = JsonRelated<'a>>,
|
related: impl Iterator<Item = JsonRelated<'a>>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut fields = vec![
|
let mut fields = vec![
|
||||||
format!("\"schema\":{}", render_json_string(DIAGNOSTIC_SCHEMA_NAME)),
|
"\"schema\":\"slovo.diagnostic\"".to_string(),
|
||||||
format!("\"version\":{}", DIAGNOSTIC_SCHEMA_VERSION),
|
"\"version\":1".to_string(),
|
||||||
format!("\"severity\":{}", render_json_string(severity)),
|
format!("\"severity\":{}", render_json_string(severity)),
|
||||||
format!("\"code\":{}", render_json_string(code)),
|
format!("\"code\":{}", render_json_string(code)),
|
||||||
format!("\"message\":{}", render_json_string(message)),
|
format!("\"message\":{}", render_json_string(message)),
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
use std::{
|
use std::{fs, path::Path};
|
||||||
collections::{BTreeMap, BTreeSet},
|
|
||||||
fs,
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::Program,
|
ast::Program,
|
||||||
@ -10,7 +6,6 @@ use crate::{
|
|||||||
lexer, lower,
|
lexer, lower,
|
||||||
project::{self, ProjectArtifact, SourceFile, ToolFailure, WorkspaceArtifact},
|
project::{self, ProjectArtifact, SourceFile, ToolFailure, WorkspaceArtifact},
|
||||||
sexpr::{Atom, SExpr, SExprKind},
|
sexpr::{Atom, SExpr, SExprKind},
|
||||||
types::Type,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> {
|
pub fn generate(input: &str, output_dir: &str) -> Result<(), ToolFailure> {
|
||||||
@ -61,23 +56,16 @@ fn render_project(
|
|||||||
artifact: &ProjectArtifact,
|
artifact: &ProjectArtifact,
|
||||||
sources: &[SourceFile],
|
sources: &[SourceFile],
|
||||||
) -> Result<String, ToolFailure> {
|
) -> Result<String, ToolFailure> {
|
||||||
let modules = sources
|
|
||||||
.iter()
|
|
||||||
.map(document_source)
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
out.push_str("# Project ");
|
out.push_str("# Project ");
|
||||||
out.push_str(&artifact.project_name);
|
out.push_str(&artifact.project_name);
|
||||||
out.push_str("\n\n");
|
out.push_str("\n\n");
|
||||||
if let Some(workspace) = &artifact.workspace {
|
if let Some(workspace) = &artifact.workspace {
|
||||||
render_workspace(&mut out, workspace);
|
render_workspace(&mut out, workspace);
|
||||||
render_workspace_package_public_api(&mut out, workspace, &modules);
|
|
||||||
} else {
|
|
||||||
render_project_package_public_api(&mut out, artifact, &modules);
|
|
||||||
}
|
}
|
||||||
for module in &modules {
|
for source in sources {
|
||||||
render_module(&mut out, module);
|
let module = document_source(source)?;
|
||||||
|
render_module(&mut out, &module);
|
||||||
}
|
}
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
@ -132,58 +120,27 @@ fn document_source(source: &SourceFile) -> Result<DocModule, ToolFailure> {
|
|||||||
sources: vec![source.clone()],
|
sources: vec![source.clone()],
|
||||||
artifact: None,
|
artifact: None,
|
||||||
})?;
|
})?;
|
||||||
let lowerable_forms = forms
|
let program = lower::lower_program(&source.path, &forms).ok();
|
||||||
.iter()
|
|
||||||
.filter(|form| !matches!(list_head(form), Some("import")))
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let program = lower::lower_program(&source.path, &lowerable_forms).ok();
|
|
||||||
Ok(module_from_forms(&source.path, &forms, program.as_ref()))
|
Ok(module_from_forms(&source.path, &forms, program.as_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DocModule {
|
struct DocModule {
|
||||||
path: String,
|
|
||||||
title: String,
|
title: String,
|
||||||
imports: Vec<String>,
|
imports: Vec<String>,
|
||||||
exports: Vec<String>,
|
exports: Vec<String>,
|
||||||
structs: Vec<String>,
|
structs: Vec<String>,
|
||||||
functions: Vec<String>,
|
functions: Vec<String>,
|
||||||
tests: Vec<String>,
|
tests: Vec<String>,
|
||||||
public_api: PublicApi,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct PublicApi {
|
|
||||||
functions: Vec<DocFunction>,
|
|
||||||
structs: Vec<DocStruct>,
|
|
||||||
enums: Vec<DocEnum>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DocFunction {
|
|
||||||
name: String,
|
|
||||||
signature: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DocStruct {
|
|
||||||
name: String,
|
|
||||||
fields: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DocEnum {
|
|
||||||
name: String,
|
|
||||||
variants: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_from_forms(file: &str, forms: &[SExpr], program: Option<&Program>) -> DocModule {
|
fn module_from_forms(file: &str, forms: &[SExpr], program: Option<&Program>) -> DocModule {
|
||||||
let mut module = DocModule {
|
let mut module = DocModule {
|
||||||
path: file.to_string(),
|
|
||||||
title: file.to_string(),
|
title: file.to_string(),
|
||||||
imports: Vec::new(),
|
imports: Vec::new(),
|
||||||
exports: Vec::new(),
|
exports: Vec::new(),
|
||||||
structs: Vec::new(),
|
structs: Vec::new(),
|
||||||
functions: Vec::new(),
|
functions: Vec::new(),
|
||||||
tests: Vec::new(),
|
tests: Vec::new(),
|
||||||
public_api: PublicApi::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for form in forms {
|
for form in forms {
|
||||||
@ -248,7 +205,6 @@ fn module_from_forms(file: &str, forms: &[SExpr], program: Option<&Program>) ->
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
module.tests = program.tests.iter().map(|test| test.name.clone()).collect();
|
module.tests = program.tests.iter().map(|test| test.name.clone()).collect();
|
||||||
module.public_api = public_api_from_program(program, &module.exports);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.imports.sort();
|
module.imports.sort();
|
||||||
@ -265,120 +221,11 @@ fn render_module(out: &mut String, module: &DocModule) {
|
|||||||
out.push_str("\n\n");
|
out.push_str("\n\n");
|
||||||
render_list(out, "Imports", &module.imports);
|
render_list(out, "Imports", &module.imports);
|
||||||
render_list(out, "Exports", &module.exports);
|
render_list(out, "Exports", &module.exports);
|
||||||
render_public_api_section(out, "###", &module.public_api);
|
|
||||||
render_list(out, "Structs", &module.structs);
|
render_list(out, "Structs", &module.structs);
|
||||||
render_list(out, "Functions", &module.functions);
|
render_list(out, "Functions", &module.functions);
|
||||||
render_list(out, "Tests", &module.tests);
|
render_list(out, "Tests", &module.tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_project_package_public_api(
|
|
||||||
out: &mut String,
|
|
||||||
artifact: &ProjectArtifact,
|
|
||||||
modules: &[DocModule],
|
|
||||||
) {
|
|
||||||
let local_root = Path::new(&artifact.project_root).join(&artifact.source_root);
|
|
||||||
let local_modules = modules
|
|
||||||
.iter()
|
|
||||||
.filter(|module| Path::new(&module.path).starts_with(&local_root))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
render_package_public_api(out, &artifact.project_name, &local_modules);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_workspace_package_public_api(
|
|
||||||
out: &mut String,
|
|
||||||
workspace: &WorkspaceArtifact,
|
|
||||||
modules: &[DocModule],
|
|
||||||
) {
|
|
||||||
let by_path = modules
|
|
||||||
.iter()
|
|
||||||
.map(|module| (module.path.as_str(), module))
|
|
||||||
.collect::<BTreeMap<_, _>>();
|
|
||||||
|
|
||||||
for package in &workspace.packages {
|
|
||||||
let local_root = Path::new(&package.root).join(&package.source_root);
|
|
||||||
let package_modules = package
|
|
||||||
.modules
|
|
||||||
.iter()
|
|
||||||
.filter(|module| Path::new(&module.path).starts_with(&local_root))
|
|
||||||
.filter_map(|module| by_path.get(module.path.as_str()).copied())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
render_package_public_api(
|
|
||||||
out,
|
|
||||||
&format!("{} {}", package.name, package.version),
|
|
||||||
&package_modules,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_package_public_api(out: &mut String, package_name: &str, modules: &[&DocModule]) {
|
|
||||||
out.push_str("## Package API ");
|
|
||||||
out.push_str(package_name);
|
|
||||||
out.push_str("\n\n");
|
|
||||||
|
|
||||||
let public_modules = modules
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.filter(|module| !module.public_api.is_empty())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
if public_modules.is_empty() {
|
|
||||||
out.push_str("None.\n\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for module in public_modules {
|
|
||||||
out.push_str("### Module ");
|
|
||||||
out.push_str(&module.title);
|
|
||||||
out.push_str("\n\n");
|
|
||||||
render_public_api_body(out, "####", &module.public_api);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_public_api_section(out: &mut String, heading: &str, public_api: &PublicApi) {
|
|
||||||
out.push_str(heading);
|
|
||||||
out.push_str(" Public API\n\n");
|
|
||||||
render_public_api_body(out, "####", public_api);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_public_api_body(out: &mut String, heading: &str, public_api: &PublicApi) {
|
|
||||||
if public_api.is_empty() {
|
|
||||||
out.push_str("None.\n\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !public_api.functions.is_empty() {
|
|
||||||
out.push_str(heading);
|
|
||||||
out.push_str(" Functions\n");
|
|
||||||
for function in &public_api.functions {
|
|
||||||
render_code_bullet(out, &function.signature);
|
|
||||||
}
|
|
||||||
out.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
if !public_api.structs.is_empty() {
|
|
||||||
out.push_str(heading);
|
|
||||||
out.push_str(" Structs\n");
|
|
||||||
for struct_decl in &public_api.structs {
|
|
||||||
render_code_bullet(out, &format!("struct {}", struct_decl.name));
|
|
||||||
for field in &struct_decl.fields {
|
|
||||||
render_indented_code_bullet(out, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
if !public_api.enums.is_empty() {
|
|
||||||
out.push_str(heading);
|
|
||||||
out.push_str(" Enums\n");
|
|
||||||
for enum_decl in &public_api.enums {
|
|
||||||
render_code_bullet(out, &format!("enum {}", enum_decl.name));
|
|
||||||
for variant in &enum_decl.variants {
|
|
||||||
render_indented_code_bullet(out, variant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.push('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_list(out: &mut String, title: &str, values: &[String]) {
|
fn render_list(out: &mut String, title: &str, values: &[String]) {
|
||||||
out.push_str("### ");
|
out.push_str("### ");
|
||||||
out.push_str(title);
|
out.push_str(title);
|
||||||
@ -395,182 +242,6 @@ fn render_list(out: &mut String, title: &str, values: &[String]) {
|
|||||||
out.push('\n');
|
out.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_head(expr: &SExpr) -> Option<&str> {
|
|
||||||
list(expr).and_then(|items| items.first()).and_then(ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_code_bullet(out: &mut String, value: &str) {
|
|
||||||
out.push_str("- `");
|
|
||||||
out.push_str(&value.replace('`', "\\`"));
|
|
||||||
out.push_str("`\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_indented_code_bullet(out: &mut String, value: &str) {
|
|
||||||
out.push_str(" - `");
|
|
||||||
out.push_str(&value.replace('`', "\\`"));
|
|
||||||
out.push_str("`\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PublicApi {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.functions.is_empty() && self.structs.is_empty() && self.enums.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn public_api_from_program(program: &Program, exports: &[String]) -> PublicApi {
|
|
||||||
let export_names = exports.iter().cloned().collect::<BTreeSet<_>>();
|
|
||||||
let aliases = alias_targets(program);
|
|
||||||
|
|
||||||
let mut functions = program
|
|
||||||
.functions
|
|
||||||
.iter()
|
|
||||||
.filter(|function| export_names.contains(&function.name))
|
|
||||||
.map(|function| DocFunction {
|
|
||||||
name: function.name.clone(),
|
|
||||||
signature: function_signature(
|
|
||||||
&function.name,
|
|
||||||
function
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.map(|param| (param.name.as_str(), ¶m.ty)),
|
|
||||||
&function.return_type,
|
|
||||||
&aliases,
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
functions.sort_by(|left, right| left.name.cmp(&right.name));
|
|
||||||
|
|
||||||
let mut structs = program
|
|
||||||
.structs
|
|
||||||
.iter()
|
|
||||||
.filter(|struct_decl| export_names.contains(&struct_decl.name))
|
|
||||||
.map(|struct_decl| DocStruct {
|
|
||||||
name: struct_decl.name.clone(),
|
|
||||||
fields: struct_decl
|
|
||||||
.fields
|
|
||||||
.iter()
|
|
||||||
.map(|field| {
|
|
||||||
format!(
|
|
||||||
"{}: {}",
|
|
||||||
field.name,
|
|
||||||
display_public_type(&field.ty, &aliases)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
structs.sort_by(|left, right| left.name.cmp(&right.name));
|
|
||||||
|
|
||||||
let mut enums = program
|
|
||||||
.enums
|
|
||||||
.iter()
|
|
||||||
.filter(|enum_decl| export_names.contains(&enum_decl.name))
|
|
||||||
.map(|enum_decl| DocEnum {
|
|
||||||
name: enum_decl.name.clone(),
|
|
||||||
variants: enum_decl
|
|
||||||
.variants
|
|
||||||
.iter()
|
|
||||||
.map(|variant| match &variant.payload_ty {
|
|
||||||
Some(payload_ty) => {
|
|
||||||
format!(
|
|
||||||
"{}({})",
|
|
||||||
variant.name,
|
|
||||||
display_public_type(payload_ty, &aliases)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => variant.name.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
enums.sort_by(|left, right| left.name.cmp(&right.name));
|
|
||||||
|
|
||||||
PublicApi {
|
|
||||||
functions,
|
|
||||||
structs,
|
|
||||||
enums,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function_signature<'a>(
|
|
||||||
name: &str,
|
|
||||||
params: impl Iterator<Item = (&'a str, &'a Type)>,
|
|
||||||
return_type: &Type,
|
|
||||||
aliases: &BTreeMap<String, Type>,
|
|
||||||
) -> String {
|
|
||||||
let params = params
|
|
||||||
.map(|(name, ty)| format!("{}: {}", name, display_public_type(ty, aliases)))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
format!(
|
|
||||||
"fn {}({}) -> {}",
|
|
||||||
name,
|
|
||||||
params,
|
|
||||||
display_public_type(return_type, aliases)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alias_targets(program: &Program) -> BTreeMap<String, Type> {
|
|
||||||
let raw = program
|
|
||||||
.type_aliases
|
|
||||||
.iter()
|
|
||||||
.map(|alias| (alias.name.clone(), alias.target.clone()))
|
|
||||||
.collect::<BTreeMap<_, _>>();
|
|
||||||
raw.keys()
|
|
||||||
.map(|name| {
|
|
||||||
let mut visiting = BTreeSet::new();
|
|
||||||
(
|
|
||||||
name.clone(),
|
|
||||||
resolve_alias_type(&Type::Named(name.clone()), &raw, &mut visiting),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display_public_type(ty: &Type, aliases: &BTreeMap<String, Type>) -> String {
|
|
||||||
let mut visiting = BTreeSet::new();
|
|
||||||
resolve_alias_type(ty, aliases, &mut visiting).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_alias_type(
|
|
||||||
ty: &Type,
|
|
||||||
aliases: &BTreeMap<String, Type>,
|
|
||||||
visiting: &mut BTreeSet<String>,
|
|
||||||
) -> Type {
|
|
||||||
match ty {
|
|
||||||
Type::Named(name) => {
|
|
||||||
let Some(target) = aliases.get(name) else {
|
|
||||||
return ty.clone();
|
|
||||||
};
|
|
||||||
if !visiting.insert(name.clone()) {
|
|
||||||
return ty.clone();
|
|
||||||
}
|
|
||||||
let resolved = resolve_alias_type(target, aliases, visiting);
|
|
||||||
visiting.remove(name);
|
|
||||||
resolved
|
|
||||||
}
|
|
||||||
Type::Ptr(inner) => Type::Ptr(Box::new(resolve_alias_type(inner, aliases, visiting))),
|
|
||||||
Type::Array(inner, len) => {
|
|
||||||
Type::Array(Box::new(resolve_alias_type(inner, aliases, visiting)), *len)
|
|
||||||
}
|
|
||||||
Type::Vec(inner) => Type::Vec(Box::new(resolve_alias_type(inner, aliases, visiting))),
|
|
||||||
Type::Slice(inner) => Type::Slice(Box::new(resolve_alias_type(inner, aliases, visiting))),
|
|
||||||
Type::Option(inner) => Type::Option(Box::new(resolve_alias_type(inner, aliases, visiting))),
|
|
||||||
Type::Result(ok, err) => Type::Result(
|
|
||||||
Box::new(resolve_alias_type(ok, aliases, visiting)),
|
|
||||||
Box::new(resolve_alias_type(err, aliases, visiting)),
|
|
||||||
),
|
|
||||||
Type::I32
|
|
||||||
| Type::I64
|
|
||||||
| Type::U32
|
|
||||||
| Type::U64
|
|
||||||
| Type::F64
|
|
||||||
| Type::Bool
|
|
||||||
| Type::Unit
|
|
||||||
| Type::String => ty.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(expr: &SExpr) -> Option<&[SExpr]> {
|
fn list(expr: &SExpr) -> Option<&[SExpr]> {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
SExprKind::List(items) => Some(items),
|
SExprKind::List(items) => Some(items),
|
||||||
|
|||||||
@ -52,16 +52,6 @@ pub fn run_tests(
|
|||||||
test_runner::run(file, &checked, filter)
|
test_runner::run(file, &checked, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_tests(
|
|
||||||
file: &str,
|
|
||||||
source: &str,
|
|
||||||
filter: Option<&str>,
|
|
||||||
) -> Result<test_runner::TestRunSuccess, test_runner::TestRunFailure> {
|
|
||||||
let checked =
|
|
||||||
checked_program(file, source).map_err(test_runner::TestRunFailure::before_execution)?;
|
|
||||||
Ok(test_runner::list(&checked, filter))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn checked_program(file: &str, source: &str) -> Result<check::CheckedProgram, Vec<Diagnostic>> {
|
fn checked_program(file: &str, source: &str) -> Result<check::CheckedProgram, Vec<Diagnostic>> {
|
||||||
let tokens = lexer::lex(file, source)?;
|
let tokens = lexer::lex(file, source)?;
|
||||||
let forms = sexpr::parse(file, &tokens)?;
|
let forms = sexpr::parse(file, &tokens)?;
|
||||||
|
|||||||
@ -2,11 +2,6 @@ use std::collections::{HashMap, HashSet};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diag::Diagnostic,
|
diag::Diagnostic,
|
||||||
reserved::{
|
|
||||||
is_unsupported_generic_standard_library_call, unsupported_generic_function,
|
|
||||||
unsupported_generic_standard_library_call, unsupported_generic_type_alias,
|
|
||||||
unsupported_reserved_type_diagnostic,
|
|
||||||
},
|
|
||||||
sexpr::{Atom, SExpr, SExprKind},
|
sexpr::{Atom, SExpr, SExprKind},
|
||||||
std_runtime,
|
std_runtime,
|
||||||
token::Span,
|
token::Span,
|
||||||
@ -2501,6 +2496,138 @@ struct RenderedMatchPattern<'a> {
|
|||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsupported_reserved_type_diagnostic(file: &str, form: &SExpr) -> Option<Diagnostic> {
|
||||||
|
if let Some(name) = expect_ident(form) {
|
||||||
|
if is_generic_type_parameter_name(name) {
|
||||||
|
return Some(unsupported_generic_type_parameter(file, form.span, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = expect_list(form)?;
|
||||||
|
let head = items.first().and_then(expect_ident)?;
|
||||||
|
match head {
|
||||||
|
"map" => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedMapType",
|
||||||
|
"`map` types are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("supported concrete type")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint(
|
||||||
|
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"set" => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedSetType",
|
||||||
|
"`set` types are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("supported concrete type")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint(
|
||||||
|
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"vec" if items.len() != 2 => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeParameter",
|
||||||
|
"generic vector syntax is reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("(vec i32), (vec i64), (vec f64), (vec bool), or (vec string)")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint("choose one current concrete vector family explicitly"),
|
||||||
|
),
|
||||||
|
_ => items
|
||||||
|
.iter()
|
||||||
|
.find_map(|item| unsupported_reserved_type_diagnostic(file, item)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_function(file: &str, span: Span) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericFunction",
|
||||||
|
"generic function declarations are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("(fn name ((arg ConcreteType) ...) -> ConcreteType body...)")
|
||||||
|
.found("(type_params ...)")
|
||||||
|
.hint("write a concrete function for each currently supported type family")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_type_alias(file: &str, span: Span) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeAlias",
|
||||||
|
"parameterized type aliases are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("(type Alias ConcreteType)")
|
||||||
|
.found("(type_params ...)")
|
||||||
|
.hint("aliases remain transparent names for concrete supported target types")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_type_parameter(file: &str, span: Span, name: &str) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeParameter",
|
||||||
|
format!(
|
||||||
|
"generic type parameter `{}` is reserved but not supported in beta.9",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("concrete supported type")
|
||||||
|
.found(name.to_string())
|
||||||
|
.hint("use a concrete promoted type such as `i32`, `string`, or `(vec i32)`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_standard_library_call(file: &str, span: Span, name: &str) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericStandardLibraryCall",
|
||||||
|
format!(
|
||||||
|
"generic standard-library call `{}` is reserved but not supported in beta.9",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("promoted concrete standard-library function")
|
||||||
|
.found(name.to_string())
|
||||||
|
.hint("use current concrete families such as `std.vec.i32.empty`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unsupported_generic_standard_library_call(name: &str) -> bool {
|
||||||
|
matches!(name, "std.vec.empty" | "std.result.map")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_generic_type_parameter_name(name: &str) -> bool {
|
||||||
|
name.len() == 1 && name.bytes().all(|byte| byte.is_ascii_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_type_form(form: &SExpr) -> String {
|
||||||
|
match &form.kind {
|
||||||
|
SExprKind::Atom(Atom::Ident(name)) => name.clone(),
|
||||||
|
SExprKind::Atom(Atom::Int(value)) => value.to_string(),
|
||||||
|
SExprKind::Atom(Atom::I64(value)) => format!("{}i64", value),
|
||||||
|
SExprKind::Atom(Atom::U32(value)) => format!("{}u32", value),
|
||||||
|
SExprKind::Atom(Atom::U64(value)) => format!("{}u64", value),
|
||||||
|
SExprKind::Atom(Atom::Float(value)) => value.to_string(),
|
||||||
|
SExprKind::Atom(Atom::String(value)) => format!("{:?}", value),
|
||||||
|
SExprKind::Atom(Atom::Arrow) => "->".to_string(),
|
||||||
|
SExprKind::List(items) => {
|
||||||
|
let parts = items.iter().map(render_type_form).collect::<Vec<_>>();
|
||||||
|
format!("({})", parts.join(" "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_function_names(forms: &[SExpr]) -> HashSet<String> {
|
fn collect_function_names(forms: &[SExpr]) -> HashSet<String> {
|
||||||
let mut names = HashSet::new();
|
let mut names = HashSet::new();
|
||||||
for form in forms {
|
for form in forms {
|
||||||
|
|||||||
@ -26,10 +26,6 @@ pub fn emit(_file: &str, program: &CheckedProgram) -> Result<String, Vec<Diagnos
|
|||||||
out.push_str("declare void @print_bool(i1)\n\n");
|
out.push_str("declare void @print_bool(i1)\n\n");
|
||||||
out.push_str("declare i32 @string_len(ptr)\n\n");
|
out.push_str("declare i32 @string_len(ptr)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_string_concat(ptr, ptr)\n\n");
|
out.push_str("declare ptr @__glagol_string_concat(ptr, ptr)\n\n");
|
||||||
out.push_str("declare i64 @__glagol_string_byte_at_result(ptr, i32)\n\n");
|
|
||||||
out.push_str("declare ptr @__glagol_string_slice_result(ptr, i32, i32)\n\n");
|
|
||||||
out.push_str("declare i1 @__glagol_string_starts_with(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare i1 @__glagol_string_ends_with(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare i64 @__glagol_string_parse_i32_result(ptr)\n\n");
|
out.push_str("declare i64 @__glagol_string_parse_i32_result(ptr)\n\n");
|
||||||
out.push_str("declare i32 @__glagol_string_parse_i64_result(ptr, ptr)\n\n");
|
out.push_str("declare i32 @__glagol_string_parse_i64_result(ptr, ptr)\n\n");
|
||||||
out.push_str("declare i64 @__glagol_string_parse_u32_result(ptr)\n\n");
|
out.push_str("declare i64 @__glagol_string_parse_u32_result(ptr)\n\n");
|
||||||
@ -37,13 +33,6 @@ pub fn emit(_file: &str, program: &CheckedProgram) -> Result<String, Vec<Diagnos
|
|||||||
out.push_str("declare i32 @__glagol_string_parse_f64_result(ptr, ptr)\n\n");
|
out.push_str("declare i32 @__glagol_string_parse_f64_result(ptr, ptr)\n\n");
|
||||||
out.push_str("declare i32 @__glagol_string_parse_bool_result(ptr, ptr)\n\n");
|
out.push_str("declare i32 @__glagol_string_parse_bool_result(ptr, ptr)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_json_quote_string(ptr)\n\n");
|
out.push_str("declare ptr @__glagol_json_quote_string(ptr)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_json_parse_string_value_result(ptr)\n\n");
|
|
||||||
out.push_str("declare i32 @__glagol_json_parse_bool_value_result(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare i64 @__glagol_json_parse_i32_value_result(ptr)\n\n");
|
|
||||||
out.push_str("declare i64 @__glagol_json_parse_u32_value_result(ptr)\n\n");
|
|
||||||
out.push_str("declare i32 @__glagol_json_parse_i64_value_result(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare i32 @__glagol_json_parse_u64_value_result(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare i32 @__glagol_json_parse_f64_value_result(ptr, ptr)\n\n");
|
|
||||||
out.push_str("declare ptr @__glagol_num_i32_to_string(i32)\n\n");
|
out.push_str("declare ptr @__glagol_num_i32_to_string(i32)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_num_i64_to_string(i64)\n\n");
|
out.push_str("declare ptr @__glagol_num_i64_to_string(i64)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_num_u32_to_string(i32)\n\n");
|
out.push_str("declare ptr @__glagol_num_u32_to_string(i32)\n\n");
|
||||||
@ -1682,8 +1671,6 @@ impl FunctionGen<'_> {
|
|||||||
| "__glagol_fs_read_open_text_result"
|
| "__glagol_fs_read_open_text_result"
|
||||||
| "__glagol_net_tcp_read_all_result"
|
| "__glagol_net_tcp_read_all_result"
|
||||||
| "__glagol_io_read_stdin_result"
|
| "__glagol_io_read_stdin_result"
|
||||||
| "__glagol_string_slice_result"
|
|
||||||
| "__glagol_json_parse_string_value_result"
|
|
||||||
) {
|
) {
|
||||||
return self.emit_string_result_host_call(expr, callee, &arg_values);
|
return self.emit_string_result_host_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
@ -1704,39 +1691,27 @@ impl FunctionGen<'_> {
|
|||||||
|| callee == "__glagol_net_tcp_bound_port_result"
|
|| callee == "__glagol_net_tcp_bound_port_result"
|
||||||
|| callee == "__glagol_net_tcp_accept_result"
|
|| callee == "__glagol_net_tcp_accept_result"
|
||||||
|| callee == "__glagol_string_parse_i32_result"
|
|| callee == "__glagol_string_parse_i32_result"
|
||||||
|| callee == "__glagol_json_parse_i32_value_result"
|
|
||||||
|| callee == "__glagol_string_byte_at_result"
|
|
||||||
{
|
{
|
||||||
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_string_parse_u32_result"
|
if callee == "__glagol_string_parse_u32_result" {
|
||||||
|| callee == "__glagol_json_parse_u32_value_result"
|
|
||||||
{
|
|
||||||
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_string_parse_i64_result"
|
if callee == "__glagol_string_parse_i64_result" {
|
||||||
|| callee == "__glagol_json_parse_i64_value_result"
|
|
||||||
{
|
|
||||||
return self.emit_i64_result_out_param_call(expr, callee, &arg_values);
|
return self.emit_i64_result_out_param_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_string_parse_u64_result"
|
if callee == "__glagol_string_parse_u64_result" {
|
||||||
|| callee == "__glagol_json_parse_u64_value_result"
|
|
||||||
{
|
|
||||||
return self.emit_i64_result_out_param_call(expr, callee, &arg_values);
|
return self.emit_i64_result_out_param_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_string_parse_f64_result"
|
if callee == "__glagol_string_parse_f64_result" {
|
||||||
|| callee == "__glagol_json_parse_f64_value_result"
|
|
||||||
{
|
|
||||||
return self.emit_f64_result_out_param_call(expr, callee, &arg_values);
|
return self.emit_f64_result_out_param_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_string_parse_bool_result"
|
if callee == "__glagol_string_parse_bool_result" {
|
||||||
|| callee == "__glagol_json_parse_bool_value_result"
|
|
||||||
{
|
|
||||||
return self.emit_bool_result_out_param_call(expr, callee, &arg_values);
|
return self.emit_bool_result_out_param_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,6 @@ use crate::{
|
|||||||
Test, TypeAliasDecl,
|
Test, TypeAliasDecl,
|
||||||
},
|
},
|
||||||
diag::Diagnostic,
|
diag::Diagnostic,
|
||||||
reserved::{
|
|
||||||
is_unsupported_generic_standard_library_call, unsupported_generic_function,
|
|
||||||
unsupported_generic_standard_library_call, unsupported_generic_type_alias,
|
|
||||||
unsupported_reserved_type_diagnostic,
|
|
||||||
},
|
|
||||||
sexpr::{Atom, SExpr, SExprKind},
|
sexpr::{Atom, SExpr, SExprKind},
|
||||||
token::Span,
|
token::Span,
|
||||||
types::Type,
|
types::Type,
|
||||||
@ -2541,6 +2536,138 @@ fn invalid_type_diagnostic(
|
|||||||
diagnostic
|
diagnostic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsupported_reserved_type_diagnostic(file: &str, form: &SExpr) -> Option<Diagnostic> {
|
||||||
|
if let Some(name) = expect_ident(form) {
|
||||||
|
if is_generic_type_parameter_name(name) {
|
||||||
|
return Some(unsupported_generic_type_parameter(file, form.span, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = expect_list(form)?;
|
||||||
|
let head = items.first().and_then(expect_ident)?;
|
||||||
|
match head {
|
||||||
|
"map" => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedMapType",
|
||||||
|
"`map` types are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("supported concrete type")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint(
|
||||||
|
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"set" => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedSetType",
|
||||||
|
"`set` types are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("supported concrete type")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint(
|
||||||
|
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"vec" if items.len() != 2 => Some(
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeParameter",
|
||||||
|
"generic vector syntax is reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(form.span)
|
||||||
|
.expected("(vec i32), (vec i64), (vec f64), (vec bool), or (vec string)")
|
||||||
|
.found(render_type_form(form))
|
||||||
|
.hint("choose one current concrete vector family explicitly"),
|
||||||
|
),
|
||||||
|
_ => items
|
||||||
|
.iter()
|
||||||
|
.find_map(|item| unsupported_reserved_type_diagnostic(file, item)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_function(file: &str, span: Span) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericFunction",
|
||||||
|
"generic function declarations are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("(fn name ((arg ConcreteType) ...) -> ConcreteType body...)")
|
||||||
|
.found("(type_params ...)")
|
||||||
|
.hint("write a concrete function for each currently supported type family")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_type_alias(file: &str, span: Span) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeAlias",
|
||||||
|
"parameterized type aliases are reserved but not supported in beta.9",
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("(type Alias ConcreteType)")
|
||||||
|
.found("(type_params ...)")
|
||||||
|
.hint("aliases remain transparent names for concrete supported target types")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_type_parameter(file: &str, span: Span, name: &str) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericTypeParameter",
|
||||||
|
format!(
|
||||||
|
"generic type parameter `{}` is reserved but not supported in beta.9",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("concrete supported type")
|
||||||
|
.found(name.to_string())
|
||||||
|
.hint("use a concrete promoted type such as `i32`, `string`, or `(vec i32)`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsupported_generic_standard_library_call(file: &str, span: Span, name: &str) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
file,
|
||||||
|
"UnsupportedGenericStandardLibraryCall",
|
||||||
|
format!(
|
||||||
|
"generic standard-library call `{}` is reserved but not supported in beta.9",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_span(span)
|
||||||
|
.expected("promoted concrete standard-library function")
|
||||||
|
.found(name.to_string())
|
||||||
|
.hint("use current concrete families such as `std.vec.i32.empty`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unsupported_generic_standard_library_call(name: &str) -> bool {
|
||||||
|
matches!(name, "std.vec.empty" | "std.result.map")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_generic_type_parameter_name(name: &str) -> bool {
|
||||||
|
name.len() == 1 && name.bytes().all(|byte| byte.is_ascii_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_type_form(form: &SExpr) -> String {
|
||||||
|
match &form.kind {
|
||||||
|
SExprKind::Atom(Atom::Ident(name)) => name.clone(),
|
||||||
|
SExprKind::Atom(Atom::Int(value)) => value.to_string(),
|
||||||
|
SExprKind::Atom(Atom::I64(value)) => format!("{}i64", value),
|
||||||
|
SExprKind::Atom(Atom::U32(value)) => format!("{}u32", value),
|
||||||
|
SExprKind::Atom(Atom::U64(value)) => format!("{}u64", value),
|
||||||
|
SExprKind::Atom(Atom::Float(value)) => value.to_string(),
|
||||||
|
SExprKind::Atom(Atom::String(value)) => format!("{:?}", value),
|
||||||
|
SExprKind::Atom(Atom::Arrow) => "->".to_string(),
|
||||||
|
SExprKind::List(items) => {
|
||||||
|
let parts = items.iter().map(render_type_form).collect::<Vec<_>>();
|
||||||
|
format!("({})", parts.join(" "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn list_head(form: &SExpr) -> Option<&str> {
|
fn list_head(form: &SExpr) -> Option<&str> {
|
||||||
let items = expect_list(form)?;
|
let items = expect_list(form)?;
|
||||||
let first = items.first()?;
|
let first = items.first()?;
|
||||||
|
|||||||
@ -8,7 +8,6 @@ mod lexer;
|
|||||||
mod llvm;
|
mod llvm;
|
||||||
mod lower;
|
mod lower;
|
||||||
mod project;
|
mod project;
|
||||||
mod reserved;
|
|
||||||
mod scaffold;
|
mod scaffold;
|
||||||
mod sexpr;
|
mod sexpr;
|
||||||
mod std_runtime;
|
mod std_runtime;
|
||||||
@ -24,11 +23,8 @@ use std::{
|
|||||||
panic::{self, AssertUnwindSafe},
|
panic::{self, AssertUnwindSafe},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::{self, Command as ProcessCommand},
|
process::{self, Command as ProcessCommand},
|
||||||
thread,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEST_RUNNER_THREAD_STACK_SIZE: usize = 16 * 1024 * 1024;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let raw_args = env::args().collect::<Vec<_>>();
|
let raw_args = env::args().collect::<Vec<_>>();
|
||||||
let command_line = raw_args.join(" ");
|
let command_line = raw_args.join(" ");
|
||||||
@ -54,29 +50,9 @@ fn run_invocation_guarded(invocation: Invocation) -> ! {
|
|||||||
panic::set_hook(Box::new(|_| {}));
|
panic::set_hook(Box::new(|_| {}));
|
||||||
|
|
||||||
let run_invocation = invocation.clone();
|
let run_invocation = invocation.clone();
|
||||||
let result = if invocation.mode == Mode::RunTests {
|
let result = panic::catch_unwind(AssertUnwindSafe(move || {
|
||||||
let thread_invocation = run_invocation.clone();
|
run_invocation_inner(run_invocation);
|
||||||
match thread::Builder::new()
|
}));
|
||||||
.name("glagol-test-runner".to_string())
|
|
||||||
.stack_size(TEST_RUNNER_THREAD_STACK_SIZE)
|
|
||||||
.spawn(move || {
|
|
||||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
|
||||||
run_invocation_inner(thread_invocation);
|
|
||||||
}))
|
|
||||||
}) {
|
|
||||||
Ok(handle) => match handle.join() {
|
|
||||||
Ok(result) => result,
|
|
||||||
Err(payload) => Err(payload),
|
|
||||||
},
|
|
||||||
Err(_) => panic::catch_unwind(AssertUnwindSafe(move || {
|
|
||||||
run_invocation_inner(run_invocation);
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
|
||||||
run_invocation_inner(run_invocation);
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
|
|
||||||
panic::set_hook(previous_hook);
|
panic::set_hook(previous_hook);
|
||||||
|
|
||||||
@ -184,13 +160,7 @@ fn run_project_check(invocation: Invocation) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_project_test(invocation: Invocation) -> ! {
|
fn run_project_test(invocation: Invocation) -> ! {
|
||||||
let result = if invocation.test_list {
|
match project::run_tests(&invocation.path, invocation.test_filter.as_deref()) {
|
||||||
project::list_tests(&invocation.path, invocation.test_filter.as_deref())
|
|
||||||
} else {
|
|
||||||
project::run_tests(&invocation.path, invocation.test_filter.as_deref())
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(success) => {
|
Ok(success) => {
|
||||||
let output = success.output;
|
let output = success.output;
|
||||||
let primary_output = if let Some(output_path) = invocation.output_path.as_deref() {
|
let primary_output = if let Some(output_path) = invocation.output_path.as_deref() {
|
||||||
@ -685,13 +655,7 @@ fn finish_formatted_source(
|
|||||||
|
|
||||||
fn run_test_mode(invocation: Invocation, source: &str) -> ! {
|
fn run_test_mode(invocation: Invocation, source: &str) -> ! {
|
||||||
let foreign_imports = c_imports_for_manifest(&invocation.path, source);
|
let foreign_imports = c_imports_for_manifest(&invocation.path, source);
|
||||||
let result = if invocation.test_list {
|
match driver::run_tests(&invocation.path, source, invocation.test_filter.as_deref()) {
|
||||||
driver::list_tests(&invocation.path, source, invocation.test_filter.as_deref())
|
|
||||||
} else {
|
|
||||||
driver::run_tests(&invocation.path, source, invocation.test_filter.as_deref())
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let output = result.output;
|
let output = result.output;
|
||||||
let primary_output = if let Some(output_path) = invocation.output_path.as_deref() {
|
let primary_output = if let Some(output_path) = invocation.output_path.as_deref() {
|
||||||
@ -892,15 +856,14 @@ fn run_native_from_llvm(
|
|||||||
let _ = io::stdout().write_all(&run_output.stdout);
|
let _ = io::stdout().write_all(&run_output.stdout);
|
||||||
let _ = io::stderr().write_all(&run_output.stderr);
|
let _ = io::stderr().write_all(&run_output.stderr);
|
||||||
let stdout = String::from_utf8_lossy(&run_output.stdout).to_string();
|
let stdout = String::from_utf8_lossy(&run_output.stdout).to_string();
|
||||||
let stderr = String::from_utf8_lossy(&run_output.stderr).to_string();
|
write_manifest_if_requested_with_foreign_imports(
|
||||||
let exit_status = run_output.status.code();
|
|
||||||
write_manifest_if_requested_with_run_report(
|
|
||||||
&invocation,
|
&invocation,
|
||||||
run_output.status.success(),
|
run_output.status.success(),
|
||||||
PrimaryOutput::Stdout {
|
PrimaryOutput::Stdout {
|
||||||
kind: Mode::Run.output_kind(),
|
kind: Mode::Run.output_kind(),
|
||||||
text: &stdout,
|
text: &stdout,
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
Some(BuildInfo {
|
Some(BuildInfo {
|
||||||
clang: &native.clang,
|
clang: &native.clang,
|
||||||
runtime: &native.runtime,
|
runtime: &native.runtime,
|
||||||
@ -908,14 +871,8 @@ fn run_native_from_llvm(
|
|||||||
}),
|
}),
|
||||||
&foreign_imports,
|
&foreign_imports,
|
||||||
project_artifact.as_ref(),
|
project_artifact.as_ref(),
|
||||||
RunReport {
|
|
||||||
exit_status,
|
|
||||||
stdout: &stdout,
|
|
||||||
stderr: &stderr,
|
|
||||||
args: &invocation.run_args,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
process::exit(exit_status.unwrap_or(1));
|
process::exit(run_output.status.code().unwrap_or(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NativeBuild {
|
struct NativeBuild {
|
||||||
@ -1120,7 +1077,6 @@ struct Invocation {
|
|||||||
project_template: scaffold::ProjectTemplate,
|
project_template: scaffold::ProjectTemplate,
|
||||||
link_c_paths: Vec<String>,
|
link_c_paths: Vec<String>,
|
||||||
test_filter: Option<String>,
|
test_filter: Option<String>,
|
||||||
test_list: bool,
|
|
||||||
run_args: Vec<String>,
|
run_args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,7 +1113,6 @@ fn parse_args(raw_args: &[String]) -> Result<Args, ParseError> {
|
|||||||
let mut project_template = scaffold::ProjectTemplate::Binary;
|
let mut project_template = scaffold::ProjectTemplate::Binary;
|
||||||
let mut link_c_paths = Vec::new();
|
let mut link_c_paths = Vec::new();
|
||||||
let mut test_filter = None;
|
let mut test_filter = None;
|
||||||
let mut test_list = false;
|
|
||||||
let mut run_args = Vec::new();
|
let mut run_args = Vec::new();
|
||||||
let mut no_color = false;
|
let mut no_color = false;
|
||||||
let command_line = raw_args.join(" ");
|
let command_line = raw_args.join(" ");
|
||||||
@ -1366,17 +1321,6 @@ fn parse_args(raw_args: &[String]) -> Result<Args, ParseError> {
|
|||||||
command_line: command_line.clone(),
|
command_line: command_line.clone(),
|
||||||
})?);
|
})?);
|
||||||
}
|
}
|
||||||
"--list" => {
|
|
||||||
if test_list {
|
|
||||||
return parse_error(
|
|
||||||
"`--list` was provided more than once",
|
|
||||||
manifest_path,
|
|
||||||
diagnostics,
|
|
||||||
command_line,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
test_list = true;
|
|
||||||
}
|
|
||||||
"check" | "fmt" | "test" | "build" | "run" | "clean" | "new" | "doc" | "symbols"
|
"check" | "fmt" | "test" | "build" | "run" | "clean" | "new" | "doc" | "symbols"
|
||||||
if path.is_none() =>
|
if path.is_none() =>
|
||||||
{
|
{
|
||||||
@ -1496,15 +1440,6 @@ fn parse_args(raw_args: &[String]) -> Result<Args, ParseError> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if test_list && mode != Mode::RunTests {
|
|
||||||
return parse_error(
|
|
||||||
"`--list` is only supported with `test` and `--run-tests`",
|
|
||||||
manifest_path,
|
|
||||||
diagnostics,
|
|
||||||
command_line,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !run_args.is_empty() && mode != Mode::Run {
|
if !run_args.is_empty() && mode != Mode::Run {
|
||||||
return parse_error(
|
return parse_error(
|
||||||
"`--` program arguments are only supported with `run`",
|
"`--` program arguments are only supported with `run`",
|
||||||
@ -1556,7 +1491,6 @@ fn parse_args(raw_args: &[String]) -> Result<Args, ParseError> {
|
|||||||
project_template,
|
project_template,
|
||||||
link_c_paths,
|
link_c_paths,
|
||||||
test_filter,
|
test_filter,
|
||||||
test_list,
|
|
||||||
run_args,
|
run_args,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -1630,7 +1564,6 @@ fn exit_parse_error(err: ParseError, command_line: &str) -> ! {
|
|||||||
project_template: scaffold::ProjectTemplate::Binary,
|
project_template: scaffold::ProjectTemplate::Binary,
|
||||||
link_c_paths: Vec::new(),
|
link_c_paths: Vec::new(),
|
||||||
test_filter: None,
|
test_filter: None,
|
||||||
test_list: false,
|
|
||||||
run_args: Vec::new(),
|
run_args: Vec::new(),
|
||||||
};
|
};
|
||||||
write_manifest_or_exit(
|
write_manifest_or_exit(
|
||||||
@ -1643,7 +1576,6 @@ fn exit_parse_error(err: ParseError, command_line: &str) -> ! {
|
|||||||
PrimaryOutput::Diagnostics { text: &stderr },
|
PrimaryOutput::Diagnostics { text: &stderr },
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
err.diagnostics,
|
err.diagnostics,
|
||||||
@ -1897,13 +1829,6 @@ struct TestSummary {
|
|||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RunReport<'a> {
|
|
||||||
exit_status: Option<i32>,
|
|
||||||
stdout: &'a str,
|
|
||||||
stderr: &'a str,
|
|
||||||
args: &'a [String],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_summary_from_report(report: test_runner::TestReport) -> TestSummary {
|
fn test_summary_from_report(report: test_runner::TestReport) -> TestSummary {
|
||||||
TestSummary {
|
TestSummary {
|
||||||
total_discovered: report.total_discovered,
|
total_discovered: report.total_discovered,
|
||||||
@ -2006,34 +1931,6 @@ fn write_manifest_if_requested_with_foreign_imports(
|
|||||||
success,
|
success,
|
||||||
primary_output,
|
primary_output,
|
||||||
test_summary,
|
test_summary,
|
||||||
None,
|
|
||||||
build_info,
|
|
||||||
foreign_imports,
|
|
||||||
project_info,
|
|
||||||
invocation.diagnostics,
|
|
||||||
);
|
|
||||||
write_manifest_or_exit(manifest_path, &manifest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_manifest_if_requested_with_run_report(
|
|
||||||
invocation: &Invocation,
|
|
||||||
success: bool,
|
|
||||||
primary_output: PrimaryOutput<'_>,
|
|
||||||
build_info: Option<BuildInfo<'_>>,
|
|
||||||
foreign_imports: &[project::ProjectArtifactCImport],
|
|
||||||
project_info: Option<&project::ProjectArtifact>,
|
|
||||||
run_report: RunReport<'_>,
|
|
||||||
) {
|
|
||||||
if let Some(manifest_path) = invocation.manifest_path.as_deref() {
|
|
||||||
let manifest = render_manifest(
|
|
||||||
Some(&invocation.path),
|
|
||||||
&invocation.command_line,
|
|
||||||
Some(invocation.manifest_mode_name.as_str()),
|
|
||||||
success,
|
|
||||||
primary_output,
|
|
||||||
None,
|
|
||||||
Some(run_report),
|
|
||||||
build_info,
|
build_info,
|
||||||
foreign_imports,
|
foreign_imports,
|
||||||
project_info,
|
project_info,
|
||||||
@ -2057,7 +1954,6 @@ fn render_manifest(
|
|||||||
success: bool,
|
success: bool,
|
||||||
primary_output: PrimaryOutput<'_>,
|
primary_output: PrimaryOutput<'_>,
|
||||||
test_summary: Option<TestSummary>,
|
test_summary: Option<TestSummary>,
|
||||||
run_report: Option<RunReport<'_>>,
|
|
||||||
build_info: Option<BuildInfo<'_>>,
|
build_info: Option<BuildInfo<'_>>,
|
||||||
foreign_imports: &[project::ProjectArtifactCImport],
|
foreign_imports: &[project::ProjectArtifactCImport],
|
||||||
project_info: Option<&project::ProjectArtifact>,
|
project_info: Option<&project::ProjectArtifact>,
|
||||||
@ -2081,10 +1977,7 @@ fn render_manifest(
|
|||||||
" (success {})\n",
|
" (success {})\n",
|
||||||
if success { "true" } else { "false" }
|
if success { "true" } else { "false" }
|
||||||
));
|
));
|
||||||
out.push_str(&format!(
|
out.push_str(" (diagnostics-schema-version 1)\n");
|
||||||
" (diagnostics-schema-version {})\n",
|
|
||||||
diag::DIAGNOSTIC_SCHEMA_VERSION
|
|
||||||
));
|
|
||||||
out.push_str(&format!(
|
out.push_str(&format!(
|
||||||
" (diagnostics-encoding {})\n",
|
" (diagnostics-encoding {})\n",
|
||||||
match diagnostics {
|
match diagnostics {
|
||||||
@ -2159,34 +2052,6 @@ fn render_manifest(
|
|||||||
out.push_str(" )");
|
out.push_str(" )");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(report) = run_report {
|
|
||||||
out.push('\n');
|
|
||||||
out.push_str(" (run-report\n");
|
|
||||||
match report.exit_status {
|
|
||||||
Some(status) => out.push_str(&format!(" (exit-status {})\n", status)),
|
|
||||||
None => out.push_str(" (exit-status null)\n"),
|
|
||||||
}
|
|
||||||
out.push_str(&format!(
|
|
||||||
" (stdout {})\n",
|
|
||||||
diag::render_string(report.stdout)
|
|
||||||
));
|
|
||||||
out.push_str(&format!(
|
|
||||||
" (stderr {})\n",
|
|
||||||
diag::render_string(report.stderr)
|
|
||||||
));
|
|
||||||
out.push_str(" (args");
|
|
||||||
if report.args.is_empty() {
|
|
||||||
out.push_str(")\n");
|
|
||||||
} else {
|
|
||||||
out.push('\n');
|
|
||||||
for arg in report.args {
|
|
||||||
out.push_str(&format!(" (arg {})\n", diag::render_string(arg)));
|
|
||||||
}
|
|
||||||
out.push_str(" )\n");
|
|
||||||
}
|
|
||||||
out.push_str(" )");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(build) = build_info {
|
if let Some(build) = build_info {
|
||||||
out.push('\n');
|
out.push('\n');
|
||||||
out.push_str(" (hosted-build\n");
|
out.push_str(" (hosted-build\n");
|
||||||
@ -2675,6 +2540,6 @@ fn normalized_output_path(path: &str) -> Option<PathBuf> {
|
|||||||
|
|
||||||
fn print_usage() {
|
fn print_usage() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"usage: glagol [check|fmt|test|build|run|clean|symbols] [--json-diagnostics] [--no-color] [--manifest <path>] [--link-c <path>] [-o <path>] [--filter <substring>] [--list] <file.slo|project> [-- <program-args>...]\n glagol fmt [--check|--write] <file.slo|project>\n glagol new <project-dir> [--name <name>] [--template binary|library|workspace]\n glagol doc <file.slo|project> -o <dir>\n glagol symbols <file.slo|project|workspace>\n glagol [--emit=llvm|--format|--print-tree|--inspect-lowering=surface|--inspect-lowering=checked|--check-tests|--run-tests] [--json-diagnostics] [--no-color] [-o <path>] [--manifest <path>] [--filter <substring>] [--list] <file.slo>\n glagol --version"
|
"usage: glagol [check|fmt|test|build|run|clean|symbols] [--json-diagnostics] [--no-color] [--manifest <path>] [--link-c <path>] [-o <path>] [--filter <substring>] <file.slo|project> [-- <program-args>...]\n glagol fmt [--check|--write] <file.slo|project>\n glagol new <project-dir> [--name <name>] [--template binary|library|workspace]\n glagol doc <file.slo|project> -o <dir>\n glagol symbols <file.slo|project|workspace>\n glagol [--emit=llvm|--format|--print-tree|--inspect-lowering=surface|--inspect-lowering=checked|--check-tests|--run-tests] [--json-diagnostics] [--no-color] [-o <path>] [--manifest <path>] [--filter <substring>] <file.slo>\n glagol --version"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -452,26 +452,6 @@ pub fn run_tests(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_tests(
|
|
||||||
input: &str,
|
|
||||||
filter: Option<&str>,
|
|
||||||
) -> Result<ProjectTestSuccess, ProjectTestFailure> {
|
|
||||||
let checked = load_checked_project(input, false).map_err(|failure| ProjectTestFailure {
|
|
||||||
diagnostics: failure.diagnostics,
|
|
||||||
report: None,
|
|
||||||
sources: failure.sources,
|
|
||||||
artifact: failure.artifact,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let success = test_runner::list(&checked.program, filter);
|
|
||||||
Ok(ProjectTestSuccess {
|
|
||||||
output: success.output,
|
|
||||||
report: success.report,
|
|
||||||
sources: checked.sources,
|
|
||||||
artifact: checked.artifact,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CheckedProject {
|
struct CheckedProject {
|
||||||
program: CheckedProgram,
|
program: CheckedProgram,
|
||||||
sources: Vec<SourceFile>,
|
sources: Vec<SourceFile>,
|
||||||
@ -1124,16 +1104,7 @@ fn parse_manifest(path: PathBuf, source: String) -> Result<Manifest, Vec<Diagnos
|
|||||||
};
|
};
|
||||||
|
|
||||||
match key {
|
match key {
|
||||||
"name" => set_manifest_key(
|
"name" => set_manifest_key(&file, &mut errors, &mut name, parsed, line.span, "name"),
|
||||||
&file,
|
|
||||||
&mut errors,
|
|
||||||
&mut name,
|
|
||||||
parsed,
|
|
||||||
line.span,
|
|
||||||
"name",
|
|
||||||
"ProjectManifestInvalid",
|
|
||||||
"project",
|
|
||||||
),
|
|
||||||
"source_root" => set_manifest_key(
|
"source_root" => set_manifest_key(
|
||||||
&file,
|
&file,
|
||||||
&mut errors,
|
&mut errors,
|
||||||
@ -1141,19 +1112,8 @@ fn parse_manifest(path: PathBuf, source: String) -> Result<Manifest, Vec<Diagnos
|
|||||||
parsed,
|
parsed,
|
||||||
line.span,
|
line.span,
|
||||||
"source_root",
|
"source_root",
|
||||||
"ProjectManifestInvalid",
|
|
||||||
"project",
|
|
||||||
),
|
|
||||||
"entry" => set_manifest_key(
|
|
||||||
&file,
|
|
||||||
&mut errors,
|
|
||||||
&mut entry,
|
|
||||||
parsed,
|
|
||||||
line.span,
|
|
||||||
"entry",
|
|
||||||
"ProjectManifestInvalid",
|
|
||||||
"project",
|
|
||||||
),
|
),
|
||||||
|
"entry" => set_manifest_key(&file, &mut errors, &mut entry, parsed, line.span, "entry"),
|
||||||
_ => errors.push(
|
_ => errors.push(
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
&file,
|
&file,
|
||||||
@ -1432,7 +1392,6 @@ fn parse_package_manifest(
|
|||||||
let mut source_root = None::<String>;
|
let mut source_root = None::<String>;
|
||||||
let mut entry = None::<String>;
|
let mut entry = None::<String>;
|
||||||
let mut dependencies = Vec::new();
|
let mut dependencies = Vec::new();
|
||||||
let mut dependency_keys = BTreeSet::<String>::new();
|
|
||||||
|
|
||||||
for line in manifest_lines(&source) {
|
for line in manifest_lines(&source) {
|
||||||
let trimmed = line.text.trim();
|
let trimmed = line.text.trim();
|
||||||
@ -1510,8 +1469,6 @@ fn parse_package_manifest(
|
|||||||
parsed,
|
parsed,
|
||||||
line.span,
|
line.span,
|
||||||
"name",
|
"name",
|
||||||
"PackageManifestInvalid",
|
|
||||||
"package",
|
|
||||||
),
|
),
|
||||||
"version" => set_manifest_key(
|
"version" => set_manifest_key(
|
||||||
&file,
|
&file,
|
||||||
@ -1520,8 +1477,6 @@ fn parse_package_manifest(
|
|||||||
parsed,
|
parsed,
|
||||||
line.span,
|
line.span,
|
||||||
"version",
|
"version",
|
||||||
"PackageManifestInvalid",
|
|
||||||
"package",
|
|
||||||
),
|
),
|
||||||
"source_root" => set_manifest_key(
|
"source_root" => set_manifest_key(
|
||||||
&file,
|
&file,
|
||||||
@ -1530,8 +1485,6 @@ fn parse_package_manifest(
|
|||||||
parsed,
|
parsed,
|
||||||
line.span,
|
line.span,
|
||||||
"source_root",
|
"source_root",
|
||||||
"PackageManifestInvalid",
|
|
||||||
"package",
|
|
||||||
),
|
),
|
||||||
"entry" => set_manifest_key(
|
"entry" => set_manifest_key(
|
||||||
&file,
|
&file,
|
||||||
@ -1540,8 +1493,6 @@ fn parse_package_manifest(
|
|||||||
parsed,
|
parsed,
|
||||||
line.span,
|
line.span,
|
||||||
"entry",
|
"entry",
|
||||||
"PackageManifestInvalid",
|
|
||||||
"package",
|
|
||||||
),
|
),
|
||||||
other => errors.push(
|
other => errors.push(
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
@ -1553,54 +1504,21 @@ fn parse_package_manifest(
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"dependencies" => {
|
"dependencies" => match parse_dependency_path(value) {
|
||||||
let valid_key = if is_project_name(key) {
|
Some(path) => dependencies.push(PackageDependency {
|
||||||
true
|
key: key.to_string(),
|
||||||
} else {
|
path,
|
||||||
errors.push(
|
span: line.span,
|
||||||
Diagnostic::new(
|
}),
|
||||||
&file,
|
None => errors.push(
|
||||||
"InvalidPackageDependencyName",
|
Diagnostic::new(
|
||||||
format!(
|
&file,
|
||||||
"package dependency name `{}` must start with `a-z` and contain only `a-z`, `0-9`, and `-`",
|
"UnsupportedDependency",
|
||||||
key
|
"workspace dependencies must use `{ path = \"...\" }` local path records only",
|
||||||
),
|
)
|
||||||
)
|
.with_span(line.span),
|
||||||
.with_span(line.span),
|
),
|
||||||
);
|
},
|
||||||
false
|
|
||||||
};
|
|
||||||
let unique_key = if dependency_keys.insert(key.to_string()) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
errors.push(
|
|
||||||
Diagnostic::new(
|
|
||||||
&file,
|
|
||||||
"DuplicatePackageDependencyName",
|
|
||||||
format!("duplicate package dependency name `{}`", key),
|
|
||||||
)
|
|
||||||
.with_span(line.span),
|
|
||||||
);
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
match parse_dependency_path(value) {
|
|
||||||
Some(path) if valid_key && unique_key => dependencies.push(PackageDependency {
|
|
||||||
key: key.to_string(),
|
|
||||||
path,
|
|
||||||
span: line.span,
|
|
||||||
}),
|
|
||||||
Some(_) => {}
|
|
||||||
None => errors.push(
|
|
||||||
Diagnostic::new(
|
|
||||||
&file,
|
|
||||||
"UnsupportedDependency",
|
|
||||||
"workspace dependencies must use `{ path = \"...\" }` local path records only",
|
|
||||||
)
|
|
||||||
.with_span(line.span),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"" | "project" => errors.push(
|
"" | "project" => errors.push(
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
&file,
|
&file,
|
||||||
@ -1756,15 +1674,13 @@ fn set_manifest_key(
|
|||||||
value: String,
|
value: String,
|
||||||
span: Span,
|
span: Span,
|
||||||
key: &str,
|
key: &str,
|
||||||
code: &'static str,
|
|
||||||
manifest_kind: &str,
|
|
||||||
) {
|
) {
|
||||||
if slot.replace(value).is_some() {
|
if slot.replace(value).is_some() {
|
||||||
errors.push(
|
errors.push(
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
file,
|
file,
|
||||||
code,
|
"ProjectManifestInvalid",
|
||||||
format!("duplicate {} manifest key `{}`", manifest_kind, key),
|
format!("duplicate project manifest key `{}`", key),
|
||||||
)
|
)
|
||||||
.with_span(span),
|
.with_span(span),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,163 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
diag::Diagnostic,
|
|
||||||
sexpr::{Atom, SExpr, SExprKind},
|
|
||||||
token::Span,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CURRENT_BETA_UNSUPPORTED: &str = "reserved but not supported in the current beta";
|
|
||||||
|
|
||||||
pub(crate) fn unsupported_reserved_type_diagnostic(file: &str, form: &SExpr) -> Option<Diagnostic> {
|
|
||||||
if let Some(name) = expect_ident(form) {
|
|
||||||
if is_generic_type_parameter_name(name) {
|
|
||||||
return Some(unsupported_generic_type_parameter(file, form.span, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let items = expect_list(form)?;
|
|
||||||
let head = items.first().and_then(expect_ident)?;
|
|
||||||
match head {
|
|
||||||
"map" => Some(
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedMapType",
|
|
||||||
format!("`map` types are {}", CURRENT_BETA_UNSUPPORTED),
|
|
||||||
)
|
|
||||||
.with_span(form.span)
|
|
||||||
.expected("supported concrete type")
|
|
||||||
.found(render_type_form(form))
|
|
||||||
.hint(
|
|
||||||
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
"set" => Some(
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedSetType",
|
|
||||||
format!("`set` types are {}", CURRENT_BETA_UNSUPPORTED),
|
|
||||||
)
|
|
||||||
.with_span(form.span)
|
|
||||||
.expected("supported concrete type")
|
|
||||||
.found(render_type_form(form))
|
|
||||||
.hint(
|
|
||||||
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
"vec" if items.len() != 2 => Some(
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedGenericTypeParameter",
|
|
||||||
format!("generic vector syntax is {}", CURRENT_BETA_UNSUPPORTED),
|
|
||||||
)
|
|
||||||
.with_span(form.span)
|
|
||||||
.expected("(vec i32), (vec i64), (vec f64), (vec bool), or (vec string)")
|
|
||||||
.found(render_type_form(form))
|
|
||||||
.hint("choose one current concrete vector family explicitly"),
|
|
||||||
),
|
|
||||||
_ => items
|
|
||||||
.iter()
|
|
||||||
.find_map(|item| unsupported_reserved_type_diagnostic(file, item)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unsupported_generic_function(file: &str, span: Span) -> Diagnostic {
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedGenericFunction",
|
|
||||||
format!(
|
|
||||||
"generic function declarations are {}",
|
|
||||||
CURRENT_BETA_UNSUPPORTED
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.with_span(span)
|
|
||||||
.expected("(fn name ((arg ConcreteType) ...) -> ConcreteType body...)")
|
|
||||||
.found("(type_params ...)")
|
|
||||||
.hint("write a concrete function for each currently supported type family")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unsupported_generic_type_alias(file: &str, span: Span) -> Diagnostic {
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedGenericTypeAlias",
|
|
||||||
format!(
|
|
||||||
"parameterized type aliases are {}",
|
|
||||||
CURRENT_BETA_UNSUPPORTED
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.with_span(span)
|
|
||||||
.expected("(type Alias ConcreteType)")
|
|
||||||
.found("(type_params ...)")
|
|
||||||
.hint("aliases remain transparent names for concrete supported target types")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unsupported_generic_type_parameter(file: &str, span: Span, name: &str) -> Diagnostic {
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedGenericTypeParameter",
|
|
||||||
format!(
|
|
||||||
"generic type parameter `{}` is {}",
|
|
||||||
name, CURRENT_BETA_UNSUPPORTED
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.with_span(span)
|
|
||||||
.expected("concrete supported type")
|
|
||||||
.found(name.to_string())
|
|
||||||
.hint("use a concrete promoted type such as `i32`, `string`, or `(vec i32)`")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unsupported_generic_standard_library_call(
|
|
||||||
file: &str,
|
|
||||||
span: Span,
|
|
||||||
name: &str,
|
|
||||||
) -> Diagnostic {
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"UnsupportedGenericStandardLibraryCall",
|
|
||||||
format!(
|
|
||||||
"generic standard-library call `{}` is {}",
|
|
||||||
name, CURRENT_BETA_UNSUPPORTED
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.with_span(span)
|
|
||||||
.expected("promoted concrete standard-library function")
|
|
||||||
.found(name.to_string())
|
|
||||||
.hint("use current concrete families such as `std.vec.i32.empty`")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_unsupported_generic_standard_library_call(name: &str) -> bool {
|
|
||||||
matches!(name, "std.vec.empty" | "std.result.map")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_generic_type_parameter_name(name: &str) -> bool {
|
|
||||||
name.len() == 1 && name.bytes().all(|byte| byte.is_ascii_uppercase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_list(expr: &SExpr) -> Option<&[SExpr]> {
|
|
||||||
match &expr.kind {
|
|
||||||
SExprKind::List(items) => Some(items),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_ident(expr: &SExpr) -> Option<&str> {
|
|
||||||
match &expr.kind {
|
|
||||||
SExprKind::Atom(Atom::Ident(name)) => Some(name),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_type_form(form: &SExpr) -> String {
|
|
||||||
match &form.kind {
|
|
||||||
SExprKind::Atom(Atom::Ident(name)) => name.clone(),
|
|
||||||
SExprKind::Atom(Atom::Int(value)) => value.to_string(),
|
|
||||||
SExprKind::Atom(Atom::I64(value)) => format!("{}i64", value),
|
|
||||||
SExprKind::Atom(Atom::U32(value)) => format!("{}u32", value),
|
|
||||||
SExprKind::Atom(Atom::U64(value)) => format!("{}u64", value),
|
|
||||||
SExprKind::Atom(Atom::Float(value)) => value.to_string(),
|
|
||||||
SExprKind::Atom(Atom::String(value)) => format!("{:?}", value),
|
|
||||||
SExprKind::Atom(Atom::Arrow) => "->".to_string(),
|
|
||||||
SExprKind::List(items) => {
|
|
||||||
let parts = items.iter().map(render_type_form).collect::<Vec<_>>();
|
|
||||||
format!("({})", parts.join(" "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -68,9 +68,6 @@ const F64_PARAM: &[RuntimeType] = &[RuntimeType::F64];
|
|||||||
const BOOL_PARAM: &[RuntimeType] = &[RuntimeType::Bool];
|
const BOOL_PARAM: &[RuntimeType] = &[RuntimeType::Bool];
|
||||||
const STRING_PARAM: &[RuntimeType] = &[RuntimeType::String];
|
const STRING_PARAM: &[RuntimeType] = &[RuntimeType::String];
|
||||||
const STRING_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::String, RuntimeType::String];
|
const STRING_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::String, RuntimeType::String];
|
||||||
const STRING_I32_PARAMS: &[RuntimeType] = &[RuntimeType::String, RuntimeType::I32];
|
|
||||||
const STRING_I32_I32_PARAMS: &[RuntimeType] =
|
|
||||||
&[RuntimeType::String, RuntimeType::I32, RuntimeType::I32];
|
|
||||||
const I32_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::I32, RuntimeType::String];
|
const I32_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::I32, RuntimeType::String];
|
||||||
const VEC_I32_PARAM: &[RuntimeType] = &[RuntimeType::VecI32];
|
const VEC_I32_PARAM: &[RuntimeType] = &[RuntimeType::VecI32];
|
||||||
const VEC_I32_I32_PARAMS: &[RuntimeType] = &[RuntimeType::VecI32, RuntimeType::I32];
|
const VEC_I32_I32_PARAMS: &[RuntimeType] = &[RuntimeType::VecI32, RuntimeType::I32];
|
||||||
@ -179,34 +176,6 @@ pub const FUNCTIONS: &[RuntimeFunction] = &[
|
|||||||
return_type: RuntimeType::String,
|
return_type: RuntimeType::String,
|
||||||
promoted: true,
|
promoted: true,
|
||||||
},
|
},
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.string.byte_at_result",
|
|
||||||
runtime_symbol: "__glagol_string_byte_at_result",
|
|
||||||
params: STRING_I32_PARAMS,
|
|
||||||
return_type: RuntimeType::ResultI32I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.string.slice_result",
|
|
||||||
runtime_symbol: "__glagol_string_slice_result",
|
|
||||||
params: STRING_I32_I32_PARAMS,
|
|
||||||
return_type: RuntimeType::ResultStringI32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.string.starts_with",
|
|
||||||
runtime_symbol: "__glagol_string_starts_with",
|
|
||||||
params: STRING_STRING_PARAMS,
|
|
||||||
return_type: RuntimeType::Bool,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.string.ends_with",
|
|
||||||
runtime_symbol: "__glagol_string_ends_with",
|
|
||||||
params: STRING_STRING_PARAMS,
|
|
||||||
return_type: RuntimeType::Bool,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
RuntimeFunction {
|
||||||
source_name: "std.string.parse_i32_result",
|
source_name: "std.string.parse_i32_result",
|
||||||
runtime_symbol: "__glagol_string_parse_i32_result",
|
runtime_symbol: "__glagol_string_parse_i32_result",
|
||||||
@ -256,55 +225,6 @@ pub const FUNCTIONS: &[RuntimeFunction] = &[
|
|||||||
return_type: RuntimeType::String,
|
return_type: RuntimeType::String,
|
||||||
promoted: true,
|
promoted: true,
|
||||||
},
|
},
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_string_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_string_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultStringI32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_bool_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_bool_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultBoolI32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_i32_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_i32_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultI32I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_u32_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_u32_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultU32I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_i64_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_i64_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultI64I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_u64_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_u64_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultU64I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
|
||||||
source_name: "std.json.parse_f64_value_result",
|
|
||||||
runtime_symbol: "__glagol_json_parse_f64_value_result",
|
|
||||||
params: STRING_PARAM,
|
|
||||||
return_type: RuntimeType::ResultF64I32,
|
|
||||||
promoted: true,
|
|
||||||
},
|
|
||||||
RuntimeFunction {
|
RuntimeFunction {
|
||||||
source_name: "std.io.eprint",
|
source_name: "std.io.eprint",
|
||||||
runtime_symbol: "__glagol_io_eprint",
|
runtime_symbol: "__glagol_io_eprint",
|
||||||
@ -827,18 +747,7 @@ const RESERVED_HELPER_SYMBOLS: &[&str] = &[
|
|||||||
"__glagol_string_parse_u64_result",
|
"__glagol_string_parse_u64_result",
|
||||||
"__glagol_string_parse_f64_result",
|
"__glagol_string_parse_f64_result",
|
||||||
"__glagol_string_parse_bool_result",
|
"__glagol_string_parse_bool_result",
|
||||||
"__glagol_string_byte_at_result",
|
|
||||||
"__glagol_string_slice_result",
|
|
||||||
"__glagol_string_starts_with",
|
|
||||||
"__glagol_string_ends_with",
|
|
||||||
"__glagol_json_quote_string",
|
"__glagol_json_quote_string",
|
||||||
"__glagol_json_parse_string_value_result",
|
|
||||||
"__glagol_json_parse_bool_value_result",
|
|
||||||
"__glagol_json_parse_i32_value_result",
|
|
||||||
"__glagol_json_parse_u32_value_result",
|
|
||||||
"__glagol_json_parse_i64_value_result",
|
|
||||||
"__glagol_json_parse_u64_value_result",
|
|
||||||
"__glagol_json_parse_f64_value_result",
|
|
||||||
"__glagol_num_u32_to_string",
|
"__glagol_num_u32_to_string",
|
||||||
"__glagol_num_u64_to_string",
|
"__glagol_num_u64_to_string",
|
||||||
"__glagol_num_f64_to_string",
|
"__glagol_num_f64_to_string",
|
||||||
@ -880,7 +789,7 @@ pub fn unsupported_standard_library_call(file: &str, span: Span, source_name: &s
|
|||||||
format!("standard library call `{}` is not supported", source_name),
|
format!("standard library call `{}` is not supported", source_name),
|
||||||
)
|
)
|
||||||
.with_span(span)
|
.with_span(span)
|
||||||
.expected("std.io.print_i32, std.io.print_u32, std.io.print_i64, std.io.print_u64, std.io.print_f64, std.io.print_string, std.io.print_bool, std.io.eprint, std.io.read_stdin_result, std.string.len, std.string.concat, std.string.byte_at_result, std.string.slice_result, std.string.starts_with, std.string.ends_with, std.string.parse_i32_result, std.string.parse_u32_result, std.string.parse_i64_result, std.string.parse_u64_result, std.string.parse_f64_result, std.string.parse_bool_result, std.json.quote_string, std.json.parse_string_value_result, std.json.parse_bool_value_result, std.json.parse_i32_value_result, std.json.parse_u32_value_result, std.json.parse_i64_value_result, std.json.parse_u64_value_result, std.json.parse_f64_value_result, std.process.argc, std.process.arg, std.process.arg_result, std.env.get, std.env.get_result, std.fs.read_text, std.fs.read_text_result, std.fs.write_text, std.fs.write_text_result, std.fs.exists, std.fs.is_file, std.fs.is_dir, std.fs.remove_file_result, std.fs.create_dir_result, std.fs.open_text_read_result, std.fs.read_open_text_result, std.fs.close_result, std.vec.i32.empty, std.vec.i32.append, std.vec.i32.len, std.vec.i32.index, std.vec.i64.empty, std.vec.i64.append, std.vec.i64.len, std.vec.i64.index, std.vec.f64.empty, std.vec.f64.append, std.vec.f64.len, std.vec.f64.index, std.vec.bool.empty, std.vec.bool.append, std.vec.bool.len, std.vec.bool.index, std.vec.string.empty, std.vec.string.append, std.vec.string.len, std.vec.string.index, std.time.monotonic_ms, std.time.sleep_ms, std.random.i32, std.num.i32_to_i64, std.num.i32_to_f64, std.num.i64_to_f64, std.num.i64_to_i32_result, std.num.f64_to_i32_result, std.num.f64_to_i64_result, std.num.i32_to_string, std.num.u32_to_string, std.num.i64_to_string, std.num.u64_to_string, std.num.f64_to_string, std.result.is_ok, std.result.is_err, std.result.unwrap_ok, or std.result.unwrap_err")
|
.expected("std.io.print_i32, std.io.print_u32, std.io.print_i64, std.io.print_u64, std.io.print_f64, std.io.print_string, std.io.print_bool, std.io.eprint, std.io.read_stdin_result, std.string.len, std.string.concat, std.string.parse_i32_result, std.string.parse_u32_result, std.string.parse_i64_result, std.string.parse_u64_result, std.string.parse_f64_result, std.string.parse_bool_result, std.json.quote_string, std.process.argc, std.process.arg, std.process.arg_result, std.env.get, std.env.get_result, std.fs.read_text, std.fs.read_text_result, std.fs.write_text, std.fs.write_text_result, std.fs.exists, std.fs.is_file, std.fs.is_dir, std.fs.remove_file_result, std.fs.create_dir_result, std.fs.open_text_read_result, std.fs.read_open_text_result, std.fs.close_result, std.vec.i32.empty, std.vec.i32.append, std.vec.i32.len, std.vec.i32.index, std.vec.i64.empty, std.vec.i64.append, std.vec.i64.len, std.vec.i64.index, std.vec.f64.empty, std.vec.f64.append, std.vec.f64.len, std.vec.f64.index, std.vec.bool.empty, std.vec.bool.append, std.vec.bool.len, std.vec.bool.index, std.vec.string.empty, std.vec.string.append, std.vec.string.len, std.vec.string.index, std.time.monotonic_ms, std.time.sleep_ms, std.random.i32, std.num.i32_to_i64, std.num.i32_to_f64, std.num.i64_to_f64, std.num.i64_to_i32_result, std.num.f64_to_i32_result, std.num.f64_to_i64_result, std.num.i32_to_string, std.num.u32_to_string, std.num.i64_to_string, std.num.u64_to_string, std.num.f64_to_string, std.result.is_ok, std.result.is_err, std.result.unwrap_ok, or std.result.unwrap_err")
|
||||||
.found(source_name)
|
.found(source_name)
|
||||||
.hint("use a promoted standard-runtime name or a legacy intrinsic alias")
|
.hint("use a promoted standard-runtime name or a legacy intrinsic alias")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,39 +173,6 @@ pub fn run(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(program: &CheckedProgram, filter: Option<&str>) -> TestRunSuccess {
|
|
||||||
let mut output = String::new();
|
|
||||||
let mut report = TestReport {
|
|
||||||
total_discovered: program.tests.len(),
|
|
||||||
selected: 0,
|
|
||||||
passed: 0,
|
|
||||||
failed: 0,
|
|
||||||
skipped: 0,
|
|
||||||
filter: filter.map(str::to_string),
|
|
||||||
};
|
|
||||||
|
|
||||||
for test in &program.tests {
|
|
||||||
output.push_str("test ");
|
|
||||||
write_test_name(&test.name, &mut output);
|
|
||||||
if let Some(filter) = filter {
|
|
||||||
if !test.name.contains(filter) {
|
|
||||||
report.skipped += 1;
|
|
||||||
output.push_str(" ... skipped\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
report.selected += 1;
|
|
||||||
output.push_str(" ... selected\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str(&format!("{} test(s) selected", report.selected));
|
|
||||||
write_report_suffix(&report, &mut output);
|
|
||||||
output.push('\n');
|
|
||||||
|
|
||||||
TestRunSuccess { output, report }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_report_suffix(report: &TestReport, output: &mut String) {
|
fn write_report_suffix(report: &TestReport, output: &mut String) {
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
" (total_discovered {}, selected {}, passed {}, failed {}, skipped {}",
|
" (total_discovered {}, selected {}, passed {}, failed {}, skipped {}",
|
||||||
@ -214,8 +181,6 @@ fn write_report_suffix(report: &TestReport, output: &mut String) {
|
|||||||
if let Some(filter) = report.filter.as_deref() {
|
if let Some(filter) = report.filter.as_deref() {
|
||||||
output.push_str(", filter ");
|
output.push_str(", filter ");
|
||||||
write_test_name(filter, output);
|
write_test_name(filter, output);
|
||||||
} else {
|
|
||||||
output.push_str(", filter none");
|
|
||||||
}
|
}
|
||||||
output.push(')');
|
output.push(')');
|
||||||
}
|
}
|
||||||
@ -721,208 +686,6 @@ fn parse_bool_result_value(value: &str) -> Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_json_i32_result_value(value: &str) -> Value {
|
|
||||||
if json_integer_token(value.as_bytes(), true) {
|
|
||||||
parse_i32_result_value(value)
|
|
||||||
} else {
|
|
||||||
Value::ResultI32 {
|
|
||||||
is_ok: false,
|
|
||||||
payload: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_i64_result_value(value: &str) -> Value {
|
|
||||||
if json_integer_token(value.as_bytes(), true) {
|
|
||||||
parse_i64_result_value(value)
|
|
||||||
} else {
|
|
||||||
Value::ResultI64I32 {
|
|
||||||
is_ok: false,
|
|
||||||
ok_payload: 0,
|
|
||||||
err_payload: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_u32_result_value(value: &str) -> Value {
|
|
||||||
if json_integer_token(value.as_bytes(), false) {
|
|
||||||
parse_u32_result_value(value)
|
|
||||||
} else {
|
|
||||||
Value::ResultU32I32 {
|
|
||||||
is_ok: false,
|
|
||||||
payload: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_u64_result_value(value: &str) -> Value {
|
|
||||||
if json_integer_token(value.as_bytes(), false) {
|
|
||||||
parse_u64_result_value(value)
|
|
||||||
} else {
|
|
||||||
Value::ResultU64I32 {
|
|
||||||
is_ok: false,
|
|
||||||
ok_payload: 0,
|
|
||||||
err_payload: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_f64_result_value(value: &str) -> Value {
|
|
||||||
match parse_json_f64(value) {
|
|
||||||
Some(payload) => Value::ResultF64I32 {
|
|
||||||
is_ok: true,
|
|
||||||
ok_payload: payload,
|
|
||||||
err_payload: 0,
|
|
||||||
},
|
|
||||||
None => Value::ResultF64I32 {
|
|
||||||
is_ok: false,
|
|
||||||
ok_payload: 0.0,
|
|
||||||
err_payload: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_string_result_value(value: &str) -> Value {
|
|
||||||
match decode_json_ascii_string_token(value.as_bytes()) {
|
|
||||||
Some(payload) => Value::ResultStringI32 {
|
|
||||||
is_ok: true,
|
|
||||||
ok_payload: payload,
|
|
||||||
err_payload: 0,
|
|
||||||
},
|
|
||||||
None => Value::ResultStringI32 {
|
|
||||||
is_ok: false,
|
|
||||||
ok_payload: String::new(),
|
|
||||||
err_payload: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode_json_ascii_string_token(bytes: &[u8]) -> Option<String> {
|
|
||||||
if bytes.len() < 2 || bytes.first() != Some(&b'"') || bytes.last() != Some(&b'"') {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut decoded = String::with_capacity(bytes.len().saturating_sub(2));
|
|
||||||
let mut index = 1;
|
|
||||||
let end = bytes.len() - 1;
|
|
||||||
while index < end {
|
|
||||||
let byte = bytes[index];
|
|
||||||
index += 1;
|
|
||||||
|
|
||||||
if byte < 0x20 || byte >= 0x80 || byte == b'"' {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if byte != b'\\' {
|
|
||||||
decoded.push(byte as char);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if index >= end {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let escaped = bytes[index];
|
|
||||||
index += 1;
|
|
||||||
match escaped {
|
|
||||||
b'"' => decoded.push('"'),
|
|
||||||
b'\\' => decoded.push('\\'),
|
|
||||||
b'/' => decoded.push('/'),
|
|
||||||
b'b' => decoded.push('\u{0008}'),
|
|
||||||
b'f' => decoded.push('\u{000c}'),
|
|
||||||
b'n' => decoded.push('\n'),
|
|
||||||
b'r' => decoded.push('\r'),
|
|
||||||
b't' => decoded.push('\t'),
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(decoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_integer_token(bytes: &[u8], allow_negative: bool) -> bool {
|
|
||||||
if bytes.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut index = 0;
|
|
||||||
if bytes[index] == b'-' {
|
|
||||||
if !allow_negative {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
index += 1;
|
|
||||||
if index == bytes.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes[index].is_ascii_digit() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if bytes[index] == b'0' && index + 1 != bytes.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
while index < bytes.len() {
|
|
||||||
if !bytes[index].is_ascii_digit() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_json_f64(text: &str) -> Option<f64> {
|
|
||||||
if !json_number_token(text.as_bytes()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
text.parse::<f64>().ok().filter(|value| value.is_finite())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_number_token(bytes: &[u8]) -> bool {
|
|
||||||
if bytes.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut index = 0;
|
|
||||||
if bytes[index] == b'-' {
|
|
||||||
index += 1;
|
|
||||||
if index == bytes.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes[index] == b'0' {
|
|
||||||
index += 1;
|
|
||||||
} else if bytes[index].is_ascii_digit() && bytes[index] != b'0' {
|
|
||||||
consume_ascii_digits(bytes, &mut index);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if index < bytes.len() && bytes[index] == b'.' {
|
|
||||||
index += 1;
|
|
||||||
if consume_ascii_digits(bytes, &mut index) == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if index < bytes.len() && (bytes[index] == b'e' || bytes[index] == b'E') {
|
|
||||||
index += 1;
|
|
||||||
if index < bytes.len() && (bytes[index] == b'+' || bytes[index] == b'-') {
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
if consume_ascii_digits(bytes, &mut index) == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index == bytes.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_f64_strict_ascii(text: &str) -> Option<f64> {
|
fn parse_f64_strict_ascii(text: &str) -> Option<f64> {
|
||||||
let bytes = text.as_bytes();
|
let bytes = text.as_bytes();
|
||||||
if !is_ascii_decimal_f64(bytes) {
|
if !is_ascii_decimal_f64(bytes) {
|
||||||
@ -996,232 +759,6 @@ fn quote_json_string_value(value: &str) -> String {
|
|||||||
quoted
|
quoted
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_string_byte_at_result_call(
|
|
||||||
file: &str,
|
|
||||||
expr: &TExpr,
|
|
||||||
args: &[TExpr],
|
|
||||||
locals: &mut HashMap<String, Value>,
|
|
||||||
functions: &HashMap<&str, &CheckedFunction>,
|
|
||||||
foreign_imports: &HashSet<&str>,
|
|
||||||
depth: usize,
|
|
||||||
) -> Result<Value, Diagnostic> {
|
|
||||||
let Some(value) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.byte_at_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(index) = args.get(1) else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.byte_at_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, value, locals, functions, foreign_imports, depth)?;
|
|
||||||
let index = eval_expr(file, index, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.byte_at_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(index) = index.as_i32() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.byte_at_result` with non-i32 index",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let payload = usize::try_from(index)
|
|
||||||
.ok()
|
|
||||||
.and_then(|index| value.as_bytes().get(index))
|
|
||||||
.map(|byte| i32::from(*byte));
|
|
||||||
Ok(match payload {
|
|
||||||
Some(payload) => Value::ResultI32 {
|
|
||||||
is_ok: true,
|
|
||||||
payload,
|
|
||||||
},
|
|
||||||
None => Value::ResultI32 {
|
|
||||||
is_ok: false,
|
|
||||||
payload: 1,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_string_slice_result_call(
|
|
||||||
file: &str,
|
|
||||||
expr: &TExpr,
|
|
||||||
args: &[TExpr],
|
|
||||||
locals: &mut HashMap<String, Value>,
|
|
||||||
functions: &HashMap<&str, &CheckedFunction>,
|
|
||||||
foreign_imports: &HashSet<&str>,
|
|
||||||
depth: usize,
|
|
||||||
) -> Result<Value, Diagnostic> {
|
|
||||||
let Some(value) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.slice_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(start) = args.get(1) else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.slice_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(count) = args.get(2) else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.slice_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, value, locals, functions, foreign_imports, depth)?;
|
|
||||||
let start = eval_expr(file, start, locals, functions, foreign_imports, depth)?;
|
|
||||||
let count = eval_expr(file, count, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.slice_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(start) = start.as_i32() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.slice_result` with non-i32 start",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(count) = count.as_i32() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.slice_result` with non-i32 count",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let bytes = value.as_bytes();
|
|
||||||
let slice = usize::try_from(start)
|
|
||||||
.ok()
|
|
||||||
.and_then(|start| {
|
|
||||||
usize::try_from(count)
|
|
||||||
.ok()
|
|
||||||
.and_then(|count| start.checked_add(count).map(|end| (start, end)))
|
|
||||||
})
|
|
||||||
.and_then(|(start, end)| {
|
|
||||||
(start <= bytes.len() && end <= bytes.len()).then(|| &bytes[start..end])
|
|
||||||
});
|
|
||||||
let Some(slice) = slice else {
|
|
||||||
return Ok(Value::ResultStringI32 {
|
|
||||||
is_ok: false,
|
|
||||||
ok_payload: String::new(),
|
|
||||||
err_payload: 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let ok_payload = String::from_utf8(slice.to_vec()).map_err(|_| {
|
|
||||||
Diagnostic::new(
|
|
||||||
file,
|
|
||||||
"TestRuntimeError",
|
|
||||||
"`std.string.slice_result` produced non-UTF-8 bytes in the test runner",
|
|
||||||
)
|
|
||||||
.with_span(expr.span)
|
|
||||||
})?;
|
|
||||||
Ok(Value::ResultStringI32 {
|
|
||||||
is_ok: true,
|
|
||||||
ok_payload,
|
|
||||||
err_payload: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_string_starts_with_call(
|
|
||||||
file: &str,
|
|
||||||
expr: &TExpr,
|
|
||||||
args: &[TExpr],
|
|
||||||
locals: &mut HashMap<String, Value>,
|
|
||||||
functions: &HashMap<&str, &CheckedFunction>,
|
|
||||||
foreign_imports: &HashSet<&str>,
|
|
||||||
depth: usize,
|
|
||||||
) -> Result<Value, Diagnostic> {
|
|
||||||
let Some(value) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.starts_with` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(prefix) = args.get(1) else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.starts_with` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, value, locals, functions, foreign_imports, depth)?;
|
|
||||||
let prefix = eval_expr(file, prefix, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.starts_with` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(prefix) = prefix.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.starts_with` with non-string prefix",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
Ok(Value::Bool(value.as_bytes().starts_with(prefix.as_bytes())))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_string_ends_with_call(
|
|
||||||
file: &str,
|
|
||||||
expr: &TExpr,
|
|
||||||
args: &[TExpr],
|
|
||||||
locals: &mut HashMap<String, Value>,
|
|
||||||
functions: &HashMap<&str, &CheckedFunction>,
|
|
||||||
foreign_imports: &HashSet<&str>,
|
|
||||||
depth: usize,
|
|
||||||
) -> Result<Value, Diagnostic> {
|
|
||||||
let Some(value) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.ends_with` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(suffix) = args.get(1) else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.string.ends_with` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, value, locals, functions, foreign_imports, depth)?;
|
|
||||||
let suffix = eval_expr(file, suffix, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.ends_with` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(suffix) = suffix.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.string.ends_with` with non-string suffix",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
Ok(Value::Bool(value.as_bytes().ends_with(suffix.as_bytes())))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_expr(
|
fn eval_expr(
|
||||||
file: &str,
|
file: &str,
|
||||||
expr: &TExpr,
|
expr: &TExpr,
|
||||||
@ -2591,50 +2128,6 @@ fn eval_expr(
|
|||||||
};
|
};
|
||||||
return Ok(Value::String(format!("{}{}", left, right)));
|
return Ok(Value::String(format!("{}{}", left, right)));
|
||||||
}
|
}
|
||||||
if runtime_symbol == "__glagol_string_byte_at_result" {
|
|
||||||
return eval_string_byte_at_result_call(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
args,
|
|
||||||
locals,
|
|
||||||
functions,
|
|
||||||
foreign_imports,
|
|
||||||
depth,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_string_slice_result" {
|
|
||||||
return eval_string_slice_result_call(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
args,
|
|
||||||
locals,
|
|
||||||
functions,
|
|
||||||
foreign_imports,
|
|
||||||
depth,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_string_starts_with" {
|
|
||||||
return eval_string_starts_with_call(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
args,
|
|
||||||
locals,
|
|
||||||
functions,
|
|
||||||
foreign_imports,
|
|
||||||
depth,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_string_ends_with" {
|
|
||||||
return eval_string_ends_with_call(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
args,
|
|
||||||
locals,
|
|
||||||
functions,
|
|
||||||
foreign_imports,
|
|
||||||
depth,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_quote_string" {
|
if runtime_symbol == "__glagol_json_quote_string" {
|
||||||
let Some(arg) = args.first() else {
|
let Some(arg) = args.first() else {
|
||||||
return Err(unsupported_test_expr(
|
return Err(unsupported_test_expr(
|
||||||
@ -2761,132 +2254,6 @@ fn eval_expr(
|
|||||||
};
|
};
|
||||||
return Ok(parse_bool_result_value(value));
|
return Ok(parse_bool_result_value(value));
|
||||||
}
|
}
|
||||||
if runtime_symbol == "__glagol_json_parse_bool_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_bool_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_bool_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_bool_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_string_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_string_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_string_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_string_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_i32_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_i32_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_i32_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_i32_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_u32_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_u32_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_u32_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_u32_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_i64_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_i64_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_i64_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_i64_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_u64_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_u64_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_u64_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_u64_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_json_parse_f64_value_result" {
|
|
||||||
let Some(arg) = args.first() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"malformed `std.json.parse_f64_value_result` calls",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let value = eval_expr(file, arg, locals, functions, foreign_imports, depth)?;
|
|
||||||
let Some(value) = value.as_string() else {
|
|
||||||
return Err(unsupported_test_expr(
|
|
||||||
file,
|
|
||||||
expr,
|
|
||||||
"`std.json.parse_f64_value_result` on non-string values",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
return Ok(parse_json_f64_result_value(value));
|
|
||||||
}
|
|
||||||
if runtime_symbol == "__glagol_process_argc" {
|
if runtime_symbol == "__glagol_process_argc" {
|
||||||
let argc = i32::try_from(env::args().count()).map_err(|_| {
|
let argc = i32::try_from(env::args().count()).map_err(|_| {
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
|
|||||||
@ -1,134 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
path::Path,
|
|
||||||
process::{Command, Output},
|
|
||||||
};
|
|
||||||
|
|
||||||
const BENCHMARKS: &[&str] = &[
|
|
||||||
"array-index-loop",
|
|
||||||
"array-struct-field-loop",
|
|
||||||
"branch-loop",
|
|
||||||
"enum-struct-payload-loop",
|
|
||||||
"json-quote-loop",
|
|
||||||
"math-loop",
|
|
||||||
"parse-loop",
|
|
||||||
"string-eq-loop",
|
|
||||||
"vec-i32-index-loop",
|
|
||||||
"vec-string-eq-loop",
|
|
||||||
];
|
|
||||||
|
|
||||||
const IMPLEMENTATIONS: &[&str] = &["slovo", "c", "rust", "python", "clojure", "common_lisp"];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn suite_catalog_is_byte_stable_and_lists_current_benchmarks() {
|
|
||||||
let repo = Path::new(env!("CARGO_MANIFEST_DIR")).join("..");
|
|
||||||
let python = python_command();
|
|
||||||
|
|
||||||
let first = run_suite_catalog(&repo, &python);
|
|
||||||
let second = run_suite_catalog(&repo, &python);
|
|
||||||
|
|
||||||
assert_success("first suite catalog run", &first);
|
|
||||||
assert_success("second suite catalog run", &second);
|
|
||||||
assert_eq!(
|
|
||||||
first.stdout, second.stdout,
|
|
||||||
"suite catalog JSON must be byte-stable across runs"
|
|
||||||
);
|
|
||||||
|
|
||||||
let stdout = String::from_utf8_lossy(&first.stdout);
|
|
||||||
for needle in [
|
|
||||||
r#""suite": "glagol-local-benchmark-suite""#,
|
|
||||||
r#""benchmark_count": 10"#,
|
|
||||||
r#""benchmark_metadata_files": 10"#,
|
|
||||||
r#""required_files": 40"#,
|
|
||||||
r#""missing_required_files": []"#,
|
|
||||||
r#""implementation_slots": 60"#,
|
|
||||||
r#""expected_implementation_slots": 60"#,
|
|
||||||
r#""missing_implementation_slots": []"#,
|
|
||||||
r#""status": "ok""#,
|
|
||||||
r#""timing_scope": "local-machine comparison only""#,
|
|
||||||
r#""timing_disclaimer": "Local timing comparison only; not a published benchmark result and not a cross-machine performance claim.""#,
|
|
||||||
r#""cold-process""#,
|
|
||||||
r#""hot-loop""#,
|
|
||||||
r#""loop_count": 1000000"#,
|
|
||||||
r#""hot_loop_count": 10000000"#,
|
|
||||||
r#""checksum_metadata""#,
|
|
||||||
r#""expected_checksum""#,
|
|
||||||
r#""hot_expected_checksum""#,
|
|
||||||
r#""required_files""#,
|
|
||||||
r#""path": "benchmark.json""#,
|
|
||||||
r#""path": "run.py""#,
|
|
||||||
r#""path": "slovo.toml""#,
|
|
||||||
r#""path": "src/main.slo""#,
|
|
||||||
r#""status": "present""#,
|
|
||||||
r#""implementation_slots""#,
|
|
||||||
r#""loop_count_source": "stdin""#,
|
|
||||||
] {
|
|
||||||
assert_contains(&stdout, needle);
|
|
||||||
}
|
|
||||||
|
|
||||||
for benchmark in BENCHMARKS {
|
|
||||||
assert_contains(&stdout, &format!(r#""name": "{}""#, benchmark));
|
|
||||||
assert_contains(&stdout, &format!(r#""directory": "{}""#, benchmark));
|
|
||||||
}
|
|
||||||
|
|
||||||
for implementation in IMPLEMENTATIONS {
|
|
||||||
assert_contains(&stdout, &format!(r#""name": "{}""#, implementation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_suite_catalog(repo: &Path, python: &str) -> Output {
|
|
||||||
Command::new(python)
|
|
||||||
.arg("benchmarks/runner.py")
|
|
||||||
.arg("--suite-list")
|
|
||||||
.arg("--json")
|
|
||||||
.current_dir(repo)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
panic!(
|
|
||||||
"run `{}` benchmarks/runner.py --suite-list --json: {}",
|
|
||||||
python, err
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn python_command() -> String {
|
|
||||||
if let Some(python) = env::var_os("PYTHON") {
|
|
||||||
return python.to_string_lossy().into_owned();
|
|
||||||
}
|
|
||||||
|
|
||||||
for candidate in ["python3", "python"] {
|
|
||||||
if Command::new(candidate)
|
|
||||||
.arg("--version")
|
|
||||||
.output()
|
|
||||||
.map(|output| output.status.success())
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
return candidate.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("benchmark suite catalog test requires python3 or python")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_contains(haystack: &str, needle: &str) {
|
|
||||||
assert!(
|
|
||||||
haystack.contains(needle),
|
|
||||||
"suite catalog output missing `{}`\nstdout:\n{}",
|
|
||||||
needle,
|
|
||||||
haystack
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1036,250 +1036,6 @@ const CASES: &[DiagnosticCase] = &[
|
|||||||
"#,
|
"#,
|
||||||
snapshot: "../tests/std-string-concat-unsupported-string-container.diag",
|
snapshot: "../tests/std-string-concat-unsupported-string-container.diag",
|
||||||
},
|
},
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-arity",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result i32 i32)
|
|
||||||
(std.string.byte_at_result "abc"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-arity.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result i32 i32)
|
|
||||||
(std.string.byte_at_result "abc" "0"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-type.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.byte_at_result "abc" 0))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-bool-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (std.string.byte_at_result "abc" 0) 1 0))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-bool-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-name-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.string.byte_at_result ((text string) (index i32)) -> (result i32 i32)
|
|
||||||
(err i32 i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-name-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-result-helper-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_string_byte_at_result ((text string) (index i32)) -> (result i32 i32)
|
|
||||||
(err i32 i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-result-helper-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-arity",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result string i32)
|
|
||||||
(std.string.slice_result "abc" 0))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-arity.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result string i32)
|
|
||||||
(std.string.slice_result "abc" 0 "1"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-type.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> string
|
|
||||||
(std.string.slice_result "abc" 0 1))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-bool-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (std.string.slice_result "abc" 0 1) 1 0))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-bool-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-name-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.string.slice_result ((text string) (start i32) (count i32)) -> (result string i32)
|
|
||||||
(err string i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-name-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-slice-result-helper-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_string_slice_result ((text string) (start i32) (count i32)) -> (result string i32)
|
|
||||||
(err string i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-slice-result-helper-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-starts-with-arity",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> bool
|
|
||||||
(std.string.starts_with "abc"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-starts-with-arity.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-starts-with-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> bool
|
|
||||||
(std.string.starts_with "abc" 1))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-starts-with-type.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-starts-with-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.starts_with "abc" "a"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-starts-with-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-starts-with-name-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.string.starts_with ((text string) (prefix string)) -> bool
|
|
||||||
false)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-starts-with-name-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-starts-with-helper-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_string_starts_with ((text string) (prefix string)) -> bool
|
|
||||||
false)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-starts-with-helper-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-ends-with-arity",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> bool
|
|
||||||
(std.string.ends_with "abc"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-ends-with-arity.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-ends-with-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> bool
|
|
||||||
(std.string.ends_with "abc" 1))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-ends-with-type.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-ends-with-context",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.ends_with "abc" "c"))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-ends-with-context.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-ends-with-name-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.string.ends_with ((text string) (suffix string)) -> bool
|
|
||||||
false)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-ends-with-name-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-ends-with-helper-shadow",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_string_ends_with ((text string) (suffix string)) -> bool
|
|
||||||
false)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-ends-with-helper-shadow.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
DiagnosticCase {
|
||||||
name: "std-string-parse-i32-result-arity",
|
name: "std-string-parse-i32-result-arity",
|
||||||
source: r#"
|
source: r#"
|
||||||
@ -1774,16 +1530,6 @@ const CASES: &[DiagnosticCase] = &[
|
|||||||
"#,
|
"#,
|
||||||
snapshot: "../tests/std-string-index-unsupported.diag",
|
snapshot: "../tests/std-string-index-unsupported.diag",
|
||||||
},
|
},
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-byte-at-unsupported",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.byte_at "42" 0))
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-byte-at-unsupported.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
DiagnosticCase {
|
||||||
name: "std-string-slice-unsupported",
|
name: "std-string-slice-unsupported",
|
||||||
source: r#"
|
source: r#"
|
||||||
@ -1795,39 +1541,6 @@ const CASES: &[DiagnosticCase] = &[
|
|||||||
"#,
|
"#,
|
||||||
snapshot: "../tests/std-string-slice-unsupported.diag",
|
snapshot: "../tests/std-string-slice-unsupported.diag",
|
||||||
},
|
},
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-contains-unsupported",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.contains "slovo" "lo")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-contains-unsupported.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-find-result-unsupported",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.find_result "slovo" "lo")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-find-result-unsupported.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
|
||||||
name: "std-string-split-unsupported",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.split "a,b" ",")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
snapshot: "../tests/std-string-split-unsupported.diag",
|
|
||||||
},
|
|
||||||
DiagnosticCase {
|
DiagnosticCase {
|
||||||
name: "std-string-tokenize-unsupported",
|
name: "std-string-tokenize-unsupported",
|
||||||
source: r#"
|
source: r#"
|
||||||
|
|||||||
@ -1,486 +0,0 @@
|
|||||||
use std::{
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sexpr_diagnostics_keep_v1_schema_across_source_pipelines() {
|
|
||||||
let cases = [
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "parse",
|
|
||||||
args: &["check"],
|
|
||||||
source: "(module main",
|
|
||||||
code: "UnclosedList",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "check",
|
|
||||||
args: &["check"],
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn id ((value i32)) -> i32
|
|
||||||
value)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(id true))
|
|
||||||
"#,
|
|
||||||
code: "TypeMismatch",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "fmt",
|
|
||||||
args: &["fmt"],
|
|
||||||
source: r#"
|
|
||||||
(module main) ; comments stay outside formatter input
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedFormatterComment",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "test",
|
|
||||||
args: &["test"],
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "false case"
|
|
||||||
false)
|
|
||||||
"#,
|
|
||||||
code: "TestFailed",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for case in cases {
|
|
||||||
let fixture = write_fixture(case.name, case.source);
|
|
||||||
let mut args = case.args.iter().map(OsStr::new).collect::<Vec<_>>();
|
|
||||||
args.push(fixture.as_os_str());
|
|
||||||
|
|
||||||
let output = run_glagol(args);
|
|
||||||
|
|
||||||
assert_exit_code(case.name, &output, 1);
|
|
||||||
assert_stdout_empty(case.name, &output);
|
|
||||||
assert_sexpr_diagnostic_schema(case.name, &output, case.code, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let project = write_project(
|
|
||||||
"sexpr-project",
|
|
||||||
"(module main)\n\n(import missing (value))\n",
|
|
||||||
);
|
|
||||||
let output = run_glagol(["check".as_ref(), project.as_os_str()]);
|
|
||||||
|
|
||||||
assert_exit_code("project", &output, 1);
|
|
||||||
assert_stdout_empty("project", &output);
|
|
||||||
assert_sexpr_diagnostic_schema("project", &output, "MissingImport", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_diagnostics_keep_v1_schema_across_policy_boundaries() {
|
|
||||||
let cases = [
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "json-parse",
|
|
||||||
args: &["--json-diagnostics", "check"],
|
|
||||||
source: "(module main",
|
|
||||||
code: "UnclosedList",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "json-check",
|
|
||||||
args: &["--json-diagnostics", "check"],
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn id ((value i32)) -> i32
|
|
||||||
value)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(id true))
|
|
||||||
"#,
|
|
||||||
code: "TypeMismatch",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "json-fmt",
|
|
||||||
args: &["--json-diagnostics", "fmt"],
|
|
||||||
source: r#"
|
|
||||||
(module main) ; comments stay outside formatter input
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedFormatterComment",
|
|
||||||
},
|
|
||||||
SourceDiagnosticCase {
|
|
||||||
name: "json-test",
|
|
||||||
args: &["--json-diagnostics", "test"],
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "false case"
|
|
||||||
false)
|
|
||||||
"#,
|
|
||||||
code: "TestFailed",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for case in cases {
|
|
||||||
let fixture = write_fixture(case.name, case.source);
|
|
||||||
let mut args = case.args.iter().map(OsStr::new).collect::<Vec<_>>();
|
|
||||||
args.push(fixture.as_os_str());
|
|
||||||
|
|
||||||
let output = run_glagol(args);
|
|
||||||
|
|
||||||
assert_exit_code(case.name, &output, 1);
|
|
||||||
assert_stdout_empty(case.name, &output);
|
|
||||||
assert_json_diagnostic_schema(case.name, &output, case.code, JsonSource::Source);
|
|
||||||
}
|
|
||||||
|
|
||||||
let project = write_project(
|
|
||||||
"json-project",
|
|
||||||
"(module main)\n\n(import missing (value))\n",
|
|
||||||
);
|
|
||||||
let output = run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"check".as_ref(),
|
|
||||||
project.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_exit_code("json project", &output, 1);
|
|
||||||
assert_stdout_empty("json project", &output);
|
|
||||||
assert_json_diagnostic_schema("json project", &output, "MissingImport", JsonSource::Source);
|
|
||||||
|
|
||||||
let usage_manifest = temp_path("json-usage", "manifest.slo");
|
|
||||||
let usage = run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"--manifest".as_ref(),
|
|
||||||
usage_manifest.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_exit_code("json usage", &usage, 2);
|
|
||||||
assert_stdout_empty("json usage", &usage);
|
|
||||||
assert_json_diagnostic_schema("json usage", &usage, "UsageError", JsonSource::SourceLess);
|
|
||||||
assert_manifest_schema_fields(&read_manifest(&usage_manifest), "json");
|
|
||||||
|
|
||||||
let toolchain_fixture = write_fixture(
|
|
||||||
"json-toolchain",
|
|
||||||
"(module main)\n\n(fn main () -> i32\n 0)\n",
|
|
||||||
);
|
|
||||||
let toolchain_manifest = temp_path("json-toolchain", "manifest.slo");
|
|
||||||
let output_path = temp_path("json-toolchain", "bin");
|
|
||||||
let missing_clang = temp_path("json-toolchain", "not-a-clang");
|
|
||||||
let toolchain = Command::new(compiler_path())
|
|
||||||
.arg("--json-diagnostics")
|
|
||||||
.arg("build")
|
|
||||||
.arg(&toolchain_fixture)
|
|
||||||
.arg("-o")
|
|
||||||
.arg(&output_path)
|
|
||||||
.arg("--manifest")
|
|
||||||
.arg(&toolchain_manifest)
|
|
||||||
.env("GLAGOL_CLANG", &missing_clang)
|
|
||||||
.env_remove("GLAGOL_RUNTIME_C")
|
|
||||||
.env_remove("SLOVO_RUNTIME_C")
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run glagol build: {}", err));
|
|
||||||
|
|
||||||
assert_exit_code("json toolchain", &toolchain, 3);
|
|
||||||
assert_stdout_empty("json toolchain", &toolchain);
|
|
||||||
assert_json_diagnostic_schema(
|
|
||||||
"json toolchain",
|
|
||||||
&toolchain,
|
|
||||||
"ToolchainUnavailable",
|
|
||||||
JsonSource::SourceLess,
|
|
||||||
);
|
|
||||||
assert_manifest_schema_fields(&read_manifest(&toolchain_manifest), "json");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn project_failure_manifests_record_schema_encoding_and_count_deterministically() {
|
|
||||||
let project = write_project(
|
|
||||||
"manifest-project",
|
|
||||||
"(module main)\n\n(import missing (value))\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
let first_sexpr = run_project_failure_manifest(&project, "sexpr", false);
|
|
||||||
let second_sexpr = run_project_failure_manifest(&project, "sexpr-repeat", false);
|
|
||||||
assert_manifest_schema_fields(&first_sexpr, "sexpr");
|
|
||||||
assert_project_diagnostics_count(&first_sexpr, 1);
|
|
||||||
assert_eq!(
|
|
||||||
project_block(&first_sexpr),
|
|
||||||
project_block(&second_sexpr),
|
|
||||||
"S-expression failure manifest project block drifted"
|
|
||||||
);
|
|
||||||
|
|
||||||
let first_json = run_project_failure_manifest(&project, "json", true);
|
|
||||||
let second_json = run_project_failure_manifest(&project, "json-repeat", true);
|
|
||||||
assert_manifest_schema_fields(&first_json, "json");
|
|
||||||
assert_project_diagnostics_count(&first_json, 1);
|
|
||||||
assert_eq!(
|
|
||||||
project_block(&first_json),
|
|
||||||
project_block(&second_json),
|
|
||||||
"JSON failure manifest project block drifted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SourceDiagnosticCase {
|
|
||||||
name: &'static str,
|
|
||||||
args: &'static [&'static str],
|
|
||||||
source: &'static str,
|
|
||||||
code: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum JsonSource {
|
|
||||||
Source,
|
|
||||||
SourceLess,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_project_failure_manifest(project: &Path, name: &str, json: bool) -> String {
|
|
||||||
let manifest = temp_path(name, "manifest.slo");
|
|
||||||
let output = if json {
|
|
||||||
run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"check".as_ref(),
|
|
||||||
"--manifest".as_ref(),
|
|
||||||
manifest.as_os_str(),
|
|
||||||
project.as_os_str(),
|
|
||||||
])
|
|
||||||
} else {
|
|
||||||
run_glagol([
|
|
||||||
"check".as_ref(),
|
|
||||||
"--manifest".as_ref(),
|
|
||||||
manifest.as_os_str(),
|
|
||||||
project.as_os_str(),
|
|
||||||
])
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_exit_code(name, &output, 1);
|
|
||||||
assert_stdout_empty(name, &output);
|
|
||||||
read_manifest(&manifest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_sexpr_diagnostic_schema(
|
|
||||||
context: &str,
|
|
||||||
output: &Output,
|
|
||||||
expected_code: &str,
|
|
||||||
expected_count: usize,
|
|
||||||
) {
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
!stderr.trim().is_empty(),
|
|
||||||
"{} did not emit diagnostics",
|
|
||||||
context
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!stderr
|
|
||||||
.lines()
|
|
||||||
.all(|line| line.starts_with('{') && line.ends_with('}')),
|
|
||||||
"{} unexpectedly emitted JSON diagnostics:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
stderr.matches("(diagnostic\n").count(),
|
|
||||||
expected_count,
|
|
||||||
"{} diagnostic block count drifted:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
stderr.matches(" (schema slovo.diagnostic)\n").count(),
|
|
||||||
expected_count,
|
|
||||||
"{} diagnostic schema name drifted:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
stderr.matches(" (version 1)\n").count(),
|
|
||||||
expected_count,
|
|
||||||
"{} diagnostic schema version drifted:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(" (severity error)\n")
|
|
||||||
&& stderr.contains(&format!(" (code {})\n", expected_code))
|
|
||||||
&& stderr.contains(" (file ")
|
|
||||||
&& stderr.contains(" (span\n"),
|
|
||||||
"{} S-expression diagnostic missed required structural fields:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_json_diagnostic_schema(
|
|
||||||
context: &str,
|
|
||||||
output: &Output,
|
|
||||||
expected_code: &str,
|
|
||||||
source: JsonSource,
|
|
||||||
) {
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
let lines = stderr
|
|
||||||
.lines()
|
|
||||||
.filter(|line| !line.trim().is_empty())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert!(!lines.is_empty(), "{} did not emit diagnostics", context);
|
|
||||||
|
|
||||||
for line in &lines {
|
|
||||||
assert!(
|
|
||||||
line.starts_with('{') && line.ends_with('}'),
|
|
||||||
"{} emitted non-JSON diagnostic text:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
line.contains(r#""schema":"slovo.diagnostic""#)
|
|
||||||
&& line.contains(r#""version":1"#)
|
|
||||||
&& line.contains(r#""severity":"error""#)
|
|
||||||
&& line.contains(r#""message":"#)
|
|
||||||
&& line.contains(r#""file":"#)
|
|
||||||
&& line.contains(r#""span":"#),
|
|
||||||
"{} JSON diagnostic missed required schema fields:\n{}",
|
|
||||||
context,
|
|
||||||
line
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
lines
|
|
||||||
.iter()
|
|
||||||
.any(|line| line.contains(&format!(r#""code":"{}""#, expected_code))),
|
|
||||||
"{} JSON diagnostics did not include code `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
expected_code,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
|
|
||||||
match source {
|
|
||||||
JsonSource::Source => assert!(
|
|
||||||
lines
|
|
||||||
.iter()
|
|
||||||
.any(|line| line.contains(r#""span":{"byte_start":"#)),
|
|
||||||
"{} JSON diagnostics should include a concrete source span:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
),
|
|
||||||
JsonSource::SourceLess => assert!(
|
|
||||||
lines
|
|
||||||
.iter()
|
|
||||||
.any(|line| line.contains(r#""file":null"#) && line.contains(r#""span":null"#)),
|
|
||||||
"{} JSON diagnostics should be source-less:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_manifest_schema_fields(manifest: &str, encoding: &str) {
|
|
||||||
assert!(
|
|
||||||
manifest.contains(" (schema slovo.artifact-manifest)\n")
|
|
||||||
&& manifest.contains(" (version 1)\n")
|
|
||||||
&& manifest.contains(" (diagnostics-schema-version 1)\n")
|
|
||||||
&& manifest.contains(&format!(" (diagnostics-encoding {})\n", encoding))
|
|
||||||
&& manifest.contains("slovo.diagnostic"),
|
|
||||||
"manifest diagnostic schema fields drifted:\n{}",
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_project_diagnostics_count(manifest: &str, expected: usize) {
|
|
||||||
assert!(
|
|
||||||
manifest.contains(&format!(" (diagnostics_count {})\n", expected)),
|
|
||||||
"manifest diagnostics count drifted:\n{}",
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn project_block(manifest: &str) -> &str {
|
|
||||||
let start = manifest
|
|
||||||
.find(" (project\n")
|
|
||||||
.expect("manifest did not contain project block");
|
|
||||||
manifest[start..]
|
|
||||||
.strip_suffix("\n)\n")
|
|
||||||
.expect("manifest did not end with artifact-manifest close")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(compiler_path())
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run glagol: {}", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compiler_path() -> &'static str {
|
|
||||||
env!("CARGO_BIN_EXE_glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let path = temp_path(name, "slo");
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(name: &str, main_source: &str) -> PathBuf {
|
|
||||||
let root = temp_dir(name);
|
|
||||||
let source_root = root.join("src");
|
|
||||||
fs::create_dir_all(&source_root)
|
|
||||||
.unwrap_or_else(|err| panic!("create `{}`: {}", source_root.display(), err));
|
|
||||||
fs::write(
|
|
||||||
root.join("slovo.toml"),
|
|
||||||
"[project]\nname = \"beta13\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|err| panic!("write project manifest: {}", err));
|
|
||||||
fs::write(source_root.join("main.slo"), main_source)
|
|
||||||
.unwrap_or_else(|err| panic!("write main source: {}", err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_manifest(path: &Path) -> String {
|
|
||||||
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_path(name: &str, extension: &str) -> PathBuf {
|
|
||||||
let mut path = std::env::temp_dir();
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-beta13-{}-{}-{}.{}",
|
|
||||||
std::process::id(),
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
extension,
|
|
||||||
));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_dir(name: &str) -> PathBuf {
|
|
||||||
let mut path = std::env::temp_dir();
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-beta13-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_exit_code(context: &str, output: &Output, expected: i32) {
|
|
||||||
assert_eq!(
|
|
||||||
output.status.code(),
|
|
||||||
Some(expected),
|
|
||||||
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_stdout_empty(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
assert!(stdout.is_empty(), "{} wrote stdout:\n{}", context, stdout);
|
|
||||||
}
|
|
||||||
@ -1,420 +0,0 @@
|
|||||||
use std::{
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn doc_file_renders_public_api_with_signatures_and_shapes() {
|
|
||||||
let source = r#"(module api (export Point Status make))
|
|
||||||
|
|
||||||
(struct Point
|
|
||||||
(x i32)
|
|
||||||
(label string))
|
|
||||||
|
|
||||||
(enum Status Ready (Blocked i32))
|
|
||||||
|
|
||||||
(fn helper ((value i32)) -> i32
|
|
||||||
value)
|
|
||||||
|
|
||||||
(fn make ((x i32) (label string)) -> Point
|
|
||||||
(Point (x x) (label label)))
|
|
||||||
|
|
||||||
(test "make is documented"
|
|
||||||
true)
|
|
||||||
"#;
|
|
||||||
let file = write_file("file-api", source);
|
|
||||||
let docs = unique_path("file-api-docs");
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
file.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("doc file", &output);
|
|
||||||
let index = read_index(&docs);
|
|
||||||
assert!(index.contains("## Module api"));
|
|
||||||
assert!(index.contains("### Imports\n\nNone.\n\n"));
|
|
||||||
assert!(index.contains("- `Point`"));
|
|
||||||
assert!(index.contains("- `make(x i32, label string) -> Point`"));
|
|
||||||
assert!(index.contains("- `make is documented`"));
|
|
||||||
|
|
||||||
let api = public_api_for_module(&index, "api");
|
|
||||||
assert!(api.contains("- `fn make(x: i32, label: string) -> Point`"));
|
|
||||||
assert!(api.contains("- `struct Point`"));
|
|
||||||
assert!(api.contains(" - `x: i32`"));
|
|
||||||
assert!(api.contains(" - `label: string`"));
|
|
||||||
assert!(api.contains("- `enum Status`"));
|
|
||||||
assert!(api.contains(" - `Ready`"));
|
|
||||||
assert!(api.contains(" - `Blocked(i32)`"));
|
|
||||||
assert!(
|
|
||||||
!api.contains("helper"),
|
|
||||||
"non-exported helper leaked into public API:\n{}",
|
|
||||||
api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn doc_project_renders_package_and_module_public_api() {
|
|
||||||
let project = write_project(
|
|
||||||
"project-api",
|
|
||||||
&[(
|
|
||||||
"math",
|
|
||||||
r#"(module math (export add Pair))
|
|
||||||
|
|
||||||
(struct Pair
|
|
||||||
(left i32)
|
|
||||||
(right i32))
|
|
||||||
|
|
||||||
(fn add ((left i32) (right i32)) -> i32
|
|
||||||
(+ left right))
|
|
||||||
|
|
||||||
(fn private_double ((value i32)) -> i32
|
|
||||||
(+ value value))
|
|
||||||
"#,
|
|
||||||
)],
|
|
||||||
"(module main)\n\n(import math (add Pair))\n\n(fn main () -> i32\n (add 1 2))\n",
|
|
||||||
);
|
|
||||||
let docs = unique_path("project-api-docs");
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
project.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("doc project", &output);
|
|
||||||
let index = read_index(&docs);
|
|
||||||
assert!(index.contains("# Project project-api"));
|
|
||||||
assert!(index.contains("## Package API project-api"));
|
|
||||||
assert!(index.contains("## Module math"));
|
|
||||||
assert!(index.contains("## Module main"));
|
|
||||||
assert!(index.contains("- `math`"));
|
|
||||||
assert!(index.contains("- `add`"));
|
|
||||||
|
|
||||||
let package_api = package_api(&index, "project-api");
|
|
||||||
assert!(package_api.contains("### Module math"));
|
|
||||||
assert!(package_api.contains("- `fn add(left: i32, right: i32) -> i32`"));
|
|
||||||
assert!(package_api.contains("- `struct Pair`"));
|
|
||||||
assert!(
|
|
||||||
!package_api.contains("private_double"),
|
|
||||||
"non-exported function leaked into package API:\n{}",
|
|
||||||
package_api
|
|
||||||
);
|
|
||||||
|
|
||||||
let math_api = public_api_for_module(&index, "math");
|
|
||||||
assert!(math_api.contains("- `fn add(left: i32, right: i32) -> i32`"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn doc_workspace_renders_each_package_api_deterministically() {
|
|
||||||
let workspace = unique_path("workspace-api");
|
|
||||||
let scaffold = run_glagol([
|
|
||||||
OsStr::new("new"),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
OsStr::new("--template"),
|
|
||||||
OsStr::new("workspace"),
|
|
||||||
]);
|
|
||||||
assert_success("workspace scaffold", &scaffold);
|
|
||||||
|
|
||||||
let docs = unique_path("workspace-api-docs");
|
|
||||||
let output = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("doc workspace", &output);
|
|
||||||
let index = read_index(&docs);
|
|
||||||
assert!(index.contains("## Workspace"));
|
|
||||||
assert!(index.contains("- `packages/app`"));
|
|
||||||
assert!(index.contains("- `packages/libutil`"));
|
|
||||||
assert!(index.contains("## Package API app 0.1.0"));
|
|
||||||
assert!(index.contains("## Package API libutil 0.1.0"));
|
|
||||||
|
|
||||||
let app_api = package_api(&index, "app 0.1.0");
|
|
||||||
assert!(app_api.contains("None."));
|
|
||||||
|
|
||||||
let lib_api = package_api(&index, "libutil 0.1.0");
|
|
||||||
assert!(lib_api.contains("### Module libutil"));
|
|
||||||
assert!(lib_api.contains("- `fn answer() -> i32`"));
|
|
||||||
assert!(lib_api.contains("- `fn label() -> string`"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn doc_workspace_package_api_excludes_loaded_std_modules() {
|
|
||||||
let workspace = write_workspace_with_std_import("workspace-std-api");
|
|
||||||
let docs = unique_path("workspace-std-api-docs");
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("doc workspace std import", &output);
|
|
||||||
let index = read_index(&docs);
|
|
||||||
assert!(
|
|
||||||
index.contains("## Module option"),
|
|
||||||
"module summaries should still include loaded std module docs:\n{}",
|
|
||||||
index
|
|
||||||
);
|
|
||||||
|
|
||||||
let app_api = package_api(&index, "app 0.1.0");
|
|
||||||
assert!(app_api.contains("### Module main"));
|
|
||||||
assert!(app_api.contains("- `fn local_some(value: i32) -> (option i32)`"));
|
|
||||||
assert!(
|
|
||||||
!app_api.contains("Module std.option") && !app_api.contains("Module option"),
|
|
||||||
"loaded std module leaked into package API:\n{}",
|
|
||||||
app_api
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!app_api.contains("some_i32"),
|
|
||||||
"loaded std helper leaked into package API:\n{}",
|
|
||||||
app_api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn public_api_normalizes_local_aliases_and_omits_alias_exports() {
|
|
||||||
let source = r#"(module aliases (export Count Score Status measure))
|
|
||||||
|
|
||||||
(type Count i32)
|
|
||||||
(type MaybeCount (option Count))
|
|
||||||
|
|
||||||
(struct Score
|
|
||||||
(value Count)
|
|
||||||
(maybe MaybeCount))
|
|
||||||
|
|
||||||
(enum Status Ready (Blocked Count) (Maybe MaybeCount))
|
|
||||||
|
|
||||||
(fn hidden ((value Count)) -> Count
|
|
||||||
value)
|
|
||||||
|
|
||||||
(fn measure ((value Count) (maybe MaybeCount)) -> Count
|
|
||||||
value)
|
|
||||||
"#;
|
|
||||||
let file = write_file("alias-api", source);
|
|
||||||
let docs = unique_path("alias-api-docs");
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
file.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("doc aliases", &output);
|
|
||||||
let index = read_index(&docs);
|
|
||||||
assert!(
|
|
||||||
index.contains("- `Count`"),
|
|
||||||
"exports summary should retain the alias name"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
index.contains("- `hidden(value Count) -> Count`"),
|
|
||||||
"function summary should retain non-public declarations"
|
|
||||||
);
|
|
||||||
|
|
||||||
let api = public_api_for_module(&index, "aliases");
|
|
||||||
assert!(api.contains("- `fn measure(value: i32, maybe: (option i32)) -> i32`"));
|
|
||||||
assert!(api.contains(" - `value: i32`"));
|
|
||||||
assert!(api.contains(" - `maybe: (option i32)`"));
|
|
||||||
assert!(api.contains(" - `Blocked(i32)`"));
|
|
||||||
assert!(api.contains(" - `Maybe((option i32))`"));
|
|
||||||
assert!(
|
|
||||||
!api.contains("Count"),
|
|
||||||
"alias names leaked into public API:\n{}",
|
|
||||||
api
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!api.contains("hidden"),
|
|
||||||
"non-exported function leaked into public API:\n{}",
|
|
||||||
api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn repeated_doc_generation_is_byte_identical() {
|
|
||||||
let source = r#"(module stable (export value))
|
|
||||||
|
|
||||||
(fn value () -> i32
|
|
||||||
42)
|
|
||||||
"#;
|
|
||||||
let file = write_file("stable-api", source);
|
|
||||||
let docs = unique_path("stable-api-docs");
|
|
||||||
|
|
||||||
let first = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
file.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_success("first doc", &first);
|
|
||||||
let first_bytes = fs::read(docs.join("index.md")).expect("read first docs");
|
|
||||||
|
|
||||||
let second = run_glagol([
|
|
||||||
OsStr::new("doc"),
|
|
||||||
file.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
docs.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_success("second doc", &second);
|
|
||||||
let second_bytes = fs::read(docs.join("index.md")).expect("read second docs");
|
|
||||||
|
|
||||||
assert_eq!(first_bytes, second_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(name: &str, modules: &[(&str, &str)], main: &str) -> PathBuf {
|
|
||||||
let project = unique_path(name);
|
|
||||||
fs::create_dir_all(project.join("src")).expect("create project src");
|
|
||||||
fs::write(
|
|
||||||
project.join("slovo.toml"),
|
|
||||||
format!(
|
|
||||||
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.expect("write manifest");
|
|
||||||
for (module, source) in modules {
|
|
||||||
fs::write(project.join("src").join(format!("{}.slo", module)), source)
|
|
||||||
.expect("write module");
|
|
||||||
}
|
|
||||||
fs::write(project.join("src/main.slo"), main).expect("write main");
|
|
||||||
project
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_workspace_with_std_import(name: &str) -> PathBuf {
|
|
||||||
let workspace = unique_path(name);
|
|
||||||
let package = workspace.join("packages/app");
|
|
||||||
fs::create_dir_all(package.join("src")).expect("create workspace package src");
|
|
||||||
fs::write(
|
|
||||||
workspace.join("slovo.toml"),
|
|
||||||
"[workspace]\nmembers = [\"packages/app\"]\ndefault_package = \"app\"\n",
|
|
||||||
)
|
|
||||||
.expect("write workspace manifest");
|
|
||||||
fs::write(
|
|
||||||
package.join("slovo.toml"),
|
|
||||||
"[package]\nname = \"app\"\nversion = \"0.1.0\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
)
|
|
||||||
.expect("write package manifest");
|
|
||||||
fs::write(
|
|
||||||
package.join("src/main.slo"),
|
|
||||||
r#"(module main (export local_some))
|
|
||||||
|
|
||||||
(import std.option (some_i32))
|
|
||||||
|
|
||||||
(fn local_some ((value i32)) -> (option i32)
|
|
||||||
(some_i32 value))
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.expect("write package main");
|
|
||||||
workspace
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_file(name: &str, source: &str) -> PathBuf {
|
|
||||||
let path = unique_path(name).with_extension("slo");
|
|
||||||
fs::write(&path, source).expect("write fixture");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_index(docs: &Path) -> String {
|
|
||||||
fs::read_to_string(docs.join("index.md")).expect("read generated docs")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn package_api<'a>(docs: &'a str, package: &str) -> &'a str {
|
|
||||||
let heading = format!("## Package API {}", package);
|
|
||||||
let start = docs
|
|
||||||
.find(&heading)
|
|
||||||
.unwrap_or_else(|| panic!("missing package API heading `{}`\n{}", heading, docs));
|
|
||||||
let rest = &docs[start..];
|
|
||||||
let end = rest
|
|
||||||
.find("\n## Package API ")
|
|
||||||
.or_else(|| rest.find("\n## Module "))
|
|
||||||
.unwrap_or(rest.len());
|
|
||||||
&rest[..end]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn public_api_for_module<'a>(docs: &'a str, module: &str) -> &'a str {
|
|
||||||
let heading = format!("## Module {}", module);
|
|
||||||
let module_start = if docs.starts_with(&heading) {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
let marker = format!("\n{}", heading);
|
|
||||||
docs.find(&marker)
|
|
||||||
.map(|index| index + 1)
|
|
||||||
.unwrap_or_else(|| panic!("missing module heading `{}`\n{}", heading, docs))
|
|
||||||
};
|
|
||||||
let module_docs = &docs[module_start..];
|
|
||||||
let module_end = module_docs
|
|
||||||
.find("\n## Module ")
|
|
||||||
.unwrap_or(module_docs.len());
|
|
||||||
let module_docs = &module_docs[..module_end];
|
|
||||||
let public_start = module_docs.find("### Public API").unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"missing public API for module `{}`\n{}",
|
|
||||||
module, module_docs
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let public_docs = &module_docs[public_start..];
|
|
||||||
let public_end = public_docs
|
|
||||||
.find("\n### Structs")
|
|
||||||
.unwrap_or(public_docs.len());
|
|
||||||
&public_docs[..public_end]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_path(name: &str) -> PathBuf {
|
|
||||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let nanos = std::time::SystemTime::now()
|
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
|
||||||
.expect("system clock before UNIX_EPOCH")
|
|
||||||
.as_nanos();
|
|
||||||
std::env::temp_dir().join(format!(
|
|
||||||
"glagol-doc-api-beta11-{}-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
nanos,
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stdout.is_empty(),
|
|
||||||
"{} wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout)
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stderr.is_empty(),
|
|
||||||
"{} wrote stderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs,
|
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_WORKSPACE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn duplicate_package_keys_report_package_manifest_invalid() {
|
|
||||||
let workspace = write_workspace(
|
|
||||||
"duplicate-package-key",
|
|
||||||
"[workspace]\nmembers = [\"packages/app\"]\n",
|
|
||||||
&[WorkspacePackageSpec {
|
|
||||||
member: "packages/app",
|
|
||||||
manifest: "[package]\nname = \"app\"\nname = \"other\"\nversion = \"0.1.0\"\n",
|
|
||||||
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"check".as_ref(),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_exit_code("duplicate package key", &output, 1);
|
|
||||||
assert_json_diagnostic_code("duplicate package key", &output, "PackageManifestInvalid");
|
|
||||||
assert_json_diagnostic_code_absent("duplicate package key", &output, "ProjectManifestInvalid");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn invalid_dependency_key_reports_invalid_package_dependency_name() {
|
|
||||||
let workspace = write_workspace(
|
|
||||||
"invalid-dependency-key",
|
|
||||||
"[workspace]\nmembers = [\"packages/app\"]\n",
|
|
||||||
&[WorkspacePackageSpec {
|
|
||||||
member: "packages/app",
|
|
||||||
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nBad_Name = { path = \"../util\" }\n",
|
|
||||||
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"check".as_ref(),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_exit_code("invalid dependency key", &output, 1);
|
|
||||||
assert_json_diagnostic_code(
|
|
||||||
"invalid dependency key",
|
|
||||||
&output,
|
|
||||||
"InvalidPackageDependencyName",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn duplicate_dependency_keys_report_duplicate_package_dependency_name() {
|
|
||||||
let workspace = write_workspace(
|
|
||||||
"duplicate-dependency-key",
|
|
||||||
"[workspace]\nmembers = [\"packages/app\"]\n",
|
|
||||||
&[WorkspacePackageSpec {
|
|
||||||
member: "packages/app",
|
|
||||||
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nutil = { path = \"../util\" }\nutil = { path = \"../util-again\" }\n",
|
|
||||||
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"--json-diagnostics".as_ref(),
|
|
||||||
"check".as_ref(),
|
|
||||||
workspace.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_exit_code("duplicate dependency key", &output, 1);
|
|
||||||
assert_json_diagnostic_code(
|
|
||||||
"duplicate dependency key",
|
|
||||||
&output,
|
|
||||||
"DuplicatePackageDependencyName",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn valid_dependency_identity_checks_cleanly() {
|
|
||||||
let workspace = write_workspace(
|
|
||||||
"valid-dependency-identity",
|
|
||||||
"[workspace]\nmembers = [\"packages/app\", \"packages/util\"]\n",
|
|
||||||
&[
|
|
||||||
WorkspacePackageSpec {
|
|
||||||
member: "packages/util",
|
|
||||||
manifest: "[package]\nname = \"util\"\nversion = \"0.1.0\"\n",
|
|
||||||
modules: &[(
|
|
||||||
"util",
|
|
||||||
"(module util (export answer))\n\n(fn answer () -> i32\n 42)\n",
|
|
||||||
)],
|
|
||||||
},
|
|
||||||
WorkspacePackageSpec {
|
|
||||||
member: "packages/app",
|
|
||||||
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nutil = { path = \"../util\" }\n",
|
|
||||||
modules: &[(
|
|
||||||
"main",
|
|
||||||
"(module main)\n\n(import util.util (answer))\n\n(fn main () -> i32\n (answer))\n",
|
|
||||||
)],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol(["check".as_ref(), workspace.as_os_str()]);
|
|
||||||
assert_success_stdout("valid dependency identity", output, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WorkspacePackageSpec<'a> {
|
|
||||||
member: &'a str,
|
|
||||||
manifest: &'a str,
|
|
||||||
modules: &'a [(&'a str, &'a str)],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_workspace(
|
|
||||||
name: &str,
|
|
||||||
workspace_manifest: &str,
|
|
||||||
packages: &[WorkspacePackageSpec<'_>],
|
|
||||||
) -> PathBuf {
|
|
||||||
let root = unique_path(name);
|
|
||||||
fs::create_dir_all(&root).expect("create workspace root");
|
|
||||||
fs::write(root.join("slovo.toml"), workspace_manifest).expect("write workspace manifest");
|
|
||||||
|
|
||||||
for package in packages {
|
|
||||||
let package_root = root.join(package.member);
|
|
||||||
let src = package_root.join("src");
|
|
||||||
fs::create_dir_all(&src).expect("create workspace package src");
|
|
||||||
fs::write(package_root.join("slovo.toml"), package.manifest)
|
|
||||||
.expect("write workspace package manifest");
|
|
||||||
for (module, source) in package.modules {
|
|
||||||
fs::write(src.join(format!("{}.slo", module)), source)
|
|
||||||
.expect("write workspace package module");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_path(name: &str) -> PathBuf {
|
|
||||||
let id = NEXT_WORKSPACE_ID.fetch_add(1, Ordering::SeqCst);
|
|
||||||
let nanos = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.map(|duration| duration.as_nanos())
|
|
||||||
.unwrap_or(0);
|
|
||||||
std::env::temp_dir().join(format!(
|
|
||||||
"glagol-package-workspace-discipline-beta24-{}-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
nanos,
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<std::ffi::OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_stdout(context: &str, output: Output, expected: &str) {
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
expected,
|
|
||||||
"{} stdout mismatch",
|
|
||||||
context
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stderr.is_empty(),
|
|
||||||
"{} wrote stderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_exit_code(context: &str, output: &Output, expected: i32) {
|
|
||||||
assert_eq!(
|
|
||||||
output.status.code(),
|
|
||||||
Some(expected),
|
|
||||||
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_json_diagnostic_code(context: &str, output: &Output, expected: &str) {
|
|
||||||
let diagnostics = diagnostic_text(output);
|
|
||||||
assert!(
|
|
||||||
diagnostics.contains(&format!(r#""code":"{}""#, expected)),
|
|
||||||
"{} did not report `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
expected,
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_json_diagnostic_code_absent(context: &str, output: &Output, unexpected: &str) {
|
|
||||||
let diagnostics = diagnostic_text(output);
|
|
||||||
assert!(
|
|
||||||
!diagnostics.contains(&format!(r#""code":"{}""#, unexpected)),
|
|
||||||
"{} unexpectedly reported `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
unexpected,
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn diagnostic_text(output: &Output) -> String {
|
|
||||||
format!(
|
|
||||||
"{}{}",
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -167,25 +167,11 @@ const DIAGNOSTIC_SNAPSHOTS: &[&str] = &[
|
|||||||
"std-random-uuid-unsupported.diag",
|
"std-random-uuid-unsupported.diag",
|
||||||
"std-result-map-unsupported.diag",
|
"std-result-map-unsupported.diag",
|
||||||
"std-vec-empty-generic-unsupported.diag",
|
"std-vec-empty-generic-unsupported.diag",
|
||||||
"std-string-byte-at-result-arity.diag",
|
|
||||||
"std-string-byte-at-result-bool-context.diag",
|
|
||||||
"std-string-byte-at-result-context.diag",
|
|
||||||
"std-string-byte-at-result-helper-shadow.diag",
|
|
||||||
"std-string-byte-at-result-name-shadow.diag",
|
|
||||||
"std-string-byte-at-result-type.diag",
|
|
||||||
"std-string-byte-at-unsupported.diag",
|
|
||||||
"std-string-concat-arity.diag",
|
"std-string-concat-arity.diag",
|
||||||
"std-string-concat-helper-shadow.diag",
|
"std-string-concat-helper-shadow.diag",
|
||||||
"std-string-concat-result-context.diag",
|
"std-string-concat-result-context.diag",
|
||||||
"std-string-concat-type.diag",
|
"std-string-concat-type.diag",
|
||||||
"std-string-concat-unsupported-string-container.diag",
|
"std-string-concat-unsupported-string-container.diag",
|
||||||
"std-string-contains-unsupported.diag",
|
|
||||||
"std-string-ends-with-arity.diag",
|
|
||||||
"std-string-ends-with-context.diag",
|
|
||||||
"std-string-ends-with-helper-shadow.diag",
|
|
||||||
"std-string-ends-with-name-shadow.diag",
|
|
||||||
"std-string-ends-with-type.diag",
|
|
||||||
"std-string-find-result-unsupported.diag",
|
|
||||||
"std-string-from-i64-unsupported.diag",
|
"std-string-from-i64-unsupported.diag",
|
||||||
"std-string-index-unsupported.diag",
|
"std-string-index-unsupported.diag",
|
||||||
"std-string-len-type.diag",
|
"std-string-len-type.diag",
|
||||||
@ -234,19 +220,7 @@ const DIAGNOSTIC_SNAPSHOTS: &[&str] = &[
|
|||||||
"std-string-parse-i32-whitespace-unsupported.diag",
|
"std-string-parse-i32-whitespace-unsupported.diag",
|
||||||
"std-string-parse-string-unsupported.diag",
|
"std-string-parse-string-unsupported.diag",
|
||||||
"std-string-scan-unsupported.diag",
|
"std-string-scan-unsupported.diag",
|
||||||
"std-string-slice-result-arity.diag",
|
|
||||||
"std-string-slice-result-bool-context.diag",
|
|
||||||
"std-string-slice-result-context.diag",
|
|
||||||
"std-string-slice-result-helper-shadow.diag",
|
|
||||||
"std-string-slice-result-name-shadow.diag",
|
|
||||||
"std-string-slice-result-type.diag",
|
|
||||||
"std-string-slice-unsupported.diag",
|
"std-string-slice-unsupported.diag",
|
||||||
"std-string-split-unsupported.diag",
|
|
||||||
"std-string-starts-with-arity.diag",
|
|
||||||
"std-string-starts-with-context.diag",
|
|
||||||
"std-string-starts-with-helper-shadow.diag",
|
|
||||||
"std-string-starts-with-name-shadow.diag",
|
|
||||||
"std-string-starts-with-type.diag",
|
|
||||||
"std-string-tokenize-unsupported.diag",
|
"std-string-tokenize-unsupported.diag",
|
||||||
"std-terminal-clear-unsupported.diag",
|
"std-terminal-clear-unsupported.diag",
|
||||||
"std-terminal-echo-unsupported.diag",
|
"std-terminal-echo-unsupported.diag",
|
||||||
@ -1221,22 +1195,6 @@ const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"i64_value",
|
"i64_value",
|
||||||
"u64_value",
|
"u64_value",
|
||||||
"f64_value",
|
"f64_value",
|
||||||
"parse_string_value_result",
|
|
||||||
"parse_bool_value_result",
|
|
||||||
"parse_i32_value_result",
|
|
||||||
"parse_u32_value_result",
|
|
||||||
"parse_i64_value_result",
|
|
||||||
"parse_u64_value_result",
|
|
||||||
"parse_f64_value_result",
|
|
||||||
"parse_null_value_result",
|
|
||||||
"parse_string_document_result",
|
|
||||||
"parse_bool_document_result",
|
|
||||||
"parse_i32_document_result",
|
|
||||||
"parse_u32_document_result",
|
|
||||||
"parse_i64_document_result",
|
|
||||||
"parse_u64_document_result",
|
|
||||||
"parse_f64_document_result",
|
|
||||||
"parse_null_document_result",
|
|
||||||
"field_string",
|
"field_string",
|
||||||
"field_bool",
|
"field_bool",
|
||||||
"field_i32",
|
"field_i32",
|
||||||
@ -1263,42 +1221,6 @@ const STANDARD_JSON_RUNTIME_NAMES: &[&str] = &[
|
|||||||
"std.num.i64_to_string",
|
"std.num.i64_to_string",
|
||||||
"std.num.u64_to_string",
|
"std.num.u64_to_string",
|
||||||
"std.num.f64_to_string",
|
"std.num.f64_to_string",
|
||||||
"std.json.parse_string_value_result",
|
|
||||||
"std.json.parse_bool_value_result",
|
|
||||||
"std.json.parse_i32_value_result",
|
|
||||||
"std.json.parse_u32_value_result",
|
|
||||||
"std.json.parse_i64_value_result",
|
|
||||||
"std.json.parse_u64_value_result",
|
|
||||||
"std.json.parse_f64_value_result",
|
|
||||||
];
|
|
||||||
|
|
||||||
const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
|
|
||||||
"(import std.string (trim_ascii))",
|
|
||||||
"std.json.quote_string",
|
|
||||||
"std.string.concat",
|
|
||||||
"std.num.i32_to_string",
|
|
||||||
"std.num.u32_to_string",
|
|
||||||
"std.num.i64_to_string",
|
|
||||||
"std.num.u64_to_string",
|
|
||||||
"std.num.f64_to_string",
|
|
||||||
"std.json.parse_string_value_result",
|
|
||||||
"std.json.parse_bool_value_result",
|
|
||||||
"std.json.parse_i32_value_result",
|
|
||||||
"std.json.parse_u32_value_result",
|
|
||||||
"std.json.parse_i64_value_result",
|
|
||||||
"std.json.parse_u64_value_result",
|
|
||||||
"std.json.parse_f64_value_result",
|
|
||||||
];
|
|
||||||
|
|
||||||
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
|
|
||||||
"parse_string_document_result",
|
|
||||||
"parse_bool_document_result",
|
|
||||||
"parse_i32_document_result",
|
|
||||||
"parse_u32_document_result",
|
|
||||||
"parse_i64_document_result",
|
|
||||||
"parse_u64_document_result",
|
|
||||||
"parse_f64_document_result",
|
|
||||||
"parse_null_document_result",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -1338,16 +1260,6 @@ const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
const STANDARD_STRING_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_STRING_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
"len",
|
"len",
|
||||||
"concat",
|
"concat",
|
||||||
"byte_at_result",
|
|
||||||
"slice_result",
|
|
||||||
"starts_with",
|
|
||||||
"ends_with",
|
|
||||||
"contains",
|
|
||||||
"index_of_option",
|
|
||||||
"last_index_of_option",
|
|
||||||
"trim_ascii_start",
|
|
||||||
"trim_ascii_end",
|
|
||||||
"trim_ascii",
|
|
||||||
"parse_i32_result",
|
"parse_i32_result",
|
||||||
"parse_i32_option",
|
"parse_i32_option",
|
||||||
"parse_u32_result",
|
"parse_u32_result",
|
||||||
@ -1556,14 +1468,9 @@ const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
"starts_with",
|
|
||||||
"without_prefix",
|
|
||||||
"ends_with",
|
|
||||||
"without_suffix",
|
|
||||||
"drop",
|
"drop",
|
||||||
"reverse",
|
"reverse",
|
||||||
"subvec",
|
"subvec",
|
||||||
@ -1595,14 +1502,9 @@ const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
"starts_with",
|
|
||||||
"without_prefix",
|
|
||||||
"ends_with",
|
|
||||||
"without_suffix",
|
|
||||||
"drop",
|
"drop",
|
||||||
"reverse",
|
"reverse",
|
||||||
"subvec",
|
"subvec",
|
||||||
@ -3705,10 +3607,6 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
|
|||||||
"std.string.parse_i64_result",
|
"std.string.parse_i64_result",
|
||||||
"std.string.parse_u32_result",
|
"std.string.parse_u32_result",
|
||||||
"std.string.parse_i32_result",
|
"std.string.parse_i32_result",
|
||||||
"std.string.byte_at_result",
|
|
||||||
"std.string.slice_result",
|
|
||||||
"std.string.starts_with",
|
|
||||||
"std.string.ends_with",
|
|
||||||
"std.string.concat",
|
"std.string.concat",
|
||||||
"std.string.len",
|
"std.string.len",
|
||||||
],
|
],
|
||||||
@ -4468,17 +4366,24 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
|
|||||||
}
|
}
|
||||||
assert_std_only_contains(
|
assert_std_only_contains(
|
||||||
&slovo_json,
|
&slovo_json,
|
||||||
STANDARD_JSON_ALLOWED_STD_NAMES,
|
STANDARD_JSON_RUNTIME_NAMES,
|
||||||
"Slovo std/json.slo must not introduce other compiler-known std names",
|
"Slovo std/json.slo must not introduce other compiler-known std names",
|
||||||
);
|
);
|
||||||
assert_std_only_contains(
|
assert_std_only_contains(
|
||||||
&glagol_json,
|
&glagol_json,
|
||||||
STANDARD_JSON_ALLOWED_STD_NAMES,
|
STANDARD_JSON_RUNTIME_NAMES,
|
||||||
"Glagol local json fixture must not introduce other compiler-known std names",
|
"Glagol local json fixture must not introduce other compiler-known std names",
|
||||||
);
|
);
|
||||||
for source in [&slovo_json, &glagol_json] {
|
for source in [&slovo_json, &glagol_json] {
|
||||||
assert_deferred_json_surface_absent(source, "standard json facade");
|
assert!(
|
||||||
assert_json_document_scalar_helpers_are_source_authored(source, "standard json facade");
|
!source.contains("parse")
|
||||||
|
&& !source.contains("token")
|
||||||
|
&& !source.contains("map")
|
||||||
|
&& !source.contains("unicode")
|
||||||
|
&& !source.contains("schema")
|
||||||
|
&& !source.contains("stream"),
|
||||||
|
"standard json facade must not claim deferred parser or richer data policies"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
||||||
assert!(
|
assert!(
|
||||||
@ -7333,17 +7238,10 @@ fn assert_project_std_import_json_tooling_matches_fixture(project: &Path) {
|
|||||||
concat!(
|
concat!(
|
||||||
"test \"explicit std json quote escapes facade\" ... ok\n",
|
"test \"explicit std json quote escapes facade\" ... ok\n",
|
||||||
"test \"explicit std json scalar values facade\" ... ok\n",
|
"test \"explicit std json scalar values facade\" ... ok\n",
|
||||||
"test \"explicit std json primitive scalar parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json primitive scalar parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json string token parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json string token parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse trimmed success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse plain success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse trailing failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json fields facade\" ... ok\n",
|
"test \"explicit std json fields facade\" ... ok\n",
|
||||||
"test \"explicit std json arrays objects facade\" ... ok\n",
|
"test \"explicit std json arrays objects facade\" ... ok\n",
|
||||||
"test \"explicit std json facade all\" ... ok\n",
|
"test \"explicit std json facade all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"5 test(s) passed\n",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -7396,18 +7294,13 @@ fn assert_project_std_import_string_tooling_matches_fixture(project: &Path) {
|
|||||||
STANDARD_STRING_SOURCE_FACADE_ALPHA,
|
STANDARD_STRING_SOURCE_FACADE_ALPHA,
|
||||||
concat!(
|
concat!(
|
||||||
"test \"explicit std string len concat\" ... ok\n",
|
"test \"explicit std string len concat\" ... ok\n",
|
||||||
"test \"explicit std string byte_at_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit std string slice_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit std string boundary wrappers\" ... ok\n",
|
|
||||||
"test \"explicit std string parse result wrappers\" ... ok\n",
|
"test \"explicit std string parse result wrappers\" ... ok\n",
|
||||||
"test \"explicit std string parse option wrappers\" ... ok\n",
|
"test \"explicit std string parse option wrappers\" ... ok\n",
|
||||||
"test \"explicit std string parse integer fallbacks\" ... ok\n",
|
"test \"explicit std string parse integer fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string parse float bool fallbacks\" ... ok\n",
|
"test \"explicit std string parse float bool fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string parse custom fallbacks\" ... ok\n",
|
"test \"explicit std string parse custom fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string search helpers\" ... ok\n",
|
|
||||||
"test \"explicit std string ascii trim helpers\" ... ok\n",
|
|
||||||
"test \"explicit std string helpers all\" ... ok\n",
|
"test \"explicit std string helpers all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"7 test(s) passed\n",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -7689,11 +7582,6 @@ fn assert_project_std_import_vec_i64_tooling_matches_fixture(project: &Path) {
|
|||||||
"test \"explicit std vec_i64 builder helpers\" ... ok\n",
|
"test \"explicit std vec_i64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 query helpers\" ... ok\n",
|
"test \"explicit std vec_i64 query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 option query helpers\" ... ok\n",
|
"test \"explicit std vec_i64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 starts_with helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 ends_with helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 without_suffix helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 without_prefix helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 transform helpers\" ... ok\n",
|
"test \"explicit std vec_i64 transform helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 subvec helper\" ... ok\n",
|
"test \"explicit std vec_i64 subvec helper\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 insert helper\" ... ok\n",
|
"test \"explicit std vec_i64 insert helper\" ... ok\n",
|
||||||
@ -7704,7 +7592,7 @@ fn assert_project_std_import_vec_i64_tooling_matches_fixture(project: &Path) {
|
|||||||
"test \"explicit std vec_i64 remove range helper\" ... ok\n",
|
"test \"explicit std vec_i64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 real program helpers\" ... ok\n",
|
"test \"explicit std vec_i64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 helpers all\" ... ok\n",
|
"test \"explicit std vec_i64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"15 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std import vec_i64 project test",
|
"std import vec_i64 project test",
|
||||||
);
|
);
|
||||||
@ -7788,7 +7676,6 @@ fn assert_project_std_import_vec_f64_tooling_matches_fixture(project: &Path) {
|
|||||||
"test \"explicit std vec_f64 builder helpers\" ... ok\n",
|
"test \"explicit std vec_f64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 query helpers\" ... ok\n",
|
"test \"explicit std vec_f64 query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 option query helpers\" ... ok\n",
|
"test \"explicit std vec_f64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_f64 starts_with helper\" ... ok\n",
|
"test \"explicit std vec_f64 starts_with helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 ends_with helper\" ... ok\n",
|
"test \"explicit std vec_f64 ends_with helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 without_suffix helper\" ... ok\n",
|
"test \"explicit std vec_f64 without_suffix helper\" ... ok\n",
|
||||||
@ -7803,7 +7690,7 @@ fn assert_project_std_import_vec_f64_tooling_matches_fixture(project: &Path) {
|
|||||||
"test \"explicit std vec_f64 remove range helper\" ... ok\n",
|
"test \"explicit std vec_f64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 real program helpers\" ... ok\n",
|
"test \"explicit std vec_f64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 helpers all\" ... ok\n",
|
"test \"explicit std vec_f64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"19 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std import vec_f64 project test",
|
"std import vec_f64 project test",
|
||||||
);
|
);
|
||||||
@ -8878,18 +8765,13 @@ fn assert_project_std_layout_local_string_tooling_matches_fixture(project: &Path
|
|||||||
test,
|
test,
|
||||||
concat!(
|
concat!(
|
||||||
"test \"explicit local string len concat\" ... ok\n",
|
"test \"explicit local string len concat\" ... ok\n",
|
||||||
"test \"explicit local string byte_at_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit local string slice_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit local string boundary wrappers\" ... ok\n",
|
|
||||||
"test \"explicit local string parse result wrappers\" ... ok\n",
|
"test \"explicit local string parse result wrappers\" ... ok\n",
|
||||||
"test \"explicit local string parse option wrappers\" ... ok\n",
|
"test \"explicit local string parse option wrappers\" ... ok\n",
|
||||||
"test \"explicit local string parse integer fallbacks\" ... ok\n",
|
"test \"explicit local string parse integer fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string parse float bool fallbacks\" ... ok\n",
|
"test \"explicit local string parse float bool fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string parse custom fallbacks\" ... ok\n",
|
"test \"explicit local string parse custom fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string search helpers\" ... ok\n",
|
|
||||||
"test \"explicit local string ascii trim helpers\" ... ok\n",
|
|
||||||
"test \"explicit local string helpers all\" ... ok\n",
|
"test \"explicit local string helpers all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"7 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std layout local string project test",
|
"std layout local string project test",
|
||||||
);
|
);
|
||||||
@ -8920,21 +8802,17 @@ fn assert_standard_string_source_fallback_helpers_alpha(project: &Path) {
|
|||||||
"std.string.parse_i64_result",
|
"std.string.parse_i64_result",
|
||||||
"std.string.parse_u32_result",
|
"std.string.parse_u32_result",
|
||||||
"std.string.parse_i32_result",
|
"std.string.parse_i32_result",
|
||||||
"std.string.byte_at_result",
|
|
||||||
"std.string.slice_result",
|
|
||||||
"std.string.starts_with",
|
|
||||||
"std.string.ends_with",
|
|
||||||
"std.string.concat",
|
"std.string.concat",
|
||||||
"std.string.len",
|
"std.string.len",
|
||||||
],
|
],
|
||||||
"standard string source helper fixture must use only existing std.string runtime names",
|
"standard string source helper fixture must use only existing std.string runtime names",
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!string.contains("locale")
|
!string.contains("trim")
|
||||||
|
&& !string.contains("locale")
|
||||||
&& !string.contains("unicode")
|
&& !string.contains("unicode")
|
||||||
&& !string.contains("bytes")
|
&& !string.contains("bytes")
|
||||||
&& !string.contains("case_insensitive")
|
&& !string.contains("case_insensitive")
|
||||||
&& !string.contains("regex")
|
|
||||||
&& !string.contains("host_error"),
|
&& !string.contains("host_error"),
|
||||||
"standard string source helper fixture must not claim deferred parsing or richer error APIs"
|
"standard string source helper fixture must not claim deferred parsing or richer error APIs"
|
||||||
);
|
);
|
||||||
@ -9547,17 +9425,10 @@ fn assert_project_std_layout_local_json_tooling_matches_fixture(project: &Path)
|
|||||||
concat!(
|
concat!(
|
||||||
"test \"explicit local json quote escapes facade\" ... ok\n",
|
"test \"explicit local json quote escapes facade\" ... ok\n",
|
||||||
"test \"explicit local json scalar values facade\" ... ok\n",
|
"test \"explicit local json scalar values facade\" ... ok\n",
|
||||||
"test \"explicit local json primitive scalar parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json primitive scalar parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json string token parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json string token parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse trimmed success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse plain success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse trailing failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json fields facade\" ... ok\n",
|
"test \"explicit local json fields facade\" ... ok\n",
|
||||||
"test \"explicit local json arrays objects facade\" ... ok\n",
|
"test \"explicit local json arrays objects facade\" ... ok\n",
|
||||||
"test \"explicit local json facade all\" ... ok\n",
|
"test \"explicit local json facade all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"5 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std layout local json project test",
|
"std layout local json project test",
|
||||||
);
|
);
|
||||||
@ -9588,14 +9459,19 @@ fn assert_standard_json_source_facade_alpha(project: &Path) {
|
|||||||
}
|
}
|
||||||
assert_std_only_contains(
|
assert_std_only_contains(
|
||||||
&json_source,
|
&json_source,
|
||||||
STANDARD_JSON_ALLOWED_STD_NAMES,
|
STANDARD_JSON_RUNTIME_NAMES,
|
||||||
"standard json source facade fixture must use only approved std runtime names directly",
|
"standard json source facade fixture must use only approved std runtime names directly",
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!main.contains("std."),
|
!main.contains("std.")
|
||||||
"standard json source facade fixture main must remain local"
|
&& !json_source.contains("parse")
|
||||||
|
&& !json_source.contains("token")
|
||||||
|
&& !json_source.contains("map")
|
||||||
|
&& !json_source.contains("unicode")
|
||||||
|
&& !json_source.contains("schema")
|
||||||
|
&& !json_source.contains("stream"),
|
||||||
|
"standard json source facade fixture must remain local and must not claim deferred JSON policies"
|
||||||
);
|
);
|
||||||
assert_deferred_json_surface_absent(&json_source, "standard json source facade fixture");
|
|
||||||
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
||||||
assert!(
|
assert!(
|
||||||
json_source.contains(&format!("(fn {} ", helper)),
|
json_source.contains(&format!("(fn {} ", helper)),
|
||||||
@ -9908,11 +9784,6 @@ fn assert_project_std_layout_local_vec_i64_tooling_matches_fixture(project: &Pat
|
|||||||
"test \"explicit local vec_i64 builder helpers\" ... ok\n",
|
"test \"explicit local vec_i64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 query helpers\" ... ok\n",
|
"test \"explicit local vec_i64 query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 option query helpers\" ... ok\n",
|
"test \"explicit local vec_i64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 starts_with helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 ends_with helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 without_suffix helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 without_prefix helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 transform helpers\" ... ok\n",
|
"test \"explicit local vec_i64 transform helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 subvec helper\" ... ok\n",
|
"test \"explicit local vec_i64 subvec helper\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 insert helper\" ... ok\n",
|
"test \"explicit local vec_i64 insert helper\" ... ok\n",
|
||||||
@ -9923,7 +9794,7 @@ fn assert_project_std_layout_local_vec_i64_tooling_matches_fixture(project: &Pat
|
|||||||
"test \"explicit local vec_i64 remove range helper\" ... ok\n",
|
"test \"explicit local vec_i64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 real program helpers\" ... ok\n",
|
"test \"explicit local vec_i64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 helpers all\" ... ok\n",
|
"test \"explicit local vec_i64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"15 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std layout local vec_i64 project test",
|
"std layout local vec_i64 project test",
|
||||||
);
|
);
|
||||||
@ -9947,7 +9818,6 @@ fn assert_project_std_layout_local_vec_f64_tooling_matches_fixture(project: &Pat
|
|||||||
"test \"explicit local vec_f64 builder helpers\" ... ok\n",
|
"test \"explicit local vec_f64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 query helpers\" ... ok\n",
|
"test \"explicit local vec_f64 query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 option query helpers\" ... ok\n",
|
"test \"explicit local vec_f64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_f64 starts_with helper\" ... ok\n",
|
"test \"explicit local vec_f64 starts_with helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 ends_with helper\" ... ok\n",
|
"test \"explicit local vec_f64 ends_with helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 without_suffix helper\" ... ok\n",
|
"test \"explicit local vec_f64 without_suffix helper\" ... ok\n",
|
||||||
@ -9962,7 +9832,7 @@ fn assert_project_std_layout_local_vec_f64_tooling_matches_fixture(project: &Pat
|
|||||||
"test \"explicit local vec_f64 remove range helper\" ... ok\n",
|
"test \"explicit local vec_f64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 real program helpers\" ... ok\n",
|
"test \"explicit local vec_f64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 helpers all\" ... ok\n",
|
"test \"explicit local vec_f64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"19 test(s) passed\n",
|
||||||
),
|
),
|
||||||
"std layout local vec_f64 project test",
|
"std layout local vec_f64 project test",
|
||||||
);
|
);
|
||||||
@ -10730,55 +10600,6 @@ fn assert_std_only_contains(source: &str, allowed: &[&str], context: &str) {
|
|||||||
assert!(!remaining.contains("std."), "{}", context);
|
assert!(!remaining.contains("std."), "{}", context);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_deferred_json_surface_absent(source: &str, context: &str) {
|
|
||||||
for deferred in [
|
|
||||||
"parse_object",
|
|
||||||
"parse_array",
|
|
||||||
"parse_value",
|
|
||||||
"tokenize",
|
|
||||||
"tokenizer",
|
|
||||||
"schema",
|
|
||||||
"stream",
|
|
||||||
"unicode",
|
|
||||||
"map",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!source.contains(deferred),
|
|
||||||
"{} must not claim deferred JSON `{}` policies",
|
|
||||||
context,
|
|
||||||
deferred
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_json_document_scalar_helpers_are_source_authored(source: &str, context: &str) {
|
|
||||||
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
||||||
assert!(
|
|
||||||
!source.contains(&format!("std.json.{}", helper)),
|
|
||||||
"{} must keep `{}` source-authored, not compiler-known",
|
|
||||||
context,
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for private_prefix in [
|
|
||||||
"__glagol_json_parse_string_document",
|
|
||||||
"__glagol_json_parse_bool_document",
|
|
||||||
"__glagol_json_parse_i32_document",
|
|
||||||
"__glagol_json_parse_u32_document",
|
|
||||||
"__glagol_json_parse_i64_document",
|
|
||||||
"__glagol_json_parse_u64_document",
|
|
||||||
"__glagol_json_parse_f64_document",
|
|
||||||
"__glagol_json_parse_null_document",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!source.contains(private_prefix),
|
|
||||||
"{} must not introduce private JSON document runtime symbol `{}`",
|
|
||||||
context,
|
|
||||||
private_prefix
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn repo_root() -> PathBuf {
|
fn repo_root() -> PathBuf {
|
||||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||||
.parent()
|
.parent()
|
||||||
|
|||||||
@ -1,239 +0,0 @@
|
|||||||
use std::{
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
const CASES: &[ReservedCase] = &[
|
|
||||||
ReservedCase {
|
|
||||||
name: "generic-function",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn id (type_params T) ((value T)) -> T
|
|
||||||
value)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericFunction",
|
|
||||||
message: "generic function declarations are reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "generic-type-alias",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(type VecOf (type_params T) (vec T))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericTypeAlias",
|
|
||||||
message: "parameterized type aliases are reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "generic-type-parameter",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(let xs (vec T) (std.vec.i32.empty))
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericTypeParameter",
|
|
||||||
message: "generic type parameter `T` is reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "generic-vector-spelling",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (vec)
|
|
||||||
(std.vec.i32.empty))
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericTypeParameter",
|
|
||||||
message: "generic vector syntax is reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "map-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (map string i32)
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedMapType",
|
|
||||||
message: "`map` types are reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "set-type",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (set string)
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedSetType",
|
|
||||||
message: "`set` types are reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "std-vec-empty",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.vec.empty i32)
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericStandardLibraryCall",
|
|
||||||
message:
|
|
||||||
"generic standard-library call `std.vec.empty` is reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
ReservedCase {
|
|
||||||
name: "std-result-map",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.result.map (ok string i32 "a") mapper)
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
code: "UnsupportedGenericStandardLibraryCall",
|
|
||||||
message:
|
|
||||||
"generic standard-library call `std.result.map` is reserved but not supported in the current beta",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_fmt_and_project_paths_reject_reserved_generic_collection_surface() {
|
|
||||||
for case in CASES {
|
|
||||||
let fixture = write_fixture(case);
|
|
||||||
|
|
||||||
let check = run_glagol([OsStr::new("check"), fixture.as_os_str()]);
|
|
||||||
assert_rejection(&format!("{} check", case.name), &check, case);
|
|
||||||
|
|
||||||
let fmt = run_glagol([
|
|
||||||
OsStr::new("fmt"),
|
|
||||||
OsStr::new("--check"),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_rejection(&format!("{} fmt --check", case.name), &fmt, case);
|
|
||||||
|
|
||||||
let project = write_project(case);
|
|
||||||
let project_check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
|
||||||
assert_rejection(
|
|
||||||
&format!("{} project check", case.name),
|
|
||||||
&project_check,
|
|
||||||
case,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReservedCase {
|
|
||||||
name: &'static str,
|
|
||||||
source: &'static str,
|
|
||||||
code: &'static str,
|
|
||||||
message: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_rejection(context: &str, output: &Output, case: &ReservedCase) {
|
|
||||||
assert_eq!(
|
|
||||||
output.status.code(),
|
|
||||||
Some(1),
|
|
||||||
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stdout.is_empty(),
|
|
||||||
"{} wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout)
|
|
||||||
);
|
|
||||||
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(&format!("error[{}]", case.code)),
|
|
||||||
"{} human diagnostic did not contain code `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
case.code,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(&format!(" (code {})", case.code)),
|
|
||||||
"{} machine diagnostic did not contain code `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
case.code,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(case.message),
|
|
||||||
"{} stderr did not contain message `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
case.message,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!stderr.contains("beta.9"),
|
|
||||||
"{} stderr still used beta.9 wording:\n{}",
|
|
||||||
context,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(case: &ReservedCase) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let path = unique_base_path(&format!("file-{}-{}", id, case.name)).with_extension("slo");
|
|
||||||
fs::write(&path, case.source)
|
|
||||||
.unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(case: &ReservedCase) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let root = unique_base_path(&format!("project-{}-{}", id, case.name));
|
|
||||||
let src = root.join("src");
|
|
||||||
fs::create_dir_all(&src).unwrap_or_else(|err| panic!("create `{}`: {}", src.display(), err));
|
|
||||||
fs::write(
|
|
||||||
root.join("slovo.toml"),
|
|
||||||
format!(
|
|
||||||
"[project]\nname = \"reserved-beta15-{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
case.name
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|err| panic!("write project manifest for `{}`: {}", case.name, err));
|
|
||||||
fs::write(src.join("main.slo"), case.source)
|
|
||||||
.unwrap_or_else(|err| panic!("write project source for `{}`: {}", case.name, err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_base_path(name: &str) -> PathBuf {
|
|
||||||
let nanos = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.map(|duration| duration.as_nanos())
|
|
||||||
.unwrap_or(0);
|
|
||||||
std::env::temp_dir().join(format!(
|
|
||||||
"glagol-reserved-beta15-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
nanos,
|
|
||||||
name
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env, fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn run_manifest_records_success_report_stdout_and_program_args() {
|
|
||||||
let Some(clang) = find_clang() else {
|
|
||||||
eprintln!("skipping run manifest success report: set GLAGOL_CLANG or install clang");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let source = write_fixture(
|
|
||||||
"success",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(print_string "beta22-out")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
"slo",
|
|
||||||
);
|
|
||||||
let manifest_path = temp_path("success-manifest", "manifest.slo");
|
|
||||||
|
|
||||||
let mut command = Command::new(compiler_path());
|
|
||||||
command
|
|
||||||
.arg("run")
|
|
||||||
.arg(&source)
|
|
||||||
.arg("--manifest")
|
|
||||||
.arg(&manifest_path)
|
|
||||||
.arg("--")
|
|
||||||
.arg("alpha")
|
|
||||||
.arg("two words")
|
|
||||||
.arg("--literal")
|
|
||||||
.env("GLAGOL_CLANG", &clang);
|
|
||||||
configure_clang_runtime_env(&mut command, &clang);
|
|
||||||
|
|
||||||
let output = command.output().expect("run glagol success manifest");
|
|
||||||
assert_success_stdout("run manifest success", &output, "beta22-out\n");
|
|
||||||
|
|
||||||
let manifest = read_manifest(&manifest_path);
|
|
||||||
assert!(
|
|
||||||
manifest.contains(" (mode run)\n")
|
|
||||||
&& manifest.contains(" (success true)\n")
|
|
||||||
&& manifest.contains(" (run-report\n")
|
|
||||||
&& manifest.contains(" (exit-status 0)\n")
|
|
||||||
&& manifest.contains(" (stdout \"beta22-out\\n\")\n")
|
|
||||||
&& manifest.contains(" (stderr \"\")\n")
|
|
||||||
&& manifest.contains(" (arg \"alpha\")\n")
|
|
||||||
&& manifest.contains(" (arg \"two words\")\n")
|
|
||||||
&& manifest.contains(" (arg \"--literal\")\n"),
|
|
||||||
"successful run manifest mismatch:\n{}",
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn run_manifest_records_nonzero_report_and_preserves_program_stderr() {
|
|
||||||
let Some(clang) = find_clang() else {
|
|
||||||
eprintln!("skipping run manifest nonzero report: set GLAGOL_CLANG or install clang");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let source = write_fixture(
|
|
||||||
"nonzero",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(import_c beta22_stderr () -> i32)
|
|
||||||
|
|
||||||
(fn emit_stderr () -> i32
|
|
||||||
(unsafe
|
|
||||||
(beta22_stderr)))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(emit_stderr)
|
|
||||||
7)
|
|
||||||
"#,
|
|
||||||
"slo",
|
|
||||||
);
|
|
||||||
let c_source = write_fixture(
|
|
||||||
"nonzero-stderr",
|
|
||||||
r#"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int beta22_stderr(void) {
|
|
||||||
fputs("beta22-err\n", stderr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
"c",
|
|
||||||
);
|
|
||||||
let manifest_path = temp_path("nonzero-manifest", "manifest.slo");
|
|
||||||
|
|
||||||
let mut command = Command::new(compiler_path());
|
|
||||||
command
|
|
||||||
.arg("run")
|
|
||||||
.arg(&source)
|
|
||||||
.arg("--link-c")
|
|
||||||
.arg(&c_source)
|
|
||||||
.arg("--manifest")
|
|
||||||
.arg(&manifest_path)
|
|
||||||
.env("GLAGOL_CLANG", &clang);
|
|
||||||
configure_clang_runtime_env(&mut command, &clang);
|
|
||||||
|
|
||||||
let output = command.output().expect("run glagol nonzero manifest");
|
|
||||||
assert_exit_code("run manifest nonzero", &output, 7);
|
|
||||||
assert_eq!(output.stdout, b"", "nonzero run stdout drifted");
|
|
||||||
assert_eq!(output.stderr, b"beta22-err\n", "nonzero run stderr drifted");
|
|
||||||
|
|
||||||
let manifest = read_manifest(&manifest_path);
|
|
||||||
assert!(
|
|
||||||
manifest.contains(" (mode run)\n")
|
|
||||||
&& manifest.contains(" (success false)\n")
|
|
||||||
&& manifest.contains(" (run-report\n")
|
|
||||||
&& manifest.contains(" (exit-status 7)\n")
|
|
||||||
&& manifest.contains(" (stdout \"\")\n")
|
|
||||||
&& manifest.contains(" (stderr \"beta22-err\\n\")\n")
|
|
||||||
&& manifest.contains(" (args)\n"),
|
|
||||||
"nonzero run manifest mismatch:\n{}",
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn run_manifest_source_failure_does_not_record_fake_run_report() {
|
|
||||||
let source = write_fixture(
|
|
||||||
"source-failure",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
true)
|
|
||||||
"#,
|
|
||||||
"slo",
|
|
||||||
);
|
|
||||||
let manifest_path = temp_path("source-failure-manifest", "manifest.slo");
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"run".as_ref(),
|
|
||||||
source.as_os_str(),
|
|
||||||
"--manifest".as_ref(),
|
|
||||||
manifest_path.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_exit_code("run manifest source failure", &output, 1);
|
|
||||||
|
|
||||||
let manifest = read_manifest(&manifest_path);
|
|
||||||
assert!(
|
|
||||||
manifest.contains(" (mode run)\n")
|
|
||||||
&& manifest.contains(" (success false)\n")
|
|
||||||
&& manifest.contains(" (kind diagnostics)\n")
|
|
||||||
&& manifest.contains("TypeMismatch")
|
|
||||||
&& !manifest.contains(" (run-report\n"),
|
|
||||||
"source failure manifest included fake run report:\n{}",
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<const N: usize>(args: [&std::ffi::OsStr; N]) -> Output {
|
|
||||||
Command::new(compiler_path())
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compiler_path() -> &'static str {
|
|
||||||
env!("CARGO_BIN_EXE_glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str, extension: &str) -> PathBuf {
|
|
||||||
let path = temp_path(name, extension);
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_path(name: &str, extension: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let mut path = env::temp_dir();
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-run-manifest-beta22-{}-{}-{}.{}",
|
|
||||||
std::process::id(),
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
extension
|
|
||||||
));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_manifest(path: &Path) -> String {
|
|
||||||
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_stdout(context: &str, output: &Output, expected: &str) {
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
expected,
|
|
||||||
"{} stdout mismatch",
|
|
||||||
context
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stderr.is_empty(),
|
|
||||||
"{} wrote stderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_exit_code(context: &str, output: &Output, expected: i32) {
|
|
||||||
assert_eq!(
|
|
||||||
output.status.code(),
|
|
||||||
Some(expected),
|
|
||||||
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_clang() -> Option<PathBuf> {
|
|
||||||
if let Some(path) = env::var_os("GLAGOL_CLANG").filter(|value| !value.is_empty()) {
|
|
||||||
let path = PathBuf::from(path);
|
|
||||||
if path.is_file() {
|
|
||||||
return Some(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let hermetic_clang = PathBuf::from("/tmp/glagol-clang-root/usr/bin/clang");
|
|
||||||
if hermetic_clang.is_file() {
|
|
||||||
return Some(hermetic_clang);
|
|
||||||
}
|
|
||||||
|
|
||||||
find_on_path("clang")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_on_path(name: &str) -> Option<PathBuf> {
|
|
||||||
let path = env::var_os("PATH")?;
|
|
||||||
env::split_paths(&path)
|
|
||||||
.map(|dir| dir.join(name))
|
|
||||||
.find(|candidate| candidate.is_file())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_clang_runtime_env(command: &mut Command, clang: &Path) {
|
|
||||||
if !clang.starts_with("/tmp/glagol-clang-root") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = Path::new("/tmp/glagol-clang-root");
|
|
||||||
let lib64 = root.join("usr/lib64");
|
|
||||||
let lib = root.join("usr/lib");
|
|
||||||
let existing = env::var_os("LD_LIBRARY_PATH").unwrap_or_default();
|
|
||||||
let mut paths = vec![lib64, lib];
|
|
||||||
paths.extend(env::split_paths(&existing));
|
|
||||||
let joined = env::join_paths(paths).expect("join LD_LIBRARY_PATH");
|
|
||||||
command.env("LD_LIBRARY_PATH", joined);
|
|
||||||
}
|
|
||||||
@ -7,18 +7,13 @@ use std::{
|
|||||||
|
|
||||||
const EXPECTED_STD_STRING_OUTPUT: &str = concat!(
|
const EXPECTED_STD_STRING_OUTPUT: &str = concat!(
|
||||||
"test \"explicit std string len concat\" ... ok\n",
|
"test \"explicit std string len concat\" ... ok\n",
|
||||||
"test \"explicit std string byte_at_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit std string slice_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit std string boundary wrappers\" ... ok\n",
|
|
||||||
"test \"explicit std string parse result wrappers\" ... ok\n",
|
"test \"explicit std string parse result wrappers\" ... ok\n",
|
||||||
"test \"explicit std string parse option wrappers\" ... ok\n",
|
"test \"explicit std string parse option wrappers\" ... ok\n",
|
||||||
"test \"explicit std string parse integer fallbacks\" ... ok\n",
|
"test \"explicit std string parse integer fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string parse float bool fallbacks\" ... ok\n",
|
"test \"explicit std string parse float bool fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string parse custom fallbacks\" ... ok\n",
|
"test \"explicit std string parse custom fallbacks\" ... ok\n",
|
||||||
"test \"explicit std string search helpers\" ... ok\n",
|
|
||||||
"test \"explicit std string ascii trim helpers\" ... ok\n",
|
|
||||||
"test \"explicit std string helpers all\" ... ok\n",
|
"test \"explicit std string helpers all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"7 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const EXPECTED_STD_NUM_OUTPUT: &str = concat!(
|
const EXPECTED_STD_NUM_OUTPUT: &str = concat!(
|
||||||
@ -37,16 +32,6 @@ fn explicit_std_string_import_loads_repo_root_standard_source() {
|
|||||||
&[
|
&[
|
||||||
"len",
|
"len",
|
||||||
"concat",
|
"concat",
|
||||||
"byte_at_result",
|
|
||||||
"slice_result",
|
|
||||||
"starts_with",
|
|
||||||
"ends_with",
|
|
||||||
"contains",
|
|
||||||
"index_of_option",
|
|
||||||
"last_index_of_option",
|
|
||||||
"trim_ascii_start",
|
|
||||||
"trim_ascii_end",
|
|
||||||
"trim_ascii",
|
|
||||||
"parse_i32_result",
|
"parse_i32_result",
|
||||||
"parse_i32_option",
|
"parse_i32_option",
|
||||||
"parse_u32_result",
|
"parse_u32_result",
|
||||||
|
|||||||
@ -1,313 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|
||||||
"test \"explicit std json document scalar string\" ... ok\n",
|
|
||||||
"test \"explicit std json document scalar bool\" ... ok\n",
|
|
||||||
"test \"explicit std json document scalar integer\" ... ok\n",
|
|
||||||
"test \"explicit std json document scalar float null\" ... ok\n",
|
|
||||||
"test \"explicit std json document scalar failures\" ... ok\n",
|
|
||||||
"test \"explicit std json document scalar all\" ... ok\n",
|
|
||||||
"6 test(s) passed\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
|
|
||||||
"parse_string_document_result",
|
|
||||||
"parse_bool_document_result",
|
|
||||||
"parse_i32_document_result",
|
|
||||||
"parse_u32_document_result",
|
|
||||||
"parse_i64_document_result",
|
|
||||||
"parse_u64_document_result",
|
|
||||||
"parse_f64_document_result",
|
|
||||||
"parse_null_document_result",
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn explicit_std_json_document_scalar_helpers_check_and_test() {
|
|
||||||
let project = write_project(
|
|
||||||
"std-json-document-scalar-beta21",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(import std.json (parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result))
|
|
||||||
|
|
||||||
(fn imported_json_document_string_ok () -> bool
|
|
||||||
(if (= (std.result.unwrap_ok (parse_string_document_result " \"slovo\" ")) "slovo")
|
|
||||||
(= (std.result.unwrap_ok (parse_string_document_result "\n\t\"slo\\\"vo\"\t")) "slo\"vo")
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_document_bool_ok () -> bool
|
|
||||||
(if (std.result.unwrap_ok (parse_bool_document_result " true "))
|
|
||||||
(= (std.result.unwrap_ok (parse_bool_document_result "\nfalse\t")) false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_document_integer_ok () -> bool
|
|
||||||
(if (= (std.result.unwrap_ok (parse_i32_document_result " -7 ")) -7)
|
|
||||||
(if (= (std.result.unwrap_ok (parse_u32_document_result "\n7\t")) 7u32)
|
|
||||||
(if (= (std.result.unwrap_ok (parse_i64_document_result " -8 ")) -8i64)
|
|
||||||
(= (std.result.unwrap_ok (parse_u64_document_result "9 ")) 9u64)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_document_float_null_ok () -> bool
|
|
||||||
(if (= (std.result.unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
|
|
||||||
(std.result.unwrap_ok (parse_null_document_result "\nnull\t"))
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_document_failures_ok () -> bool
|
|
||||||
(if (= (std.result.unwrap_err (parse_string_document_result "\"slovo\" x")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_bool_document_result " TRUE ")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_i32_document_result " 01 ")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_u32_document_result " -1 ")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_i64_document_result " 8i64 ")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_u64_document_result " ")) 1)
|
|
||||||
(if (= (std.result.unwrap_err (parse_f64_document_result " 01.0 ")) 1)
|
|
||||||
(= (std.result.unwrap_err (parse_null_document_result " NULL ")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_document_scalar_all_ok () -> bool
|
|
||||||
(if (imported_json_document_string_ok)
|
|
||||||
(if (imported_json_document_bool_ok)
|
|
||||||
(if (imported_json_document_integer_ok)
|
|
||||||
(if (imported_json_document_float_null_ok)
|
|
||||||
(imported_json_document_failures_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (imported_json_document_scalar_all_ok)
|
|
||||||
42
|
|
||||||
1))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar string"
|
|
||||||
(imported_json_document_string_ok))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar bool"
|
|
||||||
(imported_json_document_bool_ok))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar integer"
|
|
||||||
(imported_json_document_integer_ok))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar float null"
|
|
||||||
(imported_json_document_float_null_ok))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar failures"
|
|
||||||
(imported_json_document_failures_ok))
|
|
||||||
|
|
||||||
(test "explicit std json document scalar all"
|
|
||||||
(= (main) 42))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let source = read(&project.join("src/main.slo"));
|
|
||||||
let std_json = read(&std_json_path());
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!project.join("src/json.slo").exists(),
|
|
||||||
"beta21 fixture must exercise repo-root std.json, not a local module copy"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
source.starts_with("(module main)\n\n(import std.json ("),
|
|
||||||
"beta21 fixture must use an explicit std.json import"
|
|
||||||
);
|
|
||||||
assert_json_document_scalar_helpers_are_source_authored(&std_json);
|
|
||||||
|
|
||||||
let fmt = run_glagol([
|
|
||||||
OsStr::new("fmt"),
|
|
||||||
OsStr::new("--check"),
|
|
||||||
project.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_success("std json document scalar fmt --check", &fmt);
|
|
||||||
|
|
||||||
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
|
||||||
assert_success_stdout(check, "", "std json document scalar check");
|
|
||||||
|
|
||||||
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
|
||||||
assert_success_stdout(test, EXPECTED_TEST_OUTPUT, "std json document scalar test");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_document_scalar_helpers_are_not_compiler_known_runtime_calls() {
|
|
||||||
let std_json = read(&std_json_path());
|
|
||||||
assert_json_document_scalar_helpers_are_source_authored(&std_json);
|
|
||||||
|
|
||||||
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
helper,
|
|
||||||
&format!(
|
|
||||||
"(module main)\n\n(fn main () -> i32\n (std.result.unwrap_err (std.json.{} \"invalid\")))\n",
|
|
||||||
helper
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
assert_failure_stderr_contains(
|
|
||||||
&format!("direct std.json.{} runtime call", helper),
|
|
||||||
&output,
|
|
||||||
&format!(
|
|
||||||
"standard library call `std.json.{}` is not supported",
|
|
||||||
helper
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_json_document_scalar_helpers_are_source_authored(std_json: &str) {
|
|
||||||
assert!(
|
|
||||||
std_json.starts_with("(module json (export "),
|
|
||||||
"lib/std/json.slo must stay a source-authored module export"
|
|
||||||
);
|
|
||||||
|
|
||||||
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
||||||
assert!(
|
|
||||||
std_json.contains(&format!("(fn {} ", helper)),
|
|
||||||
"lib/std/json.slo is missing source facade `{}`",
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!std_json.contains(&format!("std.json.{}", helper)),
|
|
||||||
"std.json.{} must remain source-authored, not a compiler-known runtime call",
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for private_prefix in [
|
|
||||||
"__glagol_json_parse_string_document",
|
|
||||||
"__glagol_json_parse_bool_document",
|
|
||||||
"__glagol_json_parse_i32_document",
|
|
||||||
"__glagol_json_parse_u32_document",
|
|
||||||
"__glagol_json_parse_i64_document",
|
|
||||||
"__glagol_json_parse_u64_document",
|
|
||||||
"__glagol_json_parse_f64_document",
|
|
||||||
"__glagol_json_parse_null_document",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!std_json.contains(private_prefix),
|
|
||||||
"lib/std/json.slo must not introduce private JSON document runtime symbol `{}`",
|
|
||||||
private_prefix
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(name: &str, source: &str) -> PathBuf {
|
|
||||||
let root = temp_root(name);
|
|
||||||
let src = root.join("src");
|
|
||||||
fs::create_dir_all(&src).unwrap_or_else(|err| panic!("create `{}`: {}", src.display(), err));
|
|
||||||
fs::write(
|
|
||||||
root.join("slovo.toml"),
|
|
||||||
format!(
|
|
||||||
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|err| panic!("write project manifest: {}", err));
|
|
||||||
fs::write(src.join("main.slo"), source.trim_start())
|
|
||||||
.unwrap_or_else(|err| panic!("write project main.slo: {}", err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let mut path = env::temp_dir();
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-standard-json-document-scalar-beta21-{}-{}-{}.slo",
|
|
||||||
name,
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
fs::write(&path, source.trim_start())
|
|
||||||
.unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_root(name: &str) -> PathBuf {
|
|
||||||
let root = env::temp_dir().join(format!(
|
|
||||||
"glagol-standard-json-document-scalar-beta21-{}-{}-{}",
|
|
||||||
name,
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
let _ = fs::remove_dir_all(&root);
|
|
||||||
fs::create_dir_all(&root).unwrap_or_else(|err| panic!("create `{}`: {}", root.display(), err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn std_json_path() -> PathBuf {
|
|
||||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("../lib/std/json.slo")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(path: &Path) -> String {
|
|
||||||
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
output.status.code(),
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
|
|
||||||
assert_success(context, &output);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
assert_eq!(stdout, expected, "{}", context);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_failure_stderr_contains(context: &str, output: &Output, needle: &str) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"{} unexpectedly passed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stdout.is_empty(),
|
|
||||||
"{} rejected compile wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(needle),
|
|
||||||
"{} stderr did not contain `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
needle,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,424 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
const JSON_SCALAR_PARSE_NAMES: &[(&str, &str, &str)] = &[
|
|
||||||
(
|
|
||||||
"parse_bool_value_result",
|
|
||||||
"__glagol_json_parse_bool_value_result",
|
|
||||||
"(result bool i32)",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"parse_i32_value_result",
|
|
||||||
"__glagol_json_parse_i32_value_result",
|
|
||||||
"(result i32 i32)",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"parse_u32_value_result",
|
|
||||||
"__glagol_json_parse_u32_value_result",
|
|
||||||
"(result u32 i32)",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"parse_i64_value_result",
|
|
||||||
"__glagol_json_parse_i64_value_result",
|
|
||||||
"(result i64 i32)",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"parse_u64_value_result",
|
|
||||||
"__glagol_json_parse_u64_value_result",
|
|
||||||
"(result u64 i32)",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"parse_f64_value_result",
|
|
||||||
"__glagol_json_parse_f64_value_result",
|
|
||||||
"(result f64 i32)",
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_scalar_parsers_lower_to_private_runtime_helpers() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"lowering",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.result.unwrap_ok (std.json.parse_bool_value_result "true"))
|
|
||||||
(std.result.unwrap_ok (std.json.parse_i32_value_result "-0"))
|
|
||||||
(std.result.unwrap_ok (std.json.parse_u32_value_result "4294967295"))
|
|
||||||
(std.result.unwrap_ok (std.json.parse_i64_value_result "-9223372036854775808"))
|
|
||||||
(std.result.unwrap_ok (std.json.parse_u64_value_result "18446744073709551615"))
|
|
||||||
(std.result.unwrap_ok (std.json.parse_f64_value_result "1e2"))
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
assert_success("compile json scalar parser lowering", &output);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
|
|
||||||
for (_, symbol, _) in JSON_SCALAR_PARSE_NAMES {
|
|
||||||
assert!(
|
|
||||||
stdout.contains(&format!("@{}", symbol)),
|
|
||||||
"missing JSON scalar parser runtime symbol `{}`\nstdout:\n{}",
|
|
||||||
symbol,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
stdout.contains("declare i64 @__glagol_json_parse_i32_value_result(ptr)")
|
|
||||||
&& stdout.contains("declare i64 @__glagol_json_parse_u32_value_result(ptr)")
|
|
||||||
&& stdout.contains("declare i32 @__glagol_json_parse_i64_value_result(ptr, ptr)")
|
|
||||||
&& stdout.contains("declare i32 @__glagol_json_parse_u64_value_result(ptr, ptr)")
|
|
||||||
&& stdout.contains("declare i32 @__glagol_json_parse_f64_value_result(ptr, ptr)")
|
|
||||||
&& stdout.contains("declare i32 @__glagol_json_parse_bool_value_result(ptr, ptr)")
|
|
||||||
&& stdout.contains("call i64 @__glagol_json_parse_i32_value_result(")
|
|
||||||
&& stdout.contains("call i64 @__glagol_json_parse_u32_value_result(")
|
|
||||||
&& stdout.contains("call i32 @__glagol_json_parse_i64_value_result(")
|
|
||||||
&& stdout.contains("call i32 @__glagol_json_parse_u64_value_result(")
|
|
||||||
&& stdout.contains("call i32 @__glagol_json_parse_f64_value_result(")
|
|
||||||
&& stdout.contains("call i32 @__glagol_json_parse_bool_value_result(")
|
|
||||||
&& !stdout.contains("@std.json.parse_i32_value_result"),
|
|
||||||
"JSON scalar parser LLVM shape drifted\nstdout:\n{}",
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_runner_enforces_json_token_scalar_contract() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"test-runner",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "json bool true ok"
|
|
||||||
(std.result.unwrap_ok (std.json.parse_bool_value_result "true")))
|
|
||||||
|
|
||||||
(test "json bool uppercase err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_bool_value_result "TRUE")) 1))
|
|
||||||
|
|
||||||
(test "json i32 negative zero ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_i32_value_result "-0")) 0))
|
|
||||||
|
|
||||||
(test "json i32 leading zero err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_i32_value_result "01")) 1))
|
|
||||||
|
|
||||||
(test "json i32 plus err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_i32_value_result "+1")) 1))
|
|
||||||
|
|
||||||
(test "json u32 negative err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_u32_value_result "-1")) 1))
|
|
||||||
|
|
||||||
(test "json i64 max ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_i64_value_result "9223372036854775807")) 9223372036854775807i64))
|
|
||||||
|
|
||||||
(test "json u64 max ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_u64_value_result "18446744073709551615")) 18446744073709551615u64))
|
|
||||||
|
|
||||||
(test "json f64 exponent ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_f64_value_result "1e2")) 100.0))
|
|
||||||
|
|
||||||
(test "json f64 leading zero err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_f64_value_result "01.0")) 1))
|
|
||||||
|
|
||||||
(test "json f64 nonfinite err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_f64_value_result "1e309")) 1))
|
|
||||||
|
|
||||||
(test "json no leading whitespace"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_i64_value_result " 1")) 1))
|
|
||||||
|
|
||||||
(test "json no trailing whitespace"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_f64_value_result "1 ")) 1))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([OsStr::new("test"), fixture.as_os_str()]);
|
|
||||||
assert_success("run json scalar parser tests", &output);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
concat!(
|
|
||||||
"test \"json bool true ok\" ... ok\n",
|
|
||||||
"test \"json bool uppercase err\" ... ok\n",
|
|
||||||
"test \"json i32 negative zero ok\" ... ok\n",
|
|
||||||
"test \"json i32 leading zero err\" ... ok\n",
|
|
||||||
"test \"json i32 plus err\" ... ok\n",
|
|
||||||
"test \"json u32 negative err\" ... ok\n",
|
|
||||||
"test \"json i64 max ok\" ... ok\n",
|
|
||||||
"test \"json u64 max ok\" ... ok\n",
|
|
||||||
"test \"json f64 exponent ok\" ... ok\n",
|
|
||||||
"test \"json f64 leading zero err\" ... ok\n",
|
|
||||||
"test \"json f64 nonfinite err\" ... ok\n",
|
|
||||||
"test \"json no leading whitespace\" ... ok\n",
|
|
||||||
"test \"json no trailing whitespace\" ... ok\n",
|
|
||||||
"13 test(s) passed\n",
|
|
||||||
),
|
|
||||||
"json scalar parser test runner stdout drifted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hosted_json_scalar_parsers_smoke_when_toolchain_is_available() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"runtime-smoke",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.io.print_bool (std.result.unwrap_ok (std.json.parse_bool_value_result "true")))
|
|
||||||
(std.io.print_i32 (std.result.unwrap_ok (std.json.parse_i32_value_result "-0")))
|
|
||||||
(std.io.print_u32 (std.result.unwrap_ok (std.json.parse_u32_value_result "4294967295")))
|
|
||||||
(std.io.print_i64 (std.result.unwrap_ok (std.json.parse_i64_value_result "-9223372036854775808")))
|
|
||||||
(std.io.print_u64 (std.result.unwrap_ok (std.json.parse_u64_value_result "18446744073709551615")))
|
|
||||||
(std.io.print_string (std.num.f64_to_string (std.result.unwrap_ok (std.json.parse_f64_value_result "1e2"))))
|
|
||||||
(std.result.unwrap_err (std.json.parse_i32_value_result "01")))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let binary = unique_path("json-scalar-parsing-beta17-bin");
|
|
||||||
let build = run_glagol([
|
|
||||||
OsStr::new("build"),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
binary.as_os_str(),
|
|
||||||
]);
|
|
||||||
if !build.status.success() {
|
|
||||||
let stderr = String::from_utf8_lossy(&build.stderr);
|
|
||||||
assert!(
|
|
||||||
stderr.contains("ToolchainUnavailable"),
|
|
||||||
"json scalar parser build failed unexpectedly\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&build.stdout),
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let run = Command::new(&binary)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", binary.display(), err));
|
|
||||||
assert_eq!(
|
|
||||||
run.status.code(),
|
|
||||||
Some(1),
|
|
||||||
"json scalar parser binary exit code drifted\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
concat!(
|
|
||||||
"true\n",
|
|
||||||
"0\n",
|
|
||||||
"4294967295\n",
|
|
||||||
"-9223372036854775808\n",
|
|
||||||
"18446744073709551615\n",
|
|
||||||
"100.0\n",
|
|
||||||
),
|
|
||||||
"json scalar parser binary stdout drifted"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
run.stderr.is_empty(),
|
|
||||||
"json scalar parser binary wrote stderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_scalar_parser_diagnostics_cover_promoted_names_and_shadowing() {
|
|
||||||
for (name, _, return_type) in JSON_SCALAR_PARSE_NAMES {
|
|
||||||
let arity = write_fixture(
|
|
||||||
&format!("{name}-arity"),
|
|
||||||
&format!(
|
|
||||||
"(module main)\n\n(fn main () -> {}\n (std.json.{}))\n",
|
|
||||||
return_type, name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
&format!("std.json.{name} arity"),
|
|
||||||
run_glagol([arity.as_os_str()]),
|
|
||||||
"wrong number of arguments",
|
|
||||||
);
|
|
||||||
|
|
||||||
let type_mismatch = write_fixture(
|
|
||||||
&format!("{name}-type"),
|
|
||||||
&format!(
|
|
||||||
"(module main)\n\n(fn main () -> {}\n (std.json.{} 1))\n",
|
|
||||||
return_type, name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
&format!("std.json.{name} type"),
|
|
||||||
run_glagol([type_mismatch.as_os_str()]),
|
|
||||||
&format!(
|
|
||||||
"cannot call `std.json.{}` with argument of wrong type",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let source_shadow = write_fixture(
|
|
||||||
"source-shadow",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.json.parse_i32_value_result ((text string)) -> (result i32 i32)
|
|
||||||
(err i32 i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"std.json.parse_i32_value_result source shadow",
|
|
||||||
run_glagol([source_shadow.as_os_str()]),
|
|
||||||
"DuplicateFunction",
|
|
||||||
);
|
|
||||||
|
|
||||||
let helper_shadow = write_fixture(
|
|
||||||
"helper-shadow",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_json_parse_i32_value_result ((text string)) -> (result i32 i32)
|
|
||||||
(err i32 i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"__glagol_json_parse_i32_value_result helper shadow",
|
|
||||||
run_glagol([helper_shadow.as_os_str()]),
|
|
||||||
"DuplicateFunction",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deferred_json_parser_families_remain_unsupported() {
|
|
||||||
for name in [
|
|
||||||
"parse_object_result",
|
|
||||||
"parse_array_result",
|
|
||||||
"parse_value_result",
|
|
||||||
"tokenize_result",
|
|
||||||
"schema_validate_result",
|
|
||||||
"stream_parse_result",
|
|
||||||
] {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
name,
|
|
||||||
&format!(
|
|
||||||
"(module main)\n\n(fn main () -> i32\n (std.json.{} \"[]\")\n 0)\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
&format!("std.json.{name} deferred"),
|
|
||||||
run_glagol([fixture.as_os_str()]),
|
|
||||||
&format!("standard library call `std.json.{}` is not supported", name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unsupported_json_diagnostics_list_beta17_promoted_scalar_parsers() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"unsupported-guidance",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.json.parse_value_result "null")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"unsupported JSON value parser unexpectedly compiled\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains("standard library call `std.json.parse_value_result` is not supported"),
|
|
||||||
"unsupported JSON parser diagnostic drifted\nstderr:\n{}",
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
for (name, _, _) in JSON_SCALAR_PARSE_NAMES {
|
|
||||||
let promoted = format!("std.json.{name}");
|
|
||||||
assert!(
|
|
||||||
stderr.contains(&promoted),
|
|
||||||
"unsupported std guidance omitted promoted beta17 name `{}`\nstderr:\n{}",
|
|
||||||
promoted,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let dir = env::temp_dir().join(format!("glagol-json-scalar-beta17-{id}-{name}"));
|
|
||||||
fs::create_dir_all(&dir).unwrap_or_else(|err| panic!("create `{}`: {}", dir.display(), err));
|
|
||||||
let path = dir.join("main.slo");
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_path(name: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
env::temp_dir().join(format!("glagol-{name}-{id}{}", env::consts::EXE_SUFFIX))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_rejected(context: &str, output: Output, expected: &str) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"{} unexpectedly succeeded\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stdout.is_empty(),
|
|
||||||
"{} rejected compile wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(expected),
|
|
||||||
"{} diagnostic drifted; expected `{}`\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
expected,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -8,33 +8,19 @@ use std::{
|
|||||||
const EXPECTED_LOCAL_TEST_OUTPUT: &str = concat!(
|
const EXPECTED_LOCAL_TEST_OUTPUT: &str = concat!(
|
||||||
"test \"explicit local json quote escapes facade\" ... ok\n",
|
"test \"explicit local json quote escapes facade\" ... ok\n",
|
||||||
"test \"explicit local json scalar values facade\" ... ok\n",
|
"test \"explicit local json scalar values facade\" ... ok\n",
|
||||||
"test \"explicit local json primitive scalar parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json primitive scalar parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json string token parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json string token parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse trimmed success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse plain success facade\" ... ok\n",
|
|
||||||
"test \"explicit local json document parse trailing failure facade\" ... ok\n",
|
|
||||||
"test \"explicit local json fields facade\" ... ok\n",
|
"test \"explicit local json fields facade\" ... ok\n",
|
||||||
"test \"explicit local json arrays objects facade\" ... ok\n",
|
"test \"explicit local json arrays objects facade\" ... ok\n",
|
||||||
"test \"explicit local json facade all\" ... ok\n",
|
"test \"explicit local json facade all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"5 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!(
|
const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!(
|
||||||
"test \"explicit std json quote escapes facade\" ... ok\n",
|
"test \"explicit std json quote escapes facade\" ... ok\n",
|
||||||
"test \"explicit std json scalar values facade\" ... ok\n",
|
"test \"explicit std json scalar values facade\" ... ok\n",
|
||||||
"test \"explicit std json primitive scalar parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json primitive scalar parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json string token parse success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json string token parse failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse trimmed success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse plain success facade\" ... ok\n",
|
|
||||||
"test \"explicit std json document parse trailing failure facade\" ... ok\n",
|
|
||||||
"test \"explicit std json fields facade\" ... ok\n",
|
"test \"explicit std json fields facade\" ... ok\n",
|
||||||
"test \"explicit std json arrays objects facade\" ... ok\n",
|
"test \"explicit std json arrays objects facade\" ... ok\n",
|
||||||
"test \"explicit std json facade all\" ... ok\n",
|
"test \"explicit std json facade all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"5 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -46,22 +32,6 @@ const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"i64_value",
|
"i64_value",
|
||||||
"u64_value",
|
"u64_value",
|
||||||
"f64_value",
|
"f64_value",
|
||||||
"parse_string_value_result",
|
|
||||||
"parse_bool_value_result",
|
|
||||||
"parse_i32_value_result",
|
|
||||||
"parse_u32_value_result",
|
|
||||||
"parse_i64_value_result",
|
|
||||||
"parse_u64_value_result",
|
|
||||||
"parse_f64_value_result",
|
|
||||||
"parse_null_value_result",
|
|
||||||
"parse_string_document_result",
|
|
||||||
"parse_bool_document_result",
|
|
||||||
"parse_i32_document_result",
|
|
||||||
"parse_u32_document_result",
|
|
||||||
"parse_i64_document_result",
|
|
||||||
"parse_u64_document_result",
|
|
||||||
"parse_f64_document_result",
|
|
||||||
"parse_null_document_result",
|
|
||||||
"field_string",
|
"field_string",
|
||||||
"field_bool",
|
"field_bool",
|
||||||
"field_i32",
|
"field_i32",
|
||||||
@ -88,42 +58,6 @@ const STANDARD_JSON_RUNTIME_NAMES: &[&str] = &[
|
|||||||
"std.num.i64_to_string",
|
"std.num.i64_to_string",
|
||||||
"std.num.u64_to_string",
|
"std.num.u64_to_string",
|
||||||
"std.num.f64_to_string",
|
"std.num.f64_to_string",
|
||||||
"std.json.parse_string_value_result",
|
|
||||||
"std.json.parse_bool_value_result",
|
|
||||||
"std.json.parse_i32_value_result",
|
|
||||||
"std.json.parse_u32_value_result",
|
|
||||||
"std.json.parse_i64_value_result",
|
|
||||||
"std.json.parse_u64_value_result",
|
|
||||||
"std.json.parse_f64_value_result",
|
|
||||||
];
|
|
||||||
|
|
||||||
const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
|
|
||||||
"(import std.string (trim_ascii))",
|
|
||||||
"std.json.quote_string",
|
|
||||||
"std.string.concat",
|
|
||||||
"std.num.i32_to_string",
|
|
||||||
"std.num.u32_to_string",
|
|
||||||
"std.num.i64_to_string",
|
|
||||||
"std.num.u64_to_string",
|
|
||||||
"std.num.f64_to_string",
|
|
||||||
"std.json.parse_string_value_result",
|
|
||||||
"std.json.parse_bool_value_result",
|
|
||||||
"std.json.parse_i32_value_result",
|
|
||||||
"std.json.parse_u32_value_result",
|
|
||||||
"std.json.parse_i64_value_result",
|
|
||||||
"std.json.parse_u64_value_result",
|
|
||||||
"std.json.parse_f64_value_result",
|
|
||||||
];
|
|
||||||
|
|
||||||
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
|
|
||||||
"parse_string_document_result",
|
|
||||||
"parse_bool_document_result",
|
|
||||||
"parse_i32_document_result",
|
|
||||||
"parse_u32_document_result",
|
|
||||||
"parse_i64_document_result",
|
|
||||||
"parse_u64_document_result",
|
|
||||||
"parse_f64_document_result",
|
|
||||||
"parse_null_document_result",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -223,9 +157,23 @@ fn assert_json_source_shape(json: &str, main: &str, context: &str) {
|
|||||||
runtime_name
|
runtime_name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert_std_only_contains(json, STANDARD_JSON_ALLOWED_STD_NAMES, context);
|
assert_std_only_contains(json, STANDARD_JSON_RUNTIME_NAMES, context);
|
||||||
assert_deferred_json_surface_absent(json, main, context);
|
assert!(
|
||||||
assert_json_document_scalar_helpers_are_source_authored(json, context);
|
!json.contains("parse")
|
||||||
|
&& !json.contains("token")
|
||||||
|
&& !json.contains("map")
|
||||||
|
&& !json.contains("unicode")
|
||||||
|
&& !json.contains("schema")
|
||||||
|
&& !json.contains("stream")
|
||||||
|
&& !main.contains("parse")
|
||||||
|
&& !main.contains("token")
|
||||||
|
&& !main.contains("map")
|
||||||
|
&& !main.contains("unicode")
|
||||||
|
&& !main.contains("schema")
|
||||||
|
&& !main.contains("stream"),
|
||||||
|
"{} must not claim deferred JSON parsing or richer data APIs",
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
|
||||||
assert!(
|
assert!(
|
||||||
@ -243,55 +191,6 @@ fn assert_json_source_shape(json: &str, main: &str, context: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_json_document_scalar_helpers_are_source_authored(json: &str, context: &str) {
|
|
||||||
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
||||||
assert!(
|
|
||||||
!json.contains(&format!("std.json.{}", helper)),
|
|
||||||
"{} must keep `{}` source-authored, not compiler-known",
|
|
||||||
context,
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for private_prefix in [
|
|
||||||
"__glagol_json_parse_string_document",
|
|
||||||
"__glagol_json_parse_bool_document",
|
|
||||||
"__glagol_json_parse_i32_document",
|
|
||||||
"__glagol_json_parse_u32_document",
|
|
||||||
"__glagol_json_parse_i64_document",
|
|
||||||
"__glagol_json_parse_u64_document",
|
|
||||||
"__glagol_json_parse_f64_document",
|
|
||||||
"__glagol_json_parse_null_document",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!json.contains(private_prefix),
|
|
||||||
"{} must not introduce private JSON document runtime symbol `{}`",
|
|
||||||
context,
|
|
||||||
private_prefix
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_deferred_json_surface_absent(json: &str, main: &str, context: &str) {
|
|
||||||
for deferred in [
|
|
||||||
"parse_object",
|
|
||||||
"parse_array",
|
|
||||||
"parse_value",
|
|
||||||
"tokenize",
|
|
||||||
"tokenizer",
|
|
||||||
"schema",
|
|
||||||
"stream",
|
|
||||||
"unicode",
|
|
||||||
"map",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!json.contains(deferred) && !main.contains(deferred),
|
|
||||||
"{} must not claim deferred JSON `{}` policies",
|
|
||||||
context,
|
|
||||||
deferred
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_std_only_contains(source: &str, allowed: &[&str], context: &str) {
|
fn assert_std_only_contains(source: &str, allowed: &[&str], context: &str) {
|
||||||
let mut remaining = source.to_string();
|
let mut remaining = source.to_string();
|
||||||
for name in allowed {
|
for name in allowed {
|
||||||
|
|||||||
@ -1,463 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_string_parser_lowers_to_private_runtime_helper() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"lowering",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.result.unwrap_ok (std.json.parse_string_value_result "\"slovo\""))
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
assert_success("compile json string parser lowering", &output);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
stdout.contains("declare ptr @__glagol_json_parse_string_value_result(ptr)")
|
|
||||||
&& stdout.contains("call ptr @__glagol_json_parse_string_value_result(")
|
|
||||||
&& !stdout.contains("@std.json.parse_string_value_result"),
|
|
||||||
"JSON string parser LLVM shape drifted\nstdout:\n{}",
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_runner_enforces_ascii_json_string_token_contract() {
|
|
||||||
let source = r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "json string empty ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_string_value_result "\"\"")) ""))
|
|
||||||
|
|
||||||
(test "json string plain ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_string_value_result "\"slovo\"")) "slovo"))
|
|
||||||
|
|
||||||
(test "json string quote backslash slash ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_string_value_result "\"slo\\\"vo\\\\path\\/leaf\"")) "slo\"vo\\path/leaf"))
|
|
||||||
|
|
||||||
(test "json string newline tab escapes ok"
|
|
||||||
(= (std.result.unwrap_ok (std.json.parse_string_value_result "\"line\\nnext\\tend\"")) "line\nnext\tend"))
|
|
||||||
|
|
||||||
(test "json string backspace formfeed roundtrip ok"
|
|
||||||
(= (std.json.quote_string (std.result.unwrap_ok (std.json.parse_string_value_result "\"a\\b\\f\""))) "\"a\\b\\f\""))
|
|
||||||
|
|
||||||
(test "json string missing quotes err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "slovo")) 1))
|
|
||||||
|
|
||||||
(test "json string leading whitespace err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result " \"slovo\"")) 1))
|
|
||||||
|
|
||||||
(test "json string trailing whitespace err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"slovo\" ")) 1))
|
|
||||||
|
|
||||||
(test "json string unterminated err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"slovo")) 1))
|
|
||||||
|
|
||||||
(test "json string trailing bytes err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"slovo\"x")) 1))
|
|
||||||
|
|
||||||
(test "json string raw quote err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"slo\"vo\"")) 1))
|
|
||||||
|
|
||||||
(test "json string bad escape err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"bad\\x\"")) 1))
|
|
||||||
|
|
||||||
(test "json string unicode escape deferred err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"\\u0041\"")) 1))
|
|
||||||
|
|
||||||
(test "json string raw newline err"
|
|
||||||
(= (std.result.unwrap_err (std.json.parse_string_value_result "\"line\nnext\"")) 1))
|
|
||||||
"#;
|
|
||||||
let fixture = write_fixture("test-runner", source);
|
|
||||||
let output = run_glagol([OsStr::new("test"), fixture.as_os_str()]);
|
|
||||||
assert_success("run json string parser tests", &output);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
concat!(
|
|
||||||
"test \"json string empty ok\" ... ok\n",
|
|
||||||
"test \"json string plain ok\" ... ok\n",
|
|
||||||
"test \"json string quote backslash slash ok\" ... ok\n",
|
|
||||||
"test \"json string newline tab escapes ok\" ... ok\n",
|
|
||||||
"test \"json string backspace formfeed roundtrip ok\" ... ok\n",
|
|
||||||
"test \"json string missing quotes err\" ... ok\n",
|
|
||||||
"test \"json string leading whitespace err\" ... ok\n",
|
|
||||||
"test \"json string trailing whitespace err\" ... ok\n",
|
|
||||||
"test \"json string unterminated err\" ... ok\n",
|
|
||||||
"test \"json string trailing bytes err\" ... ok\n",
|
|
||||||
"test \"json string raw quote err\" ... ok\n",
|
|
||||||
"test \"json string bad escape err\" ... ok\n",
|
|
||||||
"test \"json string unicode escape deferred err\" ... ok\n",
|
|
||||||
"test \"json string raw newline err\" ... ok\n",
|
|
||||||
"14 test(s) passed\n",
|
|
||||||
),
|
|
||||||
"json string parser test runner stdout drifted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hosted_json_string_parser_smoke_when_toolchain_is_available() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"runtime-smoke",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.io.print_string (std.result.unwrap_ok (std.json.parse_string_value_result "\"slovo\"")))
|
|
||||||
(std.io.print_string (std.result.unwrap_ok (std.json.parse_string_value_result "\"slo\\\"vo\"")))
|
|
||||||
(std.io.print_string (std.result.unwrap_ok (std.json.parse_string_value_result "\"path\\/leaf\"")))
|
|
||||||
(std.result.unwrap_err (std.json.parse_string_value_result "\"\\u0041\"")))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let binary = unique_path("json-string-parsing-beta18-bin");
|
|
||||||
let build = run_glagol([
|
|
||||||
OsStr::new("build"),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
OsStr::new("-o"),
|
|
||||||
binary.as_os_str(),
|
|
||||||
]);
|
|
||||||
if !build.status.success() {
|
|
||||||
let stderr = String::from_utf8_lossy(&build.stderr);
|
|
||||||
assert!(
|
|
||||||
stderr.contains("ToolchainUnavailable"),
|
|
||||||
"json string parser build failed unexpectedly\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&build.stdout),
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let run = Command::new(&binary)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", binary.display(), err));
|
|
||||||
assert_eq!(
|
|
||||||
run.status.code(),
|
|
||||||
Some(1),
|
|
||||||
"json string parser binary exit code drifted\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
"slovo\nslo\"vo\npath/leaf\n",
|
|
||||||
"json string parser binary stdout drifted"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
run.stderr.is_empty(),
|
|
||||||
"json string parser binary wrote stderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hosted_json_string_runtime_rejects_raw_non_ascii_when_clang_is_available() {
|
|
||||||
let Some(clang) = find_clang() else {
|
|
||||||
eprintln!("skipping beta18 raw non-ASCII runtime smoke: set GLAGOL_CLANG or install clang");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let c_source = write_c_fixture(
|
|
||||||
"raw-non-ascii",
|
|
||||||
r#"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
char *__glagol_json_parse_string_value_result(const char *text);
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
const char token[] = { '"', (char)0xc3, (char)0xa9, '"', '\0' };
|
|
||||||
char *value = __glagol_json_parse_string_value_result(token);
|
|
||||||
if (value != NULL) {
|
|
||||||
free(value);
|
|
||||||
fputs("accepted raw non-ascii JSON string token\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
puts("raw-non-ascii rejected");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let runtime = Path::new(env!("CARGO_MANIFEST_DIR")).join("../runtime/runtime.c");
|
|
||||||
let binary = unique_path("json-string-raw-non-ascii-beta18-bin");
|
|
||||||
let mut compile = Command::new(&clang);
|
|
||||||
compile.arg(runtime).arg(c_source).arg("-o").arg(&binary);
|
|
||||||
configure_clang_runtime_env(&mut compile, &clang);
|
|
||||||
let compile = compile
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", clang.display(), err));
|
|
||||||
assert_success("clang beta18 raw non-ASCII runtime smoke", &compile);
|
|
||||||
|
|
||||||
let run = Command::new(&binary)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", binary.display(), err));
|
|
||||||
assert_eq!(
|
|
||||||
run.status.code(),
|
|
||||||
Some(0),
|
|
||||||
"raw non-ASCII runtime smoke exit code drifted\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
"raw-non-ascii rejected\n",
|
|
||||||
"raw non-ASCII runtime smoke stdout drifted"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
run.stderr.is_empty(),
|
|
||||||
"raw non-ASCII runtime smoke wrote stderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&run.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn json_string_parser_diagnostics_cover_promoted_name_and_shadowing() {
|
|
||||||
let arity = write_fixture(
|
|
||||||
"arity",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result string i32)
|
|
||||||
(std.json.parse_string_value_result))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"std.json.parse_string_value_result arity",
|
|
||||||
run_glagol([arity.as_os_str()]),
|
|
||||||
"wrong number of arguments",
|
|
||||||
);
|
|
||||||
|
|
||||||
let type_mismatch = write_fixture(
|
|
||||||
"type",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> (result string i32)
|
|
||||||
(std.json.parse_string_value_result 1))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"std.json.parse_string_value_result type",
|
|
||||||
run_glagol([type_mismatch.as_os_str()]),
|
|
||||||
"cannot call `std.json.parse_string_value_result` with argument of wrong type",
|
|
||||||
);
|
|
||||||
|
|
||||||
let source_shadow = write_fixture(
|
|
||||||
"source-shadow",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn std.json.parse_string_value_result ((text string)) -> (result string i32)
|
|
||||||
(err string i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"std.json.parse_string_value_result source shadow",
|
|
||||||
run_glagol([source_shadow.as_os_str()]),
|
|
||||||
"DuplicateFunction",
|
|
||||||
);
|
|
||||||
|
|
||||||
let helper_shadow = write_fixture(
|
|
||||||
"helper-shadow",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn __glagol_json_parse_string_value_result ((text string)) -> (result string i32)
|
|
||||||
(err string i32 1))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
"__glagol_json_parse_string_value_result helper shadow",
|
|
||||||
run_glagol([helper_shadow.as_os_str()]),
|
|
||||||
"DuplicateFunction",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deferred_json_parser_families_remain_unsupported_after_string_tokens() {
|
|
||||||
for name in [
|
|
||||||
"parse_object_result",
|
|
||||||
"parse_array_result",
|
|
||||||
"parse_value_result",
|
|
||||||
"tokenize_result",
|
|
||||||
"schema_validate_result",
|
|
||||||
"stream_parse_result",
|
|
||||||
] {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
name,
|
|
||||||
&format!(
|
|
||||||
"(module main)\n\n(fn main () -> i32\n (std.json.{} \"[]\")\n 0)\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
assert_rejected(
|
|
||||||
&format!("std.json.{name} deferred"),
|
|
||||||
run_glagol([fixture.as_os_str()]),
|
|
||||||
&format!("standard library call `std.json.{}` is not supported", name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unsupported_json_diagnostics_list_beta18_promoted_string_parser() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"unsupported-guidance",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.json.parse_value_result "null")
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"unsupported JSON value parser unexpectedly compiled\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains("standard library call `std.json.parse_value_result` is not supported"),
|
|
||||||
"unsupported JSON parser diagnostic drifted\nstderr:\n{}",
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains("std.json.parse_string_value_result"),
|
|
||||||
"unsupported std guidance omitted promoted beta18 name\nstderr:\n{}",
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let dir = env::temp_dir().join(format!("glagol-json-string-beta18-{id}-{name}"));
|
|
||||||
fs::create_dir_all(&dir).unwrap_or_else(|err| panic!("create `{}`: {}", dir.display(), err));
|
|
||||||
let path = dir.join("main.slo");
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_c_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let dir = env::temp_dir().join(format!("glagol-json-string-beta18-c-{id}-{name}"));
|
|
||||||
fs::create_dir_all(&dir).unwrap_or_else(|err| panic!("create `{}`: {}", dir.display(), err));
|
|
||||||
let path = dir.join("main.c");
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_path(name: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
env::temp_dir().join(format!("glagol-{name}-{id}{}", env::consts::EXE_SUFFIX))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_clang() -> Option<PathBuf> {
|
|
||||||
if let Some(path) = env::var_os("GLAGOL_CLANG").filter(|value| !value.is_empty()) {
|
|
||||||
return Some(PathBuf::from(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
let hermetic_clang = PathBuf::from("/tmp/glagol-clang-root/usr/bin/clang");
|
|
||||||
if hermetic_clang.is_file() {
|
|
||||||
return Some(hermetic_clang);
|
|
||||||
}
|
|
||||||
|
|
||||||
find_on_path("clang")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_on_path(name: &str) -> Option<PathBuf> {
|
|
||||||
let path = env::var_os("PATH")?;
|
|
||||||
for dir in env::split_paths(&path) {
|
|
||||||
let candidate = dir.join(name);
|
|
||||||
if candidate.is_file() {
|
|
||||||
return Some(candidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_clang_runtime_env(command: &mut Command, clang: &Path) {
|
|
||||||
if !clang.starts_with("/tmp/glagol-clang-root") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = Path::new("/tmp/glagol-clang-root");
|
|
||||||
let lib_dir = root.join("usr/lib");
|
|
||||||
let lib64_dir = root.join("usr/lib64");
|
|
||||||
let include_dir = root.join("usr/include");
|
|
||||||
command.env("CPATH", include_dir);
|
|
||||||
command.env(
|
|
||||||
"LIBRARY_PATH",
|
|
||||||
format!("{}:{}", lib_dir.display(), lib64_dir.display()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_rejected(context: &str, output: Output, expected: &str) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"{} unexpectedly succeeded\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stdout.is_empty(),
|
|
||||||
"{} rejected compile wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(expected),
|
|
||||||
"{} diagnostic drifted; expected `{}`\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
expected,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,309 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn standard_string_scanning_beta16_lowering_shape_uses_runtime_symbols() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"std-string-scanning-beta16-lowering",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn byte_or_code ((text string) (index i32)) -> i32
|
|
||||||
(match (std.string.byte_at_result text index)
|
|
||||||
((ok value)
|
|
||||||
value)
|
|
||||||
((err code)
|
|
||||||
code)))
|
|
||||||
|
|
||||||
(fn slice_or_empty ((text string) (start i32) (count i32)) -> string
|
|
||||||
(match (std.string.slice_result text start count)
|
|
||||||
((ok value)
|
|
||||||
value)
|
|
||||||
((err code)
|
|
||||||
"")))
|
|
||||||
|
|
||||||
(fn has_edges ((text string)) -> bool
|
|
||||||
(if (std.string.starts_with text "slo")
|
|
||||||
(std.string.ends_with text "vo")
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (has_edges (slice_or_empty "slovo" 0 5))
|
|
||||||
(byte_or_code "slovo" 3)
|
|
||||||
1))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"compiler rejected beta16 string scanning fixture\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stdout.contains("declare i64 @__glagol_string_byte_at_result(ptr, i32)")
|
|
||||||
&& stdout.contains("declare ptr @__glagol_string_slice_result(ptr, i32, i32)")
|
|
||||||
&& stdout.contains("declare i1 @__glagol_string_starts_with(ptr, ptr)")
|
|
||||||
&& stdout.contains("declare i1 @__glagol_string_ends_with(ptr, ptr)")
|
|
||||||
&& stdout.contains("call i64 @__glagol_string_byte_at_result(ptr %text, i32 %index)")
|
|
||||||
&& stdout.contains(
|
|
||||||
"call ptr @__glagol_string_slice_result(ptr %text, i32 %start, i32 %count)"
|
|
||||||
)
|
|
||||||
&& stdout.contains("call i1 @__glagol_string_starts_with(ptr %text, ptr @.str.")
|
|
||||||
&& stdout.contains("call i1 @__glagol_string_ends_with(ptr %text, ptr @.str.")
|
|
||||||
&& stdout.contains("icmp ne ptr %")
|
|
||||||
&& stdout.contains("insertvalue { i1, ptr, i32 }")
|
|
||||||
&& !stdout.contains("@std.string.byte_at_result")
|
|
||||||
&& !stdout.contains("@std.string.slice_result")
|
|
||||||
&& !stdout.contains("@std.string.starts_with")
|
|
||||||
&& !stdout.contains("@std.string.ends_with"),
|
|
||||||
"LLVM output did not contain expected beta16 string runtime shape\nstdout:\n{}",
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "compiler wrote stderr:\n{}", stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_runner_executes_standard_string_scanning_beta16_boundaries() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"std-string-scanning-beta16-test-runner",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "byte first ok"
|
|
||||||
(= (unwrap_ok (std.string.byte_at_result "slovo" 0)) 115))
|
|
||||||
|
|
||||||
(test "byte last ok"
|
|
||||||
(= (unwrap_ok (std.string.byte_at_result "slovo" 4)) 111))
|
|
||||||
|
|
||||||
(test "byte empty err"
|
|
||||||
(= (unwrap_err (std.string.byte_at_result "" 0)) 1))
|
|
||||||
|
|
||||||
(test "byte negative err"
|
|
||||||
(= (unwrap_err (std.string.byte_at_result "slovo" -1)) 1))
|
|
||||||
|
|
||||||
(test "byte end err"
|
|
||||||
(= (unwrap_err (std.string.byte_at_result "slovo" 5)) 1))
|
|
||||||
|
|
||||||
(test "slice middle ok"
|
|
||||||
(= (unwrap_ok (std.string.slice_result "slovo" 1 3)) "lov"))
|
|
||||||
|
|
||||||
(test "slice zero count ok"
|
|
||||||
(= (unwrap_ok (std.string.slice_result "slovo" 2 0)) ""))
|
|
||||||
|
|
||||||
(test "slice len zero ok"
|
|
||||||
(= (unwrap_ok (std.string.slice_result "slovo" 5 0)) ""))
|
|
||||||
|
|
||||||
(test "slice full ok"
|
|
||||||
(= (unwrap_ok (std.string.slice_result "slovo" 0 5)) "slovo"))
|
|
||||||
|
|
||||||
(test "slice negative start err"
|
|
||||||
(= (unwrap_err (std.string.slice_result "slovo" -1 1)) 1))
|
|
||||||
|
|
||||||
(test "slice negative count err"
|
|
||||||
(= (unwrap_err (std.string.slice_result "slovo" 1 -1)) 1))
|
|
||||||
|
|
||||||
(test "slice overrun err"
|
|
||||||
(= (unwrap_err (std.string.slice_result "slovo" 4 2)) 1))
|
|
||||||
|
|
||||||
(test "slice start past end err"
|
|
||||||
(= (unwrap_err (std.string.slice_result "slovo" 6 0)) 1))
|
|
||||||
|
|
||||||
(test "starts true empty"
|
|
||||||
(if (std.string.starts_with "slovo" "slo")
|
|
||||||
(std.string.starts_with "slovo" "")
|
|
||||||
false))
|
|
||||||
|
|
||||||
(test "starts false middle"
|
|
||||||
(= (std.string.starts_with "slovo" "ovo") false))
|
|
||||||
|
|
||||||
(test "ends true empty"
|
|
||||||
(if (std.string.ends_with "slovo" "ovo")
|
|
||||||
(std.string.ends_with "slovo" "")
|
|
||||||
false))
|
|
||||||
|
|
||||||
(test "ends false prefix"
|
|
||||||
(= (std.string.ends_with "slovo" "slo") false))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let output = run_glagol([OsStr::new("test"), fixture.as_os_str()]);
|
|
||||||
assert_success("run beta16 string scanning tests", &output);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
concat!(
|
|
||||||
"test \"byte first ok\" ... ok\n",
|
|
||||||
"test \"byte last ok\" ... ok\n",
|
|
||||||
"test \"byte empty err\" ... ok\n",
|
|
||||||
"test \"byte negative err\" ... ok\n",
|
|
||||||
"test \"byte end err\" ... ok\n",
|
|
||||||
"test \"slice middle ok\" ... ok\n",
|
|
||||||
"test \"slice zero count ok\" ... ok\n",
|
|
||||||
"test \"slice len zero ok\" ... ok\n",
|
|
||||||
"test \"slice full ok\" ... ok\n",
|
|
||||||
"test \"slice negative start err\" ... ok\n",
|
|
||||||
"test \"slice negative count err\" ... ok\n",
|
|
||||||
"test \"slice overrun err\" ... ok\n",
|
|
||||||
"test \"slice start past end err\" ... ok\n",
|
|
||||||
"test \"starts true empty\" ... ok\n",
|
|
||||||
"test \"starts false middle\" ... ok\n",
|
|
||||||
"test \"ends true empty\" ... ok\n",
|
|
||||||
"test \"ends false prefix\" ... ok\n",
|
|
||||||
"17 test(s) passed\n",
|
|
||||||
),
|
|
||||||
"beta16 string scanning test runner stdout drifted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn standard_string_scanning_beta16_runtime_smoke_when_clang_is_available() {
|
|
||||||
let Some(clang) = find_clang() else {
|
|
||||||
eprintln!(
|
|
||||||
"skipping beta16 string scanning runtime smoke: set GLAGOL_CLANG or install clang"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"std-string-scanning-beta16-runtime-smoke",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.io.print_i32 (unwrap_ok (std.string.byte_at_result "slovo" 3)))
|
|
||||||
(std.io.print_string (unwrap_ok (std.string.slice_result "slovo" 1 3)))
|
|
||||||
(std.io.print_bool (std.string.starts_with "slovo" "slo"))
|
|
||||||
(std.io.print_bool (std.string.ends_with "slovo" "ovo"))
|
|
||||||
(std.io.print_i32 (unwrap_err (std.string.byte_at_result "slovo" 5)))
|
|
||||||
(std.io.print_i32 (unwrap_err (std.string.slice_result "slovo" 4 2)))
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let compile = run_glagol([fixture.as_os_str()]);
|
|
||||||
assert_success("compile beta16 string scanning runtime smoke", &compile);
|
|
||||||
|
|
||||||
let run = compile_and_run_with_runtime(&clang, "std-string-scanning-beta16", &compile.stdout);
|
|
||||||
assert_success("run beta16 string scanning runtime smoke", &run);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&run.stdout),
|
|
||||||
"118\nlov\ntrue\ntrue\n1\n1\n",
|
|
||||||
"beta16 string scanning runtime stdout drifted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let mut path = env::temp_dir();
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-standard-string-scanning-beta16-{}-{}-{}.slo",
|
|
||||||
name,
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_and_run_with_runtime(clang: &Path, name: &str, ir: &[u8]) -> Output {
|
|
||||||
let manifest = Path::new(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
let temp_dir = env::temp_dir().join(format!(
|
|
||||||
"glagol-standard-string-scanning-beta16-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
fs::create_dir_all(&temp_dir)
|
|
||||||
.unwrap_or_else(|err| panic!("create `{}`: {}", temp_dir.display(), err));
|
|
||||||
|
|
||||||
let ir_path = temp_dir.join(format!("{}.ll", name));
|
|
||||||
let exe_path = temp_dir.join(name);
|
|
||||||
fs::write(&ir_path, ir).unwrap_or_else(|err| panic!("write `{}`: {}", ir_path.display(), err));
|
|
||||||
|
|
||||||
let runtime = manifest.join("../runtime/runtime.c");
|
|
||||||
let mut clang_command = Command::new(clang);
|
|
||||||
clang_command
|
|
||||||
.arg(&runtime)
|
|
||||||
.arg(&ir_path)
|
|
||||||
.arg("-o")
|
|
||||||
.arg(&exe_path)
|
|
||||||
.current_dir(manifest);
|
|
||||||
configure_clang_runtime_env(&mut clang_command, clang);
|
|
||||||
let clang_output = clang_command
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", clang.display(), err));
|
|
||||||
assert_success("clang beta16 string scanning runtime smoke", &clang_output);
|
|
||||||
|
|
||||||
Command::new(&exe_path)
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|err| panic!("run `{}`: {}", exe_path.display(), err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_clang() -> Option<PathBuf> {
|
|
||||||
if let Some(path) = env::var_os("GLAGOL_CLANG").filter(|value| !value.is_empty()) {
|
|
||||||
return Some(PathBuf::from(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
let hermetic_clang = PathBuf::from("/tmp/glagol-clang-root/usr/bin/clang");
|
|
||||||
if hermetic_clang.is_file() {
|
|
||||||
return Some(hermetic_clang);
|
|
||||||
}
|
|
||||||
|
|
||||||
find_on_path("clang")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_on_path(program: &str) -> Option<PathBuf> {
|
|
||||||
let path = env::var_os("PATH")?;
|
|
||||||
env::split_paths(&path)
|
|
||||||
.map(|dir| dir.join(program))
|
|
||||||
.find(|candidate| candidate.is_file())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_clang_runtime_env(command: &mut Command, clang: &Path) {
|
|
||||||
if !clang.starts_with("/tmp/glagol-clang-root") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = Path::new("/tmp/glagol-clang-root");
|
|
||||||
let lib64 = root.join("usr/lib64");
|
|
||||||
let lib = root.join("usr/lib");
|
|
||||||
let mut paths = vec![lib64, lib];
|
|
||||||
|
|
||||||
if let Some(existing) = env::var_os("LD_LIBRARY_PATH") {
|
|
||||||
paths.extend(env::split_paths(&existing));
|
|
||||||
}
|
|
||||||
|
|
||||||
let joined = env::join_paths(paths).expect("join LD_LIBRARY_PATH");
|
|
||||||
command.env("LD_LIBRARY_PATH", joined);
|
|
||||||
}
|
|
||||||
@ -1,478 +0,0 @@
|
|||||||
use std::{
|
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|
||||||
"test \"explicit std string contains\" ... ok\n",
|
|
||||||
"test \"explicit std string index_of_option\" ... ok\n",
|
|
||||||
"test \"explicit std string last_index_of_option\" ... ok\n",
|
|
||||||
"test \"explicit std string ascii trim\" ... ok\n",
|
|
||||||
"test \"explicit std string search trim composition\" ... ok\n",
|
|
||||||
"test \"explicit std string search trim all\" ... ok\n",
|
|
||||||
"6 test(s) passed\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
const STANDARD_STRING_SEARCH_TRIM_BETA20: &[&str] = &[
|
|
||||||
"contains",
|
|
||||||
"index_of_option",
|
|
||||||
"last_index_of_option",
|
|
||||||
"trim_ascii_start",
|
|
||||||
"trim_ascii_end",
|
|
||||||
"trim_ascii",
|
|
||||||
];
|
|
||||||
|
|
||||||
const ALLOWED_STD_REFERENCES: &[&str] = &[
|
|
||||||
"std.result",
|
|
||||||
"std.string.parse_bool_result",
|
|
||||||
"std.string.parse_f64_result",
|
|
||||||
"std.string.parse_i64_result",
|
|
||||||
"std.string.parse_u64_result",
|
|
||||||
"std.string.parse_i32_result",
|
|
||||||
"std.string.parse_u32_result",
|
|
||||||
"std.string.byte_at_result",
|
|
||||||
"std.string.slice_result",
|
|
||||||
"std.string.starts_with",
|
|
||||||
"std.string.ends_with",
|
|
||||||
"std.string.concat",
|
|
||||||
"std.string.len",
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn explicit_std_string_search_and_ascii_trim_helpers_check_and_test() {
|
|
||||||
let project = write_project(
|
|
||||||
"std-string-search-trim-beta20",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(import std.string (contains index_of_option last_index_of_option trim_ascii_start trim_ascii_end trim_ascii))
|
|
||||||
|
|
||||||
(fn option_i32_eq ((maybe (option i32)) (expected i32)) -> bool
|
|
||||||
(match maybe
|
|
||||||
((some value)
|
|
||||||
(= value expected))
|
|
||||||
((none)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn option_i32_none ((maybe (option i32))) -> bool
|
|
||||||
(match maybe
|
|
||||||
((some value)
|
|
||||||
false)
|
|
||||||
((none)
|
|
||||||
true)))
|
|
||||||
|
|
||||||
(fn imported_string_contains_ok () -> bool
|
|
||||||
(if (contains "slovo compiler" "slo")
|
|
||||||
(if (contains "slovo compiler" "compiler")
|
|
||||||
(= (contains "slovo compiler" "missing") false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_index_of_ok () -> bool
|
|
||||||
(if (option_i32_eq (index_of_option "bananana" "ana") 1)
|
|
||||||
(if (option_i32_eq (index_of_option "slovo" "s") 0)
|
|
||||||
(if (option_i32_eq (index_of_option "slovo" "vo") 3)
|
|
||||||
(option_i32_none (index_of_option "slovo" "compiler"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_last_index_of_ok () -> bool
|
|
||||||
(if (option_i32_eq (last_index_of_option "bananana" "ana") 5)
|
|
||||||
(if (option_i32_eq (last_index_of_option "slovo" "o") 4)
|
|
||||||
(if (option_i32_eq (last_index_of_option "slovo" "s") 0)
|
|
||||||
(option_i32_none (last_index_of_option "slovo" "compiler"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_ascii_trim_ok () -> bool
|
|
||||||
(if (= (trim_ascii_start "\n\t slovo \t") "slovo \t")
|
|
||||||
(if (= (trim_ascii_end "\n\t slovo \t") "\n\t slovo")
|
|
||||||
(if (= (trim_ascii "\n\t slovo \t") "slovo")
|
|
||||||
(if (= (trim_ascii "slovo") "slovo")
|
|
||||||
(= (trim_ascii " ") "")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_search_trim_composes_ok () -> bool
|
|
||||||
(if (= (trim_ascii " slovo compiler ") "slovo compiler")
|
|
||||||
(if (contains (trim_ascii " slovo compiler ") "compiler")
|
|
||||||
(if (option_i32_eq (index_of_option (trim_ascii_start "\t\tprefix-core") "core") 7)
|
|
||||||
(option_i32_eq (last_index_of_option (trim_ascii_end "core-core\n") "core") 5)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_search_trim_all_ok () -> bool
|
|
||||||
(if (imported_string_contains_ok)
|
|
||||||
(if (imported_string_index_of_ok)
|
|
||||||
(if (imported_string_last_index_of_ok)
|
|
||||||
(if (imported_string_ascii_trim_ok)
|
|
||||||
(imported_string_search_trim_composes_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (imported_string_search_trim_all_ok)
|
|
||||||
42
|
|
||||||
1))
|
|
||||||
|
|
||||||
(test "explicit std string contains"
|
|
||||||
(imported_string_contains_ok))
|
|
||||||
|
|
||||||
(test "explicit std string index_of_option"
|
|
||||||
(imported_string_index_of_ok))
|
|
||||||
|
|
||||||
(test "explicit std string last_index_of_option"
|
|
||||||
(imported_string_last_index_of_ok))
|
|
||||||
|
|
||||||
(test "explicit std string ascii trim"
|
|
||||||
(imported_string_ascii_trim_ok))
|
|
||||||
|
|
||||||
(test "explicit std string search trim composition"
|
|
||||||
(imported_string_search_trim_composes_ok))
|
|
||||||
|
|
||||||
(test "explicit std string search trim all"
|
|
||||||
(= (main) 42))
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let source = read(&project.join("src/main.slo"));
|
|
||||||
let std_string = read(&std_string_path());
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!project.join("src/string.slo").exists(),
|
|
||||||
"beta20 fixture must exercise repo-root std.string, not a local module copy"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
source.starts_with("(module main)\n\n(import std.string ("),
|
|
||||||
"beta20 fixture must use an explicit std.string import"
|
|
||||||
);
|
|
||||||
assert_std_string_search_trim_facades(&std_string);
|
|
||||||
|
|
||||||
let fmt = run_glagol([
|
|
||||||
OsStr::new("fmt"),
|
|
||||||
OsStr::new("--check"),
|
|
||||||
project.as_os_str(),
|
|
||||||
]);
|
|
||||||
assert_success("std string search trim fmt --check", &fmt);
|
|
||||||
|
|
||||||
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
|
||||||
assert_success_stdout(check, "", "std string search trim check");
|
|
||||||
|
|
||||||
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
|
||||||
assert_success_stdout(test, EXPECTED_TEST_OUTPUT, "std string search trim test");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_search_and_ascii_trim_helpers_are_not_compiler_known_runtime_calls() {
|
|
||||||
let std_string = read(&std_string_path());
|
|
||||||
assert_std_string_search_trim_facades(&std_string);
|
|
||||||
|
|
||||||
for helper in STANDARD_STRING_SEARCH_TRIM_BETA20 {
|
|
||||||
assert!(
|
|
||||||
!std_string.contains(&format!("std.string.{}", helper)),
|
|
||||||
"std.string.{} must remain source-authored, not a compiler-known runtime call",
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!std_string.contains(&format!("__glagol_string_{}", helper)),
|
|
||||||
"std.string.{} must not introduce a private runtime symbol",
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cases = [
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "contains",
|
|
||||||
symbol: "std.string.contains",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(if (std.string.contains "slovo" "ovo")
|
|
||||||
0
|
|
||||||
1))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "index-of-option",
|
|
||||||
symbol: "std.string.index_of_option",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(match (std.string.index_of_option "slovo" "o")
|
|
||||||
((some value)
|
|
||||||
value)
|
|
||||||
((none)
|
|
||||||
0)))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "last-index-of-option",
|
|
||||||
symbol: "std.string.last_index_of_option",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(match (std.string.last_index_of_option "slovo" "o")
|
|
||||||
((some value)
|
|
||||||
value)
|
|
||||||
((none)
|
|
||||||
0)))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "trim-ascii-start",
|
|
||||||
symbol: "std.string.trim_ascii_start",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.len (std.string.trim_ascii_start " slovo")))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "trim-ascii-end",
|
|
||||||
symbol: "std.string.trim_ascii_end",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.len (std.string.trim_ascii_end "slovo ")))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
UnsupportedRuntimeCase {
|
|
||||||
name: "trim-ascii",
|
|
||||||
symbol: "std.string.trim_ascii",
|
|
||||||
source: r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
(std.string.len (std.string.trim_ascii " slovo ")))
|
|
||||||
"#,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for case in cases {
|
|
||||||
let fixture = write_fixture(case.name, case.source);
|
|
||||||
let output = run_glagol([fixture.as_os_str()]);
|
|
||||||
assert_failure_stderr_contains(
|
|
||||||
&format!("direct {} runtime call", case.symbol),
|
|
||||||
&output,
|
|
||||||
&format!("standard library call `{}` is not supported", case.symbol),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_std_string_search_trim_facades(std_string: &str) {
|
|
||||||
assert!(
|
|
||||||
std_string.starts_with("(module string (export "),
|
|
||||||
"lib/std/string.slo must stay a source-authored module export"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut non_allowed_std = std_string.to_owned();
|
|
||||||
for allowed in ALLOWED_STD_REFERENCES {
|
|
||||||
non_allowed_std = non_allowed_std.replace(allowed, "");
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
!non_allowed_std.contains("std."),
|
|
||||||
"std.string beta20 helpers must use only existing std.result bridges and promoted beta16-or-earlier std.string primitives"
|
|
||||||
);
|
|
||||||
|
|
||||||
for helper in STANDARD_STRING_SEARCH_TRIM_BETA20 {
|
|
||||||
assert!(
|
|
||||||
std_string.contains(&format!("(fn {} ", helper)),
|
|
||||||
"lib/std/string.slo is missing source facade `{}`",
|
|
||||||
helper
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let search_trim_source = search_trim_source_region(std_string);
|
|
||||||
for primitive in [
|
|
||||||
("len", ["std.string.len", "(len "]),
|
|
||||||
(
|
|
||||||
"byte_at_result",
|
|
||||||
["std.string.byte_at_result", "(byte_at_result "],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"slice_result",
|
|
||||||
["std.string.slice_result", "(slice_result "],
|
|
||||||
),
|
|
||||||
("starts_with", ["std.string.starts_with", "(starts_with "]),
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
primitive
|
|
||||||
.1
|
|
||||||
.iter()
|
|
||||||
.any(|needle| search_trim_source.contains(needle)),
|
|
||||||
"beta20 search/trim facades must compose over existing beta16 string primitive `{}`",
|
|
||||||
primitive.0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
!std_string.contains("unicode")
|
|
||||||
&& !std_string.contains("grapheme")
|
|
||||||
&& !std_string.contains("locale")
|
|
||||||
&& !std_string.contains("case_insensitive")
|
|
||||||
&& !std_string.contains("regex"),
|
|
||||||
"beta20 string helpers must not claim deferred Unicode, locale, case-folding, or regex APIs"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_trim_source_region(source: &str) -> &str {
|
|
||||||
let ends_with_end = function_range(source, "ends_with").1;
|
|
||||||
let parse_start = function_range(source, "parse_i32_result").0;
|
|
||||||
&source[ends_with_end..parse_start]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function_range(source: &str, name: &str) -> (usize, usize) {
|
|
||||||
let needle = format!("(fn {} ", name);
|
|
||||||
let start = source
|
|
||||||
.find(&needle)
|
|
||||||
.unwrap_or_else(|| panic!("missing function `{}`", name));
|
|
||||||
let mut depth = 0usize;
|
|
||||||
|
|
||||||
for (offset, byte) in source.as_bytes()[start..].iter().enumerate() {
|
|
||||||
match byte {
|
|
||||||
b'(' => depth += 1,
|
|
||||||
b')' => {
|
|
||||||
depth = depth
|
|
||||||
.checked_sub(1)
|
|
||||||
.unwrap_or_else(|| panic!("unbalanced function `{}`", name));
|
|
||||||
if depth == 0 {
|
|
||||||
return (start, start + offset + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("unterminated function `{}`", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(name: &str, source: &str) -> PathBuf {
|
|
||||||
let root = temp_root(name);
|
|
||||||
let src = root.join("src");
|
|
||||||
fs::create_dir_all(&src).unwrap_or_else(|err| panic!("create `{}`: {}", src.display(), err));
|
|
||||||
fs::write(
|
|
||||||
root.join("slovo.toml"),
|
|
||||||
format!(
|
|
||||||
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|err| panic!("write project manifest: {}", err));
|
|
||||||
fs::write(src.join("main.slo"), source.trim_start())
|
|
||||||
.unwrap_or_else(|err| panic!("write project main.slo: {}", err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let mut path = env::temp_dir();
|
|
||||||
path.push(format!(
|
|
||||||
"glagol-standard-string-search-trim-beta20-{}-{}-{}.slo",
|
|
||||||
name,
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
fs::write(&path, source.trim_start())
|
|
||||||
.unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_root(name: &str) -> PathBuf {
|
|
||||||
let root = env::temp_dir().join(format!(
|
|
||||||
"glagol-standard-string-search-trim-beta20-{}-{}-{}",
|
|
||||||
name,
|
|
||||||
std::process::id(),
|
|
||||||
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
||||||
));
|
|
||||||
let _ = fs::remove_dir_all(&root);
|
|
||||||
fs::create_dir_all(&root).unwrap_or_else(|err| panic!("create `{}`: {}", root.display(), err));
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn std_string_path() -> PathBuf {
|
|
||||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("../lib/std/string.slo")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(path: &Path) -> String {
|
|
||||||
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
output.status.code(),
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
|
|
||||||
assert_success(context, &output);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
assert_eq!(stdout, expected, "{}", context);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_failure_stderr_contains(context: &str, output: &Output, needle: &str) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"{} unexpectedly passed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stdout.is_empty(),
|
|
||||||
"{} rejected compile wrote stdout:\n{}",
|
|
||||||
context,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
stderr.contains(needle),
|
|
||||||
"{} stderr did not contain `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
needle,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UnsupportedRuntimeCase {
|
|
||||||
name: &'static str,
|
|
||||||
symbol: &'static str,
|
|
||||||
source: &'static str,
|
|
||||||
}
|
|
||||||
@ -7,33 +7,18 @@ use std::{
|
|||||||
|
|
||||||
const EXPECTED_TEST_OUTPUT: &str = concat!(
|
const EXPECTED_TEST_OUTPUT: &str = concat!(
|
||||||
"test \"explicit local string len concat\" ... ok\n",
|
"test \"explicit local string len concat\" ... ok\n",
|
||||||
"test \"explicit local string byte_at_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit local string slice_result wrapper\" ... ok\n",
|
|
||||||
"test \"explicit local string boundary wrappers\" ... ok\n",
|
|
||||||
"test \"explicit local string parse result wrappers\" ... ok\n",
|
"test \"explicit local string parse result wrappers\" ... ok\n",
|
||||||
"test \"explicit local string parse option wrappers\" ... ok\n",
|
"test \"explicit local string parse option wrappers\" ... ok\n",
|
||||||
"test \"explicit local string parse integer fallbacks\" ... ok\n",
|
"test \"explicit local string parse integer fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string parse float bool fallbacks\" ... ok\n",
|
"test \"explicit local string parse float bool fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string parse custom fallbacks\" ... ok\n",
|
"test \"explicit local string parse custom fallbacks\" ... ok\n",
|
||||||
"test \"explicit local string search helpers\" ... ok\n",
|
|
||||||
"test \"explicit local string ascii trim helpers\" ... ok\n",
|
|
||||||
"test \"explicit local string helpers all\" ... ok\n",
|
"test \"explicit local string helpers all\" ... ok\n",
|
||||||
"12 test(s) passed\n",
|
"7 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_STRING_SOURCE_FALLBACK_HELPERS_ALPHA: &[&str] = &[
|
const STANDARD_STRING_SOURCE_FALLBACK_HELPERS_ALPHA: &[&str] = &[
|
||||||
"len",
|
"len",
|
||||||
"concat",
|
"concat",
|
||||||
"byte_at_result",
|
|
||||||
"slice_result",
|
|
||||||
"starts_with",
|
|
||||||
"ends_with",
|
|
||||||
"contains",
|
|
||||||
"index_of_option",
|
|
||||||
"last_index_of_option",
|
|
||||||
"trim_ascii_start",
|
|
||||||
"trim_ascii_end",
|
|
||||||
"trim_ascii",
|
|
||||||
"parse_i32_result",
|
"parse_i32_result",
|
||||||
"parse_i32_option",
|
"parse_i32_option",
|
||||||
"parse_u32_result",
|
"parse_u32_result",
|
||||||
@ -115,10 +100,6 @@ fn assert_local_string_fixture_is_source_authored(project: &Path) {
|
|||||||
"std.string.parse_u64_result",
|
"std.string.parse_u64_result",
|
||||||
"std.string.parse_i32_result",
|
"std.string.parse_i32_result",
|
||||||
"std.string.parse_u32_result",
|
"std.string.parse_u32_result",
|
||||||
"std.string.byte_at_result",
|
|
||||||
"std.string.slice_result",
|
|
||||||
"std.string.starts_with",
|
|
||||||
"std.string.ends_with",
|
|
||||||
"std.string.concat",
|
"std.string.concat",
|
||||||
"std.string.len",
|
"std.string.len",
|
||||||
] {
|
] {
|
||||||
@ -129,11 +110,11 @@ fn assert_local_string_fixture_is_source_authored(project: &Path) {
|
|||||||
"string fixture must use only the existing promoted std.string runtime names"
|
"string fixture must use only the existing promoted std.string runtime names"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!string.contains("locale")
|
!string.contains("trim")
|
||||||
|
&& !string.contains("locale")
|
||||||
&& !string.contains("unicode")
|
&& !string.contains("unicode")
|
||||||
&& !string.contains("bytes")
|
&& !string.contains("bytes")
|
||||||
&& !string.contains("case_insensitive")
|
&& !string.contains("case_insensitive")
|
||||||
&& !string.contains("regex")
|
|
||||||
&& !string.contains("host_error"),
|
&& !string.contains("host_error"),
|
||||||
"string fixture must not claim deferred parsing or richer error APIs"
|
"string fixture must not claim deferred parsing or richer error APIs"
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,7 +11,6 @@ const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit local vec_f64 builder helpers\" ... ok\n",
|
"test \"explicit local vec_f64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 query helpers\" ... ok\n",
|
"test \"explicit local vec_f64 query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 option query helpers\" ... ok\n",
|
"test \"explicit local vec_f64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_f64 starts_with helper\" ... ok\n",
|
"test \"explicit local vec_f64 starts_with helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 ends_with helper\" ... ok\n",
|
"test \"explicit local vec_f64 ends_with helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 without_suffix helper\" ... ok\n",
|
"test \"explicit local vec_f64 without_suffix helper\" ... ok\n",
|
||||||
@ -26,7 +25,7 @@ const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit local vec_f64 remove range helper\" ... ok\n",
|
"test \"explicit local vec_f64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 real program helpers\" ... ok\n",
|
"test \"explicit local vec_f64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_f64 helpers all\" ... ok\n",
|
"test \"explicit local vec_f64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"19 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -49,7 +48,6 @@ const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
@ -186,7 +184,6 @@ fn assert_local_vec_f64_fixture_is_source_authored(project: &Path) {
|
|||||||
"index_of_option_loop",
|
"index_of_option_loop",
|
||||||
"last_index_of_option_loop",
|
"last_index_of_option_loop",
|
||||||
"contains_loop",
|
"contains_loop",
|
||||||
"count_of_loop",
|
|
||||||
"sum_loop",
|
"sum_loop",
|
||||||
"concat_loop",
|
"concat_loop",
|
||||||
"take_loop",
|
"take_loop",
|
||||||
@ -199,43 +196,6 @@ fn assert_local_vec_f64_fixture_is_source_authored(project: &Path) {
|
|||||||
helper
|
helper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_count_of_cases_are_exercised(&main);
|
|
||||||
assert_prefix_suffix_cases_are_exercised(&main);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_count_of_cases_are_exercised(main: &str) {
|
|
||||||
assert!(
|
|
||||||
main.contains("(count_of (empty)"),
|
|
||||||
"main.slo must exercise count_of on an empty vec_f64"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
main.matches("(count_of").count() >= 4,
|
|
||||||
"main.slo must exercise repeated, singleton, and absent count_of cases"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_prefix_suffix_cases_are_exercised(main: &str) {
|
|
||||||
for case in [
|
|
||||||
"(starts_with values (empty))",
|
|
||||||
"(starts_with values values)",
|
|
||||||
"(ends_with values (empty))",
|
|
||||||
"(ends_with values values)",
|
|
||||||
"(without_prefix values (empty))",
|
|
||||||
"(without_prefix values values)",
|
|
||||||
"(without_suffix values (empty))",
|
|
||||||
"(without_suffix values values)",
|
|
||||||
"mismatched_prefix",
|
|
||||||
"mismatched_suffix",
|
|
||||||
"longer_prefix",
|
|
||||||
"longer_suffix",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
main.contains(case),
|
|
||||||
"main.slo must exercise vec_f64 prefix/suffix case `{}`",
|
|
||||||
case
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
fn run_glagol<I, S>(args: I) -> Output
|
||||||
|
|||||||
@ -11,7 +11,6 @@ const EXPECTED_STD_VEC_F64_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit std vec_f64 builder helpers\" ... ok\n",
|
"test \"explicit std vec_f64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 query helpers\" ... ok\n",
|
"test \"explicit std vec_f64 query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 option query helpers\" ... ok\n",
|
"test \"explicit std vec_f64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_f64 starts_with helper\" ... ok\n",
|
"test \"explicit std vec_f64 starts_with helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 ends_with helper\" ... ok\n",
|
"test \"explicit std vec_f64 ends_with helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 without_suffix helper\" ... ok\n",
|
"test \"explicit std vec_f64 without_suffix helper\" ... ok\n",
|
||||||
@ -26,7 +25,7 @@ const EXPECTED_STD_VEC_F64_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit std vec_f64 remove range helper\" ... ok\n",
|
"test \"explicit std vec_f64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 real program helpers\" ... ok\n",
|
"test \"explicit std vec_f64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_f64 helpers all\" ... ok\n",
|
"test \"explicit std vec_f64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"19 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -49,7 +48,6 @@ const STANDARD_VEC_F64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
|
|||||||
@ -11,11 +11,6 @@ const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit local vec_i64 builder helpers\" ... ok\n",
|
"test \"explicit local vec_i64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 query helpers\" ... ok\n",
|
"test \"explicit local vec_i64 query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 option query helpers\" ... ok\n",
|
"test \"explicit local vec_i64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 starts_with helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 ends_with helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 without_suffix helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 without_prefix helper\" ... ok\n",
|
|
||||||
"test \"explicit local vec_i64 transform helpers\" ... ok\n",
|
"test \"explicit local vec_i64 transform helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 subvec helper\" ... ok\n",
|
"test \"explicit local vec_i64 subvec helper\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 insert helper\" ... ok\n",
|
"test \"explicit local vec_i64 insert helper\" ... ok\n",
|
||||||
@ -26,7 +21,7 @@ const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit local vec_i64 remove range helper\" ... ok\n",
|
"test \"explicit local vec_i64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 real program helpers\" ... ok\n",
|
"test \"explicit local vec_i64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit local vec_i64 helpers all\" ... ok\n",
|
"test \"explicit local vec_i64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"15 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -49,14 +44,9 @@ const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
"starts_with",
|
|
||||||
"without_prefix",
|
|
||||||
"ends_with",
|
|
||||||
"without_suffix",
|
|
||||||
"drop",
|
"drop",
|
||||||
"reverse",
|
"reverse",
|
||||||
"subvec",
|
"subvec",
|
||||||
@ -186,7 +176,6 @@ fn assert_local_vec_i64_fixture_is_source_authored(project: &Path) {
|
|||||||
"index_of_option_loop",
|
"index_of_option_loop",
|
||||||
"last_index_of_option_loop",
|
"last_index_of_option_loop",
|
||||||
"contains_loop",
|
"contains_loop",
|
||||||
"count_of_loop",
|
|
||||||
"sum_loop",
|
"sum_loop",
|
||||||
"concat_loop",
|
"concat_loop",
|
||||||
"take_loop",
|
"take_loop",
|
||||||
@ -199,43 +188,6 @@ fn assert_local_vec_i64_fixture_is_source_authored(project: &Path) {
|
|||||||
helper
|
helper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_count_of_cases_are_exercised(&main);
|
|
||||||
assert_prefix_suffix_cases_are_exercised(&main);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_count_of_cases_are_exercised(main: &str) {
|
|
||||||
assert!(
|
|
||||||
main.contains("(count_of (empty)"),
|
|
||||||
"main.slo must exercise count_of on an empty vec_i64"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
main.matches("(count_of").count() >= 4,
|
|
||||||
"main.slo must exercise repeated, singleton, and absent count_of cases"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_prefix_suffix_cases_are_exercised(main: &str) {
|
|
||||||
for case in [
|
|
||||||
"(starts_with values (empty))",
|
|
||||||
"(starts_with values values)",
|
|
||||||
"(ends_with values (empty))",
|
|
||||||
"(ends_with values values)",
|
|
||||||
"(without_prefix values (empty))",
|
|
||||||
"(without_prefix values values)",
|
|
||||||
"(without_suffix values (empty))",
|
|
||||||
"(without_suffix values values)",
|
|
||||||
"mismatched_prefix",
|
|
||||||
"mismatched_suffix",
|
|
||||||
"longer_prefix",
|
|
||||||
"longer_suffix",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
main.contains(case),
|
|
||||||
"main.slo must exercise vec_i64 prefix/suffix case `{}`",
|
|
||||||
case
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
fn run_glagol<I, S>(args: I) -> Output
|
||||||
|
|||||||
@ -11,11 +11,6 @@ const EXPECTED_STD_VEC_I64_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit std vec_i64 builder helpers\" ... ok\n",
|
"test \"explicit std vec_i64 builder helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 query helpers\" ... ok\n",
|
"test \"explicit std vec_i64 query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 option query helpers\" ... ok\n",
|
"test \"explicit std vec_i64 option query helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 count_of helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 starts_with helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 ends_with helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 without_suffix helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 without_prefix helper\" ... ok\n",
|
|
||||||
"test \"explicit std vec_i64 transform helpers\" ... ok\n",
|
"test \"explicit std vec_i64 transform helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 subvec helper\" ... ok\n",
|
"test \"explicit std vec_i64 subvec helper\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 insert helper\" ... ok\n",
|
"test \"explicit std vec_i64 insert helper\" ... ok\n",
|
||||||
@ -26,7 +21,7 @@ const EXPECTED_STD_VEC_I64_OUTPUT: &str = concat!(
|
|||||||
"test \"explicit std vec_i64 remove range helper\" ... ok\n",
|
"test \"explicit std vec_i64 remove range helper\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 real program helpers\" ... ok\n",
|
"test \"explicit std vec_i64 real program helpers\" ... ok\n",
|
||||||
"test \"explicit std vec_i64 helpers all\" ... ok\n",
|
"test \"explicit std vec_i64 helpers all\" ... ok\n",
|
||||||
"20 test(s) passed\n",
|
"15 test(s) passed\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
@ -49,14 +44,9 @@ const STANDARD_VEC_I64_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"index_of_option",
|
"index_of_option",
|
||||||
"last_index_of_option",
|
"last_index_of_option",
|
||||||
"contains",
|
"contains",
|
||||||
"count_of",
|
|
||||||
"sum",
|
"sum",
|
||||||
"concat",
|
"concat",
|
||||||
"take",
|
"take",
|
||||||
"starts_with",
|
|
||||||
"without_prefix",
|
|
||||||
"ends_with",
|
|
||||||
"without_suffix",
|
|
||||||
"drop",
|
"drop",
|
||||||
"reverse",
|
"reverse",
|
||||||
"subvec",
|
"subvec",
|
||||||
|
|||||||
@ -1,384 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs,
|
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn file_list_preserves_order_and_does_not_execute_bodies() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"file-list",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "alpha first"
|
|
||||||
true)
|
|
||||||
|
|
||||||
(test "beta would fail"
|
|
||||||
false)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol(["test".as_ref(), "--list".as_ref(), fixture.as_os_str()]);
|
|
||||||
|
|
||||||
assert_success_stdout(
|
|
||||||
"file test list",
|
|
||||||
output,
|
|
||||||
"test \"alpha first\" ... selected\n\
|
|
||||||
test \"beta would fail\" ... selected\n\
|
|
||||||
2 test(s) selected (total_discovered 2, selected 2, passed 0, failed 0, skipped 0, filter none)\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn file_list_filter_marks_selected_and_skipped_in_order() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"file-list-filter",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "alpha first"
|
|
||||||
false)
|
|
||||||
|
|
||||||
(test "beta second"
|
|
||||||
false)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"test".as_ref(),
|
|
||||||
"--list".as_ref(),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
"--filter".as_ref(),
|
|
||||||
"beta".as_ref(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success_stdout(
|
|
||||||
"file filtered test list",
|
|
||||||
output,
|
|
||||||
"test \"alpha first\" ... skipped\n\
|
|
||||||
test \"beta second\" ... selected\n\
|
|
||||||
1 test(s) selected (total_discovered 2, selected 1, passed 0, failed 0, skipped 1, filter \"beta\")\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn legacy_run_tests_list_matches_test_subcommand_list() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"legacy-list",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "legacy first"
|
|
||||||
false)
|
|
||||||
|
|
||||||
(test "legacy second"
|
|
||||||
false)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let subcommand = run_glagol(["test".as_ref(), "--list".as_ref(), fixture.as_os_str()]);
|
|
||||||
let legacy = run_glagol([
|
|
||||||
"--run-tests".as_ref(),
|
|
||||||
"--list".as_ref(),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success("test --list", &subcommand);
|
|
||||||
assert_success("legacy --run-tests --list", &legacy);
|
|
||||||
assert_eq!(
|
|
||||||
legacy.stdout, subcommand.stdout,
|
|
||||||
"legacy list output differed from test subcommand"
|
|
||||||
);
|
|
||||||
assert!(legacy.stderr.is_empty(), "legacy list wrote stderr");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn project_list_preserves_topological_order_and_filter_counts() {
|
|
||||||
let project = write_project(
|
|
||||||
"project-list",
|
|
||||||
&[(
|
|
||||||
"provider",
|
|
||||||
"(module provider (export value))\n\n\
|
|
||||||
(fn value () -> i32\n 1)\n\n\
|
|
||||||
(test \"provider first\"\n false)\n",
|
|
||||||
)],
|
|
||||||
"(module main)\n\n\
|
|
||||||
(import provider (value))\n\n\
|
|
||||||
(fn main () -> i32\n (value))\n\n\
|
|
||||||
(test \"consumer second\"\n false)\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol([
|
|
||||||
"test".as_ref(),
|
|
||||||
"--list".as_ref(),
|
|
||||||
project.as_os_str(),
|
|
||||||
"--filter".as_ref(),
|
|
||||||
"consumer".as_ref(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_success_stdout(
|
|
||||||
"project filtered list",
|
|
||||||
output,
|
|
||||||
"test \"provider first\" ... skipped\n\
|
|
||||||
test \"consumer second\" ... selected\n\
|
|
||||||
1 test(s) selected (total_discovered 2, selected 1, passed 0, failed 0, skipped 1, filter \"consumer\")\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn workspace_list_preserves_package_order_without_running_tests() {
|
|
||||||
let workspace = write_workspace(
|
|
||||||
"workspace-list",
|
|
||||||
"[workspace]\nmembers = [\"packages/app\", \"packages/util\"]\n",
|
|
||||||
&[
|
|
||||||
WorkspacePackageSpec {
|
|
||||||
member: "packages/util",
|
|
||||||
manifest: "[package]\nname = \"util\"\nversion = \"0.1.0\"\n",
|
|
||||||
modules: &[(
|
|
||||||
"util",
|
|
||||||
"(module util (export answer))\n\n\
|
|
||||||
(fn answer () -> i32\n 41)\n\n\
|
|
||||||
(test \"util provider first\"\n false)\n",
|
|
||||||
)],
|
|
||||||
},
|
|
||||||
WorkspacePackageSpec {
|
|
||||||
member: "packages/app",
|
|
||||||
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nutil = { path = \"../util\" }\n",
|
|
||||||
modules: &[(
|
|
||||||
"main",
|
|
||||||
"(module main)\n\n\
|
|
||||||
(import util.util (answer))\n\n\
|
|
||||||
(fn main () -> i32\n (answer))\n\n\
|
|
||||||
(test \"app consumer second\"\n false)\n",
|
|
||||||
)],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol(["test".as_ref(), "--list".as_ref(), workspace.as_os_str()]);
|
|
||||||
|
|
||||||
assert_success_stdout(
|
|
||||||
"workspace list",
|
|
||||||
output,
|
|
||||||
"test \"util provider first\" ... selected\n\
|
|
||||||
test \"app consumer second\" ... selected\n\
|
|
||||||
2 test(s) selected (total_discovered 2, selected 2, passed 0, failed 0, skipped 0, filter none)\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ordinary_test_output_stays_byte_stable() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"ordinary-test",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "alpha first"
|
|
||||||
true)
|
|
||||||
|
|
||||||
(test "beta second"
|
|
||||||
true)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let subcommand = run_glagol(["test".as_ref(), fixture.as_os_str()]);
|
|
||||||
assert_success_stdout(
|
|
||||||
"ordinary test",
|
|
||||||
subcommand,
|
|
||||||
"test \"alpha first\" ... ok\n\
|
|
||||||
test \"beta second\" ... ok\n\
|
|
||||||
2 test(s) passed\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
let legacy = run_glagol(["--run-tests".as_ref(), fixture.as_os_str()]);
|
|
||||||
assert_success_stdout(
|
|
||||||
"ordinary legacy run-tests",
|
|
||||||
legacy,
|
|
||||||
"test \"alpha first\" ... ok\n\
|
|
||||||
test \"beta second\" ... ok\n\
|
|
||||||
2 test(s) passed\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_mode_reuses_checked_diagnostics_for_invalid_tests() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"invalid-list",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(test "not bool"
|
|
||||||
1)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol(["test".as_ref(), "--list".as_ref(), fixture.as_os_str()]);
|
|
||||||
|
|
||||||
assert_failure_stderr_contains(
|
|
||||||
"invalid list",
|
|
||||||
&output,
|
|
||||||
&[
|
|
||||||
"TestExpressionNotBool",
|
|
||||||
"Expected:",
|
|
||||||
"bool",
|
|
||||||
"Found:",
|
|
||||||
"i32",
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stdout.is_empty(),
|
|
||||||
"invalid list wrote stdout:\n{}",
|
|
||||||
String::from_utf8_lossy(&output.stdout)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_flag_is_rejected_outside_test_mode() {
|
|
||||||
let fixture = write_fixture(
|
|
||||||
"list-outside-test",
|
|
||||||
r#"
|
|
||||||
(module main)
|
|
||||||
|
|
||||||
(fn main () -> i32
|
|
||||||
0)
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = run_glagol(["check".as_ref(), "--list".as_ref(), fixture.as_os_str()]);
|
|
||||||
|
|
||||||
assert_failure_stderr_contains(
|
|
||||||
"check --list",
|
|
||||||
&output,
|
|
||||||
&["`--list` is only supported with `test` and `--run-tests`"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
||||||
let path = unique_path(name).with_extension("slo");
|
|
||||||
fs::write(&path, source).expect("write fixture");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_project(name: &str, modules: &[(&str, &str)], main: &str) -> PathBuf {
|
|
||||||
let root = unique_path(name);
|
|
||||||
let src = root.join("src");
|
|
||||||
fs::create_dir_all(&src).expect("create project src");
|
|
||||||
fs::write(
|
|
||||||
root.join("slovo.toml"),
|
|
||||||
format!(
|
|
||||||
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.expect("write project manifest");
|
|
||||||
fs::write(src.join("main.slo"), main).expect("write project main");
|
|
||||||
for (module, source) in modules {
|
|
||||||
fs::write(src.join(format!("{}.slo", module)), source).expect("write project module");
|
|
||||||
}
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WorkspacePackageSpec<'a> {
|
|
||||||
member: &'a str,
|
|
||||||
manifest: &'a str,
|
|
||||||
modules: &'a [(&'a str, &'a str)],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_workspace(
|
|
||||||
name: &str,
|
|
||||||
workspace_manifest: &str,
|
|
||||||
packages: &[WorkspacePackageSpec<'_>],
|
|
||||||
) -> PathBuf {
|
|
||||||
let root = unique_path(name);
|
|
||||||
fs::create_dir_all(&root).expect("create workspace root");
|
|
||||||
fs::write(root.join("slovo.toml"), workspace_manifest).expect("write workspace manifest");
|
|
||||||
for package in packages {
|
|
||||||
let package_root = root.join(package.member);
|
|
||||||
let src = package_root.join("src");
|
|
||||||
fs::create_dir_all(&src).expect("create workspace package src");
|
|
||||||
fs::write(package_root.join("slovo.toml"), package.manifest)
|
|
||||||
.expect("write workspace package manifest");
|
|
||||||
for (module, source) in package.modules {
|
|
||||||
fs::write(src.join(format!("{}.slo", module)), source)
|
|
||||||
.expect("write workspace package module");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_path(name: &str) -> PathBuf {
|
|
||||||
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::SeqCst);
|
|
||||||
let nanos = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.map(|duration| duration.as_nanos())
|
|
||||||
.unwrap_or(0);
|
|
||||||
std::env::temp_dir().join(format!(
|
|
||||||
"glagol-test-discovery-beta19-{}-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
nanos,
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<std::ffi::OsStr>,
|
|
||||||
{
|
|
||||||
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success(context: &str, output: &Output) {
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_stdout(context: &str, output: Output, expected: &str) {
|
|
||||||
assert_success(context, &output);
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
expected,
|
|
||||||
"{} stdout mismatch",
|
|
||||||
context
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stderr.is_empty(),
|
|
||||||
"{} wrote stderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_failure_stderr_contains(context: &str, output: &Output, expected: &[&str]) {
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"{} unexpectedly succeeded\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
context,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
for needle in expected {
|
|
||||||
assert!(
|
|
||||||
stderr.contains(needle),
|
|
||||||
"{} stderr missing `{}`:\n{}",
|
|
||||||
context,
|
|
||||||
needle,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,539 +0,0 @@
|
|||||||
use std::{
|
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Output},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
struct MatrixEntry {
|
|
||||||
path: &'static str,
|
|
||||||
expected_tests: usize,
|
|
||||||
run_tests: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MATRIX: &[MatrixEntry] = &[
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/basic",
|
|
||||||
expected_tests: 2,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/enum-imports",
|
|
||||||
expected_tests: 9,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-cli",
|
|
||||||
expected_tests: 17,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-env",
|
|
||||||
expected_tests: 23,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-fs",
|
|
||||||
expected_tests: 35,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-io",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-json",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-math",
|
|
||||||
expected_tests: 4,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-net",
|
|
||||||
expected_tests: 9,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-num",
|
|
||||||
expected_tests: 5,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-option",
|
|
||||||
expected_tests: 36,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-process",
|
|
||||||
expected_tests: 21,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-random",
|
|
||||||
expected_tests: 2,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-result",
|
|
||||||
expected_tests: 26,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-string",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-time",
|
|
||||||
expected_tests: 3,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-vec_bool",
|
|
||||||
expected_tests: 19,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-vec_f64",
|
|
||||||
expected_tests: 20,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-vec_i32",
|
|
||||||
expected_tests: 22,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-vec_i64",
|
|
||||||
expected_tests: 20,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-import-vec_string",
|
|
||||||
expected_tests: 19,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-cli",
|
|
||||||
expected_tests: 17,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-env",
|
|
||||||
expected_tests: 23,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-fs",
|
|
||||||
expected_tests: 35,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-io",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-json",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-math",
|
|
||||||
expected_tests: 7,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-net",
|
|
||||||
expected_tests: 9,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-num",
|
|
||||||
expected_tests: 5,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-option",
|
|
||||||
expected_tests: 36,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-process",
|
|
||||||
expected_tests: 21,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-random",
|
|
||||||
expected_tests: 3,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-result",
|
|
||||||
expected_tests: 26,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-string",
|
|
||||||
expected_tests: 12,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-time",
|
|
||||||
expected_tests: 3,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-vec_bool",
|
|
||||||
expected_tests: 19,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-vec_f64",
|
|
||||||
expected_tests: 20,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-vec_i32",
|
|
||||||
expected_tests: 22,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-vec_i64",
|
|
||||||
expected_tests: 20,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/std-layout-local-vec_string",
|
|
||||||
expected_tests: 19,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/projects/stdlib-composition",
|
|
||||||
expected_tests: 3,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/workspaces/exp-5-local",
|
|
||||||
expected_tests: 2,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
MatrixEntry {
|
|
||||||
path: "examples/workspaces/std-import-option",
|
|
||||||
expected_tests: 1,
|
|
||||||
run_tests: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn user_project_conformance_matrix_checks_lists_and_runs_stable_tests() {
|
|
||||||
assert_matrix_inventory();
|
|
||||||
|
|
||||||
let repo_root = repo_root();
|
|
||||||
for entry in MATRIX {
|
|
||||||
let fixture = repo_root.join(entry.path);
|
|
||||||
assert!(
|
|
||||||
fixture.join("slovo.toml").is_file(),
|
|
||||||
"{} must remain an existing project or workspace fixture",
|
|
||||||
entry.path
|
|
||||||
);
|
|
||||||
|
|
||||||
let check = run_glagol(
|
|
||||||
[OsStr::new("check"), fixture.as_os_str()],
|
|
||||||
&temp_root(entry.path, "check"),
|
|
||||||
);
|
|
||||||
assert_success_no_stderr(entry.path, "check", &check);
|
|
||||||
assert_stdout_eq(entry.path, "check", &check, "");
|
|
||||||
|
|
||||||
let list = run_glagol(
|
|
||||||
[
|
|
||||||
OsStr::new("test"),
|
|
||||||
OsStr::new("--list"),
|
|
||||||
fixture.as_os_str(),
|
|
||||||
],
|
|
||||||
&temp_root(entry.path, "list"),
|
|
||||||
);
|
|
||||||
assert_success_no_stderr(entry.path, "test --list", &list);
|
|
||||||
assert_stdout_contains(
|
|
||||||
entry.path,
|
|
||||||
"test --list",
|
|
||||||
&list,
|
|
||||||
&format!(
|
|
||||||
"{} test(s) selected (total_discovered {}, selected {}, passed 0, failed 0, skipped 0, filter none)",
|
|
||||||
entry.expected_tests, entry.expected_tests, entry.expected_tests
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if entry.run_tests {
|
|
||||||
let test = run_glagol(
|
|
||||||
[OsStr::new("test"), fixture.as_os_str()],
|
|
||||||
&temp_root(entry.path, "test"),
|
|
||||||
);
|
|
||||||
assert_success_no_stderr(entry.path, "test", &test);
|
|
||||||
assert_stdout_contains(
|
|
||||||
entry.path,
|
|
||||||
"test",
|
|
||||||
&test,
|
|
||||||
&format!("{} test(s) passed", entry.expected_tests),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_matrix_inventory() {
|
|
||||||
assert_eq!(MATRIX.len(), 43, "beta25 fixture-root count changed");
|
|
||||||
assert_eq!(
|
|
||||||
MATRIX
|
|
||||||
.iter()
|
|
||||||
.map(|entry| entry.expected_tests)
|
|
||||||
.sum::<usize>(),
|
|
||||||
655,
|
|
||||||
"beta25 discovered-test count changed"
|
|
||||||
);
|
|
||||||
|
|
||||||
let matrix_paths = MATRIX
|
|
||||||
.iter()
|
|
||||||
.map(|entry| entry.path.to_owned())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let mut sorted_matrix_paths = matrix_paths.clone();
|
|
||||||
sorted_matrix_paths.sort();
|
|
||||||
assert_eq!(
|
|
||||||
matrix_paths, sorted_matrix_paths,
|
|
||||||
"beta25 user-project conformance matrix must remain sorted by repository-relative path"
|
|
||||||
);
|
|
||||||
|
|
||||||
let discovered_paths = discover_fixture_paths(&repo_root());
|
|
||||||
assert_eq!(
|
|
||||||
discovered_paths, matrix_paths,
|
|
||||||
"beta25 user-project conformance matrix must cover every top-level example project and workspace fixture"
|
|
||||||
);
|
|
||||||
|
|
||||||
let inventory = MATRIX
|
|
||||||
.iter()
|
|
||||||
.map(|entry| {
|
|
||||||
format!(
|
|
||||||
"{}|tests={}|run_tests={}",
|
|
||||||
entry.path, entry.expected_tests, entry.run_tests
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
inventory,
|
|
||||||
concat!(
|
|
||||||
"examples/projects/basic|tests=2|run_tests=true\n",
|
|
||||||
"examples/projects/enum-imports|tests=9|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-cli|tests=17|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-env|tests=23|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-fs|tests=35|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-io|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-json|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-math|tests=4|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-net|tests=9|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-num|tests=5|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-option|tests=36|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-process|tests=21|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-random|tests=2|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-result|tests=26|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-string|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-time|tests=3|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-vec_bool|tests=19|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-vec_f64|tests=20|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-vec_i32|tests=22|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-vec_i64|tests=20|run_tests=true\n",
|
|
||||||
"examples/projects/std-import-vec_string|tests=19|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-cli|tests=17|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-env|tests=23|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-fs|tests=35|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-io|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-json|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-math|tests=7|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-net|tests=9|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-num|tests=5|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-option|tests=36|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-process|tests=21|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-random|tests=3|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-result|tests=26|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-string|tests=12|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-time|tests=3|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-vec_bool|tests=19|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-vec_f64|tests=20|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-vec_i32|tests=22|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-vec_i64|tests=20|run_tests=true\n",
|
|
||||||
"examples/projects/std-layout-local-vec_string|tests=19|run_tests=true\n",
|
|
||||||
"examples/projects/stdlib-composition|tests=3|run_tests=true\n",
|
|
||||||
"examples/workspaces/exp-5-local|tests=2|run_tests=true\n",
|
|
||||||
"examples/workspaces/std-import-option|tests=1|run_tests=true",
|
|
||||||
),
|
|
||||||
"beta25 user-project conformance matrix changed without updating the inventory assertion"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn discover_fixture_paths(repo_root: &Path) -> Vec<String> {
|
|
||||||
let mut paths = Vec::new();
|
|
||||||
for parent in ["examples/projects", "examples/workspaces"] {
|
|
||||||
let parent_path = repo_root.join(parent);
|
|
||||||
for entry in fs::read_dir(&parent_path).unwrap_or_else(|err| {
|
|
||||||
panic!(
|
|
||||||
"read fixture inventory `{}`: {}",
|
|
||||||
parent_path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}) {
|
|
||||||
let entry = entry.unwrap_or_else(|err| {
|
|
||||||
panic!(
|
|
||||||
"read fixture entry under `{}`: {}",
|
|
||||||
parent_path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
let path = entry.path();
|
|
||||||
if path.join("slovo.toml").is_file() {
|
|
||||||
paths.push(
|
|
||||||
path.strip_prefix(repo_root)
|
|
||||||
.expect("fixture path under repository root")
|
|
||||||
.to_string_lossy()
|
|
||||||
.replace('\\', "/"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paths.sort();
|
|
||||||
paths
|
|
||||||
}
|
|
||||||
|
|
||||||
fn repo_root() -> PathBuf {
|
|
||||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
||||||
.parent()
|
|
||||||
.expect("compiler crate has repository parent")
|
|
||||||
.to_path_buf()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_glagol<I, S>(args: I, cwd: &Path) -> Output
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
fs::create_dir_all(cwd).unwrap_or_else(|err| {
|
|
||||||
panic!("create command cwd `{}`: {}", cwd.display(), err);
|
|
||||||
});
|
|
||||||
let mut command = Command::new(env!("CARGO_BIN_EXE_glagol"));
|
|
||||||
configure_conformance_env(&mut command);
|
|
||||||
command
|
|
||||||
.args(args)
|
|
||||||
.current_dir(cwd)
|
|
||||||
.output()
|
|
||||||
.expect("run glagol")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_conformance_env(command: &mut Command) {
|
|
||||||
for key in [
|
|
||||||
"GLAGOL_STD_IMPORT_ENV_ALPHA_UNLIKELY_MISSING",
|
|
||||||
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_UNLIKELY_MISSING",
|
|
||||||
] {
|
|
||||||
command.env_remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (key, value) in [
|
|
||||||
(
|
|
||||||
"GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT",
|
|
||||||
"glagol-std-import-env-alpha-value",
|
|
||||||
),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_I32", "42"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_I64", "42000000000"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_U32", "42"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_U64", "4294967296"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_F64", "42.5"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_BOOL", "true"),
|
|
||||||
("GLAGOL_STD_IMPORT_ENV_ALPHA_INVALID", "not-a-number"),
|
|
||||||
(
|
|
||||||
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT",
|
|
||||||
"glagol-std-layout-local-env-alpha-value",
|
|
||||||
),
|
|
||||||
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_I32", "42"),
|
|
||||||
(
|
|
||||||
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_I64",
|
|
||||||
"42000000000",
|
|
||||||
),
|
|
||||||
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_U32", "42"),
|
|
||||||
(
|
|
||||||
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_U64",
|
|
||||||
"4294967296",
|
|
||||||
),
|
|
||||||
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_F64", "42.5"),
|
|
||||||
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_BOOL", "true"),
|
|
||||||
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_INVALID", "not-a-number"),
|
|
||||||
] {
|
|
||||||
command.env(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn temp_root(path: &str, command: &str) -> PathBuf {
|
|
||||||
let id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let nanos = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.expect("system clock before UNIX_EPOCH")
|
|
||||||
.as_nanos();
|
|
||||||
let fixture = path
|
|
||||||
.chars()
|
|
||||||
.map(|ch| if ch == '/' || ch == '-' { '_' } else { ch })
|
|
||||||
.collect::<String>();
|
|
||||||
std::env::temp_dir().join(format!(
|
|
||||||
"glagol-user-project-conformance-beta25-{}-{}-{}-{}-{}",
|
|
||||||
std::process::id(),
|
|
||||||
nanos,
|
|
||||||
id,
|
|
||||||
fixture,
|
|
||||||
command
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_success_no_stderr(fixture: &str, command: &str, output: &Output) {
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"{} `{}` failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
|
|
||||||
fixture,
|
|
||||||
command,
|
|
||||||
output.status.code(),
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
output.stderr.is_empty(),
|
|
||||||
"{} `{}` wrote stderr:\n{}",
|
|
||||||
fixture,
|
|
||||||
command,
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_stdout_eq(fixture: &str, command: &str, output: &Output, expected: &str) {
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
expected,
|
|
||||||
"{} `{}` stdout mismatch",
|
|
||||||
fixture,
|
|
||||||
command
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_stdout_contains(fixture: &str, command: &str, output: &Output, needle: &str) {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
assert!(
|
|
||||||
stdout.contains(needle),
|
|
||||||
"{} `{}` stdout did not contain `{}`:\n{}",
|
|
||||||
fixture,
|
|
||||||
command,
|
|
||||||
needle,
|
|
||||||
stdout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -41,30 +41,6 @@ Released in `1.0.0-beta.1`: `glagol run`, `glagol clean`,
|
|||||||
installed std/runtime discovery, README coverage, focused DX tests, and a
|
installed std/runtime discovery, README coverage, focused DX tests, and a
|
||||||
concise release-gate success line.
|
concise release-gate success line.
|
||||||
|
|
||||||
Released in `1.0.0-beta.19`: test discovery and user-project conformance
|
|
||||||
tooling. The scope adds the
|
|
||||||
`glagol test --list <file|project|workspace>` command and legacy
|
|
||||||
`glagol --run-tests --list <file>` so users and tooling can list
|
|
||||||
checked/discovered tests without executing test bodies. It preserves existing
|
|
||||||
single-file, project, and workspace ordering, honors
|
|
||||||
`--filter <substring>`, and keeps the output beta-scoped rather than a stable
|
|
||||||
public schema.
|
|
||||||
|
|
||||||
Beta19 non-scope: no parallel test execution, retries, tags/groups, coverage
|
|
||||||
reports, event streams, stable artifact-manifest or Markdown schema freeze,
|
|
||||||
LSP/watch behavior, SARIF/daemon protocols, JSON expansion, runtime helper
|
|
||||||
names, source-language syntax, package registries, semver solving, or
|
|
||||||
performance claims.
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.25`: user-project conformance matrix evidence. The
|
|
||||||
scope adds a deterministic matrix over the existing `examples/projects/` and
|
|
||||||
`examples/workspaces/` inventories so ordinary project and workspace usage has
|
|
||||||
stable-readiness evidence across all 43 top-level fixture roots and 655
|
|
||||||
discovered tests. It is tooling/conformance evidence only: no
|
|
||||||
source-language change, standard-library helper change, runtime behavior
|
|
||||||
change, package manager or registry behavior, lockfile behavior,
|
|
||||||
semantic-version solving, stable schema freeze, or performance claim.
|
|
||||||
|
|
||||||
Why first: it reduces friction for every later feature and gives users a better
|
Why first: it reduces friction for every later feature and gives users a better
|
||||||
way to exercise the beta.
|
way to exercise the beta.
|
||||||
|
|
||||||
@ -117,29 +93,6 @@ generated from `lib/std/*.slo` and guarded by `scripts/release-gate.sh`.
|
|||||||
that composes `std.fs`, `std.string`, `std.math`, and `std.io` through explicit
|
that composes `std.fs`, `std.string`, `std.math`, and `std.io` through explicit
|
||||||
standard imports, with focused check/test/doc/run coverage.
|
standard imports, with focused check/test/doc/run coverage.
|
||||||
|
|
||||||
Released in `1.0.0-beta.20`: source-authored `std.string` search and ASCII
|
|
||||||
trim helpers. The scope adds `contains`, `index_of_option`,
|
|
||||||
`last_index_of_option`, `trim_ascii_start`, `trim_ascii_end`, and
|
|
||||||
`trim_ascii` over existing byte-oriented string primitives, with explicit
|
|
||||||
`std.string` import examples and focused compiler gates. Empty needles match
|
|
||||||
at first index `0` and last index `(len value)`; ASCII trimming removes only
|
|
||||||
bytes `9`, `10`, `11`, `12`, `13`, and `32`. Unicode/grapheme semantics,
|
|
||||||
case folding, regexes, tokenizers, mutable strings, slice/view syntax, new
|
|
||||||
runtime names, and stable stdlib/API promises remain deferred.
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.23`: the public
|
|
||||||
[`docs/language/STDLIB_TIERS.md`](language/STDLIB_TIERS.md) ledger defines the
|
|
||||||
current standard-library tier labels `beta-supported`, `experimental`, and
|
|
||||||
`internal`, and aligns the docs around the generated
|
|
||||||
[`docs/language/STDLIB_API.md`](language/STDLIB_API.md) signature catalog.
|
|
||||||
JSON, loopback networking, random/time, and filesystem resource-handle helpers
|
|
||||||
are documented as experimental domains. Concrete vector modules remain
|
|
||||||
beta-supported concrete lanes, not a generic collections freeze. The slice is
|
|
||||||
documentation/catalog tooling clarity only: no syntax, helper, runtime,
|
|
||||||
manifest-schema, Markdown-schema, ABI/layout, or stable stdlib/API behavior
|
|
||||||
changes. It updates generated catalog output and the release gate so tier
|
|
||||||
metadata is visible and checked.
|
|
||||||
|
|
||||||
Why third: stdlib growth is already broad enough that naming and stability tiers
|
Why third: stdlib growth is already broad enough that naming and stability tiers
|
||||||
matter more than adding another isolated helper group.
|
matter more than adding another isolated helper group.
|
||||||
|
|
||||||
@ -191,14 +144,6 @@ local-package rules. Lockfiles, remote registries, semver solving, publishing,
|
|||||||
optional/dev/target dependencies, and stable package ABI/layout remain out of
|
optional/dev/target dependencies, and stable package ABI/layout remain out of
|
||||||
scope.
|
scope.
|
||||||
|
|
||||||
Released in `1.0.0-beta.24`: package manifest identity and dependency
|
|
||||||
diagnostics are tightened without changing the package model. Duplicate
|
|
||||||
package manifest keys, invalid dependency keys, and duplicate dependency keys
|
|
||||||
are explicit diagnostics. The slice adds no remote registry, lockfile,
|
|
||||||
semantic-version solving, package publishing, optional/dev/target
|
|
||||||
dependencies, stable package ABI/layout, source-language change, runtime
|
|
||||||
change, or standard-library change.
|
|
||||||
|
|
||||||
Why fifth: stable package rules are a prerequisite for a usable public language,
|
Why fifth: stable package rules are a prerequisite for a usable public language,
|
||||||
but remote publishing can wait.
|
but remote publishing can wait.
|
||||||
|
|
||||||
@ -243,32 +188,11 @@ Released in `1.0.0-beta.7`: `lib/std/json.slo` now provides explicit helpers
|
|||||||
for compact JSON text construction over strings, booleans, numbers, null,
|
for compact JSON text construction over strings, booleans, numbers, null,
|
||||||
fields, small arrays, and small objects. `std.json.quote_string` is a
|
fields, small arrays, and small objects. `std.json.quote_string` is a
|
||||||
compiler-known runtime helper so JSON string escaping is correct before Slovo
|
compiler-known runtime helper so JSON string escaping is correct before Slovo
|
||||||
has later byte-oriented string scanning helpers. Matching explicit
|
has source-level byte/character scanning and slicing. Matching explicit
|
||||||
std/local source fixtures and a `json-quote-loop` benchmark scaffold are in
|
std/local source fixtures and a `json-quote-loop` benchmark scaffold are in
|
||||||
place.
|
place. JSON parsing, recursive JSON values, maps/sets, generic collections,
|
||||||
|
streaming encoders, schema validation, Unicode normalization, and stable text
|
||||||
Released in `1.0.0-beta.17`: `lib/std/json.slo` now provides primitive scalar
|
encoding policy beyond the current runtime string ABI remain deferred.
|
||||||
JSON token parse facades for booleans, concrete numeric primitives, and exact
|
|
||||||
`null`. Broader JSON parsing beyond primitive scalar tokens remained deferred
|
|
||||||
for the next slices.
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.18`: `lib/std/json.slo` adds
|
|
||||||
`parse_string_value_result` for one already-isolated ASCII JSON string token.
|
|
||||||
It requires exact quotes, rejects leading/trailing whitespace, decodes the
|
|
||||||
simple JSON escapes `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, and `\t`, and
|
|
||||||
returns `err 1` for ordinary parse failure. Full JSON document parsing,
|
|
||||||
object/array parsing, tokenizer objects, Unicode escape decoding or
|
|
||||||
normalization, embedded NUL policy, streaming, schema validation, and stable
|
|
||||||
ABI/API guarantees remain deferred.
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.21`: `lib/std/json.slo` adds source-authored scalar
|
|
||||||
document parse facades for string, bool, `i32`, `u32`, `i64`, `u64`, `f64`,
|
|
||||||
and exact `null`. Each helper trims ASCII whitespace around the whole document
|
|
||||||
with `std.string.trim_ascii`, then delegates to the already released exact
|
|
||||||
value-token parser. This intentionally remains scalar document parsing only:
|
|
||||||
object/array parsing, recursive JSON values, parser/tokenizer objects,
|
|
||||||
maps/sets, streaming, new compiler-known runtime names, broader Unicode escape
|
|
||||||
policy, embedded NUL policy, and stable ABI/API guarantees remain deferred.
|
|
||||||
|
|
||||||
Why seventh: networking and CLI tools need data interchange, but a complete JSON
|
Why seventh: networking and CLI tools need data interchange, but a complete JSON
|
||||||
library depends on collection work.
|
library depends on collection work.
|
||||||
@ -346,6 +270,7 @@ Work:
|
|||||||
- language-server diagnostics and document symbols
|
- language-server diagnostics and document symbols
|
||||||
- editor-facing symbol metadata for files, projects, and workspaces
|
- editor-facing symbol metadata for files, projects, and workspaces
|
||||||
- project watch mode
|
- project watch mode
|
||||||
|
- generated API documentation for local packages
|
||||||
- clearer benchmark harness output
|
- clearer benchmark harness output
|
||||||
- machine-readable diagnostics stability policy
|
- machine-readable diagnostics stability policy
|
||||||
|
|
||||||
@ -356,232 +281,23 @@ public types. `glagol symbols <file.slo|project|workspace>` now emits
|
|||||||
deterministic `slovo.symbols` metadata for editor integrations without
|
deterministic `slovo.symbols` metadata for editor integrations without
|
||||||
starting an LSP server. This is beta API discovery only; it does not add
|
starting an LSP server. This is beta API discovery only; it does not add
|
||||||
executable generics, maps, sets, runtime changes, or a stable standard-library
|
executable generics, maps, sets, runtime changes, or a stable standard-library
|
||||||
API freeze. LSP, watch mode, benchmark-output work, stable Markdown schema,
|
API freeze. LSP, watch mode, local-package API docs, benchmark-output work,
|
||||||
stable stdlib/API compatibility freeze, SARIF/daemon protocols, and a
|
and a machine-readable diagnostics stability policy remain deferred.
|
||||||
machine-readable diagnostics stability policy remain deferred.
|
|
||||||
|
|
||||||
Why tenth: editor support matters, but it should follow a stable enough syntax,
|
Why tenth: editor support matters, but it should follow a stable enough syntax,
|
||||||
project model, and diagnostic model.
|
project model, and diagnostic model.
|
||||||
|
|
||||||
### 11. Local Package API Documentation
|
|
||||||
|
|
||||||
Goal: extend beta API discovery from `lib/std` and symbol metadata to the
|
|
||||||
local packages and modules users document with `glagol doc`.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- make `glagol doc <file|project|workspace> -o <dir>` include deterministic
|
|
||||||
exported/public API sections for local packages and modules
|
|
||||||
- list exact exported function signatures
|
|
||||||
- list exported struct fields
|
|
||||||
- list exported enum variants and payload types
|
|
||||||
- keep non-exported functions, structs, enums, tests, and aliases out of the
|
|
||||||
public API sections
|
|
||||||
- normalize module-local concrete aliases in public docs so local alias names
|
|
||||||
do not leak across module/package boundaries
|
|
||||||
- keep Markdown layout and generated file names beta-scoped rather than stable
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.11`: local file, project, package, and workspace docs
|
|
||||||
generated by `glagol doc <file|project|workspace> -o <dir>` include
|
|
||||||
deterministic public API sections with exact exported function signatures,
|
|
||||||
exported struct fields, exported enum variants/payload types, non-export
|
|
||||||
filtering, and module-local alias normalization. This extends beta10 API
|
|
||||||
discovery only; it does not freeze the Markdown schema, create a stable
|
|
||||||
stdlib/API compatibility freeze, add LSP/watch, define SARIF/daemon protocols,
|
|
||||||
set a diagnostics schema policy, implement executable generics/maps/sets, add
|
|
||||||
re-exports/globs/hierarchical modules, or define registry semantics.
|
|
||||||
|
|
||||||
Why eleventh: local packages are useful only if their public surface can be
|
|
||||||
reviewed without reading every source file, but the documentation format
|
|
||||||
should remain flexible until the package and editor stories are stronger.
|
|
||||||
|
|
||||||
### 12. Concrete Vector Query And Prefix Parity
|
|
||||||
|
|
||||||
Goal: close small source-authored helper gaps in the current concrete vector
|
|
||||||
facades before returning to larger language and tooling slices.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- add `count_of`, `starts_with`, `without_prefix`, `ends_with`, and
|
|
||||||
`without_suffix` to `std.vec_i64`
|
|
||||||
- add `count_of` to `std.vec_f64`
|
|
||||||
- keep all helpers source-authored over the already promoted concrete vector
|
|
||||||
runtime names, equality, `len`, `at`, `take`, `drop`, and recursive helper
|
|
||||||
style
|
|
||||||
- add explicit local helper project coverage for repeated count results and
|
|
||||||
prefix/suffix empty, mismatch, exact, and longer-than-input cases where
|
|
||||||
applicable
|
|
||||||
- document the slice as helper parity only, not a language/runtime change
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.12`: `std.vec_i64` gains `count_of`, `starts_with`,
|
|
||||||
`without_prefix`, `ends_with`, and `without_suffix`; `std.vec_f64` gains
|
|
||||||
`count_of`; and focused Glagol fixture tests require the corresponding explicit
|
|
||||||
source-helper coverage. The release does not add generics, maps/sets,
|
|
||||||
iterators, mutable vectors, slice/view APIs, new runtime names, ABI/layout
|
|
||||||
stability, performance claims, or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
Why twelfth: concrete vectors are already broad enough that parity gaps create
|
|
||||||
surprising differences, and source-authored helpers can close those gaps
|
|
||||||
without committing to generic collection design.
|
|
||||||
|
|
||||||
### 13. Diagnostic Catalog And Schema Policy
|
|
||||||
|
|
||||||
Goal: document the existing diagnostic machine contract before larger tooling
|
|
||||||
or editor-facing slices depend on it.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- add [`docs/language/DIAGNOSTICS.md`](language/DIAGNOSTICS.md) as the beta
|
|
||||||
`slovo.diagnostic` version `1` policy
|
|
||||||
- document the S-expression and JSON encodings, required and optional fields,
|
|
||||||
severity/source/range/related-span semantics, JSON-line discipline,
|
|
||||||
source-less diagnostics, and artifact-manifest diagnostic metadata
|
|
||||||
- classify diagnostic changes as clarifying, additive, or migration-level,
|
|
||||||
with human prose remaining beta-flexible unless machine fields, schema
|
|
||||||
markers, codes, or golden fixture shape change intentionally
|
|
||||||
- inventory the current diagnostic codes covered by
|
|
||||||
`compiler/tests/diagnostics_contract.rs` and the matching `.diag` snapshots
|
|
||||||
- keep LSP/watch, SARIF, daemon protocols, stable Markdown schema, stable
|
|
||||||
`1.0.0` diagnostics freeze, and runtime/source-language changes out of scope
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.13`:
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](language/DIAGNOSTICS.md) now defines the beta
|
|
||||||
diagnostic schema policy and catalogs the current golden diagnostic codes. The
|
|
||||||
release is documentation/tooling policy only; it does not change Glagol
|
|
||||||
diagnostic output, the source language, runtime, stdlib/API surface, or
|
|
||||||
ABI/layout behavior.
|
|
||||||
|
|
||||||
Why thirteenth: diagnostics already have a machine schema and broad golden
|
|
||||||
coverage, but the compatibility policy and current code inventory need one
|
|
||||||
central reference before future tooling or migration work builds on them.
|
|
||||||
|
|
||||||
### 14. Benchmark Suite Catalog And Metadata Gate
|
|
||||||
|
|
||||||
Goal: document the existing benchmark suite inventory and metadata listing
|
|
||||||
commands before benchmark tooling grows additional consumers.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- add [`benchmarks/README.md`](../benchmarks/README.md) as the top-level
|
|
||||||
benchmark suite catalog
|
|
||||||
- document `python3 benchmarks/runner.py --suite-list` for the non-JSON suite
|
|
||||||
inventory
|
|
||||||
- document `python3 benchmarks/runner.py --suite-list --json` for beta tooling
|
|
||||||
metadata
|
|
||||||
- list the current suite inventory without adding new benchmark kernels
|
|
||||||
- state that benchmark timings are local-machine evidence only
|
|
||||||
- keep suite-list JSON beta-scoped rather than a stable public schema
|
|
||||||
- keep timing publication, performance thresholds, source-language/runtime/
|
|
||||||
stdlib/API/diagnostic-output changes, and ABI/layout changes out of scope
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.14`:
|
|
||||||
[`benchmarks/README.md`](../benchmarks/README.md) now catalogs the current
|
|
||||||
benchmark suite, documents the root suite-list commands, records local-machine
|
|
||||||
evidence policy, and names the explicit exclusions. The release is
|
|
||||||
documentation/tooling metadata only; it does not add kernels, publish timing
|
|
||||||
numbers, define performance thresholds, define a stable JSON schema, or change
|
|
||||||
the source language, runtime, stdlib/API surface, diagnostics, or ABI/layout
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
Why fourteenth: the benchmark suite is already part of the public monorepo, but
|
|
||||||
its suite-level inventory and metadata boundary need one central reference
|
|
||||||
before future tooling can rely on it.
|
|
||||||
|
|
||||||
### 15. Reserved Generic Collection Boundary Hardening And Collection Ledger
|
|
||||||
|
|
||||||
Goal: document the current concrete collection and value-family boundary before
|
|
||||||
executable generics, maps, sets, iterators, mutable vectors, or slice/view APIs
|
|
||||||
are designed as executable features.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- add [`docs/language/COLLECTIONS.md`](language/COLLECTIONS.md) as the
|
|
||||||
collection/value-family ledger
|
|
||||||
- link to the generated [`docs/language/STDLIB_API.md`](language/STDLIB_API.md)
|
|
||||||
catalog for exact public helper signatures instead of duplicating generated
|
|
||||||
counts
|
|
||||||
- inventory the current concrete vector, option, result, and related
|
|
||||||
option/result-returning facade surfaces
|
|
||||||
- record design pressure from duplicated concrete vector, option, and result
|
|
||||||
helper families
|
|
||||||
- define prerequisites before executable generics, generic aliases, maps,
|
|
||||||
sets, iterators, mutable vectors, or slice/view APIs can be promoted
|
|
||||||
- state that current unsupported diagnostics are boundaries, not behavior
|
|
||||||
changes
|
|
||||||
- centralize reserved generic/map/set diagnostics and reword affected
|
|
||||||
reserved-boundary messages from beta.9-specific text to current-beta wording
|
|
||||||
- keep source-language/runtime/stdlib/API changes, diagnostic output shape/
|
|
||||||
code/schema/span/expected/found/hint changes, benchmark metadata schema
|
|
||||||
changes, ABI/layout changes, performance claims, and stable API freeze out
|
|
||||||
of scope
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.15`:
|
|
||||||
[`docs/language/COLLECTIONS.md`](language/COLLECTIONS.md) now records the
|
|
||||||
collection/value-family ledger and links to the generated standard-library API
|
|
||||||
catalog for exact signatures. The release also centralizes reserved
|
|
||||||
generic/map/set diagnostics and rewords affected reserved-boundary messages
|
|
||||||
away from beta.9-specific text. It does not change the source language,
|
|
||||||
runtime, stdlib/API surface, diagnostic output shape, diagnostic codes,
|
|
||||||
diagnostic schema, spans, expected/found values, hints, benchmark metadata
|
|
||||||
schema, ABI/layout behavior, or performance claims, and it does not create a
|
|
||||||
stable stdlib/API freeze.
|
|
||||||
|
|
||||||
Why fifteenth: the concrete vector, option, and result facades have enough
|
|
||||||
duplication to justify generic collection planning, but the public contract
|
|
||||||
needs an explicit boundary ledger before executable generic, map, set,
|
|
||||||
iterator, mutable-vector, or slice/view semantics are promoted.
|
|
||||||
|
|
||||||
### 16. String Scanning And Token Boundary Foundation
|
|
||||||
|
|
||||||
Goal: add the first byte-oriented string scanning and token-boundary helpers
|
|
||||||
without promoting Unicode/grapheme semantics, full JSON parsing, or language
|
|
||||||
slice/view syntax.
|
|
||||||
|
|
||||||
Work:
|
|
||||||
|
|
||||||
- add `byte_at_result`, `slice_result`, `starts_with`, and `ends_with` to
|
|
||||||
`lib/std/string.slo`
|
|
||||||
- mirror those source facades in the explicit local `std-layout-local-string`
|
|
||||||
fixture
|
|
||||||
- cover both local and explicit `std.string` imports with examples for success
|
|
||||||
and ordinary failure cases
|
|
||||||
- document byte-oriented behavior over current NUL-terminated runtime strings
|
|
||||||
- require invalid indexes and ranges to return `err 1`
|
|
||||||
- keep allocation failure on substring creation aligned with the existing
|
|
||||||
string allocation trap policy
|
|
||||||
- keep Unicode scalar/grapheme/display-width semantics, full JSON parsing,
|
|
||||||
object/array parsing, tokenizer objects, language slice/view features,
|
|
||||||
mutable strings, stable ABI/layout, and stable API freeze out of scope
|
|
||||||
|
|
||||||
Released in `1.0.0-beta.16`: `std.string` now exposes source facades and
|
|
||||||
examples for byte access, substring extraction, and prefix/suffix checks:
|
|
||||||
`byte_at_result`, `slice_result`, `starts_with`, and `ends_with`. The release is
|
|
||||||
byte-oriented over the current runtime string representation and uses `err 1`
|
|
||||||
for ordinary invalid indexes/ranges. It does not add Unicode/grapheme
|
|
||||||
semantics, full JSON parsing, object/array parsing, tokenizer objects,
|
|
||||||
language slice/view features, mutable strings, stable ABI/layout, or a stable
|
|
||||||
stdlib/API freeze.
|
|
||||||
|
|
||||||
Why sixteenth: JSON text construction and process/file/network helpers can
|
|
||||||
produce useful strings, but parsers and tokenizers need a smaller byte-boundary
|
|
||||||
foundation before richer string or data-interchange APIs are credible.
|
|
||||||
|
|
||||||
## Stable `1.0.0` Gate
|
## Stable `1.0.0` Gate
|
||||||
|
|
||||||
Slovo should not become stable until all of these are true:
|
Slovo should not become stable until all of these are true:
|
||||||
|
|
||||||
- migration and deprecation policy is documented
|
- migration and deprecation policy is documented
|
||||||
- `lib/std` has explicit beta-supported, experimental, and internal tiers plus
|
- `lib/std` has explicit stable and experimental tiers
|
||||||
a later stable-tier/deprecation policy before `1.0.0`
|
|
||||||
- package/workspace behavior is deterministic
|
- package/workspace behavior is deterministic
|
||||||
- package manifest identity and dependency-key failures have explicit
|
- conformance tests cover user-shaped projects
|
||||||
diagnostics
|
|
||||||
- conformance tests and matrix evidence cover user-shaped projects and
|
|
||||||
workspaces
|
|
||||||
- release gates are reproducible on a clean checkout
|
- release gates are reproducible on a clean checkout
|
||||||
- diagnostics and formatter output are stable for promoted features
|
- diagnostics and formatter output are stable for promoted features
|
||||||
- performance publications are repeatable and labeled as local-machine evidence
|
- performance publications are repeatable and labeled as local-machine evidence
|
||||||
- benchmark metadata promoted to stable, if any, has an explicit schema policy
|
|
||||||
- the language can build useful local CLI tools, libraries, file-processing
|
- the language can build useful local CLI tools, libraries, file-processing
|
||||||
programs, and basic host-interaction programs without undocumented behavior
|
programs, and basic host-interaction programs without undocumented behavior
|
||||||
|
|
||||||
@ -596,9 +312,5 @@ complete first:
|
|||||||
- macro system
|
- macro system
|
||||||
- stable C ABI/layout guarantees
|
- stable C ABI/layout guarantees
|
||||||
- optimizing compiler claims
|
- optimizing compiler claims
|
||||||
- mutable vectors, slice/view APIs, iterators, maps, sets, and executable
|
|
||||||
generics
|
|
||||||
- new runtime helper names or generic stdlib dispatch before an explicit
|
|
||||||
runtime/language slice
|
|
||||||
- web framework or HTTP server framework
|
- web framework or HTTP server framework
|
||||||
- broad Unicode/string normalization policy
|
- broad Unicode/string normalization policy
|
||||||
|
|||||||
@ -10,507 +10,10 @@ integration/readiness release, not the first real beta.
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
No active unreleased compiler scope is documented here yet.
|
Next scoped Glagol work is expected to continue after the `1.0.0-beta.10`
|
||||||
|
developer-experience API discovery and symbol-metadata update.
|
||||||
|
|
||||||
## 1.0.0-beta.25
|
No unreleased compiler scope is committed here yet.
|
||||||
|
|
||||||
Release label: `1.0.0-beta.25`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: user-project conformance matrix evidence
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.25 compiler/tooling slice adds deterministic stable-readiness
|
|
||||||
evidence for ordinary project and workspace usage without changing the
|
|
||||||
language, runtime, stdlib, or package manager model:
|
|
||||||
|
|
||||||
- Add a user-project conformance matrix over all 43 top-level fixture roots
|
|
||||||
under existing `examples/projects/` and `examples/workspaces/`, covering
|
|
||||||
655 discovered tests.
|
|
||||||
- Keep matrix inputs repository-local and deterministically sorted by
|
|
||||||
repository-relative path.
|
|
||||||
- Record ordinary `check`, `test --list`, and stable `test` behavior for each
|
|
||||||
existing example in the matrix.
|
|
||||||
- Treat matrix output as beta tooling evidence rather than a stable public
|
|
||||||
schema.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement source-language change, standard-library
|
|
||||||
helper change, runtime behavior change, compiler-known `std.*` runtime names,
|
|
||||||
package manager behavior, remote registries, lockfiles, semantic-version
|
|
||||||
solving, package publishing, optional/dev/target dependencies, stable
|
|
||||||
artifact-manifest schema guarantees, stable Markdown schemas, stable
|
|
||||||
conformance-matrix schema guarantees, LSP/watch/SARIF/daemon protocols, stable
|
|
||||||
ABI/layout, or performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.24
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.24`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: package manifest identity and local dependency diagnostic
|
|
||||||
hardening
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.24 compiler/tooling slice tightens local package manifest diagnostics
|
|
||||||
without changing the language, runtime, stdlib, or package graph model:
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.24`.
|
|
||||||
- Diagnose duplicate package manifest keys explicitly.
|
|
||||||
- Diagnose invalid dependency keys explicitly.
|
|
||||||
- Diagnose duplicate dependency keys explicitly.
|
|
||||||
- Keep dependency records local-path-only and require dependency keys to match
|
|
||||||
target package names.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement remote registries, lockfiles,
|
|
||||||
semantic-version solving, package publishing, optional/dev/target
|
|
||||||
dependencies, feature flags, build scripts, package archives, stable package
|
|
||||||
ABI/layout, source-language syntax, runtime C capabilities, standard-library
|
|
||||||
helpers, compiler-known `std.*` runtime names, stable artifact-manifest schema
|
|
||||||
guarantees, stable Markdown schemas, LSP/watch/SARIF/daemon protocols, or
|
|
||||||
performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.23
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.23`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: standard-library stability tier ledger and catalog alignment
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.23 compiler/tooling slice aligns generated standard-library API
|
|
||||||
catalog output with the public tier ledger:
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.23`.
|
|
||||||
- Render per-module and per-helper `beta-supported` or `experimental` tier
|
|
||||||
metadata in `docs/language/STDLIB_API.md`.
|
|
||||||
- Add `scripts/check-stdlib-api-tiers.js` and wire it into the release gate.
|
|
||||||
- Mark JSON, loopback networking, random/time, and filesystem resource-handle
|
|
||||||
helpers as experimental in generated catalog output.
|
|
||||||
- Keep concrete vector modules beta-supported concrete lanes with an explicit
|
|
||||||
no-generic-collection-freeze note.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement source-language syntax, standard-library
|
|
||||||
helpers, compiler-known `std.*` runtime names, runtime C capabilities, package
|
|
||||||
or workspace behavior, stable artifact-manifest schema guarantees, stable
|
|
||||||
Markdown schemas, LSP/watch/SARIF/daemon protocols, performance claims,
|
|
||||||
stable ABI/layout, or a stable standard-library compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.22
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.22`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: run manifest and execution report hardening
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.22 compiler/tooling slice hardens `glagol run --manifest` evidence
|
|
||||||
without changing the Slovo language or standard-library surface:
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.22`.
|
|
||||||
- Add an additive run-report block to run-mode artifact manifests.
|
|
||||||
- Record executed-program exit status, captured stdout, captured stderr, and
|
|
||||||
forwarded program arguments.
|
|
||||||
- Keep the run report as beta tooling metadata under the existing
|
|
||||||
`slovo.artifact-manifest` version `1` contract rather than a stable schema
|
|
||||||
freeze.
|
|
||||||
- Keep non-run modes outside this run-report requirement.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement source-language syntax, standard-library
|
|
||||||
helpers, compiler-known `std.*` runtime names, runtime C capabilities, package
|
|
||||||
or workspace behavior, stable artifact-manifest schema guarantees, stable
|
|
||||||
Markdown schemas, LSP/watch/SARIF/daemon protocols, performance claims,
|
|
||||||
stable ABI/layout, or a stable standard-library compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.21
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.21`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: JSON document scalar parsing foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.21 compiler/tooling slice adds focused coverage for source-authored
|
|
||||||
`std.json` document-scalar helpers without adding compiler-known runtime names:
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.21`.
|
|
||||||
- Add focused `standard_json_document_scalar_parsing_beta21` coverage for
|
|
||||||
explicit `std.json` imports of `parse_string_document_result`,
|
|
||||||
`parse_bool_document_result`, `parse_i32_document_result`,
|
|
||||||
`parse_u32_document_result`, `parse_i64_document_result`,
|
|
||||||
`parse_u64_document_result`, `parse_f64_document_result`, and
|
|
||||||
`parse_null_document_result`.
|
|
||||||
- Gate the helpers as source-authored public facades over existing JSON token
|
|
||||||
parsers and source-level document trimming/composition.
|
|
||||||
- Require direct `std.json.parse_*_document_result` runtime calls and private
|
|
||||||
`__glagol_json_*document*` runtime symbols to remain unsupported.
|
|
||||||
- Add the focused beta21 test to `scripts/release-gate.sh`.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement object parsing, array parsing, recursive JSON
|
|
||||||
values, tokenizers, Unicode escape decoding, streaming, schema validation,
|
|
||||||
stable parser APIs, new compiler-known `std.*` runtime names, runtime C
|
|
||||||
changes, source-language syntax, stable ABI/layout, or a stable
|
|
||||||
standard-library compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.20
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.20`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: string search and ASCII trim foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.20 compiler/tooling slice adds focused coverage for source-authored
|
|
||||||
`std.string` search and ASCII trim helpers without adding compiler-known
|
|
||||||
runtime names:
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.20`.
|
|
||||||
- Add focused `standard_string_search_trim_beta20` coverage for explicit
|
|
||||||
`std.string` imports of `contains`, `index_of_option`,
|
|
||||||
`last_index_of_option`, `trim_ascii_start`, `trim_ascii_end`, and
|
|
||||||
`trim_ascii`.
|
|
||||||
- Require the new public helpers to remain source facades over beta16-or-earlier
|
|
||||||
string primitives and existing result/option shapes.
|
|
||||||
- Gate direct `std.string.contains`, `std.string.index_of_option`,
|
|
||||||
`std.string.last_index_of_option`, `std.string.trim_ascii_start`,
|
|
||||||
`std.string.trim_ascii_end`, and `std.string.trim_ascii` runtime calls as
|
|
||||||
unsupported compiler-known names.
|
|
||||||
- Add the focused beta20 test to `scripts/release-gate.sh`.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement new compiler-known `std.*` runtime names,
|
|
||||||
runtime C changes, source-language syntax, Unicode or grapheme semantics,
|
|
||||||
locale/case-folded search, regex, tokenizer/parser APIs, stable string
|
|
||||||
ABI/layout, stable allocation ownership rules, or a stable standard-library
|
|
||||||
compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.19
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.19`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: test discovery and user-project conformance foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.19 compiler/tooling contract adds deterministic list-only test
|
|
||||||
discovery without changing normal test execution output:
|
|
||||||
|
|
||||||
- `glagol test --list <file|project|workspace>`
|
|
||||||
- `glagol --run-tests --list <file>` for legacy single-file test execution
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.19`.
|
|
||||||
- Reuse the same checked discovery path as normal `glagol test` for file,
|
|
||||||
project, and workspace inputs.
|
|
||||||
- Preserve current file/project/workspace test ordering.
|
|
||||||
- Honor `--filter <substring>` by marking selected and skipped discovered
|
|
||||||
tests without executing test bodies or triggering runtime/test side effects.
|
|
||||||
- Keep normal `glagol test` and legacy `glagol --run-tests` output unchanged
|
|
||||||
when `--list` is absent.
|
|
||||||
- Add focused beta19 release-gate coverage for test discovery.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement parallel test execution, retries, tags/groups, coverage,
|
|
||||||
event streams, stable artifact-manifest or Markdown schema freezes,
|
|
||||||
LSP/watch/SARIF/daemon protocols, JSON expansion, runtime helper names,
|
|
||||||
source-language syntax, package registries, semver solving, and performance
|
|
||||||
claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.18
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.18`
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Release state: JSON string token parsing foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.18 compiler/runtime contract promotes a narrow JSON string-token
|
|
||||||
parser without claiming a full JSON parser or Unicode escape policy.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.18`.
|
|
||||||
- Add the promoted compiler-known runtime name
|
|
||||||
`std.json.parse_string_value_result`.
|
|
||||||
- Lower the helper through the existing nullable string result ABI shape:
|
|
||||||
hosted C returns an allocated decoded string on success and `NULL` for
|
|
||||||
ordinary `err 1` parse failure.
|
|
||||||
- Enforce one-token ASCII JSON string checks: exact surrounding quotes, no
|
|
||||||
leading/trailing whitespace, no raw control bytes, no raw non-ASCII bytes,
|
|
||||||
no raw quotes/backslashes, and no trailing bytes.
|
|
||||||
- Decode simple JSON escapes `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, and
|
|
||||||
`\t`; reject all `\uXXXX` escapes for this beta slice.
|
|
||||||
- Run `glagol test` execution on a bounded larger worker stack so deep
|
|
||||||
source-authored stdlib fixture tests fail through normal test diagnostics
|
|
||||||
instead of host process stack overflow.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement JSON object parsing, array parsing, recursive
|
|
||||||
JSON values, tokenizers, Unicode escape decoding, Unicode normalization,
|
|
||||||
embedded NUL support in the current null-terminated string ABI, streaming,
|
|
||||||
schema validation, stable runtime helper symbols, stable ABI/layout, or a
|
|
||||||
stable standard-library compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.17
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.17`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: JSON primitive scalar parsing foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.17 compiler/runtime contract promotes strict JSON primitive scalar
|
|
||||||
token parsers for booleans and concrete numeric primitives without claiming a
|
|
||||||
full JSON parser.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.17`.
|
|
||||||
- Add promoted compiler-known runtime names for
|
|
||||||
`std.json.parse_bool_value_result`, `std.json.parse_i32_value_result`,
|
|
||||||
`std.json.parse_u32_value_result`, `std.json.parse_i64_value_result`,
|
|
||||||
`std.json.parse_u64_value_result`, and
|
|
||||||
`std.json.parse_f64_value_result`.
|
|
||||||
- Lower the helpers through the existing concrete result ABI shapes and add
|
|
||||||
hosted C runtime implementations plus matching test-runner behavior.
|
|
||||||
- Enforce whole-token JSON scalar checks: no leading/trailing whitespace, no
|
|
||||||
leading `+`, no leading-zero integer form except `0`, and no non-finite f64
|
|
||||||
values.
|
|
||||||
- Keep `std.json.parse_null_value_result` source-only and gate deferred JSON
|
|
||||||
string/object/array/value parser families as unsupported.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement JSON string parsing, object parsing, array
|
|
||||||
parsing, recursive JSON values, tokenizers, generic parse APIs,
|
|
||||||
whitespace-tolerant document parsing, streaming, schema validation, Unicode
|
|
||||||
escape handling, stable runtime helper symbols, stable ABI/layout, or a stable
|
|
||||||
standard-library compatibility contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.16
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.16`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: string scanning and token-boundary runtime foundation
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.16 compiler/runtime contract promotes a byte-oriented string
|
|
||||||
scanning foundation for source-authored stdlib wrappers without claiming
|
|
||||||
Unicode, grapheme, tokenizer, parser, or stable ABI behavior.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.16`.
|
|
||||||
- Add promoted compiler-known runtime names for `std.string.byte_at_result`,
|
|
||||||
`std.string.slice_result`, `std.string.starts_with`, and
|
|
||||||
`std.string.ends_with`.
|
|
||||||
- Lower `byte_at_result` through the existing encoded `result i32 i32` shape
|
|
||||||
and `slice_result` through the existing nullable string-result host-call
|
|
||||||
shape. Invalid indexes or ranges return `err 1`; slice allocation failure
|
|
||||||
follows the existing string allocation trap.
|
|
||||||
- Add hosted C runtime implementations over current null-terminated runtime
|
|
||||||
strings and matching test-runner behavior for deterministic Slovo tests.
|
|
||||||
- Extend diagnostics, facade project checks, and release-gate coverage for
|
|
||||||
the beta16 string-scanning boundary while keeping richer scanning and token
|
|
||||||
APIs unsupported.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement Unicode or grapheme semantics, a JSON parser,
|
|
||||||
tokenizers, split/find/contains helpers, stable string ABI/layout, stable
|
|
||||||
allocation ownership rules, or a stable standard-library compatibility
|
|
||||||
contract.
|
|
||||||
|
|
||||||
## 1.0.0-beta.15
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.15`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: reserved generic collection boundary hardening and collection ledger
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.15 compiler-side contract hardens the already-reserved
|
|
||||||
generic-shaped collection boundary without promoting executable generics,
|
|
||||||
maps, or sets. It keeps diagnostic codes and machine shapes stable while
|
|
||||||
removing beta.9-specific wording from current reserved diagnostics.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.15`.
|
|
||||||
- Centralize reserved generic and collection diagnostic construction in
|
|
||||||
`compiler/src/reserved.rs` for lowerer, formatter, and checker paths.
|
|
||||||
- Reword live compiler diagnostics and affected snapshots to say the surface
|
|
||||||
is reserved but not supported in the current beta while preserving existing
|
|
||||||
codes, schema, spans, expected/found values, and hints.
|
|
||||||
- Add focused `reserved_generic_collection_beta15` coverage for `check`,
|
|
||||||
`fmt --check`, and project-root `check` rejection of generic functions,
|
|
||||||
parameterized aliases, generic type parameters, generic vector spelling,
|
|
||||||
map/set types, and reserved generic stdlib calls `std.vec.empty` and
|
|
||||||
`std.result.map`.
|
|
||||||
- Run the focused beta.15 reserved-boundary test in `scripts/release-gate.sh`
|
|
||||||
before the full compiler test suite.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement executable generics, parameterized alias
|
|
||||||
expansion, generic vectors, map/set types, generic standard-library dispatch,
|
|
||||||
runtime collection names, ABI/layout claims, parser semantic expansion, or
|
|
||||||
current concrete collection behavior changes.
|
|
||||||
|
|
||||||
## 1.0.0-beta.14
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.14`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: benchmark suite catalog and metadata gate
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.14 compiler-side contract is tooling-only benchmark catalog hardening.
|
|
||||||
It keeps benchmark execution local and unchanged while adding deterministic
|
|
||||||
suite-level metadata for release verification.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.14`.
|
|
||||||
- Add `python3 benchmarks/runner.py --suite-list --json` for deterministic
|
|
||||||
suite-level benchmark listing and verification while preserving normal
|
|
||||||
per-benchmark `run.py` execution through the shared runner.
|
|
||||||
- Emit all 10 current benchmark names and directories, timing modes, cold/hot
|
|
||||||
loop counts, checksum metadata, required scaffold-file status,
|
|
||||||
implementation slots, and the local-only timing disclaimer.
|
|
||||||
- Add focused `benchmark_suite_catalog_beta14` coverage requiring byte-stable
|
|
||||||
suite catalog output across two runs and the current 10-benchmark inventory.
|
|
||||||
- Run the focused beta.14 suite catalog test in `scripts/release-gate.sh`
|
|
||||||
before the full compiler test suite.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement `glagol bench`, timing-result publication, a
|
|
||||||
new benchmark kernel, runtime changes, source-language changes, a stable JSON
|
|
||||||
schema claim, benchmark thresholds, or cross-machine performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.13
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.13`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: diagnostic catalog and schema policy hardening update
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.13 compiler-side contract is tooling/docs-only diagnostics policy
|
|
||||||
hardening. It keeps emitted diagnostic machine shapes stable while making the
|
|
||||||
schema name/version a single compiler constant source and gating the current
|
|
||||||
policy with focused structural tests.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.13`.
|
|
||||||
- Centralize the `slovo.diagnostic` schema name and version used by
|
|
||||||
S-expression rendering and newline-delimited JSON diagnostics, and use the
|
|
||||||
same schema version in artifact manifest diagnostics metadata.
|
|
||||||
- Add focused `diagnostics_schema_beta13` coverage for parse, check,
|
|
||||||
formatter, test-runner, project, source-less usage, toolchain, and manifest
|
|
||||||
diagnostic policy across S-expression and `--json-diagnostics` outputs.
|
|
||||||
- Require artifact manifests to keep recording diagnostics schema version,
|
|
||||||
diagnostics encoding, and project diagnostic counts deterministically.
|
|
||||||
- Run the focused beta.13 diagnostics schema test in `scripts/release-gate.sh`
|
|
||||||
before the full compiler test suite.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement LSP, watch mode, SARIF, daemon protocols,
|
|
||||||
stable human diagnostic text, a stable Markdown schema, generic collections,
|
|
||||||
generic vectors, maps, sets, runtime changes, ABI changes, source-language
|
|
||||||
expansion, standard-library/API expansion, or performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.12
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.12`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: source-authored concrete vector helper parity update
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.12 compiler-side contract is test and package metadata support for a
|
|
||||||
stdlib/helper parity release. It keeps Glagol language execution, runtime
|
|
||||||
lowering, and compiler-known `std.vec.*` names unchanged.
|
|
||||||
|
|
||||||
- Bump the `glagol` compiler package version to `1.0.0-beta.12`.
|
|
||||||
- Extend explicit local `std.vec_i64` source-helper fixture tests to require
|
|
||||||
`count_of`, `starts_with`, `without_prefix`, `ends_with`, and
|
|
||||||
`without_suffix`.
|
|
||||||
- Extend explicit local `std.vec_f64` source-helper fixture tests to require
|
|
||||||
`count_of`.
|
|
||||||
- Require focused fixture coverage for repeated count results and
|
|
||||||
prefix/suffix empty, mismatch, exact, and longer-than-input cases where
|
|
||||||
applicable.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not implement source-language runtime changes, executable
|
|
||||||
generics, generic vectors, maps, sets, iterators, mutable vectors, slice/view
|
|
||||||
APIs, generic stdlib dispatch, new compiler-known stdlib or runtime names,
|
|
||||||
stable collection ABI/layout, performance claims, or a stable stdlib/API
|
|
||||||
compatibility freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.11
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.11`
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Release state: local package API documentation update
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
The beta.11 docs/tooling contract extends beta.10 API discovery so generated
|
|
||||||
local documentation exposes the public API of local files, projects, packages,
|
|
||||||
and workspaces without changing source-language execution semantics.
|
|
||||||
|
|
||||||
- `glagol doc <file|project|workspace> -o <dir>` includes deterministic
|
|
||||||
exported/public API sections for local modules and workspace packages.
|
|
||||||
- Public API sections render exact exported function signatures, exported
|
|
||||||
struct fields, and exported enum variants with payload types.
|
|
||||||
- Module-local concrete aliases are normalized in public docs before rendering.
|
|
||||||
- Non-exported functions, structs, enums, tests, and `(type ...)` aliases stay
|
|
||||||
out of the public API sections.
|
|
||||||
|
|
||||||
### Explicit Deferrals
|
|
||||||
|
|
||||||
This release does not define a stable Markdown schema, stable stdlib/API
|
|
||||||
compatibility freeze, an LSP server, watch mode, SARIF, daemon protocols,
|
|
||||||
diagnostics schema policy, executable generics, generic vectors, maps, sets,
|
|
||||||
iterators, re-exports, globs, hierarchical modules, package registry
|
|
||||||
semantics, runtime collection changes, new standard-library runtime APIs, or
|
|
||||||
stable ABI/layout promises.
|
|
||||||
|
|
||||||
## 1.0.0-beta.10
|
## 1.0.0-beta.10
|
||||||
|
|
||||||
|
|||||||
@ -9,9 +9,10 @@ Compiler rule: make the tree visible. The pipeline should remain:
|
|||||||
.slo source -> tokens -> S-expression tree -> AST -> typed AST -> LLVM IR text -> hosted Clang/runtime executable step
|
.slo source -> tokens -> S-expression tree -> AST -> typed AST -> LLVM IR text -> hosted Clang/runtime executable step
|
||||||
```
|
```
|
||||||
|
|
||||||
Long-horizon compiler planning lives in `.llm/ROADMAP_TO_STABLE.md`. It
|
Long-horizon compiler planning lives in
|
||||||
mirrors Slovo's release train beyond the first real general-purpose beta
|
`.llm/GENERAL_PURPOSE_LANGUAGE_ROADMAP.md`. It mirrors Slovo's experimental
|
||||||
toolchain.
|
release train from the historical `v2.0.0-beta.1` tag toward and beyond the
|
||||||
|
first real general-purpose beta toolchain.
|
||||||
|
|
||||||
Release maturity policy lives in `.llm/RELEASE_MATURITY_POLICY.md`. Historical
|
Release maturity policy lives in `.llm/RELEASE_MATURITY_POLICY.md`. Historical
|
||||||
`exp-*` releases remain experimental maturity. `1.0.0-beta` is the first real
|
`exp-*` releases remain experimental maturity. `1.0.0-beta` is the first real
|
||||||
@ -21,9 +22,9 @@ general-purpose beta release.
|
|||||||
|
|
||||||
A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests.
|
A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests.
|
||||||
|
|
||||||
Current stage: `1.0.0-beta.25`, released on 2026-05-23 as user-project
|
Current stage: `1.0.0-beta.10`, released on 2026-05-22 as a
|
||||||
conformance matrix evidence. It keeps the
|
developer-experience API discovery and symbol-metadata update. It keeps the `1.0.0-beta`
|
||||||
`1.0.0-beta` language/compiler support baseline and includes the
|
language/compiler support baseline and includes the
|
||||||
`1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2` runtime/resource
|
`1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2` runtime/resource
|
||||||
foundation release, the `1.0.0-beta.3` standard-library stabilization release,
|
foundation release, the `1.0.0-beta.3` standard-library stabilization release,
|
||||||
the `1.0.0-beta.4` language-usability diagnostics release, the
|
the `1.0.0-beta.4` language-usability diagnostics release, the
|
||||||
@ -41,125 +42,12 @@ helper signatures after alias normalization, and adds
|
|||||||
`glagol symbols <file.slo|project|workspace>` for deterministic
|
`glagol symbols <file.slo|project|workspace>` for deterministic
|
||||||
editor-facing source metadata over modules, imports, exports, aliases,
|
editor-facing source metadata over modules, imports, exports, aliases,
|
||||||
structs, enums, functions, tests, spans/ranges, and workspace package labels.
|
structs, enums, functions, tests, spans/ranges, and workspace package labels.
|
||||||
The beta.11 documentation slice extends
|
It adds no source-language runtime behavior.
|
||||||
`glagol doc <file|project|workspace> -o <dir>` with deterministic
|
|
||||||
exported/public API sections for local packages and modules, including exact
|
|
||||||
exported function signatures, exported struct fields, exported enum
|
|
||||||
variants/payload types, non-export filtering, and module-local alias
|
|
||||||
normalization. The beta.12 stdlib/helper parity slice adds source-authored
|
|
||||||
coverage for `std.vec_i64.count_of`, `std.vec_i64.starts_with`,
|
|
||||||
`std.vec_i64.without_prefix`, `std.vec_i64.ends_with`,
|
|
||||||
`std.vec_i64.without_suffix`, and `std.vec_f64.count_of` without changing
|
|
||||||
source-language runtime behavior. The beta.13 tooling/docs-only diagnostics
|
|
||||||
slice centralizes the `slovo.diagnostic` schema name/version constants and
|
|
||||||
adds structural gates for S-expression diagnostics, `--json-diagnostics`, and
|
|
||||||
artifact-manifest diagnostics metadata without changing emitted machine
|
|
||||||
diagnostic shape. The beta.14 tooling-only benchmark slice adds deterministic
|
|
||||||
suite-level local benchmark listing and release-gate coverage for
|
|
||||||
`python3 benchmarks/runner.py --suite-list --json`, including all current
|
|
||||||
benchmark directories, timing modes, cold/hot loop counts, checksum metadata,
|
|
||||||
required scaffold-file status, implementation slots, and a local-only timing
|
|
||||||
disclaimer without publishing timing results or claiming a stable JSON schema.
|
|
||||||
The beta.15 compiler/tooling slice centralizes reserved generic and collection
|
|
||||||
diagnostics across lowerer, formatter, and checker paths, rewords current
|
|
||||||
reserved diagnostics to stage-neutral current-beta text, and gates the
|
|
||||||
collection ledger for generic functions, parameterized aliases, generic type
|
|
||||||
parameters, generic vector spelling, map/set types, `std.vec.empty`, and
|
|
||||||
`std.result.map` across check, fmt, and project paths without promoting those
|
|
||||||
surfaces. The beta.16 compiler/runtime slice adds byte-oriented
|
|
||||||
`std.string.byte_at_result`, `std.string.slice_result`,
|
|
||||||
`std.string.starts_with`, and `std.string.ends_with` over current
|
|
||||||
null-terminated runtime strings, with invalid indexes/ranges returning
|
|
||||||
`err 1`, without Unicode/grapheme semantics, tokenizer/parser claims, or
|
|
||||||
stable ABI/layout commitments.
|
|
||||||
The beta.17 compiler/runtime slice adds promoted `std.json` primitive scalar
|
|
||||||
parse helpers for bool, i32, u32, i64, u64, and f64 JSON tokens, with strict
|
|
||||||
whole-token checks, matching test-runner and hosted-runtime behavior, source
|
|
||||||
facade alignment, diagnostics coverage, and release-gate coverage. It keeps
|
|
||||||
`parse_null_value_result` source-only and leaves JSON strings, objects,
|
|
||||||
arrays, recursive values, tokenizers, schema validation, streaming, Unicode
|
|
||||||
escape handling, and stable JSON APIs deferred.
|
|
||||||
The beta.18 compiler/runtime slice adds promoted
|
|
||||||
`std.json.parse_string_value_result` for exact ASCII JSON string tokens, with
|
|
||||||
simple escape decoding and matching test-runner/hosted-runtime behavior. It
|
|
||||||
also runs `glagol test` execution on a bounded larger worker stack so deep
|
|
||||||
source-authored stdlib fixture tests remain gateable through ordinary
|
|
||||||
diagnostics. It keeps object parsing, array parsing, recursive values,
|
|
||||||
tokenizers, Unicode escape decoding, Unicode normalization, streaming, schema
|
|
||||||
validation, embedded NUL support in the current null-terminated string ABI, and
|
|
||||||
stable JSON APIs deferred.
|
|
||||||
The beta.19 compiler/tooling slice adds
|
|
||||||
`glagol test --list <file|project|workspace>` and legacy
|
|
||||||
`glagol --run-tests --list <file>` support. The list action reuses the same
|
|
||||||
checked discovery path as normal test execution, preserves existing
|
|
||||||
single-file, project, and workspace ordering, honors `--filter <substring>`,
|
|
||||||
and avoids executing test bodies. It keeps normal test execution output
|
|
||||||
unchanged when `--list` is absent.
|
|
||||||
|
|
||||||
The beta.20 compiler/tooling slice bumps the package version and gates
|
Next stage target: post-`1.0.0-beta.10` developer-experience and
|
||||||
source-authored `std.string` facades for `contains`, `index_of_option`,
|
collection/generic planning. Generic vectors, maps, sets, generic stdlib
|
||||||
`last_index_of_option`, `trim_ascii_start`, `trim_ascii_end`, and `trim_ascii`
|
dispatch, runtime collection changes, and collection unification remain
|
||||||
through explicit `std.string` imports. It keeps those helpers composed over
|
unimplemented until a later scoped contract promotes them explicitly.
|
||||||
beta16-or-earlier string primitives and existing option/result shapes, and
|
|
||||||
verifies that direct compiler-known runtime calls for the new helper names
|
|
||||||
remain unsupported.
|
|
||||||
|
|
||||||
The beta.21 compiler/tooling slice bumps the package version and gates
|
|
||||||
source-authored `std.json` document scalar facades for
|
|
||||||
`parse_string_document_result`, `parse_bool_document_result`,
|
|
||||||
`parse_i32_document_result`, `parse_u32_document_result`,
|
|
||||||
`parse_i64_document_result`, `parse_u64_document_result`,
|
|
||||||
`parse_f64_document_result`, and `parse_null_document_result` through explicit
|
|
||||||
`std.json` imports. It keeps those helpers source-authored over the existing
|
|
||||||
JSON token parser family and existing source-level composition, and verifies
|
|
||||||
that direct compiler-known runtime calls and private `__glagol_json_*document*`
|
|
||||||
symbols for the new helper names remain unsupported.
|
|
||||||
|
|
||||||
The beta.22 compiler/tooling slice bumps the package version and hardens
|
|
||||||
`glagol run --manifest` evidence with an additive run-report block in
|
|
||||||
run-mode artifact manifests. The block records executed-program exit status,
|
|
||||||
captured stdout, captured stderr, and forwarded program arguments. It is beta
|
|
||||||
CLI evidence metadata under the existing `slovo.artifact-manifest` version
|
|
||||||
`1` contract, not a stable schema freeze, and it adds no source-language,
|
|
||||||
runtime, package, or standard-library surface.
|
|
||||||
|
|
||||||
The beta.23 compiler/tooling slice bumps the package version and updates
|
|
||||||
generated `docs/language/STDLIB_API.md` output with per-module and per-helper
|
|
||||||
tier metadata. It adds a release-gate checker for the tier catalog, marks JSON,
|
|
||||||
loopback networking, random/time, and filesystem resource-handle helpers as
|
|
||||||
experimental, and keeps concrete vector modules beta-supported concrete lanes
|
|
||||||
without claiming generic collection stability. It adds no source-language,
|
|
||||||
runtime, package, or standard-library helper surface.
|
|
||||||
|
|
||||||
The beta.24 compiler/tooling slice bumps the package version and tightens
|
|
||||||
local package manifest diagnostics. Duplicate package manifest keys, invalid
|
|
||||||
dependency keys, and duplicate dependency keys are explicit diagnostics. It
|
|
||||||
keeps the existing closed local workspace model and adds no remote registry,
|
|
||||||
lockfile, semantic-version solving, package publishing, optional/dev/target
|
|
||||||
dependencies, stable package ABI/layout, source-language behavior, runtime
|
|
||||||
behavior, or standard-library behavior.
|
|
||||||
|
|
||||||
The beta.25 compiler/tooling slice adds deterministic stable-readiness
|
|
||||||
evidence for ordinary project and workspace usage over the existing
|
|
||||||
`examples/projects/` and `examples/workspaces/` inventories. The conformance
|
|
||||||
matrix is repository-local, sorted by stable path, and records ordinary
|
|
||||||
`check`, `test --list`, and stable `test` behavior for all 43 top-level
|
|
||||||
fixture roots and 655 discovered tests. It adds no source-language behavior,
|
|
||||||
runtime behavior, standard-library helper behavior, package manager or
|
|
||||||
registry behavior, lockfile behavior, semantic-version solving, stable schema
|
|
||||||
freeze, or performance claim.
|
|
||||||
|
|
||||||
Generic vectors, generic collections, maps, sets, generic stdlib dispatch,
|
|
||||||
runtime collection changes, collection unification, stable human diagnostic
|
|
||||||
text, stable artifact-manifest, Markdown, or conformance-matrix schema
|
|
||||||
freezes, LSP/watch protocols, SARIF/daemon protocols,
|
|
||||||
re-exports/globs/hierarchical modules,
|
|
||||||
registry semantics, semver solving, mutable vectors, stable slice/view APIs,
|
|
||||||
tokenizers, broader JSON parsing, runtime helper names, source-language
|
|
||||||
syntax, parallel test execution, retries, tags/groups, coverage/event streams,
|
|
||||||
performance claims, ABI/layout stability, and a stable stdlib/API
|
|
||||||
compatibility freeze remain unimplemented until a later scoped contract
|
|
||||||
promotes them explicitly.
|
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
||||||
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
||||||
@ -733,8 +621,6 @@ Alpha is the latest compiler semantic/runtime-operation support slice.
|
|||||||
- [x] Diagnose missing packages, duplicate package names, dependency cycles,
|
- [x] Diagnose missing packages, duplicate package names, dependency cycles,
|
||||||
path escapes, invalid package names, invalid package versions, private
|
path escapes, invalid package names, invalid package versions, private
|
||||||
visibility, and dependency key mismatches.
|
visibility, and dependency key mismatches.
|
||||||
- [x] Diagnose duplicate package manifest keys, invalid dependency keys, and
|
|
||||||
duplicate dependency keys explicitly.
|
|
||||||
- [x] Keep registries, lockfiles, semver solving, aliases/globs/re-exports,
|
- [x] Keep registries, lockfiles, semver solving, aliases/globs/re-exports,
|
||||||
generated code, build scripts, publishing, optional/dev/target
|
generated code, build scripts, publishing, optional/dev/target
|
||||||
dependencies, stable package ABI, and remote dependencies deferred.
|
dependencies, stable package ABI, and remote dependencies deferred.
|
||||||
|
|||||||
@ -1,139 +0,0 @@
|
|||||||
# Slovo Collection Ledger
|
|
||||||
|
|
||||||
Status: beta design ledger for `1.0.0-beta.15`.
|
|
||||||
|
|
||||||
This document inventories the current concrete collection and value-family
|
|
||||||
surface without redefining the generated public API catalog. Exact exported
|
|
||||||
helper signatures live in
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md), which is generated from `lib/std/*.slo`.
|
|
||||||
This ledger records design boundaries, pressure, and promotion prerequisites
|
|
||||||
for future generic collection work.
|
|
||||||
|
|
||||||
`1.0.0-beta.15` is documentation/design and compiler-boundary hardening. It
|
|
||||||
does not change the source language, typed core, runtime,
|
|
||||||
standard-library/API surface, diagnostic output shape, diagnostic codes,
|
|
||||||
diagnostic schema, benchmark metadata schema, ABI/layout behavior, or
|
|
||||||
performance claims. It does reword current reserved generic/map/set diagnostic
|
|
||||||
prose from beta.9-specific text to current-beta wording.
|
|
||||||
|
|
||||||
## Catalog Boundary
|
|
||||||
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md) remains the source of truth for current
|
|
||||||
exported standard-library helper signatures. It normalizes module-local
|
|
||||||
concrete aliases such as `VecI32`, `OptionString`, and `ResultU64` to concrete
|
|
||||||
public types, and omits non-exported helpers and `(type ...)` aliases.
|
|
||||||
|
|
||||||
This ledger intentionally does not duplicate generated module or helper
|
|
||||||
counts. If an exact signature or count is needed, use the generated catalog.
|
|
||||||
If this ledger and the catalog drift, the catalog describes the generated API
|
|
||||||
surface while this file describes the intended design boundary.
|
|
||||||
|
|
||||||
## Current Concrete Surface
|
|
||||||
|
|
||||||
| Surface | Current concrete families | Public catalog reference | Boundary |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Concrete vectors | `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, `(vec string)` | [`std.vec_i32`](STDLIB_API.md#stdvec_i32), [`std.vec_i64`](STDLIB_API.md#stdvec_i64), [`std.vec_f64`](STDLIB_API.md#stdvec_f64), [`std.vec_bool`](STDLIB_API.md#stdvec_bool), [`std.vec_string`](STDLIB_API.md#stdvec_string) | Concrete immutable value-family helpers over the existing vector runtime names. No generic vector dispatch, element-level mutation, slice/view API, iterator API, nested vector family, new runtime helper name, stable helper-symbol contract, or ABI/layout promise is implied. |
|
|
||||||
| Option value families | `(option i32)`, `(option u32)`, `(option i64)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)` | [`std.option`](STDLIB_API.md#stdoption) | Concrete constructors, observers, unwrap/fallback helpers, and option-to-result bridges. No generic option helper, mapping/chaining API, transpose/flatten family, stable API freeze, or payload-family expansion is implied. |
|
|
||||||
| Result value families | `(result i32 i32)`, `(result u32 i32)`, `(result i64 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)` | [`std.result`](STDLIB_API.md#stdresult) | Concrete `i32` error-code result helpers. No generic result helper, rich error ADT, mapping/chaining API, transpose/flatten family, stable API freeze, or alternate error payload family is implied. |
|
|
||||||
| Host and parsing result/option flows | Concrete option/result values returned by current host, CLI, file, network, parse, and numeric helpers | [`std.cli`](STDLIB_API.md#stdcli), [`std.env`](STDLIB_API.md#stdenv), [`std.fs`](STDLIB_API.md#stdfs), [`std.io`](STDLIB_API.md#stdio), [`std.net`](STDLIB_API.md#stdnet), [`std.num`](STDLIB_API.md#stdnum), [`std.string`](STDLIB_API.md#stdstring) | These helpers expose the same concrete value families through ordinary source facades. They do not create generic payload types, generic host errors, stable ABI names, or a stable compatibility freeze. |
|
|
||||||
|
|
||||||
Fixed arrays are part of the current language surface, but they are not a
|
|
||||||
standard-library helper family in the generated API catalog. Future work that
|
|
||||||
connects arrays to slices, views, iterators, maps, sets, or generic collection
|
|
||||||
helpers must define its own language, runtime, diagnostic, and documentation
|
|
||||||
contract.
|
|
||||||
|
|
||||||
## Design Pressure
|
|
||||||
|
|
||||||
The current surface deliberately repeats concrete helper families. That
|
|
||||||
duplication has been useful because each family could be promoted with narrow
|
|
||||||
tests and without a generic type system, but it now creates clear pressure:
|
|
||||||
|
|
||||||
- Vector helpers repeat construction, indexing, fallback, search, query,
|
|
||||||
concatenation, slicing-by-copy, replacement, and removal names across five
|
|
||||||
concrete element families.
|
|
||||||
- `std.option` and `std.result` repeat constructor, observer, unwrap,
|
|
||||||
fallback, and bridge helpers across concrete payload families, including the
|
|
||||||
unsigned payloads added before beta.
|
|
||||||
- Helper parity can drift between concrete modules, as shown by the beta12
|
|
||||||
vector query and prefix parity release.
|
|
||||||
- Module-local concrete aliases reduce source repetition inside facades, and
|
|
||||||
the generated catalog hides those aliases from public signatures, but aliases
|
|
||||||
do not define generic API compatibility or migration behavior.
|
|
||||||
- Host and parsing facades spread concrete option/result values through the
|
|
||||||
broader API surface, so future generic work must account for both dedicated
|
|
||||||
`std.option`/`std.result` modules and callers that already depend on
|
|
||||||
concrete return types.
|
|
||||||
|
|
||||||
This pressure is a reason to design generics carefully, not a license to infer
|
|
||||||
generic behavior from existing concrete helpers.
|
|
||||||
|
|
||||||
## Promotion Prerequisites
|
|
||||||
|
|
||||||
Before any executable generic collection feature is promoted, a release must
|
|
||||||
define and gate the full contract for that feature. At minimum:
|
|
||||||
|
|
||||||
- Executable generics need source syntax, type-parameter rules, explicit
|
|
||||||
inference policy, type-checking behavior, formatter layout, typed-core
|
|
||||||
representation, lowering/monomorphization or dispatch strategy, diagnostic
|
|
||||||
coverage, public documentation, examples, and migration rules for existing
|
|
||||||
concrete helpers.
|
|
||||||
- Generic aliases need a separate alias contract, including parameter syntax,
|
|
||||||
allowed targets, cycle checks, export/import visibility, formatter behavior,
|
|
||||||
diagnostics, and the relationship to runtime layout and public API docs.
|
|
||||||
- Maps and sets need key/value constraints, equality and hashing or ordering
|
|
||||||
policy, construction and update semantics, iteration order or non-order
|
|
||||||
policy, error behavior, runtime/resource ownership, diagnostics, and public
|
|
||||||
API stability rules.
|
|
||||||
- Iterators need an ownership and lifetime model, exhaustion semantics,
|
|
||||||
composition rules, interaction with `match` and future loops, diagnostics,
|
|
||||||
and guarantees about whether iteration is copying, borrowing, or consuming.
|
|
||||||
- Mutable vectors need element-mutation syntax, aliasing and ownership rules,
|
|
||||||
capacity/reallocation behavior, interaction with whole-value `var` / `set`,
|
|
||||||
runtime helper names, trap/error behavior, diagnostics, and layout/ABI
|
|
||||||
boundaries.
|
|
||||||
- Slice/view APIs need borrowing or ownership rules, bounds behavior,
|
|
||||||
invalidation rules when mutation exists, array/vector/string applicability,
|
|
||||||
formatter behavior, diagnostics, and runtime representation boundaries.
|
|
||||||
- Any stable stdlib/API claim needs explicit stable and experimental tiers,
|
|
||||||
compatibility and deprecation policy, migration tests, generated API-doc
|
|
||||||
behavior, and release-gate coverage.
|
|
||||||
|
|
||||||
Until those prerequisites are satisfied by a specific release, the current
|
|
||||||
concrete families remain the entire supported collection/value-family surface.
|
|
||||||
|
|
||||||
## Unsupported Boundaries
|
|
||||||
|
|
||||||
Current diagnostics that reject generic aliases, unsupported alias targets,
|
|
||||||
unsupported collection forms, unsupported vector element types, maps, sets,
|
|
||||||
iterators, slice/view APIs, mutable element operations, or broader
|
|
||||||
option/result payload shapes are boundary diagnostics. They document where the
|
|
||||||
current beta stops.
|
|
||||||
|
|
||||||
`1.0.0-beta.15` does not add, remove, rename, or reclassify diagnostic codes.
|
|
||||||
It does not change the `slovo.diagnostic` schema, JSON/S-expression output
|
|
||||||
shape, spans, expected/found values, hints, or human-readable diagnostic prose
|
|
||||||
policy. The only diagnostic-fixture change in this release is reserved-boundary
|
|
||||||
message text that no longer names beta.9 as the unsupported stage. Future
|
|
||||||
releases that change diagnostics for collection boundaries must do so through
|
|
||||||
the diagnostic policy in [`DIAGNOSTICS.md`](DIAGNOSTICS.md) and their own
|
|
||||||
release gates.
|
|
||||||
|
|
||||||
## Explicit Non-Changes
|
|
||||||
|
|
||||||
This ledger does not promote:
|
|
||||||
|
|
||||||
- executable generics
|
|
||||||
- generic aliases or parameterized aliases
|
|
||||||
- generic stdlib dispatch
|
|
||||||
- maps or sets
|
|
||||||
- iterator APIs
|
|
||||||
- mutable vector APIs
|
|
||||||
- slice/view APIs
|
|
||||||
- new runtime names or helper symbols
|
|
||||||
- stdlib/API additions, removals, or renames
|
|
||||||
- diagnostic output shape, code, schema, span, expected/found, or hint changes
|
|
||||||
- benchmark metadata schema changes
|
|
||||||
- ABI/layout guarantees
|
|
||||||
- performance claims or thresholds
|
|
||||||
- a stable `1.0.0` stdlib/API freeze
|
|
||||||
@ -1,294 +0,0 @@
|
|||||||
# Slovo Diagnostics
|
|
||||||
|
|
||||||
This document defines the `1.0.0-beta.13` beta policy for Slovo machine
|
|
||||||
diagnostics. It documents the existing `slovo.diagnostic` version `1` schema,
|
|
||||||
the relationship between the S-expression and JSON encodings, the current
|
|
||||||
golden diagnostic code catalog, and the migration rules for changing machine
|
|
||||||
diagnostic fields or codes.
|
|
||||||
|
|
||||||
This is a diagnostics policy and catalog slice only. It does not add source
|
|
||||||
language syntax, runtime behavior, stdlib APIs, ABI/layout guarantees, LSP,
|
|
||||||
watch mode, SARIF, daemon protocols, stable Markdown output, or a stable
|
|
||||||
`1.0.0` diagnostics freeze.
|
|
||||||
|
|
||||||
## Schema Identity
|
|
||||||
|
|
||||||
The machine diagnostic schema name is `slovo.diagnostic`.
|
|
||||||
|
|
||||||
The current schema version is `1`.
|
|
||||||
|
|
||||||
The S-expression form uses a root `(diagnostic ...)` object:
|
|
||||||
|
|
||||||
```text
|
|
||||||
(diagnostic
|
|
||||||
(schema slovo.diagnostic)
|
|
||||||
(version 1)
|
|
||||||
...)
|
|
||||||
```
|
|
||||||
|
|
||||||
The JSON form uses a single JSON object:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"schema":"slovo.diagnostic","version":1}
|
|
||||||
```
|
|
||||||
|
|
||||||
The schema name and version belong to the machine contract. Changing either one
|
|
||||||
requires an explicit migration note, release-note entry, and matching Glagol
|
|
||||||
snapshot or JSON fixture updates.
|
|
||||||
|
|
||||||
## Encodings
|
|
||||||
|
|
||||||
S-expression diagnostics and JSON diagnostics are two encodings of the same
|
|
||||||
diagnostic data model. They must not diverge semantically.
|
|
||||||
|
|
||||||
The default human diagnostics path may print human-readable prose and then the
|
|
||||||
S-expression machine form for source diagnostics. Human prose, spacing,
|
|
||||||
excerpts, hints, and surrounding text remain beta-flexible unless a later
|
|
||||||
release freezes them explicitly. Tools should consume the machine form, not the
|
|
||||||
human rendering.
|
|
||||||
|
|
||||||
`--json-diagnostics` emits JSON diagnostics on stderr. Each diagnostic is one
|
|
||||||
complete JSON object on one line. There is no JSON array wrapper, no pretty
|
|
||||||
printing, and no required trailing summary object for source failures. Consumers
|
|
||||||
should parse stderr as newline-delimited JSON objects and should treat each
|
|
||||||
line as an independent diagnostic record.
|
|
||||||
|
|
||||||
JSON and S-expression escaping must preserve the same string values. JSON uses
|
|
||||||
standard JSON string escaping. S-expression strings use the Glagol diagnostic
|
|
||||||
string escaping convention already used in golden `.diag` fixtures.
|
|
||||||
|
|
||||||
## Fields
|
|
||||||
|
|
||||||
Every source-attached compiler diagnostic must include these machine fields:
|
|
||||||
|
|
||||||
| Field | S-expression | JSON | Meaning |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Schema | `(schema slovo.diagnostic)` | `"schema":"slovo.diagnostic"` | Diagnostic schema name. |
|
|
||||||
| Version | `(version 1)` | `"version":1` | Diagnostic schema version. |
|
|
||||||
| Severity | `(severity error)` | `"severity":"error"` | Diagnostic severity. |
|
|
||||||
| Code | `(code TypeMismatch)` | `"code":"TypeMismatch"` | Stable PascalCase diagnostic code for the condition. |
|
|
||||||
| Message | `(message "...")` | `"message":"..."` | Concise beta-flexible human message for the machine record. |
|
|
||||||
| Source file | `(file "...")` | `"file":"..."` | Source identity used by the invocation or project loader. |
|
|
||||||
| Span | `(span ...)` | `"span":{...}` | Primary source span and line/column range. |
|
|
||||||
|
|
||||||
Optional fields may appear when the compiler has precise data:
|
|
||||||
|
|
||||||
| Field | S-expression | JSON | Meaning |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Expected | `(expected "...")` | `"expected":"..."` | Expected type, arity, value, or form. |
|
|
||||||
| Found | `(found "...")` | `"found":"..."` | Found type, arity, value, or form. |
|
|
||||||
| Hint | `(hint "...")` | `"hint":"..."` | Safe repair or orientation hint. |
|
|
||||||
| Related spans | repeated `(related ...)` | `"related":[...]` | Secondary source locations tied to the primary diagnostic. |
|
|
||||||
|
|
||||||
Optional fields are additive when they do not replace an existing machine field
|
|
||||||
or change an existing diagnostic code. Removing an optional field from an
|
|
||||||
existing golden fixture is a migration-level change unless the release note
|
|
||||||
states that the previous field was incorrect.
|
|
||||||
|
|
||||||
## Severity
|
|
||||||
|
|
||||||
Current source diagnostics use severity `error`.
|
|
||||||
|
|
||||||
JSON source-less or invocation-level messages may use `error` for failures and
|
|
||||||
`note` for informational tool output such as a machine-readable test-run
|
|
||||||
summary. A `note` is not by itself a source failure; consumers should still use
|
|
||||||
the process exit code and artifact manifest success field to determine command
|
|
||||||
success.
|
|
||||||
|
|
||||||
Adding a new severity value is an additive schema change only when old
|
|
||||||
consumers can safely ignore or display it. Reclassifying an existing failing
|
|
||||||
diagnostic from `error` to another severity is migration-level.
|
|
||||||
|
|
||||||
## Source And Range Semantics
|
|
||||||
|
|
||||||
`file` is the source identity reported by the compiler path, project loader, or
|
|
||||||
workspace loader. It is not a promise of absolute path normalization, URI
|
|
||||||
formatting, registry identity, or editor document identity.
|
|
||||||
|
|
||||||
Primary and related byte spans are zero-based and half-open: `start` is the
|
|
||||||
first byte included, and `end` is the first byte after the highlighted source.
|
|
||||||
|
|
||||||
Line and column ranges are one-based and derived from the original source text.
|
|
||||||
Columns are byte columns within the original UTF-8 source line; a tab counts as
|
|
||||||
one input byte. The end column is the first byte column after the highlighted
|
|
||||||
range on the end line.
|
|
||||||
|
|
||||||
Diagnostic locations are derived from source input, not formatter output,
|
|
||||||
lowered IR, generated C, LLVM IR, native object code, or runtime stack traces.
|
|
||||||
|
|
||||||
## Related Spans
|
|
||||||
|
|
||||||
Related spans identify secondary source locations such as an original
|
|
||||||
declaration, previous duplicate, or conflicting arm. A related span never
|
|
||||||
replaces the primary span.
|
|
||||||
|
|
||||||
In S-expression diagnostics, each related location is a repeated
|
|
||||||
`(related (span ...))` form. In JSON diagnostics, related locations are objects
|
|
||||||
inside the `related` array. Each related object has its own `file` and `span`;
|
|
||||||
it may also carry a `message` string.
|
|
||||||
|
|
||||||
Related messages are beta-flexible prose. The existence of a related span for a
|
|
||||||
current golden fixture is part of the machine shape for that fixture and should
|
|
||||||
change only intentionally.
|
|
||||||
|
|
||||||
## Source-Less Diagnostics
|
|
||||||
|
|
||||||
Some diagnostics describe tool invocation or usage failures rather than a
|
|
||||||
source range. Examples include invalid CLI arguments, missing inputs, and
|
|
||||||
source-loading failures before a source span is available.
|
|
||||||
|
|
||||||
JSON source-less diagnostics use:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"file":null,"span":null}
|
|
||||||
```
|
|
||||||
|
|
||||||
Source-less diagnostics must not invent dummy paths, byte offsets, or
|
|
||||||
line/column ranges. Text-mode source-less diagnostics may remain human-only in
|
|
||||||
current Glagol output; consumers that need machine-readable source-less
|
|
||||||
diagnostics should request `--json-diagnostics`.
|
|
||||||
|
|
||||||
If a future release adds S-expression source-less diagnostics, absence of a
|
|
||||||
source must be explicit and documented under `slovo.diagnostic` version `1` or
|
|
||||||
a later migrated version. It must not be encoded as fake source coordinates.
|
|
||||||
|
|
||||||
## Artifact Manifest Metadata
|
|
||||||
|
|
||||||
`slovo.artifact-manifest` records the diagnostic metadata for a tool
|
|
||||||
invocation. The relevant fields are:
|
|
||||||
|
|
||||||
- `(diagnostics-schema-version 1)`: the diagnostic schema version used by the
|
|
||||||
invocation.
|
|
||||||
- `(diagnostics-encoding sexpr)` or `(diagnostics-encoding json)`: the encoding
|
|
||||||
selected for diagnostics.
|
|
||||||
- `(primary-output (kind diagnostics) ...)`: the primary output kind when the
|
|
||||||
command failed by emitting diagnostics.
|
|
||||||
- `(diagnostic_artifacts ...)`: the diagnostic stream artifact metadata for
|
|
||||||
project/package/workspace modes.
|
|
||||||
- `(diagnostics_count N)`: the project-level count when available.
|
|
||||||
|
|
||||||
The manifest points to or records diagnostic streams. It does not define a
|
|
||||||
separate diagnostic schema, embed a parsed diagnostic catalog, freeze Markdown
|
|
||||||
documentation structure, or replace the newline discipline of JSON diagnostic
|
|
||||||
stderr.
|
|
||||||
|
|
||||||
## Compatibility And Migration
|
|
||||||
|
|
||||||
Diagnostic changes are classified as follows.
|
|
||||||
|
|
||||||
Clarifying changes:
|
|
||||||
|
|
||||||
- Rewording human-readable stderr prose.
|
|
||||||
- Rewording `message` or `hint` text without changing the diagnostic code,
|
|
||||||
source span, field set, severity, or expected/found semantics.
|
|
||||||
- Improving documentation around an existing code or fixture.
|
|
||||||
|
|
||||||
Additive changes:
|
|
||||||
|
|
||||||
- Adding a new diagnostic code for a newly covered boundary.
|
|
||||||
- Adding a new golden fixture for a newly rejected form.
|
|
||||||
- Adding an optional field when the old fields, code, severity, source span,
|
|
||||||
and JSON-line discipline remain valid.
|
|
||||||
- Adding related spans for a new fixture.
|
|
||||||
|
|
||||||
Migration changes:
|
|
||||||
|
|
||||||
- Renaming, removing, splitting, or merging an existing diagnostic code covered
|
|
||||||
by golden fixtures.
|
|
||||||
- Changing required field names, schema name, schema version, span shape, range
|
|
||||||
indexing, JSON null policy, or JSON-line discipline.
|
|
||||||
- Removing an existing optional field or related span from a golden fixture
|
|
||||||
without documenting the correction.
|
|
||||||
- Changing a source-attached diagnostic into a source-less diagnostic, or the
|
|
||||||
reverse, for an existing golden fixture.
|
|
||||||
- Reclassifying an existing failing diagnostic away from severity `error`.
|
|
||||||
- Changing artifact manifest diagnostic metadata fields or their meaning.
|
|
||||||
|
|
||||||
Every migration-level diagnostic change must update this document or the next
|
|
||||||
release policy, `docs/language/MIGRATION_POLICY.md` if needed,
|
|
||||||
`docs/language/RELEASE_NOTES.md`, and the matching Glagol golden snapshots or
|
|
||||||
tests.
|
|
||||||
|
|
||||||
## Current Golden Catalog
|
|
||||||
|
|
||||||
The current golden diagnostics contract is the snapshot inventory in
|
|
||||||
`compiler/tests/diagnostics_contract.rs`. As of `1.0.0-beta.13`, that contract
|
|
||||||
references 358 `.diag` snapshots under `tests/`, and those snapshots contain
|
|
||||||
114 unique diagnostic codes.
|
|
||||||
|
|
||||||
This catalog inventories those codes. It is policy-focused: messages and
|
|
||||||
fixture-specific prose remain in the snapshots.
|
|
||||||
|
|
||||||
| Area | Current codes |
|
|
||||||
| --- | --- |
|
|
||||||
| General calls, typing, signatures, and source shape | `ArityMismatch`, `ReturnTypeMismatch`, `SingleFileMainSignature`, `TypeMismatch`, `UnclosedList`, `UnknownFunction`, `UnknownTopLevelForm`, `UnsupportedBackendFeature`, `UnsupportedUnitSignatureType` |
|
|
||||||
| Control flow and tests | `EmptyWhileBody`, `IfBranchTypeMismatch`, `IfConditionNotBool`, `MalformedIfForm`, `MalformedTestForm`, `MalformedWhileForm`, `NestedWhileUnsupported`, `TestExpressionNotBool`, `WhileBodyFormNotUnit`, `WhileConditionNotBool` |
|
|
||||||
| Literals and strings | `I64LiteralOutOfRange`, `IntegerOutOfRange`, `InvalidI64Literal`, `UnsupportedFloatLiteral`, `UnsupportedStringConcatenation`, `UnsupportedStringEscape`, `UnsupportedStringLiteral` |
|
|
||||||
| Locals, assignment, and name conflicts | `CannotAssignImmutableLocal`, `CannotAssignParameter`, `DuplicateFunction`, `DuplicateLocal`, `DuplicateTestName`, `InvalidSetTarget`, `InvalidTestName`, `LocalDeclarationInWhileBodyUnsupported`, `LocalDeclarationNotAllowed`, `LocalRedeclaresParameter`, `LocalShadowsCallable`, `ParameterShadowsCallable`, `UnknownVariable`, `UnsupportedLocalType` |
|
|
||||||
| Type aliases, generics, maps, and sets | `DuplicateTypeAlias`, `MalformedTypeAlias`, `SelfTypeAlias`, `TypeAliasCycle`, `TypeAliasNameConflict`, `UnknownTypeAliasTarget`, `UnsupportedGenericFunction`, `UnsupportedGenericStandardLibraryCall`, `UnsupportedGenericTypeAlias`, `UnsupportedGenericTypeParameter`, `UnsupportedMapType`, `UnsupportedSetType`, `UnsupportedTypeAliasTarget` |
|
|
||||||
| Structs and fields | `DuplicateStruct`, `DuplicateStructConstructorField`, `DuplicateStructField`, `EmptyStructUnsupported`, `FieldAccessOnNonStruct`, `MissingStructField`, `RecursiveStructFieldUnsupported`, `StructConstructorFieldOrderMismatch`, `UnknownStructField`, `UnknownStructType`, `UnsupportedStructFieldType` |
|
|
||||||
| Arrays and vectors | `ArrayIndexNotI32`, `ArrayIndexOutOfBounds`, `EmptyArrayUnsupported`, `IndexOnNonArray`, `MutableArrayLocalUnsupported`, `UnsupportedArrayElementType`, `UnsupportedArrayEquality`, `UnsupportedArrayPrint`, `UnsupportedVectorElementType`, `UnsupportedVectorEquality`, `ZeroLengthArrayUnsupported` |
|
|
||||||
| Options, results, and match | `DuplicateMatchArm`, `MalformedMatchPattern`, `MalformedOptionConstructor`, `MalformedResultConstructor`, `MalformedUnwrapForm`, `MatchArmTypeMismatch`, `MatchBindingCollision`, `MatchSubjectTypeMismatch`, `NonExhaustiveMatch`, `OptionObservationTypeMismatch`, `OptionUnwrapTypeMismatch`, `ResultObservationTypeMismatch`, `ResultUnwrapTypeMismatch`, `UnsupportedMatchContainer`, `UnsupportedMatchMutation`, `UnsupportedMatchPayloadType`, `UnsupportedOptionPayloadType`, `UnsupportedOptionResultEquality`, `UnsupportedOptionResultPrint`, `UnsupportedResultPayloadType` |
|
|
||||||
| Enums | `DuplicateEnum`, `DuplicateEnumVariant`, `EmptyEnumUnsupported`, `EnumSubjectMismatch`, `InvalidEnumMatchArm`, `MixedEnumPayloadTypesUnsupported`, `RecursiveEnumPayloadStructUnsupported`, `UnknownEnumConstructor`, `UnknownVariantConstructor`, `UnsupportedEnumContainer`, `UnsupportedEnumEquality`, `UnsupportedEnumOrdering`, `UnsupportedEnumPayloadType`, `UnsupportedEnumPrint`, `VariantConstructorArity` |
|
|
||||||
| Unsafe operations | `MalformedUnsafeForm`, `UnsafeRequired`, `UnsupportedUnsafeOperation` |
|
|
||||||
| Standard-library reservation boundaries | `UnsupportedStandardLibraryCall` |
|
|
||||||
|
|
||||||
Future releases may add codes or split broad codes when the release scope
|
|
||||||
requires more precise tooling behavior. Such changes must be documented using
|
|
||||||
the compatibility classes above.
|
|
||||||
|
|
||||||
## Project And Workspace Codes
|
|
||||||
|
|
||||||
Project, package, and workspace diagnostics are covered by integration tests
|
|
||||||
because they often require multiple files, manifests, or generated temporary
|
|
||||||
directories rather than a single `.slo` golden fixture. These codes still use
|
|
||||||
the same `slovo.diagnostic` version `1` schema and PascalCase code policy.
|
|
||||||
|
|
||||||
Current package/workspace loader and graph diagnostics include:
|
|
||||||
|
|
||||||
- `DependencyNameMismatch`
|
|
||||||
- `DependencyPathEscape`
|
|
||||||
- `DuplicatePackageDependencyName`
|
|
||||||
- `DuplicatePackageName`
|
|
||||||
- `DuplicateWorkspaceMember`
|
|
||||||
- `InvalidPackageDependencyName`
|
|
||||||
- `InvalidPackageName`
|
|
||||||
- `InvalidPackageVersion`
|
|
||||||
- `MissingPackageDependency`
|
|
||||||
- `MissingPackageModule`
|
|
||||||
- `PackageDependencyCycle`
|
|
||||||
- `PackageImportNotDependency`
|
|
||||||
- `PackageManifestInvalid`
|
|
||||||
- `PackageSourceReadFailed`
|
|
||||||
- `PackageSourceRootEscape`
|
|
||||||
- `PackageSourceRootMissing`
|
|
||||||
- `ProjectEntryMainInvalidSignature`
|
|
||||||
- `ProjectEntryMainMissing`
|
|
||||||
- `ProjectManifestInvalid`
|
|
||||||
- `ProjectManifestReadFailed`
|
|
||||||
- `ProjectSourceReadFailed`
|
|
||||||
- `ProjectSourceRootMissing`
|
|
||||||
- `UnsupportedDependency`
|
|
||||||
- `WorkspaceBuildAmbiguousEntryPackage`
|
|
||||||
- `WorkspaceDefaultPackageEntryMissing`
|
|
||||||
- `WorkspaceDefaultPackageMissing`
|
|
||||||
- `WorkspaceEntryMainInvalidSignature`
|
|
||||||
- `WorkspaceEntryMainMissing`
|
|
||||||
- `WorkspaceManifestInvalid`
|
|
||||||
- `WorkspaceMemberManifestMissing`
|
|
||||||
- `WorkspaceMemberPathEscape`
|
|
||||||
|
|
||||||
## Explicit Deferrals
|
|
||||||
|
|
||||||
`1.0.0-beta.13` does not define:
|
|
||||||
|
|
||||||
- a stable `1.0.0` diagnostics freeze
|
|
||||||
- LSP diagnostics, watch mode, SARIF, daemon protocols, or debug adapters
|
|
||||||
- a stable Markdown documentation schema
|
|
||||||
- stable source-map, DWARF, LLVM debug metadata, or runtime stack trace schema
|
|
||||||
- warning, lint, or suggestion taxonomies beyond the current `error` and
|
|
||||||
source-less `note` uses
|
|
||||||
- localized diagnostic text
|
|
||||||
- machine-readable remediation edits
|
|
||||||
- a separate diagnostic catalog artifact emitted by the compiler
|
|
||||||
- stable package registry, URI, or workspace identity semantics for `file`
|
|
||||||
@ -46,18 +46,10 @@ Slovo must not silently repurpose an old supported form with new meaning.
|
|||||||
|
|
||||||
## Diagnostic And Tooling Changes
|
## Diagnostic And Tooling Changes
|
||||||
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md) is the beta policy for
|
Diagnostic code or machine-shape changes require a documented schema migration
|
||||||
`slovo.diagnostic` version `1`. Human-readable diagnostic prose remains
|
and matching Glagol snapshot updates. Formatter changes require before/after
|
||||||
beta-flexible, but machine fields, schema/version markers, diagnostic codes,
|
fixture coverage so agents can see whether the change is additive,
|
||||||
source/span/range semantics, JSON-line discipline, related-span shape, and
|
clarifying, or migration-level.
|
||||||
artifact-manifest diagnostic metadata are compatibility-sensitive.
|
|
||||||
|
|
||||||
Diagnostic code or machine-shape changes require the compatibility class
|
|
||||||
defined in [`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md), a documented
|
|
||||||
schema or catalog migration when the change is migration-level, and matching
|
|
||||||
Glagol snapshot updates. Formatter changes require before/after fixture
|
|
||||||
coverage so agents can see whether the change is additive, clarifying, or
|
|
||||||
migration-level.
|
|
||||||
|
|
||||||
Native executable output, package layout, stable ABI/layout promises, stable
|
Native executable output, package layout, stable ABI/layout promises, stable
|
||||||
standard-runtime printing APIs, and raw-memory/FFI contracts remain outside the
|
standard-runtime printing APIs, and raw-memory/FFI contracts remain outside the
|
||||||
|
|||||||
@ -56,10 +56,6 @@ used for solving dependency constraints.
|
|||||||
dependency paths must stay inside the workspace/package boundary after
|
dependency paths must stay inside the workspace/package boundary after
|
||||||
normalization and canonical path checks.
|
normalization and canonical path checks.
|
||||||
|
|
||||||
Duplicate keys in package manifests are `PackageManifestInvalid` diagnostics.
|
|
||||||
The manifest loader does not silently choose one spelling for repeated package
|
|
||||||
identity or dependency entries.
|
|
||||||
|
|
||||||
Dependencies are local path records only. The dependency key must match the
|
Dependencies are local path records only. The dependency key must match the
|
||||||
target package name:
|
target package name:
|
||||||
|
|
||||||
@ -67,11 +63,6 @@ target package name:
|
|||||||
mathlib = { path = "../mathlib" }
|
mathlib = { path = "../mathlib" }
|
||||||
```
|
```
|
||||||
|
|
||||||
Dependency keys use the same package-name shape as package identities. Invalid
|
|
||||||
dependency keys are `InvalidPackageDependencyName` diagnostics, and duplicate
|
|
||||||
dependency keys are `DuplicatePackageDependencyName` diagnostics before the
|
|
||||||
local dependency graph is accepted.
|
|
||||||
|
|
||||||
## Imports
|
## Imports
|
||||||
|
|
||||||
Within a workspace, a package imports a dependency module through the package
|
Within a workspace, a package imports a dependency module through the package
|
||||||
@ -115,12 +106,9 @@ The package/workspace gate covers these user-facing error families:
|
|||||||
- missing member manifests
|
- missing member manifests
|
||||||
- duplicate normalized workspace members
|
- duplicate normalized workspace members
|
||||||
- invalid member or dependency paths
|
- invalid member or dependency paths
|
||||||
- duplicate package manifest keys
|
|
||||||
- invalid package names and versions
|
- invalid package names and versions
|
||||||
- duplicate package names
|
- duplicate package names
|
||||||
- missing local path dependencies
|
- missing local path dependencies
|
||||||
- invalid dependency keys
|
|
||||||
- duplicate dependency keys
|
|
||||||
- dependency key/name mismatches
|
- dependency key/name mismatches
|
||||||
- package dependency cycles
|
- package dependency cycles
|
||||||
- private cross-package imports
|
- private cross-package imports
|
||||||
|
|||||||
@ -8,7 +8,7 @@ Historical `exp-*` releases listed here are experimental maturity milestones.
|
|||||||
The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an
|
The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an
|
||||||
experimental integration/readiness release, not as a beta maturity claim.
|
experimental integration/readiness release, not as a beta maturity claim.
|
||||||
|
|
||||||
The current release is `1.0.0-beta.25`, published on 2026-05-23. It keeps the
|
The current release is `1.0.0-beta.10`, published on 2026-05-22. It keeps the
|
||||||
`1.0.0-beta` language surface, includes the first post-beta tooling/install
|
`1.0.0-beta` language surface, includes the first post-beta tooling/install
|
||||||
hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource
|
hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource
|
||||||
foundation bundle from `1.0.0-beta.2` plus the first standard-library
|
foundation bundle from `1.0.0-beta.2` plus the first standard-library
|
||||||
@ -19,483 +19,12 @@ loopback networking foundation bundle from `1.0.0-beta.6`, and the first
|
|||||||
serialization/data-interchange foundation bundle from `1.0.0-beta.7`, and the
|
serialization/data-interchange foundation bundle from `1.0.0-beta.7`, and the
|
||||||
first concrete type alias foundation from `1.0.0-beta.8`, plus the first
|
first concrete type alias foundation from `1.0.0-beta.8`, plus the first
|
||||||
collection alias unification and generic reservation slice from
|
collection alias unification and generic reservation slice from
|
||||||
`1.0.0-beta.9`, the first developer-experience API discovery slice from
|
`1.0.0-beta.9`, and the first developer-experience API discovery slice from
|
||||||
`1.0.0-beta.10`, and the local package API documentation extension from
|
`1.0.0-beta.10`.
|
||||||
`1.0.0-beta.11`, plus the concrete vector query and prefix parity slice from
|
|
||||||
`1.0.0-beta.12`, and the diagnostic catalog and schema policy slice from
|
|
||||||
`1.0.0-beta.13`, plus the benchmark suite catalog and metadata gate from
|
|
||||||
`1.0.0-beta.14`, plus the reserved generic collection boundary hardening and
|
|
||||||
collection ledger from `1.0.0-beta.15`, plus the string scanning and token
|
|
||||||
boundary foundation from `1.0.0-beta.16`, and the JSON primitive scalar
|
|
||||||
parsing foundation from `1.0.0-beta.17`, plus the JSON string token parsing
|
|
||||||
foundation from `1.0.0-beta.18`, the test discovery and user-project
|
|
||||||
conformance foundation from `1.0.0-beta.19`, and the string search and ASCII
|
|
||||||
trim foundation from `1.0.0-beta.20`, plus the JSON document scalar parsing
|
|
||||||
foundation from `1.0.0-beta.21`, and the run manifest execution-report
|
|
||||||
hardening slice from `1.0.0-beta.22`, plus the standard-library stability tier
|
|
||||||
ledger and catalog alignment slice from `1.0.0-beta.23`, the package manifest
|
|
||||||
identity and local dependency diagnostic hardening slice from
|
|
||||||
`1.0.0-beta.24`, and the user-project conformance matrix evidence slice from
|
|
||||||
`1.0.0-beta.25`.
|
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
No active unreleased language scope is documented here yet.
|
No unreleased language scope is committed here yet.
|
||||||
|
|
||||||
## 1.0.0-beta.25
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.25`
|
|
||||||
|
|
||||||
Release name: User Project Conformance Matrix
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta tooling/conformance evidence on the `1.0.0-beta`
|
|
||||||
language baseline.
|
|
||||||
|
|
||||||
This release adds deterministic stable-readiness evidence for ordinary
|
|
||||||
project and workspace usage over the existing `examples/projects/` and
|
|
||||||
`examples/workspaces/` inventories. The conformance matrix records
|
|
||||||
repository-local example coverage for all 43 top-level fixture roots and 655
|
|
||||||
discovered tests through ordinary Glagol project/workspace entry points.
|
|
||||||
|
|
||||||
This release adds no source-language change, standard-library helper change,
|
|
||||||
runtime behavior change, compiler-known runtime names, package manager or
|
|
||||||
registry behavior, lockfile behavior, semantic-version solving, stable
|
|
||||||
artifact-manifest schema, stable Markdown schema, stable conformance-matrix
|
|
||||||
schema, stable ABI/layout, or performance claim.
|
|
||||||
|
|
||||||
## 1.0.0-beta.24
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.24`
|
|
||||||
|
|
||||||
Release name: Package Manifest Identity And Dependency Discipline
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta package/workspace diagnostic hardening on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
This release tightens diagnostics for local package manifests only. Duplicate
|
|
||||||
package manifest keys, invalid dependency keys, and duplicate dependency keys
|
|
||||||
are explicit beta package/workspace diagnostics.
|
|
||||||
|
|
||||||
The package model remains the existing closed local workspace model:
|
|
||||||
dependencies are local path records, dependency keys must match target package
|
|
||||||
names, and package-qualified imports still resolve through the local workspace
|
|
||||||
graph.
|
|
||||||
|
|
||||||
This release adds no remote registry, lockfile, semantic-version solving,
|
|
||||||
package publishing, optional/dev/target dependencies, stable package
|
|
||||||
ABI/layout, source-language syntax or semantics, runtime behavior,
|
|
||||||
standard-library helpers, compiler-known runtime names, stable manifest schema,
|
|
||||||
stable Markdown schema, or performance claim.
|
|
||||||
|
|
||||||
## 1.0.0-beta.23
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.23`
|
|
||||||
|
|
||||||
Release name: Standard Library Stability Tier Ledger And Catalog Alignment
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta documentation/catalog clarity on the `1.0.0-beta`
|
|
||||||
language baseline.
|
|
||||||
|
|
||||||
This release adds [`STDLIB_TIERS.md`](STDLIB_TIERS.md) as the public maturity
|
|
||||||
ledger for the generated [`STDLIB_API.md`](STDLIB_API.md) standard-library API
|
|
||||||
catalog. The ledger defines the tier labels `beta-supported`, `experimental`,
|
|
||||||
and `internal`.
|
|
||||||
|
|
||||||
The beta23 ledger classifies JSON, loopback networking, random/time, and
|
|
||||||
filesystem resource-handle helpers as experimental domains. Concrete vector
|
|
||||||
modules remain beta-supported concrete lanes; this is not a generic
|
|
||||||
collections freeze and does not imply executable generics, maps, sets,
|
|
||||||
iterators, mutable vectors, slice/view APIs, runtime collection changes, or
|
|
||||||
stable ABI/layout.
|
|
||||||
|
|
||||||
This release adds no source-language syntax, standard-library helpers,
|
|
||||||
compiler-known runtime names, runtime behavior, package behavior, stable
|
|
||||||
artifact-manifest schema, stable Markdown schema, stable ABI/layout, or stable
|
|
||||||
stdlib/API compatibility freeze. It does update generated catalog output and
|
|
||||||
the release gate so tier metadata is visible and checked.
|
|
||||||
|
|
||||||
## 1.0.0-beta.22
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.22`
|
|
||||||
|
|
||||||
Release name: Run Manifest And Execution Report Hardening
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta tooling/CLI evidence hardening on the `1.0.0-beta`
|
|
||||||
language baseline.
|
|
||||||
|
|
||||||
This release does not change the Slovo language or standard-library surface.
|
|
||||||
It documents the matching Glagol tooling update: `glagol run --manifest`
|
|
||||||
artifact manifests now include an additive run-report block for the executed
|
|
||||||
program's exit status, captured stdout, captured stderr, and forwarded program
|
|
||||||
arguments.
|
|
||||||
|
|
||||||
The run-report block is beta tooling metadata under the existing
|
|
||||||
`slovo.artifact-manifest` version `1` contract. It is not a stable manifest
|
|
||||||
schema freeze and does not add source-language syntax, stdlib helpers,
|
|
||||||
compiler-known runtime names, runtime C capabilities, package/import behavior,
|
|
||||||
stable ABI/layout guarantees, or stable stdlib/API compatibility.
|
|
||||||
|
|
||||||
## 1.0.0-beta.21
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.21`
|
|
||||||
|
|
||||||
Release name: JSON Document Scalar Parsing Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta standard-library JSON document scalar parsing foundation
|
|
||||||
on the `1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
The source facade adds these source-authored `std.json` helpers:
|
|
||||||
|
|
||||||
- `parse_string_document_result ((document string)) -> (result string i32)`
|
|
||||||
- `parse_bool_document_result ((document string)) -> (result bool i32)`
|
|
||||||
- `parse_i32_document_result ((document string)) -> (result i32 i32)`
|
|
||||||
- `parse_u32_document_result ((document string)) -> (result u32 i32)`
|
|
||||||
- `parse_i64_document_result ((document string)) -> (result i64 i32)`
|
|
||||||
- `parse_u64_document_result ((document string)) -> (result u64 i32)`
|
|
||||||
- `parse_f64_document_result ((document string)) -> (result f64 i32)`
|
|
||||||
- `parse_null_document_result ((document string)) -> (result bool i32)`
|
|
||||||
|
|
||||||
Each helper trims ASCII whitespace around the whole document with
|
|
||||||
`std.string.trim_ascii`, then delegates to the already released exact
|
|
||||||
value-token parser for that scalar family. Leading and trailing ASCII
|
|
||||||
whitespace around one scalar document is accepted; trailing non-whitespace
|
|
||||||
still returns `err 1` through the underlying exact parser.
|
|
||||||
|
|
||||||
This release adds no compiler-known runtime names, parser objects, object/array
|
|
||||||
parsing, recursive `JsonValue`, maps/sets, streaming, Unicode escape decoding
|
|
||||||
beyond the existing string-token behavior, embedded NUL policy, stable
|
|
||||||
ABI/layout guarantees, or stable stdlib/API freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.20
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.20`
|
|
||||||
|
|
||||||
Release name: String Search And ASCII Trim Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta standard-library string helper foundation on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
The source facade adds these source-authored `std.string` helpers:
|
|
||||||
|
|
||||||
- `contains ((value string) (needle string)) -> bool`
|
|
||||||
- `index_of_option ((value string) (needle string)) -> (option i32)`
|
|
||||||
- `last_index_of_option ((value string) (needle string)) -> (option i32)`
|
|
||||||
- `trim_ascii_start ((value string)) -> string`
|
|
||||||
- `trim_ascii_end ((value string)) -> string`
|
|
||||||
- `trim_ascii ((value string)) -> string`
|
|
||||||
|
|
||||||
Search remains byte-oriented over current runtime strings. Empty needles match:
|
|
||||||
`index_of_option` returns `some 0`, `last_index_of_option` returns
|
|
||||||
`some (len value)`, and `contains` returns `true`. Missing needles return
|
|
||||||
`none`.
|
|
||||||
|
|
||||||
The ASCII trim helpers remove only bytes `9`, `10`, `11`, `12`, `13`, and
|
|
||||||
`32` from the requested edges. This release adds no compiler-known runtime
|
|
||||||
names, Unicode/grapheme semantics, case folding, locale-sensitive matching,
|
|
||||||
regular expressions, tokenizer APIs, language slice/view syntax, mutable
|
|
||||||
strings, stable ABI/layout guarantees, or stable stdlib/API freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.19
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.19`
|
|
||||||
|
|
||||||
Release name: Test Discovery And User-Project Conformance Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta tooling/conformance foundation on the `1.0.0-beta`
|
|
||||||
language baseline.
|
|
||||||
|
|
||||||
The beta19 contract is tooling/conformance only. It adds deterministic test
|
|
||||||
discovery listing for:
|
|
||||||
|
|
||||||
- `glagol test --list <file|project|workspace>`
|
|
||||||
- `glagol --run-tests --list <file>` for the legacy single-file test path
|
|
||||||
|
|
||||||
List mode parses, lowers, type-checks, and discovers tests through the same
|
|
||||||
front-end path as normal test execution, then prints the discovered/selected
|
|
||||||
tests without evaluating their bodies. It preserves current single-file,
|
|
||||||
project, and workspace test ordering, honors `--filter <substring>`, and
|
|
||||||
leaves normal `glagol test` execution output unchanged.
|
|
||||||
|
|
||||||
This release does not add source-language syntax, runtime helper names, JSON
|
|
||||||
expansion, parallel test execution, retries, tags/groups, coverage reports,
|
|
||||||
event streams, stable manifest schemas, stable Markdown schemas, LSP/watch
|
|
||||||
behavior, SARIF/daemon protocols, package registries, semver solving, or
|
|
||||||
performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.18
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.18`
|
|
||||||
|
|
||||||
Release name: JSON String Token Parsing Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-23
|
|
||||||
|
|
||||||
Status: released beta JSON string-token parsing foundation on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
The source facade adds `std.json.parse_string_value_result`:
|
|
||||||
|
|
||||||
- signature: `(string) -> (result string i32)`
|
|
||||||
- input: one already-isolated ASCII JSON string token
|
|
||||||
- success: `ok decoded_text`
|
|
||||||
- ordinary parse failure: `err 1`
|
|
||||||
|
|
||||||
The helper requires exact surrounding quotes and no leading/trailing
|
|
||||||
whitespace. It decodes simple JSON escapes `\"`, `\\`, `\/`, `\b`, `\f`,
|
|
||||||
`\n`, `\r`, and `\t`. It rejects raw control bytes, bad escapes,
|
|
||||||
unterminated/trailing bytes, raw non-ASCII, and all `\uXXXX` escapes for this
|
|
||||||
slice.
|
|
||||||
|
|
||||||
This is string-token parsing only. It does not add object/array parsing,
|
|
||||||
recursive `JsonValue`, tokenizer APIs, generic parse APIs,
|
|
||||||
whitespace-tolerant document parsing, streaming, schema validation, Unicode
|
|
||||||
escape decoding or normalization, embedded NUL policy, stable ABI/layout, or a
|
|
||||||
stable stdlib/API freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.17
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.17`
|
|
||||||
|
|
||||||
Release name: JSON Primitive Scalar Parsing Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta primitive JSON scalar token parsing foundation on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.17` adds primitive scalar JSON token parse facades to `std.json`:
|
|
||||||
|
|
||||||
- `parse_bool_value_result`
|
|
||||||
- `parse_i32_value_result`
|
|
||||||
- `parse_u32_value_result`
|
|
||||||
- `parse_i64_value_result`
|
|
||||||
- `parse_u64_value_result`
|
|
||||||
- `parse_f64_value_result`
|
|
||||||
- `parse_null_value_result`
|
|
||||||
|
|
||||||
Numeric and boolean parse helpers consume one isolated JSON primitive token:
|
|
||||||
no leading/trailing whitespace, no leading `+`, no leading-zero integer form
|
|
||||||
except `0`, and no non-finite f64 values. `parse_null_value_result` is
|
|
||||||
source-only and returns `ok true` only for exact `null`.
|
|
||||||
|
|
||||||
This is primitive scalar token parsing only. Broader JSON parsing beyond the
|
|
||||||
beta.18 ASCII string-token helper, object/array parsing, recursive `JsonValue`,
|
|
||||||
tokenizers, generic parse APIs, whitespace-tolerant document parsing,
|
|
||||||
streaming, schema validation, Unicode escape handling, stable ABI/layout, or a
|
|
||||||
stable stdlib/API freeze remain deferred.
|
|
||||||
|
|
||||||
## 1.0.0-beta.16
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.16`
|
|
||||||
|
|
||||||
Release name: String Scanning And Token Boundary Foundation
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta string scanning and token-boundary foundation on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.16` adds the first explicit string scanning/token-boundary helper
|
|
||||||
surface:
|
|
||||||
|
|
||||||
- `std.string.byte_at_result : (string, i32) -> (result i32 i32)`
|
|
||||||
- `std.string.slice_result : (string, i32, i32) -> (result string i32)`
|
|
||||||
- `std.string.starts_with : (string, string) -> bool`
|
|
||||||
- `std.string.ends_with : (string, string) -> bool`
|
|
||||||
- matching `lib/std/string.slo` exports and explicit local/`std.string`
|
|
||||||
examples
|
|
||||||
|
|
||||||
The helpers are byte-oriented over the current NUL-terminated runtime string
|
|
||||||
representation and observe bytes before the trailing NUL. Invalid byte indexes
|
|
||||||
or ranges return `err 1`. `slice_result` returns a runtime-owned string on
|
|
||||||
success; allocation failure may follow the existing string allocation trap
|
|
||||||
policy.
|
|
||||||
|
|
||||||
This release does not add Unicode scalar, grapheme, display-width, or locale
|
|
||||||
semantics; full JSON parsing; object or array parsing; tokenizer/scanner
|
|
||||||
objects; a language slice/view feature; mutable strings; string containers;
|
|
||||||
stable ABI/layout; or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.15
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.15`
|
|
||||||
|
|
||||||
Release name: Reserved Generic Collection Boundary Hardening And Collection Ledger
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta docs/design ledger and compiler-boundary hardening
|
|
||||||
update on the `1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.15` documents the current concrete collection and value-family
|
|
||||||
boundary without changing executable behavior:
|
|
||||||
|
|
||||||
- Adds [`COLLECTIONS.md`](COLLECTIONS.md) as the collection/value-family
|
|
||||||
ledger.
|
|
||||||
- Links to the generated [`STDLIB_API.md`](STDLIB_API.md) catalog for exact
|
|
||||||
public helper signatures instead of duplicating generated helper counts.
|
|
||||||
- Inventories the current concrete vector, option, result, and related
|
|
||||||
option/result-returning facade surfaces.
|
|
||||||
- Records design pressure from duplicated concrete vector, option, and result
|
|
||||||
helper families.
|
|
||||||
- Defines prerequisites before executable generics, generic aliases, maps,
|
|
||||||
sets, iterators, mutable vectors, or slice/view APIs can be promoted.
|
|
||||||
- Documents current unsupported diagnostics as boundaries, not behavior
|
|
||||||
changes.
|
|
||||||
- Centralizes reserved generic/map/set diagnostics and rewords affected
|
|
||||||
reserved-boundary messages from beta.9-specific text to current-beta wording
|
|
||||||
while preserving diagnostic codes, schema, spans, expected/found values,
|
|
||||||
hints, and output shape.
|
|
||||||
|
|
||||||
This release does not change the source language, typed core, runtime,
|
|
||||||
stdlib/API surface, diagnostic output shape, diagnostic codes, diagnostic
|
|
||||||
schema, benchmark metadata schema, compiler-known runtime names, ABI/layout
|
|
||||||
behavior, optimizer behavior, or performance claims. It does not add
|
|
||||||
executable generics, generic aliases, maps, sets, iterators, mutable vectors,
|
|
||||||
slice/view APIs, new runtime names, or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
## 1.0.0-beta.14
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.14`
|
|
||||||
|
|
||||||
Release name: Benchmark Suite Catalog And Metadata Gate
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta documentation/tooling metadata update on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.14` documents the existing benchmark suite catalog and metadata
|
|
||||||
gate without changing the source language, runtime, standard library, API
|
|
||||||
surface, diagnostic output, compiler-known runtime names, or ABI/layout
|
|
||||||
behavior:
|
|
||||||
|
|
||||||
- Adds [`benchmarks/README.md`](../../benchmarks/README.md) as the top-level
|
|
||||||
catalog for the current ten benchmark suites:
|
|
||||||
`math-loop`, `branch-loop`, `parse-loop`, `array-index-loop`,
|
|
||||||
`string-eq-loop`, `array-struct-field-loop`,
|
|
||||||
`enum-struct-payload-loop`, `vec-i32-index-loop`,
|
|
||||||
`vec-string-eq-loop`, and `json-quote-loop`.
|
|
||||||
- Documents `python3 benchmarks/runner.py --suite-list` as the non-JSON suite
|
|
||||||
inventory command.
|
|
||||||
- Documents `python3 benchmarks/runner.py --suite-list --json` as the beta
|
|
||||||
tooling metadata form for local gates and adapters.
|
|
||||||
- States that benchmark timings are local-machine evidence only and publishes
|
|
||||||
no timing numbers.
|
|
||||||
- Records that suite-list JSON is beta tooling metadata, not a stable public
|
|
||||||
schema.
|
|
||||||
|
|
||||||
This release does not add benchmark kernels, publish timings, define
|
|
||||||
performance thresholds, define a stable JSON schema, change source-language,
|
|
||||||
runtime, stdlib/API, diagnostic-output, compiler ABI/layout, or optimizer
|
|
||||||
behavior, or make cross-machine performance claims.
|
|
||||||
|
|
||||||
## 1.0.0-beta.13
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.13`
|
|
||||||
|
|
||||||
Release name: Diagnostic Catalog And Schema Policy
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta documentation/tooling policy update on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.13` documents the existing diagnostic machine contract without
|
|
||||||
changing the source language, runtime, standard library, CLI, or diagnostic
|
|
||||||
output shape:
|
|
||||||
|
|
||||||
- Adds [`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md) as the beta
|
|
||||||
`slovo.diagnostic` version `1` policy.
|
|
||||||
- Documents the S-expression and JSON relationship, required and optional
|
|
||||||
fields, severity/source/range/related-span semantics, JSON-line discipline,
|
|
||||||
source-less diagnostics, and artifact-manifest diagnostic metadata.
|
|
||||||
- Defines compatibility and migration classes for diagnostic machine fields
|
|
||||||
and codes. Human-readable prose remains beta-flexible unless a release
|
|
||||||
intentionally changes machine fields, schema/version markers, codes, or
|
|
||||||
golden fixture shape.
|
|
||||||
- Inventories the 114 current diagnostic codes covered by the 358-snapshot
|
|
||||||
golden diagnostics contract in `compiler/tests/diagnostics_contract.rs`.
|
|
||||||
|
|
||||||
This release does not add LSP/watch behavior, SARIF, daemon protocols, stable
|
|
||||||
Markdown schema, stable `1.0.0` diagnostics freeze, source-language/runtime
|
|
||||||
changes, stdlib/API changes, or ABI/layout promises.
|
|
||||||
|
|
||||||
## 1.0.0-beta.12
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.12`
|
|
||||||
|
|
||||||
Release name: Concrete Vector Query And Prefix Parity
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta stdlib/helper parity update on the `1.0.0-beta`
|
|
||||||
language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.12` is a source-authored concrete vector helper release. It closes
|
|
||||||
small parity gaps in the current concrete vector facades without changing the
|
|
||||||
language, typed core, runtime, ABI, or compiler-known `std.vec.*` runtime
|
|
||||||
names:
|
|
||||||
|
|
||||||
- `std.vec_i64` gains `count_of`, `starts_with`, `without_prefix`,
|
|
||||||
`ends_with`, and `without_suffix`.
|
|
||||||
- `std.vec_f64` gains `count_of`.
|
|
||||||
- The helper behavior stays source-authored over the existing concrete vector
|
|
||||||
runtime names, current equality, `len`, `at`, `take`, `drop`, and recursive
|
|
||||||
helper style.
|
|
||||||
- Focused Glagol fixture coverage exercises repeated `count_of` results and
|
|
||||||
prefix/suffix empty, mismatch, exact, and longer-than-input cases where the
|
|
||||||
helper family applies.
|
|
||||||
|
|
||||||
This release does not add executable generics, maps, sets, iterators, mutable
|
|
||||||
vectors, slice/view APIs, new runtime names, new compiler-known stdlib names,
|
|
||||||
ABI/layout stability, performance claims, stable stdlib API freeze, generic
|
|
||||||
stdlib dispatch, or broad collection abstractions.
|
|
||||||
|
|
||||||
## 1.0.0-beta.11
|
|
||||||
|
|
||||||
Release label: `1.0.0-beta.11`
|
|
||||||
|
|
||||||
Release name: Local Package API Documentation
|
|
||||||
|
|
||||||
Release date: 2026-05-22
|
|
||||||
|
|
||||||
Status: released beta documentation/API-discovery update on the
|
|
||||||
`1.0.0-beta` language baseline.
|
|
||||||
|
|
||||||
`1.0.0-beta.11` extends the beta.10 API discovery lane from the generated
|
|
||||||
standard-library catalog and `glagol symbols` metadata into local package and
|
|
||||||
module documentation:
|
|
||||||
|
|
||||||
- `glagol doc <file|project|workspace> -o <dir>` includes deterministic
|
|
||||||
exported/public API sections for local source files, projects, packages, and
|
|
||||||
workspaces.
|
|
||||||
- Public API sections list exact exported function signatures, exported struct
|
|
||||||
fields, and exported enum variants with payload types.
|
|
||||||
- Module-local concrete aliases are normalized before public rendering, so
|
|
||||||
local names do not leak into package/module API docs.
|
|
||||||
- Non-exported functions, structs, enums, tests, and `(type ...)` aliases
|
|
||||||
remain omitted from the public API surface.
|
|
||||||
|
|
||||||
This release does not define a stable Markdown schema, stable stdlib/API
|
|
||||||
compatibility freeze, LSP server, watch mode, SARIF, daemon protocols,
|
|
||||||
diagnostics schema policy, executable generics, maps, sets, re-exports, globs,
|
|
||||||
hierarchical modules, package registry semantics, runtime changes, new
|
|
||||||
compiler-known runtime names, or stable ABI/layout promises.
|
|
||||||
|
|
||||||
## 1.0.0-beta.10
|
## 1.0.0-beta.10
|
||||||
|
|
||||||
|
|||||||
@ -5,138 +5,37 @@ compiler implementation inside the same monorepo.
|
|||||||
|
|
||||||
Guiding rule: the manifest wins. A feature is not accepted until it has surface syntax, typed-core meaning, lowering behavior, formatter behavior, diagnostics, and tests.
|
Guiding rule: the manifest wins. A feature is not accepted until it has surface syntax, typed-core meaning, lowering behavior, formatter behavior, diagnostics, and tests.
|
||||||
|
|
||||||
Long-horizon planning lives in `.llm/ROADMAP_TO_STABLE.md`. It defines the
|
Long-horizon planning lives in
|
||||||
release train beyond the first real general-purpose beta Slovo contract.
|
`.llm/GENERAL_PURPOSE_LANGUAGE_ROADMAP.md`. It defines the experimental
|
||||||
|
release train from the historical `v2.0.0-beta.1` tag toward and beyond the
|
||||||
|
first real general-purpose beta Slovo contract.
|
||||||
|
|
||||||
Current stage: `1.0.0-beta.25`, released on 2026-05-23 as post-beta
|
Current stage: `1.0.0-beta.10`, released on 2026-05-22 as the first post-beta
|
||||||
user-project conformance matrix evidence. It keeps the `1.0.0-beta` language
|
developer-experience API discovery update. It keeps the `1.0.0-beta` language contract and
|
||||||
contract and includes the `1.0.0-beta.1` tooling
|
includes the `1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2`
|
||||||
hardening release, the
|
runtime/resource foundation release, the `1.0.0-beta.3` standard-library
|
||||||
`1.0.0-beta.2` runtime/resource foundation release, the `1.0.0-beta.3`
|
stabilization release, the `1.0.0-beta.4` language-usability diagnostics
|
||||||
standard-library stabilization release, the `1.0.0-beta.4`
|
release, the `1.0.0-beta.5` package/workspace discipline release, and a narrow
|
||||||
language-usability diagnostics release, the `1.0.0-beta.5` package/workspace
|
`std.net` source facade for blocking loopback TCP client/server primitives over
|
||||||
discipline release, the `1.0.0-beta.6` loopback networking foundation,
|
opaque `i32` handles and concrete `result` families, plus a narrow `std.json`
|
||||||
`1.0.0-beta.7` compact JSON text construction, `1.0.0-beta.8` concrete type
|
source facade for compact JSON text construction, plus top-level module-local
|
||||||
aliases, `1.0.0-beta.9` collection alias unification and generic reservation,
|
transparent aliases for supported concrete target types, plus local alias use
|
||||||
`1.0.0-beta.10` API discovery, `1.0.0-beta.11` local package API
|
inside the current concrete vector, option, and result facades, plus a
|
||||||
documentation, `1.0.0-beta.12` concrete vector helper parity,
|
generated standard-library API catalog that lists exact exported helper
|
||||||
`1.0.0-beta.13` diagnostic catalog and schema policy, `1.0.0-beta.14`
|
signatures with module-local aliases normalized to concrete public types, plus
|
||||||
benchmark suite catalog and metadata gate, `1.0.0-beta.15` reserved generic
|
`glagol symbols` deterministic source metadata for files, projects, and
|
||||||
collection boundary hardening and collection ledger, and `1.0.0-beta.16`
|
workspaces. JSON
|
||||||
string scanning and token boundary helpers, `1.0.0-beta.17` JSON primitive
|
parsing, recursive JSON values, executable generics, generic aliases,
|
||||||
scalar token parsing, `1.0.0-beta.18` JSON string token parsing,
|
parameterized aliases, cross-module alias visibility, maps/sets, traits,
|
||||||
`1.0.0-beta.19` test discovery and user-project conformance tooling, and
|
inference, monomorphization, iterators, runtime changes for generic
|
||||||
`1.0.0-beta.20` string search and ASCII trim helpers, plus
|
collections, DNS, TLS, UDP, async IO, non-loopback binding, HTTP frameworks,
|
||||||
`1.0.0-beta.21` JSON document scalar parsing helpers, and
|
rich host-error ADTs, stable ABI/layout, and a stable standard-library API
|
||||||
`1.0.0-beta.22` run manifest execution-report hardening, plus
|
freeze remain deferred.
|
||||||
`1.0.0-beta.23` standard-library stability tier documentation,
|
|
||||||
`1.0.0-beta.24` package manifest/dependency diagnostic hardening, and
|
|
||||||
`1.0.0-beta.25` user-project conformance matrix evidence.
|
|
||||||
|
|
||||||
`1.0.0-beta.16` adds `std.string` source facades and examples for
|
Next stage target: continue from developer-experience and reserved
|
||||||
`byte_at_result`, `slice_result`, `starts_with`, and `ends_with`. These helpers
|
generic/map/set diagnostics without claiming executable generics, an LSP/watch
|
||||||
are byte-oriented over the current NUL-terminated runtime string
|
protocol, or stable standard-library APIs until the exact scope is frozen from
|
||||||
representation; invalid indexes and ranges return `err 1`, and substring
|
the manifest and roadmap.
|
||||||
allocation failure may use the existing string allocation trap policy.
|
|
||||||
`1.0.0-beta.16` does not add Unicode scalar, grapheme, display-width, or locale
|
|
||||||
semantics; full JSON parsing; object/array parsing; tokenizer objects;
|
|
||||||
language slice/view syntax; mutable strings; stable ABI/layout; performance
|
|
||||||
claims; or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
The current released JSON stage adds primitive scalar JSON token parse facades
|
|
||||||
for booleans, concrete numeric primitives, exact `null`, one narrow ASCII JSON
|
|
||||||
string-token helper, and scalar JSON document helpers that accept leading and
|
|
||||||
trailing ASCII whitespace. Object/array parsing, recursive JSON values,
|
|
||||||
tokenizers, schema validation, streaming, Unicode escape
|
|
||||||
decoding/normalization beyond the existing string-token helper, embedded NUL
|
|
||||||
policy, stable ABI/layout, and stable stdlib/API freeze remain deferred.
|
|
||||||
|
|
||||||
Full JSON parsing, object/array parsing, recursive JSON values,
|
|
||||||
executable generics, generic aliases, parameterized aliases, cross-module
|
|
||||||
alias visibility, maps/sets, traits, inference, monomorphization, iterators,
|
|
||||||
runtime changes for generic collections, DNS, TLS, UDP, async IO,
|
|
||||||
non-loopback binding, HTTP frameworks, rich host-error ADTs, stable ABI/layout,
|
|
||||||
stable Markdown schema, stable stdlib/API compatibility freeze, LSP/watch,
|
|
||||||
SARIF/daemon protocols, stable `1.0.0` diagnostics freeze,
|
|
||||||
re-exports/globs/hierarchical modules, mutable vectors, language slice/view
|
|
||||||
APIs, additional runtime names, Unicode/grapheme string semantics, timing
|
|
||||||
publication, performance claims, stable benchmark JSON schema, and package
|
|
||||||
registry semantics remain deferred.
|
|
||||||
|
|
||||||
`1.0.0-beta.19` is a tooling/conformance slice, not a new source-language
|
|
||||||
feature. It adds the `glagol test --list <file|project|workspace>` command
|
|
||||||
plus legacy `glagol --run-tests --list <file>`: parse, lower, type-check, and
|
|
||||||
discover tests through the same front-end path as normal test execution, then
|
|
||||||
list the discovered/selected tests without evaluating test bodies. The mode
|
|
||||||
preserves current single-file, project, and workspace ordering, honors
|
|
||||||
`--filter <substring>`, and leaves normal `glagol test` execution behavior
|
|
||||||
unchanged.
|
|
||||||
|
|
||||||
The beta19 tooling scope does not claim executable generics, maps/sets,
|
|
||||||
iterators, runtime helper names, source-language syntax, JSON expansion,
|
|
||||||
parallel test execution, retries, tags/groups, coverage/event streams,
|
|
||||||
LSP/watch protocols, SARIF/daemon protocols, stable artifact-manifest or
|
|
||||||
Markdown schemas, stable benchmark JSON schema, stable `1.0.0` diagnostics
|
|
||||||
freeze, stable standard-library/API compatibility freeze, registry semantics,
|
|
||||||
semver solving, performance claims, mutable vectors, language slice/view APIs,
|
|
||||||
additional runtime names, or Unicode/grapheme semantics.
|
|
||||||
|
|
||||||
`1.0.0-beta.20` adds source-authored `std.string` helpers for byte-oriented
|
|
||||||
`contains`, first/last index option search, and ASCII edge trimming over bytes
|
|
||||||
`9`, `10`, `11`, `12`, `13`, and `32`. Empty needles match at first index `0`
|
|
||||||
and last index `(len value)`. The scope adds no compiler-known runtime names,
|
|
||||||
Unicode/grapheme semantics, case folding, regexes, tokenizer APIs, language
|
|
||||||
slice/view syntax, mutable strings, stable ABI/layout guarantees, or stable
|
|
||||||
stdlib/API freeze.
|
|
||||||
|
|
||||||
`1.0.0-beta.21` adds source-authored
|
|
||||||
`std.json.parse_*_document_result` helpers for string, bool, `i32`, `u32`,
|
|
||||||
`i64`, `u64`, `f64`, and exact `null` documents by trimming ASCII whitespace
|
|
||||||
around the whole document with `std.string.trim_ascii`, then delegating to the
|
|
||||||
existing exact value-token parser for each scalar family. The scope keeps
|
|
||||||
object/array parsing, recursive JSON values, tokenizer objects, maps/sets,
|
|
||||||
streaming, new compiler-known runtime names, Unicode escape decoding beyond
|
|
||||||
the existing string-token helper, embedded NUL policy, stable ABI/layout, and
|
|
||||||
stable stdlib/API freeze deferred.
|
|
||||||
|
|
||||||
`1.0.0-beta.22` is tooling/CLI evidence hardening, not a language feature. It
|
|
||||||
documents the matching Glagol `run --manifest` update: run-mode artifact
|
|
||||||
manifests gain an additive run-report block for executed-program exit status,
|
|
||||||
captured stdout, captured stderr, and forwarded program arguments. The block is
|
|
||||||
beta tooling metadata under the existing `slovo.artifact-manifest` version `1`
|
|
||||||
contract. It is not a stable schema freeze and adds no language syntax,
|
|
||||||
standard-library helpers, runtime capabilities, package/import behavior,
|
|
||||||
stable ABI/layout, or stable stdlib/API guarantees.
|
|
||||||
|
|
||||||
`1.0.0-beta.23` is documentation/catalog clarity, not a language or stdlib
|
|
||||||
behavior feature. It adds [`STDLIB_TIERS.md`](STDLIB_TIERS.md) as the public
|
|
||||||
stability-tier ledger beside the generated [`STDLIB_API.md`](STDLIB_API.md)
|
|
||||||
signature catalog. The ledger defines `beta-supported`, `experimental`, and
|
|
||||||
`internal`; marks JSON, loopback networking, random/time, and filesystem
|
|
||||||
resource-handle helpers as experimental domains; and keeps concrete vector
|
|
||||||
modules as beta-supported concrete lanes rather than a generic collections
|
|
||||||
freeze. It adds no source-language syntax, helpers, runtime names, runtime
|
|
||||||
behavior, stable manifest schema, stable Markdown schema, stable ABI/layout,
|
|
||||||
or stable stdlib/API freeze. It does update generated catalog output and the
|
|
||||||
release gate so tier metadata is visible and checked.
|
|
||||||
|
|
||||||
`1.0.0-beta.24` is package/workspace diagnostic hardening, not a language,
|
|
||||||
runtime, package-manager, or stdlib behavior feature. It makes duplicate
|
|
||||||
package manifest keys, invalid dependency keys, and duplicate dependency keys
|
|
||||||
explicit diagnostics while keeping the existing closed local workspace model.
|
|
||||||
It adds no remote registry, lockfile, semantic-version solving, package
|
|
||||||
publishing, optional/dev/target dependencies, stable package ABI/layout,
|
|
||||||
source-language change, runtime change, or stdlib change.
|
|
||||||
|
|
||||||
`1.0.0-beta.25` is tooling/conformance evidence, not a language, stdlib,
|
|
||||||
runtime, package-manager, schema-freeze, or performance feature. It adds a
|
|
||||||
deterministic user-project conformance matrix over the existing
|
|
||||||
`examples/projects/` and `examples/workspaces/` inventories so ordinary
|
|
||||||
project and workspace usage has stable-readiness evidence. The release covers
|
|
||||||
all 43 top-level fixture roots and 655 discovered tests. It adds no
|
|
||||||
source-language change, standard-library helper change, runtime behavior
|
|
||||||
change, package manager or registry behavior, lockfile behavior,
|
|
||||||
semantic-version solving, stable schema freeze, or performance claim.
|
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`, defined in
|
The final experimental precursor scope is `exp-125`, defined in
|
||||||
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
||||||
@ -3104,9 +3003,8 @@ exp-20 f64 numeric primitive alpha decisions:
|
|||||||
|
|
||||||
## Phase 8: Improve v1 Tooling Contracts
|
## Phase 8: Improve v1 Tooling Contracts
|
||||||
|
|
||||||
- [x] Define `slovo.diagnostic` version `1` as the current v1 machine
|
- [x] Define `slovo.diagnostic` version `1` as the stable v1 machine
|
||||||
diagnostic schema, with beta policy and catalog details in
|
diagnostic schema.
|
||||||
[`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md).
|
|
||||||
- [x] Define the v1 direction for preserving source spans through LLVM IR
|
- [x] Define the v1 direction for preserving source spans through LLVM IR
|
||||||
emission while deferring stable debug metadata and source-map files.
|
emission while deferring stable debug metadata and source-map files.
|
||||||
- [x] Define `slovo.artifact-manifest` version `1` for compiler outputs and
|
- [x] Define `slovo.artifact-manifest` version `1` for compiler outputs and
|
||||||
|
|||||||
@ -2,21 +2,9 @@
|
|||||||
|
|
||||||
Status: living beta contract for `1.0.0-beta`, with the post-beta
|
Status: living beta contract for `1.0.0-beta`, with the post-beta
|
||||||
`1.0.0-beta.1` tooling/install update, `1.0.0-beta.2` runtime/resource
|
`1.0.0-beta.1` tooling/install update, `1.0.0-beta.2` runtime/resource
|
||||||
foundation update, `1.0.0-beta.10` developer-experience API discovery update,
|
foundation update, and `1.0.0-beta.10` developer-experience API discovery
|
||||||
`1.0.0-beta.11` local package API documentation update, and `1.0.0-beta.12`
|
update. The language contract integrates
|
||||||
concrete vector query and prefix parity update, and `1.0.0-beta.13`
|
promoted language slices through `exp-125` and the historical publication
|
||||||
diagnostic catalog and schema policy update, and `1.0.0-beta.14` benchmark
|
|
||||||
suite catalog and metadata gate, `1.0.0-beta.15` reserved generic collection
|
|
||||||
boundary hardening and collection ledger, `1.0.0-beta.16` string scanning
|
|
||||||
and token boundary foundation, `1.0.0-beta.17` JSON primitive scalar parsing
|
|
||||||
foundation, `1.0.0-beta.18` JSON string token parsing foundation,
|
|
||||||
`1.0.0-beta.19` test discovery and user-project conformance tooling, and
|
|
||||||
`1.0.0-beta.20` string search and ASCII trim foundation, and
|
|
||||||
`1.0.0-beta.21` JSON document scalar parsing foundation, and
|
|
||||||
`1.0.0-beta.22` run manifest and execution-report hardening, and
|
|
||||||
`1.0.0-beta.23` standard-library stability tier ledger and catalog alignment.
|
|
||||||
The language contract integrates promoted language slices through `exp-125`
|
|
||||||
and the historical publication
|
|
||||||
baseline through `exp-123`. `1.0.0-beta` is the first real general-purpose
|
baseline through `exp-123`. `1.0.0-beta` is the first real general-purpose
|
||||||
beta release. `exp-125` completed the unsigned numeric and stdlib breadth
|
beta release. `exp-125` completed the unsigned numeric and stdlib breadth
|
||||||
precursor scope, `exp-124` is the last tagged experimental alpha language
|
precursor scope, `exp-124` is the last tagged experimental alpha language
|
||||||
@ -141,142 +129,6 @@ Current v1 release surface and explicit experimental targets:
|
|||||||
for files, projects, and workspaces; this is beta API discovery only, not
|
for files, projects, and workspaces; this is beta API discovery only, not
|
||||||
executable generics, maps, sets, runtime changes, LSP/watch, or a stable
|
executable generics, maps, sets, runtime changes, LSP/watch, or a stable
|
||||||
`1.0.0` standard-library freeze
|
`1.0.0` standard-library freeze
|
||||||
- `1.0.0-beta.11` local package API documentation target:
|
|
||||||
`glagol doc <file|project|workspace> -o <dir>` includes deterministic
|
|
||||||
exported/public API sections for local packages and modules with exact
|
|
||||||
exported function signatures, exported struct fields, exported enum
|
|
||||||
variants/payload types, non-export filtering, and module-local alias
|
|
||||||
normalization; this remains beta API discovery only, not a stable Markdown
|
|
||||||
schema, stable stdlib/API
|
|
||||||
compatibility freeze, LSP/watch contract, SARIF/daemon protocol, diagnostics
|
|
||||||
schema policy, executable generics, maps/sets, re-exports, globs,
|
|
||||||
hierarchical modules, or registry semantics
|
|
||||||
- `1.0.0-beta.12` concrete vector query and prefix parity target:
|
|
||||||
source-authored `std.vec_i64` gains `count_of`, `starts_with`,
|
|
||||||
`without_prefix`, `ends_with`, and `without_suffix`; source-authored
|
|
||||||
`std.vec_f64` gains `count_of`; this is helper parity over the current
|
|
||||||
concrete vector runtime names only, not a source-language/runtime change,
|
|
||||||
executable generics, maps/sets, iterators, mutable vectors, slice/view APIs,
|
|
||||||
new runtime names, ABI/layout stability, performance claims, or a stable
|
|
||||||
stdlib API freeze
|
|
||||||
- `1.0.0-beta.13` diagnostic catalog and schema policy target:
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md) documents the existing
|
|
||||||
`slovo.diagnostic` version `1` beta policy, S-expression/JSON relationship,
|
|
||||||
required and optional fields, JSON-line discipline, source-less diagnostics,
|
|
||||||
artifact-manifest diagnostic metadata, compatibility/migration classes, and
|
|
||||||
current golden diagnostic code catalog; this is docs/tooling policy only, not
|
|
||||||
a source-language/runtime change, LSP/watch contract, SARIF/daemon protocol,
|
|
||||||
stable Markdown schema, or stable `1.0.0` diagnostics freeze
|
|
||||||
- `1.0.0-beta.14` benchmark suite catalog and metadata target:
|
|
||||||
[`benchmarks/README.md`](../../benchmarks/README.md) documents the existing
|
|
||||||
benchmark suite inventory and root suite-list commands:
|
|
||||||
`python3 benchmarks/runner.py --suite-list` and
|
|
||||||
`python3 benchmarks/runner.py --suite-list --json`; benchmark timing remains
|
|
||||||
local-machine evidence only, and suite-list JSON is beta tooling metadata
|
|
||||||
only, not a stable public schema; this is docs/tooling metadata only, not new
|
|
||||||
benchmark kernels, timing publication, performance thresholds,
|
|
||||||
source-language/runtime/stdlib/API changes, diagnostic-output changes, or
|
|
||||||
ABI/layout changes
|
|
||||||
- `1.0.0-beta.15` reserved generic collection boundary hardening target:
|
|
||||||
[`COLLECTIONS.md`](COLLECTIONS.md) documents the current concrete collection
|
|
||||||
and value-family boundary by linking to the generated
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md) catalog for exact helper signatures,
|
|
||||||
recording design pressure from duplicated concrete vector/option/result
|
|
||||||
families, defining promotion prerequisites for executable generics, generic
|
|
||||||
aliases, maps, sets, iterators, mutable vectors, and slice/view APIs, and
|
|
||||||
treating current unsupported diagnostics as boundaries; this is docs/design
|
|
||||||
and compiler-boundary hardening only, not a source-language, runtime,
|
|
||||||
stdlib/API, diagnostic output shape, diagnostic code, diagnostic schema,
|
|
||||||
diagnostic span, expected/found value, hint, benchmark metadata schema,
|
|
||||||
ABI/layout, performance-claim, or stable stdlib/API change; affected
|
|
||||||
reserved-boundary messages are reworded from beta.9-specific text to
|
|
||||||
current-beta wording
|
|
||||||
- `1.0.0-beta.16` string scanning and token boundary target:
|
|
||||||
`std.string.byte_at_result`, `std.string.slice_result`,
|
|
||||||
`std.string.starts_with`, and `std.string.ends_with` provide byte-oriented
|
|
||||||
scanning helpers over the current NUL-terminated runtime string
|
|
||||||
representation; invalid indexes and ranges return `err 1`, substring
|
|
||||||
allocation failure may follow the existing string allocation trap policy, and
|
|
||||||
this target does not add Unicode/grapheme/display-width semantics, JSON
|
|
||||||
parsing, object/array parsing, tokenizer objects, language slice/view syntax,
|
|
||||||
mutable strings, stable ABI/layout, performance claims, or a stable
|
|
||||||
stdlib/API freeze
|
|
||||||
- `1.0.0-beta.17` JSON primitive scalar parsing target:
|
|
||||||
`std.json.parse_bool_value_result`,
|
|
||||||
`std.json.parse_i32_value_result`, `std.json.parse_u32_value_result`,
|
|
||||||
`std.json.parse_i64_value_result`, `std.json.parse_u64_value_result`,
|
|
||||||
`std.json.parse_f64_value_result`, and `std.json.parse_null_value_result`
|
|
||||||
consume one already-isolated primitive scalar token and return concrete
|
|
||||||
`(result ... i32)` values; JSON document parsing beyond the beta21 scalar
|
|
||||||
helpers, string/object/array parsing, tokenizers, recursive `JsonValue`,
|
|
||||||
Unicode escape handling, stable ABI/layout, performance claims, and stable
|
|
||||||
stdlib/API freeze remain out of scope
|
|
||||||
- `1.0.0-beta.18` JSON string token parsing target:
|
|
||||||
`std.json.parse_string_value_result : (string) -> (result string i32)`
|
|
||||||
consumes one already-isolated ASCII JSON string token with exact quotes and
|
|
||||||
no leading/trailing whitespace, decodes simple JSON escapes, returns
|
|
||||||
`err 1` for ordinary parse failure, and rejects raw control bytes, bad
|
|
||||||
escapes, unterminated/trailing bytes, raw non-ASCII, and all `\uXXXX` escapes
|
|
||||||
for this slice; JSON document parsing beyond the beta21 scalar helpers,
|
|
||||||
object/array parsing, tokenizer APIs, recursive `JsonValue`, Unicode escape
|
|
||||||
decoding/normalization, embedded NUL policy, stable ABI/layout, performance
|
|
||||||
claims, and stable stdlib/API freeze remain out of scope
|
|
||||||
- `1.0.0-beta.19` test discovery and user-project conformance target:
|
|
||||||
`glagol test --list <file|project|workspace>` and legacy
|
|
||||||
`glagol --run-tests --list <file>` list checked/discovered tests without
|
|
||||||
executing test bodies; list mode preserves current test ordering, honors
|
|
||||||
`--filter <substring>`, and remains beta tooling rather than a stable
|
|
||||||
schema. This target does not add source-language syntax, runtime helper
|
|
||||||
names, JSON expansion, parallel test execution, retries, tags/groups,
|
|
||||||
coverage/event streams, stable artifact-manifest or Markdown schemas,
|
|
||||||
LSP/watch behavior, SARIF/daemon protocols, package registries, semver
|
|
||||||
solving, or performance claims
|
|
||||||
- `1.0.0-beta.20` string search and ASCII trim target:
|
|
||||||
source-authored `std.string.contains`, `std.string.index_of_option`,
|
|
||||||
`std.string.last_index_of_option`, `std.string.trim_ascii_start`,
|
|
||||||
`std.string.trim_ascii_end`, and `std.string.trim_ascii` compose over the
|
|
||||||
existing byte-oriented string primitives; search is byte-oriented, missing
|
|
||||||
needles return `none`, empty needles match at first index `0` and last index
|
|
||||||
`(len value)`, and trim removes only bytes `9`, `10`, `11`, `12`, `13`, and
|
|
||||||
`32` from the requested edges. This target does not add compiler-known
|
|
||||||
runtime names, Unicode/grapheme semantics, case folding, locale-sensitive
|
|
||||||
matching, regex, tokenizer APIs, language slice/view syntax, mutable
|
|
||||||
strings, stable ABI/layout, performance claims, or stable stdlib/API freeze
|
|
||||||
- `1.0.0-beta.21` JSON document scalar parsing:
|
|
||||||
source-authored `std.json.parse_string_document_result`,
|
|
||||||
`std.json.parse_bool_document_result`,
|
|
||||||
`std.json.parse_i32_document_result`,
|
|
||||||
`std.json.parse_u32_document_result`,
|
|
||||||
`std.json.parse_i64_document_result`,
|
|
||||||
`std.json.parse_u64_document_result`,
|
|
||||||
`std.json.parse_f64_document_result`, and
|
|
||||||
`std.json.parse_null_document_result` trim ASCII whitespace around the whole
|
|
||||||
document with `std.string.trim_ascii`, then delegate to the existing exact
|
|
||||||
value-token parsers for one scalar JSON document. This target does not add
|
|
||||||
compiler-known runtime names, object/array parsing, recursive `JsonValue`,
|
|
||||||
parser/tokenizer objects, maps/sets, streaming, Unicode escape decoding
|
|
||||||
beyond the existing string-token behavior, embedded NUL policy,
|
|
||||||
ABI/layout guarantees, performance claims, or stable stdlib/API freeze
|
|
||||||
- `1.0.0-beta.22` run manifest and execution-report hardening:
|
|
||||||
`glagol run --manifest` artifact manifests include an additive run-report
|
|
||||||
block after a supported program executes. The block records the executed
|
|
||||||
program exit status, captured stdout, captured stderr, and forwarded
|
|
||||||
program arguments. This target is beta tooling evidence only; it does not
|
|
||||||
add source-language syntax, stdlib helpers, compiler-known runtime names,
|
|
||||||
runtime C capabilities, package/import behavior, stable artifact-manifest
|
|
||||||
schema guarantees, stable ABI/layout, or stable stdlib/API freeze
|
|
||||||
- `1.0.0-beta.23` standard-library stability tier ledger and catalog
|
|
||||||
alignment:
|
|
||||||
[`STDLIB_TIERS.md`](STDLIB_TIERS.md) defines the public tier labels
|
|
||||||
`beta-supported`, `experimental`, and `internal` beside the generated
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md) signature catalog. JSON, loopback
|
|
||||||
networking, random/time, and filesystem resource-handle helpers are
|
|
||||||
experimental domains. Concrete vector modules remain beta-supported concrete
|
|
||||||
lanes, not a generic collections freeze. This target does not add
|
|
||||||
source-language syntax, stdlib helpers, compiler-known runtime names,
|
|
||||||
runtime behavior, stable artifact-manifest schema, stable Markdown schema,
|
|
||||||
stable ABI/layout, or stable stdlib/API freeze. It does update generated
|
|
||||||
catalog output and the release gate so tier metadata is visible and checked
|
|
||||||
- `exp-1` owned runtime strings: compiler-known `std.string.concat` accepts two
|
- `exp-1` owned runtime strings: compiler-known `std.string.concat` accepts two
|
||||||
`string` values and returns an immutable runtime-owned `string`; existing
|
`string` values and returns an immutable runtime-owned `string`; existing
|
||||||
string equality, length, printing, locals, parameters, returns, and calls work
|
string equality, length, printing, locals, parameters, returns, and calls work
|
||||||
@ -1101,14 +953,6 @@ structs, functions, and tests. It is a documentation generator, not a semantic
|
|||||||
reflection API, and it does not expose stable typed-core, debug metadata,
|
reflection API, and it does not expose stable typed-core, debug metadata,
|
||||||
source-map, ABI, layout, runtime reflection, or compiler-internal contracts.
|
source-map, ABI, layout, runtime reflection, or compiler-internal contracts.
|
||||||
|
|
||||||
As of `1.0.0-beta.11`, `glagol doc <file|project|workspace> -o <dir>` also
|
|
||||||
includes deterministic exported/public API sections for local packages and
|
|
||||||
modules. These sections render exact exported function signatures, exported
|
|
||||||
struct fields, and exported enum variants with payload types. They omit
|
|
||||||
non-exported functions, structs, enums, tests, and aliases from the public API
|
|
||||||
surface and normalize module-local concrete aliases before rendering public
|
|
||||||
types.
|
|
||||||
|
|
||||||
`glagol symbols <file.slo|project|workspace>` emits deterministic
|
`glagol symbols <file.slo|project|workspace>` emits deterministic
|
||||||
machine-readable S-expression metadata using the `slovo.symbols` schema. It
|
machine-readable S-expression metadata using the `slovo.symbols` schema. It
|
||||||
reports module paths, package labels when available, imports, exports,
|
reports module paths, package labels when available, imports, exports,
|
||||||
@ -1231,25 +1075,6 @@ solving, package publishing, archive formats, optional/dev/target
|
|||||||
dependencies, feature flags, package build scripts, or stable package
|
dependencies, feature flags, package build scripts, or stable package
|
||||||
ABI/layout promises.
|
ABI/layout promises.
|
||||||
|
|
||||||
`1.0.0-beta.11` extends the generated local-package documentation surface, but
|
|
||||||
not the package model itself. `glagol doc <file|project|workspace> -o <dir>`
|
|
||||||
includes deterministic exported/public API sections for local modules and
|
|
||||||
workspace packages:
|
|
||||||
|
|
||||||
- exported functions are rendered with exact parameter and return types
|
|
||||||
- exported structs are rendered with exported field names and field types
|
|
||||||
- exported enums are rendered with exported variant names and payload types
|
|
||||||
- non-exported functions, structs, enums, tests, and `(type ...)` aliases are
|
|
||||||
excluded from the public API sections
|
|
||||||
- module-local concrete aliases are normalized to their concrete public target
|
|
||||||
types before rendering
|
|
||||||
|
|
||||||
The generated Markdown remains a beta documentation format. This does not
|
|
||||||
define a stable Markdown schema, stable stdlib/API compatibility freeze,
|
|
||||||
LSP/watch behavior, SARIF or daemon protocols, diagnostics schema policy,
|
|
||||||
executable generics, maps/sets, re-exports, glob imports, hierarchical modules,
|
|
||||||
registry semantics, runtime behavior, or stable ABI/layout.
|
|
||||||
|
|
||||||
### 4.4.4 Post-Beta Networking Foundation
|
### 4.4.4 Post-Beta Networking Foundation
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.6`.
|
Status: released in `1.0.0-beta.6`.
|
||||||
@ -1299,14 +1124,6 @@ std.json.quote_string: (string) -> string
|
|||||||
std.json.null_value: () -> string
|
std.json.null_value: () -> string
|
||||||
std.json.bool_value: (bool) -> string
|
std.json.bool_value: (bool) -> string
|
||||||
std.json.i32_value/u32_value/i64_value/u64_value/f64_value
|
std.json.i32_value/u32_value/i64_value/u64_value/f64_value
|
||||||
std.json.parse_string_value_result: (string) -> (result string i32)
|
|
||||||
std.json.parse_bool_value_result: (string) -> (result bool i32)
|
|
||||||
std.json.parse_i32_value_result/parse_u32_value_result/parse_i64_value_result/parse_u64_value_result/parse_f64_value_result
|
|
||||||
std.json.parse_null_value_result: (string) -> (result bool i32)
|
|
||||||
std.json.parse_string_document_result: (string) -> (result string i32)
|
|
||||||
std.json.parse_bool_document_result: (string) -> (result bool i32)
|
|
||||||
std.json.parse_i32_document_result/parse_u32_document_result/parse_i64_document_result/parse_u64_document_result/parse_f64_document_result
|
|
||||||
std.json.parse_null_document_result: (string) -> (result bool i32)
|
|
||||||
std.json.field_string/field_bool/field_i32/field_u32/field_i64/field_u64/field_f64/field_null
|
std.json.field_string/field_bool/field_i32/field_u32/field_i64/field_u64/field_f64/field_null
|
||||||
std.json.array0/array1/array2/array3
|
std.json.array0/array1/array2/array3
|
||||||
std.json.object0/object1/object2/object3
|
std.json.object0/object1/object2/object3
|
||||||
@ -1318,34 +1135,9 @@ character iteration. It returns a complete compact JSON string literal,
|
|||||||
including surrounding quotes. The source helpers compose already-encoded JSON
|
including surrounding quotes. The source helpers compose already-encoded JSON
|
||||||
fragments with compact comma/colon separators.
|
fragments with compact comma/colon separators.
|
||||||
|
|
||||||
The Slovo-facing `1.0.0-beta.17` JSON foundation adds primitive scalar token
|
This release is not a complete JSON or serialization contract. JSON parsing,
|
||||||
parse facades only: exact boolean and numeric primitive token conversion
|
recursive JSON values, maps/sets, generic collections, streaming encoders,
|
||||||
through concrete `(result ... i32)` values, plus `parse_null_value_result`
|
schema validation, Unicode normalization, stable text encoding policy beyond
|
||||||
returning `ok true` only for exact `null` and `err 1` otherwise.
|
|
||||||
Numeric and boolean parse helpers consume one isolated JSON primitive token:
|
|
||||||
no leading/trailing whitespace, no leading `+`, no leading-zero integer form
|
|
||||||
except `0`, and no non-finite f64 values.
|
|
||||||
|
|
||||||
The `1.0.0-beta.18` JSON foundation adds
|
|
||||||
`parse_string_value_result` for one already-isolated ASCII JSON string token.
|
|
||||||
The token must start and end with quotes and contain no leading or trailing
|
|
||||||
whitespace. It decodes the simple JSON escapes `\"`, `\\`, `\/`, `\b`, `\f`,
|
|
||||||
`\n`, `\r`, and `\t`. It rejects raw control bytes, bad escapes,
|
|
||||||
unterminated or trailing bytes, raw non-ASCII, and all `\uXXXX` escapes for
|
|
||||||
this slice.
|
|
||||||
|
|
||||||
The `1.0.0-beta.21` JSON foundation adds source-authored
|
|
||||||
`parse_*_document_result` helpers for string, bool, concrete numeric
|
|
||||||
primitives, and exact `null`. Each helper accepts leading and trailing ASCII
|
|
||||||
whitespace around one scalar JSON document by composing with
|
|
||||||
`std.string.trim_ascii`, then delegates to the matching exact value-token
|
|
||||||
parser. Trailing non-whitespace still fails through the exact parser.
|
|
||||||
|
|
||||||
This is not a complete JSON or serialization contract. JSON parsing beyond the
|
|
||||||
scalar document helpers, object/array parsing, recursive JSON values, maps/sets,
|
|
||||||
generic collections, tokenizer objects, streaming decoders or encoders, schema
|
|
||||||
validation, Unicode escape decoding or normalization beyond the existing
|
|
||||||
string-token behavior, embedded NUL policy, stable text encoding policy beyond
|
|
||||||
the current null-terminated runtime string ABI, stable runtime helper symbols,
|
the current null-terminated runtime string ABI, stable runtime helper symbols,
|
||||||
and stable standard-library API guarantees remain deferred.
|
and stable standard-library API guarantees remain deferred.
|
||||||
|
|
||||||
@ -1440,194 +1232,6 @@ generic aliases, parameterized aliases, maps, sets, traits, inference,
|
|||||||
monomorphization, iterators, new runtime helpers, stable ABI/layout promises,
|
monomorphization, iterators, new runtime helpers, stable ABI/layout promises,
|
||||||
or a stable standard-library API freeze.
|
or a stable standard-library API freeze.
|
||||||
|
|
||||||
### 4.4.8 Post-Beta Local Package API Documentation
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.11` as a documentation/API-discovery update on
|
|
||||||
top of the beta.10 discovery lane.
|
|
||||||
|
|
||||||
`1.0.0-beta.11` extends `glagol doc <file|project|workspace> -o <dir>` so the
|
|
||||||
generated Markdown includes deterministic exported/public API sections for
|
|
||||||
local source files, projects, packages, and workspaces. The public API surface
|
|
||||||
is derived from explicit module exports and local package boundaries.
|
|
||||||
|
|
||||||
The public API sections include:
|
|
||||||
|
|
||||||
- exact exported function signatures, including parameter names, parameter
|
|
||||||
types, and return types
|
|
||||||
- exported struct field names and field types
|
|
||||||
- exported enum variant names and payload types, including payloadless variants
|
|
||||||
and current single-payload variants
|
|
||||||
- deterministic ordering that follows the existing module/package
|
|
||||||
documentation ordering
|
|
||||||
|
|
||||||
Non-exported functions, structs, enums, tests, and `(type ...)` aliases are
|
|
||||||
not part of the public API sections. A declaration can still appear in other
|
|
||||||
source-structure summaries when those summaries already exist, but it must not
|
|
||||||
be presented as exported/public API unless the module export list exposes it.
|
|
||||||
|
|
||||||
Module-local concrete aliases are normalized before public rendering. Public
|
|
||||||
docs show concrete target types such as `(vec i32)`, `(option string)`, and
|
|
||||||
`(result u64 i32)` rather than private alias names introduced by the
|
|
||||||
documented module. This mirrors beta.10 `lib/std` catalog behavior for local
|
|
||||||
packages and modules.
|
|
||||||
|
|
||||||
This is not a stable documentation schema. It does not freeze Markdown
|
|
||||||
headings, anchors, file names, machine parsing contracts, stable stdlib/API
|
|
||||||
compatibility freeze, LSP/watch behavior, SARIF or daemon protocols,
|
|
||||||
diagnostics schema policy, executable generics, maps/sets, re-exports, glob
|
|
||||||
imports, hierarchical modules, registry semantics, runtime behavior, package
|
|
||||||
ABI, or layout.
|
|
||||||
|
|
||||||
### 4.4.9 Post-Beta Concrete Vector Query And Prefix Parity
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.12` as a source-authored stdlib/helper parity
|
|
||||||
update on the existing concrete vector surface.
|
|
||||||
|
|
||||||
`1.0.0-beta.12` closes narrow helper gaps in the concrete vector facades:
|
|
||||||
|
|
||||||
- `std.vec_i64` exports `count_of`, `starts_with`, `without_prefix`,
|
|
||||||
`ends_with`, and `without_suffix`.
|
|
||||||
- `std.vec_f64` exports `count_of`.
|
|
||||||
|
|
||||||
The helpers are ordinary Slovo source helpers. They build on the existing
|
|
||||||
compiler-known concrete vector runtime names, equality, `len`, `at`, and
|
|
||||||
already staged source helpers such as `take` and `drop`. They do not add new
|
|
||||||
source-language syntax, typed-core forms, runtime calls, compiler-known stdlib
|
|
||||||
names, ABI/layout commitments, or performance guarantees.
|
|
||||||
|
|
||||||
The helper semantics follow the existing concrete vector family conventions:
|
|
||||||
`count_of(values,target)` returns the number of elements equal to `target`;
|
|
||||||
`starts_with(values,prefix)` and `ends_with(values,suffix)` accept empty,
|
|
||||||
exact, and shorter matching vectors and reject longer or mismatched vectors;
|
|
||||||
`without_prefix` and `without_suffix` return the original vector when the
|
|
||||||
prefix/suffix does not match and return the remaining vector when it does.
|
|
||||||
|
|
||||||
This target explicitly does not add executable generics, generic vector
|
|
||||||
dispatch, maps, sets, iterators, mutable vectors, slice/view APIs, new runtime
|
|
||||||
names, stable ABI/layout promises, performance claims, or a stable stdlib API
|
|
||||||
freeze.
|
|
||||||
|
|
||||||
### 4.4.10 Post-Beta Diagnostic Catalog And Schema Policy
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.13` as a docs/tooling policy update for the
|
|
||||||
existing diagnostic surface.
|
|
||||||
|
|
||||||
`1.0.0-beta.13` adds
|
|
||||||
[`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md) as the central beta policy for
|
|
||||||
`slovo.diagnostic` version `1`. The document records the S-expression and JSON
|
|
||||||
encodings, source-attached and source-less diagnostic field rules,
|
|
||||||
severity/source/range/related-span semantics, JSON-line discipline,
|
|
||||||
artifact-manifest diagnostic metadata, diagnostic compatibility classes, and
|
|
||||||
the current golden diagnostic code catalog.
|
|
||||||
|
|
||||||
The source language, typed core, runtime, standard library, compiler-known
|
|
||||||
runtime names, ABI/layout behavior, CLI behavior, and diagnostic output shape
|
|
||||||
are unchanged by this target. Human-readable diagnostic prose remains
|
|
||||||
beta-flexible; schema names, versions, machine fields, diagnostic codes, source
|
|
||||||
span/range semantics, JSON-line discipline, and golden fixture shape change
|
|
||||||
only intentionally through the documented migration policy.
|
|
||||||
|
|
||||||
This target explicitly does not add LSP/watch behavior, SARIF output, daemon
|
|
||||||
protocols, stable Markdown schema, stable `1.0.0` diagnostics freeze,
|
|
||||||
source-map/debug-metadata contracts, localized diagnostic text, automated
|
|
||||||
machine fix-its, or a compiler-emitted diagnostic catalog artifact.
|
|
||||||
|
|
||||||
### 4.4.11 Post-Beta Benchmark Suite Catalog And Metadata Gate
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.14` as a docs/tooling metadata update for the
|
|
||||||
existing benchmark suite.
|
|
||||||
|
|
||||||
`1.0.0-beta.14` adds
|
|
||||||
[`benchmarks/README.md`](../../benchmarks/README.md) as the top-level
|
|
||||||
benchmark suite catalog. The catalog records the current suite inventory,
|
|
||||||
base/hot-loop checksum metadata, local evidence policy, and explicit
|
|
||||||
exclusions.
|
|
||||||
|
|
||||||
The root suite-list commands are documented as:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 benchmarks/runner.py --suite-list
|
|
||||||
python3 benchmarks/runner.py --suite-list --json
|
|
||||||
```
|
|
||||||
|
|
||||||
The non-JSON listing is local review output. The JSON listing is beta tooling
|
|
||||||
metadata for local gates and adapters. The field set is intentionally not a
|
|
||||||
stable public schema in this release.
|
|
||||||
|
|
||||||
The source language, typed core, runtime, standard library, public API surface,
|
|
||||||
compiler diagnostics, diagnostic output shape, compiler-known runtime names,
|
|
||||||
ABI/layout behavior, and optimizer contract are unchanged by this target.
|
|
||||||
Benchmark timings remain local-machine evidence only and no timing numbers are
|
|
||||||
published by the release contract.
|
|
||||||
|
|
||||||
This target explicitly does not add benchmark kernels, implementation language
|
|
||||||
slots, timing publication, performance thresholds, cross-machine performance
|
|
||||||
claims, a stable benchmark JSON schema, source-language/runtime/stdlib/API
|
|
||||||
changes, diagnostic-output changes, or ABI/layout guarantees.
|
|
||||||
|
|
||||||
### 4.4.12 Post-Beta Reserved Generic Collection Boundary Hardening And Collection Ledger
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.15` as a docs/design ledger and
|
|
||||||
compiler-boundary hardening update for the existing concrete collection and
|
|
||||||
value-family surface.
|
|
||||||
|
|
||||||
`1.0.0-beta.15` adds
|
|
||||||
[`docs/language/COLLECTIONS.md`](COLLECTIONS.md) as the public collection
|
|
||||||
ledger. The ledger links to the generated
|
|
||||||
[`docs/language/STDLIB_API.md`](STDLIB_API.md) catalog for exact exported
|
|
||||||
standard-library helper signatures instead of duplicating generated counts.
|
|
||||||
|
|
||||||
The ledger inventories the current concrete vector, option, result, and
|
|
||||||
related option/result-returning facade surfaces. It records design pressure
|
|
||||||
from duplicated concrete vector/option/result helper families and defines
|
|
||||||
prerequisites before executable generics, generic aliases, maps, sets,
|
|
||||||
iterators, mutable vectors, or slice/view APIs can be promoted.
|
|
||||||
|
|
||||||
Current unsupported diagnostics are documented as boundaries of the existing
|
|
||||||
beta surface. This target does not add, remove, rename, or reclassify
|
|
||||||
diagnostic codes and does not change the `slovo.diagnostic` schema,
|
|
||||||
diagnostic output shape, golden fixture shape, or human-readable diagnostic
|
|
||||||
prose policy. It does intentionally reword affected reserved-boundary messages
|
|
||||||
from beta.9-specific text to current-beta wording while preserving diagnostic
|
|
||||||
codes, schema, spans, expected/found values, hints, and output shape.
|
|
||||||
|
|
||||||
The source language, typed core, runtime, standard library, public API surface,
|
|
||||||
benchmark metadata schema, compiler-known runtime names, ABI/layout behavior,
|
|
||||||
optimizer contract, and performance claims are unchanged by this target. This
|
|
||||||
target explicitly does not add executable generics, generic aliases,
|
|
||||||
parameterized aliases, maps, sets, generic stdlib dispatch, iterators, mutable
|
|
||||||
vectors, slice/view APIs, new runtime names, or a stable stdlib/API freeze.
|
|
||||||
|
|
||||||
### 4.4.13 Post-Beta String Scanning And Token Boundary Foundation
|
|
||||||
|
|
||||||
Status: released in `1.0.0-beta.16` as a byte-oriented string scanning and
|
|
||||||
token-boundary foundation over the existing runtime string representation.
|
|
||||||
|
|
||||||
`1.0.0-beta.16` adds these `std.string` helpers:
|
|
||||||
|
|
||||||
- `byte_at_result ((value string) (index i32)) -> (result i32 i32)`
|
|
||||||
- `slice_result ((value string) (start i32) (count i32)) -> (result string i32)`
|
|
||||||
- `starts_with ((value string) (prefix string)) -> bool`
|
|
||||||
- `ends_with ((value string) (suffix string)) -> bool`
|
|
||||||
|
|
||||||
The helpers operate on bytes before the trailing NUL in the current
|
|
||||||
NUL-terminated runtime string representation. `byte_at_result` returns `ok`
|
|
||||||
with the byte value as `i32` for valid zero-based byte indexes and returns
|
|
||||||
`err 1` for invalid indexes. `slice_result` returns `ok` with a runtime-owned
|
|
||||||
string for valid byte ranges and returns `err 1` for invalid ranges. Allocation
|
|
||||||
failure while creating the substring may follow the existing string allocation
|
|
||||||
trap policy.
|
|
||||||
|
|
||||||
`starts_with` and `ends_with` compare byte prefixes and suffixes. Empty prefixes
|
|
||||||
and empty suffixes match. No helper performs Unicode normalization, grapheme
|
|
||||||
segmentation, display-width measurement, locale-sensitive matching, or
|
|
||||||
case-folding.
|
|
||||||
|
|
||||||
This target does not add full JSON parsing, object/array parsing, tokenizer
|
|
||||||
or scanner objects, language slice/view syntax or borrowed substring views,
|
|
||||||
mutable strings, string containers, stable runtime ABI/layout, performance
|
|
||||||
claims, or a stable standard-library/API freeze.
|
|
||||||
|
|
||||||
## 4.5 v2.0.0-beta.1 Experimental Integration Readiness
|
## 4.5 v2.0.0-beta.1 Experimental Integration Readiness
|
||||||
|
|
||||||
Status: current experimental Slovo-side release contract, released 2026-05-17.
|
Status: current experimental Slovo-side release contract, released 2026-05-17.
|
||||||
@ -1823,23 +1427,22 @@ ABI symbols or stable runtime helper symbols. The exact promoted names are
|
|||||||
reserved from user function, export, import, local, and parameter
|
reserved from user function, export, import, local, and parameter
|
||||||
shadowing.
|
shadowing.
|
||||||
|
|
||||||
The latest released Slovo-side concrete collection helper target is
|
The latest released Slovo-side collection target after exp-107 is `exp-108`,
|
||||||
`1.0.0-beta.12`, Concrete Vector Query And Prefix Parity. It broadens
|
Standard Vec String, F64, And Bool Prefix And Suffix Helpers Alpha. It
|
||||||
`std/vec_i64.slo` with `count_of`, `starts_with`, `without_prefix`,
|
broadens `std/vec_string.slo`, `std/vec_f64.slo`, and `std/vec_bool.slo`
|
||||||
`ends_with`, and `without_suffix`, and broadens `std/vec_f64.slo` with
|
with exactly `starts_with`, `without_prefix`, `ends_with`, and
|
||||||
`count_of`. The helper lanes stay source-authored, recursive, immutable, and
|
`without_suffix` over the already released concrete vec-string, vec-f64, and
|
||||||
limited to the already promoted concrete vector runtime names. They do not
|
vec-bool helper surfaces. The helper lanes stay source-authored,
|
||||||
widen the promoted collection runtime surface or add new compiler-known names.
|
recursive, and immutable and do not widen the promoted collection runtime
|
||||||
|
surface beyond those connected prefix/suffix helpers.
|
||||||
|
|
||||||
The collections alpha slice explicitly defers generic vectors, vector element
|
The collections alpha slice explicitly defers generic vectors, vector element
|
||||||
types other than `i32`, `i64`, `f64`, `bool`, and `string`, vector mutation,
|
types other than `i32`, `i64`, `f64`, `bool`, and `string`, vector mutation, vector
|
||||||
mutable vector operations beyond whole-value `var`/`set` already promoted for
|
`var`, vector `set`, vector literals besides empty/append construction, a `push`
|
||||||
current concrete vectors, vector literals besides empty/append construction, a
|
alias, nested vectors, vectors in arrays, vectors in structs, vectors in
|
||||||
`push` alias, nested vectors, vectors in arrays, vectors in structs, vectors in
|
options, vectors in results, iterators, slices, maps, sets, user-visible
|
||||||
options, vectors in results, iterators, slices/views, maps, sets, user-visible
|
deallocation, stable ABI/layout/helper-symbol promises, package expansion,
|
||||||
deallocation, new runtime names, stable ABI/layout/helper-symbol promises,
|
and IO expansion.
|
||||||
performance claims, package expansion, stable stdlib API freeze, and IO
|
|
||||||
expansion.
|
|
||||||
|
|
||||||
The collection fixture targets are:
|
The collection fixture targets are:
|
||||||
|
|
||||||
@ -5215,9 +4818,7 @@ owned-runtime-string compiler-supported fixture. exp-13 adds
|
|||||||
`examples/supported/string-parse-i32-result.slo` as the first string parse
|
`examples/supported/string-parse-i32-result.slo` as the first string parse
|
||||||
result compiler-supported fixture. exp-34 adds
|
result compiler-supported fixture. exp-34 adds
|
||||||
`examples/supported/string-parse-bool-result.slo` for the exact lowercase bool
|
`examples/supported/string-parse-bool-result.slo` for the exact lowercase bool
|
||||||
parse result slice. `1.0.0-beta.16` adds byte-oriented string scanning and
|
parse result slice.
|
||||||
token-boundary helpers through the `std.string` source facade and explicit
|
|
||||||
examples.
|
|
||||||
|
|
||||||
### 8.1 Goal
|
### 8.1 Goal
|
||||||
|
|
||||||
@ -5251,9 +4852,6 @@ The promoted slice supports:
|
|||||||
`(result i32 i32)` value from an entire ASCII decimal signed `i32` string
|
`(result i32 i32)` value from an entire ASCII decimal signed `i32` string
|
||||||
- exp-34 released `std.string.parse_bool_result`, returning `(result bool i32)`
|
- exp-34 released `std.string.parse_bool_result`, returning `(result bool i32)`
|
||||||
for exact lowercase `true`/`false` parsing with `err 1` ordinary failures
|
for exact lowercase `true`/`false` parsing with `err 1` ordinary failures
|
||||||
- `1.0.0-beta.16` byte-oriented string helpers:
|
|
||||||
`std.string.byte_at_result`, `std.string.slice_result`,
|
|
||||||
`std.string.starts_with`, and `std.string.ends_with`
|
|
||||||
|
|
||||||
Everything else in the string family remains deferred until separately
|
Everything else in the string family remains deferred until separately
|
||||||
specified, implemented, diagnosed, formatted, and tested.
|
specified, implemented, diagnosed, formatted, and tested.
|
||||||
@ -5325,29 +4923,6 @@ locals, parameters, returns, and calls returning `string`. No import is
|
|||||||
required, no legacy alias is introduced, and no user-visible allocation or
|
required, no legacy alias is introduced, and no user-visible allocation or
|
||||||
deallocation form is exposed.
|
deallocation form is exposed.
|
||||||
|
|
||||||
`1.0.0-beta.16` adds byte-oriented string scanning and token-boundary helpers:
|
|
||||||
|
|
||||||
```slo
|
|
||||||
(std.string.byte_at_result "slovo" 0)
|
|
||||||
(std.string.slice_result "slovo" 1 3)
|
|
||||||
(std.string.starts_with "slovo" "slo")
|
|
||||||
(std.string.ends_with "slovo" "ovo")
|
|
||||||
```
|
|
||||||
|
|
||||||
`std.string.byte_at_result` has one `string` argument and one `i32` index. It
|
|
||||||
returns `ok byte` for valid zero-based byte indexes before the trailing NUL and
|
|
||||||
`err 1` for ordinary invalid indexes.
|
|
||||||
|
|
||||||
`std.string.slice_result` has one `string` argument, one `i32` start byte, and
|
|
||||||
one `i32` byte count. It returns `ok text` for a valid range and `err 1` for an
|
|
||||||
ordinary invalid range. The successful result is runtime-owned and immutable.
|
|
||||||
Allocation failure may trap with the existing string allocation failure policy.
|
|
||||||
|
|
||||||
`std.string.starts_with` and `std.string.ends_with` compare byte prefixes and
|
|
||||||
suffixes and return `bool`. Empty prefixes and suffixes match. These helpers do
|
|
||||||
not perform Unicode normalization, grapheme segmentation, display-width
|
|
||||||
measurement, locale-sensitive matching, or case-folding.
|
|
||||||
|
|
||||||
v1.2 promotes bool printing through the legacy alias:
|
v1.2 promotes bool printing through the legacy alias:
|
||||||
|
|
||||||
```slo
|
```slo
|
||||||
@ -5426,18 +5001,14 @@ Promoted uses of `string` values:
|
|||||||
- operands to `=` when both operands check as `string`
|
- operands to `=` when both operands check as `string`
|
||||||
- argument to `string_len` or `std.string.len`
|
- argument to `string_len` or `std.string.len`
|
||||||
- exp-1 arguments to and result from `std.string.concat`
|
- exp-1 arguments to and result from `std.string.concat`
|
||||||
- `1.0.0-beta.16` byte indexes and byte ranges through
|
|
||||||
`std.string.byte_at_result` and `std.string.slice_result`
|
|
||||||
- `1.0.0-beta.16` prefix and suffix byte comparisons through
|
|
||||||
`std.string.starts_with` and `std.string.ends_with`
|
|
||||||
|
|
||||||
Still deferred:
|
Still deferred:
|
||||||
|
|
||||||
- string ordering or comparison other than equality
|
- string ordering or comparison other than equality
|
||||||
- string values inside arrays or vectors
|
- string values inside arrays or vectors
|
||||||
- language slice/view syntax or borrowed substring views
|
- slices or borrowed substring views
|
||||||
- concatenation beyond exp-1 `std.string.concat`
|
- concatenation beyond exp-1 `std.string.concat`
|
||||||
- unchecked indexing or character/grapheme indexing
|
- indexing
|
||||||
- ownership or lifetime annotations
|
- ownership or lifetime annotations
|
||||||
- user-defined runtime bindings involving `string`
|
- user-defined runtime bindings involving `string`
|
||||||
|
|
||||||
@ -5464,11 +5035,6 @@ Required lowering shape:
|
|||||||
- exp-1 `std.string.concat` lowers to a runtime-owned immutable string
|
- exp-1 `std.string.concat` lowers to a runtime-owned immutable string
|
||||||
allocation, byte copy, and trailing terminator write; allocation failure
|
allocation, byte copy, and trailing terminator write; allocation failure
|
||||||
traps with `slovo runtime error: string allocation failed`
|
traps with `slovo runtime error: string allocation failed`
|
||||||
- `1.0.0-beta.16` `std.string.byte_at_result`,
|
|
||||||
`std.string.slice_result`, `std.string.starts_with`, and
|
|
||||||
`std.string.ends_with` operate over bytes before the trailing NUL; invalid
|
|
||||||
byte indexes/ranges return `err 1`, and successful `slice_result` returns a
|
|
||||||
runtime-owned immutable string
|
|
||||||
- since embedded NUL is not promoted, printing observes the whole decoded
|
- since embedded NUL is not promoted, printing observes the whole decoded
|
||||||
literal and equality/length observe the whole decoded value
|
literal and equality/length observe the whole decoded value
|
||||||
|
|
||||||
@ -5547,10 +5113,9 @@ as `string`. `string_len` and `print_bool` use the same compact call style as
|
|||||||
other promoted intrinsics. v1.5 `std.io.print_*` and `std.string.len` calls use
|
other promoted intrinsics. v1.5 `std.io.print_*` and `std.string.len` calls use
|
||||||
the same compact call style. exp-1 `std.string.concat` uses the same compact
|
the same compact call style. exp-1 `std.string.concat` uses the same compact
|
||||||
call style and remains inline when nested in `std.io.print_string`,
|
call style and remains inline when nested in `std.io.print_string`,
|
||||||
`std.string.len`, equality, local initializers, returns, and user calls.
|
`std.string.len`, equality, local initializers, returns, and user calls. The
|
||||||
`1.0.0-beta.16` string scanning helpers use the same compact call style. The
|
formatter must preserve the decoded literal meaning when re-emitting the
|
||||||
formatter must preserve the decoded literal meaning when re-emitting the current
|
current supported escapes.
|
||||||
supported escapes.
|
|
||||||
|
|
||||||
### 8.7 Diagnostics
|
### 8.7 Diagnostics
|
||||||
|
|
||||||
@ -5591,9 +5156,8 @@ Required promoted-boundary diagnostics:
|
|||||||
- string ordering/comparison other than equality, string containers beyond the
|
- string ordering/comparison other than equality, string containers beyond the
|
||||||
current direct struct fields, current fixed string arrays, current direct
|
current direct struct fields, current fixed string arrays, current direct
|
||||||
fixed-array struct fields, and current concrete option/result families,
|
fixed-array struct fields, and current concrete option/result families,
|
||||||
language slice/view syntax, concatenation beyond exp-1
|
slices, concatenation beyond exp-1
|
||||||
`std.string.concat`, unchecked indexing, character/grapheme indexing,
|
`std.string.concat`, indexing, mutation, user-visible allocation,
|
||||||
mutation, user-visible allocation,
|
|
||||||
user-visible deallocation, and user-defined runtime bindings must remain
|
user-visible deallocation, and user-defined runtime bindings must remain
|
||||||
unsupported with structured diagnostics or explicit backend-feature
|
unsupported with structured diagnostics or explicit backend-feature
|
||||||
diagnostics; they must not reach a backend panic
|
diagnostics; they must not reach a backend panic
|
||||||
@ -5801,14 +5365,10 @@ requirement.
|
|||||||
|
|
||||||
Slovo v1 keeps the v0 rule that diagnostics have both human-readable and
|
Slovo v1 keeps the v0 rule that diagnostics have both human-readable and
|
||||||
machine-readable forms generated from one compiler diagnostic object. Human
|
machine-readable forms generated from one compiler diagnostic object. Human
|
||||||
rendering may choose layout and surrounding prose. The machine form is the
|
rendering may choose layout and surrounding prose, but the machine form is a
|
||||||
tooling contract, with beta compatibility and migration rules defined by the
|
stable tool API.
|
||||||
diagnostics policy rather than by human text.
|
|
||||||
|
|
||||||
The v1 machine diagnostic schema is `slovo.diagnostic` version `1`. As of
|
The v1 machine diagnostic schema is `slovo.diagnostic` version `1`.
|
||||||
`1.0.0-beta.13`, the detailed beta schema policy, JSON-line discipline,
|
|
||||||
source-less diagnostic policy, compatibility classes, and current code catalog
|
|
||||||
live in [`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md).
|
|
||||||
|
|
||||||
Every machine diagnostic emitted for a v1 compiler boundary must include:
|
Every machine diagnostic emitted for a v1 compiler boundary must include:
|
||||||
|
|
||||||
@ -5870,10 +5430,8 @@ Diagnostic locations are derived from original source text, not from formatter
|
|||||||
output.
|
output.
|
||||||
|
|
||||||
The schema version belongs in every machine diagnostic and every golden
|
The schema version belongs in every machine diagnostic and every golden
|
||||||
diagnostic fixture. Human-readable diagnostic prose remains beta-flexible, but
|
diagnostic fixture. Future machine-shape changes require a documented schema
|
||||||
future machine-shape or code changes require the compatibility class defined in
|
migration and updated Glagol snapshots.
|
||||||
[`docs/language/DIAGNOSTICS.md`](DIAGNOSTICS.md) and updated Glagol snapshots
|
|
||||||
when the current golden contract changes.
|
|
||||||
|
|
||||||
### 9.2 Artifact Manifest Schema
|
### 9.2 Artifact Manifest Schema
|
||||||
|
|
||||||
@ -6120,18 +5678,12 @@ manifest source root and uses deterministic v1.3 module ordering. Plain
|
|||||||
`glagol fmt <file.slo>` continues to write formatted source to stdout.
|
`glagol fmt <file.slo>` continues to write formatted source to stdout.
|
||||||
|
|
||||||
Documentation generation records modules, imports/exports, structs, functions,
|
Documentation generation records modules, imports/exports, structs, functions,
|
||||||
tests, and beta.11 exported/public API sections as deterministic Markdown.
|
and tests as deterministic Markdown. It is generated documentation, not
|
||||||
Public API sections include exact exported function signatures, exported
|
runtime reflection, typed-core reflection, debug metadata, DWARF, source maps,
|
||||||
struct fields, exported enum variants/payload types, non-export filtering, and
|
or ABI/layout information.
|
||||||
module-local alias normalization. It is generated documentation, not runtime
|
|
||||||
reflection, typed-core reflection, debug metadata, DWARF, source maps,
|
|
||||||
ABI/layout information, or a stable Markdown schema.
|
|
||||||
|
|
||||||
LSP, watch mode, daemon protocols, SARIF, debug adapters, diagnostics schema
|
LSP, watch mode, daemon protocols, SARIF, debug adapters, stable debug
|
||||||
policy, stable debug metadata, DWARF emission, standalone source-map files,
|
metadata, DWARF emission, and standalone source-map files remain deferred.
|
||||||
stable stdlib/API compatibility freeze, executable generics, maps/sets,
|
|
||||||
re-exports, globs, hierarchical modules, and registry semantics remain
|
|
||||||
deferred.
|
|
||||||
|
|
||||||
## 10. Slice 6: Unsafe, Memory, And FFI
|
## 10. Slice 6: Unsafe, Memory, And FFI
|
||||||
|
|
||||||
@ -6214,8 +5766,7 @@ promises remain deferred until a future spec explicitly promotes them.
|
|||||||
host error ADTs, stdin APIs beyond exp-12, parsing APIs beyond exp-13
|
host error ADTs, stdin APIs beyond exp-12, parsing APIs beyond exp-13
|
||||||
`std.string.parse_i32_result`, exp-25 `std.string.parse_i64_result`, exp-28
|
`std.string.parse_i32_result`, exp-25 `std.string.parse_i64_result`, exp-28
|
||||||
`std.string.parse_f64_result`, and exp-34 exact lowercase
|
`std.string.parse_f64_result`, and exp-34 exact lowercase
|
||||||
`std.string.parse_bool_result`, string scanning/tokenizing APIs beyond
|
`std.string.parse_bool_result`,
|
||||||
`1.0.0-beta.16` byte access, substring, and prefix/suffix helpers,
|
|
||||||
result helper payload families beyond the explicitly listed
|
result helper payload families beyond the explicitly listed
|
||||||
`(result i32 i32)`, `(result i64 i32)`, `(result string i32)`, exp-28
|
`(result i32 i32)`, `(result i64 i32)`, `(result string i32)`, exp-28
|
||||||
returned `(result f64 i32)`, and exp-34 returned `(result bool i32)`
|
returned `(result f64 i32)`, and exp-34 returned `(result bool i32)`
|
||||||
@ -6224,9 +5775,8 @@ promises remain deferred until a future spec explicitly promotes them.
|
|||||||
concrete option source helpers,
|
concrete option source helpers,
|
||||||
randomness beyond the exp-11 target, time beyond
|
randomness beyond the exp-11 target, time beyond
|
||||||
the exp-8 host time/sleep target, vectors/collections beyond the exp-2
|
the exp-8 host time/sleep target, vectors/collections beyond the exp-2
|
||||||
`(vec i32)`, exp-94 `(vec i64)`, exp-99 `(vec string)`, exp-103
|
`(vec i32)`, exp-94 `(vec i64)`, exp-99 `(vec string)`, and exp-103
|
||||||
`(vec f64)`, exp-104 `(vec bool)`, and beta.12 source-helper parity
|
`(vec f64)` targets,
|
||||||
targets,
|
|
||||||
user-defined standard modules, overloading, and generic standard-library APIs
|
user-defined standard modules, overloading, and generic standard-library APIs
|
||||||
- numeric primitives and conversions beyond exp-20 direct `f64`, exp-21
|
- numeric primitives and conversions beyond exp-20 direct `f64`, exp-21
|
||||||
direct `i64`, exp-22 explicit `std.num.i32_to_i64`,
|
direct `i64`, exp-22 explicit `std.num.i32_to_i64`,
|
||||||
@ -6271,25 +5821,19 @@ promises remain deferred until a future spec explicitly promotes them.
|
|||||||
facade wrappers, including wall-clock/calendar/timezone APIs,
|
facade wrappers, including wall-clock/calendar/timezone APIs,
|
||||||
high-resolution timers, async timers, cancellation, and scheduling
|
high-resolution timers, async timers, cancellation, and scheduling
|
||||||
guarantees
|
guarantees
|
||||||
- generic vectors, vector element types other than `i32`, `i64`, `f64`,
|
- generic vectors, vector element types other than `i32`, vector mutation,
|
||||||
`bool`, and `string`, element-level mutable vectors and mutable vector
|
vector literals beyond empty/append construction, `push`, nested vectors,
|
||||||
operations beyond whole-value local reassignment, vector literals beyond
|
vectors in arrays/structs/options/results, iterators, slices, maps, sets,
|
||||||
empty/append construction, `push`, nested vectors, vectors in
|
user-visible vector deallocation, and stable vector ABI/layout/helper symbols
|
||||||
arrays/structs/options/results, iterators, slices/views, maps, sets, new
|
|
||||||
runtime vector helper names, performance claims, user-visible vector
|
|
||||||
deallocation, stable stdlib API freeze, and stable vector ABI/layout/helper
|
|
||||||
symbols
|
|
||||||
- string concatenation beyond exp-1 `std.string.concat`, parsing beyond
|
- string concatenation beyond exp-1 `std.string.concat`, parsing beyond
|
||||||
exp-13 `std.string.parse_i32_result`, exp-25
|
exp-13 `std.string.parse_i32_result`, exp-25
|
||||||
`std.string.parse_i64_result`, and exp-28
|
`std.string.parse_i64_result`, and exp-28
|
||||||
`std.string.parse_f64_result`, plus exp-34 exact lowercase
|
`std.string.parse_f64_result`, plus exp-34 exact lowercase
|
||||||
`std.string.parse_bool_result`, unchecked indexing, character/grapheme
|
`std.string.parse_bool_result`, indexing, slicing, string containers beyond
|
||||||
indexing, language slice/view syntax, string containers beyond
|
|
||||||
the current direct struct fields, current fixed string arrays, current
|
the current direct struct fields, current fixed string arrays, current
|
||||||
direct fixed-array struct fields, and current concrete option/result
|
direct fixed-array struct fields, and current concrete option/result
|
||||||
families, user-visible string allocation or deallocation, Unicode length,
|
families, user-visible string allocation or deallocation, Unicode length or
|
||||||
grapheme, display-width, locale, or digit semantics, full JSON parsing,
|
digit semantics, and stable string ABI/layout
|
||||||
object/array parsing, and stable string ABI/layout
|
|
||||||
- pointer types, allocation, deallocation, load, store, pointer arithmetic,
|
- pointer types, allocation, deallocation, load, store, pointer arithmetic,
|
||||||
reinterpretation, unchecked indexing, raw memory operations, and FFI
|
reinterpretation, unchecked indexing, raw memory operations, and FFI
|
||||||
- stable ABI and stable layout promises
|
- stable ABI and stable layout promises
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
# Slovo Standard Runtime Catalog
|
# Slovo Standard Runtime Catalog
|
||||||
|
|
||||||
Status: standard-runtime catalog through exp-104 plus the post-beta
|
Status: standard-runtime catalog through exp-104 over the released exp-14
|
||||||
`1.0.0-beta.18` JSON string token parsing foundation over the released exp-14
|
|
||||||
conformance baseline. The latest Slovo experimental alpha release is
|
conformance baseline. The latest Slovo experimental alpha release is
|
||||||
`exp-104`, Standard Vec Bool Baseline Alpha. exp-29, exp-30, exp-32,
|
`exp-104`, Standard Vec Bool Baseline Alpha. exp-29, exp-30, exp-32,
|
||||||
exp-33, and exp-35 through exp-93 add no compiler-known `std.*` names;
|
exp-33, and exp-35 through exp-93 add no compiler-known `std.*` names;
|
||||||
@ -32,27 +31,8 @@ platform error values.
|
|||||||
|
|
||||||
The `1.0.0-beta.7` serialization/data-interchange foundation release adds
|
The `1.0.0-beta.7` serialization/data-interchange foundation release adds
|
||||||
`std.json.quote_string` behind the `std.json` source facade. It provides
|
`std.json.quote_string` behind the `std.json` source facade. It provides
|
||||||
deterministic compact JSON string quoting before later byte-oriented string
|
deterministic compact JSON string quoting before source-level string scanning,
|
||||||
scanning helpers, maps, or recursive JSON values are available.
|
slicing, maps, or recursive JSON values are available.
|
||||||
|
|
||||||
The `1.0.0-beta.16` string scanning and token-boundary foundation release adds
|
|
||||||
byte-oriented `std.string` runtime helpers behind the source facade. The helpers
|
|
||||||
operate over bytes before the trailing NUL in the current runtime string
|
|
||||||
representation, return `err 1` for ordinary invalid indexes or ranges, and do
|
|
||||||
not define Unicode scalar, grapheme, display-width, locale, full JSON parser,
|
|
||||||
object/array parser, language slice/view, or stable API semantics.
|
|
||||||
|
|
||||||
The `1.0.0-beta.17` JSON primitive scalar parsing foundation release adds
|
|
||||||
promoted bool and numeric `std.json.parse_*_value_result` runtime helpers
|
|
||||||
behind the source facade. The helpers consume a whole isolated JSON primitive
|
|
||||||
token and return `err 1` for ordinary parse failure. The exact `null` helper
|
|
||||||
is source-only and is not cataloged as a promoted runtime operation.
|
|
||||||
|
|
||||||
The `1.0.0-beta.18` JSON string token parsing foundation release adds promoted
|
|
||||||
`std.json.parse_string_value_result` for one isolated ASCII JSON string token.
|
|
||||||
It decodes simple escapes, rejects Unicode escapes for this slice, and leaves
|
|
||||||
recursive JSON values, tokenizers, streaming, schema validation, and stable
|
|
||||||
JSON parse errors deferred.
|
|
||||||
|
|
||||||
The exp-era catalog is closed to names promoted through exp-104. exp-29,
|
The exp-era catalog is closed to names promoted through exp-104. exp-29,
|
||||||
exp-30, exp-32, exp-33, and exp-35 through exp-93 add no new standard-runtime
|
exp-30, exp-32, exp-33, and exp-35 through exp-93 add no new standard-runtime
|
||||||
@ -101,18 +81,7 @@ source-level result helper names are the `std.result.*` names cataloged below.
|
|||||||
| `std.num.f64_to_i64_result` | `(f64) -> (result i64 i32)` | exp-31 | `examples/supported/f64-to-i64-result.slo` | Returns `ok value` only when the `f64` input is finite, exactly integral, and in the signed `i64` range; returns `err 1` for non-finite, fractional, or out-of-range input without trapping. Conservative fixture values avoid pinning every `f64`/`i64` edge. | Uses existing standard-runtime usage recording if present; no schema change. | Unchecked casts, unchecked f64-to-i64, cast syntax, generic `cast_checked`, f32, unsigned/narrower integer families, mixed numeric arithmetic, broad math, stable helper ABI/layout/ownership. |
|
| `std.num.f64_to_i64_result` | `(f64) -> (result i64 i32)` | exp-31 | `examples/supported/f64-to-i64-result.slo` | Returns `ok value` only when the `f64` input is finite, exactly integral, and in the signed `i64` range; returns `err 1` for non-finite, fractional, or out-of-range input without trapping. Conservative fixture values avoid pinning every `f64`/`i64` edge. | Uses existing standard-runtime usage recording if present; no schema change. | Unchecked casts, unchecked f64-to-i64, cast syntax, generic `cast_checked`, f32, unsigned/narrower integer families, mixed numeric arithmetic, broad math, stable helper ABI/layout/ownership. |
|
||||||
| `std.string.len` | `(string) -> i32` | v1.5 | `examples/supported/standard-runtime.slo` | Returns the existing decoded byte-count length used by legacy `string_len`. | Uses existing standard-runtime usage recording if present; no schema change. | Unicode scalar/grapheme length, slicing, indexing, stable string ABI/layout. |
|
| `std.string.len` | `(string) -> i32` | v1.5 | `examples/supported/standard-runtime.slo` | Returns the existing decoded byte-count length used by legacy `string_len`. | Uses existing standard-runtime usage recording if present; no schema change. | Unicode scalar/grapheme length, slicing, indexing, stable string ABI/layout. |
|
||||||
| `std.string.concat` | `(string, string) -> string` | exp-1 | `examples/supported/owned-string-concat.slo` | Returns an immutable runtime-owned string; allocation failure traps as `slovo runtime error: string allocation failed`. | Uses existing standard-runtime usage recording if present; no concat-specific schema field. | Mutable strings, string containers, user-visible allocation/deallocation, stable string ABI/layout. |
|
| `std.string.concat` | `(string, string) -> string` | exp-1 | `examples/supported/owned-string-concat.slo` | Returns an immutable runtime-owned string; allocation failure traps as `slovo runtime error: string allocation failed`. | Uses existing standard-runtime usage recording if present; no concat-specific schema field. | Mutable strings, string containers, user-visible allocation/deallocation, stable string ABI/layout. |
|
||||||
| `std.string.byte_at_result` | `(string, i32) -> (result i32 i32)` | `1.0.0-beta.16` | `examples/projects/std-layout-local-string` | Returns `ok byte` for a valid zero-based byte index before the trailing NUL, or `err 1` for an invalid index. | Uses existing standard-runtime usage recording if present; no schema change. | Character/grapheme indexing, unchecked indexing, Unicode scalar values, stable string ABI/layout. |
|
| `std.json.quote_string` | `(string) -> string` | `1.0.0-beta.7` | `examples/projects/std-layout-local-json` | Returns a compact JSON string literal for the input text, including surrounding quotes; it escapes quote, backslash, newline, tab, carriage return, backspace, form feed, and other control bytes as JSON escapes. Allocation failure traps as `slovo runtime error: string allocation failed`. | Uses existing standard-runtime usage recording if present; no schema change. | JSON parsing, recursive JSON values, maps/sets, streaming encoders, schema validation, Unicode normalization, embedded NUL support in the current null-terminated string ABI, stable helper ABI/layout/ownership. |
|
||||||
| `std.string.slice_result` | `(string, i32, i32) -> (result string i32)` | `1.0.0-beta.16` | `examples/projects/std-layout-local-string` | Returns `ok text` for a valid byte range before the trailing NUL, or `err 1` for an invalid range; allocation failure may trap with the existing string allocation policy. | Uses existing standard-runtime usage recording if present; no schema change. | Borrowed substring views, language slice/view syntax, Unicode/grapheme slicing, stable string ABI/layout/ownership. |
|
|
||||||
| `std.string.starts_with` | `(string, string) -> bool` | `1.0.0-beta.16` | `examples/projects/std-layout-local-string` | Returns whether the first string starts with the prefix bytes; the empty prefix matches. | Uses existing standard-runtime usage recording if present; no schema change. | Locale-sensitive matching, case folding, Unicode normalization, tokenizer/parser APIs, stable string ABI/layout. |
|
|
||||||
| `std.string.ends_with` | `(string, string) -> bool` | `1.0.0-beta.16` | `examples/projects/std-layout-local-string` | Returns whether the first string ends with the suffix bytes; the empty suffix matches. | Uses existing standard-runtime usage recording if present; no schema change. | Locale-sensitive matching, case folding, Unicode normalization, tokenizer/parser APIs, stable string ABI/layout. |
|
|
||||||
| `std.json.quote_string` | `(string) -> string` | `1.0.0-beta.7` | `examples/projects/std-layout-local-json` | Returns a compact JSON string literal for the input text, including surrounding quotes; it escapes quote, backslash, newline, tab, carriage return, backspace, form feed, and other control bytes as JSON escapes. Allocation failure traps as `slovo runtime error: string allocation failed`. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, recursive JSON values, maps/sets, streaming encoders, schema validation, Unicode normalization, embedded NUL support in the current null-terminated string ABI, stable helper ABI/layout/ownership. |
|
|
||||||
| `std.json.parse_string_value_result` | `(string) -> (result string i32)` | `1.0.0-beta.18` | `examples/projects/std-layout-local-json` | Returns `ok decoded` for one exact ASCII JSON string token with surrounding quotes and simple escapes, or `err 1` for ordinary parse failure; rejects leading/trailing whitespace, raw control bytes, raw non-ASCII bytes, raw quote/backslash, trailing bytes, and all `\uXXXX` escapes. Allocation failure may trap with the existing string allocation policy. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, object/array/value parsing, Unicode escape decoding, Unicode normalization, embedded NUL support in the current null-terminated string ABI, stable parse error taxonomy, stable helper ABI/layout/ownership. |
|
|
||||||
| `std.json.parse_bool_value_result` | `(string) -> (result bool i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok true` for exact `true`, `ok false` for exact `false`, or `err 1` otherwise. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, whitespace-tolerant document parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.json.parse_i32_value_result` | `(string) -> (result i32 i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok value` for a whole JSON integer token in signed `i32` range, or `err 1`; rejects leading/trailing whitespace, leading `+`, and leading-zero integer forms except `0`. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, generic numeric parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.json.parse_u32_value_result` | `(string) -> (result u32 i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok value` for a whole non-negative JSON integer token in `u32` range, or `err 1`; rejects leading/trailing whitespace, leading `+`, negative tokens, and leading-zero integer forms except `0`. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, generic numeric parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.json.parse_i64_value_result` | `(string) -> (result i64 i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok value` for a whole JSON integer token in signed `i64` range, or `err 1`; rejects leading/trailing whitespace, leading `+`, and leading-zero integer forms except `0`. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, generic numeric parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.json.parse_u64_value_result` | `(string) -> (result u64 i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok value` for a whole non-negative JSON integer token in `u64` range, or `err 1`; rejects leading/trailing whitespace, leading `+`, negative tokens, and leading-zero integer forms except `0`. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, generic numeric parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.json.parse_f64_value_result` | `(string) -> (result f64 i32)` | `1.0.0-beta.17` | `examples/projects/std-layout-local-json` | Returns `ok value` for a whole finite JSON number token, including exponent form, or `err 1`; rejects leading/trailing whitespace, leading `+`, leading-zero whole-number forms except `0`, and non-finite results. | Uses existing standard-runtime usage recording if present; no schema change. | Full JSON parsing, generic numeric parsing, stable parse error taxonomy, stable helper ABI/layout. |
|
|
||||||
| `std.vec.i32.empty` | `() -> (vec i32)` | exp-2 | `examples/supported/vec-i32.slo` | Returns an empty immutable runtime-owned `(vec i32)`. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Generic vectors, element families beyond current concrete vector families, vector mutation, stable vector ABI/layout. |
|
| `std.vec.i32.empty` | `() -> (vec i32)` | exp-2 | `examples/supported/vec-i32.slo` | Returns an empty immutable runtime-owned `(vec i32)`. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Generic vectors, element families beyond current concrete vector families, vector mutation, stable vector ABI/layout. |
|
||||||
| `std.vec.i32.append` | `((vec i32), i32) -> (vec i32)` | exp-2 | `examples/supported/vec-i32.slo` | Returns a new immutable vector containing the input elements and appended value; allocation failure traps with the exp-2 vector allocation message. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Mutation, `push`, capacity APIs, user deallocation, stable vector ABI/layout. |
|
| `std.vec.i32.append` | `((vec i32), i32) -> (vec i32)` | exp-2 | `examples/supported/vec-i32.slo` | Returns a new immutable vector containing the input elements and appended value; allocation failure traps with the exp-2 vector allocation message. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Mutation, `push`, capacity APIs, user deallocation, stable vector ABI/layout. |
|
||||||
| `std.vec.i32.len` | `((vec i32)) -> i32` | exp-2 | `examples/supported/vec-i32.slo` | Returns vector length as `i32`. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Generic length APIs and stable vector ABI/layout. |
|
| `std.vec.i32.len` | `((vec i32)) -> i32` | exp-2 | `examples/supported/vec-i32.slo` | Returns vector length as `i32`. | Uses existing standard-runtime usage recording if present; no vector-specific schema field. | Generic length APIs and stable vector ABI/layout. |
|
||||||
@ -214,10 +183,8 @@ integer-to-string calls, the exp-26 f64-to-string call, and the released
|
|||||||
`std.string.parse_i64_result` /
|
`std.string.parse_i64_result` /
|
||||||
`std.string.parse_f64_result` /
|
`std.string.parse_f64_result` /
|
||||||
`std.string.parse_bool_result` result calls, bool parsing beyond exact
|
`std.string.parse_bool_result` result calls, bool parsing beyond exact
|
||||||
lowercase `true`/`false`, string scanning/tokenizing APIs beyond
|
lowercase `true`/`false`, string/bytes parse,
|
||||||
`1.0.0-beta.16` byte access, substring, and prefix/suffix helpers,
|
underscores, rich parse errors, Unicode digit parsing, f64 containers,
|
||||||
string/bytes parse, underscores, rich parse errors, Unicode digit parsing,
|
|
||||||
f64 containers,
|
|
||||||
writable resource handles, binary IO, directory handles, directory
|
writable resource handles, binary IO, directory handles, directory
|
||||||
enumeration, recursive filesystem operations, process handles, sockets, async
|
enumeration, recursive filesystem operations, process handles, sockets, async
|
||||||
resource handling, platform-specific host error codes, rich host-error ADTs,
|
resource handling, platform-specific host error codes, rich host-error ADTs,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,68 +0,0 @@
|
|||||||
# Slovo Standard Library Stability Tiers
|
|
||||||
|
|
||||||
Status: beta public ledger for `1.0.0-beta.23`.
|
|
||||||
|
|
||||||
This document records the current maturity labels for the source-authored
|
|
||||||
standard-library facade surface. Exact exported helper signatures remain in
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md), which is generated from `lib/std/*.slo`.
|
|
||||||
This ledger explains how to read that catalog during the beta line.
|
|
||||||
|
|
||||||
`1.0.0-beta.23` is documentation and catalog-tooling alignment only. It adds no
|
|
||||||
source syntax, standard-library helpers, compiler-known runtime names, runtime
|
|
||||||
behavior, package behavior, manifest schema guarantee, Markdown schema
|
|
||||||
guarantee, ABI/layout guarantee, or stable standard-library/API compatibility
|
|
||||||
freeze. It does make the generated API catalog emit tier metadata and makes the
|
|
||||||
release gate check that experimental tier metadata is present.
|
|
||||||
|
|
||||||
## Tier Labels
|
|
||||||
|
|
||||||
Slovo uses these public standard-library tier labels:
|
|
||||||
|
|
||||||
| Tier | Meaning |
|
|
||||||
| --- | --- |
|
|
||||||
| `beta-supported` | Exported from `lib/std`, covered by current beta source-search, promotion, facade, or composition gates, and suitable for beta programs. Names and behavior are still beta contracts, not a stable `1.0.0` freeze. |
|
|
||||||
| `experimental` | Exported or documented in the beta line, but intentionally fluid because the domain still depends on deferred language, runtime, resource, platform, or schema policy. Use for feedback and narrow programs, not compatibility promises. |
|
|
||||||
| `internal` | Not public standard-library API. This includes non-exported helper names, module-local concrete aliases, implementation details, generated-document internals, and private runtime symbols. Internal names may be omitted from public catalogs or changed without migration promises. |
|
|
||||||
|
|
||||||
## Catalog Boundary
|
|
||||||
|
|
||||||
[`STDLIB_API.md`](STDLIB_API.md) is the generated signature inventory: it lists
|
|
||||||
exported `(fn ...)` helpers from `lib/std/*.slo`, normalizes module-local
|
|
||||||
concrete aliases to public concrete types, and omits non-exported helpers and
|
|
||||||
`(type ...)` aliases.
|
|
||||||
|
|
||||||
This ledger is the public maturity companion to that generated catalog. If the
|
|
||||||
catalog lists a signature, read the tier marker beside that signature as the
|
|
||||||
generated summary of this ledger. The generated catalog is a beta discovery
|
|
||||||
aid, not a stable Markdown schema or stable API freeze.
|
|
||||||
|
|
||||||
## Current Tier Ledger
|
|
||||||
|
|
||||||
| Surface | Current tier | Notes |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `std.cli`, `std.env`, `std.io`, `std.math`, `std.num`, `std.option`, `std.process`, `std.result`, and byte-oriented `std.string` helpers | `beta-supported` | Current source facade helpers over promoted concrete runtime/value families. The beta label still allows additive changes and scoped migrations before `1.0.0`. |
|
|
||||||
| Concrete vector modules: `std.vec_i32`, `std.vec_i64`, `std.vec_f64`, `std.vec_bool`, and `std.vec_string` | `beta-supported` | These are concrete immutable vector lanes over existing concrete runtime families. This is not a generic collections freeze and does not imply executable generics, generic aliases, maps, sets, iterators, mutable vectors, slice/view APIs, runtime collection changes, or stable ABI/layout. |
|
|
||||||
| Basic filesystem text/status helpers such as `read_text`, `write_text_result`, `exists`, `is_file`, `is_dir`, `remove_file_result`, and `create_dir_result` | `beta-supported` | Current concrete file helpers remain beta contracts over host filesystem behavior. Platform-specific errors and richer host-error ADTs remain deferred. |
|
|
||||||
| Filesystem resource-handle helpers such as `open_text_read_result`, `read_open_text_result`, `close_result`, `read_text_via_handle_result`, and `close_ok` | `experimental` | Handles are beta-scoped opaque `i32` values. Writable handles, directory handles/enumeration, stable handle ABI/layout, and richer platform error policy remain deferred. |
|
|
||||||
| `std.json` | `experimental` | Includes compact JSON text construction, exact primitive scalar token parsing, ASCII string-token parsing, and scalar document parsing. Object/array parsing, recursive `JsonValue`, parser/tokenizer objects, maps/sets, streaming, broad Unicode escape policy, embedded NUL policy, stable text encoding policy, and stable JSON API compatibility remain deferred. |
|
|
||||||
| `std.net` | `experimental` | Current blocking loopback TCP facade only. DNS, TLS, UDP, async IO, non-loopback binding, HTTP frameworks, stable socket ABI/layout, and rich host-error ADTs remain deferred. |
|
|
||||||
| `std.random` and `std.time` | `experimental` | Available as narrow beta host facades, but deterministic testing policy, seeding/time-source contracts, monotonic/wall-clock distinctions, reproducibility guarantees, and stable platform behavior remain deferred. |
|
|
||||||
| Non-exported helper names, module-local aliases, private runtime symbols, generated catalog internals, and release-tool implementation details | `internal` | Not part of the public standard-library compatibility surface. |
|
|
||||||
|
|
||||||
## Explicit Non-Changes
|
|
||||||
|
|
||||||
This ledger does not promote:
|
|
||||||
|
|
||||||
- source-language syntax
|
|
||||||
- standard-library helper additions, removals, or renames
|
|
||||||
- compiler-known runtime names
|
|
||||||
- runtime behavior changes
|
|
||||||
- executable generics or generic aliases
|
|
||||||
- generic stdlib dispatch
|
|
||||||
- maps, sets, iterators, mutable vectors, or slice/view APIs
|
|
||||||
- object/array JSON parsing or stable JSON schemas
|
|
||||||
- DNS, TLS, UDP, async networking, or non-loopback binding
|
|
||||||
- stable resource-handle ABI/layout
|
|
||||||
- stable artifact-manifest schema
|
|
||||||
- stable generated Markdown schema
|
|
||||||
- stable `1.0.0` standard-library/API compatibility freeze
|
|
||||||
@ -14,10 +14,6 @@ catalog and the checked `projects/stdlib-composition/` example.
|
|||||||
`projects/std-layout-local-json/` examples for compact JSON text construction.
|
`projects/std-layout-local-json/` examples for compact JSON text construction.
|
||||||
`1.0.0-beta.8` reuses those JSON projects for local `JsonText`/`JsonField`
|
`1.0.0-beta.8` reuses those JSON projects for local `JsonText`/`JsonField`
|
||||||
concrete type alias fixtures.
|
concrete type alias fixtures.
|
||||||
Slovo-facing `1.0.0-beta.17` extends those JSON projects with primitive scalar
|
|
||||||
token parse success and failure checks only.
|
|
||||||
Slovo-facing `1.0.0-beta.18` extends those same JSON projects with
|
|
||||||
ASCII JSON string-token parse success and failure checks.
|
|
||||||
`1.0.0-beta.9` keeps the existing explicit std-import projects concrete while
|
`1.0.0-beta.9` keeps the existing explicit std-import projects concrete while
|
||||||
the underlying vector, option, and result facades use module-local aliases.
|
the underlying vector, option, and result facades use module-local aliases.
|
||||||
The language
|
The language
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.string (len concat byte_at_result slice_result starts_with ends_with contains index_of_option last_index_of_option trim_ascii_start trim_ascii_end trim_ascii parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
(import std.string (len concat parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
||||||
|
|
||||||
(fn imported_string_concat () -> string
|
(fn imported_string_concat () -> string
|
||||||
(concat "slo" "vo"))
|
(concat "slo" "vo"))
|
||||||
@ -8,37 +8,6 @@
|
|||||||
(fn imported_string_len_concat_score () -> i32
|
(fn imported_string_len_concat_score () -> i32
|
||||||
(+ (len (imported_string_concat)) 37))
|
(+ (len (imported_string_concat)) 37))
|
||||||
|
|
||||||
(fn imported_string_byte_at_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 0)) 115)
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 3)) 118)
|
|
||||||
(if (= (unwrap_err (byte_at_result "slovo" -1)) 1)
|
|
||||||
(= (unwrap_err (byte_at_result "slovo" 5)) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_slice_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 1 3)) "lov")
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 0 5)) "slovo")
|
|
||||||
(= (unwrap_err (slice_result "slovo" 4 2)) 1)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_boundaries_ok () -> bool
|
|
||||||
(if (starts_with "slovo" "slo")
|
|
||||||
(if (starts_with "slovo" "")
|
|
||||||
(if (starts_with "slovo" "ovo")
|
|
||||||
false
|
|
||||||
(if (ends_with "slovo" "ovo")
|
|
||||||
(if (ends_with "slovo" "")
|
|
||||||
(if (ends_with "slovo" "slo")
|
|
||||||
false
|
|
||||||
true)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_parse_result_ok () -> bool
|
(fn imported_string_parse_result_ok () -> bool
|
||||||
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
||||||
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
||||||
@ -187,67 +156,13 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_option_i32_is_some_value ((actual (option i32)) (expected i32)) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
(= payload expected))
|
|
||||||
((none)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn imported_option_i32_is_none ((actual (option i32))) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
false)
|
|
||||||
((none)
|
|
||||||
true)))
|
|
||||||
|
|
||||||
(fn imported_string_search_ok () -> bool
|
|
||||||
(if (contains "alpha beta alpha" "beta")
|
|
||||||
(if (contains "alpha" "z")
|
|
||||||
false
|
|
||||||
(if (contains "alpha" "")
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha beta alpha" "alpha") 0)
|
|
||||||
(if (imported_option_i32_is_none (index_of_option "alpha" "z"))
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha" "") 0)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha beta alpha" "alpha") 11)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha" "") 5)
|
|
||||||
(imported_option_i32_is_none (last_index_of_option "alpha" "z"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_ascii_trim_ok () -> bool
|
|
||||||
(if (= (trim_ascii_start " \t\nslovo") "slovo")
|
|
||||||
(if (= (trim_ascii_end "slovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\nslovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\n") "")
|
|
||||||
(= (trim_ascii "slovo") "slovo")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_helpers_ok () -> bool
|
(fn imported_string_helpers_ok () -> bool
|
||||||
(if (= (imported_string_len_concat_score) 42)
|
(if (= (imported_string_len_concat_score) 42)
|
||||||
(if (imported_string_byte_at_ok)
|
(if (imported_string_parse_result_ok)
|
||||||
(if (imported_string_slice_ok)
|
(if (imported_string_parse_options_ok)
|
||||||
(if (imported_string_boundaries_ok)
|
(if (imported_string_parse_integer_fallbacks_ok)
|
||||||
(if (imported_string_parse_result_ok)
|
(if (imported_string_parse_float_bool_fallbacks_ok)
|
||||||
(if (imported_string_parse_options_ok)
|
(imported_string_parse_custom_fallbacks_ok)
|
||||||
(if (imported_string_parse_integer_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_float_bool_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_custom_fallbacks_ok)
|
|
||||||
(if (imported_string_search_ok)
|
|
||||||
(imported_string_ascii_trim_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -262,15 +177,6 @@
|
|||||||
(test "explicit std string len concat"
|
(test "explicit std string len concat"
|
||||||
(= (imported_string_len_concat_score) 42))
|
(= (imported_string_len_concat_score) 42))
|
||||||
|
|
||||||
(test "explicit std string byte_at_result wrapper"
|
|
||||||
(imported_string_byte_at_ok))
|
|
||||||
|
|
||||||
(test "explicit std string slice_result wrapper"
|
|
||||||
(imported_string_slice_ok))
|
|
||||||
|
|
||||||
(test "explicit std string boundary wrappers"
|
|
||||||
(imported_string_boundaries_ok))
|
|
||||||
|
|
||||||
(test "explicit std string parse result wrappers"
|
(test "explicit std string parse result wrappers"
|
||||||
(imported_string_parse_result_ok))
|
(imported_string_parse_result_ok))
|
||||||
|
|
||||||
@ -286,11 +192,5 @@
|
|||||||
(test "explicit std string parse custom fallbacks"
|
(test "explicit std string parse custom fallbacks"
|
||||||
(imported_string_parse_custom_fallbacks_ok))
|
(imported_string_parse_custom_fallbacks_ok))
|
||||||
|
|
||||||
(test "explicit std string search helpers"
|
|
||||||
(imported_string_search_ok))
|
|
||||||
|
|
||||||
(test "explicit std string ascii trim helpers"
|
|
||||||
(imported_string_ascii_trim_ok))
|
|
||||||
|
|
||||||
(test "explicit std string helpers all"
|
(test "explicit std string helpers all"
|
||||||
(= (main) 42))
|
(= (main) 42))
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import std.vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,16 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec f64) (append3 (pair 10.0 20.0) 30.0 20.0 10.0))
|
|
||||||
(if (= (count_of (empty) 20.0) 0)
|
|
||||||
(if (= (count_of values 99.0) 0)
|
|
||||||
(if (= (count_of values 20.0) 2)
|
|
||||||
(= (count_of values 10.0) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
(fn imported_starts_with_helper_ok () -> bool
|
||||||
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
||||||
(let prefix (vec f64) (pair 10.0 20.0))
|
(let prefix (vec f64) (pair 10.0 20.0))
|
||||||
@ -295,21 +285,19 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_starts_with_helper_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_ends_with_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_without_suffix_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_without_prefix_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_replace_helper_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_replace_range_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_remove_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_remove_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,9 +331,6 @@
|
|||||||
(test "explicit std vec_f64 option query helpers"
|
(test "explicit std vec_f64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit std vec_f64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_f64 starts_with helper"
|
(test "explicit std vec_f64 starts_with helper"
|
||||||
(imported_starts_with_helper_ok))
|
(imported_starts_with_helper_ok))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import std.vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,92 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append3 (pair 10i64 20i64) 30i64 20i64 10i64))
|
|
||||||
(if (= (count_of (empty) 20i64) 0)
|
|
||||||
(if (= (count_of values 99i64) 0)
|
|
||||||
(if (= (count_of values 20i64) 2)
|
|
||||||
(= (count_of values 10i64) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 20i64 30i64))
|
|
||||||
(if (starts_with values (empty))
|
|
||||||
(if (starts_with values prefix)
|
|
||||||
(if (starts_with values values)
|
|
||||||
(if (starts_with values longer_prefix)
|
|
||||||
false
|
|
||||||
(if (starts_with values mismatched_prefix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_ends_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (ends_with values (empty))
|
|
||||||
(if (ends_with values suffix)
|
|
||||||
(if (ends_with values values)
|
|
||||||
(if (ends_with values longer_suffix)
|
|
||||||
false
|
|
||||||
(if (ends_with values mismatched_suffix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_suffix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (= (without_suffix values (empty)) values)
|
|
||||||
(if (= (without_suffix values values) (empty))
|
|
||||||
(if (= (without_suffix values suffix) (triple 10i64 20i64 30i64))
|
|
||||||
(if (= (without_suffix values longer_suffix) values)
|
|
||||||
(if (= (without_suffix values mismatched_suffix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_prefix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 10i64 21i64))
|
|
||||||
(if (= (without_prefix values (empty)) values)
|
|
||||||
(if (= (without_prefix values values) (empty))
|
|
||||||
(if (= (without_prefix values prefix) (triple 30i64 40i64 50i64))
|
|
||||||
(if (= (without_prefix values longer_prefix) values)
|
|
||||||
(if (= (without_prefix values mismatched_prefix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_transform_helpers_ok () -> bool
|
(fn imported_transform_helpers_ok () -> bool
|
||||||
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
||||||
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
||||||
@ -295,25 +209,15 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(if (imported_replace_helper_ok)
|
|
||||||
(if (imported_replace_range_helper_ok)
|
|
||||||
(if (imported_remove_helper_ok)
|
|
||||||
(if (imported_remove_range_helper_ok)
|
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,21 +247,6 @@
|
|||||||
(test "explicit std vec_i64 option query helpers"
|
(test "explicit std vec_i64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit std vec_i64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 starts_with helper"
|
|
||||||
(imported_starts_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 ends_with helper"
|
|
||||||
(imported_ends_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 without_suffix helper"
|
|
||||||
(imported_without_suffix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 without_prefix helper"
|
|
||||||
(imported_without_prefix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 transform helpers"
|
(test "explicit std vec_i64 transform helpers"
|
||||||
(imported_transform_helpers_ok))
|
(imported_transform_helpers_ok))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
(import std.json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
||||||
|
|
||||||
(type JsonText string)
|
(type JsonText string)
|
||||||
|
|
||||||
@ -32,117 +32,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_json_parse_scalar_success () -> bool
|
|
||||||
(if (unwrap_ok (parse_bool_value_result "true"))
|
|
||||||
(if (= (unwrap_ok (parse_i32_value_result "-7")) -7)
|
|
||||||
(if (= (unwrap_ok (parse_u32_value_result "7")) 7u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_value_result "8")) 8i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_value_result "9")) 9u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_value_result "1e2")) 100.0)
|
|
||||||
(unwrap_ok (parse_null_value_result "null"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_scalar_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_bool_value_result "TRUE")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i32_value_result "01")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u32_value_result "-1")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i64_value_result "8i64")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u64_value_result "")) 1)
|
|
||||||
(if (= (unwrap_err (parse_f64_value_result "01.0")) 1)
|
|
||||||
(= (unwrap_err (parse_null_value_result "NULL")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_string_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slovo\"")) "slovo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slo\\\"vo\"")) "slo\"vo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slo\\\\vo\"")) "slo\\vo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"a\\/b\"")) "a/b")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"line\\nnext\"")) "line\nnext")
|
|
||||||
(= (unwrap_ok (parse_string_value_result "\"tab\\tnext\"")) "tab\tnext")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_string_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "slovo")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result " \"slovo\"")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo\" ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo\"x")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"\\x\"")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"\n\"")) 1)
|
|
||||||
(= (unwrap_err (parse_string_value_result "\"\\u0041\"")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_trimmed_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_document_result " \t\n\"slovo\" \n\t")) "slovo")
|
|
||||||
(if (unwrap_ok (parse_bool_document_result "\n true \t"))
|
|
||||||
(if (= (unwrap_ok (parse_i32_document_result " -7 ")) -7)
|
|
||||||
(if (= (unwrap_ok (parse_u32_document_result " 7 ")) 7u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_document_result " 8 ")) 8i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_document_result " 9 ")) 9u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
|
|
||||||
(unwrap_ok (parse_null_document_result " null "))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_plain_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_document_result "\"plain\"")) "plain")
|
|
||||||
(if (= (unwrap_ok (parse_bool_document_result "false")) false)
|
|
||||||
(if (= (unwrap_ok (parse_i32_document_result "-8")) -8)
|
|
||||||
(if (= (unwrap_ok (parse_u32_document_result "8")) 8u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_document_result "9")) 9i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_document_result "10")) 10u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_document_result "1.5")) 1.5)
|
|
||||||
(unwrap_ok (parse_null_document_result "null"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_trailing_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_string_document_result " \t\"slovo\"x \n")) 1)
|
|
||||||
(if (= (unwrap_err (parse_bool_document_result " truex ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i32_document_result " -7x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u32_document_result " 7x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i64_document_result " 8x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u64_document_result " 9x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_f64_document_result " 1.5x ")) 1)
|
|
||||||
(= (unwrap_err (parse_null_document_result " nullx ")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_fields () -> bool
|
(fn imported_json_fields () -> bool
|
||||||
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
|
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
|
||||||
(if (= (field_bool "ok" true) "\"ok\":true")
|
(if (= (field_bool "ok" true) "\"ok\":true")
|
||||||
@ -186,22 +75,8 @@
|
|||||||
(fn imported_json_all () -> bool
|
(fn imported_json_all () -> bool
|
||||||
(if (imported_json_quote_escapes)
|
(if (imported_json_quote_escapes)
|
||||||
(if (imported_json_scalar_values)
|
(if (imported_json_scalar_values)
|
||||||
(if (imported_json_parse_scalar_success)
|
(if (imported_json_fields)
|
||||||
(if (imported_json_parse_scalar_failure)
|
(imported_json_arrays_objects)
|
||||||
(if (imported_json_parse_string_success)
|
|
||||||
(if (imported_json_parse_string_failure)
|
|
||||||
(if (imported_json_parse_document_trimmed_success)
|
|
||||||
(if (imported_json_parse_document_plain_success)
|
|
||||||
(if (imported_json_parse_document_trailing_failure)
|
|
||||||
(if (imported_json_fields)
|
|
||||||
(imported_json_arrays_objects)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
@ -217,27 +92,6 @@
|
|||||||
(test "explicit std json scalar values facade"
|
(test "explicit std json scalar values facade"
|
||||||
(imported_json_scalar_values))
|
(imported_json_scalar_values))
|
||||||
|
|
||||||
(test "explicit std json primitive scalar parse success facade"
|
|
||||||
(imported_json_parse_scalar_success))
|
|
||||||
|
|
||||||
(test "explicit std json primitive scalar parse failure facade"
|
|
||||||
(imported_json_parse_scalar_failure))
|
|
||||||
|
|
||||||
(test "explicit std json string token parse success facade"
|
|
||||||
(imported_json_parse_string_success))
|
|
||||||
|
|
||||||
(test "explicit std json string token parse failure facade"
|
|
||||||
(imported_json_parse_string_failure))
|
|
||||||
|
|
||||||
(test "explicit std json document parse trimmed success facade"
|
|
||||||
(imported_json_parse_document_trimmed_success))
|
|
||||||
|
|
||||||
(test "explicit std json document parse plain success facade"
|
|
||||||
(imported_json_parse_document_plain_success))
|
|
||||||
|
|
||||||
(test "explicit std json document parse trailing failure facade"
|
|
||||||
(imported_json_parse_document_trailing_failure))
|
|
||||||
|
|
||||||
(test "explicit std json fields facade"
|
(test "explicit std json fields facade"
|
||||||
(imported_json_fields))
|
(imported_json_fields))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.string (len concat byte_at_result slice_result starts_with ends_with contains index_of_option last_index_of_option trim_ascii_start trim_ascii_end trim_ascii parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
(import std.string (len concat parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
||||||
|
|
||||||
(fn imported_string_concat () -> string
|
(fn imported_string_concat () -> string
|
||||||
(concat "slo" "vo"))
|
(concat "slo" "vo"))
|
||||||
@ -8,37 +8,6 @@
|
|||||||
(fn imported_string_len_concat_score () -> i32
|
(fn imported_string_len_concat_score () -> i32
|
||||||
(+ (len (imported_string_concat)) 37))
|
(+ (len (imported_string_concat)) 37))
|
||||||
|
|
||||||
(fn imported_string_byte_at_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 0)) 115)
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 3)) 118)
|
|
||||||
(if (= (unwrap_err (byte_at_result "slovo" -1)) 1)
|
|
||||||
(= (unwrap_err (byte_at_result "slovo" 5)) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_slice_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 1 3)) "lov")
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 0 5)) "slovo")
|
|
||||||
(= (unwrap_err (slice_result "slovo" 4 2)) 1)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_boundaries_ok () -> bool
|
|
||||||
(if (starts_with "slovo" "slo")
|
|
||||||
(if (starts_with "slovo" "")
|
|
||||||
(if (starts_with "slovo" "ovo")
|
|
||||||
false
|
|
||||||
(if (ends_with "slovo" "ovo")
|
|
||||||
(if (ends_with "slovo" "")
|
|
||||||
(if (ends_with "slovo" "slo")
|
|
||||||
false
|
|
||||||
true)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_parse_result_ok () -> bool
|
(fn imported_string_parse_result_ok () -> bool
|
||||||
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
||||||
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
||||||
@ -187,67 +156,13 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_option_i32_is_some_value ((actual (option i32)) (expected i32)) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
(= payload expected))
|
|
||||||
((none)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn imported_option_i32_is_none ((actual (option i32))) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
false)
|
|
||||||
((none)
|
|
||||||
true)))
|
|
||||||
|
|
||||||
(fn imported_string_search_ok () -> bool
|
|
||||||
(if (contains "alpha beta alpha" "beta")
|
|
||||||
(if (contains "alpha" "z")
|
|
||||||
false
|
|
||||||
(if (contains "alpha" "")
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha beta alpha" "alpha") 0)
|
|
||||||
(if (imported_option_i32_is_none (index_of_option "alpha" "z"))
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha" "") 0)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha beta alpha" "alpha") 11)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha" "") 5)
|
|
||||||
(imported_option_i32_is_none (last_index_of_option "alpha" "z"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_ascii_trim_ok () -> bool
|
|
||||||
(if (= (trim_ascii_start " \t\nslovo") "slovo")
|
|
||||||
(if (= (trim_ascii_end "slovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\nslovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\n") "")
|
|
||||||
(= (trim_ascii "slovo") "slovo")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_helpers_ok () -> bool
|
(fn imported_string_helpers_ok () -> bool
|
||||||
(if (= (imported_string_len_concat_score) 42)
|
(if (= (imported_string_len_concat_score) 42)
|
||||||
(if (imported_string_byte_at_ok)
|
(if (imported_string_parse_result_ok)
|
||||||
(if (imported_string_slice_ok)
|
(if (imported_string_parse_options_ok)
|
||||||
(if (imported_string_boundaries_ok)
|
(if (imported_string_parse_integer_fallbacks_ok)
|
||||||
(if (imported_string_parse_result_ok)
|
(if (imported_string_parse_float_bool_fallbacks_ok)
|
||||||
(if (imported_string_parse_options_ok)
|
(imported_string_parse_custom_fallbacks_ok)
|
||||||
(if (imported_string_parse_integer_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_float_bool_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_custom_fallbacks_ok)
|
|
||||||
(if (imported_string_search_ok)
|
|
||||||
(imported_string_ascii_trim_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -262,15 +177,6 @@
|
|||||||
(test "explicit std string len concat"
|
(test "explicit std string len concat"
|
||||||
(= (imported_string_len_concat_score) 42))
|
(= (imported_string_len_concat_score) 42))
|
||||||
|
|
||||||
(test "explicit std string byte_at_result wrapper"
|
|
||||||
(imported_string_byte_at_ok))
|
|
||||||
|
|
||||||
(test "explicit std string slice_result wrapper"
|
|
||||||
(imported_string_slice_ok))
|
|
||||||
|
|
||||||
(test "explicit std string boundary wrappers"
|
|
||||||
(imported_string_boundaries_ok))
|
|
||||||
|
|
||||||
(test "explicit std string parse result wrappers"
|
(test "explicit std string parse result wrappers"
|
||||||
(imported_string_parse_result_ok))
|
(imported_string_parse_result_ok))
|
||||||
|
|
||||||
@ -286,11 +192,5 @@
|
|||||||
(test "explicit std string parse custom fallbacks"
|
(test "explicit std string parse custom fallbacks"
|
||||||
(imported_string_parse_custom_fallbacks_ok))
|
(imported_string_parse_custom_fallbacks_ok))
|
||||||
|
|
||||||
(test "explicit std string search helpers"
|
|
||||||
(imported_string_search_ok))
|
|
||||||
|
|
||||||
(test "explicit std string ascii trim helpers"
|
|
||||||
(imported_string_ascii_trim_ok))
|
|
||||||
|
|
||||||
(test "explicit std string helpers all"
|
(test "explicit std string helpers all"
|
||||||
(= (main) 42))
|
(= (main) 42))
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import std.vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,16 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec f64) (append3 (pair 10.0 20.0) 30.0 20.0 10.0))
|
|
||||||
(if (= (count_of (empty) 20.0) 0)
|
|
||||||
(if (= (count_of values 99.0) 0)
|
|
||||||
(if (= (count_of values 20.0) 2)
|
|
||||||
(= (count_of values 10.0) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
(fn imported_starts_with_helper_ok () -> bool
|
||||||
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
||||||
(let prefix (vec f64) (pair 10.0 20.0))
|
(let prefix (vec f64) (pair 10.0 20.0))
|
||||||
@ -295,21 +285,19 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_starts_with_helper_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_ends_with_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_without_suffix_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_without_prefix_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_replace_helper_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_replace_range_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_remove_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_remove_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,9 +331,6 @@
|
|||||||
(test "explicit std vec_f64 option query helpers"
|
(test "explicit std vec_f64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit std vec_f64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_f64 starts_with helper"
|
(test "explicit std vec_f64 starts_with helper"
|
||||||
(imported_starts_with_helper_ok))
|
(imported_starts_with_helper_ok))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import std.vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import std.vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,92 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append3 (pair 10i64 20i64) 30i64 20i64 10i64))
|
|
||||||
(if (= (count_of (empty) 20i64) 0)
|
|
||||||
(if (= (count_of values 99i64) 0)
|
|
||||||
(if (= (count_of values 20i64) 2)
|
|
||||||
(= (count_of values 10i64) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 20i64 30i64))
|
|
||||||
(if (starts_with values (empty))
|
|
||||||
(if (starts_with values prefix)
|
|
||||||
(if (starts_with values values)
|
|
||||||
(if (starts_with values longer_prefix)
|
|
||||||
false
|
|
||||||
(if (starts_with values mismatched_prefix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_ends_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (ends_with values (empty))
|
|
||||||
(if (ends_with values suffix)
|
|
||||||
(if (ends_with values values)
|
|
||||||
(if (ends_with values longer_suffix)
|
|
||||||
false
|
|
||||||
(if (ends_with values mismatched_suffix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_suffix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (= (without_suffix values (empty)) values)
|
|
||||||
(if (= (without_suffix values values) (empty))
|
|
||||||
(if (= (without_suffix values suffix) (triple 10i64 20i64 30i64))
|
|
||||||
(if (= (without_suffix values longer_suffix) values)
|
|
||||||
(if (= (without_suffix values mismatched_suffix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_prefix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 10i64 21i64))
|
|
||||||
(if (= (without_prefix values (empty)) values)
|
|
||||||
(if (= (without_prefix values values) (empty))
|
|
||||||
(if (= (without_prefix values prefix) (triple 30i64 40i64 50i64))
|
|
||||||
(if (= (without_prefix values longer_prefix) values)
|
|
||||||
(if (= (without_prefix values mismatched_prefix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_transform_helpers_ok () -> bool
|
(fn imported_transform_helpers_ok () -> bool
|
||||||
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
||||||
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
||||||
@ -295,25 +209,15 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(if (imported_replace_helper_ok)
|
|
||||||
(if (imported_replace_range_helper_ok)
|
|
||||||
(if (imported_remove_helper_ok)
|
|
||||||
(if (imported_remove_range_helper_ok)
|
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,21 +247,6 @@
|
|||||||
(test "explicit std vec_i64 option query helpers"
|
(test "explicit std vec_i64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit std vec_i64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 starts_with helper"
|
|
||||||
(imported_starts_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 ends_with helper"
|
|
||||||
(imported_ends_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 without_suffix helper"
|
|
||||||
(imported_without_suffix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 without_prefix helper"
|
|
||||||
(imported_without_prefix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit std vec_i64 transform helpers"
|
(test "explicit std vec_i64 transform helpers"
|
||||||
(imported_transform_helpers_ok))
|
(imported_transform_helpers_ok))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
(module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
(module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
||||||
|
|
||||||
(import string (trim_ascii))
|
|
||||||
|
|
||||||
(type JsonText string)
|
(type JsonText string)
|
||||||
|
|
||||||
@ -32,56 +30,6 @@
|
|||||||
(fn f64_value ((value f64)) -> JsonText
|
(fn f64_value ((value f64)) -> JsonText
|
||||||
(std.num.f64_to_string value))
|
(std.num.f64_to_string value))
|
||||||
|
|
||||||
(fn parse_string_value_result ((token string)) -> (result string i32)
|
|
||||||
(std.json.parse_string_value_result token))
|
|
||||||
|
|
||||||
(fn parse_bool_value_result ((token string)) -> (result bool i32)
|
|
||||||
(std.json.parse_bool_value_result token))
|
|
||||||
|
|
||||||
(fn parse_i32_value_result ((token string)) -> (result i32 i32)
|
|
||||||
(std.json.parse_i32_value_result token))
|
|
||||||
|
|
||||||
(fn parse_u32_value_result ((token string)) -> (result u32 i32)
|
|
||||||
(std.json.parse_u32_value_result token))
|
|
||||||
|
|
||||||
(fn parse_i64_value_result ((token string)) -> (result i64 i32)
|
|
||||||
(std.json.parse_i64_value_result token))
|
|
||||||
|
|
||||||
(fn parse_u64_value_result ((token string)) -> (result u64 i32)
|
|
||||||
(std.json.parse_u64_value_result token))
|
|
||||||
|
|
||||||
(fn parse_f64_value_result ((token string)) -> (result f64 i32)
|
|
||||||
(std.json.parse_f64_value_result token))
|
|
||||||
|
|
||||||
(fn parse_null_value_result ((token string)) -> (result bool i32)
|
|
||||||
(if (= token "null")
|
|
||||||
(ok bool i32 true)
|
|
||||||
(err bool i32 1)))
|
|
||||||
|
|
||||||
(fn parse_string_document_result ((document string)) -> (result string i32)
|
|
||||||
(parse_string_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_bool_document_result ((document string)) -> (result bool i32)
|
|
||||||
(parse_bool_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_i32_document_result ((document string)) -> (result i32 i32)
|
|
||||||
(parse_i32_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_u32_document_result ((document string)) -> (result u32 i32)
|
|
||||||
(parse_u32_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_i64_document_result ((document string)) -> (result i64 i32)
|
|
||||||
(parse_i64_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_u64_document_result ((document string)) -> (result u64 i32)
|
|
||||||
(parse_u64_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_f64_document_result ((document string)) -> (result f64 i32)
|
|
||||||
(parse_f64_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn parse_null_document_result ((document string)) -> (result bool i32)
|
|
||||||
(parse_null_value_result (trim_ascii document)))
|
|
||||||
|
|
||||||
(fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField
|
(fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField
|
||||||
(std.string.concat (std.string.concat (quote_string name) ":") encoded_value))
|
(std.string.concat (std.string.concat (quote_string name) ":") encoded_value))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
(import json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
|
||||||
|
|
||||||
(type JsonText string)
|
(type JsonText string)
|
||||||
|
|
||||||
@ -32,117 +32,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_json_parse_scalar_success () -> bool
|
|
||||||
(if (unwrap_ok (parse_bool_value_result "true"))
|
|
||||||
(if (= (unwrap_ok (parse_i32_value_result "-7")) -7)
|
|
||||||
(if (= (unwrap_ok (parse_u32_value_result "7")) 7u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_value_result "8")) 8i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_value_result "9")) 9u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_value_result "1e2")) 100.0)
|
|
||||||
(unwrap_ok (parse_null_value_result "null"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_scalar_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_bool_value_result "TRUE")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i32_value_result "01")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u32_value_result "-1")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i64_value_result "8i64")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u64_value_result "")) 1)
|
|
||||||
(if (= (unwrap_err (parse_f64_value_result "01.0")) 1)
|
|
||||||
(= (unwrap_err (parse_null_value_result "NULL")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_string_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slovo\"")) "slovo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slo\\\"vo\"")) "slo\"vo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"slo\\\\vo\"")) "slo\\vo")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"a\\/b\"")) "a/b")
|
|
||||||
(if (= (unwrap_ok (parse_string_value_result "\"line\\nnext\"")) "line\nnext")
|
|
||||||
(= (unwrap_ok (parse_string_value_result "\"tab\\tnext\"")) "tab\tnext")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_string_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "slovo")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result " \"slovo\"")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo\" ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"slovo\"x")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"\\x\"")) 1)
|
|
||||||
(if (= (unwrap_err (parse_string_value_result "\"\n\"")) 1)
|
|
||||||
(= (unwrap_err (parse_string_value_result "\"\\u0041\"")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_trimmed_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_document_result " \t\n\"slovo\" \n\t")) "slovo")
|
|
||||||
(if (unwrap_ok (parse_bool_document_result "\n true \t"))
|
|
||||||
(if (= (unwrap_ok (parse_i32_document_result " -7 ")) -7)
|
|
||||||
(if (= (unwrap_ok (parse_u32_document_result " 7 ")) 7u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_document_result " 8 ")) 8i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_document_result " 9 ")) 9u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
|
|
||||||
(unwrap_ok (parse_null_document_result " null "))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_plain_success () -> bool
|
|
||||||
(if (= (unwrap_ok (parse_string_document_result "\"plain\"")) "plain")
|
|
||||||
(if (= (unwrap_ok (parse_bool_document_result "false")) false)
|
|
||||||
(if (= (unwrap_ok (parse_i32_document_result "-8")) -8)
|
|
||||||
(if (= (unwrap_ok (parse_u32_document_result "8")) 8u32)
|
|
||||||
(if (= (unwrap_ok (parse_i64_document_result "9")) 9i64)
|
|
||||||
(if (= (unwrap_ok (parse_u64_document_result "10")) 10u64)
|
|
||||||
(if (= (unwrap_ok (parse_f64_document_result "1.5")) 1.5)
|
|
||||||
(unwrap_ok (parse_null_document_result "null"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_parse_document_trailing_failure () -> bool
|
|
||||||
(if (= (unwrap_err (parse_string_document_result " \t\"slovo\"x \n")) 1)
|
|
||||||
(if (= (unwrap_err (parse_bool_document_result " truex ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i32_document_result " -7x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u32_document_result " 7x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_i64_document_result " 8x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_u64_document_result " 9x ")) 1)
|
|
||||||
(if (= (unwrap_err (parse_f64_document_result " 1.5x ")) 1)
|
|
||||||
(= (unwrap_err (parse_null_document_result " nullx ")) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_json_fields () -> bool
|
(fn imported_json_fields () -> bool
|
||||||
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
|
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
|
||||||
(if (= (field_bool "ok" true) "\"ok\":true")
|
(if (= (field_bool "ok" true) "\"ok\":true")
|
||||||
@ -186,22 +75,8 @@
|
|||||||
(fn imported_json_all () -> bool
|
(fn imported_json_all () -> bool
|
||||||
(if (imported_json_quote_escapes)
|
(if (imported_json_quote_escapes)
|
||||||
(if (imported_json_scalar_values)
|
(if (imported_json_scalar_values)
|
||||||
(if (imported_json_parse_scalar_success)
|
(if (imported_json_fields)
|
||||||
(if (imported_json_parse_scalar_failure)
|
(imported_json_arrays_objects)
|
||||||
(if (imported_json_parse_string_success)
|
|
||||||
(if (imported_json_parse_string_failure)
|
|
||||||
(if (imported_json_parse_document_trimmed_success)
|
|
||||||
(if (imported_json_parse_document_plain_success)
|
|
||||||
(if (imported_json_parse_document_trailing_failure)
|
|
||||||
(if (imported_json_fields)
|
|
||||||
(imported_json_arrays_objects)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
@ -217,27 +92,6 @@
|
|||||||
(test "explicit local json scalar values facade"
|
(test "explicit local json scalar values facade"
|
||||||
(imported_json_scalar_values))
|
(imported_json_scalar_values))
|
||||||
|
|
||||||
(test "explicit local json primitive scalar parse success facade"
|
|
||||||
(imported_json_parse_scalar_success))
|
|
||||||
|
|
||||||
(test "explicit local json primitive scalar parse failure facade"
|
|
||||||
(imported_json_parse_scalar_failure))
|
|
||||||
|
|
||||||
(test "explicit local json string token parse success facade"
|
|
||||||
(imported_json_parse_string_success))
|
|
||||||
|
|
||||||
(test "explicit local json string token parse failure facade"
|
|
||||||
(imported_json_parse_string_failure))
|
|
||||||
|
|
||||||
(test "explicit local json document parse trimmed success facade"
|
|
||||||
(imported_json_parse_document_trimmed_success))
|
|
||||||
|
|
||||||
(test "explicit local json document parse plain success facade"
|
|
||||||
(imported_json_parse_document_plain_success))
|
|
||||||
|
|
||||||
(test "explicit local json document parse trailing failure facade"
|
|
||||||
(imported_json_parse_document_trailing_failure))
|
|
||||||
|
|
||||||
(test "explicit local json fields facade"
|
(test "explicit local json fields facade"
|
||||||
(imported_json_fields))
|
(imported_json_fields))
|
||||||
|
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
(module string (export trim_ascii))
|
|
||||||
|
|
||||||
(fn len ((value string)) -> i32
|
|
||||||
(std.string.len value))
|
|
||||||
|
|
||||||
(fn byte_at_result ((value string) (index i32)) -> (result i32 i32)
|
|
||||||
(std.string.byte_at_result value index))
|
|
||||||
|
|
||||||
(fn slice_result ((value string) (start i32) (count i32)) -> (result string i32)
|
|
||||||
(std.string.slice_result value start count))
|
|
||||||
|
|
||||||
(fn is_ascii_trim_byte ((value i32)) -> bool
|
|
||||||
(if (= value 9)
|
|
||||||
true
|
|
||||||
(if (= value 10)
|
|
||||||
true
|
|
||||||
(if (= value 11)
|
|
||||||
true
|
|
||||||
(if (= value 12)
|
|
||||||
true
|
|
||||||
(if (= value 13)
|
|
||||||
true
|
|
||||||
(= value 32)))))))
|
|
||||||
|
|
||||||
(fn byte_is_ascii_trim ((value string) (position i32)) -> bool
|
|
||||||
(match (byte_at_result value position)
|
|
||||||
((ok byte)
|
|
||||||
(is_ascii_trim_byte byte))
|
|
||||||
((err code)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn trim_ascii_start ((value string)) -> string
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(var start i32 0)
|
|
||||||
(while (and (< start value_len) (byte_is_ascii_trim value start))
|
|
||||||
(set start (+ start 1)))
|
|
||||||
(match (slice_result value start (- value_len start))
|
|
||||||
((ok text)
|
|
||||||
text)
|
|
||||||
((err code)
|
|
||||||
value)))
|
|
||||||
|
|
||||||
(fn trim_ascii_end ((value string)) -> string
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(var end i32 value_len)
|
|
||||||
(while (and (> end 0) (byte_is_ascii_trim value (- end 1)))
|
|
||||||
(set end (- end 1)))
|
|
||||||
(match (slice_result value 0 end)
|
|
||||||
((ok text)
|
|
||||||
text)
|
|
||||||
((err code)
|
|
||||||
value)))
|
|
||||||
|
|
||||||
(fn trim_ascii ((value string)) -> string
|
|
||||||
(trim_ascii_end (trim_ascii_start value)))
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import string (len concat byte_at_result slice_result starts_with ends_with contains index_of_option last_index_of_option trim_ascii_start trim_ascii_end trim_ascii parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
(import string (len concat parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
||||||
|
|
||||||
(fn imported_string_concat () -> string
|
(fn imported_string_concat () -> string
|
||||||
(concat "slo" "vo"))
|
(concat "slo" "vo"))
|
||||||
@ -8,37 +8,6 @@
|
|||||||
(fn imported_string_len_concat_score () -> i32
|
(fn imported_string_len_concat_score () -> i32
|
||||||
(+ (len (imported_string_concat)) 37))
|
(+ (len (imported_string_concat)) 37))
|
||||||
|
|
||||||
(fn imported_string_byte_at_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 0)) 115)
|
|
||||||
(if (= (unwrap_ok (byte_at_result "slovo" 3)) 118)
|
|
||||||
(if (= (unwrap_err (byte_at_result "slovo" -1)) 1)
|
|
||||||
(= (unwrap_err (byte_at_result "slovo" 5)) 1)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_slice_ok () -> bool
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 1 3)) "lov")
|
|
||||||
(if (= (unwrap_ok (slice_result "slovo" 0 5)) "slovo")
|
|
||||||
(= (unwrap_err (slice_result "slovo" 4 2)) 1)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_boundaries_ok () -> bool
|
|
||||||
(if (starts_with "slovo" "slo")
|
|
||||||
(if (starts_with "slovo" "")
|
|
||||||
(if (starts_with "slovo" "ovo")
|
|
||||||
false
|
|
||||||
(if (ends_with "slovo" "ovo")
|
|
||||||
(if (ends_with "slovo" "")
|
|
||||||
(if (ends_with "slovo" "slo")
|
|
||||||
false
|
|
||||||
true)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_parse_result_ok () -> bool
|
(fn imported_string_parse_result_ok () -> bool
|
||||||
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
(if (= (unwrap_ok (parse_i32_result "40")) 40)
|
||||||
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
(if (= (unwrap_ok (parse_u32_result "40")) 40u32)
|
||||||
@ -187,67 +156,13 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_option_i32_is_some_value ((actual (option i32)) (expected i32)) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
(= payload expected))
|
|
||||||
((none)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn imported_option_i32_is_none ((actual (option i32))) -> bool
|
|
||||||
(match actual
|
|
||||||
((some payload)
|
|
||||||
false)
|
|
||||||
((none)
|
|
||||||
true)))
|
|
||||||
|
|
||||||
(fn imported_string_search_ok () -> bool
|
|
||||||
(if (contains "alpha beta alpha" "beta")
|
|
||||||
(if (contains "alpha" "z")
|
|
||||||
false
|
|
||||||
(if (contains "alpha" "")
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha beta alpha" "alpha") 0)
|
|
||||||
(if (imported_option_i32_is_none (index_of_option "alpha" "z"))
|
|
||||||
(if (imported_option_i32_is_some_value (index_of_option "alpha" "") 0)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha beta alpha" "alpha") 11)
|
|
||||||
(if (imported_option_i32_is_some_value (last_index_of_option "alpha" "") 5)
|
|
||||||
(imported_option_i32_is_none (last_index_of_option "alpha" "z"))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_ascii_trim_ok () -> bool
|
|
||||||
(if (= (trim_ascii_start " \t\nslovo") "slovo")
|
|
||||||
(if (= (trim_ascii_end "slovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\nslovo \t\n") "slovo")
|
|
||||||
(if (= (trim_ascii " \t\n") "")
|
|
||||||
(= (trim_ascii "slovo") "slovo")
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_string_helpers_ok () -> bool
|
(fn imported_string_helpers_ok () -> bool
|
||||||
(if (= (imported_string_len_concat_score) 42)
|
(if (= (imported_string_len_concat_score) 42)
|
||||||
(if (imported_string_byte_at_ok)
|
(if (imported_string_parse_result_ok)
|
||||||
(if (imported_string_slice_ok)
|
(if (imported_string_parse_options_ok)
|
||||||
(if (imported_string_boundaries_ok)
|
(if (imported_string_parse_integer_fallbacks_ok)
|
||||||
(if (imported_string_parse_result_ok)
|
(if (imported_string_parse_float_bool_fallbacks_ok)
|
||||||
(if (imported_string_parse_options_ok)
|
(imported_string_parse_custom_fallbacks_ok)
|
||||||
(if (imported_string_parse_integer_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_float_bool_fallbacks_ok)
|
|
||||||
(if (imported_string_parse_custom_fallbacks_ok)
|
|
||||||
(if (imported_string_search_ok)
|
|
||||||
(imported_string_ascii_trim_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -262,15 +177,6 @@
|
|||||||
(test "explicit local string len concat"
|
(test "explicit local string len concat"
|
||||||
(= (imported_string_len_concat_score) 42))
|
(= (imported_string_len_concat_score) 42))
|
||||||
|
|
||||||
(test "explicit local string byte_at_result wrapper"
|
|
||||||
(imported_string_byte_at_ok))
|
|
||||||
|
|
||||||
(test "explicit local string slice_result wrapper"
|
|
||||||
(imported_string_slice_ok))
|
|
||||||
|
|
||||||
(test "explicit local string boundary wrappers"
|
|
||||||
(imported_string_boundaries_ok))
|
|
||||||
|
|
||||||
(test "explicit local string parse result wrappers"
|
(test "explicit local string parse result wrappers"
|
||||||
(imported_string_parse_result_ok))
|
(imported_string_parse_result_ok))
|
||||||
|
|
||||||
@ -286,11 +192,5 @@
|
|||||||
(test "explicit local string parse custom fallbacks"
|
(test "explicit local string parse custom fallbacks"
|
||||||
(imported_string_parse_custom_fallbacks_ok))
|
(imported_string_parse_custom_fallbacks_ok))
|
||||||
|
|
||||||
(test "explicit local string search helpers"
|
|
||||||
(imported_string_search_ok))
|
|
||||||
|
|
||||||
(test "explicit local string ascii trim helpers"
|
|
||||||
(imported_string_ascii_trim_ok))
|
|
||||||
|
|
||||||
(test "explicit local string helpers all"
|
(test "explicit local string helpers all"
|
||||||
(= (main) 42))
|
(= (main) 42))
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(module string (export len concat byte_at_result slice_result starts_with ends_with contains index_of_option last_index_of_option trim_ascii_start trim_ascii_end trim_ascii parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
(module string (export len concat parse_i32_result parse_i32_option parse_u32_result parse_u32_option parse_i64_result parse_i64_option parse_u64_result parse_u64_option parse_f64_result parse_f64_option parse_bool_result parse_bool_option parse_i32_or_zero parse_u32_or_zero parse_i64_or_zero parse_u64_or_zero parse_f64_or_zero parse_bool_or_false parse_i32_or parse_u32_or parse_i64_or parse_u64_or parse_f64_or parse_bool_or))
|
||||||
|
|
||||||
(import result (ok_or_none_i32 ok_or_none_u32 ok_or_none_i64 ok_or_none_u64 ok_or_none_f64 ok_or_none_bool))
|
(import result (ok_or_none_i32 ok_or_none_u32 ok_or_none_i64 ok_or_none_u64 ok_or_none_f64 ok_or_none_bool))
|
||||||
|
|
||||||
@ -8,111 +8,6 @@
|
|||||||
(fn concat ((left string) (right string)) -> string
|
(fn concat ((left string) (right string)) -> string
|
||||||
(std.string.concat left right))
|
(std.string.concat left right))
|
||||||
|
|
||||||
(fn byte_at_result ((value string) (index i32)) -> (result i32 i32)
|
|
||||||
(std.string.byte_at_result value index))
|
|
||||||
|
|
||||||
(fn slice_result ((value string) (start i32) (count i32)) -> (result string i32)
|
|
||||||
(std.string.slice_result value start count))
|
|
||||||
|
|
||||||
(fn starts_with ((value string) (prefix string)) -> bool
|
|
||||||
(std.string.starts_with value prefix))
|
|
||||||
|
|
||||||
(fn ends_with ((value string) (suffix string)) -> bool
|
|
||||||
(std.string.ends_with value suffix))
|
|
||||||
|
|
||||||
(fn suffix_starts_with ((value string) (needle string) (position i32) (value_len i32)) -> bool
|
|
||||||
(match (slice_result value position (- value_len position))
|
|
||||||
((ok text)
|
|
||||||
(starts_with text needle))
|
|
||||||
((err code)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn index_of_option ((value string) (needle string)) -> (option i32)
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(let needle_len i32 (len needle))
|
|
||||||
(let max_start i32 (- value_len needle_len))
|
|
||||||
(var position i32 0)
|
|
||||||
(var found_position i32 -1)
|
|
||||||
(while (and (> needle_len 0) (and (< found_position 0) (<= position max_start)))
|
|
||||||
(set found_position (if (suffix_starts_with value needle position value_len)
|
|
||||||
position
|
|
||||||
found_position))
|
|
||||||
(set position (+ position 1)))
|
|
||||||
(if (= needle_len 0)
|
|
||||||
(some i32 0)
|
|
||||||
(if (< found_position 0)
|
|
||||||
(none i32)
|
|
||||||
(some i32 found_position))))
|
|
||||||
|
|
||||||
(fn last_index_of_option ((value string) (needle string)) -> (option i32)
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(let needle_len i32 (len needle))
|
|
||||||
(let max_start i32 (- value_len needle_len))
|
|
||||||
(var position i32 0)
|
|
||||||
(var found_position i32 -1)
|
|
||||||
(while (and (> needle_len 0) (<= position max_start))
|
|
||||||
(set found_position (if (suffix_starts_with value needle position value_len)
|
|
||||||
position
|
|
||||||
found_position))
|
|
||||||
(set position (+ position 1)))
|
|
||||||
(if (= needle_len 0)
|
|
||||||
(some i32 value_len)
|
|
||||||
(if (< found_position 0)
|
|
||||||
(none i32)
|
|
||||||
(some i32 found_position))))
|
|
||||||
|
|
||||||
(fn contains ((value string) (needle string)) -> bool
|
|
||||||
(match (index_of_option value needle)
|
|
||||||
((some position)
|
|
||||||
true)
|
|
||||||
((none)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn is_ascii_trim_byte ((value i32)) -> bool
|
|
||||||
(if (= value 9)
|
|
||||||
true
|
|
||||||
(if (= value 10)
|
|
||||||
true
|
|
||||||
(if (= value 11)
|
|
||||||
true
|
|
||||||
(if (= value 12)
|
|
||||||
true
|
|
||||||
(if (= value 13)
|
|
||||||
true
|
|
||||||
(= value 32)))))))
|
|
||||||
|
|
||||||
(fn byte_is_ascii_trim ((value string) (position i32)) -> bool
|
|
||||||
(match (byte_at_result value position)
|
|
||||||
((ok byte)
|
|
||||||
(is_ascii_trim_byte byte))
|
|
||||||
((err code)
|
|
||||||
false)))
|
|
||||||
|
|
||||||
(fn trim_ascii_start ((value string)) -> string
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(var start i32 0)
|
|
||||||
(while (and (< start value_len) (byte_is_ascii_trim value start))
|
|
||||||
(set start (+ start 1)))
|
|
||||||
(match (slice_result value start (- value_len start))
|
|
||||||
((ok text)
|
|
||||||
text)
|
|
||||||
((err code)
|
|
||||||
value)))
|
|
||||||
|
|
||||||
(fn trim_ascii_end ((value string)) -> string
|
|
||||||
(let value_len i32 (len value))
|
|
||||||
(var end i32 value_len)
|
|
||||||
(while (and (> end 0) (byte_is_ascii_trim value (- end 1)))
|
|
||||||
(set end (- end 1)))
|
|
||||||
(match (slice_result value 0 end)
|
|
||||||
((ok text)
|
|
||||||
text)
|
|
||||||
((err code)
|
|
||||||
value)))
|
|
||||||
|
|
||||||
(fn trim_ascii ((value string)) -> string
|
|
||||||
(trim_ascii_end (trim_ascii_start value)))
|
|
||||||
|
|
||||||
(fn parse_i32_result ((value string)) -> (result i32 i32)
|
(fn parse_i32_result ((value string)) -> (result i32 i32)
|
||||||
(std.string.parse_i32_result value))
|
(std.string.parse_i32_result value))
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import vec_f64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,16 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec f64) (append3 (pair 10.0 20.0) 30.0 20.0 10.0))
|
|
||||||
(if (= (count_of (empty) 20.0) 0)
|
|
||||||
(if (= (count_of values 99.0) 0)
|
|
||||||
(if (= (count_of values 20.0) 2)
|
|
||||||
(= (count_of values 10.0) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
(fn imported_starts_with_helper_ok () -> bool
|
||||||
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
(let values (vec f64) (append2 (triple 10.0 20.0 30.0) 40.0 50.0))
|
||||||
(let prefix (vec f64) (pair 10.0 20.0))
|
(let prefix (vec f64) (pair 10.0 20.0))
|
||||||
@ -295,21 +285,19 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_starts_with_helper_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_ends_with_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_without_suffix_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_without_prefix_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_replace_helper_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_replace_range_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_remove_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_remove_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,9 +331,6 @@
|
|||||||
(test "explicit local vec_f64 option query helpers"
|
(test "explicit local vec_f64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit local vec_f64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_f64 starts_with helper"
|
(test "explicit local vec_f64 starts_with helper"
|
||||||
(imported_starts_with_helper_ok))
|
(imported_starts_with_helper_ok))
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(module vec_f64 (export empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(module vec_f64 (export empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(type VecF64 (vec f64))
|
(type VecF64 (vec f64))
|
||||||
|
|
||||||
@ -92,16 +92,6 @@
|
|||||||
(fn contains ((values VecF64) (target f64)) -> bool
|
(fn contains ((values VecF64) (target f64)) -> bool
|
||||||
(contains_loop values target 0 (len values)))
|
(contains_loop values target 0 (len values)))
|
||||||
|
|
||||||
(fn count_of_loop ((values VecF64) (target f64) (position i32) (values_len i32) (hits i32)) -> i32
|
|
||||||
(if (< position values_len)
|
|
||||||
(count_of_loop values target (+ position 1) values_len (+ hits (if (= (at values position) target)
|
|
||||||
1
|
|
||||||
0)))
|
|
||||||
hits))
|
|
||||||
|
|
||||||
(fn count_of ((values VecF64) (target f64)) -> i32
|
|
||||||
(count_of_loop values target 0 (len values) 0))
|
|
||||||
|
|
||||||
(fn sum_loop ((values VecF64) (position i32) (values_len i32) (total f64)) -> f64
|
(fn sum_loop ((values VecF64) (position i32) (values_len i32) (total f64)) -> f64
|
||||||
(if (< position values_len)
|
(if (< position values_len)
|
||||||
(sum_loop values (+ position 1) values_len (+ total (at values position)))
|
(sum_loop values (+ position 1) values_len (+ total (at values position)))
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(module main)
|
(module main)
|
||||||
|
|
||||||
(import vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains count_of sum concat take starts_with without_prefix ends_with without_suffix drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
(import vec_i64 (empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))
|
||||||
|
|
||||||
(fn imported_empty_length () -> i32
|
(fn imported_empty_length () -> i32
|
||||||
(len (empty)))
|
(len (empty)))
|
||||||
@ -72,92 +72,6 @@
|
|||||||
false)
|
false)
|
||||||
false))
|
false))
|
||||||
|
|
||||||
(fn imported_count_of_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append3 (pair 10i64 20i64) 30i64 20i64 10i64))
|
|
||||||
(if (= (count_of (empty) 20i64) 0)
|
|
||||||
(if (= (count_of values 99i64) 0)
|
|
||||||
(if (= (count_of values 20i64) 2)
|
|
||||||
(= (count_of values 10i64) 2)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_starts_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 20i64 30i64))
|
|
||||||
(if (starts_with values (empty))
|
|
||||||
(if (starts_with values prefix)
|
|
||||||
(if (starts_with values values)
|
|
||||||
(if (starts_with values longer_prefix)
|
|
||||||
false
|
|
||||||
(if (starts_with values mismatched_prefix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_ends_with_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (ends_with values (empty))
|
|
||||||
(if (ends_with values suffix)
|
|
||||||
(if (ends_with values values)
|
|
||||||
(if (ends_with values longer_suffix)
|
|
||||||
false
|
|
||||||
(if (ends_with values mismatched_suffix)
|
|
||||||
false
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_suffix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let suffix (vec i64) (pair 40i64 50i64))
|
|
||||||
(let longer_suffix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_suffix (vec i64) (pair 40i64 51i64))
|
|
||||||
(if (= (without_suffix values (empty)) values)
|
|
||||||
(if (= (without_suffix values values) (empty))
|
|
||||||
(if (= (without_suffix values suffix) (triple 10i64 20i64 30i64))
|
|
||||||
(if (= (without_suffix values longer_suffix) values)
|
|
||||||
(if (= (without_suffix values mismatched_suffix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= suffix (pair 40i64 50i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_without_prefix_helper_ok () -> bool
|
|
||||||
(let values (vec i64) (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(let prefix (vec i64) (pair 10i64 20i64))
|
|
||||||
(let longer_prefix (vec i64) (append2 values 60i64 70i64))
|
|
||||||
(let mismatched_prefix (vec i64) (pair 10i64 21i64))
|
|
||||||
(if (= (without_prefix values (empty)) values)
|
|
||||||
(if (= (without_prefix values values) (empty))
|
|
||||||
(if (= (without_prefix values prefix) (triple 30i64 40i64 50i64))
|
|
||||||
(if (= (without_prefix values longer_prefix) values)
|
|
||||||
(if (= (without_prefix values mismatched_prefix) values)
|
|
||||||
(if (= values (append2 (triple 10i64 20i64 30i64) 40i64 50i64))
|
|
||||||
(= prefix (pair 10i64 20i64))
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false))
|
|
||||||
|
|
||||||
(fn imported_transform_helpers_ok () -> bool
|
(fn imported_transform_helpers_ok () -> bool
|
||||||
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
(if (= (concat (empty) (pair 7i64 8i64)) (pair 7i64 8i64))
|
||||||
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
(if (= (concat (pair 1i64 2i64) (triple 3i64 4i64 5i64)) (append3 (pair 1i64 2i64) 3i64 4i64 5i64))
|
||||||
@ -295,25 +209,15 @@
|
|||||||
(if (imported_builder_helpers_ok)
|
(if (imported_builder_helpers_ok)
|
||||||
(if (imported_query_helpers_ok)
|
(if (imported_query_helpers_ok)
|
||||||
(if (imported_option_query_helpers_ok)
|
(if (imported_option_query_helpers_ok)
|
||||||
(if (imported_count_of_helper_ok)
|
(if (imported_transform_helpers_ok)
|
||||||
(if (imported_starts_with_helper_ok)
|
(if (imported_subvec_helper_ok)
|
||||||
(if (imported_ends_with_helper_ok)
|
(if (imported_insert_helper_ok)
|
||||||
(if (imported_without_suffix_helper_ok)
|
(if (imported_insert_range_helper_ok)
|
||||||
(if (imported_without_prefix_helper_ok)
|
(if (imported_replace_helper_ok)
|
||||||
(if (imported_transform_helpers_ok)
|
(if (imported_replace_range_helper_ok)
|
||||||
(if (imported_subvec_helper_ok)
|
(if (imported_remove_helper_ok)
|
||||||
(if (imported_insert_helper_ok)
|
(if (imported_remove_range_helper_ok)
|
||||||
(if (imported_insert_range_helper_ok)
|
(imported_real_program_helpers_ok)
|
||||||
(if (imported_replace_helper_ok)
|
|
||||||
(if (imported_replace_range_helper_ok)
|
|
||||||
(if (imported_remove_helper_ok)
|
|
||||||
(if (imported_remove_range_helper_ok)
|
|
||||||
(imported_real_program_helpers_ok)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
false)
|
false)
|
||||||
@ -343,21 +247,6 @@
|
|||||||
(test "explicit local vec_i64 option query helpers"
|
(test "explicit local vec_i64 option query helpers"
|
||||||
(imported_option_query_helpers_ok))
|
(imported_option_query_helpers_ok))
|
||||||
|
|
||||||
(test "explicit local vec_i64 count_of helper"
|
|
||||||
(imported_count_of_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_i64 starts_with helper"
|
|
||||||
(imported_starts_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_i64 ends_with helper"
|
|
||||||
(imported_ends_with_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_i64 without_suffix helper"
|
|
||||||
(imported_without_suffix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_i64 without_prefix helper"
|
|
||||||
(imported_without_prefix_helper_ok))
|
|
||||||
|
|
||||||
(test "explicit local vec_i64 transform helpers"
|
(test "explicit local vec_i64 transform helpers"
|
||||||
(imported_transform_helpers_ok))
|
(imported_transform_helpers_ok))
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user