Skip to content

Releases: TickPoints/prima-language

v0.5.2-alpha

Choose a tag to compare

@github-actions github-actions released this 04 Oct 00:48

Fixed

  • Release workflow no longer tears down successful builds. A single failing matrix target used
    to run gh run cancel, which cancelled every other in-progress build and left the GitHub Release
    with no assets. That step is gone: with fail-fast: false each target now builds and uploads
    independently, so every target that does build still contributes its binary and checksum. The
    release job is also idempotent — it creates the release, or updates it when a partial run is
    re-run — instead of aborting because the release already exists.

v0.5.2

Choose a tag to compare

@github-actions github-actions released this 04 Oct 01:03

Fixed

  • 32-bit builds no longer fail the Value size guard. The prima-core compile-time assertion
    pinned Value at 24 bytes, the size it takes on 64-bit targets. On 32-bit targets (e.g.
    armv7-unknown-linux-gnueabihf) the tag packs into Number's spare discriminants and Value is
    16 bytes, so the release build aborted with E0080. The guard is now pointer-width aware
    (24 bytes on 64-bit, 16 on 32-bit) while still catching any growth of the hot-path value.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 12:21

Added

  • Four-tier standard library (Cargo features). prima-stdlib now splits its modules into
    opt-in tiers — core (default: built-in classes + num), system (io/time/sys),
    advanced (linalg/stats/physics/plot; pulls nalgebra), and render (formula
    rendering; the heaviest dependency) — with a full aggregate. The prima binary now defaults to
    full (all tiers, including render); the prima-stdlib library baseline remains core, and
    leaner binaries use --no-default-features --features <tier>. CI runs --all-features, with a
    tier job compiling each level on its own. This isolates the heavy optional dependencies (e.g. the
    LaTeX→SVG backend) from the default library build.

  • math standard-library module (spec §18.6). Integer number theory — gcd/lcm,
    factor (prime factorization), primes (sieve), mod_pow, and crt (Chinese remainder) —
    plus polynomial tools over lowest-degree-first Array<F64> coefficients (poly_eval,
    poly_add, poly_mul, poly_derivative, poly_roots via Durand–Kerner returning
    Array<Complex>) and continued_fraction. primes is a layered @builtin(O1) with a .pra
    fallback; allocation is bounded by explicit limits. taylor is not yet implemented (it needs a
    call-site interceptor) and factor uses deterministic trial division.

  • sys::process / sys::fs / sys::term (spec §18.6). Run external commands through the
    platform shell and capture output (process::run, process::exit_code), filesystem queries
    (fs::exists/is_file/is_dir/size/read_dir/metadata), and terminal detection
    (term::size/is_tty). All fallible operations return Result and never panic; the
    arbitrary-command and arbitrary-path trust boundaries are documented in the module docs.

  • physics formulas and Vector3 (spec §18.6). The physics module is now an embedded
    .pra module rather than a Rust-hosted constants namespace: the CODATA 2022 constants are
    declared as typed pub consts (SI-exact Integer/Rational forms preserved), and the module
    gains elementary formulas implemented as Rust @builtins — kinematics (velocity,
    displacement, projectile_*), mechanics (force, momentum, kinetic_energy,
    potential_energy, work, power), simple harmonic motion (shm_*, simple_pendulum),
    thermodynamics (celsius_to_kelvin, kelvin_to_celsius, heat, ideal_gas_pressure), and
    electromagnetism (coulomb_force, ohm_*, electrical_power) — plus a Vector3 class with
    new/add/sub/scale/dot/cross/length/normalize. All formulas take and return
    F64 and report wrong arity or non-real arguments as errors.

  • plot heatmaps and contours (spec §18.6). plot::heatmap renders a scalar grid as a
    color-mapped image (viridis-like ramp with a colorbar in the figure margin), plot::contour
    draws evenly spaced iso-lines with marching squares, and plot::hist renders a histogram.
    Ragged/empty grids and invalid level/bin counts report a RuntimeError; NaN/Inf cells are
    skipped rather than panicking.

  • render formula rendering (spec §18.6). render::to_svg renders a symbolic expression or
    LaTeX string to a self-contained SVG (core LaTeX view → RaTeX parse/layout/to_display_list
    → render_to_svg with embedded glyph outlines), and render::to_terminal transliterates the
    same view into Unicode terminal math text. Available behind the render tier, which keeps the
    RaTeX dependencies out of the default build. PNG output and the print terminal-formula
    term-render integration remain deferred.

