source: doc/proposals/modules-gen-hdr/cfa-cppp

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

Add POC illustrating generating headers from compile units

  • Property mode set to 100755
File size: 5.4 KB
Line 
1#! /usr/bin/python3
2
3import fileinput
4import sys
5import re
6import os
7from enum import Enum
8
9class Section(Enum):
10 PREAMBLE = 1
11 EXP_TYPE = 2
12 EXP_VALUE = 3
13 STATIC = 4
14 UNKNOWN = 5
15
16class ValueSubsection(Enum):
17 FUNCTION = 1
18 VARIABLE = 2
19 NA = 3
20
21outfile = sys.argv[1]
22outfile_local = os.path.basename(outfile)
23parts = re.match(r"(?P<module>.*)\.(?P<mode>[^\.]*)\.[hc]$", outfile_local)
24module = parts.group('module')
25outtype = parts.group('mode')
26
27srcfile = os.path.join(os.path.dirname(outfile), module) + ".src.c"
28circImpVar = "__{mod}_{ty}_IMPORTING__".format(mod=module.upper(), ty=outtype.upper())
29
30sys.stdout = open(outfile, 'w')
31
32# data about the current //#-delimited chunk of file
33section = Section.PREAMBLE
34valueSubsection = ValueSubsection.NA
35lines = []
36
37def declOnly():
38 if valueSubsection == ValueSubsection.VARIABLE:
39 eqpos = lines[0].find('=')
40 lines[0] = lines[0][0:eqpos]
41 print( 'extern', lines[0], ';' )
42 else:
43 if lines[0].endswith("{"):
44 lines[0] = lines[0][0:len(lines[0])-2].rstrip()
45 print( lines[0], ';' )
46
47def fulldump():
48 for line in lines:
49 print(line)
50
51def flush():
52 global lines
53 # print("\t// flush", outtype, section)
54
55 if (section == Section.PREAMBLE):
56 postpreamble()
57 elif (len(lines) == 0):
58 return
59 elif (outtype == 'tdcl') & (section == Section.EXP_TYPE):
60 declOnly()
61 elif (outtype == 'defn') & (section == Section.EXP_TYPE):
62 fulldump()
63 elif (outtype == 'defn') & (section == Section.EXP_VALUE):
64 declOnly()
65 elif (outtype == 'impl') & (section == Section.EXP_VALUE):
66 fulldump()
67 elif (outtype == 'impl') & (section == Section.STATIC):
68 fulldump()
69 else:
70 for line in lines:
71 pass #print("//", line)
72
73 lines = []
74
75class ImportStyle(Enum):
76 NO_EXPORT = 1
77 EXPORT_INCOMPLETE = 2
78 EXPORT_COMPLETE = 3
79
80def emitInclude(imodule, iftype):
81 print('#include "{mod}.{typ}.h"'.format(mod=imodule, typ=iftype))
82
83def import_(cmd):
84 if section == Section.PREAMBLE:
85 if cmd.startswith("auto"):
86 cmd = cmd.replace("auto","").lstrip()
87 if cmd.startswith("&"):
88 cmd = cmd.replace("&","").lstrip()
89 style = ImportStyle.EXPORT_INCOMPLETE
90 else:
91 style = ImportStyle.EXPORT_COMPLETE
92 elif cmd.startswith("static"):
93 cmd = cmd.replace("static","").lstrip()
94 style = ImportStyle.NO_EXPORT
95 else:
96 print("#error import not understood:", cmd)
97 style = ImportStyle.NO_EXPORT
98 imodule = cmd
99 if( style != ImportStyle.EXPORT_COMPLETE) & (outtype == "impl"):
100 emitInclude(imodule, "defn")
101 if (style == ImportStyle.EXPORT_COMPLETE) & (outtype == "defn"):
102 emitInclude(imodule, "defn")
103 if (style != ImportStyle.NO_EXPORT) & (outtype == "tdcl"):
104 emitInclude(imodule, outtype)
105 else:
106 print("#error illegal place for: import ", cmd)
107
108def beginunit():
109 print("//", outfile_local)
110 if (outtype == "tdcl"):
111 print("#pragma once")
112 elif outtype == "defn":
113 print("#ifdef", circImpVar)
114 print("#error Illegal circularity detected")
115 print("#else")
116 print("#define", circImpVar)
117 if outtype == "defn":
118 emitInclude(module, "tdcl")
119 elif outtype == "impl":
120 emitInclude(module, "defn")
121
122def postpreamble():
123 if outtype == "defn":
124 print("#undef", circImpVar)
125 print("#pragma once")
126
127
128
129def endunit():
130 if outtype == "defn":
131 print("#endif // ", circImpVar)
132
133try:
134 with open(srcfile, "r") as file:
135 beginunit()
136 for line in file:
137 line = line.rstrip()
138 if ( line.startswith("#import") ):
139 line = line.replace("#import", "").lstrip()
140 import_(line)
141 elif ( line.startswith("//#") ):
142 flush()
143 line = line.replace("//#", "").lstrip()
144 if line[0] == '@':
145 section = Section.EXP_TYPE
146 valueSubsection = ValueSubsection.NA
147 elif line[0] == '$':
148 section = Section.EXP_VALUE
149 valueSubsection = ValueSubsection.NA
150 # print("\t// object decl:{name}, with deps:{decldeps}".format(
151 # name=name, decldeps=decldeps))
152 line = line[1:]
153 if line[0] == 'f':
154 valueSubsection = ValueSubsection.FUNCTION
155 elif line[0] == 'v':
156 valueSubsection = ValueSubsection.VARIABLE
157 else:
158 print("#error $-subdirective not understood: ", line)
159 valueSubsection = ValueSubsection.NA
160 elif line[0] == '-':
161 section = Section.STATIC
162 valueSubsection = ValueSubsection.NA
163 else:
164 print("#error directive not understood:", line)
165 section = Section.UNKNOWN
166 valueSubsection = ValueSubsection.NA
167 line = line[1:]
168 else:
169 line = line.split("//")[0].rstrip()
170 if (line):
171 lines.append(line)
172 flush()
173 endunit()
174except FileNotFoundError:
175 print("Error: The file '" + srcfile + "' was not found.")
176
177
Note: See TracBrowser for help on using the repository browser.