source: doc/proposals/modules-gen-hdr/README

Last change on this file was 47064914, checked in by Michael Brooks <mlbrooks@…>, 3 months ago

Add missing Makefile, provide gitignore that hit it, minor edit readme

  • Property mode set to 100644
File size: 8.0 KB
Line 
1cfa-cppp - CForall pre-preprocessor
2
3POC deriving header files from a compile unit's source.
4
5Input: Aet of interdependent *.src.c files, each written as if header files are not a consideration (Java-style, definitions only), annotated with both the language additions and POC scaffolding listed below.
6
7Key Intermediate: For each %.src.c input, %.tdcl.h, %.defn.h, %.impl.c, containing relevant true-cpp #include directives of each other, such that the resulting classic-C build of a self-sufficient set of *.impl.c files gives the demo's Output.
8
9Output: Linked and running program
10
11Terminology
12- auto: as in C, "exported from here;" different from `extern`, which means "exported by someone else" in C
13- shred: "Shredding foo.src.c" means producing the "foo" Key Intermediates from the "foo" Input.
14- value: the opposite of a type, includes function
15- vicious: cyclic dependency that cannot be bootstrapped with the tools under POC
16
17
18To run:
19 if grep -q 'cfa-cppp' Makefile; then echo ok; else echo Wrong folder; fi;
20 make # expect success
21 hello/a.out # expect log of fcn calls and glb-var vals
22 coop/a.out # expect log of chickens hatching from eggs
23 akwd-val-trans/a.out # expect four coop-like logs of a/b calls
24 make err-vicious/a.out # expect failure after shredding done
25 make clean # expect success
26 make hello/a.out CFLAGS=-DERR1 # expect failure after shredding done
27 grep -rE 'ERR[0-9]*' --include=*.src.c # repeat prev -DERR act / do "manual" steps
28 # on resulting grep hits
29
30
31Demos are
32- (`err-` means "build is expected to fail")
33- hello: valid hello-world scenario with transitive dependency
34 - linear (bottom-up) build order would be fine
35- coop (chickens and eggs): valid circular dependency, resolved with `import auto &`
36 - "as much mutual recursion as I can cram, without going vicious"
37- vicious: the bridge too far, that coop resisted crossing, a:tdefs <-> b:tdefs
38 - requires an out-of-scope user's recourse, like multiple manual header fragments
39 - there does not exist a C-valid order of each module's offerings obtainable by ordering based on only offering sort (e.g. type definition, value declaration) and compile unit
40 - would never arise as real C code, without a split like one compile unit implementing two headers
41 - key difficulty: each side has a type definition that embeds a type defined on the opposite side
42- typeof: valid cicular dependency, its poential hiding in typeof
43 - b:vdefs -> a:tdefs -> b:vdecls
44- vicious-typeof: a vicious-cycle potential hiding in typeof, a:vdecls <-> b:vdecls
45 - comments under 'vicious' apply
46 - (including) expect recourse like multiple manual header fragments to resolve
47- vicious*/recourse-classic
48 - example of a manual header split that resolves the circularity
49- vicious*/recourse-proposed
50 - same split, given in a plausible headerless representation that's not demo-implemented
51
52In scope
53- module-level export vs private
54- automatically handle circular dependency (demos: valid=coop invalid=err-vicious)
55- ordered dependency with transitive "re-export" (demo: hello)
56- separate compilation
57- structs, functions and global variables
58
59Out of Scope
60- (though believed not deal breakers for this proposal)
61- quality error messages
62- private struct fields, friends
63- illustrating how to set up a build (current Makefile is "get it to work")
64- crawling imports ("first-time gcc -MMD"), determining a build order
65- interaction of these modules with preexsting CFA features (current demos are C)
66- extracting shred-relevant information from C source (mocked up with scaffolding below)
67- C preprocessor integration: exporting a macro, ifdef'ing a #import
68- user's recourse for situations where headers are not inferrable
69- typedefs
70- controling visibility of types (equiv. choosing to put a struct in *.h vs *.c)
71- proffering implementation (equiv. function bodies in the header, like for static-inline)
72- rejecting attempt to offer something public that can't be understood without seeing something private
73- relaxing declare before use
74- legacy integration (demo uses printf/exit as loose declarations, main as "just define it")
75- linker control (demo dumps all exports into one linker namespace)
76
77
78Language additions modelled
79- (The proposal is to add nicer versions of these placeholders to CFA)
80- module imports (#import), where `foo` corresponds with foo.c; one of:
81- `#import static foo`: this implementation depends on foo's interface
82 - most common, equivaluent of #include in *.c
83- `#import auto & foo`: above, plus this interface mentions types from foo's interface without relying on size information
84 - relevant limitation is you can't nest those types inside types defined here
85 - it's a recourse for breaking a "normal" include cycle
86 - syntax parallels `forall T &` emphasizing you get enough to define functions that take imported types by reference, but not by value
87 - uncommon, equiv. replacing #include with a type forward declaration or giving *.fwd.h)
88- `#import auto foo`: above, plus this interface has unlimited access to foo's interface (quite common, equiv. #include in *.h)
89
90Scaffolding for the POC
91- (The proposal is to have better compile-time analysis, making these elements unnecessary)
92- No single-line definitions allowed
93- The first line of every user-given definition is a valid declaration, with its semicolon removed and an open-curly added
94- Every user-given definition is preceded, on the adjacent line, by a `//#` directive, which is the appropriate one of:
95 - `@` for an exported type
96 - `$f` for an exported function
97 - `$v` for an exported variable
98 - `-` for anything static
99- Generally, abide with the shredder being brittle on whitespace
100
101Choice: semantics of transitive import
102- Option A: To import+export a depended-upon module means re-exporting both its types and its values (functions, variables)
103 - Benefit: the typical basic application of C headers works this way
104- Option B: To import+export a depended-upon module means re-exporting only its types
105 - I'll use those types types in my exported declarations
106 - by importing me, you'll get those types so that you can use my declarations
107 - if you also want its values, you'll need to import them yourself
108 - Benefit: gives importers a tidier symbol table; you get implicitly only what you actually need
109- Incomplete Option A used in demo: You re-export values only with `import auto M`, but not with `import auto & M`.
110 - This association is unnecessary mental complexity for a user.
111 - To do either a clean option A or B requires
112 - adding a third header flavour (a further split of .defn.h)
113 - furthermore, option A probably needs the rules for desugaring #import into #include to become transitive
114 - Left KISS / "common denominator" here
115 - Present-state workaround to achieve full Option A: Extra import in demo `akwd-val-trans/over_a.src.c`
116 - No option-B mockup available from present state because decision "`import auto M` re-exports values" means present state does exports that option B does not want
117
118Eventual implementation remark
119- To extract shred-relevant information from C source...
120- For %.c -> %.tdcl.h
121 - Ignore imports
122 - Need a limp-mode parser that does not differentiate types from identifiers
123 - It only has to produce the list of type names (non-recursively) exported, i.e. infer the `//# @` annotations
124- For %.c -> {%.defn.h, %.impl.c}
125 - On seeing `import auto foo` (or `import auto & foo`), pre-load the parser's type/id table as if `import auto & foo`, i.e. recursively consult imports, in limp mode, stopping upon a cycle (like #pragma once).
126 - It's not necessary to know information in foo.defn.h to shred % accurately.
127 - Today's CFA parser works and is sufficient (though overkill)
128 - Parsing here only needs to enable extracting a declaration from its definition.
129 - User errors, like, "You tried to pass an incomplete type by value," can come out later, while compiling %.impl.c.
Note: See TracBrowser for help on using the repository browser.