Pyro

A scripting language for people who enjoy the simpler things in life.

Version 0.9.35

Type Annotations



Pyro supports optional type annotations for variable, function, and method declarations, e.g.

var foo: i64 = 123;
var bar: f64 = 1.0;

def is_long(text: str) -> bool {
    return text:byte_count() > 100;
}

def increment(value: i64, inc: i64 = 1) -> i64 {
    return value + inc;
}

Pyro doesn't (currently) do anything with these type annotations, apart from verifying their syntax, but they're useful for documenting your code's intended interface.

Future versions of Pyro may support optional type-checking or automatic documentation generation using type annotations.

Builtin Types

Annotations for builtin types are as follows:

The annotations below describe interfaces rather than concrete types:

A callable value is callable; an iterable value has an :$iter() method that returns an iterator; an iterator value has a :$next() method that returns the next item from a sequence.

Type annotations beginning with a lowercase letter are reserved for language builtins.

Syntax

Specify a variable's type by following its name with a colon and a type declaration:

var name: type;
var name: type = value;

The same syntax works for function and method parameters:

def func_name(arg1: type, arg2: type) {
    ...
}

Functions and methods can declare their return type by following their parameter list with an arrow, ->, and a type declaration:

def func_name() -> type {
    ...
}

Container types can optionally specify their content types in square brackets, e.g.

var foo: vec[str];
var bar: map[str, i64];
var baz: tup[i64, bool, str];

Where a type can be one of a discrete set of options, separate the options with a |, e.g.

var foo: i64|f64;
var bar: map[str, i64|f64];

Type declarations can be nested as required, e.g.

var foo: vec[map[str, i64|f64]];

Nullable Types

You can indicate that a type is nullable — i.e. can be either the specified type or null — by appending a ? to the type name, e.g.

var foo: i64?;
var bar: vec[str?];
var baz: map?[str, i64];

Callable Values

You can indicate that a value is callable — i.e. that the value is a function, method, class, or callable instance — using the callable type, e.g.

var foo: callable;

You can optionally specify the callable's return type, e.g.

var foo: callable -> bool;

You can optionally specify the callable's parameter types, e.g.

var foo: callable();
var bar: callable() -> bool;
var baz: callable(i64, str);
var bam: callable(i64, str) -> bool;

The callable type is nullable, e.g.

var foo: callable?;
var bar: callable?(i64) -> bool;

Type Names

A type name should specify either one of the builtin types or a user-defined type, possibly imported from a module, e.g.

var foo: UserType;

Here, foo is an instance of the class UserType. Type names can include a module path, e.g.

var bar: mod1::mod2::UserType;

Here, bar is an instance of the class UserType defined in the module mod1::mod2.

Type Aliases

You can define an alias for a type using a typedef statement, e.g.

typedef Token tup[str, i64, bool];

def makes_token() -> Token {
    return $tup("FOO", 123, true);
}

Variadic Functions

A type annotation in a variadic function specifies the type of the individual parameter values, e.g.

def add(*args: i64|f64) {
    return args:iter():sum();
}

assert add(1, 2.0) == 3.0;

Here, add() is a function that takes a variable number of arguments; each argument can be an i64 or an f64.