Skip to content

🚀 JetPascal v0.2.0: Breaking Down the Wall

Latest

Choose a tag to compare

@jarroddavis68 jarroddavis68 released this 18 Nov 20:24

TL;DR

JetPascal v0.2.0 is the Pascal-to-C++ transpiler that breaks down the traditional barrier between Pascal and the C++ ecosystem. Mix Pascal and C++ freely, include headers directly, link libraries with a single directive, and access 40+ years of C++ libraries without writing wrapper code. Complete Pascal language support, built-in unit testing, cross-platform compilation, and a revolutionary smart token architecture.

🎯 The Game-Changing Feature

Zero-Friction C++ Ecosystem Access

For decades, Pascal developers faced a critical barrier: accessing C++ libraries required DLL wrappers, FFI bindings, and constant maintenance overhead. JetPascal eliminates this completely.

Unknown tokens = C++ - Don't recognize it? Emit it as C++
Direct header inclusion - #include_header '<vector>' brings C++ into scope
Unrestricted C++ blocks - #startcpp/#endcpp for ANY C++ code
Static library linking - #link 'raylib' - done
Seamless token mixing - Pascal and C++ in the same expression
No wrappers needed - Zero FFI overhead, zero binding maintenance

🔥 What's New in v0.2.0

The "Living in C++" Philosophy

JetPascal operates at the C++ boundary at all times:

  1. Pascal as Syntactic Sugar - Pascal transpiles to C++23
  2. Transparent Fallthrough - Unknown tokens emit as raw C++
  3. C++ Semantics - Leverage C++23 features for Pascal behavior
  4. Zero Overhead - No FFI, no marshaling, direct code generation

Example - Mixing Pascal and C++:

program MixedDemo;

#include_header '<cmath>'

var
  LValue: Integer;
  LResult: Double;

begin
  // Pure Pascal
  LValue := 10;
  WriteLn('Pascal: Value = ', LValue);
  
  // Pure C++ - std::cout is not a Pascal token, emitted as C++!
  std::cout << "C++: Hello!" << std::endl;
  
  // Mixed: Pascal WriteLn with C++ expression
  WriteLn('Square root: ', std::sqrt(16.0));
  
  // Mixed: C++ expression in Pascal assignment
  LResult := std::pow(2.0, 8.0);
  WriteLn('2^8 = ', LResult);
end.

This just works. No wrappers. No bindings. Pascal calls C++, C++ calls Pascal - seamlessly.

Unrestricted C++ Blocks - Complete Freedom

Need to write complex C++ code? Use #startcpp/#endcpp:

program AdvancedCpp;

#include_header '<vector>'
#include_header '<algorithm>'

var
  LSum: Integer;

begin
  LSum := 0;
  
  #startcpp
  // ANY C++ code - ZERO restrictions!
  std::vector<int> numbers = {5, 2, 8, 1, 9};
  
  // Sort with C++ STL
  std::sort(numbers.begin(), numbers.end());
  
  // Lambda expressions
  auto multiply = [](int a, int b) { return a * b; };
  std::cout << "10 * 5 = " << multiply(10, 5) << std::endl;
  
  // Calculate sum for Pascal variable
  for (const auto& n : numbers) {
    LSum += n;  // Modifying Pascal variable from C++!
  }
  
  // Range-based for
  std::cout << "Sorted: ";
  for (const auto& n : numbers) {
    std::cout << n << " ";
  }
  std::cout << std::endl;
  #endcpp
  
  WriteLn('Sum from C++: ', LSum);  // Using the value C++ calculated
end.

C++ lambdas. STL algorithms. Range-based loops. Templates. All available.

Static Library Linking - Single Executable Deployment

The raylib example that changes everything:

program RaylibGame;

#optimization releasesmall
#include_header '"raylib.h"'

#link 'raylib'
#link 'gdi32'
#link 'opengl32'
#link 'winmm'

