Compile-Time Evaluation
XXML supports compile-time evaluation, allowing expressions to be computed during compilation rather than at runtime. This enables constant folding, type-safe compile-time constants, and optimization opportunities.
Basic Syntax
Use the Compiletime keyword after Instantiate to declare a compile-time constant:
Instantiate Compiletime Integer^ As <x> = Integer::Constructor(10);
Instantiate Compiletime Bool^ As <flag> = Bool::Constructor(true);
Instantiate Compiletime String^ As <name> = String::Constructor("Hello");Supported Types
The following built-in types are declared as Compiletime classes and support compile-time evaluation:
| Type | Description |
|---|---|
Integer | 64-bit signed integers |
Float | 32-bit floating point |
Double | 64-bit floating point |
Bool | Boolean values |
String | String values |
Compile-Time Operations
Integer Methods
Instantiate Compiletime Integer^ As <x> = Integer::Constructor(10);
Instantiate Compiletime Integer^ As <y> = Integer::Constructor(5);
// Arithmetic
Instantiate Compiletime Integer^ As <sum> = x.add(y); // 15
Instantiate Compiletime Integer^ As <diff> = x.subtract(y); // 5
Instantiate Compiletime Integer^ As <prod> = x.multiply(y); // 50
Instantiate Compiletime Integer^ As <quot> = x.divide(y); // 2
Instantiate Compiletime Integer^ As <rem> = x.modulo(y); // 0
// Comparisons (return Bool)
Instantiate Compiletime Bool^ As <eq> = x.equals(y); // false
Instantiate Compiletime Bool^ As <lt> = x.lessThan(y); // false
Instantiate Compiletime Bool^ As <gt> = x.greaterThan(y); // true
// Properties
Instantiate Compiletime Bool^ As <isZ> = x.isZero(); // false
Instantiate Compiletime Bool^ As <isP> = x.isPositive(); // true
Instantiate Compiletime Bool^ As <isE> = x.isEven(); // true
// Conversions
Instantiate Compiletime String^ As <str> = x.toString(); // "10"Bool Methods
Instantiate Compiletime Bool^ As <a> = Bool::Constructor(true);
Instantiate Compiletime Bool^ As <b> = Bool::Constructor(false);
// Logical operations
Instantiate Compiletime Bool^ As <notA> = a.not(); // false
Instantiate Compiletime Bool^ As <andR> = a.and(b); // false
Instantiate Compiletime Bool^ As <orR> = a.or(b); // true
Instantiate Compiletime Bool^ As <xorR> = a.xor(b); // true
// Conversions
Instantiate Compiletime String^ As <str> = a.toString(); // "true"
Instantiate Compiletime Integer^ As <int> = a.toInteger(); // 1String Methods
Instantiate Compiletime String^ As <s> = String::Constructor("Hello World");
// Properties
Instantiate Compiletime Integer^ As <len> = s.length(); // 11
Instantiate Compiletime Bool^ As <empty> = s.isEmpty(); // false
// Transformations
Instantiate Compiletime String^ As <up> = s.toUpperCase(); // "HELLO WORLD"
Instantiate Compiletime String^ As <lo> = s.toLowerCase(); // "hello world"
Instantiate Compiletime String^ As <rv> = s.reverse(); // "dlroW olleH"
// String operations
Instantiate Compiletime String^ As <cat> = s.append(String::Constructor("!"));
Instantiate Compiletime Bool^ As <has> = s.contains(String::Constructor("World"));
Instantiate Compiletime Integer^ As <idx> = s.indexOf(String::Constructor("o"));Chained Operations
Compile-time operations can be chained:
Instantiate Compiletime Integer^ As <a> = Integer::Constructor(2);
Instantiate Compiletime Integer^ As <b> = Integer::Constructor(3);
Instantiate Compiletime Integer^ As <c> = Integer::Constructor(4);
// (a + b) * c = (2 + 3) * 4 = 20
Instantiate Compiletime Integer^ As <result> = a.add(b).multiply(c);Note
Mixed Compile-Time and Runtime
Compile-time values can be used with runtime values:
Instantiate Compiletime Integer^ As <factor> = Integer::Constructor(10);
Instantiate Integer^ As <runtime> = Integer::Constructor(5);
// Compile-time value used in runtime expression
Instantiate Integer^ As <result> = runtime.multiply(factor); // 50User-Defined Compile-Time Classes
Classes can be marked as Compiletime to enable full compile-time constructor and method evaluation:
[ Class <Point> Compiletime Final Extends None
[ Private <>
Property <x> Types Integer^;
Property <y> Types Integer^;
]
[ Public <>
Constructor = default;
Constructor Parameters (
Parameter <px> Types Integer^,
Parameter <py> Types Integer^
) -> {
Set x = px;
Set y = py;
}
Method <getX> Returns Integer^ Parameters () -> {
Return x;
}
Method <getY> Returns Integer^ Parameters () -> {
Return y;
}
]
]
[ Entrypoint
{
// Create Point at compile-time
Instantiate Compiletime Point^ As <p> = Point::Constructor(
Integer::Constructor(10),
Integer::Constructor(20)
);
// These method calls are evaluated at compile-time!
Run Console::printLine(String::Constructor("x = ").append(p.getX().toString()));
Run Console::printLine(String::Constructor("y = ").append(p.getY().toString()));
Exit(0);
}
]Generated LLVM IR
The above code generates optimized IR where method calls are completely eliminated:
; String constants directly embedded - no runtime method calls!
@.str.1 = private constant [5 x i8] c"x = \00"
@.str.2 = private constant [3 x i8] c"10\00" ; p.getX().toString() folded to "10"
@.str.3 = private constant [5 x i8] c"y = \00"
@.str.4 = private constant [3 x i8] c"20\00" ; p.getY().toString() folded to "20"
define i32 @main() {
; No Point_getX, Point_getY, or Integer_toString calls!
%ct.str = call ptr @String_Constructor(ptr @.str.2)
; ...
}Compile-Time Methods
Individual methods can be marked as compile-time:
[ Class <Math> Final Extends None
[ Public <>
Method <factorial> Compiletime Returns Integer^ Parameters (
Parameter <n> Types Integer^
) Do {
If (n.lessOrEqual(Integer::Constructor(1))) -> {
Return Integer::Constructor(1);
}
Return n.multiply(factorial(n.subtract(Integer::Constructor(1))));
}
]
]Benefits
- Performance: Expressions computed at compile-time have zero runtime overhead
- Type Safety: Compile-time evaluation catches errors during compilation
- Optimization: The compiler can optimize based on known constant values
- Code Clarity: Clearly marks values that are constant throughout execution
Tip
Supported Statements
The following statement types are supported in compile-time method/constructor bodies:
| Statement | Description |
|---|---|
Set x = expr | Property or variable assignment |
Instantiate Type As <var> = expr | Local variable declaration |
Return expr | Return statement |
Run expr | Expression statement |
Limitations
- Compile-time values must be initialized with compile-time evaluable expressions
- I/O operations cannot be performed at compile-time
- Compile-time class methods must have deterministic behavior
- Recursive compile-time methods have depth limits to prevent infinite loops
- External/native functions cannot be called at compile-time
- Control flow statements (
If,While,For) in compile-time methods are not yet supported
Next Steps
Learn about Types for more information about XXML's type system, or explore Advanced Topics for more compiler features.