Finalize the X Macro article

Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
This commit is contained in:
Danila Fedorin 2023-10-14 15:38:54 -07:00
parent dd232cedb5
commit c189da3671
2 changed files with 13 additions and 13 deletions

View File

@ -1,7 +1,6 @@
--- ---
title: "My Favorite C++ Pattern: X Macros" title: "My Favorite C++ Pattern: X Macros"
date: 2023-10-09T15:06:11-07:00 date: 2023-10-09T15:06:11-07:00
draft: true
tags: ["C++", "Chapel", "Compilers"] tags: ["C++", "Chapel", "Compilers"]
description: "In this post, I talk about my favorite C/C++ pattern involving macros." description: "In this post, I talk about my favorite C/C++ pattern involving macros."
--- ---
@ -12,7 +11,7 @@ then, I've used the pattern many more times, and have been very satisfied with
how it turned out. However, it feels like the pattern is relatively unknown, so how it turned out. However, it feels like the pattern is relatively unknown, so
I thought I'd show it off, and some of its applications in the I thought I'd show it off, and some of its applications in the
[Chapel compiler](https://github.com/chapel-lang/chapel/). I've slightly tweaked [Chapel compiler](https://github.com/chapel-lang/chapel/). I've slightly tweaked
a lot of the snippets I directly present in this article for the sake of simpler a lot of the snippets I directly show in this article for the sake of simpler
presentation; I've included links to the original code (available on GitHub) presentation; I've included links to the original code (available on GitHub)
if you want to see the unabridged version. if you want to see the unabridged version.
@ -44,7 +43,7 @@ returned. Some strings, however, occur a lot in the compiler, to the point that
it would be inefficient to perform the whole "find-or-create" operation every it would be inefficient to perform the whole "find-or-create" operation every
time. One example is the `"this"` string, which is an identifier with a lot of time. One example is the `"this"` string, which is an identifier with a lot of
special behavior in the language (much like `this` in languages such as Java). special behavior in the language (much like `this` in languages such as Java).
To support these frequent flier strings, the compiler initializes them once, To support such frequent flier strings, the compiler initializes them once,
and creates a variable per-string that can be accessed to get that string's value. and creates a variable per-string that can be accessed to get that string's value.
There's that repetitive code. Defining a brand new variable for each string, There's that repetitive code. Defining a brand new variable for each string,
@ -75,11 +74,11 @@ X(bytes , "bytes")
// A lot more of these... // A lot more of these...
{{< /githubsnippet >}} {{< /githubsnippet >}}
What's This `X` thing? That right there is the essence of the pattern: the macro What's this `X` thing? That right there is the essence of the pattern: the macro
`X` _isn't defined in the header!_. Effectively, `all-global-strings.h` is just `X` _isn't defined in the header!_ Effectively, `all-global-strings.h` is just
a list, and we can "iterate" over this list to generate some code for each a list, and we can "iterate" over this list to generate some code for each
one of its elements, in as many places as we want. What I mean by this is one of its elements, in as many places as we want. What I mean by this is
that we can then write code like this: that we can then write code like the following:
{{< githubsnippet "chapel-lang/chapel" "cd108338d321d0b3edf6258e0b2a58459d88a348" "frontend/include/chpl/framework/global-strings.h" "C++" 76 >}} {{< githubsnippet "chapel-lang/chapel" "cd108338d321d0b3edf6258e0b2a58459d88a348" "frontend/include/chpl/framework/global-strings.h" "C++" 76 >}}
struct GlobalStrings { struct GlobalStrings {
@ -150,8 +149,8 @@ that _use_ the compiler. I'll go through the use cases in turn.
#### Tags and Dynamic Casting #### Tags and Dynamic Casting
First, to deal with a general absence of First, to deal with a general absence of
[RTTI](https://en.wikipedia.org/wiki/Run-time_type_information), it is used [RTTI](https://en.wikipedia.org/wiki/Run-time_type_information), the hierarchy header
to declare an "tag" enum. Each AST node has a tag matching its class; is used to declare a "tag" enum. Each AST node has a tag matching its class;
this allows us inspect the AST and perform safe casts similar to `dynamic_cast`. this allows us inspect the AST and perform safe casts similar to `dynamic_cast`.
Note that for parent classes (defined via `BEGIN_SUBCLASSES`), we actually Note that for parent classes (defined via `BEGIN_SUBCLASSES`), we actually
end up creating _two_ tags: one `START_...` and one `END_...`. The reason end up creating _two_ tags: one `START_...` and one `END_...`. The reason
@ -240,7 +239,7 @@ isLoop(AstTag::While) // Returns true; a 'while' loop is a loop.
``` ```
On the top-level AST node class, we generate `isWhateverNode` and On the top-level AST node class, we generate `isWhateverNode` and
`toWhateverNode` for each AST class. Thus, user code is able to inspect the `toWhateverNode` for each AST subclass. Thus, user code is able to inspect the
AST and perform (checked) casts using plain methods. I omit `isWhateverNode` AST and perform (checked) casts using plain methods. I omit `isWhateverNode`
here for brevity (its definition is very simple), and include only here for brevity (its definition is very simple), and include only
`toWhateverNode`. `toWhateverNode`.
@ -288,7 +287,7 @@ random snippet of code I pulled out:
Thus, developers adding new AST nodes are not required to manually implement Thus, developers adding new AST nodes are not required to manually implement
the `isWhatever`, `toWhatever`, and other functions. This and a fair bit the `isWhatever`, `toWhatever`, and other functions. This and a fair bit
of other AST functionality (which I will cover in the next subsection) is of other AST functionality (which I will cover in the next subsection) is
automatically generating using X Macros. automatically generated using X Macros.
{{< dialog >}} {{< dialog >}}
{{< message "question" "reader" >}} {{< message "question" "reader" >}}
@ -599,7 +598,8 @@ struct PerNodeInfo {
}; };
{{< /githubsnippet >}} {{< /githubsnippet >}}
Then, when I need to add methods, I do something like the following: Then, when I need to add methods, I use template specialization by writing
something like the following:
```C++ ```C++
template <> template <>
@ -673,7 +673,7 @@ unfortunate remnants of C++'s past. However, I think that what I've demonstrated
demonstrates the versatility of the X Macro pattern -- feel free to apply it to demonstrates the versatility of the X Macro pattern -- feel free to apply it to
the degree that you find appropriate. the degree that you find appropriate.
The thing I like the most pattern is that the header files read quite nicely: The thing I like the most about this pattern is that the header files read quite nicely:
you end up with a very declarative "scaffold" of what's going on. The you end up with a very declarative "scaffold" of what's going on. The
`uast-classes-list.h` makes for an excellent and fairly readable reference of `uast-classes-list.h` makes for an excellent and fairly readable reference of
all the AST nodes in the Chapel compiler. The `method-tables.h` header provides all the AST nodes in the Chapel compiler. The `method-tables.h` header provides

View File

@ -1,6 +1,6 @@
--- ---
title: "Proving My Compiler Code Incorrect With Alloy" title: "Proving My Compiler Code Incorrect With Alloy"
date: 2023-06-04T21:56:00-07:00 date: 2023-10-14T15:38:17-07:00
tags: ["Chapel", "Compilers", "Alloy"] tags: ["Chapel", "Compilers", "Alloy"]
description: "In this post, I apply Alloy to a piece of code in the Chapel compiler to find a bug." description: "In this post, I apply Alloy to a piece of code in the Chapel compiler to find a bug."
--- ---