Révision | 39e4e9f0fd80de9c3707194f08d10e9a289403f6 (tree) |
---|---|
l'heure | 2024-03-18 07:12:08 |
Auteur | Albert Mietus < albert AT mietus DOT nl > |
Commiter | Albert Mietus < albert AT mietus DOT nl > |
Imported CCastle::DocParts (former: localHacks) to here
@@ -0,0 +1,251 @@ | ||
1 | +.. (C) 2023,2024 Albert Mietus. Part of CCastle project | |
2 | + | |
3 | +.. include:: /std/localtoc.irst | |
4 | + | |
5 | +.. _AR_pipeline: | |
6 | + | |
7 | +====================== | |
8 | +Architectural overview | |
9 | +====================== | |
10 | + | |
11 | +The (new) CastleCompiler(s) share a common "pipeline" architecture. Which is flexible, both in functionality and | |
12 | +implementation, as they share the :ref:`AIGR <AIGR>` --see below -- for input and/or output. | |
13 | + | |
14 | +AIGR pipeline | |
15 | +============== | |
16 | + | |
17 | +The pipeline starts with source, in text format, that is explored by the :ref:`Readers` and translated in the | |
18 | +:ref:`AIGR`. The next components all read this format, like the :ref:`Transformers`, that transform it to a "better" | |
19 | +form -- see later. Last, the `AIGR` is converted into a binary by (one of the) the :ref:`Backends` | |
20 | +|BR| | |
21 | +Most :ref:`Backends` consist of two main parts: the :ref:`Writers` (which is part of CCastle), and a *Translator*: an | |
22 | +external *compiler* that translate/compiles the generated intermediate code into a binary. | |
23 | + | |
24 | +.. uml:: AIGR_pipeline.puml | |
25 | + | |
26 | +As the `AIGR` is a format (not a call-interface!), this architecture gives flexibility on deployment of the components. | |
27 | +A simple (Castle)compiler can hold them as (plug-in) libraries in one process. | |
28 | +|BR| | |
29 | +Alternatively, each component can be a process, where te several processes communicate with e.g. unix-pipes, or | |
30 | +network-connections). And there are many more option, not only separated in space, but also in time: As the AIGR can be | |
31 | +serialised [#pickle]_, it is possible to save it in file, and read it for the next component, later ... | |
32 | + | |
33 | +.. Important:: Although it is possible to saving a (pickled) AIGR, that component (nor action) is **NOT** a `Writer`! | |
34 | + | |
35 | + One should typically speak about “saving” the AIGR, and “loading the (AIGR) file”. It is a feature of the | |
36 | + :ref:`AIGR_component` (see below). | |
37 | + | |
38 | + | |
39 | +The Reader(s) | |
40 | +============= | |
41 | + | |
42 | +A typical reader reads (some) source-files and then translate that, in a few steps, into the :ref:`AIGR`, as | |
43 | +shown below. | |
44 | +|BR| | |
45 | +The :ref:`mockReader` is different: it does output (needed) ‘`AIGR`’, and so can act as the starts of a | |
46 | +pipeline (and therefor considered as a ‘`Reader`’), but has no input. | |
47 | + | |
48 | +.. uml:: AIGR_Reader.puml | |
49 | + | |
50 | +Some sub-components in the ‘`Reader`’ may also work on the ‘`AIGR`’, as shown. The difference (to a ‘`Translator`’) is | |
51 | +simple: the '`Reader'` should do all error-checking, etc, to make sure the inputs (so the code of the developer) is | |
52 | +valid. A normal Translator (nor the '`Backend'`) should ever find errors. | |
53 | +|BR| | |
54 | +When implementing that (`Reader`) functionality is more convenient as after converting the :ref:`ATS into the AIGR | |
55 | +<AST-2-AIGR>` an “AIGR-analyser” is build. | |
56 | + | |
57 | +.. _Transformers: | |
58 | + | |
59 | +Transformers | |
60 | +============ | |
61 | + | |
62 | +All ‘`Transformers`’ receive and post (a “dialect” of) the`AIGR`, pushing it into a form that van be handled by the | |
63 | +backend to create an efficient binary. There can be many `Transformers`, and typically several of them are run in | |
64 | +sequence. Other sets of `Transformers` exclude each other. | |
65 | + | |
66 | + | |
67 | +A `Transformer` is often triggered by one of the :ref:`Rewriters` | |
68 | + | |
69 | +We show two examples. | |
70 | + | |
71 | +.. uml:: AIGR_Transformers.puml | |
72 | + :align: right | |
73 | + :scale: 50% | |
74 | + | |
75 | +FSM | |
76 | +--- | |
77 | +In Castle, one can directly describe a FSM (see: :ref:`FSMs-are-needed`) including advance/extended variants. Like | |
78 | +the non-deterministic “NFA”s, and the “State-Charts” (known from UML), with orthogonale regions and hierarchically | |
79 | +‘superstates’. See :need:`U_FSM_Syntax` for the demands. | |
80 | +|BR| | |
81 | +Those FSM are initially stored “asis” in the AIGR, and step-by-step rewritten by several FSM-Transformers. | |
82 | + | |
83 | +The ``FSM.NFA_2_FSM`` Transformer reworks a NFA into a (bigger, deterministic) FSM. This is a well know algorithm, such | |
84 | +that non-deterministic edges and epsilon-transitions are gone. | |
85 | +|BR| | |
86 | +The resulting `AIGR` has the same functionality, but is simpler to translate into a binary | |
87 | + | |
88 | +Similarly, the ``FSM.SuperStates`` Transformer can “flatten” complex hierarchical FSM’s into ones that are easier to | |
89 | +translate into executable code. | |
90 | + | |
91 | +This is an examples of set of `Transformers` that can work collectively. First, remove the non-determinisms, then handle | |
92 | +the SuperStates and completely transformer the (simple) FSM into regulair routines. | |
93 | + | |
94 | +Machinery | |
95 | +--------- | |
96 | +.. caution:: | |
97 | + :class: clear-none | |
98 | + | |
99 | + The Machinery part is still in development. And so, it’s **not** sure that the Machinery will be implemented as a | |
100 | + `Transformer`! | |
101 | + | |
102 | +‘:ref:`TheMachinery`’ is an abstraction of the technology to connect ports and send data (like events) over | |
103 | +them. Several implementations are possible, like direct function-calls, dispatching to concurent thread-pools, or | |
104 | +distributing them over a network. | |
105 | + | |
106 | +Typically, one wil only use one Machinery: connecting two port with DDS, ‘sending’ an event by dispatching it whereas | |
107 | +the receiving event-handler expect a traditional call, will not work. By choosing one Machinery-Transformer, all | |
108 | +bolt-and nuts will fit. | |
109 | + | |
110 | +.. caution:: This is **not** an requirement! | |
111 | + | |
112 | + One can imagine, that (eventually) a Mixed-Machinery is used. Ultimately, only the details of each (individual) | |
113 | + connection should be aligned. | |
114 | + | |
115 | + .. admonition:: Advanced example | |
116 | + | |
117 | + The *Machinery-kind* can be seen an attribute of the (super)component that holds the connections (and | |
118 | + sub-component, with ports). By using that Machinery for those connections, it will work. | |
119 | + |BR| | |
120 | + But the (external) ports and connections of that super(component) can use another Machinery; when the | |
121 | + supper-super-component’s machinery-kind attribute has another value. | |
122 | + | |
123 | + Again, this makes it complicated. But it gives flexibility: for deep-down connections we might prefer direct | |
124 | + calls, but use concurent options at a (bit) higher level. And use maximal decoupling for networking-applications. | |
125 | + | |
126 | + .. note:: | |
127 | + | |
128 | + Here, we see an example of having the “connected/concurent components” abstraction and | |
129 | + ‘:ref:`TheMachinery`’ abstraction. | |
130 | + | |
131 | + The CCastle code, use “components, ports and connections” only. Later, we compiling it, the details of the | |
132 | + Machinery are added. | |
133 | + |BR| | |
134 | + And by implementing it in/as a `Transformer` we can add more-and-more advanced options without the need to change | |
135 | + the source. Only some (global) “compiler options” have to be improved. | |
136 | + (many) sor | |
137 | + | |
138 | + | |
139 | +Writers & Backends | |
140 | +================== | |
141 | + | |
142 | +The ‘`Backends`’ read the (simplified & optimised) `AIGR` and transform it to a binary that can be executed. Typically | |
143 | +this is a two-step approach: A ‘`Writer`’ renders the `AIGR` into a low-level intermediate [#intermediate]_ language [#lll-ex]_ | |
144 | + | |
145 | +The interface between the ‘`Writer`’ and the ‘Translator’ is typically file-based, and depend heavily on the chosesn | |
146 | +‘Translator’ -- which is not part of CCastle. | |
147 | +|BR| | |
148 | +As those two are very depending on each other, there is little commonality between various `Backend` variants. | |
149 | + | |
150 | +Some examples | |
151 | + | |
152 | +* The :ref:`RPy` backend/writer renders to RPython, such that (PyY’s) rpython-translator can handle it. The intermediate | |
153 | + file-format is fully described by RPython: the :ref:`RPy` `Writer` needs to emit exactly that format. | |
154 | +* **CC2Cpy** (now defunct [#CC2Cpy-not-AIGR]_) generates standard C code, that can be translated into binaries by many | |
155 | + (standard, C) compilers. So, it’s a bit more generic (then **RPy**), but still the writer is limited to C -- and so | |
156 | + has to *emulate* namespaces, as that isn’t handled in C | |
157 | + |BR| | |
158 | + A possible variant is using C++, both as lll and translator (but as I’m not a a fan of it, somebody else has to make | |
159 | + it | |
160 | +* Both mentioned writers are implemented in python, for now (that is the ‘py’ part of CC2Cpy). | |
161 | + |BR| | |
162 | + Future variants of those `Writers` will be implemented in Castle itself. This does not change the input (`AIGR`) not | |
163 | + the output of the `Writers` (rpython and C). And such we can use easily upgrade the `Backend` as the `Translator` does | |
164 | + not change. | |
165 | + | |
166 | + | |
167 | +.. _AIGR_component: | |
168 | + | |
169 | +The AIGR auxiliary component | |
170 | +============================ | |
171 | + | |
172 | +The `AIGR` *auxiliary* component describes & handles the ‘:ref:`AIGR`’ and is used by all regulair components. Sometimes | |
173 | +it (the `AIGR`) is called an `“intermediate language” (‘IM’), or “intermediate representation” (‘IR’) | |
174 | +<https://en.wikipedia.org/wiki/Intermediate_representation>`__. Many existing IMs are quite “flat”, low-level and very | |
175 | +operational, like `RTL <https://en.wikipedia.org/wiki/Register_transfer_language>`__ or `SSA | |
176 | +<https://en.wikipedia.org/wiki/Static_single-assignment_form>`__ -- they are great to convert code to assembly. | |
177 | + | |
178 | + | |
179 | + | |
180 | +.. uml:: AIGR-exampleSieve.puml | |
181 | + :align: right | |
182 | + :scale: 70% | |
183 | + :caption: The *Sieve Protocols*, as example of a AIGR (part) | |
184 | + | |
185 | +For the *CCastle Workshop Tools*, a more abstract representation is chosen, with more structure. Visually, it resembles | |
186 | +a tree, but without the need to have a single root (making it a “forest”), and with interconnects (making it a | |
187 | +graph). Structurally, it is not dissimular to the XLM/DOM, known by many webpages; but again without the “single | |
188 | +document-root” -- the DOM has interconnects, known as “links” (a term not used in the AIGR). | |
189 | +|BR| | |
190 | +The AIGR reminds also to the AST (of CCastle), after all, each language construct is “stored” in the AIGR. Some see it as a | |
191 | +semantically parsed AST. A namedID (like a variable, or function) in the source, when in the same namespace denotes the | |
192 | +same artifact -- even it is mention at several places (and can have aliases). In the AIGR it is the same ‘node’ having | |
193 | +multiple incoming ‘edges’ -- and so, violates the tree’s non-cycle rule. | |
194 | + | |
195 | +The AIGR-component describes all possible elements, and the relations (so it is a bit like the XML `DTD | |
196 | +<https://en.wikipedia.org/wiki/Document_type_definition>`__ or `Schema | |
197 | +<https://en.wikipedia.org/wiki/XML_schema>`__). And has (will have) general routines to facilitate handling the AIGR. | |
198 | +|BR| | |
199 | +By example, you can expect routines to “save” an AIGR to file, and “load” is later. | |
200 | + | |
201 | +.. warning:: | |
202 | + | |
203 | + Although the AIGR is a graph, the AIGR-component will **not** be able to visualize that graph. | |
204 | + | |
205 | + Other workshop tools may do that, and probably use the AIGR-component to read it. The visualising is part of that | |
206 | + tool. For the example above an manual conversion to plantUML is made. | |
207 | + | |
208 | + | |
209 | +Currently, the AIGR is in the design phase, and may change. | |
210 | +|BR| | |
211 | +For that reason, only a Python dataclass reference model is available (Work-in-Progress). The (unit & behaviour) tests | |
212 | +and TesDoubles make it quite understandable. Once, it will be fully documented (and versioned) And available for | |
213 | +multiple languages (including Castle :-) | |
214 | + | |
215 | + | |
216 | + | |
217 | +-------- | |
218 | + | |
219 | +.. rubric:: Footnotes | |
220 | + | |
221 | +.. [#pickle] | |
222 | + This can be done by *pickling* in python, or using an XML format, or ... | |
223 | + | |
224 | +.. [#intermediate] | |
225 | + We call this low-level-language “intermediate”, as the user shouldn't care about it. And consider it as an internal | |
226 | + detail of the `Backend`. | |
227 | + |BR| | |
228 | + Note however, other tools/environments may speak about the *“Generaring to XXX-language ...”*, which is then | |
229 | + compiled in the normal way. (one may hope, the ‘generated source’ isn’t edited anymore, as old tools did allow). | |
230 | + | |
231 | + Aside of terms, it’s the same! | |
232 | + | |
233 | + .. XXX The hint below overlaps a bit. The |BR| hack is a workaround | |
234 | + | |
235 | + |BR| | |
236 | + | |
237 | + .. hint:: Generating (e.g.) C-code *sounds* like it is needed to intergrade existing code. | |
238 | + |BR| | |
239 | + That is an outdated view however. | |
240 | + | |
241 | + Nowadays all modern languages support a ‘FFI’ (`Foreign Function Interface | |
242 | + <https://en.wikipedia.org/wiki/Foreign_function_interface>`__). Castle will support that to. | |
243 | + | |
244 | +.. [#lll-ex] | |
245 | + A well know example of such low-level-languages is C, or C++. But also RPython --which translate to C, first and | |
246 | + then that an executable-- is can also be used. | |
247 | + Other options are the ‘LLVM-IM’ and so use the LLVM (known from e.g. CLang) backend as Transformer | |
248 | + | |
249 | +.. [#CC2Cpy-not-AIGR] | |
250 | + Notice, the current CC2Cpy module isn’t using the AIGR, and a therefore not a Writer. However, an upcomming version | |
251 | + of it may use the AIGR as interface, making it true `Writer` and a good example. |
@@ -0,0 +1,220 @@ | ||
1 | +.. (C) 2023,2024 Albert Mietus. Part of CCastle project | |
2 | + | |
3 | +.. _AR_PyPackages: | |
4 | + | |
5 | +.. sidebar:: Note | |
6 | + | |
7 | + In this article we focus on the python implementation of CCastle Compiler, and use python terminology. Partly, | |
8 | + because it is needed to design that well, partly because this is a first step into the ultimate goal, the CCastle | |
9 | + implementation of all Castle :ref:`Workshop Tools <Workshop-Design>`. | |
10 | + |BR| | |
11 | + And, because “the zen of python” is a good inspiration, studding it seems wise. | |
12 | + | |
13 | +=============================== | |
14 | +Short: PyPackages (START/DRAFT) | |
15 | +=============================== | |
16 | + | |
17 | +Most of the AR-components as described in e.g ‘:ref:`AR_pipeline`’ are *plugins*: independent deplorable packages. | |
18 | +As there are two views of *packages* [#packaging]_, associated by how to use them: (1) *import* and (2) *distribution* | |
19 | +packages, we need to **design** this well. | |
20 | + | |
21 | +Seen from the ‘*4+1 Architectural View Model*’ [#4+1AR]_ this is part of the “Deployment view”. And as such, a valuable reason to describe & | |
22 | +study the options in details | |
23 | + | |
24 | +.. admonition:: Summary & Conclusions (ToDo) | |
25 | + | |
26 | + For those, that are not interested in de design-study, this is the result | |
27 | + | |
28 | + * The top-level namespace is ‘castle’, for all public, more-or-less official packages | |
29 | + * Only base packages (which can’t be a plugin) are located directly in ‘castle’. Also some generic “main/app” routines can be located there. | |
30 | + | |
31 | + - ``castle.aigr``, the common intermediate langage | |
32 | + - ``castle.monorail``, the code to load the plugins and put them in the pipeline | |
33 | + | |
34 | + * Most packages are plugins and use a namespace that denotes the “location” in the pipeline; in plural form to | |
35 | + denotes the are options. | |
36 | + | |
37 | + - ``castle.readers.<name>`` | |
38 | + - ``castle.transformers.<name>`` | |
39 | + - ``castle.writers.<name>`` (not *backends*, as only the writer-part is part of Castle.) | |
40 | + | |
41 | + * Use “pep 420” *native namespace packages* for all plugins. | |
42 | + | |
43 | + - *In short*: plugins should **never** put an `__init__.py` file in a *shared* namespace-part (like castle.readers.) | |
44 | + - Only the “main” package is allowed to put files there. | |
45 | + | |
46 | + * Optional, auxiliary (plugin) packages are usually named (placed-in) | |
47 | + | |
48 | + - ``castle.<loc>.plugins.<opt>``. | |
49 | + | |
50 | + * Local (non public) extensions should normally *not* be in ‘castle’. | |
51 | + * Optional plugins, that can be shared by many plugins for test, debug & development purposed are allowed in one | |
52 | + place in the castle-hierarchy, | |
53 | + | |
54 | + - ``castle.TESTDOUBLES.<hier>``, | |
55 | + | |
56 | + - *TESTDOUBLES* is in capitals, to signal it’s a specical case | |
57 | + - Those plugins should *not* have production code -- no application should depend/need those | |
58 | + |BR| (But for test & verification) | |
59 | + - *‘<hier>’* is typical namespace, below castle, like: aigr | |
60 | + | |
61 | + - ``castle.TESTDOUBLES.aigr.sieve`` holds (parts of) ‘:ref:`Castle-TheSieve`’ in ‘:ref:`AIGR`’, As test-input for | |
62 | + e.g. plugins. Or as reference for a reader. | |
63 | + | |
64 | + | |
65 | +.. hint:: Suppose we make the “nice-fsm-plugin” that act as transformer ... | |
66 | + | |
67 | + .. note:: The resulting namespace will be: |BR| ``castle.transformers.fsm.nice_fsm`` | |
68 | + | |
69 | + The name of the top directly does not matter (for python). We advice a name that shows it’s not a python-id, and is | |
70 | + related to the package name. For example: | |
71 | + |BR| | |
72 | + ``<nice-fsm-plugin>`` | |
73 | + | |
74 | + This directory contains the *only* package-info-file, which name a content depends on the (package) build systems. | |
75 | + E.g. | |
76 | + | |
77 | + * ``pyproject.toml`` (`setup.py` is outdated) | |
78 | + | |
79 | + + **name** *:str* e.g. ``castle-RPy-writer`` or “nice-fsm-castle-plugin” | |
80 | + + *version* *:str* typical a dotted number (as string) | |
81 | + + **dependencies** *:List[str]* =[ ``castle-aigr``, `<package-names>`, ...] | |
82 | + | |
83 | + We need a file-hierarchy, with *empty* directories, that mirror the (shared) namespace | |
84 | + | |
85 | + * ``<nice-fsm-plugin>/castle/`` -- empty, no `__init__,py` | |
86 | + * ``<nice-fsm-plugin>/castle/transformers/`` -- empty, no `__init__,py` | |
87 | + * ``<nice-fsm-plugin>/castle/transformers/fsm`` -- empty, no `__init__,py` | |
88 | + * ``<nice-fsm-plugin>/castle/transformers/fsm/nice_fsm`` Holds all code: | |
89 | + | |
90 | + - **__init__.py** can be empty, but typically uses ``from .<> import <>`` to have the “api functionality” available | |
91 | + - **<files>.py** code | |
92 | + - **<sub>/** sub-package, (full-dirname to be included in `packages=[...]` above | |
93 | + | |
94 | + | |
95 | + | |
96 | + | |
97 | +Opportunity | |
98 | +=========== | |
99 | +Let study the options, our needs and how others handle packages & plugins, before designing for castle. | |
100 | + | |
101 | + | |
102 | +Importing | |
103 | +--------- | |
104 | + | |
105 | +When `import`\ing a package we (typical) use a hierarchical namespace to make the functionality of (a part of) the | |
106 | +package available. For example ``import castle.aigr`` will load that common package. | |
107 | +|BR| | |
108 | +It dotted name show :ref:`aigr<AIGR>` is part of castle. | |
109 | + | |
110 | +Packages that are optional, or where alternatives are available, are conveniently bundled in an extra ‘layer’: | |
111 | + | |
112 | +- ``from castle.readers import typicalReader as reader`` | |
113 | +- ``from castle.TESTDOUBLES.readers import mockReader as reader`` (selected option for mocks) | |
114 | +- ``from castle.readers import mockReader as reader`` (alternative, not preferred) | |
115 | + | |
116 | + | |
117 | +The “dotted names” gives the user/SW-engineer an hint on which (sub)packages are available, and where it fits. Aside of | |
118 | +that, the name is not very important. During importing we can even *rename* a package, with the `as <name>` langage feature. | |
119 | + | |
120 | +.. note:: The functionality does not depend on the name! | |
121 | + | |
122 | + After a package is imported, all it’s functionality is available; always. The name of the (sub)package isn’t | |
123 | + relevant, nor is the (disk) location. | |
124 | + It is also possible to use castle-plugins when they are not located in the *castle.namespace*. As shown by the | |
125 | + next example: | |
126 | + |BR| | |
127 | + ``from myLocal.Hack import MyOwnReader as reader`` (not advised). | |
128 | + | |
129 | +Installing | |
130 | +---------- | |
131 | + | |
132 | +When `(pip) install`\ing a **distribution** package, typically a zip-file is downloaded, and extracte into a | |
133 | +directory. The name of that directory typically correspondes with the namespace, when importing. | |
134 | +|BR| | |
135 | +The developer of a distribution specifies (has to design) in which namespaces (“directory”) the functionality becomes | |
136 | +available. | |
137 | + | |
138 | +For small, simple packages this is straightforward. Typically, the *directories* ‘in’ the distribution (zipfile) match the | |
139 | +name(s) that are used to import it. | |
140 | +|BR| | |
141 | +For bigger packages --especially when using plugins, and multiple parties can contribute and (independently) distribute | |
142 | +sub-packages-- it a bit more complicated. All parties should agree on the name(s), to make is clear for the users. | |
143 | + | |
144 | +A typical user expect that all packages for CCastle become available in `castle.`, or something that is close to it | |
145 | +[#sphinxcontrib]_ | |
146 | + | |
147 | +Related | |
148 | +------- | |
149 | + | |
150 | +There is a clear relation between the tow kind of packages, and for small packages the are typical 1:1. All (importable) | |
151 | +sub-packages are in the same “zip. | |
152 | +|BR| | |
153 | +For bigger packages/distributions -- and certainly for when using “plugins”-- this is not the case. | |
154 | + | |
155 | +Namespaces Packages | |
156 | +------------------- | |
157 | + | |
158 | +It is possible to combine several *distribution packages* into one *importable* packages (structure). This is called | |
159 | +*namespace package(s)*. Since python-3.3 (pep 420), this is standardised in `Native namespace packages | |
160 | +<https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#native-namespace-packages>`__. | |
161 | + | |
162 | +In short: each independent sub-package-developer should use of a common (same name), but “empty” top-directory. That | |
163 | +dir should be ‘in’ the distribution-package (aka the zipfile). That dir should only contain a (1) sub-dir. And all files | |
164 | +should be in that sub-dir. | |
165 | + | |
166 | +.. warning:: The name of that common directory should be aligned! | |
167 | + | |
168 | +XXXX | |
169 | + | |
170 | + | |
171 | + | |
172 | +Why? | |
173 | +==== | |
174 | + | |
175 | +Clarity | |
176 | +-------- | |
177 | + | |
178 | +It should be easy for the user to understand which package is related to CCastle and how it is related. Some packages are | |
179 | +mandatory (e.g :ref:`castle.aigr <AIGR>`) or are needed in de base-setup, others are (external) plugins. But packages | |
180 | +also have a place in the :ref:`AIGR pipeline <AR_pipeline>` -- it’s convenient to effortlessly tell *readers* and | |
181 | +*backends* (etc) aside. | |
182 | + | |
183 | +Ownership | |
184 | +--------- | |
185 | + | |
186 | +Each (distribution) package has an owner too. Typical, the have there own “code archive”, own “package-numbering” and | |
187 | +“release cycle”, ect. This also aplies to plugins! They should be (able to) deployed independently. | |
188 | +|BR| | |
189 | +In practice, “ownership” (like: who owns the code-archive, but also “when” to release) are the borders that define the | |
190 | +distribution-packages. | |
191 | + | |
192 | +------ | |
193 | + | |
194 | +XXXX | |
195 | + | |
196 | +------ | |
197 | + | |
198 | + | |
199 | +.. rubric:: Footnotes | |
200 | + | |
201 | +.. [#packaging] | |
202 | + .. seealso:: https://packaging.python.org/en/latest/tutorials/packaging-projects | |
203 | + | |
204 | +.. [#4+1AR] | |
205 | + I often use a “modern, OO variation of the standard `4+1 AR model <https://en.wikipedia.org/wiki/4+1_architectural_view_model>`__” | |
206 | + to describe architecture. As the `original paper <https://www.cs.ubc.ca/~gregor/teaching/papers/4+1view-architecture.pdf>`__ | |
207 | + comes from the pre-OO-era, its jargon is a bit outdated. | |
208 | + |BR| | |
209 | + See e.g. http://systemenbetermaken.nl/AR/ for some slides about it -- one-day I will make a blog .. | |
210 | + | |
211 | + | |
212 | +.. [#sphinxcontrib] | |
213 | + For example many extensions for “Sphinx” are available as a sub-package of ``sphinxcontrib``, where sphinx itself is | |
214 | + locates in ``sphinx`` (notice: `sphinxcontrib` is used, not `sphinx.contrib` -- possible because namespace-package | |
215 | + wheren’t available/standardised when sphinx(contrib) started.) | |
216 | + |BR| | |
217 | + In this location one can find mostly “standard extensions”. | |
218 | + | |
219 | + Other (independent) sphinx-additions are installed (aka can be found) in ``sphinx_<name>``. Despite those namespaces | |
220 | + (and directories) are completely independent for a human/user it clear the are related. |
@@ -0,0 +1,34 @@ | ||
1 | +ToDo: Temporary landings for AR-references | |
2 | +========================================== | |
3 | + | |
4 | +.. _ToDoARC: | |
5 | + | |
6 | +Describing AR components (todo) | |
7 | +------------------------------- | |
8 | + | |
9 | + | |
10 | +.. _Readers: | |
11 | + | |
12 | +Readers [ToDo] | |
13 | +************** | |
14 | + | |
15 | +.. _Writers: | |
16 | + | |
17 | +Writers [ToDo] | |
18 | +************** | |
19 | + | |
20 | +.. _Backends: | |
21 | + | |
22 | +Backends [ToDo] | |
23 | +*************** | |
24 | + | |
25 | + | |
26 | +.. _mockReader: | |
27 | + | |
28 | +mockReader [ToDo] | |
29 | +***************** | |
30 | + | |
31 | +.. _AST-2-AIGR: | |
32 | + | |
33 | +AST-2-AIGR [ToDo] | |
34 | +***************** |
@@ -0,0 +1,40 @@ | ||
1 | +@startuml | |
2 | +!include AR_skins.inc | |
3 | + | |
4 | +folder "AIGR example" #c0c0c0 { | |
5 | +object StartSieve <<EventProtocol>> | |
6 | +object runTo <<Event>>{ | |
7 | + max: int | |
8 | +} | |
9 | +object newMax <<Event>> { | |
10 | + max: int | |
11 | +} | |
12 | + StartSieve *-- runTo | |
13 | + StartSieve *-- newMax | |
14 | + | |
15 | + | |
16 | +object SlowStart << EventProtocol>> | |
17 | +object queue_max <<TypedParameter>> { | |
18 | + :int | |
19 | +} | |
20 | +object setMax <<Event>> { | |
21 | + setMax :int | |
22 | +} | |
23 | + SlowStart *-- setMax | |
24 | + SlowStart *- queue_max | |
25 | + | |
26 | +object "SlowStart(1)" as SlowStart_1 <<ProtocolWrapper>> { | |
27 | + queue_max=1 | |
28 | +} | |
29 | + SlowStart <-- SlowStart_1: based on | |
30 | + | |
31 | + | |
32 | +object SimpleSieve <<EventProtocol>> | |
33 | + SlowStart_1 <-- SimpleSieve: based_on | |
34 | + | |
35 | +object input <<Event>> { | |
36 | + try :int | |
37 | +} | |
38 | + SimpleSieve *--input | |
39 | +} | |
40 | +@enduml |
@@ -0,0 +1,33 @@ | ||
1 | +@startuml | |
2 | +skin rose | |
3 | +!include AR_skins.inc | |
4 | + | |
5 | +frame "CCastle Compiler" as CCC #c0c0c0 { | |
6 | + package Readers #white { | |
7 | + | |
8 | + node typicalReader { | |
9 | + [parser] | |
10 | + [analyse\n(ast)] as ast_ana | |
11 | + [AST 2 AIGR] as AST2AIGR | |
12 | + () "AIGR" as aigr1 | |
13 | + [analyse\n(aigr)] as aigr_ana | |
14 | + () "AIGR" as aigr2 | |
15 | + | |
16 | + parser -> ast_ana : AST | |
17 | + ast_ana -> AST2AIGR : AST | |
18 | + AST2AIGR -> aigr1 | |
19 | + aigr1 -> aigr_ana | |
20 | + aigr_ana -( aigr2 | |
21 | + } | |
22 | + TXT -> typicalReader | |
23 | + | |
24 | + node mockReader { | |
25 | + [TestDoubles/\nAIGR] as mock | |
26 | + () "AIGR" as aigr3 | |
27 | + mock -( aigr3 | |
28 | + } | |
29 | + | |
30 | + typicalReader -[hidden]down-> mockReader | |
31 | +} | |
32 | + | |
33 | +@enduml |
@@ -0,0 +1,44 @@ | ||
1 | +@startuml | |
2 | +skin rose | |
3 | +!include AR_skins.inc | |
4 | +left to right direction | |
5 | + | |
6 | + | |
7 | +''NOTE: Old RTD/plantuml.1.2020.2.jar syntax! | |
8 | + | |
9 | +!procedure $comp($name) | |
10 | +''!function $comp($name) | |
11 | + !$in = $name + "in" | |
12 | + !$out = $name + "out" | |
13 | + | |
14 | + [$name] | |
15 | + () "AIGR" as $in | |
16 | + () "AIGR" as $out | |
17 | + | |
18 | + $in )-- $name | |
19 | + $name --( $out | |
20 | +!endprocedure | |
21 | +''!endfunction | |
22 | + | |
23 | + | |
24 | +frame "CCastle Compiler" as CCC #c0c0c0 { | |
25 | + folder Transformers #white { | |
26 | + package FSM { | |
27 | + $comp("FSM.NFA_2_FSM") | |
28 | + $comp("FSM.SuperStates") | |
29 | +' $comp("FSM.Epsilon") | |
30 | + $comp("FSM_2_Routine") | |
31 | + } | |
32 | + package Machinery { | |
33 | + $comp("DirectCall") | |
34 | + $comp("LibDispatch") | |
35 | + $comp("DDS") | |
36 | + } | |
37 | + package "more ..." as m { | |
38 | + $comp("...") | |
39 | + } | |
40 | + } | |
41 | +} | |
42 | + | |
43 | + | |
44 | +@enduml |
@@ -0,0 +1,43 @@ | ||
1 | +@startuml | |
2 | +skin rose | |
3 | +!include AR_skins.inc | |
4 | + | |
5 | +' it stat with txt-src | |
6 | +file "*.Castle" as f1 | |
7 | +file "*.Moat" as f2 | |
8 | + | |
9 | +' those files are input | |
10 | +() "files" as txt | |
11 | + f1 --> txt | |
12 | + f2 --> txt | |
13 | + | |
14 | +package "CCastle Compiler" as CCC { | |
15 | + txt -> CCC | |
16 | + | |
17 | + () "AIGR" as a1 | |
18 | + () "AIGR" as a2 | |
19 | + | |
20 | + [Readers] | |
21 | + [Transformers] | |
22 | + Folder Backends { | |
23 | + [Writers] | |
24 | + [Translators] | |
25 | + | |
26 | + Backends #->Writers | |
27 | + | |
28 | + () "files" as txt2 | |
29 | + Writers -( txt2 | |
30 | + txt2 )-> Translators | |
31 | + } | |
32 | + | |
33 | + | |
34 | + | |
35 | + Readers -( a1 | |
36 | + a1 )-> Transformers | |
37 | + Transformers -( a2 | |
38 | + a2 )-> Backends | |
39 | +} | |
40 | + | |
41 | +Translators 0)-> bin | |
42 | + | |
43 | +@enduml |
@@ -0,0 +1,35 @@ | ||
1 | +'' -*- mode: plantuml -*- '' | |
2 | +skinparam componentStyle uml2 | |
3 | + | |
4 | +skinparam component { | |
5 | + BorderColor white | |
6 | + BackgroundColor #000066 | |
7 | + FontColor white | |
8 | +} | |
9 | +skinparam package { | |
10 | + BorderColor #000066 | |
11 | + BackgroundColor #eeeeff | |
12 | +} | |
13 | +skinparam interface { | |
14 | + BorderColor #000066 | |
15 | + BackgroundColor #000066 | |
16 | + FontColor #000066 | |
17 | +} | |
18 | +skinparam file { | |
19 | + BorderColor #c0c0c0 | |
20 | + BackgroundColor #808080 | |
21 | + FontColor #000066 | |
22 | +} | |
23 | +skinparam { | |
24 | + ArrowColor #000066 | |
25 | +} | |
26 | +skinparam node { | |
27 | + BorderColor #000066 | |
28 | + BackgroundColor #eeeeff | |
29 | +} | |
30 | + | |
31 | +skinparam object { | |
32 | + BorderColor #000066 | |
33 | + BackgroundColor white | |
34 | + FontColor #000066 | |
35 | +} |
@@ -0,0 +1,9 @@ | ||
1 | +Top Level architecture (LOCAL only) | |
2 | +=================================== | |
3 | + | |
4 | + | |
5 | +.. toctree:: | |
6 | + :glob: | |
7 | + | |
8 | + * | |
9 | + */index |
@@ -0,0 +1,34 @@ | ||
1 | +analyse_imports (220122) | |
2 | +======================== | |
3 | + | |
4 | +.. UML:: | |
5 | + | |
6 | + @startuml | |
7 | + skinparam ArrowColor green | |
8 | + | |
9 | + skinparam component { | |
10 | + BackgroundColor #0077ff | |
11 | + BorderColor black | |
12 | + } | |
13 | + skinparam folder { | |
14 | + BackgroundColor lightblue | |
15 | + BorderColor black | |
16 | + } | |
17 | + | |
18 | + cloud "AsIS 2022/Jan/22" #pink { | |
19 | + | |
20 | + folder AST { | |
21 | + folder castle { | |
22 | + [peg] --> [_base] | |
23 | + [_base] | |
24 | + [~__init __] | |
25 | + } | |
26 | + } | |
27 | + | |
28 | + folder Arpeggio { | |
29 | + [grammar] | |
30 | + [vistor] --> [peg] | |
31 | + } | |
32 | + | |
33 | + } | |
34 | + @enduml |
@@ -0,0 +1,50 @@ | ||
1 | +.. -*- plantuml -*- | |
2 | +.. filename: date of start | |
3 | +.. date in title: last version | |
4 | + | |
5 | +AIGR:: ComponentInterface and Protocols (231009) | |
6 | +================================================ | |
7 | + | |
8 | +.. uml:: | |
9 | + | |
10 | + @startuml | |
11 | + | |
12 | + abstract AIGR | |
13 | + class ComponentInterface | |
14 | + class Protocol | |
15 | + class EventProtocol | |
16 | + class Port { | |
17 | + - direction :PortDirection | |
18 | + - type :PortType | |
19 | + } | |
20 | + abstract ProtocolWrapper { | |
21 | + -based_on\n(the Generic Protocol) | |
22 | + } | |
23 | + class Argument <<(S,lightgreen)>> { | |
24 | + +value :Any | |
25 | + +name :Optional[Str] | |
26 | + } | |
27 | + class TypedParameters <<(S,lightgreen)>> { | |
28 | + +name :str | |
29 | + +type :Type | |
30 | + } | |
31 | + class Type <<(T,lightblue)>> | |
32 | + '-------------------- | |
33 | + | |
34 | + ComponentInterface <--- ComponentInterface: based_on | |
35 | + Port "*" -* ComponentInterface | |
36 | + | |
37 | + Protocol <--- Protocol: based_on | |
38 | + Protocol <-- EventProtocol | |
39 | + Protocol <-- ProtocolWrapper | |
40 | + | |
41 | + ProtocolWrapper *- "+"Argument | |
42 | + | |
43 | + EventProtocol *- "*" Event: events | |
44 | + Event *-- "*" TypedParameters : typedParameters | |
45 | + Event o- "?" Type: returns | |
46 | + | |
47 | + Port o. Protocol: type | |
48 | + | |
49 | + @enduml | |
50 | + |
@@ -0,0 +1,26 @@ | ||
1 | +.. -*- plantuml -*- | |
2 | + | |
3 | +TestDoubles/AIGR: The interfaces of the SIEVE (BUSY) | |
4 | +==================================================== | |
5 | + | |
6 | +.. uml:: | |
7 | + | |
8 | + @startuml | |
9 | + | |
10 | + object "**Sieve**" as Sieve <<ComponentInterface>> { | |
11 | + + {static} new(onPrime:int) | |
12 | + } | |
13 | + note right of Sieve: alt-name: **SieveMoat** | |
14 | + object try <<Port>>{ | |
15 | + In: PortDirection | |
16 | + SimpleSieve: type | |
17 | + } | |
18 | + object corprime <<Port>> { | |
19 | + Out: PortDirection | |
20 | + SimpleSieve: type | |
21 | + } | |
22 | + | |
23 | + Sieve *-- try | |
24 | + Sieve *-- corprime | |
25 | + | |
26 | + @enduml |
@@ -0,0 +1,94 @@ | ||
1 | +Namespace & protocols | |
2 | +********************* | |
3 | + | |
4 | +.. uml:: | |
5 | + | |
6 | + @startuml | |
7 | + | |
8 | + package "Protocols in ‘TheSieve’" as P1 <<Node>> { | |
9 | + | |
10 | + package start_sieve as P1A { | |
11 | + object start_sieve <<Source_NS>> #LightSkyBlue { | |
12 | + file: 'start_sieve.Castle' | |
13 | + } | |
14 | + object " " as P1A_d <<dict>> #lightcyan { | |
15 | + StartSieve | |
16 | + base :NS | |
17 | + } | |
18 | + object StartSieve <<EventProtocol>> | |
19 | + | |
20 | + start_sieve o-- P1A_d | |
21 | + start_sieve <-- StartSieve | |
22 | + P1A_d::StartSieve -> StartSieve #DarkMagenta | |
23 | + P1A_d::base --> base #DarkMagenta | |
24 | + } | |
25 | + | |
26 | + package slow_start as P1B { | |
27 | + object slow_start <<Source_NS>> #LightSkyBlue { | |
28 | + file: 'slow_start.Castle' | |
29 | + } | |
30 | + object " " as P1B_d <<dict>> #lightcyan { | |
31 | + SlowStart | |
32 | + base :NS | |
33 | + | |
34 | + } | |
35 | + object SlowStart <<EventProtocol>> { | |
36 | + queue_max :int | |
37 | + } | |
38 | + | |
39 | + slow_start o-- P1B_d | |
40 | + slow_start <-- SlowStart | |
41 | + P1B_d::SlowStart -> SlowStart #DarkMagenta | |
42 | + P1B_d::base -> base #DarkMagenta | |
43 | + } | |
44 | + | |
45 | + package simple_sieve as P1C { | |
46 | + object simple_sieve <<Source_NS>> #LightSkyBlue { | |
47 | + file: 'simple_sieve.Castle' | |
48 | + } | |
49 | + object " " as P1C_d <<dict>> #lightcyan { | |
50 | + SlowStart(1) | |
51 | + SimpleSieve | |
52 | + base :NS | |
53 | + slow_start :NS | |
54 | + } | |
55 | + object "SlowStart(1)" as SlowStart_1 <<ProtocolWrapper>> { | |
56 | + queue_max=1 | |
57 | + } | |
58 | + object SimpleSieve <<EventProtocol>> | |
59 | + SlowStart_1 <|-- SimpleSieve: based_on | |
60 | + | |
61 | + simple_sieve o-- P1C_d | |
62 | + simple_sieve <-- SlowStart_1 | |
63 | + simple_sieve <--- SimpleSieve | |
64 | + P1C_d::SlowStart_1 -> SlowStart_1 #DarkMagenta | |
65 | + P1C_d::SimpleSieve -> SimpleSieve #DarkMagenta | |
66 | + } | |
67 | + | |
68 | + P1B <--- P1C_d #LightSkyBlue : //import// ""slow_start"" | |
69 | + SlowStart <|---- SlowStart_1 #SkyBlue : based_on | |
70 | + } | |
71 | + | |
72 | + package "Build-in Protocols" as P2 <<Node>> { | |
73 | + package base { | |
74 | + object Protocol <<_RootProtocol>> | |
75 | + } | |
76 | + package buildin { | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + Protocol <|-- StartSieve #SkyBlue : based_on | |
81 | + Protocol <|-- SlowStart #SkyBlue : based_on | |
82 | + | |
83 | + | |
84 | + @enduml | |
85 | + | |
86 | +Updates | |
87 | +======= | |
88 | + | |
89 | +23Nov13 | |
90 | +------- | |
91 | + | |
92 | +* As ``SlowStart_1`` is based on ``SlowStart``, the **source_NS** (aka *package*) ``start_sieve`` needs to be | |
93 | + “imported”. So, a line is added. As well as the `start_sieve` entry in the NS of the ``simple_sieve`` package | |
94 | +* Also, the entry `base` was forgotten in that NS |
@@ -0,0 +1,104 @@ | ||
1 | +AIGR/SIEVE Namespace analyse | |
2 | +============================ | |
3 | + | |
4 | +.. uml:: | |
5 | + | |
6 | + @startuml | |
7 | + skin rose | |
8 | + 'skinparam style strictuml | |
9 | + skinparam sequenceMessageAlign left | |
10 | + | |
11 | + actor Dev | |
12 | + entity T_Protocol | |
13 | + boundary "CastleMacros.jinja2" as m | |
14 | + | |
15 | + !procedure $register($ns, $n, $details=0) | |
16 | + Dev -> $ns : register($n) | |
17 | + $ns o--\o $n : ""$ns._dict[$n] := $n"" | |
18 | + activate $ns | |
19 | + | |
20 | + !if $details | |
21 | + group details | |
22 | + $ns -> $ns : _register_2ways() | |
23 | + $ns-> $n : register_in_NS() | |
24 | + end | |
25 | + $n o--\o $ns :""$n._ns := $ns"" | |
26 | + !else | |
27 | + $n o--\o $ns :""$n._ns := $ns"" | |
28 | + !endif | |
29 | + deactivate $ns | |
30 | + !endprocedure | |
31 | + | |
32 | + | |
33 | + participant "simple_sieve :NS" as simple_sieve #LightSkyBlue | |
34 | + participant "slow_start :NS" as slow_start #LightSkyBlue | |
35 | + participant "SimpleSieve:P" as SimpleSieve | |
36 | + participant "SlowStart_1:P" as SlowStart_1 | |
37 | + participant "SlowStart:P" as SlowStart | |
38 | + | |
39 | + == TestDoubles/AIGR/sieve/namespaces.py == | |
40 | + | |
41 | + $register(simple_sieve, slow_start,1) | |
42 | + alt "old AIGR" | |
43 | + $register(simple_sieve, SlowStart_1) | |
44 | + else "deleted 'simple_sieve.register(protocols.SlowStart_1)'" | |
45 | + note over simple_sieve, SlowStart1 #aqua: Is it a hack? Should it be in RenderNS (ToDo), or ... | |
46 | + end | |
47 | + $register(simple_sieve, SimpleSieve) | |
48 | + $register(slow_start, SlowStart) | |
49 | + | |
50 | + == pytst/writers/RPy/test_3_SieveProtocols.py== | |
51 | + | |
52 | + | |
53 | + [-> T_Protocol: render((sieve.SlowStart_1, sieve.SimpleSieve)) | |
54 | + note left: ""inherit_from={{proto.based_on.ns.name}}.{{m.ProtocolName(proto.based_on)}}"" | |
55 | + | |
56 | + ... sieve.SlowStart_1 ... | |
57 | + T_Protocol -> SlowStart_1: based_on() | |
58 | + SlowStart_1 o/--x SlowStart: "".based_on"" | |
59 | + T_Protocol <-- SlowStart_1: SlowStart | |
60 | + | |
61 | + T_Protocol -> SlowStart: ns() | |
62 | + T_Protocol <-- SlowStart: slow_start | |
63 | + | |
64 | + opt "obj 2 str" | |
65 | + T_Protocol -> slow_start :name | |
66 | + T_Protocol <-- slow_start : "slow_start" | |
67 | + end | |
68 | + | |
69 | + T_Protocol -> m: ProtocolName(SlowStart) | |
70 | + T_Protocol <--m: ""cc_P_Slowstart"" | |
71 | + note right: cc_P_{{Proto.name}} | |
72 | + note left of T_Protocol: inherit_from=slow_start.cc_P_SlowStart | |
73 | + | |
74 | + ... sieve.SimpleSieve ... | |
75 | + T_Protocol -> SimpleSieve: based_on() | |
76 | + SimpleSieve o/--x SlowStart_1: "".based_on"" | |
77 | + T_Protocol <-- SimpleSieve: SlowStart_1 | |
78 | + | |
79 | + T_Protocol -> SlowStart_1: ns() | |
80 | + alt "old AIGR" | |
81 | + T_Protocol <-- SlowStart_1: simple_sieve | |
82 | + note left: Note: ‘simple_sieve’ is (also) is the current namespace\n\tSo, it should be named | |
83 | + | |
84 | + opt "obj 2 str" | |
85 | + T_Protocol -> simple_sieve : name | |
86 | + T_Protocol <-- simple_sieve : "<color:red>simple_sieve</color>" | |
87 | + end | |
88 | + | |
89 | + T_Protocol -> m: ProtocolName(SimpleSieve) | |
90 | + T_Protocol <--m: ""cc_P_SimpleSieve"" | |
91 | + note right: cc_P_{{Proto.name}} | |
92 | + | |
93 | + note left of T_Protocol #orangered: <color:yellow>inherit_from=<color:white>simple_sieve.<color:yellow>cc_P_SimpleSieve | |
94 | + else "deteled 'simple_sieve.register(protocols.SlowStart_1)'" | |
95 | + T_Protocol <-- SlowStart_1: <NIL> | |
96 | + | |
97 | + T_Protocol -> m: ProtocolName(SimpleSieve) | |
98 | + T_Protocol <--m: ""cc_P_SimpleSieve"" | |
99 | + | |
100 | + note left of T_Protocol #lime: <color:white>inherit_from=cc_P_SimpleSieve</color> | |
101 | + end | |
102 | + | |
103 | + @enduml | |
104 | + |
@@ -0,0 +1,15 @@ | ||
1 | +Some (LOCAL only) Design Notes | |
2 | +============================== | |
3 | + | |
4 | +This are “quick and dirty” design diagrams. That where useful when created (see file-name), but may be less relevant | |
5 | +later. | |
6 | + | |
7 | +* Sound designs, are typically worked out (adding text & view), and move to a stable, to-be-maintained, location | |
8 | +* Outdated ones are (will be) moved to :ref:`DocParts_Design_old` (and will never be maintained). | |
9 | +* the one here, a undecided, may or may-not be maintained. | |
10 | + | |
11 | +.. toctree:: | |
12 | + :glob: | |
13 | + | |
14 | + * | |
15 | + */index |
@@ -0,0 +1,139 @@ | ||
1 | +OLD-Peg Diagram | |
2 | +=============== | |
3 | + | |
4 | +This anayse/design(?) date from around 2021/2022 | |
5 | + | |
6 | +.. UML:: | |
7 | + | |
8 | + @startuml | |
9 | + | |
10 | + package _base { | |
11 | + | |
12 | + abstract AST_BASE { | |
13 | + -_parse_tree | |
14 | + +position() | |
15 | + +position_end() | |
16 | + ~serialize() | |
17 | + } | |
18 | + | |
19 | + class ID { | |
20 | + +name | |
21 | + #validate_or_raise() | |
22 | + } | |
23 | + | |
24 | + ID =|> AST_BASE | |
25 | + } | |
26 | + | |
27 | + package MixIns #Gray { | |
28 | + | |
29 | + class MixIn_value_attribute<MixIn> { | |
30 | + _value | |
31 | + value() | |
32 | + } | |
33 | + | |
34 | + class MixIn_expr_attribute<MixIn> { | |
35 | + _expr | |
36 | + expr() | |
37 | + } | |
38 | + | |
39 | + class MixIn_children_tuple<MixIn> { | |
40 | + _children :Tuple | |
41 | + __len__() | |
42 | + __getitem__() | |
43 | + __iter__() | |
44 | + } | |
45 | + } | |
46 | + | |
47 | + package Peg #0077ff { | |
48 | + | |
49 | + abstract PEG | |
50 | + AST_BASE <|== PEG | |
51 | + | |
52 | + | |
53 | + | |
54 | + abstract Terminal | |
55 | + PEG <|== Terminal | |
56 | + MixIn_value_attribute <|... Terminal | |
57 | + Terminal <|== StrTerm | |
58 | + Terminal <|== RexExpTerm | |
59 | + Terminal <|== Number | |
60 | + | |
61 | + abstract Markers #Orange | |
62 | + annotation EOF #Orange | |
63 | + PEG <|== Markers | |
64 | + Markers <|== EOF | |
65 | + | |
66 | + abstract NonTerminal | |
67 | + PEG <|== NonTerminal | |
68 | + abstract Expression | |
69 | + NonTerminal <|== Expression | |
70 | + | |
71 | + class Setting { | |
72 | + name : ID | |
73 | + value | |
74 | + } | |
75 | + PEG <|== Setting | |
76 | + | |
77 | + class Rule { | |
78 | + name :ID | |
79 | + expr :[] Expression | |
80 | + } | |
81 | + NonTerminal <|== Rule | |
82 | + | |
83 | + interface Rules | |
84 | + PEG <|== Rules | |
85 | + MixIn_children_tuple <|... Rules | |
86 | + Rules <|== ParseRules | |
87 | + Rules <|== Settings | |
88 | + | |
89 | + class Grammar { | |
90 | + +all_rules :Rules | |
91 | + -parse_rules :ParseRules | |
92 | + -settings :Settings | |
93 | + } | |
94 | + NonTerminal <|== Grammar | |
95 | + | |
96 | + | |
97 | + abstract Group | |
98 | + Expression <|== Group | |
99 | + Group <|== UnorderedGroup | |
100 | + MixIn_expr_attribute <|... UnorderedGroup | |
101 | + abstract Quantity | |
102 | + Group <|== Quantity | |
103 | + MixIn_expr_attribute <|... Quantity | |
104 | + Expression <|== Sequence | |
105 | + MixIn_children_tuple <|... Sequence | |
106 | + | |
107 | + Expression <|== OrderedChoice | |
108 | + MixIn_children_tuple <|... OrderedChoice | |
109 | + | |
110 | + class Optional << (?, #0077ff) >> | |
111 | + Quantity <|== Optional | |
112 | + class ZeroOrMore << (*, #0077ff) >> | |
113 | + Quantity <|== ZeroOrMore | |
114 | + class OneOrMore << (+, #0077ff) >> | |
115 | + Quantity <|== OneOrMore | |
116 | + | |
117 | + abstract Predicate | |
118 | + Expression <|== Predicate | |
119 | + MixIn_expr_attribute <|... Predicate | |
120 | + class AndPredicate << (&, #0077ff) notconsuming >> | |
121 | + Predicate <|== AndPredicate | |
122 | + class NotPredicate << (! ,#0077ff) not consuming >> | |
123 | + Predicate <|== NotPredicate | |
124 | + | |
125 | + } | |
126 | + @enduml | |
127 | + | |
128 | + | |
129 | + | |
130 | + | |
131 | + | |
132 | + | |
133 | + | |
134 | + | |
135 | + | |
136 | + | |
137 | + | |
138 | + | |
139 | + |
@@ -0,0 +1,12 @@ | ||
1 | +.. _DocParts_Design_old: | |
2 | + | |
3 | +Old (design) notes (LOCAL only) | |
4 | +=============================== | |
5 | + | |
6 | +These are outdated, and not maintain | |
7 | + | |
8 | +.. toctree:: | |
9 | + :glob: | |
10 | + | |
11 | + * | |
12 | + */index |
@@ -0,0 +1,9 @@ | ||
1 | +All kind of (LOCAL only) Designs | |
2 | +================================= | |
3 | + | |
4 | + | |
5 | +.. toctree:: | |
6 | + :glob: | |
7 | + | |
8 | + * | |
9 | + */index |
@@ -0,0 +1,102 @@ | ||
1 | +PortNumbers: not needed in the AIGR nor RPy | |
2 | +******************************************* | |
3 | + | |
4 | +Summary | |
5 | +======= | |
6 | + | |
7 | +After a successful try with (optional) *AutoNumbering*, I decided that the **port_number** *(a low int)* is an unneeded | |
8 | +leftover of the once “handCompiled-C” version. It isn't needed in general. And so, -as we don’t store/use *portNo*-- the | |
9 | +auto-numbering option is removed (but documented, as it might be convenient later). | |
10 | + | |
11 | +Background | |
12 | +---------- | |
13 | + | |
14 | +In the (handCompiled) C version, everything is stored in an C-array; and we have to use (array) indexes to find the | |
15 | +element. Therefore, those port numbers (as index) have to be unique, contiguous “low” numbers. In general, this is | |
16 | +inconvenient. When a base-component(interface) changes the number of ports, all other have to be renumbered. | |
17 | +|BR| | |
18 | +That is fine for (generated) C-code, but unwanted in e.g the AIGR-model. | |
19 | + | |
20 | +Also the *Sieve_in_rPython* variant has those index ``portNo``’s -- although with a question-mark. And thy are never | |
21 | +used. | |
22 | +|BR| | |
23 | +Arrays in (r)Python are list and can be indexed with (e.g.) a name. Such a ``nameID`` is more convenient, and the Castle | |
24 | +semantics already secures uniqueness. | |
25 | + | |
26 | +Thus,the RPy backend doesn't need to render ‘PortNo’ (see | |
27 | +file:`castle/writers/RPy/templates/parts/interface_DataStructures.jinja2`) and hence doesn't need in the AIGR either. | |
28 | + | |
29 | + | |
30 | +AutoNumbering | |
31 | +============== | |
32 | + | |
33 | +I have made a variant of :file:`castle/aigr/interfaces.py` to support automatically numbering of port. It quite simple. | |
34 | + | |
35 | +* We need to store the `port_no` in ``Port`` and with a default marker: `_AUTO_NUMBER`. | |
36 | +* In ``ComponentInterface``, in the post_init a call to ``_number_auto_ports()`` is make | |
37 | +* That method add portNo’s to the ports of that instance. After some basic checks. | |
38 | + |BR| | |
39 | + Note, the routine isn't perfect - there are complex edge cases that are ignored. | |
40 | + | |
41 | +.. code-block:: ReasonML | |
42 | + :emphasize-lines: 3,8 | |
43 | + | |
44 | + @dataclass | |
45 | + class Port(AIGR): | |
46 | + _AUTO_NUMBER=-1 | |
47 | + name: str | |
48 | + _: KW_ONLY | |
49 | + direction: PortDirection | |
50 | + type: PortType | |
51 | + port_no: int=_AUTO_NUMBER # automatically set in ComponentInterface | |
52 | + | |
53 | + | |
54 | +.. code-block:: ReasonML | |
55 | + :emphasize-lines: 4,7 | |
56 | + | |
57 | + @dataclass | |
58 | + class ComponentInterface(AIGR): | |
59 | + ... | |
60 | + def __post_init__(self): | |
61 | + self._number_auto_ports() | |
62 | + | |
63 | + def _number_auto_ports(self): | |
64 | + all_auto = all(p.port_no == Port._AUTO_NUMBER for p in self.ports) | |
65 | + if all_auto: | |
66 | + start = self.based_on._noPorts() if isinstance(self.based_on, ComponentInterface) else 0 | |
67 | + for n, p in enumerate(self.ports, start=start): | |
68 | + p.port_no = n | |
69 | + else: | |
70 | + any_auto =any(p.port_no == Port._AUTO_NUMBER for p in self.ports) | |
71 | + assert not any_auto, "Do not mix automatic port-numbering with pre-set ones. Typically, use set all!!" | |
72 | + | |
73 | +.. error:: AutoNumbering is tricky | |
74 | + | |
75 | + During the development, all kind of complex edge cases are found. As the feature is removed, those checks are | |
76 | + (mostly) ignored. And covert by statements as “do not mix”, “use with care”, and “only during development”. | |
77 | + | |
78 | + Conceptually, all (the inherited and own/defined) ports should be numbered: 0, 1, 2 ... | |
79 | + |BR| | |
80 | + Whenever a portNo can be preset, that isn’t possible. Some corner cases: | |
81 | + | |
82 | + * The pre-set numbers of two ports can be te same. | |
83 | + | |
84 | + - Ignore in auto-numbering, as it can’t be fixed (here) | |
85 | + - Idea (not realised): write a checker (plugin) for the AIGR-model | |
86 | + - As a variant: those non unique numbers can be set in anywhere in inherit tree of `Components`. | |
87 | + | |
88 | + * Some portNo’s are set, others not | |
89 | + | |
90 | + - We kind of need to find the available numbers first | |
91 | + - Is there a reason that some numbers are skipped? Than do no use them -- complex | |
92 | + - Or, just continue at the highest port-no -- more holes | |
93 | + | |
94 | + * We need all kind of auxiliary methods for ComponentInterface, to handle port-numbering | |
95 | + | |
96 | + - Not *SOLID*: code becomes hard to maintain and misleading | |
97 | + - But, putting the in ``Port`` doesn't solve it | |
98 | + | |
99 | + | |
100 | +At the end, instead of “solving” those issues, I reconsidered the portNo attribute. By abandoning that left-over, all | |
101 | +those issues are solved too. | |
102 | + |
@@ -0,0 +1,9 @@ | ||
1 | +Some notes (LOCAL only) | |
2 | +======================= | |
3 | + | |
4 | + | |
5 | +.. toctree:: | |
6 | + :glob: | |
7 | + | |
8 | + * | |
9 | + */index |
@@ -0,0 +1,9 @@ | ||
1 | +Partial Docs (LOCAL only) | |
2 | +========================= | |
3 | + | |
4 | + | |
5 | +.. toctree:: | |
6 | + :glob: | |
7 | + | |
8 | + * | |
9 | + */index |