-
Notifications
You must be signed in to change notification settings - Fork 6
Reserved Words
The Language Reference's Reserved Words page lists two groups of keywords: one that "may not be used as labels for any purpose", and one that may label data but "may not be the label of any PROCEDURE statement". The compiler does not agree with either list in full.
Everything on this page was settled by compiling it, on Clarion 10 (10.0.12567) and Clarion 12 (12.0.14204), with identical results. The test project, which builds every word of both lists in every place a label can go (990 builds per version), is in the repository: test-programs/ReservedWordsTest. The extension's reserved-keyword diagnostic follows these results.
- 44 keywords can never be a label, anywhere: not a variable, not a GROUP field, not a CLASS method, not a PROCEDURE or ROUTINE.
-
A keyword can name a parameter, but a reserved one only the last:
(LONG X, LONG If)builds,(LONG If, LONG X)does not. -
A keyword can start a statement in column 1 (
OF 1,END), because it cannot be a label there. -
A keyword can be the prefix of a colon label (
Return:NotSet). - Everything else in the help's lists is not reserved at all: WINDOW, CLASS, QUEUE, SELF, PARENT and the rest can label anything, a PROCEDURE included; so can CODE, DATA, NULL and THROW.
- But SELF, PARENT and NULL are system intrinsics: reusing them as a method's parameter or local (SELF, PARENT) or a procedure's name (NULL) draws a warning, and a SELF or PARENT so declared hides the real one — see below.
| ACCEPT | AND | ASSERT | BEGIN | BREAK | BY |
| CASE | CATCH | CHOOSE | COMPILE | CONST | CYCLE |
| DO | ELSE | ELSIF | END | EXECUTE | EXIT |
| FINALLY | FUNCTION | GOTO | IF | INCLUDE | LOOP |
| MEMBER | NEW | NOT | OF | OMIT | OR |
| OROF | PRAGMA | PROCEDURE | PROGRAM | RETURN | ROUTINE |
| SECTION | THEN | TIMES | TO | TRY | UNTIL |
| WHILE | XOR |
Each of these fails as a label in every place tested — global data, procedure-local data, a GROUP field, a CLASS property, a CLASS method, a global PROCEDURE, a ROUTINE, an executable statement's label, and a method's local data:
Loop LONG ! ❌ global or local variable
MyGroup GROUP
If LONG ! ❌ a GROUP field too
END
MyClass CLASS
Return PROCEDURE ! ❌ a CLASS method too
ENDNote CATCH, FINALLY and TRY: they are reserved in Win32 Clarion, not only in Clarion.NET.
Each of the 44 builds as a parameter's name when it is the only parameter or the last one, in a procedure's prototype and implementation (and, tested alone, in a method's). Followed by another parameter, it fails:
MAP
Scale PROCEDURE(LONG If) ! ✅ alone
Shift PROCEDURE(LONG X, STRING Loop) ! ✅ last
Rotate PROCEDURE(LONG If, LONG X) ! ❌ Expected: <ID> )
ENDThe words that are not reserved (below) build as a parameter's name in any position. Legal or not, a keyword as a parameter name is best avoided.
The Language Reference says a statement without a label must not start in column one. For a statement that starts with a reserved word, the compiler accepts it anyway — the word cannot be a label, so it can only be the statement:
CODE
CASE X
OF 1 ! ✅ builds
X = 2
END
IF X = 1 ! ✅ builds
X = 3
END ! ✅ buildsOF, IF, END, LOOP, ELSE, RETURN and CODE were all tested this way. A statement that starts with an ordinary name still fails in column 1, because that name is read as a label:
X = 1 ! ❌ in column 1: X is taken for a label
X = 1 ! ✅So a reserved word in column 1 is only an error when it is used as a label — when a declaration follows it (If LONG, Loop PROCEDURE, End EQUATE(1)).
A keyword before the colon is a prefix, not a label on its own:
Return:NotSet EQUATE(0) ! ✅ builds
If:Flag LONG ! ✅ builds
CODE
If:Flag = Return:NotSet ! ✅ and can be usedThe help's first list includes them, but all four build as a label everywhere — a variable, a field, a method, a PROCEDURE:
Code LONG ! ✅
Data STRING(20) ! ✅
Null BYTE ! ✅
Throw PROCEDURE ! ✅ (ABC's own classes have a Throw method)NULL as the name of a PROCEDURE or method builds with a warning — see SELF, PARENT and NULL are intrinsics.
The help's second list — APPLICATION, CLASS, DETAIL, FILE, FOOTER, FORM, GROUP, HEADER, ITEM, ITEMIZE, JOIN, MAP, MENU, MENUBAR, MODULE, OLE, OPTION, QUEUE, PARENT, RECORD, REPORT, SELF, SHEET, TAB, TOOLBAR, VIEW, WINDOW — says these may label data but not a PROCEDURE. Neither compiler enforces that: all 27 build in every place tested, a global PROCEDURE's label included.
MAP
Window PROCEDURE ! ✅ builds
END
Window PROCEDURE
CODEThe test declares such a PROCEDURE and does not call it. Calling a procedure named Window or Class may be awkward; declaring it is legal.
SELF, PARENT and NULL are what the compiler calls system intrinsics. Reusing one compiles, but with a warning; for SELF and PARENT the new name then hides the intrinsic (a procedure named Null did not stop Ref &= NULL compiling — checked at compile time only):
| Where | Warning |
|---|---|
| SELF or PARENT as a method's parameter or local variable |
Redefining system intrinsic: SELF / PARENT
|
| NULL as the name of a PROCEDURE or method | Redefining system intrinsic: NULL |
Everywhere else — global or local data, a GROUP field, a global PROCEDURE named Self or Parent — they build with no warning.
The hiding is real. Inside a method that declares a Self local, SELF means that local, not the object:
Shape.Fill PROCEDURE
Self LONG ! ⚠️ Redefining system intrinsic: SELF
CODE
SELF.Draw(1) ! ❌ Field not found: DRAW / Unknown procedure labelOther methods of the class keep the real SELF. So the help's advice that SELF and PARENT should not name a method's locals or parameters is right in effect — "cannot" is just not what happens.
The reserved keyword labels diagnostic (clarion.diagnostics.reservedKeywordLabels) reports one of the 44 words used as a label — followed by a declaration — wherever it stands, inside a GROUP or CLASS as much as outside. It does not report parameter names, statements that start with a reserved word in column 1, colon-prefixed labels, or any of the words that are not reserved.