github.com/ipld/go-ipld-prime@v0.21.0/schema/gen/go/HACKME.md (about) 1 hacking gengo 2 ============= 3 4 What the heck? 5 -------------- 6 7 We're doing code generation. 8 9 The name of the game is "keep it simple". 10 Most of this is implemented as string templating. 11 No, we didn't use the Go AST system. We could have; we didn't. 12 Implementing this as string templating seemed easier to mentally model, 13 and the additional value provided by use of AST libraries seems minimal 14 since we feed the outputs into a compiler for verification immediately anyway. 15 16 Some things seem significantly redundant. 17 That's probably because they are. 18 In general, if there's a choice between apparent redundancy in the generator itself 19 versus almost any other tradeoff which affects the outputs, we prioritize the outputs. 20 (This may be especially noticable when it comes to error messages: we emit a lot 21 of them... while making sure they contain very specific references. This leads 22 to some seemingly redundant code, but good error messages are worth it.) 23 24 See [README_behaviors](README_behaviors.md) for notes about the behaviors of the code output by the generator; 25 this document is about the generator code itself and the design thereof. 26 27 28 Entrypoints 29 ----------- 30 31 The most important intefaces are all in [`generators.go`](generators.go). 32 33 The function you're most likely looking for that "does the thing" is the 34 `Generate(outputPath string, pkgName string, schema.TypeSystem, *AdjunctCfg)` method, 35 which can be found in the [`generate.go`](generate.go) file. 36 You can take any of the functions inside of that and use them as well, 37 if you want more granular control over what content ends up in which files. 38 39 The eventual plan is be able to drive this whole apparatus around via a CLI 40 which consumes IPLD Schema files. 41 Implementing this can come after more of the core is done. 42 (Seealso the `schema/tmpBuilders.go` file a couple directories up for why 43 this is currently filed as nontrivial/do-later.) 44 45 46 Organization 47 ------------ 48 49 ### How many things are generated, anyway? 50 51 There are roughly *seven* categories of API to generate per type: 52 53 - 1: the readonly thing a native caller uses 54 - 2: the builder thing a native caller uses 55 - 3: the readonly typed node 56 - 4: the builder/assembler for typed node 57 - 5: the readonly representation node 58 - 6: the builder/assembler via representation 59 - 7: and a maybe wrapper 60 61 (And these are just the ones nominally visible in the exported API surface! 62 There are several more concrete types than this implied by some parts of that list, 63 such as iterators for the nodes, internal parts of builders, and so forth.) 64 65 These numbers will be used to describe some further organization. 66 67 ### How are the generator components grouped? 68 69 There are three noteworthy types of generator internals: 70 71 - `TypeGenerator` 72 - `NodeGenerator` 73 - `NodebuilderGenerator` 74 75 The first one is where you start; the latter two do double duty for each type. 76 77 Exported types for purpose 1, 2, 3, and 7 are emitted from `TypeGenerator` (3 from the embedded `NodeGenerator`). 78 79 The exported type for purpose 5 is emitted from another `NodeGenerator` instance. 80 81 The exported types for purposes 4 and 6 are emitted from two distinct `NodebuilderGenerator` instances. 82 83 For every variation in type kind and representation strategy for that type kind, 84 one type implementing `TypeGenerator` is composed, and it has functions which 85 yield all the other interfaces for addressing the various purposes. 86 87 ### How are files and their contents grouped? 88 89 Most of the files in this package are following a pattern: 90 91 - for each kind: 92 - `gen{Kind}.go` -- has emitters for the native type parts (1, 2, 7) and type-level node behaviors (3, 4). 93 - for each representation that kind can have: 94 - `gen{Kind}Repr{ReprStrat}.go` -- has emitters for (5, 6). 95 96 A `mixins` sub-package contains some code which is used and embedded in the generators in this package. 97 These features are mostly per-kind -- representation kind, not type-level kind. 98 For example, you'll see "map" behaviors from the mixins package added to "struct" generators. 99 100 ### What are all these abbreviations? 101 102 See [HACKME_abbrevs.md](HACKME_abbrevs.md). 103 104 ### Code architecture 105 106 See [HACKME_tradeoffs.md](HACKME_tradeoffs.md) for an overview of tradeoffs, 107 and which priorities we selected in this package. 108 (There are *many* tradeoffs.) 109 110 See [HACKME_memorylayout.md](HACKME_memorylayout.md) for a (large) amount of 111 exposition on how this code is designed in order to be allocation-avoidant 112 and fast in general. 113 114 See [HACKME_templates.md](HACKME_templates.md) for some overview on how we've 115 used templates, and what forms of reuse and abstraction there are. 116 117 See [HACKME_scalars.md](HACKME_scalars.md) for some discussion of scalars 118 and (why we generate more of them than you might expect). 119 120 See [HACKME_maybe.md](HACKME_maybe.md) for notes how how the 'maybe' feature 121 (how we describe `nullable` and `optional` schema features in generated golang code) 122 has evolved. 123 124 125 Testing 126 ------- 127 128 See [HACKME_testing.md](HACKME_testing.md) for some details about how this works. 129 130 In general, try to copy some of the existing tests and get things to suit. 131 132 Be advised that we use the golang plugin feature, and that has some additional 133 requirements of your development environment than is usual in golang. 134 (Namely, you have to be on linux and you have to have a c compiler!) 135