begin
  InitWindow(800, 450, "JetPascal + raylib!");
  SetTargetFPS(60);
  
  while not WindowShouldClose() do
  begin
    BeginDrawing();
      ClearBackground(RAYWHITE);
      DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
    EndDrawing();
  end;
  
  CloseWindow();
end.

This is a complete, working game window that compiles to a single .exe with raylib statically linked!

  • ✅ No wrapper code
  • ✅ No DLL dependencies
  • ✅ Direct C++ function calls
  • ✅ Single-file deployment
  • ✅ Production-ready

Complete Pascal Language Support

All the Pascal features you expect:

Basic Types

var
  LInt: Integer;      // 32-bit signed
  LInt64: Int64;      // 64-bit signed
  LUInt: UInt64;      // 64-bit unsigned
  LCard: Cardinal;    // 32-bit unsigned
  LWord: Word;        // 16-bit unsigned
  LByte: Byte;        // 8-bit unsigned
  LBool: Boolean;     // Boolean
  LChar: Char;        // Character
  LSingle: Single;    // 32-bit float
  LDouble: Double;    // 64-bit float
  LStr: String;       // Unicode string

Pointers and Memory

var
  LPtr: PInteger;
  LValue: Integer;

begin
  // Allocate
  New(LPtr);
  LPtr^ := 42;
  WriteLn('Value: ', LPtr^);
  Dispose(LPtr);
  
  // Manual memory management
  GetMem(LPtr, SizeOf(Integer));
  LPtr^ := 100;
  WriteLn('Value: ', LPtr^);
  FreeMem(LPtr);
  
  // Zero-filled allocation
  LPtr := AllocMem(SizeOf(Integer));
  WriteLn('Zero-filled: ', LPtr^);
  FreeMem(LPtr);
end.

Arrays

type
  TStaticArray = array[1..10] of Integer;
  TNegativeIndex = array[-5..5] of Integer;
  TMatrix = array[1..3, 1..3] of Double;

var
  LArr: TStaticArray;
  LNeg: TNegativeIndex;
  LMatrix: TMatrix;

begin
  // Regular arrays
  LArr[5] := 100;
  
  // Negative indices work!
  LNeg[-3] := 42;
  LNeg[0] := 0;
  LNeg[3] := 42;
  
  // Multi-dimensional
  LMatrix[2, 3] := 3.14;
end.

Records

type
  TPoint = record
    X: Integer;
    Y: Integer;
  end;
  
  TPerson = record
    Name: String;
    Age: Integer;
  end;

var
  LPoint: TPoint;
  LPerson: TPerson;

begin
  LPoint.X := 10;
  LPoint.Y := 20;
  
  LPerson.Name := 'Alice';
  LPerson.Age := 30;
end.

Records map directly to C++ structs - no overhead, no translation.

Control Flow

var
  LI: Integer;

begin
  // If/then/else
  if LI > 0 then
    WriteLn('Positive')
  else if LI < 0 then
    WriteLn('Negative')
  else
    WriteLn('Zero');
  
  // For loops (to/downto)
  for LI := 1 to 10 do
    WriteLn(LI);
  
  for LI := 10 downto 1 do
    WriteLn(LI);
  
  // While loop
  while LI < 100 do
  begin
    Inc(LI);
    if LI = 50 then
      break;
  end;
  
  // Repeat/until
  repeat
    Dec(LI);
    if LI < 25 then
      continue;
    WriteLn(LI);
  until LI <= 0;
end.

Exception Handling

var
  LMsg: String;

begin
  try
    WriteLn('Before exception');
    RaiseException('Something went wrong!');
    WriteLn('After exception - not reached');
  except
    LMsg := GetExceptionMessage();
    WriteLn('Caught: ', LMsg);
  end;
  
  try
    WriteLn('In try block');
  finally
    WriteLn('Finally always executes');
  end;
end.

C++ exceptions under the hood - proper cleanup, proper unwinding.

Functions and Procedures

function Add(const A, B: Integer): Integer;
begin
  Result := A + B;
