Skip to content

NitroPascal is a full-featured Object Pascal compiler built entirely on top of Parse() - the compiler construction toolkit. It exists to prove a point: a complete, production-quality language can be built with Parse() without touching a parser generator, a lexer generator, or a custom pipeline.

License

Notifications You must be signed in to change notification settings

tinyBigGAMES/NitroPascal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NitroPascal

Discord Follow on Bluesky

What is NitroPascal?

NitroPascal is Object Pascal. It compiles to native binaries via C++23.

NitroPascal is a full-featured Object Pascal compiler built entirely on top of Parse() - the compiler construction toolkit. It exists to prove a point: a complete, production-quality language can be built with Parse() without touching a parser generator, a lexer generator, or a custom pipeline. Every stage - tokenization, Pratt parsing, semantic analysis, C++23 code generation, and native compilation via Zig - is driven through a single Parse() configuration object.

program Hello;

begin
  WriteLn('Hello from NitroPascal!');
end.

NitroPascal is not a toy. It is a working Pascal compiler that handles programs, procedures, functions, typed variables, arrays, sets, pointers, records, string manipulation, math, and memory management - all the things you would expect from a real Pascal implementation. The generated output is clean C++23, compiled to a native Win64 or Linux64 binary by the Zig/Clang backend that ships with ParseKit.

NitroPascal is the reference showcase for the Parse() Compiler Construction Toolkit. If you want to see what a full language looks like when built on Parse(), this is it. Read the source. Every grammar rule, every semantic check, every code emitter is a Parse() registration call - nothing more.

🚧 Under Construction

NitroPascal is actively developed. The foundation is solid and the core language works. More features are being added continuously.