Changed

  • The prima binary now defaults to the full stdlib tier (all modules, including render).
    The root package's default Cargo feature is full, so cargo build/cargo install/cargo run
    produce a complete binary without --features; the prima-stdlib library baseline remains the
    lean core (built-in classes + num), and lean binaries use
    --no-default-features --features <tier>.

  • Number slimmed to 16 bytes and Value to 24 bytes (spec §5/§6.1). The interpreter/VM
    hot-path value types lost their oversized payloads with semantics unchanged. Number::Complex
    is now a single boxed pointer (Number::Complex(Box<Complex>), built via Number::from_complex
    and read via Number::as_complex_parts); previously its two inline Box fields formed a
    16-byte payload with no spare niche, forcing the enum tag out to 24 bytes. Value::String and
    Value::Error now hold Box<str> instead of String, and Value::Tuple holds Box<[Value]>
    instead of Vec<Value> — 16-byte fat pointers rather than 24-byte headers, with no extra
    allocation (construction goes through into_boxed_str/into_boxed_slice). Compile-time
    const _: () = assert!(...) guards pin both sizes so a future variant cannot silently regrow
    the hot path. Note: flattening the Real enum was not needed — with Complex boxed the
    Real variant's spare discriminants host the Number tag, so Number reaches 16 bytes without
    touching the ~500 Number::Real(…) sites. The default whole-function JIT path is unchanged;
    benches/RESULTS.md was regenerated (interpreted paths within run-to-run noise).

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 03 Oct 08:26

Added

  • Structured diagnostic codes (spec §16.4, appendix C). Every compiler and runtime diagnostic
    now carries a first-class code and renders rustc-style as error[E0011]: / warning[W0003]: /
    error[R0005]: instead of burying the code in the message text. SyntaxError/TypeError gained
    code/help fields and RuntimeError gained code() plus a Coded variant, so the
    E####/R#### tables in appendix C are now enforced by the implementation.
  • Previously unimplemented appendix C validations. E0041 duplicate_definition (same-scope
    fn/class/const, duplicate parameters, duplicate fields, duplicate methods), E0051 missing_type_ann (@builtin/@c_api::extern signatures must be typed), E0052 unknown_type
    (with did you mean, covering let/const/parameter/return annotations), E0063 self_not_first, E0081 op_overload_bad_arity, and runtime R0002 underflow (integer collapse
    below the target minimum, distinct from R0001 overflow).
  • Actionable suggestions. did you mean ...? now covers undefined names (E0040), unknown
    types (E0052), unknown/missing fields (E0060/E0061), unknown config keys (E0022),
    @builtin optimization tiers (E0057), call-site arity, and method-name typos, alongside
    rule-based hints (for example the explicit-collapse hint for Expr/numeric mismatches).
  • --json machine-readable diagnostics. All diagnostics can be emitted as rustc-style NDJSON
    on stderr (severity/code/message/spans/notes/help), keeping the program's stdout clean
    for editors and CI.
  • --color auto|always|never and --quiet/-q global switches.
  • Project scaffolding: prima new <name> and prima init write the spec §20 layout
    (prima.toml / config.toml / README.md / .gitignore / src/main.pra).
  • Project-root discovery: prima run / check / fmt / doc accept an omitted file and use
    the nearest ancestor prima.toml (or src/main.pra); prima test defaults to src/ inside a
    project.
  • prima completions <shell> emits a shell completion script via clap_complete.
  • prima test --json emits one NDJSON event per test ({"type":"test","file","status","message"})
    plus a final {"type":"summary","passed","failed","skipped"} on stderr; --quiet suppresses
    passing/skipped lines while keeping failures and the summary.

