Skip to main content

Unary

Unary operators act on one following operand. Velox supports unary +, unary -, not and a restricted @ procedure-address form in its modified PascalScript expression parser.

Syntax​

+NumericExpression
-NumericExpression
not BooleanOrIntegerExpression
@ScriptProcedure

not binds to the following factor. The current parser handles unary + and a non-literal unary - differently: each consumes the following multiplying-level term. This is a Velox/PascalScript precedence quirk, so parenthesise a signed operand whenever it contains *, /, div, mod, and, shl, shr or as.

How it works​

TPSPascalCompiler.ReadFactor handles these forms:

  • Unary + consumes the following term and returns it unchanged. It is a sign-identity/no-op.
  • Unary - creates an otMinus node (or reads a negative integer literal directly). DoUnCalc emits the runtime cm_vm negation opcode.
  • not creates an otNot node. DoUnCalc emits Boolean negation for the compiler's Boolean types and integer bitwise complement for other integer types.
  • @ requires a procedure/function identifier that resolves to a script-internal TPSInternalProcedure, then produces a procedural-pointer value.

Example​

procedure ScriptEvent(var Value: Variant);
var
Delta: Integer;
Enabled: Boolean;
begin
Delta := -5;
Enabled := not False;
if Enabled then
Value := Delta;
end;

Unary minus stores -5; Boolean not changes False to True.

Unary sign​

Unary + does not convert, widen or validate a value beyond parsing the following expression. Unary - requires a runtime type supported by DoMinus (signed/real/Variant-compatible numeric paths as registered). Negating the lowest value of a fixed-width signed type can overflow its representable positive range; there is no extra checked-arithmetic contract here.

not​

For the default Boolean type and the recognised LongBool, WordBool and ByteBool aliases, not is logical negation. For integer types it complements every bit. These operations are different:

not True { Boolean False }
not 0 { all bits set in the selected integer representation }

Do not use integer not as though it returned a Boolean condition.

Restricted address-of behaviour​

The Velox parser's @ path is narrower than Delphi and Free Pascal:

  • it expects an identifier;
  • FindProc must resolve it;
  • the resolved procedure must be script-internal, not merely an imported/external function; and
  • it returns a procedural pointer used by a compatible procedural type/call path.

It does not implement the general Delphi rule that @ can take the address of an arbitrary variable or imported method. Most Velox configuration scripts do not need procedure pointers; use them only when a registered declaration explicitly requires one.

Common mistakes​

  • Using not on an integer when Boolean negation was intended, or on a Variant without first establishing its subtype.
  • Assuming unary + performs numeric conversion.
  • Negating unsigned values and expecting a portable positive/negative mathematical result.
  • Copying Delphi pointer examples that take @Variable or @ImportedFunction; this parser rejects those forms.
  • Omitting parentheses around a negated comparison. Write not (A = B) to show the intended Boolean operand.

Edge cases and quirks​

  • A negative integer literal is read as one signed literal where possible; a non-literal expression is compiled as runtime negation. Boundary diagnostics can therefore differ between literal parsing and calculated values.
  • The compiler builds not before multiplying-level binary operations. not A and B means (not A) and B.
  • Unary + and non-literal unary - call ReadTerm, not ReadFactor. Consequently, -A and B is parsed as -(A and B), whereas (-A) and B must be written explicitly. This differs from the usual Pascal rule that all unary operators have the same highest precedence.
  • Type checking for some unary nodes is completed when the calculation is emitted/executed; a permissive Variant or unsuitable runtime subtype can fail at runtime.
  • Address-of produces a procedural reference, not object ownership and not permission to call unregistered code.

Errors, performance and concurrency​

Unknown/internal-procedure restrictions, unsuitable operand types and incompatible procedural-pointer assignment cause compile-time or runtime type errors. Unary scalar operations are constant-time. They do not mutate their operand or provide synchronisation; evaluated property/function operands keep their normal side effects.

  • Arithmetic (Math) — binary numeric operations and fixed-width behaviour.
  • Boolean — binary logical and bitwise operations.
  • Relational (Comparison) — parenthesise a comparison when applying Boolean not.

External references​