Вирт - русифицированный паскаль. A modern, self-hosting Object Pascal compiler built for the 2020s. Zero legacy, full ARC, and unified UTF-8.
Find a file
Graeme Geldenhuys 6e18aba8f1 Insert ARC on class vars, class fields, params; rewire Free as release
Completes the variable/field/param ARC insertion pass for class types
and wires the destructor path for ARC-managed fields.

Compiler changes:
  * EmitAssignment: tyClass branch mirrors string ARC (addref new, release
    old, store)
  * EmitFieldAssignment: same pattern for string and class field stores
  * EmitStringCleanup renamed EmitArcCleanup; releases class locals
    alongside string locals at block exit
  * EmitExcPathArcCleanup: releases class locals on exception unwind
  * EmitFuncDef / EmitMethodDef: addref class value params on entry and
    release on exit (matches the existing string convention for standalone
    funcs; closes the gap for methods)
  * Obj.Free lowered to _ClassRelease + nil-out of the variable slot —
    Free is now a sanctioned synonym for immediate release, and the
    scope-exit release on the zeroed slot becomes a safe no-op
  * New EmitFieldCleanupDefs emits a $_FieldCleanup_<Class> function per
    class (and per generic instantiation) that releases each ARC-managed
    field; _ClassRelease invokes it before free() when the refcount
    reaches zero

Inherited fields are already merged into the derived class's Fields list
by the semantic analyser, so the derived cleanup is authoritative — no
parent chain, which would otherwise double-release.

RTL changes:
  * Object header grows from 8 to 16 bytes to carry the cleanup fn pointer
  * _ClassAlloc takes (size, cleanup_fn); refcount still starts at 0
  * _ClassRelease calls cleanup before free when rc reaches zero

Absorbs Task 4 (Free as release synonym).  phase2_milestone valgrind
test remains leak-clean with the new ARC rules in force; 5 new codegen
assertions cover the insertion points explicitly.
2026-04-23 00:52:55 +01:00
compiler Insert ARC on class vars, class fields, params; rewire Free as release 2026-04-23 00:52:55 +01:00
docs Document class-ownership decision: universal ARC on TObject 2026-04-23 00:08:55 +01:00
rtl Insert ARC on class vars, class fields, params; rewire Free as release 2026-04-23 00:52:55 +01:00
tests Collapse Write+WriteLn pairs into multi-arg WriteLn in milestone tests 2026-04-22 23:19:55 +01:00
tools Phase 1 bootstrap: Blaise compiler skeleton 2026-04-20 15:35:50 +01:00
vendor/qbe Fix compilation errors; vendor QBE 1.2; end-to-end Hello World works 2026-04-20 16:38:57 +01:00
.gitignore Add CLAUDE.md to .gitignore 2026-04-20 22:45:38 +01:00
LICENCE Initial project scaffold 2026-04-20 14:22:10 +01:00
project.xml Phase 1 bootstrap: Blaise compiler skeleton 2026-04-20 15:35:50 +01:00
README.adoc Document class-ownership decision: universal ARC on TObject 2026-04-23 00:08:55 +01:00

= Blaise
:toc: left
:toclevels: 2
:icons: font
:source-highlighter: rouge

A modern, cross-platform Object Pascal compiler targeting native code via
https://c9x.me/compile/[QBE] (and eventually LLVM). Single language mode,
single string type, zero-GUID interfaces, reified generics, and first-class
https://github.com/graemeg/opdebugger[OPDF] debug format support.

Bootstrapped with https://www.freepascal.org/[Free Pascal Compiler].
Built with https://github.com/graemeg/pasbuild[PasBuild].
Licensed under the BSD 3-Clause licence.

== Design Philosophy

The Object Pascal ecosystem has two options: Embarcadero Delphi (proprietary,
Windows-first) and Free Pascal (open source but carrying 30 years of accumulated
complexity — five language modes, five string types, and thousands of include files).

This compiler takes a different approach:

* *One language mode.* No `{$mode}` switches; no legacy dialect support.
* *One string type.* UTF-8 reference-counted string. `RawBytes` for binary data.
* *One memory model.* Automatic reference counting applies uniformly to
  strings, classes, and interfaces. No manual/auto split between `TObject`
  and `TInterfacedObject`; `[Weak]` breaks cycles. `Free` is retained as a
  synonym for immediate release.
