Finalize the X Macro article
Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
This commit is contained in:
parent
dd232cedb5
commit
c189da3671
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
title: "My Favorite C++ Pattern: X Macros"
|
||||
date: 2023-10-09T15:06:11-07:00
|
||||
draft: true
|
||||
tags: ["C++", "Chapel", "Compilers"]
|
||||
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
|
||||
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
|
||||
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)
|
||||
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
|
||||
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).
|
||||
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.
|
||||
|
||||
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...
|
||||
{{< /githubsnippet >}}
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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 >}}
|
||||
struct GlobalStrings {
|
||||
|
@ -150,8 +149,8 @@ that _use_ the compiler. I'll go through the use cases in turn.
|
|||
|
||||
#### Tags and Dynamic Casting
|
||||
First, to deal with a general absence of
|
||||
[RTTI](https://en.wikipedia.org/wiki/Run-time_type_information), it is used
|
||||
to declare an "tag" enum. Each AST node has a tag matching its class;
|
||||
[RTTI](https://en.wikipedia.org/wiki/Run-time_type_information), the hierarchy header
|
||||
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`.
|
||||
Note that for parent classes (defined via `BEGIN_SUBCLASSES`), we actually
|
||||
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
|
||||
`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`
|
||||
here for brevity (its definition is very simple), and include only
|
||||
`toWhateverNode`.
|
||||
|
@ -288,7 +287,7 @@ random snippet of code I pulled out:
|
|||
Thus, developers adding new AST nodes are not required to manually implement
|
||||
the `isWhatever`, `toWhatever`, and other functions. This and a fair bit
|
||||
of other AST functionality (which I will cover in the next subsection) is
|
||||
automatically generating using X Macros.
|
||||
automatically generated using X Macros.
|
||||
|
||||
{{< dialog >}}
|
||||
{{< message "question" "reader" >}}
|
||||
|
@ -599,7 +598,8 @@ struct PerNodeInfo {
|
|||
};
|
||||
{{< /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++
|
||||
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
|
||||
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
|
||||
`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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
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"]
|
||||
description: "In this post, I apply Alloy to a piece of code in the Chapel compiler to find a bug."
|
||||
---
|
||||
|
|
Loading…
Reference in New Issue
Block a user