pluops

PLUOpS: Programming Languages Unambiguous Operator Specification

Publicly available, open specification for designing progamming languages.

Version: 1.3 (2026-09-18) Specification page: https://nvitya.github.io/pluops/

Value Types

The following generic type descriptions are used here:

Type Name Description
int Signed integer number
uint Unsigned integer number
float Floating-point number
bool Boolean value; it can be either true or false
ptr Pointer value containing a memory address. It can be typed or untyped

Generic Type Rules for Numeric Types

Unary operators (operators with a single operand, such as negation) usually preserve the operand’s type. Operators with two operands usually use the following rules:

Operand 1 Operand 2 Result
int int int
uint uint uint
float float float
uint int int
int uint int
float int or uint float
int or uint float float

Unary Operators: Operators with One Operand

Form: operator_symbol operand or operand operator_symbol

Operator Symbol Valid Types Description
- int, uint, float Numerical negation: - a
Either floating-point negation or integer negation.
Unsigned integers are converted to signed integers: uint -> int.
not bool Logical NOT: not a
The result is bool.
~ int, uint Bitwise NOT: ~ a
Preserves integer signedness.
For scripting languages, floating-point operands should first be converted to integers using the Round() function.
%
(recommended)
any addressable value Address-of: % a
The operand must be a variable or an expression that can provide an unambiguous memory address.
The result is a typed ptr, such as ^int, ^uint, or ^float.
Do not use this symbol for integer remainder.
^
(prefix)
any type Pointer type designator: ^T
Allowed only in type expressions.
The result is a pointer type pointing to type T, such as ^int, ^uint, ^float, or ^bool.
Multiple levels are allowed, such as ^^int or ^^^int.
^
(postfix)
ptr Pointer dereference: a^
The result has the type referenced by the typed pointer: ^int -> int, ^uint -> uint, ^float -> float, etc.

Binary Operators: Operators with Two Operands

Form: operand1 operator_symbol operand2

Operator Symbol Valid Types Description
+ int, uint, float Numerical addition: a + b
Either floating-point or integer addition according to the “Generic Type Rules”.
- int, uint, float Numerical subtraction: a - b
Either floating-point or integer subtraction according to the “Generic Type Rules”, with one exception:
uint - uint -> int.
* int, uint, float Numerical multiplication: a * b
Either floating-point or integer multiplication according to the “Generic Type Rules”.
/ int, uint, float Floating-point division: a / b
This operator always performs floating-point division; the result is always a floating-point value.
div int, uint Truncating integer division: a div b
This operator always performs truncating integer division.
The result is uint for uint div uint.
The result is int for int div uint or uint div int.
rem int, uint Integer division remainder: a rem b
Same as the a % b in the C programming language.
r = a - (a div b) * b, can be negative!
The result is uint for uint rem uint.
The result is int for int rem uint or uint rem int.
mod int, uint Integer modulo: a mod b
r = a - (a div b) * b
if r < 0 then r = r + b
Cannot be negative.
The result is uint for uint mod uint.
The result is int for int mod uint or uint mod int.
& int, uint Bitwise AND: a & b
Preserves integer signedness.
For scripting languages, floating-point operands should first be converted to integers using the Round() function (to handle 0.999 as 1).
| int, uint Bitwise OR: a | b
Preserves integer signedness. This operation is invalid for floating-point numbers.
For scripting languages, floating-point operands should first be converted to integers using the Round() function.
<< int, uint Bitwise shift left: a << b
Preserves the signedness of a. This operation is invalid for floating-point numbers.
For scripting languages, floating-point operands should first be converted to integers using the Round() function.
>> int, uint Bitwise shift right: a >> b
Preserves the signedness of a. This operation is invalid for floating-point numbers.
For scripting languages, floating-point operands should first be converted to integers using the Round() function.
and bool Logical AND: a and b
The result is bool.
or bool Logical OR: a or b
The result is bool.
== int, uint, float, bool Equality comparison: a == b, non-associative
int comparison is used when each operand is either int or uint.
float comparison is used when either operand is float.
bool comparison is used when both operands are bool, when only one operand is bool then the operation is invalid.
The result is always bool.
<> int, uint, float, bool Inequality comparison: a <> b (preferred), non-associative
int comparison is used when each operand is either int or uint.
float comparison is used when either operand is float.
bool comparison is used when both operands are bool, when only one operand is bool then the operation is invalid.
The result is always bool.
!= int, uint, float, bool Inequality comparison: a != b (alternative), non-associative
int comparison is used when each operand is either int or uint.
float comparison is used when either operand is float.
The result is always bool.
< int, uint, float Numerical less-than comparison: a < b, non-associative, with range comparison exception
uint comparison is used for uint < uint.
int comparison is used for int < uint or uint < int.
float comparison is used when either operand is float.
The result is always bool.
<= int, uint, float Numerical less-than-or-equal comparison: a <= b, non-associative, with range comparison exception
uint comparison is used for uint <= uint.
int comparison is used for int <= uint or uint <= int.
float comparison is used when either operand is float.
The result is always bool.
> int, uint, float Numerical greater-than comparison: a > b, non-associative, with range comparison exception
uint comparison is used for uint > uint.
int comparison is used for int > uint or uint > int.
float comparison is used when either operand is float.
The result is always bool.
>= int, uint, float Numerical greater-than-or-equal comparison: a >= b, non-associative, with range comparison exception
uint comparison is used for uint >= uint.
int comparison is used for int >= uint or uint >= int.
float comparison is used when either operand is float.
The result is always bool.
. structured types Structured type member access: a.member_name.
is any expression + Type Type test: a is T
The result is bool: true if the type of a is T or a descendant of T.
as any expression + Type Type casting: a as T
The result is a converted to type T.
The conversion might be invalid.
Some languages might provide alternative forms, such as T(a).
[+]
(postfix)
a: array or ptr
b: int, uint
Pointer or array indexing: a[b]
On arrays: The array element at index b in array a is returned.
On pointers: When a = ^T, the result type is also ^T and points to the address a + b * SizeOf(T) (without dereferencing, unlike in C).