* *Clean interfaces.* No COM GUIDs; interface dispatch via compile-time vtable mapping.
* *Reified generics.* Monomorphization at compile time — no type erasure.
* *Modern build system.* PasBuild with `project.xml`; no makefiles.
* *First-class debugger.* OPDF is the default debug format; DWARF is not required.

See link:docs/design.adoc[docs/design.adoc] for the full architecture and
implementation plan.

== Repository Layout

This project uses PasBuild's multi-module layout. Each subdirectory with a
`project.xml` is an independent module; the root `project.xml` is the aggregator.

....
project.xml                       Root aggregator (packaging=pom)
│
├── compiler/                     The compiler binary (packaging=application)
│   ├── project.xml
│   └── src/
│       ├── main/pascal/          uLexer, uParser, uAST, uCodeGenQBE, ...
│       └── test/pascal/          FPTest test suite for compiler units
│
├── rtl/                          Runtime library (packaging=library)
│   ├── project.xml
│   └── src/
│       ├── main/pascal/          System.pas, SysUtils.pas, Classes.pas, ...
│       └── test/pascal/          FPTest test suite for RTL units
│
├── tools/
│   └── migration-analyser/       FPC/Delphi migration report tool (packaging=application)
│       ├── project.xml           depends on compiler module
│       └── src/
│           ├── main/pascal/
│           └── test/pascal/
│
├── vendor/qbe/                   Vendored QBE backend source (pinned, built from source)
└── docs/                         Design documents and specifications
....

PasBuild compiles each module to its own `target/` subdirectory. Build output is
never committed to the repository.

== Status

[cols="1,3,1", options="header"]
|===
| Phase | Goal | Status

| 1
| Bootstrap pipeline — Hello World on Linux x86_64 via PasBuild
| Complete

| 2
| Type system — classes, records, ARC, exceptions
| Complete

| 3
| Generics + zero-GUID interfaces
| Complete

| 4
| OPDF debug info emission
| Planned

| 5
| Self-hosting + LLVM + Windows + macOS ARM64
| Planned

| 6
| LSP + VS Code extension
| Planned

| 7
| Migration analyser for FPC/Delphi codebases
| Planned
|===

== Building

=== Prerequisites

* Free Pascal Compiler 3.2.2 or later (stable; 3.3.x development snapshots are not required)
* https://github.com/graemeg/pasbuild[PasBuild]
* A C compiler (`gcc` or `clang`) for building the vendored QBE backend
* GNU `ld` or `lld` (Linux); `ld` (macOS)

=== Build all modules

[source,shell]
----
pasbuild compile
----

PasBuild resolves the module dependency order automatically and compiles
`rtl` → `compiler` → `tools/migration-analyser`.

=== Build with a profile

[source,shell]
----
pasbuild compile -p debug      # includes -g -gl -Criot -gh
pasbuild compile -p release    # includes -O2 -CX -XX -Xs
----

=== Run tests

[source,shell]
----
pasbuild test
----

=== Build a single module

[source,shell]
----
pasbuild compile -m blaise-compiler
----

=== Running the compiler

Once built, the compiler binary is at `compiler/target/blaise`.

[source,shell]
----
# Compile a single file
compiler/target/blaise --source Hello.pas --output Hello

# Compile via project.xml
compiler/target/blaise --project project.xml --config debug --output myapp

# Emit QBE IR (useful for debugging the compiler itself)
compiler/target/blaise --source Hello.pas --emit-ir
----

== What Is Dropped From Classic Pascal

[cols="1,3", options="header"]
|===
| Feature | Reason for removal

| `ShortString`, `AnsiString`, `WideString`, `UnicodeString`
| Replaced by a single UTF-8 reference-counted `string` type

| `with` statement
| Source of hard-to-diagnose symbol resolution bugs; breaks static analysis

| Old-style `object` types
| Use `record` (stack/value) or `class` (heap/reference) instead

| COM-style interface GUIDs
| Interface dispatch via compile-time vtable; GUIDs are unnecessary complexity

| Multiple language modes
| One dialect, maintained well, beats five dialects maintained poorly

| `assign`, `reset`, `rewrite`, `blockread`
| Replaced by a stream-based I/O RTL

| `TObject` vs `TInterfacedObject` split
| One unified class model under automatic reference counting; `[Weak]`
  breaks cycles
|===

== Licence

BSD 3-Clause. See link:LICENCE[LICENCE].