Skip to content

πŸ•ŠοΈPax is a minimal systems programming language emphasizing simplicity and self-containment. Pascal/Oberon heritage with modern conveniences: managed strings, automatic memory management, and zero external dependencies.

License

Notifications You must be signed in to change notification settings

tinyBigGAMES/PaxLang

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pax

Discord Follow on Bluesky

A minimal systems programming language that compiles to native executables via C99.

What is Pax?

The Pax Programming Language is a Pascal/Oberon-inspired systems programming language targeting Win64. It compiles to C via TinyCC with a completely self-contained toolchain - no external dependencies required. Memory is automatically managed via the Boehm-Demers-Weiser Garbage Collector. Configuration is handled through TOML files powered by DX.TOML, providing a clean, readable format for build settings, C header import definitions, and general-purpose application configuration.

module exe HelloWorld;

routine printf(const fmt: pointer to char; ...): int32; external 'msvcrt.dll';

var
  name: string;

begin
  name := 'Pax';
  printf('Hello from %s!\n', pointer to char(name));
  printf('GC heap: %lld bytes\n', gc_heapsize());
end.

✨ Key Features

  • 🎯 Minimal by design - Clean syntax, no redundancy, just what you need
  • πŸ“– Pascal heritage - Readable, structured code inspired by Pascal and Oberon
  • 🧹 Automatic memory - Boehm GC handles allocation and cleanup
  • πŸ“¦ Self-contained - Embedded TinyCC toolchain, single executable distribution
  • πŸͺŸ Windows native - Call any DLL directly, full Windows API access
  • πŸŽ›οΈ Multiple outputs - Build executables, DLLs, or static libraries
  • ⚑ JIT compilation - Compile and execute code in memory without generating files
  • 🧬 Type extension - Record inheritance without class complexity
  • πŸ›οΈ Classes - Methods, inheritance, and virtual dispatch
  • πŸ”€ Union types - C-compatible unions with anonymous nesting
  • πŸ“Š Dynamic arrays - setlength/len with automatic memory management
  • πŸ“ Managed strings - UTF-8 and UTF-16 string types with emoji support
  • πŸ”Œ Varargs support - Full C interop with printf-style functions
  • πŸ§ͺ Built-in testing - Integrated unit test framework
  • ⚠️ Exception handling - try/except/finally with OS exception support
  • 🏷️ Version info - Embed metadata and icons in executables
  • πŸ”„ C header import - Convert C headers to Pax modules automatically
  • βš™οΈ TOML configuration - General-purpose configuration file support

πŸ“˜ Language Overview

Built-in Types

Type Size Description
int8, int16, int32, int64 1-8 bytes Signed integers
uint8, uint16, uint32, uint64 1-8 bytes Unsigned integers
float32, float64 4-8 bytes Floating point
boolean 1 byte true / false
char, uchar 1 byte Signed/unsigned characters
wchar, uwchar 2 bytes Wide characters (UTF-16)
string, wstring 8 bytes Managed strings (UTF-8 / UTF-16)
pointer, pointer to T 8 bytes Untyped / typed pointers

Module Types

Type Description
module exe Name Executable program
module lib Name Static library (.a)
module dll Name Dynamic library (.dll)
module jit Name JIT compilation (compile and run in memory)

Operators

Arithmetic and Comparison

+ - * /           // Arithmetic
div mod           // Integer division and modulo
= <> < > <= >=    // Comparison
and or not        // Logical
in                // Set membership

Compound Assignment

var
  n: int32;
  s: string;
  days: set of 0..6;

begin
  n := 10;
  n += 5;         // n = n + 5
  n -= 3;         // n = n - 3
  n *= 2;         // n = n * 2
  n /= 4;         // n = n / 4 (integer division)
  
  s := 'Hello';
  s += ' World';  // String concatenation
  
  days := {1, 2};
  days += {3};    // Set union
  days -= {1};    // Set difference
end.

Type Aliases

type
  THandle = uint64;
  TSize = int64;
  TFileHandle = THandle;  // Alias of alias
  
var
  h: THandle;
  fh: TFileHandle;

begin
  h := 12345;
  fh := h;        // Compatible assignment
