A community-driven compiler fork that explores the modern language features the official compiler chose not to adopt. Upstream is deliberately conservative - this fork is where the experimental ideas get to run.
Everything turns on with one line:
{$mode unleashed}The mode is based on objfpc, and every feature can also be enabled one by one with {$modeswitch X}. Backward compatibility is the one hard rule: existing Pascal code keeps compiling untouched.
program taste;
{$mode unleashed}
uses Classes, SysUtils;
// statement expression: if as a value
function fib(n: integer): int64;
begin
result := if n < 2 then n else fib(n-1)+fib(n-2);
end;
// tuple return type
function minMax(const a: array of integer): (lo, hi: integer);
begin
result := (a[0], a[0]);
for var v in a do begin // inline loop variable
if v < result.lo then result.lo := v;
if v > result.hi then result.hi := v;
end;
end;
var hits: integer;
begin
var nums := [34, 7, 23, 32, 5, 62]; // inferred array of LongInt
var (lo, hi) := minMax(nums); // tuple destructuring
writeln($'min = {lo}, max = {hi}'); // string interpolation
var f := async fib(32); // background thread, one keyword
for parallel var i := 1 to 1000 do // loop body across all cores
if fib(15) = 610 then lock(hits) do hits += 1; // zero-setup critical section
writeln($'fib(32) = {await f}, hits = {hits}');
var log := autofree TStringList.Create; // freed at scope exit, no finally
log.Add($'finished at {Now:hh:nn:ss}');
write(log.Text);
end.Every feature has a full reference page with the complete grammar, semantics, edge cases, IDE notes and a runnable demo. Start at the documentation index.
One thread per call, one join per result. No event loop, no function coloring.
var f := async fetch(url); // runs on its own thread
prepareUI; // meanwhile, here
writeln(await f); // joins, result cached
f.Cancel; // futures have a control surfaceThe loop body runs across a worker pool, and the loop is a barrier.
for parallel(4) var i := 1 to 1_000_000 do
partial[WorkerIndex] += 1.0/(double(i)*i);
// control reaches this line only after every iteration is doneA critical section without the section: init, enter, release and done are implied.
lock(total) do total += n;
trylock(cache) wait 50 do
cache.Add(item)
else
queue.Add(item);Declare where you first need it, with the type inferred and block scope.
var count := 0; // integer, inferred
var names: array of string;
for var line in lines do
if line <> '' then count += 1;if, case and try yield a value, computed where it is consumed.
var kind := if size > 1024 then 'big' else 'small';
var port := try StrToInt(cfg) except 8080;
var msg := case level of 0: 'off'; 1: 'warn'; else 'all'; end;First-match dispatch over strings, ranges, tuples and bare conditions.
match cmd of
'start', 'go': run;
'stop': halt;
_: writeln($'unknown command: {cmd}');
end;Anonymous record types in parentheses, with literals and destructuring.
function split(s: string): (head, tail: string);
begin
exit(copy(s, 1, 1), copy(s, 2, length(s)));
end;
var (first, rest) := split('unleashed');Placeholders are type-checked and concatenated at compile time.
writeln($'user {name} has {count} items');
writeln($'{done/total:%.1f}% at {Now:hh:nn:ss}');defer and autofree replace the try..finally boilerplate.
var list := autofree TStringList.Create; // freed at scope exit
defer CloseFile(f); // fires in LIFO order
with var http := autofree THTTPClient.Create do
http.Get(url);C-struct layout control with Pascal type safety.
type
TPacket = record
embed THeader; // fields flattened into this record
union
raw: array[4] of byte;
value: dword;
end;
flags: byte bitsize 3;
end;A property with no accessors synthesizes its backing field, at zero cost.
type
TUser = class
property Name: string;
property Age: integer = 18; // seeded at construction
property Id: int64 readonly;
end;Backtick literals keep every byte, triple quotes strip the indentation.
const query = '''
select id, name
from users
where active = 1
''';
const banner = `+------+
| menu |
+------+`;Smaller unlocks, layout control and compiler switches - one page each.
A self-contained GUI installer for Windows and Linux. It downloads the sources, builds the compiler and the IDE into a directory of your choice, optionally installs cross compilers, and drops a desktop shortcut wired to a per-install IDE config. No PATH changes, no registry side effects, no overwriting of an existing compiler install - the whole thing lives in one folder and can be removed by deleting that folder.
Cross targets are checkboxes: x86_64-win64, x86_64-linux, i386-win32, i386-linux, wasm32-wasip1. The compiler and the IDE can be pinned to a branch or to a specific commit instead of taking the latest.
Re-runs are surgical: unchanged parts self-skip, a newly ticked cross target gets built, an unticked one gets removed, and toggling an addon rebuilds just the IDE.
Supported out of the box, nothing to configure. Download fpcupdeluxe, untick GitLab, and pick unleashed.git as the compiler version and the Lazarus version. From there it behaves like any regular install: compiler only, Lazarus only, or both at once, with cross compilers on the Cross tab.
For the best experience use the Unleashed Pascal IDE, a fork of the Lazarus IDE that understands unleashed mode end to end. Its parser, code completion and Code Insight know the new syntax, so inline vars, tuples, match, async / await and the rest autocomplete and navigate like any built-in construct, with no false-positive error markers in the editor.
Stock Lazarus still builds and runs Unleashed projects fine, but its Code Insight does not recognize the new syntax and will flag it as errors. On stock Lazarus enable the mode through -Munleashed in the project's Custom Options rather than {$mode unleashed} in the source - that keeps the background parser quieter about the constructs it cannot model.
Unleashed Pascal is a home for innovation. If you have built a language feature that did not find a home upstream, this is where it belongs.
Wanted: new language ideas - modeswitches, syntax extensions, compiler enhancements, proposed through GitHub Issues or Discussions; a well-described idea with clear use cases is valuable even without an implementation. And complete, high-quality implementations with production-grade code, test coverage and documentation.
Not wanted: minor convenience patches, trivial reformats, or tweaks that only scratch a personal itch. Every change to a compiler carries weight.