end;

procedure Swap(var A, B: Integer);
var
  LTemp: Integer;
begin
  LTemp := A;
  A := B;
  B := LTemp;
end;

function Factorial(const N: Integer): Integer;
begin
  if N <= 1 then
    Result := 1
  else
    Result := N * Factorial(N - 1);
end;

Units - Modular Programming

UnitMath.pas:

unit UnitMath;

interface

function Add(const A, B: Integer): Integer;
function Multiply(const A, B: Integer): Integer;

implementation

function Add(const A, B: Integer): Integer;
begin
  Result := A + B;
end;

function Multiply(const A, B: Integer): Integer;
begin
  Result := A * B;
end;

end.

Program.pas:

program MyApp;

uses
  UnitMath;

begin
  WriteLn('10 + 20 = ', Add(10, 20));
  WriteLn('10 * 20 = ', Multiply(10, 20));
end.

Built-in Unit Testing Framework

Professional testing built into the language:

#unittestmode on
program MathTests;

function Add(const A, B: Integer): Integer;
begin
  Result := A + B;
end;

function Multiply(const A, B: Integer): Integer;
begin
  Result := A * B;
end;

begin
  WriteLn('Main program');
end.

test 'Addition works correctly'
begin
  AssertEqual(4, Add(2, 2));
  AssertEqual(10, Add(7, 3));
  AssertEqual(-5, Add(-2, -3));
end;

test 'Multiplication works correctly'
begin
  AssertEqual(20, Multiply(4, 5));
  AssertEqual(0, Multiply(5, 0));
  AssertEqual(-15, Multiply(3, -5));
end;

Features:

  • #unittestmode on directive
  • test 'description' blocks
  • AssertEqual(expected, actual)
  • Assert(condition)
  • Integrated test runner
  • Clean output

Compiler Directives - Total Build Control

Everything configured in your Pascal source - no external build files:

program MyApp;

// Optimization
#optimization releasefast    // debug, releasesafe, releasefast, releasesmall

// Cross-compilation
#target x86_64-linux         // native, x86_64-windows, x86_64-linux, 
                              // aarch64-macos, aarch64-linux, wasm32-wasi

// Application type
#apptype gui                  // console, gui

// Search paths
#unit_path '../units'
#include_path '../include'
#library_path '../lib'

// C++ integration
#include_header '<vector>'
#include_header '"mylib.h"'
#link 'raylib'

// ABI control
#abi c                        // c, cpp

// Preprocessor
#define DEBUG
#ifdef DEBUG
  WriteLn('Debug mode');
#endif

begin
  // Your code
end.

Supported Targets:

  • native - Current platform
  • x86_64-windows - Windows 64-bit
  • x86_64-linux - Linux 64-bit
  • aarch64-macos - macOS ARM64 (Apple Silicon)
  • aarch64-linux - Linux ARM64
  • wasm32-wasi - WebAssembly (experimental)

Optimization Levels:

  • debug - Fast compile, full debug info
  • releasesafe - Optimized with safety checks
  • releasefast - Maximum speed
  • releasesmall - Minimum size

C++ Operators

var
  LValue: Integer;
  LX, LY: Integer;

begin
  // Compound assignment
  LValue := 10;
  LValue += 5;   // 15
  LValue -= 3;   // 12
  LValue *= 2;   // 24
  LValue /= 4;   // 6
  
  // Increment/decrement
  WriteLn(++LValue);  // Prefix: 7
  WriteLn(LValue++);  // Postfix: 7 (then becomes 8)
  WriteLn(--LValue);  // Prefix: 7
  WriteLn(LValue--);  // Postfix: 7 (then becomes 6)
  
  // Bitwise operations
  LX := 0b1100;
  LY := 0b1010;
  WriteLn(LX & LY);   // AND: 0b1000
  WriteLn(LX | LY);   // OR: 0b1110
  WriteLn(LX ^ LY);   // XOR: 0b0110
  WriteLn(~LX);       // NOT
  WriteLn(LX << 2);   // Shift left
  WriteLn(LX >> 1);   // Shift right