end.

Records and Extension

type
  TPoint = record
    x: int32;
    y: int32;
  end;

  TColorPoint = record(TPoint)  // Inherits from TPoint
    color: uint32;
  end;

var
  p: TColorPoint;

begin
  p.x := 100;         // Inherited from TPoint
  p.y := 200;         // Inherited from TPoint
  p.color := $FF0000;
end.

Classes

Classes provide object-oriented programming with methods and virtual dispatch:

type
  TCounter = class
    Count: int32;
    Name: string;
    
    method Reset();
    begin
      Self.Count := 0;
    end;
    
    method Increment();
    begin
      Self.Count := Self.Count + 1;
    end;
    
    method GetCount(): int32;
    begin
      return Self.Count;
    end;
  end;

var
  counter: pointer to TCounter;

begin
  new(counter);
  counter.Reset();
  counter.Increment();
  printf('Count: %d\n', counter.GetCount());  // Count: 1
  dispose(counter);
end.

Inheritance and Parent Calls

Classes support single inheritance with method overriding:

type
  TAnimal = class
    method Speak();
    begin
      printf('Animal speaks\n');
    end;
  end;
  
  TDog = class(TAnimal)
    method Speak();
    begin
      parent.Speak();        // Call parent's implementation
      printf('Dog barks!\n');
    end;
  end;

var
  dog: pointer to TDog;

begin
  new(dog);
  dog.Speak();  // Prints: Animal speaks / Dog barks!
end.

Key features:

  • Self references the current instance
  • parent calls the parent class's implementation (non-virtual dispatch)
  • Method calls on instances use virtual dispatch via automatic vtable
  • Fields are inherited from parent classes

Packed Records and Alignment

type
  // Packed record - no padding between fields
  THeader = record packed
    magic: uint16;
    version: uint8;
    flags: uint8;
  end;

  // Explicit alignment for SIMD or cache optimization
  TAlignedData = record align(16)
    values: array[0..3] of float32;
  end;

  // Bit fields for compact storage
  TFlags = record packed
    enabled: uint8 : 1;   // 1 bit
    priority: uint8 : 3;  // 3 bits
    reserved: uint8 : 4;  // 4 bits
  end;

Union Types

type
  // All fields share the same memory location
  TValue = union
    asInt: int64;
    asFloat: float64;
    asPtr: pointer;
  end;

  // Record with anonymous union (C-style variant)
  TVariant = record
    kind: int32;
    union
      intVal: int64;
      floatVal: float64;
      strVal: pointer to char;
    end;
  end;

Dynamic Arrays

var
  numbers: array of int32;
  i: int32;

begin
  setlength(numbers, 10);
  
  for i := 0 to len(numbers) - 1 do
    numbers[i] := i * 2;
  end;
end.

Open Array Parameters

Routines can accept dynamic arrays as parameters:

// Const array parameter (read-only)
routine SumArray(const arr: array of int32): int32;
var
  i: int32;
  total: int32;
begin
  total := 0;
  for i := 0 to len(arr) - 1 do
    total := total + arr[i];
  end;
  return total;
end;

// Var array parameter (can modify)
routine FillArray(var arr: array of int32; const value: int32);
var
  i: int32;
begin
  for i := 0 to len(arr) - 1 do
    arr[i] := value;
  end;
end;

var
  nums: array of int32;
  sum: int32;

begin
  setlength(nums, 5);
  FillArray(nums, 10);      // Fill with 10s
  sum := SumArray(nums);    // sum = 50
end.

Sets

type
  TDays = set of 0..6;

var
  weekdays: TDays;
  weekend: TDays;
  alldays: TDays;
  today: int32;

begin
  weekdays := {1, 2, 3, 4, 5};  // Mon-Fri
  weekend := {0, 6};            // Sun, Sat
  
  alldays := weekdays + weekend; // Union
  weekdays := alldays - weekend; // Difference
  
  today := 3;
  if today in weekdays then
    // It's a weekday
  end;
end.

Enumerations

