A minimal open-source host application for the Plan9Basic interpreter engine — a modern, cross-platform BASIC language runtime built with Delphi / FireMonkey (FMX).
This project packages the core interpreter engine together with a growing set of standard libraries and a ready-to-compile FMX host form, making it easy to:
- Embed BASIC scripting into your own Delphi/FMX applications.
- Load, edit, and run
.basPlan9Basic scripts interactively. - Perform HTTP requests, query AI providers, and build RAG pipelines — all from BASIC.
- Study or fork the interpreter engine for your own BASIC dialect.
| Windows 64-bit | Linux Ubuntu 22.04 (64-bit) | Android (64-bit) |
|---|---|---|
![]() |
![]() |
![]() |
This project is released under the MIT License — one of the most permissive open-source licenses available.
You are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this software in both open-source and commercial products. The only requirement is that the copyright notice and license text are preserved in all copies or substantial portions of the Software.
See LICENSE for the full text.
Why MIT? The goal is maximum freedom. MIT imposes no copyleft obligations — you can integrate the engine into proprietary software without any restrictions. It is the closest practical equivalent to placing code in the public domain while still protecting against liability.
| Tool | Notes |
|---|---|
| RAD Studio or Delphi | FireMonkey (FMX) required. Version 10.3 Rio or later recommended. |
| Target platform | Windows, macOS, Linux, iOS, Android — all FireMonkey targets are supported. |
| External dependencies | None beyond the standard RAD Studio / FMX RTL. |
| File | Description |
|---|---|
basic.pas |
TBasicEngine — top-level interface between a host application and the language runtime. |
lexer.pas |
Tokenizer — converts BASIC source text into a stream of lexical tokens. |
parser.pas |
Parser — validates syntax and emits intermediate postfix code. |
exec.pas |
Stack machine VM — executes the compiled postfix program. |
UnitUtils.pas |
Utility helpers shared across all engine components. |
utils/UnitGC.pas |
Garbage collector for non-visual heap objects (arrays, dicts, JSON, HTTP clients, AI clients, etc.). |
| File | Description |
|---|---|
Libs/ArrayLib.pas |
Dynamic arrays with 1-based indexing, up to 10 dimensions. Numeric, string, and pointer variants. |
Libs/StdLib.pas |
General-purpose utilities: type conversion, formatting, pointer helpers. |
Libs/StrLib.pas |
47+ string manipulation functions (search, replace, split, encoding, clipboard…). |
Libs/SysLib.pas |
File system, environment variables, and platform operations. |
Libs/TimerLib.pas |
Timer control: interval timers with OnTimer callbacks. Required by the engine for breakpoint handling. |
Libs/NumLib.pas |
Mathematics: trigonometry, logarithms, rounding, random numbers, abs, sign, min, max. |
Libs/DateTimeLib.pas |
Date and time: current date/time, formatting, parsing, and date arithmetic. |
Libs/JsonLib.pas |
JSON support: parse, build, and navigate JSON objects and arrays. GC-tracked. |
Libs/ConfigLib.pas |
Persistent INI-style configuration files. Cross-platform storage locations. |
Libs/Base64Lib.pas |
Base64 encoding and decoding for strings and binary files. URL-safe variant included. |
Libs/ZipLib.pas |
ZIP archive operations: create, open, add files, extract, and list archive contents. |
Libs/HttpLib.pas |
NEW — Full HTTP client: GET, POST, PUT, DELETE, PATCH, HEAD. Custom headers, cookies, Basic/Bearer auth, form data, query parameters, URL/HTML encoding, timeout control, and status-code helpers. 82 functions. Cross-platform synchronous API. |
Libs/PlatformInfoLib.pas |
NEW — OS and platform detection: name, version (major, minor, build), service pack, architecture, and version-check helpers. |
| File | Description |
|---|---|
Libs/AI/AILib.pas |
NEW — Provider-agnostic AI transport layer. Supports Anthropic (Claude), OpenAI (GPT), Google (Gemini), Mistral, Groq, DeepSeek, xAI/Grok, Perplexity, Together AI, Fireworks AI, OpenRouter, local Ollama, and LM Studio — all through a single unified interface. Includes synchronous completion, multi-turn conversation management, streaming (SSE), and tool-use support. 49 functions. |
Libs/AI/RAGLib.pas |
NEW — Plan9Basic bindings for the RAG engine. Lets scripts create a knowledge-base index, retrieve relevant documents by query, look up documents by tag or function name, and feed the results directly into an AI prompt. 13 functions. |
Libs/AI/RAGEngine.pas |
NEW — Pure-Delphi Retrieval-Augmented Generation engine. No external dependencies, no vector databases, no embeddings API, no Python required. Uses multi-signal keyword scoring (tag, title, function-name, category, and dependency signals) with token-budget management to select the most relevant documents for a given query. Consumed internally by RAGLib.pas. |
| File | Description |
|---|---|
AppletRunner.pas |
Minimal FMX host form — load, edit, and run .bas scripts with a single click. |
Plan9BasicApplet.dpr |
Delphi project file. |
The repository is fully self-contained — every file needed to compile is included.
Plan9Basic-AppletRunner/
├── LICENSE
├── README.md
├── Plan9BasicApplet.dproj ← Open this in RAD Studio to build
├── Plan9BasicApplet.dpr ← RAD Studio main project file
├── AppletRunner.pas ← Host application form
│
├── basic.pas ← Engine: main interface (TBasicEngine)
├── lexer.pas ← Engine: tokenizer
├── parser.pas ← Engine: parser / code generator
├── exec.pas ← Engine: stack machine VM
├── UnitUtils.pas ← Engine: shared utilities
│
├── utils/
│ └── UnitGC.pas ← Engine: garbage collector
│
├── Libs/
│ ├── ArrayLib.pas ← Standard library: dynamic arrays
│ ├── StdLib.pas ← Standard library: general utilities
│ ├── StrLib.pas ← Standard library: string functions
│ ├── SysLib.pas ← Standard library: system / file I/O
│ ├── TimerLib.pas ← Timer control library (required by exec.pas)
│ ├── NumLib.pas ← Mathematics: trig, log, random, rounding
│ ├── DateTimeLib.pas ← Date and time operations
│ ├── JsonLib.pas ← JSON parse, build, navigate
│ ├── ConfigLib.pas ← INI-style persistent configuration files
│ ├── Base64Lib.pas ← Base64 encode / decode
│ ├── ZipLib.pas ← ZIP archive create, extract, list
│ ├── HttpLib.pas ← NEW: HTTP client (82 functions)
│ ├── PlatformInfoLib.pas ← NEW: OS / platform detection
│ └── AI/
│ ├── AILib.pas ← NEW: AI provider transport layer (49 functions)
│ ├── RAGLib.pas ← NEW: RAG engine Plan9Basic bindings (13 functions)
│ └── RAGEngine.pas ← NEW: Pure-Delphi RAG engine (no external deps)
│
└── assets/
├── images/ ← Screenshots used in this README
└── examples/ ← Ready-to-run example applets (see below)
The assets/examples/ folder contains ready-to-run .bas scripts that demonstrate
both the language and the standard libraries. Load any of them in the Applet Runner
and press Run ▶ to try them out.
| File | What it demonstrates |
|---|---|
stdlib_test.bas |
Type conversion, formatting, and pointer helpers (StdLib) |
strlib_test.bas |
String manipulation functions (StrLib) |
numlib_test.bas |
Mathematics and rounding functions (NumLib) |
datetimelib_test.bas |
Date and time operations (DateTimeLib) |
syslib_test.bas |
File system and environment operations (SysLib) |
ArrayLib_Tests.bas |
Multi-dimensional dynamic arrays (ArrayLib) |
json_test.bas |
Building, parsing, and navigating JSON (JsonLib) |
Base64_quick_test.bas |
Quick Base64 encode/decode round-trip (Base64Lib) |
Base64Lib_tests.bas |
Full Base64 test suite including URL-safe variant |
test_ziplib.bas |
ZIP archive creation, listing, and extraction (ZipLib) |
configlib_example.bas |
INI-style persistent configuration files (ConfigLib) |
string_formatter.bas |
Formatted output and string building patterns |
do_loop_test.bas |
Loop constructs and control-flow patterns |
| File | What it demonstrates |
|---|---|
HttpLib_SimpleTest.bas |
The simplest possible GET request in one line |
HttpLib_QuickTest.bas |
Ten-test validation covering GET, POST, PUT, DELETE, auth, params, and URL encoding |
HttpLib_MethodsTest.bas |
Every HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD) side-by-side |
HttpLib_Tests.bas |
Full 22-test suite: client lifecycle, custom headers, cookies, form data (URL-encoded and multipart), Basic/Bearer auth, response headers, status codes, timeouts, User-Agent, and error handling — tested against httpbin.org |
HttpLib_DebugTest.bas |
Verbose request/response inspection for debugging connectivity issues |
| File | What it demonstrates |
|---|---|
hello_ai.bas |
The absolute minimum to call an AI and get a response — one client, one question, one answer. Works out-of-the-box with local Ollama (no API key needed), or switch PROVIDER$ to "anthropic", "openai", "groq", "deepseek", or any other supported cloud provider |
- Open RAD Studio.
- Choose File → Open and select
Plan9BasicApplet.dpr. - RAD Studio will generate the companion
.dprojfile automatically. - Select your target platform (Win32, Win64, macOS, Linux, iOS, Android).
- Press F9 to build and run.
dcc64 Plan9BasicApplet.dpr ^
-NSSystem;FMX;Data ^
-I.. -I..\utils -I..\Libs -I..\Libs\AI| Platform | Load / Save behaviour |
|---|---|
| Windows, macOS, Linux | Native file picker dialogs (TOpenDialog / TSaveDialog). |
| iOS, Android | TDialogService.InputQuery prompts for a filename. Files are read from and written to the app's Documents folder (TPath.GetDocumentsPath). Deploy .bas scripts to the device before loading, or type/paste the script directly into the editor and save it first. |
The P9B_DESKTOP conditional in AppletRunner.pas is set automatically at
compile time — no manual changes are needed when switching target platforms.
' --- Hello World ---
PRINTLN "Hello, World!"
' --- Variables and loops ---
LET name$ = "Plan9Basic"
FOR i = 1 TO 3
PRINTLN name$ + " — iteration: " + STR$(i)
NEXT i
' --- String library ---
LET s$ = UCase$("hello world")
PRINTLN s$
' --- Array library ---
arr# = dim#(10)
FOR i = 1 TO 10
arr#[i] = i * i
NEXT i
PRINTLN "5 squared = "; arr#[5]
' --- System library ---
PRINTLN "Documents directory: " + DocumentsPath$()Save the file with a .bas extension, click Load in the Applet Runner, then
press Run ▶.
' --- Simple one-liner GET ---
LET response$ = http_simpleget$("https://httpbin.org/get")
PRINTLN response$
' --- Client-based workflow ---
LET client# = http_client#("https://api.example.com")
LET client# = http_header#(client#, "Authorization", "Bearer " + myToken$)
LET client# = http_param#(client#, "page", "1")
LET response$ = http_get$(client#, "/items")
IF http_ok(client#) <> 0 THEN
PRINTLN "Status: " + STR$(http_status(client#))
PRINTLN response$
ELSE
PRINTLN "Error: " + http_errormsg$()
END IF
LET x = http_free(client#)' Works with local Ollama (free, no API key):
' 1. Install Ollama from https://ollama.com
' 2. Run: ollama pull llama3.2
' 3. Run this script as-is
LET PROVIDER$ = "ollama" ' or "anthropic", "openai", "groq", "deepseek" …
LET APIKEY$ = "" ' leave empty for Ollama; paste your key for cloud providers
LET MODEL$ = "llama3.2"
LET ai# = ai_client#(PROVIDER$, APIKEY$)
LET ai# = ai_model#(ai#, MODEL$)
LET response$ = ai_complete$(ai#, "Explain recursion in one sentence.")
IF ai_ok(ai#) = 1 THEN
PRINTLN response$
ELSE
PRINTLN "Error: " + ai_errormsg$()
END IF
LET x = ai_free(ai#)See assets/examples/hello_ai.bas for the full annotated version and instructions
for switching between providers.
TBasicEngine (defined in basic.pas) is designed to be embedded. Here is the
minimal integration pattern:
uses
basic, exec, UnitGC,
ArrayLib, StdLib, StrLib, SysLib, TimerLib,
HttpLib, PlatformInfoLib,
AILib, RAGLib;
// --- Initialisation (e.g. in FormCreate) ---
GC := TGarbageCollector.Create();
Engine := TBasicEngine.Create();
RegisterArrayFuncs(Engine.Functions);
RegisterStdFuncs(Engine.Functions);
RegisterStrFuncs(Engine.Functions);
RegisterSysFuncs(Engine.Functions);
RegisterTimerFuncs(Engine.Functions, Engine, OutputMemo.Lines); // required
RegisterHttpFuncs(Engine.Functions, Engine, OutputMemo.Lines);
RegisterPlatformInfoFuncs(Engine.Functions);
RegisterAIFuncs(Engine.Functions, Engine, OutputMemo.Lines);
RegisterRAGFuncs(Engine.Functions);
Engine.ScriptTimeOut := 30;
// --- Compile and run ---
if Engine.Compile(MyMemo.Lines) = 0 then
Engine.ExecuteProgram(OutputMemo.Lines)
else
ShowMessage('Line ' + IntToStr(Engine.ErrorLine) + ': ' + Engine.ErrorMessage);
// --- Clean up (e.g. in FormDestroy) ---
FreeAndNil(Engine);
FreeAndNil(GC);| Member | Kind | Description |
|---|---|---|
Compile(source: TStrings): Integer |
Function | Returns 0 on success, error count otherwise. |
ExecuteProgram(stdout: TStrings) |
Procedure | Runs the compiled program; PRINT output appended to stdout. |
Stop() |
Procedure | Signals the VM to halt at the next instruction. |
ErrorLine |
Property | 1-based line number of the last compile error. |
ErrorMessage |
Property | Human-readable description of the last compile error. |
Functions |
Property | TFunctionsDictionary — pass to RegisterXxxFuncs() calls. |
ScriptTimeOut |
Property | Maximum execution time in seconds (default: 30). |
OnPrintOutput |
Event | Fires for each PRINT; IsClear = True means CLS was called. |
Plan9Basic is a modern BASIC language interpreter designed for embedding in
Delphi / FireMonkey applications. It draws inspiration from classic BASIC dialects
while offering structured control flow (IF/ELSEIF/ENDIF, FOR/NEXT,
WHILE/ENDWHILE, REPEAT/UNTIL, SELECT/CASE), user-defined functions,
and a rich standard library system.
The engine compiles source code to a compact postfix intermediate representation and executes it on a stack machine VM, making it fast and easy to extend.
The full Plan9Basic language — documentation, interactive examples, and the complete online BASIC environment — lives at plan9basic.com.
This repository is the heart of that project. The interpreter engine published
here (basic.pas, lexer.pas, parser.pas, exec.pas) is the exact same engine
that powers the Plan9Basic website. Every language feature documented there —
every statement, operator, built-in function, and library call — can be reproduced
locally by building this project. If it runs on the website, it runs here.
In practical terms this means:
- Any script you write and test on the website compiles and runs identically from this open-source runner.
- Any script you build and debug locally can be copied directly to the website without modification.
- Embedding this engine in your own application gives you the same language capabilities that the website offers, ready to be extended in any direction you choose.
Contributions are welcome!
- Bug reports: open a GitHub Issue with a minimal reproducing script.
- Pull requests: please keep changes focused; add an example script when fixing a language bug.
- New library functions: follow the
Register*Funcs(Lib: TFunctionsDictionary)pattern used by the existing libraries.
So you dug through the source code, found something that looks suspiciously wrong, or thought of a feature so obviously missing that you can't believe it isn't there yet — congratulations, you are now officially a Plan9Basic contributor in spirit!
Feel free to drop an email to plan9basic@plan9basic.com describing what you found or what you'd like to see. Bug reports, improvement suggestions, and creative ideas are all genuinely appreciated.
Fair warning: responses arrive at the speed of available free time, which in the life of a solo developer can range from "reply in 24 hours" to "reply after I finish this one last feature that turned into a three-week rabbit hole." Rest assured, every message is read and nothing gets lost — it just occasionally gets read at 11 pm with a coffee that should have been a decaf.
Your patience is appreciated almost as much as your bug reports. 🙂
Released under the MIT License.


