Portsy
Designed by | User:RocketRace |
---|---|
Appeared in | 2021 |
Computational class | |
Reference implementation | Unimplemented |
File extension(s) | .pts |
Portsy is a small C-like programming language embedded entirely within Python's module import syntax. The language was inspired by the semantics of Python modules and imports. It was designed by User:RocketRace in August of 2021.
Syntactic Features
Portsy programs consist of lines of the form from portsy import ...
, replacing the ellipsis with some code. For the purposes of this article, the from portsy import
preamble will be omitted. In the following sections, [name]
will be written to represent any sequence of characters considered a valid identifier in Python 3. Note that strings that are reserved tokens in Python are invalid identifiers in Portsy.
Each line can either be a name ([name]
), a label ([name] as [name]
), a group (a comma-delimited list of names or labels enclosed in parentheses, with an optional trailing comma -- e.g. ([name], [name] as [name], [name],)
), or an anchor (the literal string *
). These lexical atoms build up Portsy's grammar. Code between a # character and a newline is ignored.
Portsy programs can be split up into blocks. While it is not necessary, by convention these are differentiated with an extra level of indentation, typically four spaces. A block begins with a name or label, and ends with an anchor. Blocks may contain other blocks, given each is properly delimited. Each inner block is higher than the previous lower one. An example is shown below, and will be explained in the Semantic Features section.
fn as first # label, start of block (foo, bar) # group, in block foo # name, in block * # anchor, end of block
Semantic Features
Top-level source code consists of crates. Crates are declarations, evaluated before any entry point to the program is called. Each crate has rules for its syntax.
Program execution follows chains, which are sequences of imperatively executed operations. Chains contain lines of names, labels and groups, with the following kinds:
Said | Shown | Told |
---|---|---|
Lonely name | foo |
A lonely name is treated as a handoff point. See fn , op and unit for more on handoff points. The name must be assigned a value, which will be handed off to a lower block.
|
Lonely label | foo as bar |
A lonely label assigns the value of its left operand to the name in its right operand. The left name must have an assigned value. |
Greedy name | foo , (bar, baz) |
A greedy name is a name followed by a group (the meal). Like a lonely name, this is also a handoff point. Only certain names are greedy, some examples being fn s.
|
Greedy label | foo as bar , (baz, quz) |
A greedy label is a label followed by a group (the meal). Like a lonely label, this also assigns its value to its right operand (in this case bar ). Only certain labels are greedy. If a name is greedy, the equivalent label is also greedy.
|
Lonely group | (foo as bar, baz, _, bar) |
A lonely group interprets its innards as elements of a chain, with some alterations. These are the ingroup variants of each element.
|
The fn
, op
and unit
crates
A fn
defines a function. This begins a block with a group defining arguments and a chain defining the function body. Example definitions are shown below.
fn as foo # takes no arguments (_) # (_) represents the empty group # chain *
fn as bar # takes one argument (x) # chain *
or equivalently,
fn as bar # parentheses in single-element x # groups can be omitted freely # chain *
Inside the chain of a fn
, upon being handed off a value, the fn
will stop executing and evaluate to the handed-off value.
A fn
can be executed using a greedy name or label, including ingroup greedy names and labels:
some_fn as some_name (some, arguments, to, the, function)
(a, b, c, some_fn, some, ingroup, arguments, _, d, e, f) (a, b, c, some_fn as some_name, some, ingroup, arguments, _, d, e, f)
An op
defines a monadic operation. This is a special case of fn
, with only one implicit operand X
. The argument group is omitted.
op as foo # notice missing argument group X # this particular op just returns its argument *
An op
can only be called using lonely (potentially ingroup) labels. The right operand must additionally have a value assigned to it, and is treated as the argument to the op
.
# foo is defined some_op as foo # apply once to foo some_op as foo # apply a second time
A unit
is another special case of a fn
, this time taking no arguments.
unit as foo # chain *
An op
can only be called using lonely (potentially ingroup) labels. The right operand need not have a value assigned to it.
some_unit as foo some_unit as bar
The use
crate
The use
crate can be used to define names outside of chains. It pulls in a definition from an external bubble, be it a definition for a fn
, op
, unit
, or other, and applies it to the current program. use
begins a block containing the definitions that should be pulled from the specified bubble.
use as some_bubble some_definition some_other_definition as renamed_definition # ... *
There are a number of external bubbles included in Portsy (see the Included Bubbles section), and more can be defined by third parties. The definitions inside the included portsy
bubble are automatically pulled into Portsy programs, allowing the programmer to use them without explicitly asking for them. (See the Portsy Bubble section).
The value model
Every value in Portsy is either a signed integer or an array of values. Note that while a name may be assigned to a fn
or other similar things, they are not values and cannot be interpreted as such.
Values can be manipulated using definitions from bubbles. The included bubbles provide a baseline for writing programs.
Included Bubbles
portsy
This bubble exports