type
  TColor = (
    clRed,
    clGreen,
    clBlue
  );

  TErrorCode = (
    Success = 0,
    NotFound = 404,
    ServerError = 500
  );
  
  TPriority = (
    Low,           // 0 (auto)
    Medium = 5,    // 5 (explicit)
    High,          // 6 (auto continues)
    Critical = 10  // 10 (explicit)
  );

var
  color: TColor;
  err: TErrorCode;
  priority: TPriority;
  val: int32;

begin
  color := clGreen;
  err := NotFound;
  
  // Enum comparison
  if priority > Low then
    // Higher priority
  end;
  
  // Enum in case statement
  case err of
    Success:
      printf('OK\n');
    NotFound:
      printf('Not found\n');
    ServerError:
      printf('Server error\n');
  end;
  
  // Enum to integer cast
  val := int32(color);  // val = 1 (clGreen)
  
  // Integer to enum cast
  color := TColor(2);   // color = clBlue
end.

Control Flow

var
  i: int32;
  sum: int32;
  n: int32;
  ch: char;

begin
  // If-then-else
  if n > 10 then
    sum := 1;
  else
    sum := 0;
  end;
  
  // While loop
  while i < 10 do
    i := i + 1;
  end;
  
  // For loop (ascending)
  for i := 1 to 10 do
    sum := sum + i;
  end;
  
  // For loop (descending)
  for i := 10 downto 1 do
    sum := sum + i;
  end;
  
  // Repeat-until
  repeat
    i := i + 1;
  until i >= 10;
  
  // Case statement with ranges
  case n of
    0: sum := 0;
    1..10: sum := 1;
    11..100: sum := 2;
  else
    sum := -1;
  end;
  
  // Case with character ranges
  case ch of
    'a'..'z': sum := 1;
    'A'..'Z': sum := 2;
    '0'..'9': sum := 3;
  else
    sum := 0;
  end;
end.

Exception Handling

Pax provides structured exception handling using try/except/finally blocks. Both software exceptions (raised by your code) and OS exceptions (access violations, divide by zero) are caught.

var
  result: int32;

begin
  // Basic try-except
  try
    raiseexception('Something went wrong');
    result := 1;  // Never reached
  except
    result := 0;  // Exception caught
  end;
  
  // Try-finally (cleanup always runs)
  try
    result := DoSomething();
  finally
    Cleanup();  // Always executes
  end;
  
  // Try-except-finally combined
  try
    riskyOperation();
  except
    handleError();
  finally
    cleanup();  // Runs whether exception occurred or not
  end;
end.

Raising Exceptions

begin
  // Raise with message (code defaults to 1)
  raiseexception('File not found');
  
  // Raise with custom code and message
  raiseexceptioncode(404, 'Resource not found');
end.

Exception Intrinsics

begin
  try
    raiseexceptioncode(42, 'Custom error');
  except
    printf('Code: %d\n', getexceptioncode());     // 42
    printf('Message: %s\n', pointer to char(getexceptionmessage()));  // Custom error
  end;
end.

Catching OS Exceptions

OS-level exceptions are automatically caught via Windows Vectored Exception Handling:

var
  p: pointer to int32;
  a, b, c: int32;

begin
  // Null pointer dereference
  try
    p := nil;
    p^ := 42;  // Access violation!
  except
    printf('Caught: 0x%08X\n', getexceptioncode());  // 0xC0000005
  end;
  
  // Integer divide by zero
  try
    a := 10;
    b := 0;
    c := a div b;  // Divide by zero!
  except
    printf('Caught: 0x%08X\n', getexceptioncode());  // 0xC0000094
  end;
end.

Common Exception Codes

Code Description
1 Default software exception
0xC0000005 Access violation (null pointer, invalid memory)
0xC0000094 Integer divide by zero
0xC0000095 Integer overflow
0xC00000FD Stack overflow

Routine Types (Function Pointers)

type
  TIntFunc = routine(const a: int32; const b: int32): int32;
  TCallback = routine(const x: int32): int32;

routine Add(const a: int32; const b: int32): int32;
begin
  return a + b;
end;

routine Multiply(const a: int32; const b: int32): int32;
begin
  return a * b;
end;

// Higher-order function
routine Apply(const fn: TIntFunc; const x: int32; const y: int32): int32;
begin
  return fn(x, y);
