README.adoc: - Native x86-64 is the default backend since v0.12.0; QBE is opt-in (--backend qbe). Reframed the intro, project status, bootstrap, and single-file compile examples accordingly (native one-step build leads; QBE shown as the opt-in multi-step path). - Test count 3474 -> 3800+ (3744 compiler + 57 stdlib). - Added a Standard library status line (generics collections, JSON, SHA-1, Base64, GUIDs, sockets, WebSockets, HTTP server, blaise.testing). - Bootstrap example resolves the newest releases/v* binary instead of the stale v0.7.0 path, and uses the native --output build. - OPDF now debugs incrementally-compiled multi-unit programs. grammar.ebnf (CLAUDE.md sync rule): - TypeName accepts a unit-qualified, possibly-dotted QualIdent (UnitName.TypeName, System.SysUtils.TFormatSettings). - FieldAssignment l-value extended with a Selector chain (.Field / [Index] / .Method(...)) so Self.F[i].Sub := value parses. language-rationale.adoc: - New entries "Qualified type names" and "Chained l-value assignment" recording the decision, reasoning, and alternatives for the two conservative FPC/Delphi-compatible parser extensions made this cycle.
287 lines
10 KiB
Plaintext
287 lines
10 KiB
Plaintext
= Blaise Pascal Compiler
|
|
:icons: font
|
|
:source-highlighter: rouge
|
|
|
|
image:https://github.com/graemeg/blaise/actions/workflows/bootstrap.yml/badge.svg["Build status", link="https://github.com/graemeg/blaise/actions/workflows/bootstrap.yml"]
|
|
|
|
**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 and 0-based indexing. `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 two backends: a direct native x86-64 code generator (the default since
|
|
v0.12.0) and https://c9x.me/compile/[QBE] (now opt-in via `--backend qbe`).
|
|
Single language mode, single string type, zero-GUID interfaces, reified
|
|
generics, and first-class
|
|
https://github.com/graemeg/opdebugger[OPDF] debug format support — including
|
|
full source-level debugging of incrementally-compiled multi-unit programs.
|
|
|
|
|
|
== 🚀 Project Status
|
|
|
|
* **Self-Hosting:** Yes. Blaise bootstraps and recompiles itself with byte-for-byte fixpoint. FPC is no longer required — the entire toolchain runs on Blaise alone.
|
|
* **Testing:** 3800+ tests and growing (Test-Driven Development from day one). The test suite itself compiles under Blaise.
|
|
* **Backends:** Two code-generation backends — a direct native x86-64 backend (the default since v0.12.0) and QBE (opt-in via `--backend qbe`). Both pass the full fixpoint and test suite.
|
|
* **Standard library:** A growing opt-in stdlib — generics collections, JSON (DOM + parser + writer), SHA-1 and Base64, RFC 4122 GUIDs, TCP sockets, WebSockets, a minimal HTTP/1.1 server, and a `blaise.testing` unit-test framework.
|
|
|
|
|
|
[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
|
|
| Complete ✅
|
|
|
|
| 6
|
|
| Language improvements + expand RTL & StdLib + bug fixing
|
|
| In-Progress
|
|
|
|
| 7
|
|
| Native backend feature parity + Windows + macOS ARM64
|
|
| In-Progress
|
|
|
|
| 8
|
|
| LSP + VS Code extension
|
|
| Planned
|
|
|
|
| 9
|
|
| 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, blaise.codegen.qbe, blaise.codegen.native.*, ...
|
|
│ └── test/pascal/ Test suite (blaise.testing, compiled by Blaise)
|
|
│
|
|
├── runtime/ Always-linked runtime (packaging=library)
|
|
│ ├── project.xml
|
|
│ ├── Makefile
|
|
│ └── src/
|
|
│ ├── main/asm/ Platform assembly (setjmp, atomics, UTF-8)
|
|
│ ├── main/pascal/ system.pas, blaise_str.pas, blaise_arc.pas, ...
|
|
│ └── test/pascal/ Runtime tests (punit, compiled by Blaise)
|
|
│
|
|
├── stdlib/ Standard library — opt-in via uses clause
|
|
│ ├── project.xml
|
|
│ └── src/
|
|
│ └── main/pascal/ sysutils.pas, classes.pas, math.pas, ...
|
|
│
|
|
├── 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
|
|
|
|
* A previously released Blaise binary (see `releases/`)
|
|
* https://github.com/graemeg/pasbuild[PasBuild]
|
|
* A C compiler (`gcc` or `clang`) for building the vendored QBE backend and linking
|
|
* GNU `make` for the runtime build
|
|
|
|
NOTE: FPC is *not* required. Blaise is fully self-hosting — each release binary
|
|
compiles the next version. The bootstrap chain starts from the binary in
|
|
`releases/`.
|
|
|
|
=== Bootstrap from a release
|
|
|
|
The runtime build compiles its Pascal units (`blaise_str.pas`, `blaise_arc.pas`,
|
|
`blaise_sys.pas`) using the Blaise binary at `compiler/target/blaise`. On a
|
|
clean checkout that binary does not exist yet, so the release binary must be
|
|
passed explicitly via the `BLAISE` make variable.
|
|
|
|
[source,shell]
|
|
----
|
|
# Resolve the newest release binary (substitute the path below for $RELEASE).
|
|
RELEASE=$(ls -d releases/v*/ | sort -V | tail -1)blaise # e.g. releases/v0.12.0/blaise
|
|
|
|
# 1. Build the runtime using the release binary (BLAISE= avoids chicken-and-egg)
|
|
cd runtime && make BLAISE=../$RELEASE && make install && cd ..
|
|
|
|
# 2. Compile the compiler using the release binary (native backend — the
|
|
# default since v0.12.0 — needs no external assembler or QBE)
|
|
$RELEASE \
|
|
--source compiler/src/main/pascal/Blaise.pas \
|
|
--unit-path compiler/src/main/pascal \
|
|
--unit-path runtime/src/main/pascal \
|
|
--unit-path stdlib/src/main/pascal \
|
|
--output compiler/target/blaise
|
|
----
|
|
|
|
Once `compiler/target/blaise` exists, subsequent RTL rebuilds (`make && make install`)
|
|
work without the override.
|
|
|
|
The native backend (default) emits and links a binary directly — no external
|
|
tools. To bootstrap via the opt-in QBE backend instead, build the vendored QBE
|
|
once (`cd vendor/qbe && make`), add `--backend qbe --emit-ir > /tmp/blaise.ssa`
|
|
to step 2, then `vendor/qbe/qbe -o /tmp/blaise.s /tmp/blaise.ssa` and
|
|
`gcc -o compiler/target/blaise /tmp/blaise.s compiler/target/blaise_rtl.a`.
|
|
|
|
=== Bootstrap a development checkout
|
|
|
|
The procedure above works while the latest release binary is new enough to
|
|
compile the current source. Between releases that ceases to hold: once a commit
|
|
teaches the parser a new feature and a later commit uses it in the
|
|
runtime/compiler, the release binary can no longer build `master` directly.
|
|
|
|
`scripts/rolling-bootstrap.sh` rebuilds the chain commit-by-commit from the last
|
|
release binary up to the checked-out revision, producing a working `-pre`
|
|
bootstrap binary. See link:scripts/BOOTSTRAP.adoc[scripts/BOOTSTRAP.adoc] for the
|
|
prerequisite (placing the release binary under `releases/`) and usage.
|
|
|
|
=== Build via PasBuild
|
|
|
|
PasBuild can drive the full compile and test cycle using a Blaise binary:
|
|
|
|
[source,shell]
|
|
----
|
|
pasbuild compile -m blaise-compiler --compiler compiler/target/blaise
|
|
pasbuild test -m blaise-compiler --compiler compiler/target/blaise
|
|
----
|
|
|
|
=== Run tests
|
|
|
|
[source,shell]
|
|
----
|
|
pasbuild test -m blaise-compiler --compiler compiler/target/blaise
|
|
----
|
|
|
|
=== Verify self-hosting fixpoint
|
|
|
|
After any compiler change, verify that the compiler reproduces itself:
|
|
|
|
[source,shell]
|
|
----
|
|
./scripts/fixpoint.sh
|
|
----
|
|
|
|
This generates stage-2 and stage-3 IR and confirms they are identical.
|
|
|
|
=== Running the compiler
|
|
|
|
Once built, the compiler binary is at `compiler/target/blaise`.
|
|
|
|
[source,shell]
|
|
----
|
|
# Compile a single-file program (native backend — default, no external tools)
|
|
compiler/target/blaise --source Hello.pas --output Hello
|
|
|
|
# Compile via the opt-in QBE backend (emits QBE IR, assembled + linked separately)
|
|
compiler/target/blaise --source Hello.pas --backend qbe --emit-ir > Hello.ssa
|
|
vendor/qbe/qbe -o Hello.s Hello.ssa
|
|
gcc -o Hello Hello.s compiler/target/blaise_rtl.a
|
|
|
|
# Compile with unit search paths
|
|
compiler/target/blaise --source MyApp.pas \
|
|
--unit-path src/units \
|
|
--emit-ir > MyApp.ssa
|
|
|
|
# Emit QBE IR only (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.*
|