Вирт - русифицированный паскаль. A modern, self-hosting Object Pascal compiler built for the 2020s. Zero legacy, full ARC, and unified UTF-8.
Find a file
Graeme Geldenhuys c657cccc11 feat(rtl+compiler): string data-pointer ABI — consistency with class objects
Changes Blaise's string variable convention from header-pointer to
data-pointer, matching how class objects work: the pointer stored in a
variable slot points to the first useful byte, with the ARC bookkeeping
header immediately before it at negative offsets.

New layout (data-pointer convention):
  data_ptr - 12  RefCount  (4 bytes, Integer)
  data_ptr -  8  Length    (4 bytes, Integer)
  data_ptr -  4  Capacity  (4 bytes, Integer)
  data_ptr +  0  char data (UTF-8 bytes + NUL terminator)

Old layout (header-pointer convention):
  header_ptr +  0  RefCount
  header_ptr +  4  Length
  header_ptr +  8  Capacity
  header_ptr + 12  char data

Benefits:
- Consistency: both strings and class objects use "pointer to content"
  convention; ARC header hidden at negative offsets for both
- S[N] subscript: simplifies from (ptr + N + 11) to (ptr + N - 1)
- PChar(str) cast: becomes an identity — str IS already the data pointer
- C interop: zero-cost on non-Win32 targets (Linux, macOS POSIX)
- OPDF: recAnsiStr now emits correct negative LengthOffset/RefCountOffset

RTL changes (all six string-layer files):
  blaise_str.pas   StrAlloc returns base+12; StrLen reads ptr-8;
                   StrData is identity; all callers updated
  blaise_arc.pas   _StringAddRef/Release access ptr-HDR_SIZE;
                   _StringEquals/_StringConcat updated
  blaise_sys.pas   _SysWriteStr/Int/Int64 read len at ptr-8
  blaise_str_fmt.c str_alloc returns base+HDR_SIZE; str_data identity;
                   str_len reads ptr-8
  blaise_io.c      io_str_alloc/data/len updated; all callers fixed
  blaise_process.c proc_str_alloc/data/from_cstr updated

Compiler codegen:
  EmitStrLit    adds 'add $__sN, 12' to convert header label to data ptr
  S[N]          'add idx, 11' → 'sub idx, 1'
  PChar(str)    '+12 add' removed — identity pass-through
  for B in S    length from ptr-8; data from ptr+0 (no skip offset)

OPDF emitter: LengthOffset=-8, RefCountOffset=-12 (was +4, +0)

Tests: 2 test assertions updated to match new ABI semantics;
1105 total, all passing.
2026-05-02 12:26:13 +01:00
compiler feat(rtl+compiler): string data-pointer ABI — consistency with class objects 2026-05-02 12:26:13 +01:00
docs feat(compiler): for..in — string byte iteration (Step 7c) 2026-05-02 11:12:52 +01:00
plugins feat(test): PDR integration test suite and pasbuild-integration-test plugin 2026-05-02 00:35:00 +01:00
rtl feat(rtl+compiler): string data-pointer ABI — consistency with class objects 2026-05-02 12:26:13 +01:00
tests feat(plugin): add pasbuild-blaise-compile plugin 2026-05-01 11:18:36 +01:00
tools Stub program unit for the migration analyser. 2026-04-24 08:12:30 +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 release: promote version to 0.1.0 2026-04-27 09:17:23 +01:00
LICENCE Initial project scaffold 2026-04-20 14:22:10 +01:00
project.xml build: disable blaise-rtl from default reactor build 2026-04-24 08:06:01 +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].