Language Documentation
Every statement in Period ends with a period (.). Comments begin with two dashes and extend to the end of the line.
Installation & First Steps
Download the latest Period-Setup.exe from the download page and run it. The installer will:
- Install
period.exetoC:\Program Files\Period. - Add Period to your system PATH.
- Install the VS Code extension automatically.
After installation, verify it works:
period --version
Run your first program:
period hello.period
Or start the interactive REPL:
period
Basics
A Period program is a sequence of statements. Each statement ends with a period. Whitespace and blank lines are ignored.
-- This is a comment.
let x be 10.
show x.
Keywords and reserved words (let, if, true, nothing, etc.) must be lowercase. Let, LET, and lEt are all errors. Variable and function names are case-sensitive.
Variables
Use let to declare a variable and set to reassign an existing variable or index.
let name be "Period".
set name to "Period Language".
let items be [1, 2, 3].
set items[0] to 10.
Variable names must start with a letter or underscore and may contain letters, digits, and underscores.
Data Types
Numbers
Integers and floating-point numbers are supported. Arithmetic follows standard precedence rules.
let count be 42.
let pi be 3.14.
let result be 2 ** 10 + 5.
Strings
Strings are enclosed in double quotes and support \n, \t, \", and \\ escapes.
let message be "Hello, Period.".
let lines be "First line\nSecond line".
Booleans and Nothing
true and false are the boolean values. nothing represents the absence of a value, similar to null in other languages.
let flag be true.
let empty be nothing.
Lists
Lists are ordered, mutable collections. Use brackets for indexing. Negative indexing is not supported.
let numbers be [1, 2, 3].
show numbers[0].
set numbers[0] to 10.
show length with numbers.
Dictionaries
Dictionaries store key-value pairs. Keys can be strings, numbers, or booleans.
let person be {"name": "Ada", "age": 36}.
show person["name"].
set person["age"] to 37.
show length with person.
Operators
Arithmetic
+addition (also string/list concatenation)-subtraction and unary negation*multiplication (also string repetition by an integer)/division%modulo**power
Comparison
==, !=, <, >, <=, >=
Logical
and, or, not
Operator Precedence
From highest to lowest: parentheses, indexing, function calls, unary not and -, **, * / %, + -, comparisons, and, or.
Conditionals
Use if ... then: to branch. The optional otherwise: block runs when the condition is false.
let score be 85.
if score >= 60 then:
show "pass".
otherwise:
show "fail".
You can nest conditionals inside any block. Blocks end when the indentation returns to the previous level.
Loops
Use while with repeat: to loop while a condition is true.
let i be 0.
while i < 10 repeat:
show i.
set i to i + 1.
Use for ... in ... repeat: to iterate over a list, string, dictionary keys, or a range. The range built-in accepts one, two, or three integer arguments: range with <stop>, range with <start>, <stop>, or range with <start>, <stop>, <step>.
for i in range with 5 repeat:
show i.
for ch in "hello" repeat:
show ch.
for n in [1, 2, 3] repeat:
show n.
Functions
Define functions with define and call them with with. Use return to send a value back. Functions that do not explicitly return yield nothing.
define greet with name:
show "Hello, " + name + "!".
greet with "World".
define factorial with n:
if n <= 1 then:
return 1.
return n * factorial with (n - 1).
Parameters are passed by value. Functions close over the environment in which they are defined.
Type Annotations
Type annotations are optional. Use them on parameters and return values to get runtime type checks.
define add with number a, number b returns number:
return a + b.
define greet with string name returns string:
return "Hello, " + name + "!".
Built-in type names are nothing, boolean, integer, number, string, list, dictionary, function, and class. You can also use a class name to match instances of that class.
Classes
Define a class with class, an optional init constructor, and define methods. Inside methods, this refers to the current instance.
class Person:
init with name, age:
set this name to name.
set this age to age.
define greet with greeting:
show greeting + ", " + this name + "!".
let ada be new Person with "Ada", 42.
tell ada to greet with "Hello".
show the age of ada.
Create instances with new <ClassName> with <args>, call methods with tell <object> to <method> with <args>, and read properties with the <property> of <object>.
Imports
Use import to bring in built-in or standard-library modules. Multiple modules can be imported in one statement, separated by commas. The last separator may be replaced with and, but only one and is allowed.
import math.
import math, random, string.
import math, random and string.
After importing, call the exported functions directly by name:
import math, random and string.
let n be random with nothing.
let greeting be upper with "hello".
show sqrt with 2.
If two imported modules export the same name, you must qualify it with from:
import math, random and string.
show sin from math with 5.
let joined be join from string with "-", ["a", "b"].
Using an unqualified name that is exported by more than one imported module is an error.
Period ships with the following modules. The native modules have .periodi stub files in period/stdlib/ for documentation and IDE support, while their implementations are provided by the runtime:
math— trigonometry, roots, and roundingrandom— random numbersstring— case conversiontime— timestampslist— list utilities (source inperiod/stdlib/list.period)text— text utilities (source inperiod/stdlib/text.period)
If a .period source file is missing, the native built-in implementation is used as a fallback. You can also write .periodi interface files (like Python .pyi stubs) that declare exports without implementation; the LSP reads them for completions and hover, while the runtime ignores them. Use ... as a placeholder expression or body. A leading string literal in a block is treated as a docstring and does not need a trailing .:
define sin with value returns number:
"Return the sine of a value."
...
let pi be ....
Local modules must be imported with a relative path: .helper loads helper.period from the same directory as the importing file, and ..helper loads it from the parent directory. A project lib/ folder is also checked for relative imports. Plain module names such as helper only resolve to built-in or standard-library modules.
Built-in Functions
Period provides a small set of built-in functions. They are called like any other function using with.
length with <value>
Returns the number of characters in a string, elements in a list, or keys in a dictionary.
show length with "hello". -- 5
show length with [1, 2, 3]. -- 3
string with <value>
Converts a value to its string representation.
show string with 42. -- "42"
number with <value>
Parses a string or converts a value to a number. Booleans become 1 or 0.
show number with "3.14". -- 3.14
type with <value>
Returns the type name as a string: nothing, boolean, integer, number, string, list, dictionary, function, built-in, class, or instance of <ClassName>.
show type with [1, 2]. -- "list"
input
Reads one line from standard input and returns it as a string.
show "What is your name?".
let name be input.
show "Nice to meet you, " + name + ".".
REPL
Running period without arguments starts the interactive Read-Eval-Print Loop. Type statements ending with a period and press Enter.
$ period
Period programming language REPL.
Type a statement ending with '.' and press Enter. Use Ctrl+C or type 'exit.' to quit.
>>> let x be 10.
>>> show x * 2.
20
>>> exit.
Use exit., quit., or Ctrl+C to leave the REPL.
VS Code Extension
The Windows installer automatically installs the Period VS Code extension. If you need to install it manually:
code --install-extension period-language.vsix
The extension provides:
- Syntax highlighting for
.periodfiles - LSP-powered diagnostics with red/yellow squiggles
- Hover information for keywords, built-ins, and user-defined symbols
- Auto-completion for keywords, built-ins, and defined names
If the language server is not found automatically, set period.languageServerPath in VS Code settings to the full path of period.exe.
Error Messages
Period reports errors with the exact line and column range. The parser recovers from errors so multiple problems can be reported in a single pass.
example.period:1:11: error: Expected '.' at the end of a 'let' statement.
1 | let x be 5
| ^
Runtime errors, such as division by zero or undefined variables, also print the offending source line with a caret pointing to the error, similar to Python:
example.period:2:8: runtime error: Division by zero.
2 | show 0 / 0.
| ^
Even compile-time diagnostics from the C/JIT backend are mapped back to the original Period source, so you see the same caret style instead of raw C compiler output:
example.period:1:7: error: 'x' undeclared
1 | show x.
| ^
Grammar Reference
A concise reference for the Period language grammar.
program := <statement>*
statement := "let" <identifier> "be" <expression> "."
| "set" <expression> "to" <expression> "."
| "show" <expression> "."
| "if" <expression> (",")? "then" ":" <block> ("otherwise" ":" <block>)?
| "while" <expression> "repeat" ":" <block>
| "for" <identifier> "in" <expression> "repeat" ":" <block>
| "define" <identifier> ("with" <params>)? ("returns" <type>)? ":" <block>
| "class" <identifier> ":" <class-body>
| "return" <expression>? "."
| "import" <module-path> ("," <module-path>)* ("and" <module-path>)? "."
| <expression> "."
block := <indent> <statement>+ <dedent>
class-body := <indent> (<init> | <method>)+ <dedent>
init := "init" ("with" <params>)? ":" <block>
method := "define" <identifier> ("with" <params>)? ("returns" <type>)? ":" <block>
module-path := "."* <identifier> ("." <identifier>)*
expression := <or-expr>
or-expr := <and-expr> ("or" <and-expr>)*
and-expr := <not-expr> ("and" <not-expr>)*
not-expr := "not" <not-expr> | <comparison>
comparison := <additive> (("=="|"!="|"<"|">"|"<="|">=") <additive>)?
additive := <multiplicative> (("+"|"-") <multiplicative>)*
multiplicative := <power> (("*"|"/"|"%") <power>)*
power := <unary> ("**" <power>)?
unary := ("-"|"not") <unary> | <call>
call := <primary> ("from" <module-path>)? ("with" <arguments>)? ("[" <expression> "]")*
primary := <number> | <string> | <bool> | "nothing" | "input" | "this"
| <identifier> | "(" <expression> ")" | "[" <arguments>? "]" | "{" <pairs>? "}"
| "new" <primary> ("with" <arguments>)?
| "tell" <expression> "to" <identifier> ("with" <arguments>)?
| "the" <identifier> "of" <expression>
property := <primary> <identifier>
Tips & Best Practices
- End every statement with a period. Missing periods are the most common parse error.
- Use indentation for blocks. After
if ... then:,while ... repeat:,for ... in ... repeat:,define ... :,class ... :, orinit ... :, indent the body by one level (four spaces is recommended). - Prefer functions and methods over deep nesting. They help keep programs article-like.
- Use comments as paragraphs. A short comment before each section makes the code read like a document.
- Check error locations. Diagnostics point to the exact character range, so read them carefully.