1 A Systems Programming Language Target for Micropython
2 =====================================================
3
4 Python-compatible syntax for processing using the compiler module.
5
6 The principal focus is on specific machine code generation and not
7 analysis. Thus, only block generation, address reference generation,
8 temporary storage administration and other code generation tasks are to be
9 left to the systems programming language compiler.
10
11 Special Functions
12 -----------------
13
14 In syspython, the function invocation notation is reserved to specify
15 primitive operations such as attribute access and actual function invocations,
16 with the latter being expressed as follows:
17
18 fn(y) # original Python
19 apply(fn, y) # syspython
20
21 Thus, in syspython, whenever the invocation notation is used, the target of
22 the invocation is always a special function and not a general Python function
23 or method. Note that the apply function resembles the Python function of the
24 same name but is not actually that particular function.
25
26 Low-Level Code
27 --------------
28
29 Most Python-level program code should be wrapped in special function
30 invocations, and as a result other syntax features might be used to express
31 low-level concepts. Low-level operations may also be expressed using other
32 special functions. For example:
33
34 storelocal(element, loadobjtable(loadattr(obj, classcode), attrcode))
35
36 Here, element holds the raw data provided by the table access involving a base
37 defined by the classcode of an object and an offset defined by the supplied
38 attrcode.
39
40 Note that all low-level functions deal only with addresses and offsets, not
41 symbols. In the above example, loadattr combines the address of obj with the
42 symbol classcode whose actual value must be substituted by the compiler.
43 However, the loadobjtable function requires a genuine offset value for the
44 classcode (which is why loadattr is being used to obtain it), and a genuine
45 offset for the attrcode (which is provided directly).
46
47 Program Data and Data Structure Definition
48 ------------------------------------------
49
50 Given that micropython has already deduced object and parameter details,
51 such information must be communicated in the systems programming language
52 so that the compiler does not have to deduce it again.
53
54 Explicit constant declaration shall be done at the start of the main
55 module:
56
57 constants(...)
58
59 Each module may feature keyword arguments, and a list of such names is
60 provided as follows:
61
62 keywords(...)
63
64 Explicit structure declaration is still performed using class statements,
65 but base classes are omitted and attributes are declared explicitly as
66 follows:
67
68 class C:
69 instattrs(member...)
70 classattrs(member...)
71
72 Other object table information, such as inherited class attributes and
73 class compatibility (to support isinstance) are also declared explicitly:
74
75 inherited(superclass, member...)
76 descendants(class...)
77
78 Other than function definitions, no other code statements shall appear in
79 class definitions; such statements will appear after classes have been
80 defined.
81
82 For classes in the module namespace or within other classes, the __main__
83 function collects together all "loose" (module-level) statements; class
84 attribute assignments will occur in the __main__ function, and where a name
85 is associated with a function definition and another object, the function will
86 also be explicitly assigned in the __main__ function using its full name.
87
88 For classes in function namespaces, the containing function could contain the
89 "loose" statements at the point at which the class appears. However, such
90 classes are not currently supported in micropython.
91
92 Any class or function defined once in a namespace need not be assigned to that
93 namespace in the __main__ function, but where multiple definitions exist and
94 program logic determines which definition prevails, such definitions must be
95 assigned in the __main__ function.
96
97 For example:
98
99 class C:
100 def method(self, ...):
101 ...
102 if something:
103 method = something
104
105 This is represented as follows:
106
107 class C:
108 ...
109 def method(self, ...):
110 ...
111
112 def __main__():
113 globalnames(...)
114 ...
115 if something:
116 storeattr(module.C, method, something)
117
118 Imports
119 -------
120
121 Imports act as invocations of module code and name assignments within a
122 particular scope and are defined as follows:
123
124 # import package
125 package.__main__()
126 storelocal(package, static(package))
127
128 # import package.module
129 package.__main__()
130 package.module.__main__()
131 storelocal(package, static(package))
132
133 # from package.module import cls
134 package.__main__()
135 package.module.__main__()
136 storelocal(cls, loadattribute(package.module, cls)) # see below
137
138 Since import statements can appear in code that may be executed more than
139 once, __main__ functions should test and set a flag indicating whether the
140 function has already been called.
141
142 Python would arguably be more sensible as a language if imports were
143 processed separately, but this would then rule out logic controlling the
144 use of modules.
145
146 Name and Attribute Declarations
147 -------------------------------
148
149 Assignments and name usage involve locals and globals but usage is declared
150 explicitly:
151
152 localnames(...)
153
154 At the function level, locals are genuine local name definitions whereas
155 globals refer to module globals:
156
157 globalnames(...)
158
159 At the module level, locals are effectively equivalent to module globals and
160 are declared as such.
161
162 Each module's __main__ function will declare any referenced module globals as
163 globals. Note that the __main__ function is not a genuine attribute of any
164 module but an internal construct used to initialise modules appropriately.
165
166 Such declarations must appear first in a program unit (module, function).
167 For example:
168
169 def f(a, b):
170 localnames(a, b, x, y)
171 globalnames(f, g)
172
173 storelocal(x, 1)
174 storelocal(y, x)
175 storelocal(a, b)
176 storeattr(module, g, f)
177
178 Names and Attributes
179 --------------------
180
181 Bare names refer to locals or globals according to the localnames and
182 globalnames declarations, or to constants such as None, True, False and
183 NotImplemented. Storage of local or global names is done using explicit
184 functions as follows:
185
186 storelocal(name, value)
187 storeattr(module, name, value) # see below
188
189 No operator usage: all operators are converted to invocations, including
190 all attribute access except static references to modules or particular class
191 or function definitions using the following notation:
192
193 static(package)
194 static(package.module)
195 static(package.module.cls)
196 static(package.module.cls.function)
197
198 A shorthand dot notation could be employed:
199
200 package.module
201 package.module.cls
202 package.module.cls.function
203
204 Where multiple definitions of static objects occur, the dot notation cannot be
205 used, and the full name of such definitions must be quoted. For example:
206
207 static("package.module.cls#1.function")
208
209 In general, attribute access must use an explicit function indicating the
210 kind of access operation being performed. For example:
211
212 # Instance-related operations:
213
214 loadattr(obj, attrname) # preserve retrieved context
215
216 # Static attribute operations:
217
218 loadaddress(parent, attrname) # preserve retrieved context
219 loadaddresscontext(parent, attrname, obj) # replace context with obj
220 loadaddresscontextcond(parent, attrname, obj) # run-time context decision
221
222 # Unoptimised operations:
223
224 loadattrindex(obj, attrname) # preserve retrieved context
225 loadattrindexcontextcond(obj, attrname) # run-time context decision
226
227 # Instance-related operations:
228
229 storeattr(obj, attrname, value) # preserve context for value
230
231 # Static attribute operations:
232
233 storeaddress(parent, attrname, value) # preserve context for value
234 storeaddresscontext(parent, attrname, value, obj) # replace context with obj
235
236 # Unoptimised operations:
237
238 storeattrindex(obj, attrname, value) # preserve context for value
239
240 Recall that for loadattrindex family functions, the location of the attribute
241 is obtained from the object table and the nature of the attribute is
242 determined from the stored context value.
243
244 Temporary variables could employ similar functions:
245
246 loadtemp(0)
247 storetemp(0, value)
248
249 Operators and Invocations
250 -------------------------
251
252 Conventional operators use the operator functions.
253
254 Special operators could also use the operator functions (where available)
255 but might as well be supported directly:
256
257 __is__(a, b)
258 __is_not__(a, b)
259
260 Logical operators involving short-circuit evaluation could be represented
261 as function calls, but the evaluation semantics would be preserved:
262
263 __and__(...) # returns the first non-true value or the final value
264 __not__(obj) # returns the inverse of the boolean interpretation of obj
265 __or__(...) # returns the first true value or the final value
266
267 Comparisons could be rephrased in a verbose fashion:
268
269 a < b < c becomes lt(a, b) and lt(b, c)
270 or __and__(lt(a, b), lt(b, c))
271
272 Advanced Control-Flow
273 ---------------------
274
275 Any statements requiring control-flow definition in terms of blocks must
276 be handled in the language as the notions of labels and blocks are not
277 introduced earlier apart from the special case of jumping to another
278 callable (described below).
279
280 Special functions for low-level operations:
281
282 check(obj, type)
283 jump(callable)
284
285 Function/subroutine definition with entry points for checked and unchecked
286 parameters.
287
288 def fn_checked(self, ...):
289 check(self, Type) # raises a TypeError if not isinstance(self, Type)
290 jump(fn_unchecked) # preserves the frame and return address
291
292 def fn_unchecked(self, ...):
293 ...
294
295 The jump function might also be used for inlining appropriate functions.
296
297 Exceptions must also be handled in the language.
298
299 Object Type Detection
300 ---------------------
301
302 Occasionally, the type of an object (instance of a particular class, class,
303 and so on) needs to be determined at run-time:
304
305 isclass(obj)