Source files and declarations
Spaces delimit indented suites. Tabs are rejected, and indentation must return
to an existing level. Blank lines and comment-only lines do not affect
indentation. Parentheses permit multiline expressions. Comments start with #.
Identifiers contain ASCII letters, digits, and underscores and cannot start with
a digit. Keywords and names beginning __plenty_ are reserved.
Diagnostics use one-based line and column positions.
Strings accept
single, double, or triple quotes; triple quotes permit physical newlines. The
first standalone string in an indented function body is its documentation. Use
return "text" when that first string should be the returned value. A b
prefix makes a byte literal, b"...", which holds ASCII
characters and \xHH escapes. Strings accept the
escapes \0, \n, \r, \t,
\\, \', \", and \u{H...} for a scalar by code point. Integer
literals are decimal, hexadecimal (0xFF), octal
(0o17), or binary (0b1010), with optional _ digit separators and width
suffixes.
Module scope contains functions, classes, enums, protocols, type aliases, constants, static assertions, imports, and target conditionals. Executable statements and mutable bindings belong inside functions; there are no global variables. Named functions belong at module scope; classes and enums can declare methods, and protocols declare method requirements. Anonymous functions can appear in function bodies; see functions.
A line holding only @name annotates the declaration below it. The set of
annotations is closed and compiler-known: @copy and @newtype on classes,
and @redacted on classes and enums.
See annotations.
Names follow lexical scope and prelude rules. Modules use
explicit imports, with visibility controlled by
pub. An application has a main entrypoint.
Keywords
A keyword cannot name a binding, parameter, field, function, type, or module. These keywords have a meaning in Plenty:
and, as, break, case, class, const, continue, def, dimension, elif,
else, enum, export, extern, False, for, from, if, import,
in, match, mut, not, opaque, or, pass, protocol, pub,
return, True, type, while, with, yield
These are reserved but have no meaning, so a Python or Rust habit is rejected instead of becoming a name:
async, await, lambda, None, struct, trait, try
None, try, and lambda have diagnostics that name the replacement:
Nothing, a Result, and an anonymous function.
self and is are not keywords. except, finally, and raise are not
reserved either, but a statement that begins like Python exception handling
is rejected.