Skip to content

Syntax

This page describes syntax of Pen. You can compose programs building up those language constructs. See also Types about syntax for specific data types.

Module

Modules are sets of type and function definitions. Syntactically, a module consists of statements. See Modules about how modules themselves interact with each other.

Statements

Statements are constructs that declare functions and types in modules.

Import statement

It imports types and functions from another module from the same or another package.

See Modules for more details.

import Foo'Bar

Foreign import statement

It imports a function from a foreign language.

See Foreign Function Interface (FFI) for more details.

import foreign "c" foo \(number, number) number

Record type definition

It defines a record type.

See Records for more details.

type foo {
  bar number
  baz string
}

Type alias

It gives another name to a type.

type foo = number | none

Function definition

It defines a function with a given name. The right-hand side of = signs must be function expressions.

foo = \(x number, y number) number {
  x + y
}

Foreign function definition

It defines a function exported to foreign languages.

See Foreign Function Interface (FFI) for more details.

foreign "c" foo = \(x number, y number) number {
  x + y
}

Block

A block consists of 1 or more expressions wrapped in { and }. Values of the last expressions are treated as resulting values of the blocks.

{
  foo(ctx, z)

  x + y + z
}

If you want to keep values of intermediate expressions for later use, you can define variables putting their names and = operators in front of the expressions.

{
  x = 42

  ...
}

Expressions

Expressions represent some computation. Expressions can be nested; expressions often contain other expressions inside.

Function call

It calls a function to evaluate it with given arguments returning its result value.

f(x, y)

Operators

Arithmetic

Arithmetic operators add, subtract, multiply, or divide a number with another.

1 + 1
1 - 1
1 * 1
1 / 1

Comparison

Equality

Equal (==) and not-equal (!=) operators compare two values and return a boolean value indicating if they are equal or not.

1 == 1
1 != 1

The operators can compare any types except functions and types containing them.

"foo" == "bar"
foo{x: 0} == foo{x: 1}
42 != none
Ordering

Order operators compare two numbers and return a boolean value indicating if the condition is correct or not.

1 < 1
1 <= 1
1 > 1
1 >= 1

Boolean

A not operator flips a boolean value.

!true

An and operator returns true if both operands are true, or false otherwise.

true & false

An or operator returns true if either operand is true, or false otherwise.

true | false

Error handling

? suffix operators immediately exit the current functions with operands if they are of the error type. Both the operands and result values of functions where the operators are used must be a union type containing the error type.

x?

Function

It creates a function.

First, functions declare their argument names and types (x number and y number) and their result types (number). After that, function bodies of blocks describe how the functions compute result values.

\(x number, y number) number {
  x + y
}

Conditionals

If expression

It evaluates one of blocks depending on a condition of an expression of a boolean type.

  • It evaluates the first block if a given boolean value is true.
  • Otherwise, it evaluates the second block.
if x {
  ...
} else {
  ...
}

If-type expression

It evaluates one of blocks depending on the type of a given expression. The expression (foo()) needs to be bound to a variable (x) and, in each block, the variable is treated as its specified type.

if x = foo() as number {
  ...
} else if string | none {
  ...
} else {
  ...
}

If-list expression

It deconstructs a list and evaluates one of two blocks depending on if the list is empty or not.

  • If a given list has 1 or more element, it evaluates the first block with a function that returns its first element (x) and rest of elements as a list (xs).
  • If the list has no element, it evaluates the second block.
if [x, ...xs] = ... {
  ...
} else {
  ...
}

If-map expression

It gets a value for a key in a map and evaluates one of two blocks depending on if the map has the key or not.

  • If a value for a key (key) is found, it evaluates the first block with the value (value).
  • If the map has no such key, it evaluates the second block.
if value = xs[key] {
  ...
} else {
  ...
}

Loop

List comprehension

It iterates a list and creates another list with elements computed by a given expression.

[number f(x()) for x in xs]

Multiple for clauses iterate multiple lists considering all combinations of their elements.

[number f(y())
  for y in x()
  for x in xs
]

Multiple lists in a for clause iterate them at once.

[number f(x(), y()) for x, y in xs, ys]

You can use if clauses to filter elements.

[number f(x()) for x in xs if g(x())]

Comment

Comments start with # and end with new-line characters.

# This is a comment.