From c189da36719d93491eba3118e83cc6d270a7ce56 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 14 Oct 2023 15:38:54 -0700 Subject: [PATCH] Finalize the X Macro article Signed-off-by: Danila Fedorin --- content/blog/chapel_x_macros.md | 24 ++++++++++++------------ content/blog/dyno_alloy/index.md | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/content/blog/chapel_x_macros.md b/content/blog/chapel_x_macros.md index 728a0eb..cd42d84 100644 --- a/content/blog/chapel_x_macros.md +++ b/content/blog/chapel_x_macros.md @@ -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 diff --git a/content/blog/dyno_alloy/index.md b/content/blog/dyno_alloy/index.md index 283ca60..1343622 100644 --- a/content/blog/dyno_alloy/index.md +++ b/content/blog/dyno_alloy/index.md @@ -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." ---