Introduction

This book is being rewritten. Most pages describe a mix of planned and legacy syntax, and many of their examples do not run on the current interpreter. Pages marked Legacy page will be rewritten in P7 Docs truth. Until then, trust the example on this page and examples/app.poo in the repository over the rest of the book.

The name Poo comes from the Burmese word for guinea pig (ပူး).

Where PooLang is today

PooLang v0.1.11 is a small tree-walking interpreter written in Rust with no third-party dependencies. Source code goes through three stages: a lexer turns it into tokens, a parser builds an abstract syntax tree, and an interpreter walks that tree to run the program. The poo command runs a .poo file.

This program runs on v0.1.11:

use std::poutln;

// Comments open and close with two slashes. //
poo name <: "Guinea Pig";
mut count int = 0;
count = count + 1;

poof add(a int, b int) >> int {
    return a + b;
}

if count > 0 and not false {
    poutln("Hello, ", name, "! 2 + 3 = ", add(2, 3));
} elif count == 0 {
    poutln("unreachable");
}

It prints:

Hello, Guinea Pig! 2 + 3 = 5

A few rules of v0.1 syntax that the older pages get wrong:

  • Output functions must be imported before use, for example use std::poutln;.
  • poo declares an immutable variable and mut declares a mutable one. <: infers the type (poo x <: 5;); = follows an explicit type (poo x int = 5;). Reassignment uses = (x = 1;).
  • Functions are declared with poof, parameters need types, and >> gives the return type: poof add(a int, b int) >> int { ... }.
  • Comments are paired: // like this //.
  • Logical operators are and, or, and not (! also works); && and || do not exist.

Where PooLang is going

PooLang is being repositioned as a sandboxed scripting language for AI agents: an LLM agent writes the script and a host program runs it safely. The goals for that design are explicit capabilities granted by the host, resource budgets, deterministic execution, an interpreter that reports errors instead of panicking, and diagnostics that an LLM can read and act on.

Version 0.2 will move to a more conventional syntax while keeping the poo and poof keywords. Because of that change, this book will be rewritten against v0.2 rather than patched page by page.

Getting Started

Installation

Using Automated Installers

The fastest way to install PooLang is via our universal installers:

Linux / macOS

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/shayyz-code/poolang/releases/latest/download/poo-installer.sh | sh

Windows

powershell -c "irm https://github.com/shayyz-code/poolang/releases/latest/download/poo-installer.ps1 | iex"

From Source

If you have Rust and Cargo installed, you can build from source:

git clone https://github.com/shayyz-code/poolang.git
cd poolang
cargo build --release

The binary will be available at ./target/release/poo.

Running your first program

Create a file named hello.poo:

use std::pout;

pout("Hello, Guinea Pig!");

Run it using the PooLang CLI:

poo hello.poo

Next Steps

Check out the Variables & Types section to learn more about PooLang syntax.

Variables & Types

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

Variable Declarations

PooLang uses the poo keyword to declare variables. By default, variables are immutable, meaning their value cannot be changed after assignment.

poo age << 5;

If you need to reassign a value, you must use the mut keyword:

poo mut score << 0;
score << 10; # This is allowed

Assignment Operator

Note that PooLang uses the << operator for assignment instead of the traditional =. This helps distinguish PooLang code at a glance.

Supported Types

  1. Integer: Whole numbers (e.g., 42, -10).
  2. Float: Decimal numbers (e.g., 3.14, 2.0).
  3. String: Text enclosed in double quotes (e.g., "Hello").
  4. Boolean: Truth values (true or false).
  5. Vector: A collection of values (e.g., [1, 2, 3]).

Type Inference

PooLang automatically infers the type of a variable based on the value assigned to it. You do not need to explicitly declare types for variables.

Operators & Math

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

PooLang supports standard arithmetic operations with proper mathematical precedence (PEMDAS).

Arithmetic Operators

OperatorDescriptionExample
+Addition5 + 2
-Subtraction10 - 4
*Multiplication3 * 3
/Division20 / 5

Precedence Example

poo result << 10 + 5 * 2; # result is 20 (5*2=10, 10+10=20)

Comparison Operators

These operators return a Boolean (true or false).

OperatorDescription
==Equal to
!=Not equal to
>Greater than
<Less than
>=Greater than or equal to
<=Less than or equal to

Logical Operators

