Phel v0.36.0 – Lisp on PHP, now with numeric tower and first-class Vars

原始链接: https://github.com/phel-lang/phel-lang/releases/tag/v0.36.0

相关文章

原文

First-class Vars + Ratios/BigInteger/BigDecimal numeric tower + Uuid/PhpClass/MapEntry/Queue types + faster test/REPL scans.

🎉 Added

Compiler

  • (var sym) special form for first-class Var handles (#1717)
  • #'sym reader macro for (var sym) (#1717)
  • Ratio literals 1/2, -3/4 parse to Rational (#1825)

Lang

  • Phel\Lang\Uuid value type; #uuid "...", random-uuid, parse-uuid return Uuid
  • Phel\Lang\PhpClass value type wrapping a normalised PHP class/interface FQN
  • Phel\Lang\Collections\Map\MapEntry value type, equal by value to a 2-element vector
  • Phel\Lang\Collections\Queue\PersistentQueue persistent FIFO with amortised O(1) push/peek/pop (#1869)
  • Phel\Lang\BigDecimal value type; M-suffix literals 1.5M, 1.5e3M
  • Phel\Lang\BigInteger and Phel\Lang\Rational value types (#1825)
  • Phel\Lang\NumericOperations runtime dispatch for Rational, BigInteger, native numbers (#1825)
  • PhelVar is callable, exposes addWatch/removeWatch/alterMeta/resetMeta/isDynamic
  • PhelVarStateRegistry singleton for watches, meta overrides, dynamic-flag cache

Core

  • Var type with deref, meta, alter-var-root (#1717)
  • find-var, var-get, var?, bound?, thread-bound?, var-set (#1717)
  • with-redefs for any var, restores on exception
  • with-bindings rebinds dynamic vars from a Var -> value map
  • add-watch/remove-watch target Var, fire on alter-var-root
  • alter-meta!/reset-meta! survive def redefinitions
  • symbol accepts a Var (#1821); special-symbol? recognizes var (#1822)
  • ratio?, bigint?, numerator, denominator, rationalize (#1825)
  • quot, rem, mod; % aliases rem (#1831)
  • floor, ceil, round, sqrt (#1831)
  • +', -', *', inc', dec' auto-promoting variants (#1831)
  • bigint, biginteger constructors (#1831)
  • map-entry constructor; map-entry? predicate (MapEntry or 2-element vector); key/val work on either
  • class, class?, class-name for PhpClass
  • bigdec constructor; bigdec?/decimal? predicates
  • (queue & xs) constructor and queue? predicate (#1869)
  • type returns :uuid, :php/class, :map-entry, :queue, :bigdec, :atom, :var, :ratio, :bigint

Testing

  • phel test --list prints discovered tests after applying filters/selectors and skips execution
  • phel test --last-failed re-runs only tests that failed on the previous run; failures persist to .phel/last-failed.txt
  • phel test --slowest=N prints the N slowest tests after the summary

Documentation

  • docs/numeric-tower.md covers int/BigInteger/Rational/float (#1832)

⚖️ Changed

Compiler

  • Zero-denominator ratio literals raise ZeroDenominatorRatioParserException at parse time (#1825)

Lang

  • (first m) and (next m) yield MapEntry instances; MapEntry equals a 2-vector both ways (#1868)
  • assoc and conj on MapEntry return a PersistentVector; (nth entry idx) and (count entry) work directly (#1871)
  • BigDecimal::__toString returns the canonical decimal form without the M suffix; pr/prn keep the suffix (#1877)
  • printer renders rationals as n/d (#1825)

Stdlib

  • Top-level (use ...) in src/phel/core/* uses dot-separated class FQNs
  • with-mocks/with-mock-wrapper expand to with-redefs
  • *ns* bootstrap is "phel.core" (dot form)
  • Arithmetic, comparisons, predicates dispatch on Rational/BigInteger (#1825)

🐛 Fixed

Compiler

  • Symbol/keyword names ending in ' (inc', dec', +', -', *') resolve cross-namespace
  • Oversize decimal int literals lex as float (#1837)
  • clojure.lang.X FQNs resolve to \Phel\Lang\X (BigInt to BigInteger, Ratio to Rational) (#1840)
  • LiteralEmitter::emitFloat skips .0 when the rendered float carries . or an exponent (#1846)
  • N-suffix int literals beyond PHP_INT_MAX parse as BigInteger (#1850)
  • LiteralEmitter::emitFloat emits NAN/INF/-INF as constants on PHP 8.5 (#1898)
  • VarEmitter prefixes \Phel\Lang\Registry with leading backslash so (var sym) resolves outside phel\\ namespaces

Core

  • +, -, *, / mixing ##Inf/##NaN with BigDecimal fall back to float arithmetic (#1887)
  • vector? returns true for MapEntry produced by hash map iteration (#1889)
  • BigDecimal with a float in +, -, *, /, quot, rem, mod, compare returns a float (#1891)
  • rationalize uses the shortest round-trip decimal (#1832)
  • float/double accept Rational and BigInteger (#1836)
  • integer? accepts BigInteger; int? stays PHP-int only (#1837)
  • int/long/short/byte accept Rational, BigInteger, BigDecimal (#1842, #1867)
  • int/long/short/byte on float route through BigInteger::fromFloat; out-of-range raises OverflowException, NaN/Inf raise InvalidArgumentException (#1846)
  • quot returns float when any operand is float (#1844)
  • abs(PHP_INT_MIN) returns BigInteger 9223372036854775808 (#1844)
  • bigint accepts floats, truncates toward zero, rejects NaN/Inf; uses shortest round-trip decimal (#1845, #1852)
  • pos-int?/neg-int?/nat-int? accept BigInteger
  • symbol rejects non-name input with InvalidArgumentException; (symbol nil name) returns unqualified symbol (#1859)
  • zero?/pos?/neg?, </<=/>/>=, ==, number? route BigDecimal through the numeric tower (#1867)
  • bigdec accepts Rational; non-terminating expansions raise ArithmeticError (#1873)
  • +, -, *, /, abs, quot, rem, mod, rationalize accept BigDecimal; / raises ArithmeticError on non-terminating expansions (#1875)

Lang

  • = between int and BigInteger is symmetric (#1830)
  • +, -, *, ** on PHP ints auto-promote to BigInteger on overflow (#1830)
  • (/ 1.0 0.0) returns ##Inf; (/ -1.0 0.0) returns ##-Inf; (/ 0.0 0.0) returns ##NaN (#1830)

Testing

  • --filter and :filters drop non-matching tests at discovery instead of marking S (#1888)

Performance

  • REPL boot prunes vendor/, .git/, node_modules/ at scan descent; directory scans memoised per process (#1885)
  • bin/phel test --ns 'pat.**' preloads only matching namespaces and their dependency closure
  • bin/phel test skips re-registering dependency-graph entries on cache hits and re-restoring a namespace's environment after the first file
  • NamespaceCollector collapses three overlapping directory scans into one (#1901)

Breaking

Core

  • binding throws InvalidArgumentException for non-^:dynamic vars; use with-redefs
  • (/ int int) with non-integer result returns Rational; use (/ 1.0 2) or (double ...) for float division (#1825)
  • uuid? accepts only Phel\Lang\Uuid; wrap strings with parse-uuid or #uuid "..."; random-uuid/parse-uuid and s/coerce :uuid return Uuid; s/validate :uuid still accepts canonical strings

🗑️ Removed

Core

  • var alias for atom (#1717)
  • var? alias for atom? (#1717)
  • set! alias for reset! (#1717)

Documentation

  • README updated for dot-separated namespace syntax

👥 Contributors

@Chemaclass @Lacsw @jasalt @JesusValeraDev @SAY-5

Full Changelog: v0.35.0...v0.36.0

联系我们 contact @ memedata.com