pascal 0.1.4

A modern Pascal compiler with build/intepreter/package manager built with Rust
Documentation

pascal-rs — A Modern Pascal Compiler & Interpreter in Rust

pascal-rs is a Pascal compiler, interpreter, and package manager written in Rust. It supports standard Pascal and a growing subset of Object Pascal (classes, exceptions, inheritance, virtual dispatch), with a modern cargo/npm-style build system (pascal.toml), backed by 228 automated tests and 10 runnable example programs.


Status

Metric Value
Tests 228 passing (127 unit + 101 integration)
Language Standard Pascal + Object Pascal subset
Interpreter Full-featured tree-walking execution
Compiler x86-64 assembly generation with optimizations
Build System pascal.toml manifest, dependency management, lock file
Edition Rust 2024

What's New

Object Pascal in the Interpreter

The interpreter now supports core Object Pascal features at the AST/runtime level:

  • ClassesValue::Object with field access, constructors, destructors, method dispatch
  • Inheritance — single inheritance with field/method merging
  • Virtual/Override — vtable-style dispatch via find_method_in_hierarchy
  • is / as — runtime type checks walking the inheritance chain
  • inherited — call parent class methods
  • Properties — read/write resolution infrastructure
  • Exceptionstry/except/finally, raise, on E: Type do matching, re-raise

Interpreter Enhancements

  • ArraysSetLength, indexing with bounds checking, high(), low(), length()
  • Records — field access and assignment via dot notation
  • String indexings[i] (1-indexed, Pascal style)
  • exit — early return from functions/procedures, with optional return value (exit(42))
  • break — loop termination
  • with statement — pushes object/record fields into scope
  • uses clause — loads and imports .pas unit files
  • Nested functions — proper scoping for functions declared inside functions

Build System & Package Manager

A modern cargo/npm-style project management system:

  • pascal init <name> — scaffold a new project with pascal.toml, src/, tests/, examples/
  • pascal build — compile all units in dependency order (topological sort)
  • pascal run — run the project's main program (or pascal run file.pas for single files)
  • pascal add <dep> — add a dependency (version, --path, or --git)
  • pascal remove <dep> — remove a dependency
  • pascal.toml — project manifest (package metadata, dependencies, build config)
  • pascal.lock — reproducible builds with SHA-256 checksums

Parser Improvements

  • Source location tracking — error messages now include at line N, column M
  • Error recoveryconsume_or_skip and synchronize for resilient parsing
  • exit/break tokens — properly parsed as statements (not silently skipped)

Bug Fixes

  • Recursive function scopingset_local_variable prevents recursive calls from clobbering parent scope return variables
  • exit inside if/begin..endEarlyReturn now propagates correctly through all control flow

10 Example Programs

Validated end-to-end (source → lexer → parser → interpreter):

# File Features
01 01_basics.pas Variables, arithmetic, if/else, while, for, repeat/until, case
02 02_functions.pas Factorial, Fibonacci, IsPrime, GCD, procedures
03 03_strings.pas Reverse, palindrome, char counting, copy, pos, upcase
04 04_arrays.pas SetLength, indexing, high/low/length
05 05_classes.pas Shape area calculations with functions
06 06_exceptions.pas try/except, try/finally, nested exceptions, raise
07 07_nested_functions.pas exit() with return values, early return patterns
08 08_math_algorithms.pas GCD, Collatz, digit sum, fast exponentiation
09 09_class_hierarchy.pas Polymorphic dispatch, string comparisons
10 10_comprehensive.pas Recursion, primes, strings, case, exceptions combined

Why pascal-rs?

Compared to Alternatives

pascal-rs Free Pascal (FPC) Delphi GNU Pascal
Implementation language Rust (memory-safe) Object Pascal/C C++ C
Interpreter mode Built-in tree-walker No No No
Package manager Built-in (pascal.toml) No No No
Test suite 228 automated tests Large but external Proprietary Minimal
Object Pascal Subset (classes, exceptions, virtual) Full Full Partial
Trait-based design Yes — testable, extensible No No No
Error messages Line/column, colored Basic Good Basic
x86-64 codegen Yes, with optimizations Mature, multi-target Mature Basic
Active Yes Yes Yes No (2006)
Cross-platform Yes (Rust targets) Yes Windows-focused Yes
License Apache-2.0 LGPL Commercial GPL

When to Use pascal-rs

  • Learning compiler construction — clean Rust codebase, trait-based architecture, well-tested
  • Running Pascal programs quicklypascal run program.pas with no assembly/linking step
  • Research & experimentation — easy to extend with new optimizations or language features
  • Small projects & algorithms — full standard Pascal with functions, recursion, strings, arrays