end.

System Functions

Built-in functions for common operations:

var
  LPtr: Pointer;
  LSize: Integer;
  LValue: Integer;

begin
  // Memory
  LPtr := AllocMem(100);       // Allocate zero-filled
  FreeMem(LPtr);               // Free memory
  GetMem(LPtr, 200);           // Allocate
  ReallocMem(LPtr, 300);       // Reallocate
  LSize := SizeOf(Integer);    // Size of type
  
  // Ordinal
  LValue := Ord('A');          // Get ordinal value
  Inc(LValue);                 // Increment
  Dec(LValue);                 // Decrement
  
  // Command line
  WriteLn('Arg count: ', ParamCount());
  WriteLn('Arg 1: ', ParamStr(1));
  
  // I/O
  WriteLn('Hello, World!');
  Write('No newline');
  WriteLn('Multiple ', 'arguments ', 123, ' ', 3.14);
  
  // Exceptions
  RaiseException('Error message');
  WriteLn(GetExceptionMessage());
end.

Full Conditional Compilation

Complete C++ preprocessor support:

program Conditionals;

#define VERSION 2
#define FEATURE_X

#ifdef FEATURE_X
  WriteLn('Feature X enabled');
#else
  WriteLn('Feature X disabled');
#endif

#if VERSION >= 2
  WriteLn('Version 2 or higher');
#endif

#ifndef FEATURE_Y
  WriteLn('Feature Y not defined');
#endif

#undef FEATURE_X

begin
  WriteLn('Conditional compilation works!');
end.

🏗️ Revolutionary Architecture

Smart Token System

JetPascal's architecture is fundamentally different from traditional compilers:

Traditional Compilers:

  • Monolithic parser
  • Giant switch statements
  • "God Object" antipattern
  • Hard to extend
  • Difficult to maintain

JetPascal's Smart Tokens:

  • Self-contained token objects
  • Each token handles its own parsing
  • Each token emits its own C++ code
  • Factory pattern for extensibility
  • Minimal core (150-200 lines)
  • Polymorphic dispatch

Adding a new feature:

  1. Create a new smart token class
  2. Register it in JetPascal.Setup.pas
  3. Done!

Example - Adding the Inc function required ONE line:

RegisterSmartToken('inc', TIncToken);

The TIncToken class handles everything:

  • Parsing the Inc(Variable) syntax
  • Validating parameters
  • Emitting C++ code ++Variable
  • Edge cases and error handling

"Just Works" Principle

New features integrate automatically with existing infrastructure:

Example: Adding records required ZERO changes to:

  • Variable declarations
  • Assignments
  • Field access
  • Function parameters

Why? Because Pascal record syntax maps directly to C++ struct syntax, and JetPascal "lives in C++".

100+ Smart Tokens

Current smart token categories:

System:

  • ParamCount, ParamStr
  • Ord, Inc, Dec
  • SizeOf

Memory:

  • New, Dispose
  • GetMem, FreeMem
  • AllocMem, ReallocMem

Types:

  • Integer, Int64, UInt64, Cardinal, Word, Byte
  • Boolean, Char
  • Single, Double
  • String
  • Arrays, Records, Pointers
  • Enumerations

Control Flow:

  • if, then, else
  • while, do
  • for, to, downto
  • repeat, until
  • break, continue

Exceptions:

  • try, except, finally
  • RaiseException
  • GetExceptionMessage

I/O:

  • WriteLn, Write

