Skip to content

Latest commit

 

History

History
815 lines (614 loc) · 17.4 KB

File metadata and controls

815 lines (614 loc) · 17.4 KB

PIE Language Reference

Complete reference for the PIE programming language syntax and semantics.


Table of Contents

  1. Program Structure
  2. Types
  3. Variables and Declarations
  4. Operators
  5. Control Flow
  6. Functions
  7. Arrays
  8. Dictionaries
  9. Strings
  10. Comments
  11. Modules
  12. Type Conversion
  13. I/O
  14. Reserved Words

1. Program Structure

A PIE program is a sequence of function definitions and top-level statements.

Entry Point

PIE recognizes a void main() function as the program entry point:

void main() {
    output("Hello, PIE!", string);
}

Top-level statements outside any function are also valid and are automatically treated as part of main:

// This is a complete, valid PIE program
int x = 10;
int y = 20;
output(x + y, int);

File Layout

[import statements]
[function definitions]
[top-level statements / main() function]

Imports must appear before the code that uses them. Functions can be defined in any order — PIE resolves calls across the file.


2. Types

Primitive Types

Type Width Description
int 32-bit Signed integer. Range: −2,147,483,648 to 2,147,483,647.
float 64-bit IEEE 754 double-precision floating point.
char 8-bit Single ASCII character.
string pointer Null-terminated character string.
bool / boolean 1-bit true or false.

Handle Types

These types represent opaque handles to system resources.

Type Description
file An open file handle returned by file_open().
socket A TCP socket handle returned by tcp_socket().
database A SQLite database handle returned by sqlite.open().
regex A compiled regular expression returned by regex_compile().
dict A hash map with string keys and mixed-type values.
ptr A generic pointer, used for module-defined opaque objects.

Module-Qualified Types

When using standard-library modules, more readable type aliases are available:

Alias Resolves to Source
json.object ptr import json;
json.array ptr import json;
http.request ptr import http;
http.response ptr import http;

3. Variables and Declarations

Syntax

type identifier;
type identifier = expression;

Primitive Variables

int age = 25;
float price = 19.99;
char grade = 'A';
string name = "Alice";
bool active = true;

// Declaration without initialization (value is undefined — always initialize)
int count;

Null

null can be assigned to any pointer-like type:

string s = null;
file f = null;
database db = null;
json.object obj = null;

Check for null using ==:

if (db == null) {
    output("Could not open database", string);
    return;
}

Scope

Variables are scoped to the block { } in which they are declared:

void example() {
    int x = 10;          // function scope

    if (x > 5) {
        int y = 20;      // block scope — only visible inside this if block
        output(y, int);
    }
    // y is not accessible here
}

4. Operators

Arithmetic

Operator Description Example
+ Addition (also string concatenation) a + b
- Subtraction a - b
* Multiplication a * b
/ Division a / b
% Modulo a % b

Integer division truncates toward zero: 7 / 2 == 3.

Comparison

Operator Description
== Equal
!= Not equal
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal

Comparison operators return 1 (true) or 0 (false) as integers.

When a string is compared to an integer, PIE compares the string's length to the integer:

string password = "hello";
if (password < 8) {
    output("Too short", string);   // Triggers: strlen("hello") < 8 → 5 < 8
}

Logical

Operator Description
&& Logical AND — both sides must be non-zero
|| Logical OR — at least one side must be non-zero
! Logical NOT (unary) — flips 0/non-zero
if (age >= 18 && age <= 65) { ... }
if (score < 0 || score > 100) { ... }
if (!found) { ... }

Assignment

x = 10;
name = "Bob";

Increment / Decrement

Only postfix forms are supported:

i++;   // equivalent to i = i + 1
i--;   // equivalent to i = i - 1

String Concatenation

The + operator concatenates strings. Non-string values are automatically converted:

string msg = "Score: " + 95 + ", grade: " + 'A';
// Produces: "Score: 95, grade: A"

The left-most operand determines the operation: "x" + 1 → concatenation, but 1 + 2 → integer addition.

Operator Precedence (high to low)

  1. Unary: -x, !x
  2. *, /, %
  3. +, -
  4. <, >, <=, >=
  5. ==, !=
  6. &&
  7. ||
  8. =

Use parentheses to override: (a + b) * c.


5. Control Flow

If / Else

if (condition) {
    // ...
}

if (condition) {
    // then branch
} else {
    // else branch
}

if (score >= 90) {
    output("A", string);
} else if (score >= 80) {
    output("B", string);
} else if (score >= 70) {
    output("C", string);
} else {
    output("F", string);
}

While

int i = 0;
while (i < 10) {
    output(i, int);
    i++;
}

Do-While

Executes the body at least once before checking the condition:

int choice = -1;
do {
    output("Enter 1 or 2: ", string);
    input(choice, int);
} while (choice != 1 && choice != 2);