OperatorDescription
&&Logical AND
`
!Logical NOT

Comments

In PooLang v0.1.11 a comment opens with // and closes with another //. Everything between the two markers is ignored, so a comment can sit between statements on one line or span several lines.

use std::poutln;

// A comment opens and closes with two slashes. //
poutln("before"); // A comment can sit between statements. // poutln("after");
// It can also
   span several lines. //

This program prints before and then after.

Conditionals

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

PooLang uses if, elif, and else to control the flow of execution based on boolean conditions.

If Statements

The simplest form is a single if block:

if x > 10 {
    pout("x is large");
}

If-Else

You can provide an alternative path using else:

if x > 10 {
    pout("x is large");
} else {
    pout("x is small");
}

Elif (Else If)

For multiple conditions, use elif:

if x > 100 {
    pout("Huge");
} elif x > 10 {
    pout("Large");
} else {
    pout("Small");
}

Scoping

Variables declared inside a conditional block are scoped to that block and are not accessible outside.

if true {
    poo temp << 1;
}
# temp is no longer accessible here

Loops

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

PooLang provides two primary ways to repeat logic: while loops and for loops.

While Loops

The while loop continues to execute as long as its condition remains true.

poo mut count << 0;

while count < 5 {
    pout("Count: ", count);
    count << count + 1;
}

For Loops

PooLang supports for loops that iterate over a range or a collection.

Range Iteration

You can iterate over a range of numbers using the .. syntax:

for i in 0..5 {
    pout(i); # Prints 0, 1, 2, 3, 4
}

Vector Iteration

You can also iterate over elements in a vector:

poo items << [10, 20, 30];

for item in items {
    pout(item);
}

Scoping

The loop variable (like i or item) is only accessible within the body of the loop.

Functions

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

Functions in PooLang allow you to encapsulate logic into reusable blocks. They are defined using the poof keyword.

Defining a Function

A basic function looks like this:

poof sayHello() {
    pout("Hello!");
}

Return Types

PooLang uses the >> operator to specify the return type of a function.

poof getNumber() >> int {
    return 42;
}

Common return types include int, float, string, bool, and void (if no value is returned).

Parameters

You can pass data into functions via parameters:

poof add(a, b) >> int {
    return a + b;
}

poo sum << add(5, 5); # sum is 10

Function Scope

Functions create their own scope. Variables declared inside a function are not accessible outside. Functions can, however, access variables in the global scope if they are defined before the function is called.

Standard Library

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

PooLang includes a small built-in standard library to handle common tasks like output.

Printing to Console

The pout function is used to print values to the standard output.

use std::pout;

pout("Hello, World");
pout("The result is: ", 42);

Import Syntax

Note the use std::pout; line. pout is not available by default: calling it without importing it first fails with the runtime error Undefined function: pout.

Future Plans

The standard library is currently minimal. Planned additions include:

  • std::math: Advanced math functions (sin, cos, etc.)
  • std::fs: File system operations
  • std::str: String manipulation utilities

Lexer

Legacy page. This page predates the v0.2 redesign and may show syntax the v0.1.11 interpreter does not accept. It will be rewritten in P7 Docs truth.

The Lexer (also known as a Tokenizer) is the first stage of the PooLang pipeline. Its job is to take raw source code (a string of characters) and turn it into a sequence of meaningful Tokens.

How it works

The Lexer scans the input character by character and groups them into tokens like:

  • Keywords: poo, mut, if, while
  • Operators: <<, +, -, *, /
  • Literals: Integers (10), Strings ("hi"), Booleans (true)
  • Identifiers: Variable and function names

Implementation

The implementation is located in src/lexer.rs. It uses a simple state-machine approach to recognize different patterns of text.

Example

Input:

poo x << 5;

Tokens produced:

  1. Keyword(Poo)
  2. Identifier("x")
  3. Operator(Assign)
  4. Literal(Integer(5))
  5. Semicolon

Parser

The Parser takes the stream of tokens produced by the Lexer and organizes them into a hierarchical structure called an Abstract Syntax Tree (AST).

How it works

PooLang uses a Recursive Descent parser. It looks at the current token and decides which rule of the language grammar to apply next.

For example, if the parser see the poo token, it knows it is starting a variable declaration and expects an identifier followed by an assignment operator.

Abstract Syntax Tree (AST)

The AST is a tree-like representation of your code. For example, the expression 1 + 2 * 3 would be parsed into a tree where + is the root, 1 is the left child, and another tree representing 2 * 3 is the right child.

The AST node definitions can be found in src/ast.rs.

Implementation

The parser logic resides in src/parser.rs. It handles:

  • Statement parsing
  • Expression parsing (with operator precedence)
  • Error reporting for syntax errors

Interpreter

The Interpreter is the final stage of the PooLang pipeline. It takes the Abstract Syntax Tree (AST) produced by the Parser and executes the logic it represents.

How it works

PooLang uses a Tree-Walking Interpreter. It traverses the AST recursively, "visiting" each node and performing the corresponding action in the real world (e.g., adding two numbers, updating a variable in memory).

Environment and State

The interpreter maintains an Environment (or Scope) which maps variable names to their current values. When you declare a variable with poo, it is added to the current environment.

Implementation

The interpreter is located in src/interpreter.rs. Key features include:

  • Value system: Defines how integers, floats, and strings are stored in memory.
  • Scope management: Handles nested scopes for loops and functions.
  • Runtime Errors: Detects issues like dividing by zero or using an undefined variable.