Changed

  • REPL errors now print the structured error[CODE]: header, and location-less runtime errors keep
    their R#### code.

v0.4.1-alpha

Choose a tag to compare

@github-actions github-actions released this 13 Sep 04:25

Performance

This round adds whole-function native compilation (opt_level >= O2), and the cross-language
benchmark now runs 7×–1700× faster than CPython on every kernel (benches/RESULTS.md,
default path). An earlier register channel plus lock-free arrays had already brought the VM to
CPython parity (Python × 0.3–0.9); the JIT supersedes it on pure numeric bodies.

  • Whole-function JIT for the pure numeric subset (spec §19.2). A typed register IR
    (prima_jit::ir) and a cranelift lowering (prima_jit::func) compile complete fn bodies:
    i64/f64/bool locals, dense local arrays, arithmetic/comparisons, to_f64,
    if/while/for/return, local.push/len and indexing. The interpreter lowers a body to
    the IR (prima-runtime::jit_fn); only pure numeric bodies lower, everything else stays on the
    VM/AST. Generated code is exact — integer arithmetic is checked and array accesses are
    bounds-checked, and an overflow or out-of-range index sets an error flag so the call is re-run
    on the interpreter (the JIT is pure). Loop back-edges poll host cancellation, so interruption
    behaves like the interpreter. Dense arrays are arena-allocated and freed at the single
    epilogue; compilations are cached per function definition.

  • Pooled VM frame and operand-stack buffers (spec §19.5). run_vm reuses frame/stack buffers
    across calls (and nested calls), avoiding reallocation.

  • VM subset: dict index assignment and slice assignment (spec §11.3/§11.6). d[k] = v and
    arr[lo..hi] = rhs now run natively in the VM (dict/set literals compile too), removing AST
    fallbacks for them; dict/set mutating method calls still fall back to the AST.

  • Register-form local instructions (spec §19.5). A new instruction family operates directly
    on local slots (RegBin/RegBinImm, RegMulAdd, RegNeg, RegToF64, RegMove, RegIndex,
    RegIndexPush, RegIndexStore/Imm, RegPush/Imm), plus fused loop forms
    (BranchLocalCmpSum, RegIndexBranchFalse) and a bulk RegFill for the
    for _ in lo..hi { a.push(const) } idiom. The compiler emits them when operands are local
    slots or inline immediates; every non-numeric/non-array shape falls back to the existing stack
    path, so observable behavior is unchanged. Op is now Copy, and the dispatch loop matches
    slot references directly on the Small/F64 fast paths instead of cloning operands.

  • Lock-free copy-on-write arrays (spec §11.3). ArrayVal now wraps Arc<Vec<Value>> and
    copies on write through Arc::make_mut instead of Arc<RwLock<Vec<Value>>>. Array reads are
    plain dereferences (no lock), removing the per-element RwLock atomics from every index read
    and array loop; Send + Sync (and therefore the parfor/@parallel paths) is preserved.

  • Fast-hash environments. Env's value/function namespaces and the VM's function-dispatch
    table use rustc_hash::FxHashMap instead of SipHash, cutting the cost of every non-local name
    lookup and call resolution.

