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 Given that micropython has already deduced object and parameter details,
12 such information must be communicated in the systems programming language
13 so that the compiler does not have to deduce it again.
14
15 Explicit constant declaration shall be done at the start of the main
16 module:
17
18 __constants__(...)
19
20 Explicit structure declaration is still performed using class statements,
21 but base classes are omitted and attributes are declared explicitly as
22 follows:
23
24 class C:
25 __instattrs__(member...)
26 __classattrs__(member...)
27
28 Other object table information, such as inherited class attributes and
29 class compatibility (to support isinstance) are also declared explicitly:
30
31 __inherited__(superclass, member...)
32 __descendants__(class...)
33
34 Other than function definitions, no other code statements shall appear in
35 class definitions; such statements will appear after classes have been
36 defined in a __main__ function collecting together all "loose"
37 (module-level) statements.
38
39 Imports act as invocations of module code and name assignments within a
40 particular scope and are defined as follows:
41
42 # import package
43 package.__main__()
44 package = __module__(package)
45
46 # import package.module
47 package.__main__()
48 package.module.__main__()
49 package = __module__(package)
50
51 # from package.module import cls
52 package.__main__()
53 package.module.__main__()
54 cls = __loadattribute__(package.module, cls) # see below
55
56 Since import statements can appear in code that may be executed more than
57 once, __main__ functions should test and set a flag indicating whether the
58 function has already been called.
59
60 Python would arguably be more sensible as a language if imports were
61 processed separately, but this would then rule out logic controlling the
62 use of modules.
63
64 Assignments and name usage involve locals and globals but usage is declared
65 explicitly:
66
67 __localnames__(...)
68
69 At the function level, locals are genuine local name definitions whereas
70 globals refer to module globals:
71
72 __globalnames__(...)
73
74 At the module level, locals are effectively equivalent to module globals but
75 are declared as follows:
76
77 __moduleattrs__(...)
78
79 Each module's __main__ function will declare any referenced module globals as
80 globals. Note that the __main__ function is not a genuine attribute of any
81 module but an internal construct used to initialise modules appropriately.
82
83 Such declarations must appear first in a program unit (module, function).
84 For example:
85
86 def f(a, b):
87 __localnames__(a, b, x, y)
88 __globalnames__(f, g)
89
90 x = 1 # local
91 y = x # locals
92 a = b # locals
93 g = f # globals
94
95 No operator usage: all operators are converted to invocations, including
96 all attribute access except static references to modules using the
97 following notation:
98
99 __module__(package)
100 __module__(package.module)
101 package.module # shorthand where dot notation is used
102
103 In general, attribute access must use an explicit function indicating the
104 kind of access operation being performed. For example:
105
106 __loadaddress__(obj, attrname)
107 __loadaddresscontext__(obj, attrname)
108 __loadaddresscontextcond__(obj, attrname)
109 __loadattr__(obj, attrname)
110 __loadattrindex__(obj, attrname)
111 __loadattrindexcontext__(obj, attrname)
112 __loadattrindexcontextcond__(obj, attrname)
113
114 __storeaddress__(obj, attrname, value)
115 __storeaddresscontext__(obj, attrname, value)
116 __storeattr__(obj, attrname, value)
117 __storeattrindex__(obj, attrname, value)
118
119 Conventional operators use the operator functions.
120
121 Special operators could also use the operator functions (where available)
122 but might as well be supported directly:
123
124 __is__(a, b)
125
126 Logical operators involving short-circuit evaluation could be represented
127 as function calls, but the evaluation semantics would be preserved:
128
129 __and__(...) # returns the first non-true value or the final value
130 __not__(obj) # returns the inverse of the boolean interpretation of obj
131 __or__(...) # returns the first true value or the final value
132
133 Comparisons could be rephrased in a verbose fashion:
134
135 a < b < c becomes lt(a, b) and lt(b, c)
136 or __and__(lt(a, b), lt(b, c))
137
138 Any statements requiring control-flow definition in terms of blocks must
139 be handled in the language as the notions of labels and blocks are not
140 introduced earlier apart from the special case of jumping to another
141 callable (described below).
142
143 Special functions for low-level operations:
144
145 __check__(obj, type)
146 __jump__(callable)
147
148 Function/subroutine definition with entry points for checked and unchecked
149 parameters.
150
151 def fn_checked(self, ...):
152 __check__(self, Type) # raises a TypeError if not isinstance(self, Type)
153 __jump__(fn_unchecked) # preserves the frame and return address
154
155 def fn_unchecked(self, ...):
156 ...