Language Reference

Learn how to read and write Polonio templates, from values and output to reusable page logic.

Start with a template, then add the language features your page needs. Web, storage, and database features are introduced separately in the Runtime guide.

Template Structure

Templates mix literal HTML, emitted as written, with embedded Polonio code. Use the .pol extension for templates.

Code blocks

<%
var title = "Docs"
if title != null
  echo title
end
%>

Interpolation + inline echo

<h1>$title</h1>
<p>2 + 3 = <% echo 2 + 3 %></p>
<p>Literal $: write "$$" in text.
Use /* ... */ for block comments. In HTML segments, those comments are removed before rendering.

Equality & Comparison

== never converts values: different types are unequal. Arrays and objects compare structurally; functions and Error views compare by identity. != is its negation.

<, <=, >, and >= support two numbers or two strings only. Strings use byte-wise lexicographic order; other pairs raise a RuntimeError.

Types

Polonio has seven value types.

TypeDescription
nullDefault value for uninitialized variables and missing function arguments.
booltrue / false.
numberDouble-precision floating point (all integers are represented as doubles).
stringUTF-8 text with " or ' quoting plus \n, \t, \", \' escapes.
arrayOrdered list accessed with numeric indices.
objectString-keyed map storing arbitrary values.
functionUser-defined or built-in function value; user functions can close over surrounding values.

Variables

<%
var name
var count = 2
name = "Ana"
count += 3
count ..= " total"
%>

Operators

Use parentheses when an expression would be clearer. Function calls and indexing bind most tightly; assignments are right-associative.

Precedence (high → low)Operators
Call / Indexfn(), array[index], object["key"]
Unary-expr, not expr
Multiplicative*, /, %
Additive+, -
Concatenation..
Comparison<, <=, >, >=
Equality==, !=
Logical ANDand
Logical ORor
Assignment=, +=, -=, *=, /=, %=, ..=
Comparisons do not coerce types. Only `number == number`, `string == string`, etc. return true; mixed types compare as false.

Control Flow

If / Elseif / Else

<%
if user["role"] == "admin"
  echo "Welcome"
elseif user["role"] == "editor"
  echo "Hi"
else
  echo "Guest"
end
%>

Loops

<%
for i, item in items
  echo i .. ": " .. item
end

while total < 10
  total += 1
end
%>
Polonio does not impose a language-level iteration limit on loops; stop an intentional infinite program through normal process interruption.

Functions

<%
function greet(name)
  return "Hello " .. name
end

function counter()
  var value = 0
  return function()
    value += 1
    return value
  end
end
%>

See Fibonacci for recursion and Closures for captured state.

Includes

include "partial.pol" streams another template using the same interpreter and environments.

<% include "partials/nav.pol" %>

Operational recovery

Use attempt / recover only for unavailable capabilities and resources. Programming errors remain fatal; recovery never retries or rolls back output or side effects.

attempt
  var config = file_read("config.json")
recover error
  echo error["category"]
end

The optional binding is immutable and exists only in recover. A finalized send_file response cannot be recovered.

Truthiness

Conditions treat values as follows:

ValueTruthy?
nullfalse
falsefalse
truetrue
numberfalse if zero (including -0), otherwise true.
stringfalse if empty; "0", whitespace, and every other non-empty byte string are true.
arrayfalse if empty, otherwise true.
objectfalse if empty, otherwise true.
functionAlways true.
Error viewAlways true.

Conditions do not convert values. The same table is used by if, elseif, while, not, and, and or.

Scope & Closures

Lookup is lexical. var binds the current scope; assignment updates the nearest existing binding or creates a current binding when absent. Functions and each for iteration create scopes, while conditionals, while, includes, and template blocks share their current scope.

Polonio uses lexical scope:

Use helper functions to hide state when needed. Large templates often wrap logic in function render_item(item) and call it immediately to avoid polluting globals.

See Closures for a complete lexical-capture example.

Collection Mutation

Arrays and mutable objects are shared reference-like values. Assignment, calls, returns, and nesting do not deep-copy them. Mutating builtins update the shared collection; slice and concat create new outer arrays. See Collections and Aliasing.

Next steps

Practice these ideas in the Examples, then use the Built-in Functions reference as you build. When a template needs requests, sessions, files, or SQLite, continue to the Runtime guide. The language specification is the frozen v1.0 contract.