Fixed

  • to_f64 register fast path honors a user shadow. The register to_f64 lowering now
    validates against the process-wide function-definition epoch and calls a user fn to_f64 when
    one is defined, matching the AST interpreter (regression-tested).

  • ExprPool::number no longer panics on complex numbers. A new try_number returns None
    for values with no symbolic representation (complex); callers that can receive one report a
    clear error instead of panicking (spec §6.1).

  • CSV parsing is UTF-8-correct (spec §18.1). io::csv_parse decoded fields byte-by-byte as
    Latin-1, corrupting any non-ASCII data; it now parses by Unicode scalar values.

  • VM operand truncation is rejected. Constant-pool indices, parameter/argument counts, and
    array/tuple element counts beyond the u16 instruction-field range now reject compilation
    (AST fallback) instead of silently wrapping (spec §19.5).

  • Terminal escape injection. Program output is filtered for C0 control characters and DEL at
    the print/println sink, so untrusted strings cannot emit ANSI escapes; newline/tab are
    preserved. The stdlib arbitrary-path I/O trust boundary is now documented.

  • f-string {:spec} width counts characters, not bytes. Multi-byte content and fill
    characters now pad to the correct visual width (spec §18.1).

  • Rounding collapse no longer saturates. Number::rounded_digits and the collapse rounding
    family use checked float→integer conversions and reject out-of-range digit counts instead of
    saturating to i64::MAX (spec §9.6).

  • REPL no longer replays the whole session. Each entry is evaluated once against a persistent
    environment (Evaluator::eval_value_keep_env), removing the O(n²) session replay that made
    long sessions lag (spec §20).

  • Dedicated nesting-depth error code. "Expression nesting is too deep" now reports
    E0012 expression_nesting_too_deep (new spec appendix C entry) instead of borrowing the
    generic E0010.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 15:04

Performance

This release is a ground-up pass over the interpreter's hot paths. The cross-language benchmark
(benches/RESULTS.md) improves from 11.8×–4159× slower than CPython to 1.07×–7.1×: sumsq is at
parity (1.07×) and fib is at parity, while pi/poly/dot sit at 2.1×–2.8× and sieve at
7.1× (the remaining gap is the boxed-Value stack-machine cost measured by perf; closing it
fully needs register-style specialization).

  • Bytecode VM promoted to the default execution path (spec §19.5). vm := true is now the
    default; the AST interpreter remains the authoritative fallback outside the compiled subset. The
    dispatch loop was restructured around a cached top frame with the hot instruction set handled
    inline (local load/store, constants, jumps, typed arithmetic, fused loop forms), so numeric loops
    no longer pay a per-instruction delegation to the evaluator.

  • Number/Value shrank from 64 to 32/24 bytes. Number::Integer/Number::Rational (and the
    fixed-width I128/U128) now box their payloads, and Value boxes Dict/Set/Result
    payloads, halving every clone/push/pop in the interpreter and VM (number semantics, rendering,
    keys, and equality are unchanged — regression-tested).

  • Fused bytecode instructions (spec §14/§12.2): SetLocalNc (bind without stack round-trip),
    AddImmLocal (x += <small literal> in place), AddToSlot (fused x = x + expr), and
    BranchLocalLt/BranchLocalLe (fused while/for loop tests on two local slots). A while
    loop iteration compiles to 3–4 instructions instead of 10–18.

  • Typed arithmetic fast paths in the VM dispatch (spec §6.1/§6.5): Small/Small uses checked
    i64 arithmetic, F64/F64 plain IEEE + - * / % (division keeps the fraction policy and the
    exact-layer zero-divisor diagnostics), mixed exact/F64 division promotes directly, and array
    indexing/index-assignment with integer indices run inline with the authoritative diagnostics.

  • Per-call-site callee cache (spec §19.5). CallName sites cache their resolved builtin or
    program-function callee, validated against a process-wide function-definition epoch (bumped by
    every Env::set_func), so a user redefinition (e.g. shadowing a core builtin) always
    re-resolves while repeated calls skip the environment walk. to_f64 with a numeric argument
    converts directly on the cached path.

  • Inlined small-integer representation for Number (spec §6.1). The numeric tower's integer
    layer gains an internal Small(i64) variant that is semantically identical to Integer
    (Small(5) == Integer(5), same rendering, conversions, and hash keys) but avoids the per-value
    heap allocation of num_bigint::BigInt. Integer literals, as_i64, and the add/subtract/
    multiply hot paths now run allocation-free with checked i64 arithmetic, falling back to the
    exact BigInt path on overflow (results stay exact).

  • Shared copy-on-write array representation for Value::Array (spec §11.3). Value::Array
    now holds a shared handle (prima_core::ArrayVal, an Arc<RwLock<Vec<Value>>> — Arc/RwLock
    keep Value: Send + Sync for the parfor/@parallel rayon paths) instead of an owned
    Vec<Value>, so cloning an array value is O(1) instead of a full element copy. Mutation goes
    through ArrayVal::with_mut, which mutates the buffer in place when the handle is uniquely
    owned and copy-on-writes when shared, preserving value semantics exactly: let b = a; b[0] = 9
    (or b.push(x)) still leaves a unchanged, and storing an array into its own buffer (a[0] = a) stores a snapshot copy rather than creating a reference cycle. Equality, hashing keys,
    rendering/print output, and error messages are unchanged.

  • Quadratic lexing on large inputs (spec §3). The lexer's cur/peek_char decoded the
    current character by running str::from_utf8 over the entire remaining input — O(n²) overall
    (lexing 400 000 tokens took ~70 s, a hang-DoS on untrusted source). Decoding is now a single O(1)
    incremental read: 400 000 tokens lex in ~0.18 s (~400× faster at that size).

  • Exact BigInt arithmetic-sum closed form (spec §10/§19.1). The for i in 0..n { acc += i }
    closed-form optimization computed n(n-1)/2 in i64; it now computes the product in BigInt,
    matching the real loop's exact accumulation at every magnitude.

