From 4df17cc9f78bc43bbaf2824384dc737ba57afd64 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Sat, 9 May 2026 19:43:36 +0200 Subject: [PATCH] Document the operators. --- docs/Features/Language/Operators.md | 10 ++-- docs/Reference/Compiler Constants.md | 2 +- docs/Reference/Core/And.md | 67 +++++++++++++++++++++++++++ docs/Reference/Core/AndAlso.md | 52 +++++++++++++++++++++ docs/Reference/Core/Is.md | 3 +- docs/Reference/Core/IsNot.md | 3 +- docs/Reference/Core/Mod.md | 47 +++++++++++++++++++ docs/Reference/Core/Not.md | 56 +++++++++++++++++++++++ docs/Reference/Core/Or.md | 68 ++++++++++++++++++++++++++++ docs/Reference/Core/OrElse.md | 52 +++++++++++++++++++++ docs/Reference/Operators.md | 38 ++++++++++++++++ docs/Reference/Statements.md | 4 -- 12 files changed, 390 insertions(+), 12 deletions(-) create mode 100644 docs/Reference/Core/And.md create mode 100644 docs/Reference/Core/AndAlso.md create mode 100644 docs/Reference/Core/Mod.md create mode 100644 docs/Reference/Core/Not.md create mode 100644 docs/Reference/Core/Or.md create mode 100644 docs/Reference/Core/OrElse.md create mode 100644 docs/Reference/Operators.md diff --git a/docs/Features/Language/Operators.md b/docs/Features/Language/Operators.md index f2f8930..4719cb5 100644 --- a/docs/Features/Language/Operators.md +++ b/docs/Features/Language/Operators.md @@ -7,7 +7,7 @@ permalink: /Features/Language/Operators # New Operators -twinBASIC introduces several new operators to enhance language capabilities. +twinBASIC introduces several new operators to enhance language capabilities. Reference pages for each individual operator live under [Reference → Operators](../../Reference/Operators). ## Bitshift Operators @@ -17,12 +17,12 @@ twinBASIC introduces several new operators to enhance language capabilities. ### OrElse and AndAlso -With the regular `Or` and `And` statements, both sides are evaluated, even when not necessary. With a short circuit operator, if the condition is resolved by the first side, the other side is not evaluated. So if you have: -`If Condition1 OrElse Condition2 Then`, if Condition1 is `True`, then `Condition2` will not be evaluated, and any code called by it will not run. +With the regular [`Or`](../../tB/Core/Or) and [`And`](../../tB/Core/And) statements, both sides are evaluated, even when not necessary. With a short-circuit operator, if the condition is resolved by the first side, the other side is not evaluated. So if you have +`If Condition1 `[`OrElse`](../../tB/Core/OrElse)` Condition2 Then`, if `Condition1` is `True`, then `Condition2` will not be evaluated, and any code called by it will not run. The companion conjunction operator is [`AndAlso`](../../tB/Core/AndAlso). ### If() Operator -Short-circuit `If()` operator with syntax identical to the tradition `IIf`. This has the additional benefit of not converting variables into a `Variant` if they're the same type; i.e. `If(condition, Long, Long)` the `Long` variables will never become a `Variant`. +Short-circuit [`If()`](../../tB/Core/If) operator with syntax identical to the traditional [`IIf`](../../tB/Core/IIf). This has the additional benefit of not converting variables into a `Variant` if they're the same type; i.e. `If(condition, Long, Long)` the `Long` variables will never become a `Variant`. ## Assignment Operators @@ -32,5 +32,5 @@ These are the equivalent of `var = var (operand) (var2)`. So `i += 1` is the equ ## IsNot Operator -The logical opposite of the *Is* operator for testing object equivalence. For example, instead of `If (object Is Nothing) = False` you could now write `If object IsNot Nothing Then`. +The logical opposite of the [`Is`](../../tB/Core/Is) operator for testing object equivalence. For example, instead of `If (object Is Nothing) = False` you could now write `If object `[`IsNot`](../../tB/Core/IsNot)` Nothing Then`. diff --git a/docs/Reference/Compiler Constants.md b/docs/Reference/Compiler Constants.md index a1c09ac..d191dcb 100644 --- a/docs/Reference/Compiler Constants.md +++ b/docs/Reference/Compiler Constants.md @@ -1,7 +1,7 @@ --- title: Compiler Constants parent: Reference Section -nav_order: 4 +nav_order: 5 permalink: /Reference/Compiler-Constants --- diff --git a/docs/Reference/Core/And.md b/docs/Reference/Core/And.md new file mode 100644 index 0000000..75fe0a8 --- /dev/null +++ b/docs/Reference/Core/And.md @@ -0,0 +1,67 @@ +--- +title: And +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/And +--- +# And operator +{: .no_toc } + +Used to perform a logical conjunction on two expressions. + +Syntax: +> *result* **=** *expression1* **And** *expression2* + +*result* +: Any numeric variable. + +*expression1*, *expression2* +: Any expressions. + +If both expressions evaluate to **True**, *result* is **True**. If either expression evaluates to **False**, *result* is **False**. The following table illustrates how *result* is determined: + +| If *expression1* is | And *expression2* is | The *result* is | +|:-----|:-----|:-----| +| **True** | **True** | **True** | +| **True** | **False** | **False** | +| **True** | **Null** | **Null** | +| **False** | **True** | **False** | +| **False** | **False** | **False** | +| **False** | **Null** | **False** | +| **Null** | **True** | **Null** | +| **Null** | **False** | **False** | +| **Null** | **Null** | **Null** | + +The **And** operator also performs a bitwise comparison of identically positioned bits in two numeric expressions and sets the corresponding bit in *result* according to the following table: + +| If bit in *expression1* is | And bit in *expression2* is | The *result* is | +|:-----:|:-----:|:-----:| +| 0 | 0 | 0 | +| 0 | 1 | 0 | +| 1 | 0 | 0 | +| 1 | 1 | 1 | + +> [!NOTE] +> **And** evaluates *both* operands every time, even when *expression1* alone determines the result. Use [**AndAlso**](AndAlso) when you want short-circuit evaluation — for example, when *expression2* is expensive, has side effects, or would fail without the guard provided by *expression1*. + +### Example + +This example uses the **And** operator to perform a logical conjunction on two expressions. + +```tb +Dim A, B, C, D, MyCheck +A = 10: B = 8: C = 6: D = Null ' Initialize variables. +MyCheck = A > B And B > C ' Returns True. +MyCheck = B > A And B > C ' Returns False. +MyCheck = A > B And B > D ' Returns Null. +MyCheck = A And B ' Returns 8 (bitwise comparison). +``` + +### See Also + +- [**AndAlso** operator](AndAlso) +- [**Or** operator](Or) +- [**Not** operator](Not) +- [Operators](../../Reference/Operators) + +{% include VBA-Attribution.md %} diff --git a/docs/Reference/Core/AndAlso.md b/docs/Reference/Core/AndAlso.md new file mode 100644 index 0000000..1e25a5a --- /dev/null +++ b/docs/Reference/Core/AndAlso.md @@ -0,0 +1,52 @@ +--- +title: AndAlso +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/AndAlso +--- +# AndAlso operator +{: .no_toc } + +Performs a short-circuit logical conjunction of two **Boolean** expressions. If the left operand evaluates to **False**, the right operand is not evaluated. + +> [!NOTE] +> **AndAlso** is a twinBASIC extension. The classic [**And**](And) operator always evaluates both operands and returns a bitwise result; **AndAlso** evaluates the right operand only when needed and always returns a **Boolean**. + +Syntax: +> *result* **=** *expression1* **AndAlso** *expression2* + +*result* +: A **Boolean** variable. + +*expression1*, *expression2* +: Any expressions that evaluate to **Boolean** (or are coercible to **Boolean**). + +If *expression1* is **False**, *result* is **False** and *expression2* is not evaluated. Otherwise *expression2* is evaluated and its **Boolean** value becomes *result*. + +This is the standard "short-circuit AND". It is useful when *expression2* depends on *expression1* having succeeded — for example, a null-check guarding a property access. + +### Example + +Guarding a property access by first verifying the object reference: + +```tb +If obj IsNot Nothing AndAlso obj.IsReady Then + ' Safe to call - obj.IsReady is only evaluated when obj is non-Nothing. + obj.DoWork +End If +``` + +Compare with the equivalent code using **And**, which would crash if `obj` were **Nothing** because both operands are always evaluated: + +```tb +' WRONG - obj.IsReady is evaluated even when obj is Nothing. +If obj IsNot Nothing And obj.IsReady Then + obj.DoWork +End If +``` + +### See Also + +- [**OrElse** operator](OrElse) +- [**And** operator](And) +- [Operators](../../Reference/Operators) diff --git a/docs/Reference/Core/Is.md b/docs/Reference/Core/Is.md index 4a2dc90..84a2641 100644 --- a/docs/Reference/Core/Is.md +++ b/docs/Reference/Core/Is.md @@ -1,6 +1,7 @@ --- title: Is -parent: Statements +parent: Operators +grand_parent: Reference Section permalink: /tB/Core/Is --- # Is diff --git a/docs/Reference/Core/IsNot.md b/docs/Reference/Core/IsNot.md index 380c814..bf122a4 100644 --- a/docs/Reference/Core/IsNot.md +++ b/docs/Reference/Core/IsNot.md @@ -1,6 +1,7 @@ --- title: IsNot -parent: Statements +parent: Operators +grand_parent: Reference Section permalink: /tB/Core/IsNot --- # IsNot diff --git a/docs/Reference/Core/Mod.md b/docs/Reference/Core/Mod.md new file mode 100644 index 0000000..8c5c196 --- /dev/null +++ b/docs/Reference/Core/Mod.md @@ -0,0 +1,47 @@ +--- +title: Mod +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/Mod +--- +# Mod operator +{: .no_toc } + +Used to divide two numbers and return only the remainder. + +Syntax: +> *result* **=** *number1* **Mod** *number2* + +*result* +: Any numeric variable. + +*number1*, *number2* +: Any numeric expressions. + +The modulus, or remainder, operator divides *number1* by *number2* (rounding floating-point numbers to integers) and returns only the remainder as *result*. For example, in the following expression, A (*result*) equals 5: + +```tb +A = 19 Mod 6.7 +``` + +Usually, the data type of *result* is **Byte**, **Byte** variant, **Integer**, **Integer** variant, **Long**, or **Variant** containing a **Long**, regardless of whether *result* is a whole number. Any fractional portion is truncated. + +However, if any operand is **Null**, *result* is **Null**. Any operand that is **Empty** is treated as 0. + +### Example + +This example uses the **Mod** operator to divide two numbers and return only the remainder. If either number is a floating-point number, it is first rounded to an integer. + +```tb +Dim MyResult +MyResult = 10 Mod 5 ' Returns 0. +MyResult = 10 Mod 3 ' Returns 1. +MyResult = 12 Mod 4.3 ' Returns 0. +MyResult = 12.6 Mod 5 ' Returns 3. +``` + +### See Also + +- [Operators](../../Reference/Operators) + +{% include VBA-Attribution.md %} diff --git a/docs/Reference/Core/Not.md b/docs/Reference/Core/Not.md new file mode 100644 index 0000000..e93399f --- /dev/null +++ b/docs/Reference/Core/Not.md @@ -0,0 +1,56 @@ +--- +title: Not +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/Not +--- +# Not operator +{: .no_toc } + +Used to perform logical negation on an expression. + +Syntax: +> *result* **=** **Not** *expression* + +*result* +: Any numeric variable. + +*expression* +: Any expression. + +The following table illustrates how *result* is determined: + +| If *expression* is | Then *result* is | +|:-----|:-----| +| **True** | **False** | +| **False** | **True** | +| **Null** | **Null** | + +In addition, the **Not** operator inverts the bit values of its operand and sets the corresponding bit in *result* according to the following table: + +| If bit in *expression* is | Then bit in *result* is | +|:-----:|:-----:| +| 0 | 1 | +| 1 | 0 | + +### Example + +This example uses the **Not** operator to perform logical negation on an expression. + +```tb +Dim A, B, C, D, MyCheck +A = 10: B = 8: C = 6: D = Null ' Initialize variables. +MyCheck = Not (A > B) ' Returns False. +MyCheck = Not (B > A) ' Returns True. +MyCheck = Not (C > D) ' Returns Null. +MyCheck = Not A ' Returns -11 (bitwise comparison). +``` + +### See Also + +- [**And** operator](And) +- [**Or** operator](Or) +- [**IsNot** operator](IsNot) +- [Operators](../../Reference/Operators) + +{% include VBA-Attribution.md %} diff --git a/docs/Reference/Core/Or.md b/docs/Reference/Core/Or.md new file mode 100644 index 0000000..fc6756f --- /dev/null +++ b/docs/Reference/Core/Or.md @@ -0,0 +1,68 @@ +--- +title: Or +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/Or +--- +# Or operator +{: .no_toc } + +Used to perform a logical disjunction on two expressions. + +Syntax: +> *result* **=** *expression1* **Or** *expression2* + +*result* +: Any numeric variable. + +*expression1*, *expression2* +: Any expressions. + +If either or both expressions evaluate to **True**, *result* is **True**. The following table illustrates how *result* is determined: + +| If *expression1* is | And *expression2* is | Then *result* is | +|:-----|:-----|:-----| +| **True** | **True** | **True** | +| **True** | **False** | **True** | +| **True** | **Null** | **True** | +| **False** | **True** | **True** | +| **False** | **False** | **False** | +| **False** | **Null** | **Null** | +| **Null** | **True** | **True** | +| **Null** | **False** | **Null** | +| **Null** | **Null** | **Null** | + +The **Or** operator also performs a bitwise comparison of identically positioned bits in two numeric expressions and sets the corresponding bit in *result* according to the following table: + +| If bit in *expression1* is | And bit in *expression2* is | Then *result* is | +|:-----:|:-----:|:-----:| +| 0 | 0 | 0 | +| 0 | 1 | 1 | +| 1 | 0 | 1 | +| 1 | 1 | 1 | + +> [!NOTE] +> **Or** evaluates *both* operands every time, even when *expression1* alone determines the result. Use [**OrElse**](OrElse) when you want short-circuit evaluation — for example, when *expression2* is expensive, has side effects, or only matters when *expression1* is **False**. + +### Example + +This example uses the **Or** operator to perform logical disjunction on two expressions. + +```tb +Dim A, B, C, D, MyCheck +A = 10: B = 8: C = 6: D = Null ' Initialize variables. +MyCheck = A > B Or B > C ' Returns True. +MyCheck = B > A Or B > C ' Returns True. +MyCheck = A > B Or B > D ' Returns True. +MyCheck = B > D Or B > A ' Returns Null. +MyCheck = A Or B ' Returns 10 (bitwise comparison). +``` + +### See Also + +- [**OrElse** operator](OrElse) +- [**And** operator](And) +- [**Not** operator](Not) +- [Operators](../../Reference/Operators) + +{% include VBA-Attribution.md %} diff --git a/docs/Reference/Core/OrElse.md b/docs/Reference/Core/OrElse.md new file mode 100644 index 0000000..45b18b0 --- /dev/null +++ b/docs/Reference/Core/OrElse.md @@ -0,0 +1,52 @@ +--- +title: OrElse +parent: Operators +grand_parent: Reference Section +permalink: /tB/Core/OrElse +--- +# OrElse operator +{: .no_toc } + +Performs a short-circuit logical disjunction of two **Boolean** expressions. If the left operand evaluates to **True**, the right operand is not evaluated. + +> [!NOTE] +> **OrElse** is a twinBASIC extension. The classic [**Or**](Or) operator always evaluates both operands and returns a bitwise result; **OrElse** evaluates the right operand only when needed and always returns a **Boolean**. + +Syntax: +> *result* **=** *expression1* **OrElse** *expression2* + +*result* +: A **Boolean** variable. + +*expression1*, *expression2* +: Any expressions that evaluate to **Boolean** (or are coercible to **Boolean**). + +If *expression1* is **True**, *result* is **True** and *expression2* is not evaluated. Otherwise *expression2* is evaluated and its **Boolean** value becomes *result*. + +This is the standard "short-circuit OR". It is useful when *expression2* is more expensive to evaluate, or when *expression2* would fail or have unwanted side effects in the case where *expression1* is already **True**. + +### Example + +Skipping an expensive lookup when a cheaper test already proves the condition: + +```tb +If IsCached(key) OrElse FetchFromDisk(key) Then + ' FetchFromDisk is only called when IsCached returned False. + Process key +End If +``` + +Compare with the equivalent code using **Or**, which would always call `FetchFromDisk` even when the cached lookup already succeeded: + +```tb +' Inefficient - FetchFromDisk runs even when IsCached returned True. +If IsCached(key) Or FetchFromDisk(key) Then + Process key +End If +``` + +### See Also + +- [**AndAlso** operator](AndAlso) +- [**Or** operator](Or) +- [Operators](../../Reference/Operators) diff --git a/docs/Reference/Operators.md b/docs/Reference/Operators.md new file mode 100644 index 0000000..dc754f4 --- /dev/null +++ b/docs/Reference/Operators.md @@ -0,0 +1,38 @@ +--- +title: Operators +parent: Reference Section +nav_order: 4 +has_toc: false +permalink: /Reference/Operators +--- + +# Operators + +Operators built into the twinBASIC language. They are understood by the compiler and are not declared or defined in the runtime library. + +> [!WARNING] +> Work in Progress + +## Arithmetic + +- [Mod](../tB/Core/Mod) -- divides two numbers and returns only the remainder + +## Logical and Bitwise + +Both operands are always evaluated. + +- [And](../tB/Core/And) -- logical or bitwise conjunction +- [Or](../tB/Core/Or) -- logical or bitwise disjunction +- [Not](../tB/Core/Not) -- logical or bitwise negation + +## Logical (Short-Circuit) + +The right operand is evaluated only when the left operand does not already determine the result. + +- [AndAlso](../tB/Core/AndAlso) -- (twinBASIC) short-circuit conjunction; evaluates the right operand only if the left is **True** +- [OrElse](../tB/Core/OrElse) -- (twinBASIC) short-circuit disjunction; evaluates the right operand only if the left is **False** + +## Object Identity + +- [Is](../tB/Core/Is) -- compares two object references for identity +- [IsNot](../tB/Core/IsNot) -- (twinBASIC) the logical inverse of **Is** diff --git a/docs/Reference/Statements.md b/docs/Reference/Statements.md index 96517fa..7c2f5e3 100644 --- a/docs/Reference/Statements.md +++ b/docs/Reference/Statements.md @@ -62,10 +62,6 @@ These statements are built into the language itself. They are understood by the * [Interface](../tB/Core/Interface) -- (twinBASIC) defines a COM interface using twinBASIC syntax -* [Is](../tB/Core/Is) -- compares two object references for identity - -* [IsNot](../tB/Core/IsNot) -- the logical inverse of **Is**; compares two object references for non-identity - * [Kill](../tB/Core/Kill) -- deletes files from a disk * [Let](../tB/Core/Let) -- assigns the value of an expression to a variable or property