Skip to content

Commit eb896cf

Browse files
zimri-leisherZimri Leisher
andauthored
Fpy loops (#246)
* start working on loops * get expr attr * Much more work on getting members of exprs * All tests passing on new grammar! * small bugfixes * Variable array index and oob checks seem to work * Fix bug in model * Some attempt to get scope working... * lil more fixes * Some work on for loops * Much more work on for and while loops, added assert stmt * Stuck on a lil problem with variable scope * Much more work on for loops, seems to be almost working * little more work on loops * some more work on loops * Significant rework of files, get for and while loops mostly workinggits! * Start working on check * A little work on break/continue * Break and continue working * lil test * Remove check * Start working on casting * start working on const folding * Switch over to new codegen system, almost done * Almost all tests passing * Fix more break and continue issues, also add a sort of IR * Add some more tests * Update readme * Get working with real fpyseq * Okay actually get working * Fix bug in lexer * Fix use before declare in loop bounds * Fix some warnings, spelling errors, other bugs * sp * fix annotations * sp * sp * sp * fix ut * 3.9 fix: * Work on bytecode spec * cleanup and update for peek * Switch to using peek * format * Speed up the compmiler a bunch * A little work on range type * Start working on discarding unused values * Fix almost all tests for new for loop stuff * All tests passing * Update spec and docs, all tests passing * Remove assert dir * Remove float floor div * work on polymorphic funcs * fmt * More work on polymorphism * readme change: * More work on polymorphism * overloading nearly there, some more test * Add more tests for casting * Fix a small bug in const folding * Fix more bugs * More fixes to math domains * remove ellipsis from syntax * Add even more test cases * Rework some tests * python 3.9 fix * py3.9 fix * sp * Add some visitor tests, add tests for floor divide * remove flags system for now * sp * catch recursion error * sp * Work on better intermediate types alg * Fix really large float literals * Little more work on good algos for intermediate type * More work on better intermediate type alg, rename Type->Value for fpp stuff * New coercion/intermediate logic mostly done... * Warn on empty ranges * Fix all tests * Update directives from latest devel * Works on real fprime * sp * Import errs fix * Update directives spec * Commonize some array index calc code * sp --------- Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
1 parent 873b754 commit eb896cf

26 files changed

+8452
-3650
lines changed

.github/actions/spelling/expect.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ argdesc
1414
ARGN
1515
argname
1616
argtype
17+
astassign
1718
autoapi
1819
AUTOBRIEF
1920
autocoded
@@ -37,6 +38,7 @@ calcsize
3738
calibri
3839
callergraph
3940
callgraph
41+
capsys
4042
cata
4143
CCB
4244
CCFF
@@ -98,6 +100,8 @@ docbook
98100
docset
99101
dontinclude
100102
DOTFONTPATH
103+
downcasted
104+
downcasting
101105
downfiles
102106
downlinker
103107
dox
@@ -146,6 +150,7 @@ fileurl
146150
Firefox
147151
fle
148152
focusring
153+
fors
149154
fne
150155
FONTNAME
151156
FONTPATH
@@ -163,6 +168,7 @@ fpybc
163168
fqn
164169
fsw
165170
gdiplus
171+
getattr
166172
getbootstrap
167173
getoption
168174
github
@@ -185,6 +191,7 @@ hookspecs
185191
hpaulson
186192
htags
187193
hyperlinks
194+
iabs
188195
idct
189196
idk
190197
idl
@@ -268,6 +275,7 @@ odl
268275
OKBLUE
269276
OKGREEN
270277
OMG
278+
oob
271279
OPREG
272280
oring
273281
osexc
@@ -288,9 +296,11 @@ plainnat
288296
plantuml
289297
PNGs
290298
postlex
299+
postlexer
291300
preds
292301
prm
293302
prmdb
303+
probs
294304
procs
295305
PROGRAMLISTING
296306
projectbrief
@@ -368,6 +378,7 @@ subhist
368378
subhistory
369379
superpackage
370380
superpkg
381+
sus
371382
tabetc
372383
tagfile
373384
tcanham
@@ -435,6 +446,7 @@ webified
435446
webpage
436447
website
437448
wikipedia
449+
wrt
438450
WSL
439451
wx
440452
xapian

src/fprime_gds/common/fpy/README.md

Lines changed: 120 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,38 @@ For types, Fpy has most of the same basic ones that FPP does:
4242

4343
Float literals are denoted with a decimal point (`5.0`, `0.123`) and Boolean literals have a capitalized first letter: `True`, `False`. There is no way to differentiate between signed and unsigned integer literals, so the compiler looks at where the literal is used to determine the signedness.
4444

45-
Note there is currently no built-in `string` type. See [Strings](#12-strings).
45+
Note there is currently no built-in `string` type. See [Strings](#15-strings).
46+
47+
## 3. Type coercion and casting
48+
If you have a lower-bitwidth numerical type and want to turn it into a higher-bitwidth type, this happens automatically:
49+
```py
50+
low_bitwidth_int: U8 = 123
51+
high_bitwidth_int: U32 = low_bitwidth_int
52+
# high_bitwidth_int == 123
53+
low_bitwidth_float: F32 = 123.0
54+
high_bitwidth_float: F64 = low_bitwidth_float
55+
# high_bitwidth_float == 123.0
56+
```
57+
58+
However, the opposite produces a compiler error:
59+
```py
60+
high_bitwidth: U32 = 25565
61+
low_bitwidth: U8 = high_bitwidth # compiler error
62+
```
63+
64+
If you are sure you want to do this, you can manually cast the type to the lower-bitwidth type:
65+
```py
66+
high_bitwidth: U32 = 16383
67+
low_bitwidth: U8 = U8(high_bitwidth) # no more error!
68+
# low_bitwidth == 255
69+
```
70+
This is called downcasting. It has the following behavior:
71+
* 64-bit floats are downcasted to 32-bit floats as if by `static_cast<F32>(f64_value)` in C++
72+
* Unsigned integers are bitwise truncated to the desired length
73+
* Signed integers are first reinterpreted bitwise as unsigned, then truncated to the desired length. Then, if the sign bit of the resulting number is set, `2 ** dest_type_bits` is subtracted from the resulting number to make it negative. This may have unintended behavior so use it cautiously.
4674

47-
## 3. Dictionary Types
75+
76+
## 4. Dictionary Types
4877

4978
Fpy also has access to all structs, arrays and enums in the FPrime dictionary:
5079
```py
@@ -60,7 +89,7 @@ struct_var: Ref.SignalPair = Ref.SignalPair(0.0, 1.0)
6089

6190
In general, the syntax for instantiating a struct or array type is `Full.Type.Name(arg, ..., arg)`.
6291

63-
## 4. Math
92+
## 5. Math
6493
You can do basic math and store the result in variables in Fpy:
6594
```py
6695
pemdas: F32 = 1 - 2 + 3 * 4 + 10 / 5 * 2 # == 15.0
@@ -71,26 +100,28 @@ Fpy supports the following math operations:
71100
* Modulo: `%`
72101
* Exponentiation: `**`
73102
* Floor division: `//`
74-
* Natural logarithm: `log(x)`
103+
* Natural logarithm: `log(F64)`
104+
* Absolute value: `abs(F64), abs(I64), abs(U64)`
75105

76-
The behavior of these operators is designed to mimic Python. Note that **division always returns a float**. This means that `5 / 2 == 2.5`, not `2`. This may be confusing coming from C++, but it is consistent with Python.
106+
The behavior of these operators is designed to mimic Python.
107+
> Note that **division always returns a float**. This means that `5 / 2 == 2.5`, not `2`. This may be confusing coming from C++, but it is consistent with Python.
77108
78-
## 5. Variable Arguments to Commands, Macros and Constructors
109+
## 6. Variable Arguments to Commands, Macros and Constructors
79110

80111
Where this really gets interesting is when you pass variables or expressions into commands:
81112
```py
82113
# this is a command that takes an F32
83-
Ref.recvBuffComp.PARAMETER4_PRM_SET(1 - 2 + 3 * 4 + 10 / 5 * 2)
114+
Ref.sendBuffComp.PARAMETER4_PRM_SET(1 - 2 + 3 * 4 + 10 / 5 * 2)
84115
# alternatively:
85116
param4: F32 = 15.0
86-
Ref.recvBuffComp.PARAMETER4_PRM_SET(param4)
117+
Ref.sendBuffComp.PARAMETER4_PRM_SET(param4)
87118
```
88119

89-
You can also pass variable arguments to the [`sleep`](#10-relative-and-absolute-sleep), [`exit`](#11-exit-macro), and `log` macros, as well as to constructors.
120+
You can also pass variable arguments to the [`sleep`](#12-relative-and-absolute-sleep), [`exit`](#13-exit-macro), `abs` and `log` macros, as well as to constructors.
90121

91-
There are some restrictions on passing string values, or complex types containing string values, to commands. See [Strings](#12-strings).
122+
There are some restrictions on passing string values, or complex types containing string values, to commands. See [Strings](#15-strings).
92123

93-
## 6. Getting Telemetry Channels and Parameters
124+
## 7. Getting Telemetry Channels and Parameters
94125

95126
Fpy supports getting the value of telemetry channels:
96127
```py
@@ -108,8 +139,8 @@ prm_3: U8 = Ref.sendBuffComp.parameter3
108139

109140
A significant limitation of this is that it will only return the value most recently saved to the parameter database. This means you must command `_PRM_SAVE` before the sequence will see the new value.
110141

111-
#### Note: If a telemetry channel and parameter have the same fully-qualified name, the fully-qualified name will get the value of the telemetry channel
112-
## 7. Conditionals
142+
> Note: If a telemetry channel and parameter have the same fully-qualified name, the fully-qualified name will get the value of the telemetry channel
143+
## 8. Conditionals
113144
Fpy supports comparison operators:
114145
```py
115146
value: bool = 1 > 2 and (3 + 4) != 5
@@ -125,7 +156,7 @@ record1: Svc.DpRecord = Svc.DpRecord(0, 1, 2, 3, 4, 5, Fw.DpState.UNTRANSMITTED)
125156
record2: Svc.DpRecord = Svc.DpRecord(0, 1, 2, 3, 4, 5, Fw.DpState.UNTRANSMITTED)
126157
records_equal: bool = record1 == record2 # == True
127158
```
128-
## 8. If/elif/else
159+
## 9. If/elif/else
129160

130161
You can branch off of conditionals with `if`, `elif` and `else`:
131162
```py
@@ -148,7 +179,7 @@ if CdhCore.cmdDisp.CommandsDispatched >= 1:
148179
CdhCore.cmdDisp.CMD_NO_OP_STRING("should happen")
149180
```
150181

151-
## 9. Getting Struct Members and Array Items
182+
## 10. Getting Struct Members and Array Items
152183

153184
You can access members of structs by name, or array elements by index:
154185
```py
@@ -159,20 +190,68 @@ signal_pair_time: F32 = Ref.SG1.PairOutput.time
159190
com_queue_depth_0: U32 = ComCcsds.comQueue.comQueueDepth[0]
160191
```
161192

162-
You cannot reassign struct members or array elements however:
193+
You can also reassign struct members or array elements:
163194
```py
164195
# Ref.SignalPair is a struct type
165196
signal_pair: Ref.SignalPair = Ref.SG1.PairOutput
166-
# compiler error:
167197
signal_pair.time = 0.2
168198

169199
# Svc.ComQueueDepth is an array type
170200
com_queue_depth: Svc.ComQueueDepth = ComCcsds.comQueue.comQueueDepth
171-
# compiler error:
172201
com_queue_depth[0] = 1
173202
```
174203

175-
## 10. Relative and Absolute Sleep
204+
## 11. For and while loops
205+
You can loop while a condition is true:
206+
```py
207+
counter: U64 = 0
208+
while counter < 100:
209+
counter = counter + 1
210+
211+
# counter == 100
212+
```
213+
214+
You can also loop over a range of integers:
215+
```py
216+
sum: I64 = 0
217+
# loop i from 0 inclusive to 5 exclusive
218+
for i in 0..5:
219+
sum = sum + i
220+
221+
# sum == 10
222+
```
223+
The loop variable, in this case `i`, is always of type `I64`. If a variable with the same name as the loop variable already exists, it can be reused as long as it is an `I64`:
224+
```py
225+
i: I64 = 123
226+
for i in 0..5: # okay: reuse of `i`
227+
sum = sum + i
228+
```
229+
230+
There is currently no support for a step size other than 1.
231+
232+
While inside of a loop, you can break out of the loop:
233+
```py
234+
counter: U64 = 0
235+
while True:
236+
counter = counter + 1
237+
if counter == 100:
238+
break
239+
240+
# counter == 100
241+
```
242+
243+
You can also continue on to the next iteration of the loop, skipping the remainder of the loop body:
244+
```py
245+
odd_numbers_sum: I64 = 0
246+
for i in 0..10:
247+
if i % 2 == 0:
248+
continue
249+
odd_numbers_sum = odd_numbers_sum + i
250+
251+
# odd_numbers_sum == 25
252+
```
253+
254+
## 12. Relative and Absolute Sleep
176255
You can pause the execution of a sequence for a relative duration, or until an absolute time:
177256
```py
178257
CdhCore.cmdDisp.CMD_NO_OP_STRING("second 0")
@@ -190,15 +269,30 @@ CdhCore.cmdDisp.CMD_NO_OP_STRING("much later")
190269

191270
Make sure that the `Svc.FpySequencer.checkTimers` port is connected to a rate group. The sequencer only checks if a sleep is done when the port is called, so the more frequently you call it, the more accurate the wakeup time.
192271

193-
## 11. Exit Macro
272+
## 13. Exit Macro
194273
You can end the execution of the sequence early by calling the `exit` macro:
195274
```py
196-
# exit takes a boolean argument
197-
# True means "end the sequence without an error"
198-
exit(True)
199-
# False means "end the sequence and raise an error"
200-
exit(False)
275+
# exit takes a U8 argument
276+
# 0 is the error code meaning "no error"
277+
exit(0)
278+
# anything else means an error occurred, and will show up in telemetry
279+
exit(123)
280+
```
281+
282+
## 14. Assertions
283+
You can assert that a Boolean condition is true:
284+
```py
285+
# won't end the sequence
286+
assert 1 > 0
287+
# will end the sequence
288+
assert 0 > 1
289+
```
290+
291+
You can also specify an error code to be raised if the expression is not true:
292+
```py
293+
# will raise an error code of 123
294+
assert 1 > 2, 123
201295
```
202296

203-
## 12. Strings
297+
## 15. Strings
204298
Fpy does not support a fully-fledged `string` type yet. You can pass a string literal as an argument to a command, but you cannot pass a string from a telemetry channel. You also cannot store a string in a variable, or perform any string manipulation. These features will be added in a later Fpy update.

0 commit comments

Comments
 (0)