Fixed

  • C-ABI panic across the FFI boundary (spec §18.4). Generated extern "C" wrappers called
    call_file_export unguarded, so any interpreter panic unwound across the C boundary — aborting
    the host process on Rust ≥ 1.81. call_file_export now wraps its body in catch_unwind: the
    panic payload is logged to stderr, the per-thread module cache is dropped, and the call surfaces
    as a RuntimeError so each wrapper returns its documented default value.

  • Parser/evaluator/checker stack exhaustion on deeply nested source (spec §16.4). Tens of
    thousands of nested parentheses or a 100 000-term flat expression (0+0+0+…, which the iterative
    Pratt loop wraps into a deep chain without recursing) drove recursive consumers into
    stack-overflow SIGSEGV; prima check on untrusted source was the hard exposure. The parser now
    enforces an exact per-node AST depth budget (2 000) plus a balanced recursion guard (512) and
    reports E0010-coded syntax errors (appendix C has no dedicated "too deep" code), running on a
    dedicated 32 MB thread; the evaluator and static checker gained matching Drop-safe depth
    guards. All examples/ still parse unchanged.

  • JIT parameter-index truncation and slot-offset overflow (spec §19.2). Op::Param carries a
    u8 index but the compiler cast parameter positions with idx as u8 (≥ 257 parameters silently
    read the wrong slot), and the parameter-buffer offset was computed as i32::from(8 * i) with
    i: u8 — a debug panic at ≥ 32 parameters and a silently wrong slot in release. Indices beyond
    the instruction set's range are now rejected (interpreter fallback, never a wrong value), the
    offset is computed in i32, and validate_bytecode enforces the arity limit. 32- and
    33-parameter functions are regression-tested.

  • JIT engine initialization panics. JITBuilder::new and declare_function used unwrap();
    an environment where cranelift cannot initialize now permanently marks the JIT unavailable and
    every compilation degrades to the interpreter fallback.

  • Silent lost write in the bytecode VM's array index assignment (spec §19.5). Under the VM,
    A[i] = v evaluated the store against a stack copy of the array and never wrote back. The
    compiler now lowers index assignment to IndexStoreLocal(slot)/IndexStoreName(name) (in-place
    mutation through the slot or the environment chain) and mutating Array methods on local slots
    run through MethodLocal, mutating the slot's array directly.

  • Multi-parameter functions misbound in the bytecode VM (spec §11/§19.5). Function chunks
    bound parameters with per-parameter SetLocal instructions, which pop the last-pushed
    argument and push it back — with two or more parameters every parameter received the wrong
    argument and the operand stack leaked the arguments. A single BindParams instruction now
    distributes the call arguments to the parameter slots in order (single-parameter kernels had
    worked by accident; two-parameter VM/AST parity is regression-tested).

  • Float→integer saturation in Number::as_bigint/as_rational (spec §9.2). Converting a
    fractional-free float beyond the i64 range (e.g. to_bigint(1e19)) silently saturated to
    i64::MAX. Both conversions now apply the same i64 round-trip guard used by as_i64 and
    return None; collapse callers report proper errors instead of a silently wrong result.

  • i64 overflow in loop index stepping and the parfor iteration count (spec §16.1 R0001).
    for … step s, range(start, end, step?), and parfor stepped/materialized with unchecked
    arithmetic (debug panic, or silent wrap → dropped iterations/infinite loop in release). All
    paths now use checked_add/i128 counting and report RuntimeError::Overflow.

  • Hash-consing collision unsoundness (spec §8.1). ExprPool::intern deduplicated by 64-bit
    content hash alone, so a hash collision silently replaced one symbolic expression with another
    (DefaultHasher is keyed identically in every process, making collisions constructible).
    Interning now keeps per-hash candidate buckets and confirms ExprData equality before reusing
    an ExprId, preserving the equal-content ⇒ equal-ExprId invariant under collisions.

  • parfor + JIT-fallback data race (spec §17.2). A jit(...) callable whose compilation
    failed runs through an interpreted fallback that dereferences the registering thread's
    Rc<RefCell<Env>>; inside a parfor rayon task that is a cross-thread Rc race (UB). Worker
    threads are now marked for the duration of a parfor task and the JIT fallback refuses to run
    on them with a clear error; single-threaded fallback behavior is unchanged.

  • No interruption path for long-running evaluations (spec §16). The evaluator now checks a
    process-wide cancellation flag at loop back-edges and statement boundaries (RuntimeError "interrupted"), and the C ABI exports prima_cancel/prima_cancel_reset so an embedded host
    can stop a runaway export instead of hanging forever.

  • Process-level leaks. The JIT registry (spec §19.2) grew without bound for loops like
    while … { f = jit(x^2); f(1.0); } — callables are now evicted (oldest-first) once the registry
    reaches its capacity, and Value::JitFunction lookups prune dead entries. The generated C-ABI
    wrappers' CSTR_KEEP buffer (spec §18.4) accumulated one CString per string-returning call;
    it now uses a double buffer that is recycled across calls.

  • Dict/Set key semantics diverged from membership tests (spec §11.6). d[1] a...