βœ… What Works Today

  • Program structure - program, var, const, type, begin..end.
  • Primitive types - Integer, Double, Boolean, Char, String
  • Procedures and functions - full declarations, parameters (const, var, out), Result return convention
  • Control flow - if/then/else, while/do, for/to/downto, repeat/until, case/of, break, continue, exit
  • Arrays - fixed arrays with arbitrary index bounds, dynamic arrays, SetLength
  • Sets - Pascal set types, Include, Exclude, in operator
  • Pointers - typed pointer declarations, ^T, @expr, dereference, pointer type aliases
  • Records - field declarations, nested records, pass by value/ref/out, functions returning records
  • Literals - integer, real, string, char (#65), hex ($FF), boolean, nil
  • Intrinsics - Inc, Dec, Ord, Chr, Succ, Pred, Odd, Assigned, Length, Copy, Pos, UpperCase, LowerCase, Trim, IntToStr, StrToInt, StrToIntDef, StringOfChar, Abs, Sqr, Sqrt, Max, Min, Round, Trunc, New, Dispose
  • I/O - WriteLn, Write

πŸ”œ Planned / In Progress

  • Classes and objects with inheritance and virtual dispatch
  • Exception handling (try/except/finally)
  • Enumerations
  • Units and uses clause
  • String escape sequences and extended string handling
  • More intrinsics and RTL coverage
  • Linux64 cross-compile support

🎯 Why NitroPascal?

NitroPascal serves two audiences.

If you write Pascal, NitroPascal gives you a path from .pas source to a native binary without a legacy toolchain. Write standard Object Pascal, get a fast, small native executable. Just the NitroPascal compiler and the bundled Zig backend.

If you build languages, NitroPascal is the definitive answer to "can Parse() handle a real language?" Browse src/NitroPascal.Lexer.pas, src/NitroPascal.Grammar.pas, src/NitroPascal.Semantics.pas, and src/NitroPascal.CodeGen.pas. Every feature maps directly to Parse() API calls. There is no magic, no custom parser, no hand-rolled AST infrastructure. If NitroPascal can implement full Pascal on Parse(), your language can too.

πŸ”„ How It Works

NitroPascal is four source files and Parse():

NitroPascal.Lexer.pas     - keyword and operator registration
NitroPascal.Grammar.pas   - Pratt grammar rules (prefix + infix + statement handlers)
NitroPascal.Semantics.pas - type assignment and symbol resolution rules
NitroPascal.CodeGen.pas   - C++23 emitters for every AST node kind

Each file is a set of AParse.Config().Register*() calls. That is the entire compiler. Parse() provides the tokenizer, the Pratt parser engine, the scope-aware semantic walker, the C++23 IR builder, and the Zig compilation backend. NitroPascal provides the language definition.

Pascal source
      |
      v
+-----------+  tokens   +----------+   AST        +------------+
|   Lexer   | --------> |  Parser  | -----------> | Semantics  |
| (Parse()) |           | (Parse())|              | (Parse())  |
+-----------+           +----------+              +------------+
                                                        |
                                            enriched AST (type, scope, decl)
                                                        |
                                                        v
                                                 +-----------+
                                                 |  CodeGen  | --> .h + .cpp
                                                 | (Parse()) |
                                                 +-----------+
                                                       |
                                                       v
                                                  +---------+
                                                  |   Zig   | --> native binary
                                                  +---------+

πŸš€ Getting Started

Prerequisites: Directory Layout

NitroPascal requires the ParseKit sources to be present as a sibling directory alongside NitroPascal. The Delphi project references ParseKit's source directly. The required layout is:

C:\Dev\                         <- or any root you choose
  ParseKit\                     <- ParseKit repo root (contains src\, bin\, etc.)
  NitroPascal\                  <- NitroPascal repo root (contains src\, bin\, etc.)

Both repos must share the same parent directory. If they do not, the Delphi project will not compile.

Step 1: Get ParseKit

Option 1: Download ParseKit ZIP

Option 2: Git clone

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

Place (or clone) it so the folder structure matches the layout above.

Step 2: Get NitroPascal

Option 1: Download NitroPascal ZIP

Option 2: Git clone

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

Step 3: Download the Toolchain

The toolchain must be downloaded separately. It contains the Zig compiler and C++ runtime that NitroPascal uses to compile generated code to native binaries. Without it, the pipeline cannot produce binaries.

Download parsekit-toolchain.zip

Unzip the toolchain directly into the root of your NitroPascal directory:

NitroPascal\          <- repo root
  bin\                <- toolchain contents go here (zig\, res\, etc.)
  src\
  ...

This is a permanent release entry. The URL will never change. When the toolchain is updated, the same release entry is replaced in place. You always download from the same link.

System Requirements

Requirement
Host OS Windows 10/11 x64
Linux target WSL2 + Ubuntu (wsl --install -d Ubuntu)
Delphi Delphi 11 Alexandria or later (to build from source)

Step 4: Open in Delphi and Build

  1. Open src\NitroPascal.groupproj in Delphi
  2. Build all projects in the group (NitroPascal, Testbed)
  3. The Testbed project compiles and runs all tests in bin\res\tests\ and prints colour-coded pass/fail results

Step 5: Compile a Pascal Program

cd NitroPascal\bin
testbed

Or call the compiler programmatically:

uses
  NitroPascal;

var
  LCompiler: TNitroPascal;
begin
  LCompiler := TNitroPascal.Create();
  try
    LCompiler.SetSourceFile('hello.pas');
    LCompiler.SetOutputPath('output');
    if LCompiler.Compile(True) then
      WriteLn('Done.')
    else
      WriteLn('Failed: ', LCompiler.GetLastError());
  finally
    LCompiler.Free();
  end;
end;

πŸ“– Language Sample

program Showcase;

var
  i:    Integer;
  s:    String;
  arr:  array[1..5] of Integer;
  flags: set of (0..7);

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

begin
  // Arithmetic and string intrinsics
  s := 'Hello, NitroPascal!';
  WriteLn(UpperCase(s));
  WriteLn('Length: ', IntToStr(Length(s)));

  // Arrays (1-based indexing)
  for i := 1 to 5 do
    arr[i] := i * i;
  WriteLn('Squares: ', arr[1], ' ', arr[2], ' ', arr[3], ' ', arr[4], ' ', arr[5]);

  // Sets
  flags := [1, 3, 5];
  Include(flags, 7);
  if 3 in flags then
    WriteLn('3 is in flags');

  // Recursion
  for i := 1 to 7 do
    WriteLn(IntToStr(i) + '! = ' + IntToStr(Factorial(i)));
end.

🀝 Contributing

NitroPascal is an open project. Whether you are fixing a bug, improving documentation, adding a language feature, or writing a new test case, contributions are welcome.

  • Report bugs: Open an issue with a minimal reproduction. The smaller the example, the faster the fix.
  • Suggest features: Describe the use case first, then the syntax you have in mind. Features that emerge from real problems get traction fastest.
  • Submit pull requests: Bug fixes, documentation improvements, new test cases, and well-scoped features are all welcome. Keep changes focused.
  • Add tests: The bin\res\tests\ directory contains .pas test files. New tests that cover edge cases or new features are always valuable.

Join the Discord to discuss development, ask questions, and share what you are building.

πŸ’™ Support the Project

NitroPascal is built in the open. If it saves you time or sparks something useful:

  • ⭐ Star the repo: it costs nothing and helps others find the project
  • πŸ—£οΈ Spread the word: write a post, mention it in a community you are part of
  • πŸ’¬ Join us on Discord: share what you are building and help shape what comes next
  • πŸ’– Become a sponsor: sponsorship directly funds time spent on the compiler, runtime, and documentation

πŸ“„ License

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

Apache 2.0 is a permissive open source license that lets you use, modify, and distribute NitroPascal freely in both open source and commercial projects. You are not required to release your own source code. You can embed NitroPascal into a proprietary product, ship it as part of a commercial tool, or build on top of it without restriction.

The license includes an explicit patent grant, meaning contributors cannot later assert patent claims against you for using their contributions. Attribution is required - keep the copyright notice and license file in place - but beyond that, NitroPascal is yours to build with.

πŸ”— Links

NitroPascalβ„’ - A full-featured Object Pascal compiler built on Parse().

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

About

NitroPascal is a full-featured Object Pascal compiler built entirely on top of Parse() - the compiler construction toolkit. It exists to prove a point: a complete, production-quality language can be built with Parse() without touching a parser generator, a lexer generator, or a custom pipeline.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project