end;

var
  mathOp: TIntFunc;
  result: int32;

begin
  mathOp := Add;
  result := mathOp(10, 5);     // 15
  
  mathOp := Multiply;
  result := mathOp(10, 5);     // 50
  
  result := Apply(Add, 3, 4);  // 7
end.

Strings and Raw Strings

var
  path: string;
  msg: wstring;

begin
  // Normal strings - backslashes are escape characters
  path := 'C:\\Users\\Name\\file.txt';
  
  // Raw strings - no escape processing (great for paths)
  path := @'C:\Users\Name\file.txt';
  
  // Wide strings for Windows API (UTF-16)
  msg := L'Hello World!';
  
  // Raw wide strings
  msg := @L'C:\Path\To\File';
end.

String Literal Concatenation

String literals can be concatenated with the + operator:

var
  path: string;
  wide: wstring;

begin
  // Raw string + regular string
  path := @'C:\Users\' + 'Admin';
  
  // Wide string concatenation
  wide := L'Hello' + L'World';
  
  // Raw wide + regular wide
  wide := @L'C:\Path\' + L'File';
end.

Pointers and Const Pointers

routine wprintf(const fmt: pointer to const wchar; ...): int32; external 'msvcrt.dll';

var
  value: int32;
  ptr: pointer to int32;
  constPtr: pointer to const char;

begin
  value := 42;
  ptr := address of value;  // Get pointer to value
  ptr^ := 100;              // Dereference and assign
  // value is now 100
end.

External Routines

Call Windows DLL functions with simple declarations - no binding libraries required:

module exe WinAPI;

routine MessageBoxW(hwnd: pointer; text: pointer to wchar; 
  caption: pointer to wchar; utype: uint32): int32; external 'user32.dll';

begin
  MessageBoxW(nil, L'Hello from Pax!', L'Pax', 0);
end.

Linking Libraries

For custom DLLs or when linking multiple functions from the same library, use #library:

module exe CustomDLL;

#library 'mylib'

// Routines declared without DLL name - linked via #library
routine MyFunction(const value: int32): int32; external;
routine MyOtherFunction(const msg: pointer to char); external;

begin
  MyOtherFunction('Hello');
end.

GC Intrinsics

begin
  // Force garbage collection
  gc_collect();
  
  // Query heap statistics
  printf('Heap size: %lld bytes\n', gc_heapsize());
  printf('Used: %lld bytes\n', gc_usedsize());
  printf('GC cycles: %lld\n', gc_collectcount());
  
  // Dump detailed GC stats (debug builds)
  gc_dump();
end.

Command Line Arguments

var
  i: int32;
  arg: string;

begin
  printf('Arguments: %d\n', paramcount());
  
  for i := 0 to paramcount() do
    arg := paramstr(i);
    printf('  [%d] %s\n', i, pointer to char(arg));
  end;
end.

Conditional Compilation

#define DEBUG
#define VERSION 100

begin
  #ifdef DEBUG
  printf('Debug mode enabled\n');
  #endif
  
  #ifndef RELEASE
  printf('Not a release build\n');
  #endif
  
  #if VERSION >= 100
  printf('Version 100 or higher\n');
  #elif VERSION >= 50
  printf('Version 50-99\n');
  #else
  printf('Old version\n');
  #endif
  
  #undef DEBUG
end.

PAX Compiler Constants

begin
  // Available as both preprocessor macros and runtime constants
  printf('Pax version: %s\n', PAX_VERSION_STR);
  printf('Major: %d\n', PAX_MAJOR_VERSION);
  printf('Minor: %d\n', PAX_MINOR_VERSION);
  printf('Patch: %d\n', PAX_PATCH_VERSION);
  printf('Combined: %d\n', PAX_VERSION);
  
  // Preprocessor detection
  #ifdef PAX
  printf('Compiled with Pax\n');
  #endif
end.

Unit Testing

module exe MyTests;

#unittestmode on

routine Add(const a: int32; const b: int32): int32;
begin
  return a + b;
end;

routine IsPositive(const a: int32): boolean;
begin
  return a > 0;
end;

begin
  // Normal entry point (skipped in test mode)
end.

