This would allow users to better structure and organize their code by aliasing common values with custom constants, not merely relying on system provided constants.
Example showing the definition of one global user-defined constant FOO with value 12, and three user-defined constants in def 0, where BAR has the value of a const string "Hello", BAZ has the value 12 (via global FOO) and BUZZ has the value of a system-defined constant ACTOR_ONE.
The compiler API compiles myOperation to be equivalent with: myOperation("Hello", 12, 12, ACTOR_ONE, OBJECT_TWO);
Language Changes
Parser and Lexer Changes
New syntax for the const statement is needed. This syntax may be allowed wherever a statement is allowed in a routine as well as outside of routines. Any IDENTIFIER is allowed for the name of a user-defined constant. Any primitive can be assigned to a constant.
User-defined constants are matched with primitive's IDENTIFIERs, so no parser changes are needed here.
Behaviour
User-defined constants are evaluated when they are collected. They are collected in their scope, before their scope is processed. They are collected top-down inside their scope:
For outside of routines, user-defined constants are collected and evaluated after imports have been processed. All these constants are globally visible.
For inside of routines (or macros), the user-defined constants are evaluated before any operation in the routine are evaluated (INCLUDING MACRO CALLS). These are scoped to the routine/macro and take precedence over globally scoped user-defined constants.
If a user-defined constant is defined multiple times with the same name in the same scope, it's value is overwritten.
Whenever the compiler encounters an IDENTIFIER in a primitive, it will first look up user-defined constants in the current scope. If found, it is immediately replaced with its evaluated value with the value of the constant. If no user-defined constant is found, the compiler assumes a system-defined constant is meant.
When a user-defined constant is assigned an IDENTIFIER, the same lookup rules as described above are performed. Only user-
defined constants from outer scopes or previously defined inside the same scope can be used to be assigned to a user-defined constant, otherwise it will be interpreted as a system defined constant. See this example (evaluation order and result is given in the comments):
const EXAMPLE = 1; // Evaluated 1st: Evaluates to integer 1
def 0 {
const FOO = FUZZ; // Evaluated 3rd: Evaluates to system-defined constant FUZZ
const BAR = BAZ; // Evaluated 4th: Evaluates to system-defined constant FOOBAR (via globally scoped user-defined const. BAZ)
const FUZZ = BAR; // Evaluated 5th: Evaluates to system-defined constant FOOBAR (via locally scoped BAR -> globally scoped BAZ)
}
const BAZ = FOOBAR; // Evaluated 2nd: Evaluates to system-defined constant FOOBAR
Compiler Implementation
Compiler Interface Changes
No changes.
Decompiler Changes
No changes.
How to teach
First two new terms need to be established to replace "constants":
System-defined constants are provided by to the API/CLI of ExplorerScript's compiler or decompiler and are not processed at all by ExplorerScript itself. These values are transparently handled and unchanged in the respective output. The caller of the compiler/decompiler must verify if returned system-defined constants are actually valid. These were known as constants before this PR. System-defined constants are a primitive.
User-defined constants are defined using the const keyword in ExplorerScript source code. They are evaluated at compile time into primitives. The CLI/API of the compiler/decompiler replaces these constants with their primitive value.
The documentation must be updated to explain the difference between user-defined and system-defined constants and additionally contain a section on defining user-defined constants. It must not go into too many details about compile-time behavior differences in the main text but should do so in an admonition.
After this change the documentation must not mention "constants" anymore, it must always mention "user-defined" or "system-defined" constants as described above. An exception are places where both are treated equality, there they may be grouped under the term "constants".
Alternatives
Quite a few variations could be thought of, in both syntax and evaluation. This seems to be the most sensible.
Summary
Add user-defined constants defined at compile time by the ExplorerScript compiler itself. These are scoped globally or to their routine/macro.
This proposal talks about "user-defined constants" and "system-defined constants", replacing the term "constants". See "How to teach" for defintions.
Dependencies
Motivation
This would allow users to better structure and organize their code by aliasing common values with custom constants, not merely relying on system provided constants.
Examples
Example showing the definition of one global user-defined constant
FOO
with value 12, and three user-defined constants indef 0
, whereBAR
has the value of a const string "Hello",BAZ
has the value 12 (via globalFOO
) andBUZZ
has the value of a system-defined constant ACTOR_ONE. The compiler API compiles myOperation to be equivalent with:myOperation("Hello", 12, 12, ACTOR_ONE, OBJECT_TWO);
Language Changes
Parser and Lexer Changes
New syntax for the const statement is needed. This syntax may be allowed wherever a statement is allowed in a routine as well as outside of routines. Any
IDENTIFIER
is allowed for the name of a user-defined constant. Anyprimitive
can be assigned to a constant. User-defined constants are matched withprimitive
'sIDENTIFIER
s, so no parser changes are needed here.Behaviour
User-defined constants are evaluated when they are collected. They are collected in their scope, before their scope is processed. They are collected top-down inside their scope:
If a user-defined constant is defined multiple times with the same name in the same scope, it's value is overwritten.
Whenever the compiler encounters an
IDENTIFIER
in aprimitive
, it will first look up user-defined constants in the current scope. If found, it is immediately replaced with its evaluated value with the value of the constant. If no user-defined constant is found, the compiler assumes a system-defined constant is meant.When a user-defined constant is assigned an
IDENTIFIER
, the same lookup rules as described above are performed. Only user- defined constants from outer scopes or previously defined inside the same scope can be used to be assigned to a user-defined constant, otherwise it will be interpreted as a system defined constant. See this example (evaluation order and result is given in the comments):Compiler Implementation
Compiler Interface Changes
No changes.
Decompiler Changes
No changes.
How to teach
First two new terms need to be established to replace "constants":
primitive
.const
keyword in ExplorerScript source code. They are evaluated at compile time into primitives. The CLI/API of the compiler/decompiler replaces these constants with their primitive value.The documentation must be updated to explain the difference between user-defined and system-defined constants and additionally contain a section on defining user-defined constants. It must not go into too many details about compile-time behavior differences in the main text but should do so in an admonition.
After this change the documentation must not mention "constants" anymore, it must always mention "user-defined" or "system-defined" constants as described above. An exception are places where both are treated equality, there they may be grouped under the term "constants".
Alternatives
Quite a few variations could be thought of, in both syntax and evaluation. This seems to be the most sensible.
Backwards compatibility
This is fully backwards compatible.