From 8196ab379495ab00c11b74b55b6f2fabd99ab351 Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Mon, 20 Sep 2021 23:01:35 -0400 Subject: Updates and fixes for the book. --- .../book/the_lux_programming_language/chapter_9.md | 119 +++++++-------------- 1 file changed, 36 insertions(+), 83 deletions(-) (limited to 'documentation/book/the_lux_programming_language/chapter_9.md') diff --git a/documentation/book/the_lux_programming_language/chapter_9.md b/documentation/book/the_lux_programming_language/chapter_9.md index 49ffe48bb..13d3c2462 100644 --- a/documentation/book/the_lux_programming_language/chapter_9.md +++ b/documentation/book/the_lux_programming_language/chapter_9.md @@ -1,6 +1,6 @@ # Chapter 9: Meta-programming -_Where we go meta. For real._ +_Where we take a peek behind the curtains of the compiler._ --- @@ -18,39 +18,49 @@ Instead, I'll reveal the infrastructure that makes macros possible, and we'll di The Lux compiler was designed to integrate very well with the language itself. -Most compilers are just programs that take source code and emit some binary executable or some byte-code. But the Lux compiler opens itself for usage within Lux programs and provides Lux programmers with a wealth of information. +Most compilers are just programs that take source code and emit some binary executable or some byte-code. + +But the Lux compiler opens itself for usage within Lux programs and provides Lux programmers with a wealth of information. The `Lux` type enters the stage. ```clojure -(type: #export Lux - {#info Info - #source Source - #location Location - #current_module (Maybe Text) - #modules (List [Text Module]) - #scopes (List Scope) - #type_context Type_Context - #expected (Maybe Type) - #seed Nat - #scope_type_vars (List Nat) - #extensions Any - #host Any}) +(type: .public Lux + (Rec Lux + (Record + [#info Info + #source Source + #location Location + #current_module (Maybe Text) + #modules (List [Text Module]) + #scopes (List Scope) + #type_context Type_Context + #expected (Maybe Type) + #seed Nat + #scope_type_vars (List Nat) + #extensions Any + #eval (-> Type Code (-> Lux (Either Text [Lux Any]))) + #host Any]))) ``` - By the way, the `Lux` type and other weird types you may not recognize there are all defined in the `library/lux` module. Check the documentation for the Standard Library for more details. + By the way, the `Lux` type and other weird types you may not recognize there are all defined in the `library/lux` module. + Check [the documentation for the Standard Library](https://github.com/LuxLang/lux/tree/master/documentation/library/standard) for more details. The `Lux` type represents the state of the Lux compiler at any given point. -It is not a reflection of that state, or a subset of it. It is `the` state of the Lux compiler; and, as you can see, it contains quite a lot of information about compiled modules, the state of the type-checker, the lexical and global environments, and more. +It is not a reflection of that state, or a subset of it. + +It **is** the state of the Lux compiler; and, as you can see, it contains quite a lot of information about compiled modules, the state of the type-checker, the lexical and global environments, and more. Heck, you can even access the yet-unprocessed source code of a module at any given time. That's pretty neat. -You can actually write computations that can read and even modify (_careful with that one_) the state of the compiler. This turns out to be massively useful when implementing a variety of powerful macros. +You can actually write computations that can read and even modify (_careful with that one_) the state of the compiler. + +This turns out to be massively useful when implementing a variety of powerful macros. -For example, remember the `open:` and `\` macros from [chapter 7](chapter_7.md)? +For example, remember the `open:` and `#` macros from [chapter 7](chapter_7.md)? They actually look up the typing information for the structures you give them to figure out the names of members and generate the code necessary to get that functionality going. @@ -71,7 +81,7 @@ I won't go into detail about what's available, but you'll quickly get an idea of However, one thing I _will_ say is that those functions rely heavily on the `Meta` type, which is defined thusly: ```clojure -(type: #export (Meta a) +(type: .public (Meta a) (-> Lux (Either Text [Lux a]))) ``` @@ -79,7 +89,7 @@ However, one thing I _will_ say is that those functions rely heavily on the `Met The `Meta` type has a `Functor`, and a `Monad`, but they are a bit rather complicated. -You saw some functor/monad examples in the last chapter, but this is more colorful. +You saw some `Functor`/`Monad` examples in the last chapter, but this is more colorful. `Meta` instances are functions that given an instance of the `Lux` compiler state, will perform some calculations which may fail (_with an error message_); but if they succeed, they yield a value, plus a (_possibly updated_) instance of the `Lux` compiler state. @@ -93,72 +103,15 @@ The compiler is only ever present during... well... compilation. And that is precisely when all of your `Lux`-dependant code will execute. -Basically, in order for you to get your hands on that _sweet_ compiler information, your code must be run at compile-time. But only macro code can ever do that, so you will have to wait until the next chapter to learn how this story ends. - -## Definition annotations - -Another important piece of information you should be aware of is that definitions don't just have values and types associated with them, but also arbitrary meta-data which you can customize as much as you want. - -The relevant types in the `library/lux` module are: - -```clojure -(type: #export Location - {#module Text - #line Nat - #column Nat}) - -(type: #export (Ann m v) - {#meta m - #datum v}) - -(type: #export (Code' w) - (#Bit Bit) - (#Nat Nat) - (#Int Int) - (#Rev Rev) - (#Frac Frac) - (#Text Text) - (#Identifier Name) - (#Tag Name) - (#Form (List (w (Code' w)))) - (#Tuple (List (w (Code' w)))) - (#Record (List [(w (Code' w)) (w (Code' w))]))) - -(type: #export Code - (Ann Location (Code' (Ann Location)))) -``` - -You can add annotations to definitions in the many definition macros offered in the standard library. -You can also annotate modules when using the `module:` macro. +Basically, in order for you to get your hands on that _sweet_ compiler information, your code must be run at compile-time. -All you need to do is pass in some record syntax, with tags signaling the type of annotation you want, and the associated value being either an explicit variant `Code`, or some function or macro call that would produce such a value. - -Here's an example from `library/lux`: - -```clojure -(def: #export (is? reference sample) - {#.doc (doc "Tests whether the 2 values are identical (not just 'equal')." - "This one should succeed:" - (let [value +5] - (is? value value)) - - "This one should fail:" - (is? +5 (+ +2 +3)))} - (All [a] (-> a a Bit)) - ("lux is" reference sample)) -``` - - The (_optional_) annotations always goes after the declaration or name of the thing being defined. - -Note that all tag usage within annotation records should be fully qualified, to avoid potential confusions, as different modules could be using annotation tags with similar names. - -The `library/lux/meta/annotation` module contains various functions for reading and exploring annotations, and some modules in the standard library (for example, the `lbrary/lux/ffi` module) make heavy use of annotations to figure out properties of definitions which may be useful during code-generation and parsing in macros. - -And also, as you can appreciate from the previous example, some macros may be designed to be used during annotation specification. +But only macro code can ever do that, so you will have to wait until the next chapter to learn the conclusion to this story. --- -This chapter feels a little empty because the topic only makes sense within the context of macros. But macros by themselves are a huge subject, and involve more machinery than you've seen so far. +This chapter feels a little empty because the topic only makes sense within the context of macros. + +But macros by themselves are a huge subject, and involve more machinery than you've seen so far. However, I wanted to give you a taste of what's possible in order to whet your appetite, while keeping the chapter focused. -- cgit v1.2.3