test 'Addition works correctly'
begin
  TestAssertEqualInt(5, Add(2, 3));
  TestAssertEqualInt(0, Add(-1, 1));
end;

test 'Boolean assertions'
begin
  TestAssertTrue(IsPositive(5));
  TestAssertFalse(IsPositive(-5));
end;

test 'Pointer and allocation assertions'
var
  p: pointer to int32;
begin
  p := nil;
  TestAssertNil(p);
  
  new(p);
  TestAssertNotNil(p);
  p^ := 42;
  TestAssertEqualInt(42, p^);
end;

Version Info and Icons

module exe MyApp;

#subsystem gui
#addverinfo yes
#vimajor 1
#viminor 0
#vipatch 0
#viproductname 'My Application'
#videscription 'A sample Pax application'
#vicompanyname 'My Company'
#vicopyright 'Copyright 2025'
#exeicon @'assets\app.ico'

begin
  // Application code
end.

JIT Compilation

JIT modules compile and execute directly in memory without generating executable files. This is useful for scripting, rapid prototyping, or embedding Pax as a scripting language in applications.

module jit Calculator;

routine printf(const fmt: pointer to char; ...): int32; external 'msvcrt.dll';

var
  x: int32;
  y: int32;

begin
  x := 10;
  y := 20;
  printf('=== JIT Module ===\n');
  printf('x = %d, y = %d\n', x, y);
  printf('x + y = %d\n', x + y);
  printf('x * y = %d\n', x * y);
end.

JIT modules use the same language features as regular executables but run immediately after compilation. The paxrtl.dll runtime must be available in the host application's working directory.

πŸ“‹ Directives Reference

Build Directives

Directive Description
#subsystem console/gui PE subsystem (default: console)
#library 'name' Link a library
#librarypath 'path' Add library search path
#includepath 'path' Add C include path
#addfile 'file' Add .c, .obj, .lib, .dll to link
#modulepath 'path' Add module search path
#outputpath 'path' Set output directory
#generatedpath 'path' Set generated C files directory

Preprocessor Directives

Directive Description
#define SYM [value] Define preprocessor symbol
#undef SYM Undefine symbol
#ifdef SYM Conditional if defined
#ifndef SYM Conditional if not defined
#if expr Conditional expression
#elif expr Else if
#else Else branch
#endif End conditional

Compiler Directives

Directive Description
#debug Enable debug info (STABS format)
#unittestmode on/off Enable unit test mode
#maxerrors N Max errors before stopping
#option 'flag' Pass raw TCC option

Version Info Directives

Directive Description
#addverinfo yes/no Enable version info embedding
#vimajor N Major version number
#viminor N Minor version number
#vipatch N Patch version number
#viproductname 'name' Product name
#videscription 'desc' File description
#vifilename 'name' Original filename
#vicompanyname 'name' Company name
#vicopyright 'text' Copyright notice
#exeicon 'path' Executable icon

πŸ”§ C Header Importer

Pax includes a built-in C header importer that converts C headers into Pax module source code. It uses TCC for preprocessing (expanding macros, includes) then parses the result to generate Pax declarations.

Basic Usage

LImporter := TPaxCImporter.Create();
try
  LImporter.SetModuleName('sdl3');           // Output module name (sdl3.pax)
  LImporter.SetDllName('sdl3.dll');          // DLL to link against
  LImporter.SetOutputPath('libs/sdl3/src');  // Where to write output
  LImporter.AddIncludePath('libs/sdl3/include');
  LImporter.AddExcludedType('va_list');
  LImporter.SetHeader('libs/sdl3/include/sdl3/sdl.h');
  LImporter.Process();
finally
  LImporter.Free();
end;

Configuration Files

The importer supports TOML configuration files for repeatable builds:

// Save current settings to config file
LImporter.SaveConfig('libs/sdl3/sdl3.toml');

// Load settings from config file
LImporter.LoadConfig('libs/sdl3/sdl3.toml');
LImporter.Process();

TOML Config Format