Directives:

  • All # directives (optimization, target, link, etc.)
  • All conditional compilation (#define, #ifdef, etc.)

Unit Testing:

  • #unittestmode
  • test blocks
  • Assert, AssertEqual

🎁 Zig Build System Integration

Everything self-contained - no external dependencies:

  • ✅ Zig toolchain included
  • ✅ Latest Clang/LLVM compiler
  • ✅ C++ standard library
  • ✅ Cross-compilation support
  • ✅ Optimized build pipeline
  • ✅ Static and dynamic linking
  • ✅ ~500MB installation - everything you need

Cross-compilation is trivial:

#target x86_64-linux

That's it. JetPascal + Zig handle everything else.

🚀 Getting Started

Installation

Requirements:

  • Windows 10 or later
  • ~500MB disk space
  • 2GB RAM minimum

Steps:

  1. Download latest release from GitHub
  2. Extract to folder (e.g., C:\Dev\JetPascal)
  3. Add bin to PATH
  4. Verify: jet version

Your First Program

jet init HelloWorld
cd HelloWorld
jet build
jet run

Real-World Example - raylib Game

jet init MyGame
cd MyGame

Edit src/MyGame.pas:

program MyGame;

#optimization releasesmall
#include_header '"raylib.h"'
#link 'raylib'
#link 'gdi32'
#link 'opengl32'
#link 'winmm'

begin
  InitWindow(800, 450, "My First Game!");
  SetTargetFPS(60);
  
  while not WindowShouldClose() do
  begin
    BeginDrawing();
      ClearBackground(RAYWHITE);
      DrawText("It just works!", 200, 200, 20, DARKGRAY);
    EndDrawing();
  end;
  
  CloseWindow();
end.
jet build
jet run

You just created a game window with raylib. Zero wrapper code. Zero bindings.

📚 CLI Reference

jet init <name> [--template <type>]  # Create project
jet build                             # Build current project
jet run                               # Run compiled program
jet clean                             # Remove build artifacts
jet zig <args>                        # Pass through to Zig
jet version                           # Show version
jet help                              # Show help

Project templates:

  • program (default) - Executable
  • library - Shared library (.dll/.so)
  • unit - Static library (.lib/.a)

💡 Why JetPascal Changes Everything

The Old Way (Traditional Pascal)

Want to use a C++ library?

  1. Find or create a C interface wrapper
  2. Write Pascal FFI bindings
  3. Maintain bindings when library updates
  4. Deal with marshaling overhead
  5. Handle DLL distribution
  6. Debug across language boundary

Result: Weeks of work, ongoing maintenance burden

The JetPascal Way

Want to use a C++ library?

  1. #include_header '"library.h"'
  2. #link 'library'
  3. Call functions directly

Result: Done. No wrappers. No bindings. No friction.

Real-World Impact

Before JetPascal:

  • Pascal developers isolated from C++ ecosystem
  • Raylib? Requires wrapper project
  • OpenCV? Custom bindings needed
  • Boost? Forget about it

With JetPascal:

  • Raylib? #include_header + #link - done
  • OpenCV? Same approach - works
  • Boost? Include and use - no problem

The entire C++ ecosystem is now accessible to Pascal developers.

🎯 The Bottom Line

JetPascal v0.2.0 breaks down the wall between Pascal and C++.

✅ Write Pascal syntax
✅ Include C++ headers
✅ Link C++ libraries
✅ Mix freely in same source
✅ No wrappers needed
✅ No FFI overhead
✅ No binding maintenance
✅ Complete Pascal language
✅ Built-in unit testing
✅ Cross-platform compilation
✅ Smart token architecture
✅ Everything self-contained

Build games. Build utilities. Build applications. Access the entire C++ universe.


📖 Documentation

Comprehensive docs available:

🌐 Community

🤝 Contributing

JetPascal is open source (BSD 3-Clause License). Contributions welcome!

🔮 What's Next?

JetPascal has the foundation for Pascal/C++ interop. What libraries do YOU want to use? Let us know!


Write Pascal. Access C++. Ship everywhere. 🚀

File Integrity

Files are signed with minisign using this public key:
RWTqBYfsUOCQscb6ZeknLC0On3cvWCVzMzlHamtgXNaDOO4bNs3WCSkV

Copyright © 2025-present tinyBigGAMES™ LLC. All Rights Reserved.