Вирт - русифицированный паскаль. A modern, self-hosting Object Pascal compiler built for the 2020s. Zero legacy, full ARC, and unified UTF-8.
Find a file
Graeme Geldenhuys aa492080a5 fix(codegen): fix 5 compiler bugs found by comprehensive e2e tests
Nested record field assignment (O.A.V := 10):
EmitFieldAssignment called EmitExpr on ObjExpr for record-typed bases,
which loaded the contents instead of returning the storage address.
Fixed to use EmitInstancePtr, which correctly returns the address of
inline record storage and the heap pointer for class-typed bases.

Int64 literals exceeding int32 range:
TIntLiteral always emitted =w copy N even for values like 3000000000
that overflow 32-bit signed range.  The semantic pass also always
assigned TypeInteger to int literals regardless of value.  Both now
check whether the value fits in [-2147483648..2147483647] and use
TypeInt64 / =l copy N when it does not.

Byte(X) type cast not truncating:
The type-cast emit path (ResolvedDecl=nil) used =w copy for all
word-typed targets.  Byte casts now emit =w and %t, 255 to mask to
8 bits, matching the expected truncation semantics.

inherited call not setting Result:
EmitInheritedCall always emitted a plain call statement, discarding
the return value of function overrides.  It now captures the return
value and stores it into %_var_Result when the parent method has a
non-void return type.

@Obj.MethodName compiler crash:
AnalyseAddrOfExpr only handled TIdentExpr; TFieldAccessExpr with a
method field caused AnalyseFieldAccess to return nil (procedure has
no return type), then crashed on nil.Name.  Added a branch that
recognises both RecordName (simple) and Base (chained) forms, builds
a method-pointer TProceduralTypeDesc (IsMethodPtr=True), and sets it
on the expression.  EmitAddrOfExpr now allocates a 16-byte block and
stores the static code pointer and loaded object pointer into it.

Also adds ~50 e2e tests covering these features and more:
control flow, records (nested, string fields), pointers, text blocks,
sets, procedural types, default params, open arrays, var/const params,
string ops, Int64, type casts, is/as, inheritance, and interfaces.
2026-05-12 19:15:13 +01:00
compiler fix(codegen): fix 5 compiler bugs found by comprehensive e2e tests 2026-05-12 19:15:13 +01:00
docs docs(lang): document that Ord() is not needed for string processing 2026-05-12 18:05:25 +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(lang): switch to 0-based string indexing throughout compiler and RTL 2026-05-11 17:50:35 +01:00
scripts fix(codegen): eliminate dynamic stack allocs — phi for short-circuit bools, hoist exc frames 2026-05-06 11:47:52 +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 fix: we don't have any code for migration-analyser yet. Disable tests for it. 2026-05-08 00:52:44 +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: begin v0.7.0-dev cycle 2026-05-11 18:02:00 +01:00
README.adoc docs: ditch the TOC in the readme. 2026-05-06 13:10:56 +01:00

= Blaise Pascal Compiler
:icons: font
:source-highlighter: rouge

**The Pascal you love, reimagined for the modern era.**

Blaise is a next-generation Object Pascal compiler built from the ground up to eliminate decades of legacy baggage. It prioritizes developer productivity, memory safety, and high-performance execution.


== ✨ The Vision

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.

The result — 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.


== 🚀 Project Status

* **Self-Hosting:** Yes. Blaise currently bootstraps and recompiles itself with byte-for-byte exact matches.
* **Testing:** 1200+ tests and growing (Test-Driven Development from day one).
* **Backends:** Currently utilizing a QBE backend, with an LLVM backend in active development.


[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
| Complete ✅

| 5
| Self-hosting + LLVM + Windows + macOS ARM64
| In-Progress

| 6
| LSP + VS Code extension
| Planned

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

== 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
|===

== 📢 Community

The core architecture is still being finalised, so the project is not yet
accepting code contributions. Feedback on language design, syntax choices, and
the future direction of Blaise is very welcome — please use the
https://github.com/graemeg/blaise/discussions[Discussions] tab on GitHub.


== 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.

== 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
----

== Licence

Apache License v2.0 with Runtime Library Exception. See link:LICENSE[LICENSE].


---
*Built with ❤️ for the Pascal community by Graeme.*