v0.2.0
The second release of DotProlog, and the first with independent conformance evidence: all 768
applicable declarations of the pinned Logtalk 3.101.0 ISO Prolog corpus pass — as consulted
bytecode, as generated C#, across both compiled↔bytecode boundaries, and from a published
NativeAOT executable. The engine gained first-argument clause indexing, the language gained an
opt-in strict ISO mode, and dotnet test now drives Prolog test projects directly.
A changelog section dated 0.1.1 (2026-07-30) was never shipped — no tag, no GitHub release, and
nothing on NuGet.org — so its content is folded in here and this release is 0.2.0.
Added
- First-argument clause indexing in the bytecode VM. Static multi-clause predicates dispatch
through a clause table keyed on the first argument, and dynamic predicates skip clauses whose
first argument could never unify — under the unchanged logical update view. A call with a bound
first argument that can only reach one clause creates no choice point. Solutions and their order
are unchanged; build-time generated C# keeps its existing in-order clause chains. - The pinned 768-case independent ISO corpus now runs exhaustively through generated C#,
compiled-to-bytecode, bytecode-to-compiled, and NativeAOT paths in CI. - Part 3 DCG semicontexts and
Name//Aritydeclarations fordynamic/1,multifile/1, and
discontiguous/1. - An opt-in strict ISO language mode for embedding,
dotnet prolog, generated code, and
.dplprojbuilds. It rejects known predefined extensions during source preparation and at
runtime meta-call and host-binding boundaries. - A
prolog-testtemplate whosetest_*predicates are discovered and run bydotnet test. - A clean local-feed consumer gate that installs the packed templates and .NET tool, then builds,
runs, NativeAOT-publishes, and tests generated projects from a path containing spaces. - A uv-managed MkDocs documentation site on Python 3.14 with getting-started, language, .NET
integration, architecture, and contributing guides, plus strict link validation in CI. - The ISO evaluable functors for trigonometry, logarithms, exponentials, rounding, float
decomposition, and bitwise complement. - ISO
unify_with_occurs_check/2with transactional failure and cycle-safe rational-tree
traversal. - ISO
current_predicate/1enumeration for static, dynamic, declared-empty, and runtime-created
user procedures.
Changed
- Module preparation now requires one leading
module/2declaration and rejects malformed,
unexported, or conflicting selected imports. - DCG processing uses the Part 3
|operator priority, rejects reserved and predefined grammar
heads, and applies the specifiedphrase/2and terminal-sequence validation. - Extended DCGs lower soft cut consistently in static and runtime-loaded source; strict mode treats
the additional control as an ordinary nonterminal. - The repository test suite now uses Microsoft.Testing.Platform v2 through the .NET 10
global.jsontest-runner contract, so xUnit and Prolog test projects run together. - Release checksums now cover packages, symbols, the SBOM, and all native binaries; the CycloneDX
tool is pinned, and a missing NuGet API key fails rather than silently skipping publication. - Child build processes close standard input, are killed with their process tree if they exceed the
integration-test limit, and every CI and release job has an explicit timeout. DotProlog.Sdknow carries a real package title and description.- Arithmetic now enforces ISO operand signatures, float division result types, bounded-overflow
errors, and the distinct exceptional cases for zero division, undefined results, and float
overflow. - The repository's ISO-derived conformance corpus now contains 563 passing cases.
- Integration tests no longer tolerate the zero-tests-ran exit code, child-process output reads
share the process deadline instead of waiting on a held pipe forever, and a failing release
verify platform no longer cancels its siblings.
Fixed
- The repository gates pass again on Windows and Linux: conformance and strict-ISO runner
rebuilds now use isolated build outputs instead of overwriting the shared test assembly that a
later no-build step executes, MSBuild worker nodes no longer outlive their step holding task
assemblies locked, host paths interpolated into quoted atoms escape their backslashes, the
Logtalk adapter emits the same line endings on every platform, and the packed-package consumer
gate findsnuget.configon case-sensitive filesystems. - The machine protected new environment frames only against the newest choice point, so a frame
deallocated by last-call optimisation could be overwritten while an older choice point still
referenced it. Solutions were silently dropped —forall/2with a compound action and
findall/3over goals with in-clause disjunction or negation were the visible cases — and an
uncaught exception could vanish while backtracking throughcatch/3. The protection watermark
is now monotone up the choice-point stack. retract/1andclause/2re-read the database generation on every redo, letting clauses
asserted after the goal started appear mid-enumeration. Both now keep the generation captured at
the first solution and resume from a stable clause cursor, soasserta/1between solutions can
no longer shift or repeat answers.- Copying a cyclic term — through
copy_term/2,findall/3,assertz/1, orthrow/1— looped
forever. It now raises catchablerepresentation_error(cyclic_term), and the term writer prints
cycles as...instead of hanging. - Every meta-call of a control term compiled a fresh clause into the append-only program. Compiled
control goals are now cached by shape, so long-running loops no longer grow memory without bound. - Integer division by zero always raises
evaluation_error(zero_divisor); only float0.0/0.0
remainsundefined. atom_chars/2,atom_codes/2,number_chars/2, andnumber_codes/2with a bound first
argument now convert it and unify with the list instead of raisinginstantiation_error.- Number conversion no longer lets oversized float literals become IEEE infinities or wraps
oversized radix literals; out-of-range input raises the reader'ssyntax_error(float_overflow)
andrepresentation_error(max_integer|min_integer). format/3accepts real stream handles and aliases, andformat(user_error, ...)writes to the
error stream instead of the current output.phrase/2,3treated a run-time if-then-else as a plain disjunction and offered the else branch
as an extra solution.writeq/1emits the named ISO escapes and delimited hex escapes for control characters, so its
output always reads back.- The build task deletes generated facades whose contract was removed or renamed,
dotnet clean
removes the generated directory, and facade generation reruns when the project file or the set
of source files changes — not only when a surviving file's timestamp moves. - Contract mistakes that previously escaped into raw C# compiler errors — or crashed the build
task — are reported asDPL2011–DPL2014diagnostics, and anondetexport with no outputs
streams one unit value per solution as ADR 0006 promises. - Prolog test projects honour run filters, capture
user_errorinto failure reports, and fail a
looping test after a configurable per-test timeout instead of hangingdotnet test.
Compatibility
- Requires .NET 10. Packages are platform-neutral; NativeAOT publishing is exercised on Linux,
Windows, and macOS in CI. - Independent evidence, but still no full ISO claim. The 768 applicable declarations of the
pinned Logtalk 3.101.0 corpus pass on every execution path, and the repository's own 563 cases
encoded from ISO/IEC 13211-1 pass as well. Licensed-text traceability and the Part 2 module and
Part 3 grammar completion gates remain open. See COMPATIBILITY.md. - The strict ISO mode is opt-in; the default profile is unchanged, so existing programs that
use predefined extensions keep working. - There is still no string type: an atom is the only text term, and the SWI-Prolog string
predicates are absent rather than aliased to atoms.
Known limitations
plcand the foreign-predicate source generator are designed but not implemented.- First-argument indexing applies to the bytecode VM; build-time generated C# still tries a
predicate's clauses in order. - A character is a UTF-16 code unit, so
atom_length/2counts a character outside the Basic
Multilingual Plane as two.
Full Changelog: v0.1.0...v0.2.0