When to Use Something Else

  • Large production codebases — FPC or Delphi have decades of maturity
  • Full Delphi compatibility — pascal-rs covers a subset of Object Pascal
  • GUI applications — FPC/Lazarus or Delphi have mature widget libraries
  • Multi-target compilation — FPC supports ARM, MIPS, PowerPC, WebAssembly, etc.

Quick Start

Installation

git clone https://github.com/yingkitw/pascal-rs.git
cd pascal-rs
cargo build --release

Create a Project

# Scaffold a new project
./target/release/pascal init myapp
cd myapp

# Build all units in dependency order
./target/release/pascal build

# Run the project
./target/release/pascal run

This creates:

myapp/
├── pascal.toml          # Project manifest
├── src/
│   └── myapp.pas        # Main program
├── tests/
├── examples/
├── .gitignore
└── README.md

Run a Single File

# Interpret directly (no project needed)
./target/release/pascal run examples/01_basics.pas

# Compile to x86-64 assembly
./target/release/pascal compile examples/01_basics.pas -S

Run All Tests

cargo test
test result: ok. 228 passed; 0 failed; 0 ignored

Usage

Commands

Command Description Example
init Create a new project pascal init myapp
build Build the current project pascal build
run Run a program or project pascal run / pascal run file.pas
add Add a dependency pascal add mathlib
remove Remove a dependency pascal remove mathlib
compile Compile a single file pascal compile prog.pas -S
info Inspect a PPU file pascal info module.ppu
clean Remove build artifacts pascal clean

Project Management

# Create a new project
pascal init calculator
cd calculator

# Add dependencies
pascal add mathlib -V "1.0"
pascal add utils --path "../shared/utils"
pascal add network --git "https://github.com/example/network.git"

# Remove a dependency
pascal remove network

# Build (compiles all units in dependency order)
pascal build
pascal build -v    # verbose

# Run the project's main program
pascal run

pascal.toml

[package]
name = "calculator"
version = "0.2.0"
description = "A calculator app"
authors = ["Alice"]
license = "MIT"
src = "src"
main = "calculator.pas"

[dependencies]
mathlib = "1.0"
utils = { path = "../shared/utils" }
network = { git = "https://github.com/example/network.git", branch = "main" }

[build]
optimization = 2
output = "build"

Single-File Mode

pascal run program.pas        # Interpret directly
pascal run program.pas -v     # With trace output
pascal compile program.pas -S # Emit x86-64 assembly
pascal compile program.pas -O2 -o build

Compile Options

Option Description
-o, --output <DIR> Output directory
-O, --optimize <LEVEL> Optimization level (0–3)
-v, --verbose Verbose output
-S, --assembly Generate assembly output
-d, --debug Debug information
-I, --include <DIR> Add unit search path
--no-cache Disable PPU caching

Examples

Recursive Fibonacci with Exit

program Fibonacci;
var
  i: integer;

function Fib(n: integer): integer;
begin
  if n <= 1 then
    exit(n);
  Fib := Fib(n - 1) + Fib(n - 2);
end;

begin
  for i := 0 to 10 do
    writeln('Fib(', i, ') = ', Fib(i));
end.

Prime Sieve with Early Return

program Primes;
var
  i, count: integer;

function IsPrime(n: integer): boolean;
var
  i: integer;
begin
  if n < 2 then
  begin
    IsPrime := false;
    exit;
  end;
  i := 2;
  while i * i <= n do
  begin
    if n mod i = 0 then
    begin
      IsPrime := false;
      exit;
    end;
    inc(i);
  end;
  IsPrime := true;
end;

begin
  count := 0;
  for i := 2 to 100 do
    if IsPrime(i) then
      inc(count);
  writeln('Primes under 100: ', count);  { Output: 25 }
end.

String Operations

program Strings;
var
  s, rev: string;
  i, len: integer;

function ReverseStr(s: string): string;
var
  i, n: integer;
  r: string;
begin
  n := length(s);
  r := '';
  for i := n downto 1 do
    r := concat(r, copy(s, i, 1));
  ReverseStr := r;
end;

begin
  s := 'Hello, Pascal!';
  writeln('Original: ', s);
  writeln('Length: ', length(s));
  writeln('Upper: ', upcase(s));
  writeln('Reversed: ', ReverseStr(s));
  writeln('Substring: ', copy(s, 8, 6));  { Pascal }
  writeln('Char 1: ', s[1]);              { H }
end.

Exception Handling

program Exceptions;
begin
  try
    writeln('Before raise');
    raise Exception.Create('something went wrong');
    writeln('SHOULD NOT PRINT');
  except
    on E: Exception do
      writeln('Caught: ', E.Message);
  end;

  try
    raise Exception.Create('error');
  finally
    writeln('Finally always runs');
  end;
end.

Math Algorithms

program Math;
var
  a, b: integer;

