A compiled, statically-typed language with C-like syntax built on LLVM
PIE is a statically-typed, compiled programming language with C-like syntax and modern high-level features. It compiles to native machine code via LLVM, offering solid performance while providing built-in support for arrays, dictionaries, regular expressions, HTTP, JSON, file I/O, and more.
- LLVM-Based Compilation — Fast native code via LLVM IR
- C-Like Syntax — Familiar structure for C/C++ programmers
- Static Typing — Type errors caught at compile time
- Module System — Import standard library and user-defined modules
- Rich Standard Library — Math, strings, file I/O, regex, HTTP, JSON, SQLite, and more
- Dynamic Arrays — Growable arrays with built-in operations
- Dictionaries — Hash maps with automatic type inference
- Regular Expressions — NFA-based Kleene syntax pattern matching
- TCP Sockets — Raw network socket support
- HTTP Client & Server — Full HTTP support via libcurl and libmicrohttpd
- Python 3.7+
- LLVM tools:
llc,clang - Python packages:
llvmlite >= 0.45.1,ply >= 3.11 - System libraries (for HTTP/JSON modules):
libcurl,libmicrohttpd,libjansson,libsqlite3
# Clone the repository
git clone https://github.com/Pie-Compiler/PIE-Compiler-V1-Python.git
cd PIE-Compiler-V1-Python
# Set up virtual environment
python3 -m venv venv
source venv/bin/activate
# Install Python dependencies
pip install llvmlite ply
# Install system libraries (Ubuntu/Debian)
sudo apt-get install -y libcurl4-openssl-dev libmicrohttpd-dev libjansson-dev libsqlite3-devCreate hello.pie:
// Hello, World in PIE
output("Hello, PIE!", string);
int x = 10;
int y = 20;
output("Sum: " + (x + y), string);
Compile and run:
python3 src/main.py hello.pie
./programOutput:
Hello, PIE!
Sum: 30
Full documentation is in the docs/ directory:
| File | Description |
|---|---|
| language-reference.md | Complete syntax, types, operators, control flow |
| standard-library.md | All built-in functions |
| module-system.md | Creating and importing modules |
| advanced-features.md | Arrays, dicts, regex, networking |
| examples.md | Practical examples and tutorials |
| quick-reference.md | Syntax cheat sheet |
int count = 42; // 32-bit signed integer
float pi = 3.14159; // 64-bit double-precision float
char grade = 'A'; // Single ASCII character
string name = "Alice"; // Null-terminated string
bool valid = true; // Boolean (true / false)
dict info = {}; // Hash map (string keys, mixed values)
regex pat = regex_compile("a+"); // Compiled regex pattern
file f = file_open("x.txt", "r"); // File handle
socket sock = tcp_socket(); // TCP socket
int age = 25;
string city = "Nairobi";
output(age, int); // Prints: 25
output(city, string); // Prints: Nairobi
// String concatenation with + embeds values inline
output("Age: " + age, string); // Age: 25
output("City: " + city, string); // City: Nairobi
// Float output with precision
float score = 95.5677;
output(score, float); // 95.57 (2 decimal default)
output(score, float, 4); // 95.5677
// If / else if / else
if (x > 10) {
output("big", string);
} else if (x == 10) {
output("ten", string);
} else {
output("small", string);
}
// For loop
for (int i = 0; i < 5; i++) {
output(i, int);
}
// While loop
while (x > 0) {
x--;
}
// Do-while loop
do {
output(x, int);
x++;
} while (x < 5);
// Switch
switch (day) {
case 1:
output("Monday", string);
break;
case 2:
output("Tuesday", string);
break;
default:
output("Other", string);
}
// Integer function
int add(int a, int b) {
return a + b;
}
// Recursive function
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
// String-returning function
string grade(float score) {
if (score >= 90.0) { return "A"; }
if (score >= 80.0) { return "B"; }
return "C";
}
// Void function (entry point)
void main() {
output(add(3, 4), int); // 7
output(factorial(5), int); // 120
output(grade(85.0), string); // B
}
Note: PIE supports both top-level statements (no
mainfunction needed for simple scripts) andmain()as the entry point.
// Static arrays (fixed size)
int nums[5] = [1, 2, 3, 4, 5];
output(nums[0], int); // 1
// Dynamic arrays (growable)
string names[] = ["Alice", "Bob", "Charlie"];
arr_push(names, "David"); // Add element
output(arr_size(names), int); // 4
string last = arr_pop(names); // Remove and return last
output(last, string); // David
// Array utilities
int exists = arr_contains(names, "Bob"); // 1 (true)
int idx = arr_indexof(names, "Bob"); // 1
float avg = arr_avg([10, 20, 30]); // 20.0
// Print entire array
output(names, array);
Multi-dimensional (static):
int matrix[3][3];
matrix[0][0] = 1;
output(matrix[0][0], int);
dict student = {
"name": "Alice",
"age": 20,
"GPA": 3.8
};
// Type is inferred from the receiving variable
string name = dict_get(student, "name"); // infers string
int age = dict_get(student, "age"); // infers int
float gpa = dict_get(student, "GPA"); // infers float
output("Name: " + name + ", Age: " + age, string);
// Add / update keys
dict_set(student, "age", 21);
dict_set(student, "year", 2);
// Check / delete
int has = dict_has_key(student, "year"); // 1
dict_delete(student, "year");
// Missing keys return type defaults: "" for string, 0 for int, 0.0 for float
string missing = dict_get(student, "absent"); // ""
Import standard library modules:
import http;
import json;
import sqlite;
import date;
// HTTP GET
string resp = http.get("https://jsonplaceholder.typicode.com/todos/1");
output(resp, string);
Import user-defined modules:
// mathutils.pie defines: export int square(int x) { return x * x; }
import mathutils;
output(mathutils.square(5), int); // 25
Import from a subdirectory:
import util from "./Utils/";
output(util.add(3, 4), int); // 7
string text = " Hello, PIE World! ";
string trimmed = string_trim(text);
string upper = string_to_upper(trimmed);
string reversed = string_reverse("HELLO");
output(trimmed, string); // Hello, PIE World!
output(upper, string); // HELLO, PIE WORLD!
output(reversed, string); // OLLEH
int pos = string_index_of(trimmed, "PIE");
output("PIE at index: " + pos, string); // PIE at index: 7
// Write a file
file f = file_open("notes.txt", "w");
if (f != null) {
int count = 42;
file_write(f, "Count: " + count + "\n");
file_write(f, "Done!\n");
file_close(f);
}
// Read all content
file r = file_open("notes.txt", "r");
if (r != null) {
string content = file_read_all(r);
output(content, string);
file_close(r);
}
// Read line by line into array
file g = file_open("notes.txt", "r");
if (g != null) {
string lines[] = file_read_lines(g);
for (int i = 0; i < arr_size(lines); i++) {
output("Line " + (i+1) + ": " + lines[i], string);
}
file_close(g);
}
PIE uses Kleene syntax with . for concatenation and | for alternation:
regex vowels = regex_compile("(a|e|i|o|u)+");
output(regex_match(vowels, "aeiou"), int); // 1 (match)
output(regex_match(vowels, "xyz"), int); // 0 (no match)
regex_free(vowels);
// Phone number pattern: exactly 10 digits
string digits = "(0|1|2|3|4|5|6|7|8|9)";
regex phone = regex_compile("(" + digits + "." + digits + "." + digits + "):10");
output(regex_match(phone, "0712345678"), int); // 1
regex_free(phone);
import http;
string resp = http.get("https://jsonplaceholder.typicode.com/todos/1");
int code = http.get_status_code();
output("Status: " + code, string);
output(resp, string);
import json;
// Build a JSON object
json.object user = json.create_object();
json.set_string(user, "name", "Bob");
json.set_int(user, "age", 28);
string serialized = json.stringify(user);
output(serialized, string); // {"name":"Bob","age":28}
// Parse JSON
json.object parsed = json.parse("{\"x\": 10, \"y\": 20}");
int x = json.get_int(parsed, "x");
output("x = " + x, string); // x = 10
import sqlite;
database db = sqlite.open("app.sqlite");
sqlite.exec(db, "CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)");
sqlite.exec(db, "INSERT INTO items (name) VALUES ('Widget')");
dict rows[] = sqlite.query(db, "SELECT * FROM items");
for (int i = 0; i < arr_size(rows); i++) {
dict row = rows[i];
string n = dict_get_string(row, "name");
output("Item: " + n, string);
}
sqlite.close(db);
import http;
void handler(ptr request, ptr response) {
string method = http.request_get_method(request);
string path = http.request_get_path(request);
if (method == "GET" && path == "/") {
http.response_set_status(response, 200);
http.response_set_header(response, "Content-Type", "text/plain");
http.response_set_body(response, "Hello from PIE!");
} else {
http.response_set_status(response, 404);
http.response_set_body(response, "Not Found");
}
}
void main() {
output("Server running on port 8080", string);
http.listen(8080, handler);
}
| Function | Signature | Description |
|---|---|---|
sqrt |
float(float) |
Square root |
pow |
float(float, float) |
Power |
abs |
float(float) |
Absolute value |
abs_int |
int(int) |
Integer absolute value |
floor, ceil, round |
float(float) |
Rounding |
min, max |
float(float, float) |
Min/max (float) |
min_int, max_int |
int(int, int) |
Min/max (int) |
sin, cos, tan |
float(float) |
Trigonometry |
log, log10, exp |
float(float) |
Logarithm/exp |
rand |
int() |
Random integer |
rand_range |
int(int, int) |
Random in range |
srand |
void(int) |
Seed random |
pi, e |
float() |
Math constants |
| Function | Description |
|---|---|
strlen(s) |
Length |
strcmp(a, b) |
Compare (0 if equal) |
strcat(dest, src) |
Concatenate |
string_to_upper(s) |
Uppercase |
string_to_lower(s) |
Lowercase |
string_trim(s) |
Strip whitespace |
string_substring(s, start, len) |
Extract substring |
string_index_of(haystack, needle) |
Find position (-1 if not found) |
string_replace_char(s, old, new) |
Replace character |
string_reverse(s) |
Reverse |
string_count_char(s, ch) |
Count occurrences |
string_char_at(s, i) |
Character at index |
int n = string_to_int("42"); // "42" → 42
float f = string_to_float("3.14"); // "3.14" → 3.14
char c = string_to_char("Hello"); // "Hello" → 'H'
int a = char_to_int('A'); // 'A' → 65
char h = int_to_char(72); // 72 → 'H'
float g = int_to_float(7); // 7 → 7.0
int i = float_to_int(3.9); // 3.9 → 3 (truncates)
| Function | Description |
|---|---|
arr_push(arr, val) |
Append element |
arr_pop(arr) |
Remove and return last element |
arr_size(arr) |
Number of elements |
arr_contains(arr, val) |
Returns 1 if val exists |
arr_indexof(arr, val) |
Index of val (-1 if not found) |
arr_avg(arr) |
Average of numeric array |
| Function | Description |
|---|---|
dict_get(d, key) |
Get value (type inferred from context) |
dict_set(d, key, val) |
Set value |
dict_has_key(d, key) |
Returns 1 if key exists |
dict_key_exists(d, key) |
Alias for dict_has_key |
dict_delete(d, key) |
Remove key |
dict_get_int(d, key) |
Get int value explicitly |
dict_get_float(d, key) |
Get float value explicitly |
dict_get_string(d, key) |
Get string value explicitly |
int ts = time_now(); // Unix timestamp
string local = time_to_local(ts); // "HH:MM:SS" local time
string enc = caesar_cipher("HELLO", 3); // "KHOOR"
string dec = caesar_decipher("KHOOR", 3); // "HELLO"
string r13 = rot13("SECRET"); // "FRPERG"
string xor = xor_cipher("text", "key"); // XOR encryption
| Category | Operators |
|---|---|
| Arithmetic | + - * / % |
| Comparison | == != < > <= >= |
| Logical | && || ! |
| Assignment | = |
| Increment | ++ -- (prefix and postfix) |
| String concat | + (also converts ints/floats) |
String comparison works with > and < using string length:
// Compares string lengths
if ("hello" > 3) {
output("long string", string);
}
// Single-line comment
/*
Multi-line
comment
*/
PIE-Compiler-V1-Python/
├── src/
│ ├── main.py # Compiler entry point
│ ├── frontend/
│ │ ├── lexer.py # NFA/DFA tokenizer (Thompson's construction)
│ │ ├── parser.py # PLY LALR(1) parser
│ │ ├── ast.py # AST node definitions
│ │ ├── semanticAnalysis.py # Type checking and validation
│ │ └── symbol_table.py # Symbol management
│ ├── backend/
│ │ └── llvm_generator.py # LLVM IR code generation
│ └── runtime/ # C runtime library
│ ├── runtime.c # I/O (input/output)
│ ├── math_lib.c # Math functions
│ ├── string_lib.c # String utilities
│ ├── d_array.c # Dynamic arrays
│ ├── dict_lib.c # Dictionaries
│ ├── regex_lib.c # NFA-based regex engine
│ ├── file_lib.c # File I/O
│ ├── net_lib.c # TCP sockets
│ ├── time_lib.c # Time functions
│ ├── crypto_lib.c # Caesar cipher, ROT13, XOR
│ ├── pie_http.c/h # HTTP client/server (libcurl + libmicrohttpd)
│ ├── pie_json.c/h # JSON (jansson)
│ ├── pie_sqlite.c/h # SQLite
│ └── pie_date.c/h # Date/time module
├── stdlib/ # Standard library modules
│ ├── http/ # HTTP module
│ ├── json/ # JSON module
│ ├── date/ # Date/time module
│ └── sqlite/ # SQLite module
├── testFiles/ # Example/test programs
│ ├── DataTypes.pie
│ ├── Arrays.pie
│ ├── Dictionaries.pie
│ ├── Functions.pie
│ ├── Recursion.pie
│ ├── NestedFunctions.pie
│ ├── File_I_O.pie
│ ├── DataManipulation.pie
│ ├── Regex.pie
│ ├── Database.pie
│ ├── Network.pie
│ ├── HttpClient.pie
│ ├── HttpServer.pie
│ ├── Json.pie
│ └── Modular.pie
├── examples/
│ ├── modules/ # Standard module examples
│ └── user_modules/ # User-defined module examples
├── docs/ # Documentation
└── README.md
source.pie
↓ Lexer (NFA/DFA - Thompson's construction)
Tokens
↓ Parser (PLY LALR(1))
AST
↓ Semantic Analyzer (type checking, module resolution)
Validated AST
↓ LLVM Code Generator (llvmlite)
output.ll (LLVM IR)
↓ clang + linker (runtime.c + module C sources)
./program (native executable)
python3 src/main.py <source.pie>
./programIntermediate files produced:
output.ll— LLVM IR (human-readable)program— Final native executable
See CHANGELOG.md for version history.
Made with ❤️ — Happy coding with PIE!