Read more

v0.3.5

Choose a tag to compare

@github-actions github-actions released this 05 Sep 03:11

Added

  • Cross-language benchmark suite (benches/RESULTS.md). A new cargo bench --bench bench_suite (harness-free) measures six deterministic, scalar-valued kernels (integer accumulation, Leibniz π, iterative Fibonacci, Sieve of Eratosthenes, sparse dot-product, Horner polynomial) across three implementations of identical semantics: Prima (in-process, warm Evaluator::call_function), CPython (bench_ref.py, kernel timed with perf_counter to exclude startup), and a native Rust closure. Each run verifies the three results agree (cross-language correctness), then writes a Markdown table to benches/RESULTS.md. This is the AST-interpreter baseline; the vm := true bytecode VM (spec §19.5) and JIT hot path (spec §19.2) are the mechanisms tracked against it.

  • Doc-test support in prima doc (spec §20 / §4.1). prima doc --test extracts ```pra fenced code blocks from ////`//!` doc comments, statically checks each with `check_src_checked`, and (`--run`) executes them and compares captured `print`/`println` output to a trailing `// expect: ` line — Rust doc-test style. The Markdown renderer now preserves fenced code blocks verbatim plus Markdown list/heading lines, and reports per-block pass/fail with correct exit codes.

  • Conservative name/scope checks in prima check (spec §16.2 / appendix C). A new check/names pass detects statically-decidable name errors without evaluating: E0040 undefined_name (single-segment path/symbol outside scope), E0080 return_outside_fn, E0062 self_outside_method, and the W0003 unused_binding warning, with the pre-imported core builtins and primitive type names seeded into the root scope to avoid false positives. prima check emits these via a new check_src_checked API that also returns warnings, and --deny W0003 promotes them.

  • anyhow error propagation at the CLI (spec §16). The root prima-language crate now depends on anyhow: every CLI subcommand (run/parse/check/compile/repl/fmt/test/doc) returns anyhow::Result<ExitCode>, and read_src plus the I/O/build steps in cabi/fmt/doc carry a contextual source chain (rendered as caused by: lines). The library crates keep structured thiserror enums (RuntimeError/SyntaxError/CoreError) and the rustc-style diagnostics renderer still owns source-level output, so the numbered error/warning-code surface is unchanged.

  • Bytecode VM execution path (spec §19.5, gated, default off). A working stack bytecode VM in prima-runtime vm/ (op instruction set + Chunk/Program IR, comp AST→bytecode compiler, exec dispatch loop, helpers value-level utilities). compile_program/compile_function_body lower a numeric/control-flow/function-call subset (literals, local/name loads, binary/unary ops, let/assignment/if/while/for/return, array/tuple literals, indexing, calls by name and methods); the executor delegates every value-producing op to the Evaluator (eval_binary/eval_compare/call_method/apply_function) so VM results equal AST results by construction. Evaluator::vm_call_function exposes an explicit VM entry. Unsupported constructs cause a whole-function fallback to the AST interpreter (the authoritative path). On the benchmark kernels the VM is ≈1.5–1.8× faster than the AST interpreter (benches/RESULTS.md), with sieve/dot (mutating array methods) at parity via fallback.