[cimporter]
header = "libs/sdl3/include/sdl3/sdl.h"
module_name = "sdl3"
dll_name = "sdl3.dll"
output_path = "libs/sdl3/src"
include_paths = ["libs/sdl3/include"]
library_paths = ["libs/sdl3/bin"]
copy_dlls = ["libs/sdl3/bin/sdl3.dll"]
excluded_types = ["va_list", "__builtin_va_list", "MSG", "XEvent"]
excluded_functions = ["alloca"]

[[cimporter.insertions]]
target = "(* Forward declarations (opaque types) *)"
file = "libs/sdl3/src/sdl3_constants.txt"
position = "before"
occurrence = 1

Importer Methods

Method Description
SetHeader(filename) Set the C header file to import
SetModuleName(name) Set output module name (defaults to header name)
SetDllName(name) Set DLL name for external declarations
SetOutputPath(path) Set output directory for generated .pax file
AddIncludePath(path) Add C include search path
AddLibraryPath(path) Add library search path
AddCopyDLL(path) Add DLL to copy to output
AddExcludedType(name) Skip type during import
AddExcludedFunction(name) Skip function during import
InsertTextBefore(target, text) Insert text before target line
InsertTextAfter(target, text) Insert text after target line
InsertFileBefore(target, file) Insert file content before target line
InsertFileAfter(target, file) Insert file content after target line
LoadConfig(filename) Load settings from TOML file
SaveConfig(filename) Save settings to TOML file
Process() Run the import process
GetLastError() Get error message if Process() failed
Clear() Reset all settings

What Gets Imported

  • Structs, unions, and typedefs
  • Function declarations with varargs
  • Enumerations with explicit values
  • Pointer types and arrays
  • Forward declarations for opaque types
  • Packed records, alignment, and bit fields
  • Constants from #define (integers, floats, strings)
  • Typed constants from compound literals (e.g., raylib Color constants)

Importing Headers with Dependencies

When a C library depends on another (e.g., SDL3_image uses SDL3 types), the importer can generate proper module imports and qualified type references.

Example: Importing SDL3_image (depends on SDL3)

LImporter := TPaxCImporter.Create();
try
  // Basic settings
  LImporter.SetModuleName('sdl3_image');
  LImporter.SetDllName('sdl3_image.dll');
  LImporter.SetOutputPath('libs/sdl3_image/src');
  
  // Generate "import sdl3;" in output
  LImporter.AddModuleImport('sdl3');
  
  // Generate "#modulepath 'libs/sdl3/src'" so compiler can find sdl3.pax
  LImporter.AddModulePath('libs/sdl3/src');
  
  // Include paths - TCC needs both for preprocessing
  LImporter.AddIncludePath('libs/sdl3_image/include');
  LImporter.AddIncludePath('libs/sdl3/include', 'sdl3');  // Associate with sdl3 module
  
  // Source path - only generate output from SDL3_image headers
  LImporter.AddSourcePath('libs/sdl3_image/include');
  
  LImporter.SetHeader('libs/sdl3_image/include/sdl3_image/sdl_image.h');
  LImporter.Process();
finally
  LImporter.Free();
end;

How It Works:

  1. AddModuleImport('sdl3') - Generates import sdl3; at the top of the output module
  2. AddModulePath('libs/sdl3/src') - Generates #modulepath directive so the Pax compiler can locate sdl3.pax
  3. AddIncludePath(path, 'sdl3') - Associates the SDL3 include path with the sdl3 module name. Types from this path are automatically qualified (e.g., SDL_Surface becomes sdl3.SDL_Surface)
  4. AddSourcePath - Only headers in this path produce output. SDL3 headers are parsed for type information but not re-exported

Generated Output:

module lib sdl3_image;

import sdl3;

#modulepath 'libs/sdl3/src'

public type
  IMG_Animation = record
    frames: pointer to pointer to sdl3.SDL_Surface;  // Qualified!
    // ...
  end;

public routine IMG_LoadTexture(const Arenderer: pointer to sdl3.SDL_Renderer;
  const Afile: pointer to const char): pointer to sdl3.SDL_Texture; external 'sdl3_image.dll';

Current Limitations