Associativity

Unless stated otherwise, binary operators are left-associative. Repeated uses of the same op operator are therefore grouped from left to right:

a op b op c op d  ->  ((a op b) op c) op d

Range Comparisons

It is recommended to support the following three-operand chained comparisons:

x < y < z
x <= y < z
x < y <= z
x <= y <= z

x > y > z
x >= y > z
x > y >= z
x >= y >= z

A chained comparison x op1 y op2 z is equivalent to (x op1 y) and (y op2 z), except that y is evaluated only once.

Longer chains such as w < x < y < z and direction changes such as x < y > z should be reported as invalid expressions.

Parentheses

Form: ( expression )

The ( and ) symbols are used to group expressions, as in mathematics. The enclosed expression is treated as a single operand in the containing expression, overriding the default operator precedence where applicable.

A parenthesized expression has the same type, value, and addressability as the enclosed expression. Parenthesized expressions may be nested.

Operator Precedence

The operator precedence was designed to avoid the need for parentheses in the most common expressions.

Precedence is listed from highest to lowest.

Level Operators and syntax Meaning
1 literals, identifiers, (...), [...], T(expr), new T Primary expressions, array literals, casts, allocation
2 expr(args...), expr.member, expr[index], expr[start:end], ptr[index], ptr^ Function calls, member access, indexing, slicing, pointer indexing, pointer dereference
3 %expr, -expr, ~expr Address-of, unary minus, bitwise NOT
4 <<, >> Bit shifts
5 & Bitwise AND
6 |, xor Bitwise OR, bitwise XOR
7 /, div, rem, mod Floating-point division, integer division, integer remainder, integer modulo
8 * Multiplication
9 +, - Addition, subtraction
10 ==, <>, <, <=, >, >=, is, as Comparison, type test, “as” cast
11 not Logical NOT
12 and Logical AND
13 or Logical OR

Symbols Left Free

Symbol Possible Uses
{, } block delimiters
' String delimiter
" String delimiter
: Block start, type designation marker, member name designation marker
, list separator
; Statement termination
\ Escape symbol in strings, line continuation
? (in DQ: inference marker)
# (in DO: preprocessor directive)
$ (in DQ: context-dependent symbols)
@ (in DQ: namespace designator)
` Recommended for infix operators, such as `cxdiv`
! -

Document Changes

Version Date (ISO) Persons Changes
1.3 2026-09-18 Viktor Guáth-Nagy Added associativity information, x < y < z range comparions, , corrected for list separator
1.2 2026-09-04 Viktor Guáth-Nagy == and <> operator rules with bool described, rem added to the operator precedence
1.1 2026-09-03 Viktor Guáth-Nagy Added rem operator
corrected ==, <> and != valid with bool
1.0 2026-08-23 Viktor Guáth-Nagy Initial version

Contributing

For changes or improvements please create an issue here:

https://github.com/nvitya/pluops/issues