Changed

  • Memory-strategy docs reconciled to reference counting (spec §12.3/12.4). The spec and implementation docs no longer plan a host-layer tracing GC: class instances are Rc<RefCell<ClassInstance>> (matching the implementation), the mem::collect() mutation/GC control is removed, and mem::Arc remains a planned explicit-reference-counting wrapper (Phase 12). The ADR, risk table, W_host memory row, and mem stdlib rows were updated in both the Chinese (authoritative) and English mirror docs. docs/AGENTS.md now records the "spec-first" priority rule (conflict → ask → SPECIFICATIONS → IMPLEMENTATION → code).

  • Modularized the interpreter (spec §4.8). The single 6.5k-line prima-runtime eval.rs god module is split into a src/eval/ module directory with one cohesive file per concern: env (environment/function values), helpers (stateless diagnostic & numeric helpers), entry (construction + module system), stmt (statement/control-flow), expr (expression + numeric ops), call (call dispatch/JIT/higher-order), class (classes & builtin value-type methods), apply (indexing/function application/broadcast/SIMD), pattern (match/pattern-routing), and builtin (builtins + I/O). eval.rs now holds only the module root (type/Flow/re-exports). All 607 tests pass unchanged; no behavior, formatting, or public API changed.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 04:04

Added

  • Builtin method system for every core type (spec §18.1/§11.3/§11.6/§9, Phase 10). The embedded core::<class> .pra modules (String/Array/Dict/Set/Number/Char/Tuple/Option/Result) are now the single source of truth for each type's method set and /// docs, and builtin-value method calls dispatch through their class definitions with the @builtin(ON) layering (spec §18.4): the registered Rust fast path runs at opt_level >= N and the .pra fallback body is the semantic authority. String gains the full Python-str-inspired set (~50 methods: predicates, case transforms, padding, count/rfind/removeprefix/removesuffix/splitlines/expandtabs/partition/…; split("") yields the single characters); Array/Dict/Set fill the Python gaps (copy, setdefault, popitem, symmetric_difference, issubset/issuperset/isdisjoint, pop/clear/update); Number adds predicates/accessors (is_integer/abs/sign/floor/ceil/round/sqrt/numerator/denominator/real/imag/bit_length/is_*); Char/Tuple/Option/Result get their full small method sets (is_*/code/count/get/is_some/is_ok/value_or/…). prima doc --stdlib and failed-call diagnostics now cover every core type. Builtin-class method definitions live in the standard library; without prima_stdlib::init() the methods are unavailable (the interpreter reports a clear error).

Fixed

  • Windows io tests. crates/prima-stdlib/tests/io.rs embedded the temp-file path directly into a Prima string literal; on Windows the path's backslashes (e.g. \U in C:\Users\...) were read as invalid escape sequences and every test failed with syntax error: invalid escape sequence. Paths are now escaped with primed_str (doubling backslashes, quoting double-quotes, spec §18.1) before interpolation.