For

for (initializer; condition; update) {
    // ...
}

// Standard integer loop
for (int i = 0; i < n; i++) {
    output(i, int);
}

// Countdown
for (int i = 10; i > 0; i--) {
    output(i, int);
}

// Loop over array
for (int i = 0; i < arr_size(items); i++) {
    output(items[i], string);
}

Switch

switch (expression) {
    case value1:
        // statements
        break;
    case value2:
        // statements
        break;
    default:
        // statements
        break;
}

break is required to prevent fall-through. default handles all unmatched cases.

int day = 3;
switch (day) {
    case 1: output("Monday", string);    break;
    case 2: output("Tuesday", string);   break;
    case 3: output("Wednesday", string); break;
    default: output("Another day", string); break;
}

Break and Continue

// break — exit the innermost loop or switch immediately
for (int i = 0; i < 100; i++) {
    if (i == 50) break;
}

// continue — skip the rest of the current iteration
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue;  // skip even numbers
    output(i, int);
}

Return

// Void function
void greet(string name) {
    output("Hello, " + name, string);
    return;   // optional in void functions
}

// Function with return value
int add(int a, int b) {
    return a + b;
}

// Early return for guard clauses
void process(database db) {
    if (db == null) {
        output("No database", string);
        return;
    }
    // ... rest of function
}

6. Functions

Definition Syntax

return_type function_name(param_type param_name, ...) {
    // body
    return value;  // required unless return_type is void
}

Return Types

Any type can be a return type: int, float, string, char, bool, void, dict, file, database, ptr, regex, socket.

Examples

// No parameters, no return value
void print_separator() {
    output("--------------------", string);
}

// Parameters and return value
int add(int a, int b) {
    return a + b;
}

float circle_area(float radius) {
    return pi() * radius * radius;
}

string repeat(string s, int n) {
    string result = "";
    for (int i = 0; i < n; i++) {
        result = result + s;
    }
    return result;
}

// Multiple parameters of different types
void log_event(string message, int level) {
    if (level > 0) {
        output("[" + level + "] " + message, string);
    }
}

Calling Functions

print_separator();
int sum = add(3, 7);
float area = circle_area(5.0);
string line = repeat("=", 40);
log_event("Started", 1);

Parameter Passing

All parameters are passed by value — the function receives a copy. Modifying a parameter inside the function does not affect the caller's variable.

void double_it(int x) {
    x = x * 2;   // only changes the local copy
}

void main() {
    int n = 5;
    double_it(n);
    output(n, int);  // still 5
}

Recursion

int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

int fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

7. Arrays

Static Arrays (Fixed Size)

Declared with an explicit size. Size cannot change at runtime.

int nums[5];                          // uninitialized
int values[5] = [10, 20, 30, 40, 50]; // with initializer
string names[3] = ["Alice", "Bob", "Charlie"];

Access is zero-indexed:

int first = values[0];   // 10
values[2] = 99;          // modify in place

Dynamic Arrays (Growable)

Declared with type name[] = [...]. The [] comes after the identifier name, not after the type.

int scores[] = [85, 92, 78, 95, 60];  // ✅ correct
// int[] scores = [85, 92, 78, 95];   // ✗ wrong syntax

string words[] = ["hello", "world"];
float prices[] = [9.99, 14.50, 3.75];
dict rows[] = [];                      // empty dict array

Dynamic arrays support arr_push and arr_pop:

int data[] = [1, 2, 3];
arr_push(data, 4);           // [1, 2, 3, 4]
arr_push(data, 5);           // [1, 2, 3, 4, 5]
int last = arr_pop(data);    // removes and returns 5
int size = arr_size(data);   // 4

Array Built-in Functions

Function Signature Description
arr_push arr_push(array, value) Append a value to a dynamic array
arr_pop arr_pop(array) Remove and return the last element
arr_size arr_size(array) → int Number of elements
arr_contains arr_contains(array, value) → int 1 if value found, else 0
arr_indexof arr_indexof(array, value) → int Index of value, or −1
arr_avg arr_avg(array) → float Arithmetic mean of a numeric array

Iterating Arrays

string fruits[] = ["apple", "banana", "cherry"];
for (int i = 0; i < arr_size(fruits); i++) {
    output(fruits[i], string);
}

Arrays of Dictionaries

The most common pattern when working with database results or collections of records:

dict people[] = [
    {"name": "Alice", "age": 30},
    {"name": "Bob",   "age": 25}
];

for (int i = 0; i < arr_size(people); i++) {
    dict p = people[i];
    string name = dict_get_string(p, "name");
    int age     = dict_get_int(p, "age");
    output(name + " is " + age + " years old", string);
}

8. Dictionaries

A dict is a hash map with string keys and values of any type.

Literal Syntax

dict empty = {};

