|
| 1 | +# QAST Nodes |
| 2 | + |
| 3 | +The "Q" Abstract Syntax Tree is a set of nodes used to represent the runtime |
| 4 | +behavior of a program that is being compiled. Parsing a program with a grammar |
| 5 | +produces a parse tree. As the name suggests, this is strongly tied to the |
| 6 | +syntax of the language being parsed, and reflects the structure of the grammar. |
| 7 | +This parse tree is mapped by action methods into an abstract syntax tree - a |
| 8 | +tree of QAST nodes. Rather than talking about program syntax, they talk about |
| 9 | +what happens at runtime: loops, conditionals, variable lookups, etc. This |
| 10 | +document describes the available nodes and what they are for. |
| 11 | + |
| 12 | +## QAST::CompUnit |
| 13 | +While it's not mandatory, most QAST trees that are produced should have a |
| 14 | +QAST::CompUnit at the top. It should have a single QAST::Block child. This |
| 15 | +child block represents the outermost scope of the compilation unit. |
| 16 | + |
| 17 | +QAST::CompUnit incorporates information that is relevant to the entire |
| 18 | +unit of code that is being compiled. This includes: |
| 19 | + |
| 20 | +* **hll** - the name of the high level language that this QAST tree was |
| 21 | + produced from, for example, "perl6", "tcl", "bf". |
| 22 | + |
| 23 | +* **load** - code to evaluate at the point that the compilation unit is |
| 24 | + loaded as a module (but not if it is invoked as a mainline program). |
| 25 | + Happens after any deserialization and deserialization related actions |
| 26 | + have executed. |
| 27 | + |
| 28 | +* **main** - like load, but instead this contains code to execute if the |
| 29 | + compilation unit is invoked as the mainline |
| 30 | + |
| 31 | +Example usage: |
| 32 | + |
| 33 | + QAST::CompUnit.new( |
| 34 | + # Set the HLL. |
| 35 | + :hll('perl6'), |
| 36 | + |
| 37 | + # This variable contains the outermost QAST::Block of the |
| 38 | + # program. |
| 39 | + $top_block, |
| 40 | + |
| 41 | + # If we run the program as the mainline, then call the top |
| 42 | + # block automatically. |
| 43 | + :main(QAST::Op.new( |
| 44 | + :op('call'), |
| 45 | + QAST::BVal.new( :value($top_block) ) |
| 46 | + )) |
| 47 | + ) |
| 48 | + |
| 49 | +Additional adverbs that can be set on a QAST:CompUnit relate to bounded |
| 50 | +serialization, which will be covered separately. |
| 51 | + |
| 52 | +## QAST::Block |
| 53 | +A QAST::Block is both a unit of invocation and a unit of lexical scoping. |
| 54 | +To clarify, this means that if: |
| 55 | + |
| 56 | +* You want to create something that can be called, such as a subroutine, |
| 57 | + closure block or method |
| 58 | +* You want a fresh lexical environment |
| 59 | + |
| 60 | +Then you want to use a QAST::Block. A block can have as many children as |
| 61 | +you wish, and the final child should evaluate to the return value of the |
| 62 | +block. A simple example of a block is: |
| 63 | + |
| 64 | + QAST::Block.new( |
| 65 | + QAST::IVal.new( :value(42) ) |
| 66 | + ) |
| 67 | + |
| 68 | +This will compile to a block of code that, when invoked, returns 42. |
| 69 | + |
| 70 | +A block can be given a name and a compilation unit unique ID. The name |
| 71 | +is user facing, and will appear in any automatically generated backtraces. |
| 72 | +It does not need to be unique within the compilation unit. The compilation |
| 73 | +unit unique ID, as the name suggests, does need to be. You typically do |
| 74 | +not need to worry about it much, however; it will be generated for you the |
| 75 | +first time it is needed, if you do not specify it up front. Often, you will |
| 76 | +not need to worry about it at all. Here's a block with a name. |
| 77 | + |
| 78 | + QAST::Block.new( |
| 79 | + :name('answer'), |
| 80 | + QAST::IVal.new( :value(42) ) |
| 81 | + ) |
| 82 | + |
| 83 | +Note that giving a block a name does not imply *any* installation of the |
| 84 | +block under this name. It's not installed automatically for you as a |
| 85 | +method or subroutine. That's for you to do. |
| 86 | + |
| 87 | +Blocks can be placed within other blocks. This nesting represents the static |
| 88 | +chain that will be used for the lookup of lexically scoped variables. When |
| 89 | +you nest one block inside of another, you may wish for it to be invoked |
| 90 | +automatically when it is encountered, or you may wish that it be treated as |
| 91 | +an object (for example, which you can bind somewhere). You can configure this |
| 92 | +by setting the blocktype: |
| 93 | + |
| 94 | + QAST::Block.new( |
| 95 | + QAST::Op.new( |
| 96 | + :op('say'), |
| 97 | + QAST::SVal.new( :value('before') ) |
| 98 | + ), |
| 99 | + QAST::Block.new( |
| 100 | + :blocktype('immediate'), |
| 101 | + QAST::Op.new( |
| 102 | + :op('say'), |
| 103 | + QAST::SVal.new( :value('nested') ) |
| 104 | + ) |
| 105 | + ), |
| 106 | + QAST::Op.new( |
| 107 | + :op('say'), |
| 108 | + QAST::SVal.new( :value('after') ) |
| 109 | + ) |
| 110 | + ) |
| 111 | + |
| 112 | +Here, 'immediate' indicates that this block should be executed immediately, |
| 113 | +whenever it is reached during program execution. The default, 'declaration', |
| 114 | +does not have these semantics. You use it when you plan to bind the block, |
| 115 | +for example into a lexical variable, or you are installing it elsewhere |
| 116 | +(for example, as a method). |
| 117 | + |
| 118 | +Block has one more handy feature: it can be used to maintain a symbol table. |
| 119 | +It provides you with a hash per symbol (typically, these correspond to the |
| 120 | +variables you declare in the block, but you can put whatever you want in it). |
| 121 | + |
| 122 | + $my_block.symbol('$foo', :scope('lexical'), :readonly(1)); |
| 123 | + |
| 124 | +The named parameters you pass are stored in a hash for the symbol '$foo'. If |
| 125 | +you call it again: |
| 126 | + |
| 127 | + $my_block.symbol('$foo', :scope('local'), :optimized(1)); |
| 128 | + |
| 129 | +Then the updated value for 'scope' will be put in place, the new 'optimized' |
| 130 | +value will be stored and the existing 'readonly' value will be left intact. |
| 131 | +That is to say, you can safely add extra information over time. To get all |
| 132 | +the known facts about a symbol in a hash, simply do: |
| 133 | + |
| 134 | + my %sym := $my_block.symbol('$foo'); |
| 135 | + |
| 136 | +Two keys have special significance to the QAST to VM compiler: |
| 137 | + |
| 138 | +* **scope** is used to find a default scope for a variable, if none is |
| 139 | + set in a QAST::Var node that is doing a lookup |
| 140 | + |
| 141 | +* **type** is used to know the type of the variable. This matters if the |
| 142 | + variable is natively typed, since it influences the code generation |
| 143 | + |
| 144 | +## QAST::Stmts and QAST::Stmt |
| 145 | + |
| 146 | +## QAST::IVal, QAST::NVal and QAST::SVal |
| 147 | + |
| 148 | +## QAST::Var |
| 149 | + |
| 150 | +## QAST::Op |
| 151 | + |
| 152 | +## QAST::VarWithFallback |
| 153 | + |
| 154 | +## QAST::BVal |
| 155 | + |
| 156 | +## QAST::WVal |
| 157 | + |
| 158 | +## QAST::Want |
| 159 | + |
| 160 | +## QAST::VM |
0 commit comments