LALR parsers works from inner-to-outer. So, in this example, the field is constructed before the struct is:
struct S {
inner: bool,
}
This is great for Slice definitions, where we don't want to null-initialize a bunch of data, then set it later.
But, it's a problem for the preprocessor, because it means that inner directives (that should be skipped) are still executed:
#if UNDEFINED
#define FOO // This is defined when it shouldn't be!
#endif
Because the inner expressions are run first, before the preprocessor even checks the outer condition.
This PR fixes this by no longer performing actions during parsing. Instead, the preprocessor works more like the Slice parser. It builds up a mini-AST for itself, then we traverse the AST once we have complete information. During traversal we evaluate these conditionals, and only visit the contents of those that are true.
LALR parsers works from inner-to-outer. So, in this example, the field is constructed before the struct is:
This is great for Slice definitions, where we don't want to null-initialize a bunch of data, then set it later.
But, it's a problem for the preprocessor, because it means that inner directives (that should be skipped) are still executed:
Because the inner expressions are run first, before the preprocessor even checks the outer condition.
This PR fixes this by no longer performing actions during parsing. Instead, the preprocessor works more like the Slice parser. It builds up a mini-AST for itself, then we traverse the AST once we have complete information. During traversal we evaluate these conditionals, and only visit the contents of those that are true.