dict person = {
    "name":  "Alice",
    "age":   28,
    "score": 95.5
};

Dictionary Functions

Function Signature Description
dict_create () → dict Create an empty dictionary
dict_get_int (dict, string) → int Get integer value by key
dict_get_float (dict, string) → float Get float value by key
dict_get_string (dict, string) → string Get string value by key
dict_set (dict, string, value) Set a key to a value
dict_has_key (dict, string) → int 1 if key exists, else 0
dict_delete (dict, string) Remove a key

Typed Getters

Use the typed getter for the value's actual type — using the wrong getter causes undefined behavior:

dict d = {"id": 1, "name": "Bob", "score": 88.5};

int   id    = dict_get_int(d, "id");       // ✅
string name = dict_get_string(d, "name");  // ✅
float score = dict_get_float(d, "score");  // ✅

Safe Access Pattern

Always check dict_has_key before accessing keys from untrusted data:

if (dict_has_key(row, "email") == 1) {
    string email = dict_get_string(row, "email");
    output(email, string);
}

9. Strings

String literals use double quotes. Escape sequences:

Sequence Meaning
\n Newline
\t Tab
\\ Backslash
\" Double quote
\0 Null terminator

Concatenation

The + operator concatenates strings and auto-converts adjacent integers and floats:

string msg = "Count: " + 5 + ", avg: " + 88.5;
// → "Count: 5, avg: 88.5"

String Functions (Summary)

Function Returns Description
strlen(s) int Length of s
string_trim(s) string Remove leading/trailing whitespace
string_to_upper(s) string Convert to uppercase
string_to_lower(s) string Convert to lowercase
string_contains(s, sub) int 1 if sub is in s
string_starts_with(s, pre) int 1 if s starts with pre
string_ends_with(s, suf) int 1 if s ends with suf
string_index_of(s, sub) int Index of first sub, or −1
string_substring(s, start, len) string Substring at start, length len
string_reverse(s) string Reversed copy
string_replace_char(s, from, to) string Replace all from chars with to
string_char_at(s, i) char Character at index i
string_to_char(s) char First character
string_to_int(s) int Parse as integer
string_to_float(s) float Parse as float
string_is_empty(s) int 1 if null or zero-length
string_count_char(s, c) int Count occurrences of c
string_split_to_array(s, delim) string[] Split on delim, return array
strcmp(s1, s2) int 0 if equal, <0 if s1 < s2, >0 if s1 > s2

See the Standard Library for full signatures and examples.


10. Comments

// Single-line comment

/*
 * Multi-line comment.
 * Can span many lines.
 */

int x = 10;  // inline comment

11. Modules

Importing a Standard Library Module

import sqlite;
import json;
import http;
import date;

Call module functions with dot notation:

database db = sqlite.open("data.sqlite");
json.object obj = json.create_object();
string resp = http.get("https://example.com");
int ts = date.now();

Importing a User-Defined Module

Create utils.pie in the same directory with exported functions:

// utils.pie
export string greet(string name) {
    return "Hello, " + name + "!";
}

Then import it:

import utils;

void main() {
    output(utils.greet("Alice"), string);
}

Only functions marked export are accessible from outside the module. Internal helpers without export remain private.

See Module System for the full guide.


12. Type Conversion

PIE is statically typed — no implicit conversions. Use explicit conversion functions:

Conversion Function
intfloat int_to_float(n)
floatint float_to_int(n) (truncates)
intstring int_to_string(n)
floatstring float_to_string(n)
charstring char_to_string(c)
charint char_to_int(c) (ASCII code)
intchar int_to_char(n) (ASCII code)
stringint string_to_int(s)
stringfloat string_to_float(s)
stringchar string_to_char(s) (first char)
float avg = int_to_float(total) / int_to_float(count);
string display = "Total: " + int_to_string(total);
int code = char_to_int('A');   // 65

13. I/O

output()

Print a value to stdout followed by a newline.

output(expression, type);
output(expression, float, precision);  // float with decimal places

The type argument is a keyword: int, float, string, char.

output("Hello", string);           // Hello
output(42, int);                   // 42
output(3.14159, float, 2);         // 3.14
output('A', char);                 // A
output("x = " + x, string);       // x = 10

input()

Read from stdin into a variable.

input(variable, type);
int age;
output("Enter your age: ", string);
input(age, int);

string name;
output("Enter your name: ", string);
input(name, string);

System

exit();         // terminate the program immediately
sleep(3);       // pause for 3 seconds
clear();        // clear the terminal screen (ANSI)

14. Reserved Words

int        float      char       string     bool       boolean
void       file       socket     database   dict       regex
array      ptr
if         else       for        while      do         switch
case       default    break      continue   return
import     from       as         export
true       false      null
input      output     exit       sleep      clear
arr_push   arr_pop    arr_size   arr_contains  arr_indexof  arr_avg