Limitation Workaround
Function-like macros Manually add equivalent Pax routines
Expression macros (arithmetic/bitwise) Use InsertFileBefore() to inject constants from a text file
va_list types cause errors Use AddExcludedType('va_list') and similar
Platform-specific types (MSG, XEvent) Use AddExcludedType() to skip them
Inline functions Manually translate to Pax routines
Complex preprocessor conditionals Import may include/exclude based on TCC's platform detection

βš™οΈ TOML Configuration

Pax includes a general-purpose TOML configuration class that can be used for any configuration needs. It wraps the DX.TOML library with a simple, type-safe API.

Basic Usage

LConfig := TPaxConfig.Create();
try
  if LConfig.LoadFromFile('settings.toml') then
  begin
    // Read values with defaults
    LHost := LConfig.GetString('database.host', 'localhost');
    LPort := LConfig.GetInteger('database.port', 5432);
    LEnabled := LConfig.GetBoolean('database.enabled', True);
    
    // Read arrays
    LPaths := LConfig.GetStringArray('search.paths');
    
    // Check if key exists
    if LConfig.HasKey('database.timeout') then
      LTimeout := LConfig.GetInteger('database.timeout');
    
    // Modify and save
    LConfig.SetString('database.host', 'newhost');
    LConfig.SetInteger('database.port', 3306);
    LConfig.SaveToFile('settings.toml');
  end;
finally
  LConfig.Free();
end;

Supported Types

Method Description
GetString / SetString String values
GetInteger / SetInteger Int64 values
GetFloat / SetFloat Double values
GetBoolean / SetBoolean Boolean values
GetDateTime / SetDateTime TDateTime values
GetStringArray / SetStringArray Array of strings
GetIntegerArray / SetIntegerArray Array of Int64
GetFloatArray / SetFloatArray Array of Double

Arrays of Tables

For TOML arrays of tables (e.g., [[items]]):

// Get count of table entries
LCount := LConfig.GetTableCount('items');

// Read fields from each table
for LI := 0 to LCount - 1 do
begin
  LName := LConfig.GetTableString('items', LI, 'name', '');
  LValue := LConfig.GetTableInteger('items', LI, 'value', 0);
  LWeight := LConfig.GetTableFloat('items', LI, 'weight', 0.0);
  LActive := LConfig.GetTableBoolean('items', LI, 'active', False);
end;

Key Path Notation

Keys use dot notation to access nested tables:

[database]
host = "localhost"
port = 5432

[database.connection]
timeout = 30
retries = 3
LHost := LConfig.GetString('database.host');
LTimeout := LConfig.GetInteger('database.connection.timeout');

πŸ—οΈ Architecture

The compiler is built in Delphi with a clean pipeline architecture:

Unit Purpose
Pax.Lexer Tokenization with full Unicode support
Pax.AST Abstract syntax tree node definitions
Pax.Parser Recursive descent parser with error recovery
Pax.Types Type registry and type system management
Pax.Symbols Symbol table with scope management
Pax.Checker Semantic analysis and type checking
Pax.CodeGen C99 code generation
Pax.Compiler Build orchestration and TinyCC integration

Additional Components

Unit Purpose
Pax.ArArchive Native AR archive creation for static libraries
Pax.ZipVFS Virtual file system for embedded toolchain
Pax.IATHook IAT hooking for transparent file redirection
Pax.LibTCC TinyCC (libtcc) integration
Pax.ModuleLoader Module dependency resolution
Pax.Errors Error types, codes, and diagnostic formatting
Pax.CImporter C header to Pax module converter
Pax.Config General-purpose TOML configuration management
Pax.Utils Utility functions and console helpers
Pax.Resources Localized error messages and resource strings

πŸ“Š Status

Under active development.

The core compiler is functional and can produce working executables, DLLs, and static libraries. All major language features are implemented:

  • Records with inheritance
  • Classes with methods and virtual dispatch
  • Unions (named and anonymous)
  • Packed records and alignment
  • Bit fields
  • Dynamic arrays
  • Sets with ranges and operations
  • Managed strings (UTF-8/UTF-16)
  • External DLL calls with varargs
  • Module system with imports
  • Unit testing framework
  • GC intrinsics
  • Version info embedding
  • Icon embedding
  • Type aliases
  • Routine types (function pointers)
  • Compound assignment operators
  • Case statement ranges
  • Conditional compilation
  • PAX compiler constants
  • Enumeration types
  • Exception handling (try/except/finally)
  • JIT compilation (compile and run in memory)
  • C header importer with TOML config
  • General-purpose TOML configuration