v0.2.4-beta

Choose a tag to compare

@github-actions github-actions released this 28 Aug 06:27

Added

  • Quick-install scripts. install.sh (POSIX bash) and install.ps1 (Windows PowerShell) at the repo root download the latest prima release binary for the detected OS/architecture (mapping to the release matrix targets), verify the SHA-256 checksum, and install to ~/.local/bin (override with PRIMA_INSTALL_DIR; PRIMA_TARGET/PRIMA_VERSION override detection). The README now shows the one-line install commands.
  • CI workflow (.github/workflows/ci.yml). Runs cargo fmt --all --check and cargo clippy --workspace --all-targets -- -D warnings on ubuntu and cargo test --workspace on ubuntu + windows, for every push to main/dev and every pull request.
  • tests/cli.rs: run_all_examples_succeed now also runs the previously unasserted examples autodiff, builtin_layers, capi, config_simplify, fstring, jit, mymath, opt_levels.

Changed

  • Release workflow macOS matrix. x86_64-apple-darwin was pinned to macos-13, a GitHub-hosted runner retired in Dec 2025 — a retired runs-on label leaves the job queued forever instead of failing. Both macOS targets now run on macos-15 (arm64): x86_64-apple-darwin is cross-compiled on Apple Silicon via rustup target add + cargo build --target (the Xcode SDK is universal), and aarch64-apple-darwin builds natively. The build job gained a timeout-minutes safety net and verifies the x86_64 macOS artifact's architecture with file.
  • Comment/consistency housekeeping. Removed stray Chinese text from code comments (src/diagnostics.rs, examples/jit.pra), fixed a duplicated phrase in examples/linear_algebra.pra, dropped stale "prima-jit is a stub" wording in benches/bench_jit.rs (the crate is fully implemented), and reworded "deferred to a later phase/stage" doc comments to "later release". docs/IMPLEMENTATION-*.md §5 roadmap heading updated to reflect Phases 0–12 scope.
  • Workspace reformatted with cargo fmt (rustfmt 1.9). The whole workspace is now canonical rustfmt output (cargo fmt --all --check passes), so formatting is enforced in CI like clippy and the tests.
  • README (English + Chinese) rewritten with badges, an install section, and updated document version references (v2.1 → v2.3); the broken cargo run -- release run quick-start command was corrected.

v0.2.3-beta

Choose a tag to compare

@github-actions github-actions released this 28 Aug 02:30

Added

  • opt_level optimization tiers (spec §10.2/§13.2, Phase 8). A new OptLevel policy (O0–O3, default O2) gates the compiler optimization channels: the arithmetic-series loop closed form now requires opt_level >= O1, automatic JIT hot-path compilation and tail-call optimization require opt_level >= O2, and tier O3 enables SIMD vectorization of dense F64 array elementwise binary ops (runtime::simd, via the portable wide crate on stable Rust). simplify_level was wired into the symbolic simplify pipeline (simplify_at), so lowering it reduces only how deeply a symbolic value is canonicalized — never its mathematical value. Results are semantically identical across tiers (equivalence tests; IEEE lane arithmetic is bit-identical to scalar).

Changed

  • @builtin layered optimization (spec §18.4, Phase 9). @builtin may now take a tier, @builtin(O0)–@builtin(O3): tier O0 (bare) stays signature-only and must bind to a registered Rust implementation (E0055/E0056); tiers O1–O3 carry a .pra fallback body (the semantic authority, E0056 if absent) plus an optional Rust fast path used when opt_level >= N, with an invalid tier reported as E0057. A new Function::Layered variant dispatches between the two implementations at call time. register_impl was augmented with register_impl_level and a declarative builtin! macro (builtin!("num::fibonacci", fibonacci_impl, O1)) that replaces the manual string-keyed registration calls across the stdlib crates; the .pra @builtin(ON) annotation remains the authoritative dispatch tier.