ext_php_rs/
flags.rs

1//! Flags and enums used in PHP and the Zend engine.
2
3use bitflags::bitflags;
4
5#[cfg(php81)]
6use crate::ffi::ZEND_ACC_ENUM;
7#[cfg(not(php82))]
8use crate::ffi::ZEND_ACC_REUSE_GET_ITERATOR;
9use crate::ffi::{
10    _IS_BOOL, CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR,
11    E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE,
12    E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
13    E_WARNING, GC_IMMUTABLE, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE,
14    IS_INDIRECT, IS_ITERABLE, IS_LONG, IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE,
15    IS_RESOURCE, IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID,
16    PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER, Z_TYPE_FLAGS_SHIFT,
17    ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED,
18    ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED,
19    ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL,
20    ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK, ZEND_ACC_HAS_RETURN_TYPE,
21    ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
22    ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
23    ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
24    ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
25    ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES,
26    ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE,
27    ZEND_ACC_USE_GUARDS, ZEND_ACC_USES_THIS, ZEND_ACC_VARIADIC, ZEND_EVAL_CODE,
28    ZEND_HAS_STATIC_IN_METHODS, ZEND_INTERNAL_FUNCTION, ZEND_USER_FUNCTION,
29};
30
31use std::{convert::TryFrom, fmt::Display};
32
33use crate::error::{Error, Result};
34
35bitflags! {
36    /// Flags used for setting the type of Zval.
37    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
38    pub struct ZvalTypeFlags: u32 {
39        /// Undefined
40        const Undef = IS_UNDEF;
41        /// Null
42        const Null = IS_NULL;
43        /// `false`
44        const False = IS_FALSE;
45        /// `true`
46        const True = IS_TRUE;
47        /// Integer
48        const Long = IS_LONG;
49        /// Floating point number
50        const Double = IS_DOUBLE;
51        /// String
52        const String = IS_STRING;
53        /// Array
54        const Array = IS_ARRAY;
55        /// Object
56        const Object = IS_OBJECT;
57        /// Resource
58        const Resource = IS_RESOURCE;
59        /// Reference
60        const Reference = IS_REFERENCE;
61        /// Callable
62        const Callable = IS_CALLABLE;
63        /// Constant expression
64        const ConstantExpression = IS_CONSTANT_AST;
65        /// Void
66        const Void = IS_VOID;
67        /// Pointer
68        const Ptr = IS_PTR;
69        /// Iterable
70        const Iterable = IS_ITERABLE;
71
72        /// Interned string extended
73        const InternedStringEx = Self::String.bits();
74        /// String extended
75        const StringEx = Self::String.bits() | Self::RefCounted.bits();
76        /// Array extended
77        const ArrayEx = Self::Array.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
78        /// Object extended
79        const ObjectEx = Self::Object.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
80        /// Resource extended
81        const ResourceEx = Self::Resource.bits() | Self::RefCounted.bits();
82        /// Reference extended
83        const ReferenceEx = Self::Reference.bits() | Self::RefCounted.bits();
84        /// Constant ast extended
85        const ConstantAstEx = Self::ConstantExpression.bits() | Self::RefCounted.bits();
86
87        /// Reference counted
88        const RefCounted = (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT);
89        /// Collectable
90        const Collectable = (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT);
91
92        /// Immutable (used for the shared empty array)
93        const Immutable = GC_IMMUTABLE;
94    }
95}
96
97bitflags! {
98    /// Flags for building classes.
99    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
100    pub struct ClassFlags: u32 {
101        /// Final class or method
102        const Final = ZEND_ACC_FINAL;
103        /// Abstract method
104        const Abstract = ZEND_ACC_ABSTRACT;
105        /// Immutable `op_array` and class_entries
106        /// (implemented only for lazy loading of `op_array`s)
107        const Immutable = ZEND_ACC_IMMUTABLE;
108        /// Function has typed arguments / class has typed props
109        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
110        /// Top-level class or function declaration
111        const TopLevel = ZEND_ACC_TOP_LEVEL;
112        /// op_array or class is preloaded
113        const Preloaded = ZEND_ACC_PRELOADED;
114
115        /// Class entry is an interface
116        const Interface = ZEND_ACC_INTERFACE;
117        /// Class entry is a trait
118        const Trait = ZEND_ACC_TRAIT;
119        /// Anonymous class
120        const AnonymousClass = ZEND_ACC_ANON_CLASS;
121        /// Class is an Enum
122        #[cfg(php81)]
123        const Enum = ZEND_ACC_ENUM;
124        /// Class linked with parent, interfaces and traits
125        const Linked = ZEND_ACC_LINKED;
126        /// Class is abstract, since it is set by any abstract method
127        const ImplicitAbstractClass = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
128        /// Class has magic methods `__get`/`__set`/`__unset`/`__isset` that use guards
129        const UseGuards = ZEND_ACC_USE_GUARDS;
130
131        /// Class constants updated
132        const ConstantsUpdated = ZEND_ACC_CONSTANTS_UPDATED;
133        /// Objects of this class may not have dynamic properties
134        const NoDynamicProperties = ZEND_ACC_NO_DYNAMIC_PROPERTIES;
135        /// User class has methods with static variables
136        const HasStaticInMethods = ZEND_HAS_STATIC_IN_METHODS;
137        /// Children must reuse parent `get_iterator()`
138        #[cfg(not(php82))]
139        const ReuseGetIterator = ZEND_ACC_REUSE_GET_ITERATOR;
140        /// Parent class is resolved (CE)
141        const ResolvedParent = ZEND_ACC_RESOLVED_PARENT;
142        /// Interfaces are resolved (CE)
143        const ResolvedInterfaces = ZEND_ACC_RESOLVED_INTERFACES;
144        /// Class has unresolved variance obligations
145        const UnresolvedVariance = ZEND_ACC_UNRESOLVED_VARIANCE;
146        /// Class is linked apart from variance obligations
147        const NearlyLinked = ZEND_ACC_NEARLY_LINKED;
148
149        /// Class cannot be serialized or unserialized
150        #[cfg(php81)]
151        const NotSerializable = crate::ffi::ZEND_ACC_NOT_SERIALIZABLE;
152    }
153}
154
155bitflags! {
156    /// Flags for building methods.
157    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
158    pub struct MethodFlags: u32 {
159        /// Visibility public
160        const Public = ZEND_ACC_PUBLIC;
161        /// Visibility protected
162        const Protected = ZEND_ACC_PROTECTED;
163        /// Visibility private
164        const Private = ZEND_ACC_PRIVATE;
165        /// Method or property overrides private one
166        const Changed = ZEND_ACC_CHANGED;
167        /// Static method
168        const Static = ZEND_ACC_STATIC;
169        /// Final method
170        const Final = ZEND_ACC_FINAL;
171        /// Abstract method
172        const Abstract = ZEND_ACC_ABSTRACT;
173        /// Immutable `op_array` and class_entries
174        /// (implemented only for lazy loading of op_arrays)
175        const Immutable = ZEND_ACC_IMMUTABLE;
176        /// Function has typed arguments / class has typed props
177        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
178        /// Top-level class or function declaration
179        const TopLevel = ZEND_ACC_TOP_LEVEL;
180        /// `op_array` or class is preloaded
181        const Preloaded = ZEND_ACC_PRELOADED;
182
183        /// Deprecation flag
184        const Deprecated = ZEND_ACC_DEPRECATED;
185        /// Function returning by reference
186        const ReturnReference = ZEND_ACC_RETURN_REFERENCE;
187        /// Function has a return type
188        const HasReturnType = ZEND_ACC_HAS_RETURN_TYPE;
189        /// Function with variable number of arguments
190        const Variadic = ZEND_ACC_VARIADIC;
191        /// `op_array` has finally blocks (user only)
192        const HasFinallyBlock = ZEND_ACC_HAS_FINALLY_BLOCK;
193        /// "main" `op_array` with `ZEND_DECLARE_CLASS_DELAYED` opcodes
194        const EarlyBinding = ZEND_ACC_EARLY_BINDING;
195        /// Closure uses `$this`
196        const UsesThis = ZEND_ACC_USES_THIS;
197        /// Call through user function trampoline
198        ///
199        /// # Example
200        /// - `__call`
201        /// - `__callStatic`
202        const CallViaTrampoline = ZEND_ACC_CALL_VIA_TRAMPOLINE;
203        /// Disable inline caching
204        const NeverCache = ZEND_ACC_NEVER_CACHE;
205        /// `op_array` is a clone of trait method
206        const TraitClone = ZEND_ACC_TRAIT_CLONE;
207        /// Function is a constructor
208        const IsConstructor = ZEND_ACC_CTOR;
209        /// Function is a closure
210        const Closure = ZEND_ACC_CLOSURE;
211        /// Function is a fake closure
212        const FakeClosure = ZEND_ACC_FAKE_CLOSURE;
213        /// Function is a generator
214        const Generator = ZEND_ACC_GENERATOR;
215        /// Function was processed by pass two (user only)
216        const DonePassTwo = ZEND_ACC_DONE_PASS_TWO;
217        /// `run_time_cache` allocated on heap (user only)
218        const HeapRTCache = ZEND_ACC_HEAP_RT_CACHE;
219        /// `op_array` uses strict mode types
220        const StrictTypes = ZEND_ACC_STRICT_TYPES;
221    }
222}
223
224bitflags! {
225    /// Flags for building properties.
226    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
227    pub struct PropertyFlags: u32 {
228        /// Visibility public
229        const Public = ZEND_ACC_PUBLIC;
230        /// Visibility protected
231        const Protected = ZEND_ACC_PROTECTED;
232        /// Visibility private
233        const Private = ZEND_ACC_PRIVATE;
234        /// Property or method overrides private one
235        const Changed = ZEND_ACC_CHANGED;
236        /// Static property
237        const Static = ZEND_ACC_STATIC;
238        /// Promoted property
239        const Promoted = ZEND_ACC_PROMOTED;
240    }
241}
242
243bitflags! {
244    /// Flags for building constants.
245    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
246    pub struct ConstantFlags: u32 {
247        /// Visibility public
248        const Public = ZEND_ACC_PUBLIC;
249        /// Visibility protected
250        const Protected = ZEND_ACC_PROTECTED;
251        /// Visibility private
252        const Private = ZEND_ACC_PRIVATE;
253        /// Promoted constant
254        const Promoted = ZEND_ACC_PROMOTED;
255    }
256}
257
258bitflags! {
259    /// Flags for building module global constants.
260    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
261    pub struct GlobalConstantFlags: u32 {
262        /// No longer used -- always case-sensitive
263        #[deprecated(note = "No longer used -- always case-sensitive")]
264        const CaseSensitive = CONST_CS;
265        /// Persistent
266        const Persistent = CONST_PERSISTENT;
267        /// Can't be saved in file cache
268        const NoFileCache = CONST_NO_FILE_CACHE;
269        /// Deprecated (this flag is not deprecated, it literally means the constant is deprecated)
270        const Deprecated = CONST_DEPRECATED;
271    }
272}
273
274bitflags! {
275    /// Represents the result of a function.
276    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
277    pub struct ZendResult: i32 {
278        /// Function call was successful.
279        const Success = 0;
280        /// Function call failed.
281        const Failure = -1;
282    }
283}
284
285bitflags! {
286    /// Represents permissions for where a configuration setting may be set.
287    pub struct IniEntryPermission: u32 {
288        /// User
289        const User = PHP_INI_USER;
290        /// Per directory
291        const PerDir = PHP_INI_PERDIR;
292        /// System
293        const System = PHP_INI_SYSTEM;
294        /// All
295        const All = PHP_INI_ALL;
296    }
297}
298
299bitflags! {
300    /// Represents error types when used via php_error_docref for example.
301    pub struct ErrorType: u32 {
302        /// Error
303        const Error = E_ERROR;
304        /// Warning
305        const Warning = E_WARNING;
306        /// Parse
307        const Parse = E_PARSE;
308        /// Notice
309        const Notice = E_NOTICE;
310        /// Core error
311        const CoreError = E_CORE_ERROR;
312        /// Core warning
313        const CoreWarning = E_CORE_WARNING;
314        /// Compile error
315        const CompileError = E_COMPILE_ERROR;
316        /// Compile warning
317        const CompileWarning = E_COMPILE_WARNING;
318        /// User error
319        #[cfg_attr(php84, deprecated = "`E_USER_ERROR` is deprecated since PHP 8.4. Throw an exception instead.")]
320        const UserError = E_USER_ERROR;
321        /// User warning
322        const UserWarning = E_USER_WARNING;
323        /// User notice
324        const UserNotice = E_USER_NOTICE;
325        /// Strict
326        const Strict = E_STRICT;
327        /// Recoverable error
328        const RecoverableError = E_RECOVERABLE_ERROR;
329        /// Deprecated
330        const Deprecated = E_DEPRECATED;
331        /// User deprecated
332        const UserDeprecated = E_USER_DEPRECATED;
333    }
334}
335
336/// Represents the type of a function.
337#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
338pub enum FunctionType {
339    /// Internal function
340    Internal,
341    /// User function
342    User,
343    /// Eval code
344    Eval,
345}
346
347impl From<u8> for FunctionType {
348    #[allow(clippy::bad_bit_mask)]
349    fn from(value: u8) -> Self {
350        match value.into() {
351            ZEND_INTERNAL_FUNCTION => Self::Internal,
352            ZEND_USER_FUNCTION => Self::User,
353            ZEND_EVAL_CODE => Self::Eval,
354            _ => panic!("Unknown function type: {value}"),
355        }
356    }
357}
358
359/// Valid data types for PHP.
360#[repr(C, u8)]
361#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
362pub enum DataType {
363    /// Undefined
364    Undef,
365    /// `null`
366    Null,
367    /// `false`
368    False,
369    /// `true`
370    True,
371    /// Integer (the irony)
372    Long,
373    /// Floating point number
374    Double,
375    /// String
376    String,
377    /// Array
378    Array,
379    /// Iterable
380    Iterable,
381    /// Object
382    Object(Option<&'static str>),
383    /// Resource
384    Resource,
385    /// Reference
386    Reference,
387    /// Callable
388    Callable,
389    /// Constant expression
390    ConstantExpression,
391    /// Void
392    #[default]
393    Void,
394    /// Mixed
395    Mixed,
396    /// Boolean
397    Bool,
398    /// Pointer
399    Ptr,
400    /// Indirect (internal)
401    Indirect,
402}
403
404impl DataType {
405    /// Returns the integer representation of the data type.
406    #[must_use]
407    pub const fn as_u32(&self) -> u32 {
408        match self {
409            DataType::Undef => IS_UNDEF,
410            DataType::Null => IS_NULL,
411            DataType::False => IS_FALSE,
412            DataType::True => IS_TRUE,
413            DataType::Long => IS_LONG,
414            DataType::Double => IS_DOUBLE,
415            DataType::String => IS_STRING,
416            DataType::Array => IS_ARRAY,
417            DataType::Object(_) => IS_OBJECT,
418            DataType::Resource | DataType::Reference => IS_RESOURCE,
419            DataType::Indirect => IS_INDIRECT,
420            DataType::Callable => IS_CALLABLE,
421            DataType::ConstantExpression => IS_CONSTANT_AST,
422            DataType::Void => IS_VOID,
423            DataType::Mixed => IS_MIXED,
424            DataType::Bool => _IS_BOOL,
425            DataType::Ptr => IS_PTR,
426            DataType::Iterable => IS_ITERABLE,
427        }
428    }
429}
430
431// TODO: Ideally want something like this
432// pub struct Type {
433//     data_type: DataType,
434//     is_refcounted: bool,
435//     is_collectable: bool,
436//     is_immutable: bool,
437//     is_persistent: bool,
438// }
439//
440// impl From<u32> for Type { ... }
441
442impl TryFrom<ZvalTypeFlags> for DataType {
443    type Error = Error;
444
445    fn try_from(value: ZvalTypeFlags) -> Result<Self> {
446        macro_rules! contains {
447            ($t: ident) => {
448                if value.contains(ZvalTypeFlags::$t) {
449                    return Ok(DataType::$t);
450                }
451            };
452        }
453
454        contains!(Undef);
455        contains!(Null);
456        contains!(False);
457        contains!(True);
458        contains!(False);
459        contains!(Long);
460        contains!(Double);
461        contains!(String);
462        contains!(Array);
463        contains!(Resource);
464        contains!(Callable);
465        contains!(ConstantExpression);
466        contains!(Void);
467
468        if value.contains(ZvalTypeFlags::Object) {
469            return Ok(DataType::Object(None));
470        }
471
472        Err(Error::UnknownDatatype(0))
473    }
474}
475
476impl From<u32> for DataType {
477    #[allow(clippy::bad_bit_mask)]
478    fn from(value: u32) -> Self {
479        macro_rules! contains {
480            ($c: ident, $t: ident) => {
481                if (value & $c) == $c {
482                    return DataType::$t;
483                }
484            };
485        }
486
487        contains!(IS_VOID, Void);
488        contains!(IS_PTR, Ptr);
489        contains!(IS_INDIRECT, Indirect);
490        contains!(IS_CALLABLE, Callable);
491        contains!(IS_CONSTANT_AST, ConstantExpression);
492        contains!(IS_REFERENCE, Reference);
493        contains!(IS_RESOURCE, Resource);
494        contains!(IS_ARRAY, Array);
495        contains!(IS_STRING, String);
496        contains!(IS_DOUBLE, Double);
497        contains!(IS_LONG, Long);
498        contains!(IS_TRUE, True);
499        contains!(IS_FALSE, False);
500        contains!(IS_NULL, Null);
501
502        if (value & IS_OBJECT) == IS_OBJECT {
503            return DataType::Object(None);
504        }
505
506        contains!(IS_UNDEF, Undef);
507
508        DataType::Mixed
509    }
510}
511
512impl Display for DataType {
513    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
514        match self {
515            DataType::Undef => write!(f, "Undefined"),
516            DataType::Null => write!(f, "Null"),
517            DataType::False => write!(f, "False"),
518            DataType::True => write!(f, "True"),
519            DataType::Long => write!(f, "Long"),
520            DataType::Double => write!(f, "Double"),
521            DataType::String => write!(f, "String"),
522            DataType::Array => write!(f, "Array"),
523            DataType::Object(obj) => write!(f, "{}", obj.as_deref().unwrap_or("Object")),
524            DataType::Resource => write!(f, "Resource"),
525            DataType::Reference => write!(f, "Reference"),
526            DataType::Callable => write!(f, "Callable"),
527            DataType::ConstantExpression => write!(f, "Constant Expression"),
528            DataType::Void => write!(f, "Void"),
529            DataType::Bool => write!(f, "Bool"),
530            DataType::Mixed => write!(f, "Mixed"),
531            DataType::Ptr => write!(f, "Pointer"),
532            DataType::Indirect => write!(f, "Indirect"),
533            DataType::Iterable => write!(f, "Iterable"),
534        }
535    }
536}
537
538#[cfg(test)]
539mod tests {
540    #![allow(clippy::unnecessary_fallible_conversions)]
541    use super::DataType;
542    use crate::ffi::{
543        IS_ARRAY, IS_ARRAY_EX, IS_CONSTANT_AST, IS_CONSTANT_AST_EX, IS_DOUBLE, IS_FALSE,
544        IS_INDIRECT, IS_INTERNED_STRING_EX, IS_LONG, IS_NULL, IS_OBJECT, IS_OBJECT_EX, IS_PTR,
545        IS_REFERENCE, IS_REFERENCE_EX, IS_RESOURCE, IS_RESOURCE_EX, IS_STRING, IS_STRING_EX,
546        IS_TRUE, IS_UNDEF, IS_VOID,
547    };
548    use std::convert::TryFrom;
549
550    #[test]
551    fn test_datatype() {
552        macro_rules! test {
553            ($c: ident, $t: ident) => {
554                assert_eq!(DataType::try_from($c), Ok(DataType::$t));
555            };
556        }
557
558        test!(IS_UNDEF, Undef);
559        test!(IS_NULL, Null);
560        test!(IS_FALSE, False);
561        test!(IS_TRUE, True);
562        test!(IS_LONG, Long);
563        test!(IS_DOUBLE, Double);
564        test!(IS_STRING, String);
565        test!(IS_ARRAY, Array);
566        assert_eq!(DataType::try_from(IS_OBJECT), Ok(DataType::Object(None)));
567        test!(IS_RESOURCE, Resource);
568        test!(IS_REFERENCE, Reference);
569        test!(IS_CONSTANT_AST, ConstantExpression);
570        test!(IS_INDIRECT, Indirect);
571        test!(IS_VOID, Void);
572        test!(IS_PTR, Ptr);
573
574        test!(IS_INTERNED_STRING_EX, String);
575        test!(IS_STRING_EX, String);
576        test!(IS_ARRAY_EX, Array);
577        assert_eq!(DataType::try_from(IS_OBJECT_EX), Ok(DataType::Object(None)));
578        test!(IS_RESOURCE_EX, Resource);
579        test!(IS_REFERENCE_EX, Reference);
580        test!(IS_CONSTANT_AST_EX, ConstantExpression);
581    }
582}