πŸ”¨ Building

Get the Source

Option 1: Download ZIP

Option 2: Git Clone

git clone https://github.com/tinyBigGAMES/PaxLang.git

Compile

  1. Open src\Pax Programming Language.groupproj in Delphi
  2. Build the project

That's it! Everything is included - TinyCC, Boehm GC, and runtime resources are already bundled in the repo. The compiled executable will be output to the bin folder.

πŸ’» Command Line Interface

The pax command line tool provides everything you need to create, build, and run Pax projects.

Usage

pax <COMMAND> [OPTIONS]

Commands

Command Description
init <name> [type] Create a new Pax project
build Compile the project
run Build and execute the program
clean Remove all generated files
version Display version information
help Display help message

Creating a Project

# Create an executable project (default)
pax init MyGame

# Create a static library
pax init MyLib lib

# Create a shared library (DLL)
pax init MyPlugin dll

This creates a project folder with the following structure:

MyGame/
β”œβ”€β”€ src/
β”‚   └── MyGame.pax    # Main source file
└── pax.toml          # Project configuration

Project Types

Type Description Output
exe Executable program (default) .exe
lib Static library .a
dll Shared library .dll

Building and Running

# Navigate to project folder
cd MyGame

# Build the project
pax build

# Build and run
pax run

# Clean generated files
pax clean

Project Configuration (pax.toml)

The pax.toml file stores all project settings:

[pax]
signature = "PAX-7F3A9B2C-E1D5-4A8F-B6C2-9D0E3F7A1B5C"
version = "1"
compiler = "0.1.0"
last_build = "2025-01-01T12:00:00.000Z"

[build]
mainsourcefile = "src\\MyGame.pax"
outputpath = "."
modulename = "MyGame"
buildtype = "exe"
subsystem = "console"
unittestmode = false
debugmode = false
verbose = false
maxerrors = 100

[paths]
modulepaths = []
includepaths = []
librarypaths = []

[tccoptions]
options = []

[versioninfo]
enabled = false
major = 0
minor = 0
patch = 0
productname = ""
description = ""
filename = ""
companyname = ""
copyright = ""

[resources]
exeicon = ""

Build Output Structure

After building, the project folder contains:

MyGame/
β”œβ”€β”€ src/
β”‚   └── MyGame.pax
β”œβ”€β”€ generated/           # Generated C code
β”‚   β”œβ”€β”€ MyGame.c
β”‚   └── MyGame.h
β”œβ”€β”€ out/
β”‚   └── bin/             # Compiled output
β”‚       β”œβ”€β”€ MyGame.exe
β”‚       └── paxrtl.dll   # Runtime library
└── pax.toml

Example Workflow

# Create a new project
pax init HelloWorld

# Edit the source (src/HelloWorld.pax)
cd HelloWorld

# Build and run
pax run

# Output:
# Hello from Pax!

Generated Template (exe)

(*
  HelloWorld - Pax EXE
*)

module exe HelloWorld;

routine printf(const fmt: pointer to const char; ...): int32; external 'msvcrt.dll';

begin
  printf('Hello from Pax!\n');
end.

πŸ“‹ Requirements

Minimum Tested
Platform Windows 10 x64 Windows 11 25H2 x64
Build Delphi 11 (Alexandria) Delphi 12 (Athens)

Dependencies: None for end users - TinyCC and Boehm GC are embedded.

🀝 Contributing

Contributions are welcome! Join our Discord to discuss development.

πŸ“„ License

Pax is licensed under the Apache License 2.0. See LICENSE for details.

πŸ”— Links


Paxβ„’ Programming Language.

Copyright Β© 2025-present tinyBigGAMESβ„’ LLC
All Rights Reserved.

About

πŸ•ŠοΈPax is a minimal systems programming language emphasizing simplicity and self-containment. Pascal/Oberon heritage with modern conveniences: managed strings, automatic memory management, and zero external dependencies.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project