Вирт - русифицированный паскаль. A modern, self-hosting Object Pascal compiler built for the 2020s. Zero legacy, full ARC, and unified UTF-8.
Find a file
Graeme Geldenhuys dbe1f37b65 feat(unit/lang): unit infrastructure fixes uncovered by punit re-port (Phase D)
Re-restoring 'overload' directives across punit.pas (the Phase A
blocker called out by the handover) surfaced a series of unit-section
gaps that were silently broken because no test exercised them.  Each
fix is small and bounded; together they let punit progress past the
overload duplicate-identifier wall and ten subsequent declarations,
into the next genuine missing-feature blocker (Delete-as-builtin).

Compiler changes:

- ParseForwardDecl (uParser.pas): now accepts the same directive set
  as ParseMethodDecl — overload, external, inline, stdcall, cdecl,
  register, pascal, safecall, forward, deprecated, platform,
  experimental.  Previously only 'external' was recognised, so any
  unit interface forward decl carrying 'overload' raised
  "Expected token tkImplementation".
- AnalyseUnit / AnalyseUnitForExport (uSemantic.pas): symbol
  registration for both forward and impl-only standalone proc/func
  decls now propagates IsOverload, sets ResolvedQbeName, and uses
  signature-aware matching to pair an impl with its forward decl
  when both are overloaded.
- AnalyseUnit: now also processes interface-section variable decls
  (registering them as IsGlobal symbols visible to impl bodies),
  interface-section const decls, impl-section const + type decls,
  and impl-section global var decls.  AnalyseUnitForExport got the
  matching impl-section type-decl + interface-section var-decl
  passes.  Without these, any unit whose impl bodies referenced an
  impl-section enum or an interface-section global silently raised
  "Unknown type" / "Undeclared variable".
- AnalyseStandaloneDecl: skip body analysis when ADecl.Body = nil.
  Prevents an AV when a forward-only decl reaches the body pass
  (e.g. a forward overload whose impl lives in another section).
- TFieldAssignment: accept skVarParameter (in addition to skVariable
  and skParameter) as a valid receiver kind so 'Suites.Count := 0'
  is permitted inside 'procedure InitSuiteList(var Suites: TSuiteList)'.
- Var-argument check: an L-value var argument may now be a
  TFieldAccessExpr (R.F or P^.F) in addition to a plain TIdentExpr.
  The existing field-access typing already produces ResolvedType so
  the subsequent CheckTypesMatch handles it correctly.
- CheckTypesMatch: nil literal now compatible with tyProcedural
  parameter slots (procedural-type fields are routinely nil-cleared
  via SetXxxHandler(nil) idioms).

punit changes:

- Re-applied 'overload;' to every interface and implementation
  declaration of the 17 names that participate in overload sets
  (AddSuite, AddTest, AssertEquals, AssertPassed, DoRunSysTests,
  ExpectMessage, FreeSuiteList, GetSuite, GetSuiteCount,
  GetSuiteIndex, GetTest, GetTestCount, GetTestIndex, RunSuite,
  RunTest, SetTestResult, SetTestResultRec).

Tests: 1179 pass, 0 errors, 0 failures.  New regression coverage:

- cp.test.varparams: var-arg accepts R.F and P^.F field accesses.
- cp.test.units: interface var visible in impl, impl-section type
  decl in scope, forward decl with 'overload' parses + analyses.

Punit still does not compile end-to-end: the next blocker is the
Delete(S, Idx, Count) string built-in (line 844), unrelated to
overloading.  That is a separate language-feature task.
2026-05-04 11:06:12 +01:00
compiler feat(unit/lang): unit infrastructure fixes uncovered by punit re-port (Phase D) 2026-05-04 11:06:12 +01:00
docs feat(lang): standalone function overloading — Phase A (arity) 2026-05-04 10:22:21 +01:00
plugins chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +01:00
rtl feat(unit/lang): unit infrastructure fixes uncovered by punit re-port (Phase D) 2026-05-04 11:06:12 +01:00
tests chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +01:00
tools chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +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
LICENSE chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +01:00
NOTICE chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +01:00
project.xml chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception 2026-05-03 19:45:29 +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].