function GCD(a, b: integer): integer;
begin
  while b <> 0 do
  begin
    a := a mod b;
    if a = 0 then
    begin
      GCD := b;
      exit;
    end;
    b := b mod a;
  end;
  GCD := a;
end;

function Power(base, exp: integer): integer;
var
  result: integer;
begin
  result := 1;
  while exp > 0 do
  begin
    if exp mod 2 = 1 then
      result := result * base;
    base := base * base;
    exp := exp div 2;
  end;
  Power := result;
end;

begin
  writeln('GCD(48, 18) = ', GCD(48, 18));    { 6 }
  writeln('2^10 = ', Power(2, 10));           { 1024 }
end.

Unit System

MathUtils.pas:

unit MathUtils;

interface

function Add(a, b: integer): integer;
function IsEven(n: integer): boolean;

implementation

function Add(a, b: integer): integer;
begin
  Add := a + b;
end;

function IsEven(n: integer): boolean;
begin
  IsEven := (n mod 2) = 0;
end;

end.

Main.pas:

program Main;
uses MathUtils;
var
  x: integer;
begin
  x := Add(10, 5);
  writeln('10 + 5 = ', x);
  writeln('Is even: ', IsEven(x));
end.

See the examples/ directory for all 10 validated example programs.


Architecture

Source (.pas) → Lexer (logos) → Parser (recursive descent) → AST
                                                              │
                                    ┌─────────────────────────┼──────────────────┐
                                    ▼                         ▼                  ▼
                              Interpreter              Optimizer           Type Checker
                           (tree-walking)          (const fold, DCE)    (basic validation)
                                    │                     │
                                    ▼                     ▼
                              Direct Output        Code Generator → Assembly (.s)

Project Structure

pascal-rs/
├── src/
│   ├── lexer.rs                # Lexical analysis (logos-based, 100+ tokens)
│   ├── parser/                 # Recursive descent parser
│   │   ├── mod.rs              # Parser core with source location tracking
│   │   ├── expression.rs       # Expression parsing (precedence climbing)
│   │   ├── statement.rs        # Statement parsing (if, while, for, try, exit)
│   │   └── decl.rs             # Declaration parsing (var, type, class, function)
│   ├── ast.rs                  # AST node definitions
│   ├── interpreter.rs          # Tree-walking interpreter (Object Pascal support)
│   ├── build_system.rs         # Package manager & build system (pascal.toml)
│   ├── type_checker.rs         # Type validation
│   ├── optimizer.rs            # Optimization passes
│   ├── unit_codegen.rs         # x86-64 code generation
│   ├── resolver.rs             # Symbol resolution
│   └── traits/                 # Trait abstractions for testability
├── tests/                      # 101 integration tests across 8 test files
├── examples/                   # 10 validated example programs
├── ARCHITECTURE.md
├── SPEC.md
└── TODO.md

Built-in Functions & Procedures

Math: abs, sqr, sqrt, sin, cos, ln, exp, round, trunc

String: length, concat, copy, pos, upcase, lowercase, inttostr, strtoint

Ordinal: ord, chr, odd, succ, pred, inc, dec

Array: length, high, low, setlength

I/O: write, writeln, readln

Control: exit, break, halt, random


Testing

cargo test                                        # All 228 tests
cargo test --lib                                  # 127 unit tests
cargo test --test run_example_tests               # 19 example pipeline tests
cargo test --test run_integration_tests           # 10 integration tests
cargo test --test run_compiler_tests              # 10 codegen tests
cargo test --test run_complex_validation_tests    # 9 complex validation tests
cargo test --test run_interpreter_tests           # 11 interpreter tests
cargo test --test run_simple_compiler_tests       # 18 parser tests
cargo test --test run_simple_interpreter_tests    # 13 simple interpreter tests
cargo test --test run_type_checker_tests          # 10 type checker tests

Test Breakdown

Library (unit tests)        127  (includes 12 build system tests)
Example pipeline tests       19
Compiler codegen tests       10
Complex validation            9
Integration tests            10
Interpreter tests            11
Simple compiler (parser)     18
Simple interpreter           13
Type checker                 10
Basic                         1
─────────────────────────────────
Total                       228

Documentation

  • ARCHITECTURE.md — module design and data flow
  • SPEC.md — language feature matrix (parser/interpreter/codegen status)
  • TODO.md — development roadmap and completed phases

Current Limitations

  • Inline class method bodies — parser doesn't yet support method bodies inside type class declarations (interpreter supports classes via AST)
  • Array element assignmentarr[i] := val not yet supported
  • Multi-dimensional arrays — single dimension only in interpreter
  • File I/O — not implemented
  • Generics/templates — not implemented
  • GUI framework — not included (use FPC/Lazarus for GUI apps)

License

Apache-2.0


Made with Rust228 tests passing | Standard Pascal + Object Pascal subset | Compiler + Interpreter + Package Manager