fprime-gds 4.0.2a2__py3-none-any.whl → 4.0.2a4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. fprime_gds/common/distributor/distributor.py +9 -6
  2. fprime_gds/common/fpy/README.md +190 -42
  3. fprime_gds/common/fpy/SPEC.md +153 -39
  4. fprime_gds/common/fpy/bytecode/assembler.py +62 -0
  5. fprime_gds/common/fpy/bytecode/directives.py +620 -294
  6. fprime_gds/common/fpy/codegen.py +687 -910
  7. fprime_gds/common/fpy/grammar.lark +44 -9
  8. fprime_gds/common/fpy/main.py +27 -4
  9. fprime_gds/common/fpy/model.py +799 -0
  10. fprime_gds/common/fpy/parser.py +29 -34
  11. fprime_gds/common/fpy/test_helpers.py +119 -0
  12. fprime_gds/common/fpy/types.py +563 -0
  13. fprime_gds/common/models/dictionaries.py +23 -0
  14. fprime_gds/common/pipeline/standard.py +5 -0
  15. fprime_gds/common/testing_fw/api.py +8 -1
  16. fprime_gds/executables/cli.py +9 -0
  17. fprime_gds/executables/run_deployment.py +2 -0
  18. fprime_gds/flask/app.py +17 -2
  19. fprime_gds/flask/default_settings.py +1 -0
  20. fprime_gds/flask/static/index.html +7 -4
  21. fprime_gds/flask/static/js/config.js +9 -1
  22. fprime_gds/flask/static/js/vue-support/channel.js +16 -0
  23. fprime_gds/flask/static/js/vue-support/event.js +1 -0
  24. fprime_gds/flask/static/js/vue-support/fp-row.js +25 -1
  25. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/METADATA +1 -1
  26. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/RECORD +31 -27
  27. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/entry_points.txt +2 -1
  28. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/WHEEL +0 -0
  29. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/licenses/LICENSE.txt +0 -0
  30. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/licenses/NOTICE.txt +0 -0
  31. {fprime_gds-4.0.2a2.dist-info → fprime_gds-4.0.2a4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,799 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+ import inspect
4
+ import math
5
+ import struct
6
+ import typing
7
+ from fprime_gds.common.fpy.bytecode.directives import (
8
+ AllocateDirective,
9
+ AndDirective,
10
+ ConstCmdDirective,
11
+ Directive,
12
+ ExitDirective,
13
+ FloatAddDirective,
14
+ FloatDivideDirective,
15
+ FloatExponentDirective,
16
+ FloatFloorDivideDirective,
17
+ FloatModuloDirective,
18
+ FloatMultiplyDirective,
19
+ FloatSubtractDirective,
20
+ GotoDirective,
21
+ MemCompareDirective,
22
+ SignedIntDivideDirective,
23
+ SignedModuloDirective,
24
+ UnsignedIntDivideDirective,
25
+ IntMultiplyDirective,
26
+ FloatLogDirective,
27
+ DiscardDirective,
28
+ StackCmdDirective,
29
+ StorePrmDirective,
30
+ StoreTlmValDirective,
31
+ IfDirective,
32
+ IntAddDirective,
33
+ IntEqualDirective,
34
+ IntNotEqualDirective,
35
+ IntSubtractDirective,
36
+ LoadDirective,
37
+ NoOpDirective,
38
+ NotDirective,
39
+ OrDirective,
40
+ PushValDirective,
41
+ StoreDirective,
42
+ UnsignedLessThanDirective,
43
+ UnsignedLessThanOrEqualDirective,
44
+ UnsignedGreaterThanDirective,
45
+ UnsignedGreaterThanOrEqualDirective,
46
+ SignedGreaterThanDirective,
47
+ SignedGreaterThanOrEqualDirective,
48
+ SignedIntToFloatDirective,
49
+ SignedLessThanDirective,
50
+ SignedLessThanOrEqualDirective,
51
+ UnsignedIntToFloatDirective,
52
+ FloatEqualDirective,
53
+ FloatExtendDirective,
54
+ FloatGreaterThanDirective,
55
+ FloatGreaterThanOrEqualDirective,
56
+ FloatLessThanDirective,
57
+ FloatLessThanOrEqualDirective,
58
+ FloatNotEqualDirective,
59
+ FloatToSignedIntDirective,
60
+ FloatToUnsignedIntDirective,
61
+ FloatTruncateDirective,
62
+ UnsignedModuloDirective,
63
+ WaitAbsDirective,
64
+ WaitRelDirective,
65
+ IntegerZeroExtend16To64Directive,
66
+ IntegerZeroExtend32To64Directive,
67
+ IntegerZeroExtend8To64Directive,
68
+ IntegerSignedExtend16To64Directive,
69
+ IntegerSignedExtend32To64Directive,
70
+ IntegerSignedExtend8To64Directive,
71
+ IntegerTruncate64To16Directive,
72
+ IntegerTruncate64To32Directive,
73
+ IntegerTruncate64To8Directive
74
+ )
75
+
76
+ debug = True
77
+
78
+ WORD_SIZE = 8
79
+ # store return addr and prev stack frame offset in stack frame header
80
+ STACK_FRAME_HEADER_SIZE = 2 * WORD_SIZE
81
+ MAX_INT64 = 2**63 - 1
82
+ MIN_INT64 = -(2**63)
83
+ MASK_64_BIT = 2**64 - 1
84
+
85
+
86
+ def overflow_check(val: int) -> int:
87
+ masked_val = val & MASK_64_BIT
88
+ if masked_val > MAX_INT64:
89
+ return masked_val - 2**64
90
+ return masked_val
91
+
92
+
93
+ class DirectiveErrorCode(Enum):
94
+ NO_ERROR = 0
95
+ DIR_OUT_OF_BOUNDS = 1
96
+ TLM_GET_NOT_CONNECTED = 2
97
+ TLM_NOT_FOUND = 3
98
+ TLM_ACCESS_OUT_OF_BOUNDS = 4
99
+ PRM_GET_NOT_CONNECTED = 5
100
+ PRM_NOT_FOUND = 6
101
+ PRM_ACCESS_OUT_OF_BOUNDS = 7
102
+ CMD_SERIALIZE_FAILURE = 8
103
+ DELIBERATE_FAILURE = 9
104
+ STACK_OVERFLOW = 10
105
+ STACK_UNDERFLOW = 11
106
+ INVALID_ARGUMENT = 12
107
+ DIVIDE_BY_ZERO = 13
108
+
109
+
110
+ class FpySequencerModel:
111
+
112
+ def __init__(self, stack_size=4096) -> None:
113
+ self.stack = bytearray()
114
+ self.max_stack_size = stack_size
115
+ self.stack_frame_start = 0
116
+
117
+ self.dirs: list[Directive] = None
118
+ self.next_dir_idx = 0
119
+ self.tlm_db: dict[int, bytearray] = {}
120
+ self.prm_db: dict[int, bytearray] = {}
121
+
122
+ def reset(self):
123
+ self.stack = bytearray()
124
+ self.stack_frame_start = 0
125
+
126
+ self.dirs: list[Directive] = None
127
+ self.next_dir_idx = 0
128
+ self.tlm_db: dict[int, bytearray] = {}
129
+ self.prm_db: dict[int, bytearray] = {}
130
+
131
+ def dispatch(self, dir: Directive) -> DirectiveErrorCode:
132
+ opcode = dir.opcode
133
+ opcode_name = opcode.name
134
+
135
+ handler_fn = None
136
+ for name, func in inspect.getmembers(type(self), inspect.isfunction):
137
+ if not name.startswith("handle"):
138
+ # not a dir handler
139
+ continue
140
+ signature = inspect.signature(func)
141
+ params = list(signature.parameters.values())
142
+ assert len(params) == 2
143
+ assert params[1].annotation is not None
144
+ annotations = typing.get_type_hints(func)
145
+ param_type = annotations[params[1].name]
146
+ if isinstance(dir, param_type):
147
+ handler_fn = func
148
+ break
149
+
150
+ if handler_fn is None:
151
+ raise NotImplementedError(opcode_name + " not implemented")
152
+
153
+ # otherwise call the handler
154
+ ret = handler_fn(self, dir)
155
+ if ret is None:
156
+ return DirectiveErrorCode.NO_ERROR
157
+ return ret
158
+
159
+ def run(self, dirs: list[Directive], tlm: dict[int, bytearray] = None):
160
+ if tlm is None:
161
+ tlm = {}
162
+ self.reset()
163
+ self.dirs = dirs
164
+ self.tlm_db = tlm
165
+ if debug:
166
+ # begin the sequence at dir 0
167
+ print("stack", len(self.stack))
168
+ for byte in range(0, len(self.stack)):
169
+
170
+ print(
171
+ type(self.stack[byte]),
172
+ end=" ",
173
+ )
174
+ print()
175
+ while self.next_dir_idx < len(self.dirs):
176
+ next_dir = self.dirs[self.next_dir_idx]
177
+ if debug:
178
+ print(f"{self.next_dir_idx}:", next_dir)
179
+ self.next_dir_idx += 1
180
+ result = self.dispatch(next_dir)
181
+ if result != DirectiveErrorCode.NO_ERROR:
182
+ return result
183
+ if debug:
184
+ print("stack", len(self.stack))
185
+ for byte in range(0, len(self.stack)):
186
+
187
+ print(
188
+ self.stack[byte],
189
+ end=" ",
190
+ )
191
+ print()
192
+ return DirectiveErrorCode.NO_ERROR
193
+
194
+ def get_int_fmt_str(self, size: int, signed: bool) -> str:
195
+ fmt_char = None
196
+ if size == 1:
197
+ fmt_char = "b"
198
+ elif size == 2:
199
+ fmt_char = "h"
200
+ elif size == 4:
201
+ fmt_char = "i"
202
+ elif size == 8:
203
+ fmt_char = "q"
204
+ else:
205
+ assert False, size
206
+ if not signed:
207
+ fmt_char = fmt_char.upper()
208
+
209
+ return ">" + fmt_char
210
+
211
+ def push(
212
+ self, val: int | float | bytes | bytearray | bool, signed=True, size=WORD_SIZE
213
+ ):
214
+ if isinstance(val, (bytes, bytearray)):
215
+ self.stack += val
216
+ elif isinstance(val, bool):
217
+ # push a byte onto stack
218
+ self.push(b"\xff" if val else b"\x00")
219
+ elif isinstance(val, float):
220
+ self.push(struct.pack(">d", val))
221
+ else:
222
+ assert isinstance(val, int), val
223
+ # first convert the int into bits
224
+ # have to do some stupid python stuff to deal with negatives
225
+ if val < 0:
226
+ # this should give us the right bit repr for two's complement
227
+ val = val + (1 << (size * 8))
228
+
229
+ bits = bin(val)[2:] # remove "0b"
230
+ # okay now truncate if necessary
231
+ bits = bits[-(size * 8) :]
232
+ self.stack += int(bits, 2).to_bytes(size, byteorder="big", signed=False)
233
+
234
+ def pop(self, type=int, signed=True, size=WORD_SIZE) -> int | float | bytearray:
235
+ """pops one word off the stack and interprets it as an int or float, of
236
+ the specified signedness (if applicable) and bit width (if applicable)"""
237
+ value = self.stack[-size:]
238
+ self.stack = self.stack[:-size]
239
+ if type == int:
240
+ fmt_str = self.get_int_fmt_str(size, signed)
241
+ return struct.unpack(fmt_str, value)[0]
242
+ elif type == float:
243
+ if size == 8:
244
+ return struct.unpack(">d", value)[0]
245
+ assert size == 4, size
246
+ return struct.unpack(">f", value)[0]
247
+ elif type == bytes or type == bytearray:
248
+ # compiler knows best. always let them have the last word ;)
249
+ return value
250
+ elif type == bool:
251
+ assert size == 1, size
252
+ return bool(value[0])
253
+ else:
254
+ assert False, type
255
+
256
+ def handle_allocate_stack(self, dir: AllocateDirective):
257
+ if len(self.stack) + dir.size > self.max_stack_size:
258
+ return DirectiveErrorCode.STACK_OVERFLOW
259
+
260
+ self.stack += bytearray(0 for i in range(0, dir.size))
261
+
262
+ def handle_no_op(self, dir: NoOpDirective):
263
+ pass
264
+
265
+ def handle_pop_discard(self, dir: DiscardDirective):
266
+ if len(self.stack) < WORD_SIZE:
267
+ return DirectiveErrorCode.STACK_UNDERFLOW
268
+ self.pop(size=dir.size, type=bytes)
269
+
270
+ def handle_load(self, dir: LoadDirective):
271
+ if len(self.stack) + dir.size > self.max_stack_size:
272
+ return DirectiveErrorCode.STACK_OVERFLOW
273
+
274
+ if dir.lvar_offset + self.stack_frame_start + dir.size > len(self.stack):
275
+ return DirectiveErrorCode.STACK_OVERFLOW
276
+
277
+ # grab a word beginning at lvar start and put on operand stack
278
+ value = self.stack[
279
+ self.stack_frame_start
280
+ + dir.lvar_offset : (self.stack_frame_start + dir.lvar_offset + dir.size)
281
+ ]
282
+ self.push(value)
283
+
284
+ def handle_store(self, dir: StoreDirective):
285
+ if len(self.stack) < dir.size:
286
+ return DirectiveErrorCode.STACK_UNDERFLOW
287
+
288
+ if dir.lvar_offset + self.stack_frame_start + dir.size > len(self.stack):
289
+ return DirectiveErrorCode.STACK_OVERFLOW
290
+
291
+ # get the last `dir.size` bytes of the stack
292
+ value = self.stack[-dir.size :]
293
+ # remove them from top of stack
294
+ self.stack = self.stack[: -dir.size]
295
+ # put into lvar array at the given offset
296
+ for i in range(0, len(value)):
297
+ self.stack[dir.lvar_offset + self.stack_frame_start + i] = value[i]
298
+
299
+ def handle_push_val(self, dir: PushValDirective):
300
+ if len(self.stack) + WORD_SIZE > self.max_stack_size:
301
+ return DirectiveErrorCode.STACK_OVERFLOW
302
+ self.push(dir.val)
303
+
304
+ def handle_wait_rel(self, dir: WaitRelDirective):
305
+ if len(self.stack) < 8:
306
+ return DirectiveErrorCode.STACK_UNDERFLOW
307
+
308
+ seconds = self.pop(type=float)
309
+
310
+ print("wait rel", seconds)
311
+
312
+ def handle_wait_abs(self, dir: WaitAbsDirective):
313
+ if len(self.stack) < 11:
314
+ return DirectiveErrorCode.STACK_UNDERFLOW
315
+ useconds = self.pop(size=4)
316
+ seconds = self.pop(size=4)
317
+ time_context = self.pop(size=1)
318
+ time_base = self.pop(size=2)
319
+
320
+ print("wait abs", time_context, time_base, seconds, useconds)
321
+
322
+ def handle_const_cmd(self, dir: ConstCmdDirective):
323
+ print("cmd opcode", dir.cmd_opcode, "args", dir.args)
324
+ # always push CmdResponse.OK
325
+ self.push(0, size=4)
326
+
327
+ def handle_stack_cmd(self, dir: StackCmdDirective):
328
+ if len(self.stack) < dir.args_size + 4:
329
+ return DirectiveErrorCode.STACK_UNDERFLOW
330
+
331
+ cmd = self.stack[-(dir.args_size + 4) :]
332
+ self.stack = self.stack[: -(dir.args_size + 4)]
333
+
334
+ print(
335
+ "cmd opcode",
336
+ int.from_bytes(cmd[-4:], signed=False, byteorder="big"),
337
+ "args",
338
+ cmd[:-4],
339
+ )
340
+ # always push CmdResponse.OK
341
+ self.push(0, size=4)
342
+
343
+ def handle_goto(self, dir: GotoDirective):
344
+ if dir.dir_idx > len(self.dirs):
345
+ return DirectiveErrorCode.DIR_OUT_OF_BOUNDS
346
+ self.next_dir_idx = dir.dir_idx
347
+
348
+ def handle_if(self, dir: IfDirective):
349
+ if dir.false_goto_dir_index > len(self.dirs):
350
+ return DirectiveErrorCode.DIR_OUT_OF_BOUNDS
351
+ if len(self.stack) < 1:
352
+ return DirectiveErrorCode.STACK_UNDERFLOW
353
+ conditional = self.pop(type=bool, size=1)
354
+ if not conditional:
355
+ self.next_dir_idx = dir.false_goto_dir_index
356
+
357
+ def handle_store_tlm_val(self, dir: StoreTlmValDirective):
358
+ whole_value: bytearray = self.tlm_db.get(dir.chan_id, None)
359
+ if whole_value is None:
360
+ return DirectiveErrorCode.TLM_NOT_FOUND
361
+
362
+ if (
363
+ self.stack_frame_start + dir.lvar_offset + len(whole_value)
364
+ > self.max_stack_size
365
+ ):
366
+ return DirectiveErrorCode.STACK_OVERFLOW
367
+
368
+ self.stack[
369
+ self.stack_frame_start
370
+ + dir.lvar_offset : (
371
+ self.stack_frame_start + dir.lvar_offset + len(whole_value)
372
+ )
373
+ ] = whole_value
374
+
375
+ def handle_store_prm(self, dir: StorePrmDirective):
376
+ whole_value: bytearray = self.prm_db.get(dir.prm_id, None)
377
+ if whole_value is None:
378
+ return DirectiveErrorCode.PRM_NOT_FOUND
379
+
380
+ if (
381
+ self.stack_frame_start + dir.lvar_offset + len(whole_value)
382
+ > self.max_stack_size
383
+ ):
384
+ return DirectiveErrorCode.STACK_OVERFLOW
385
+
386
+ self.stack[
387
+ self.stack_frame_start
388
+ + dir.lvar_offset : (
389
+ self.stack_frame_start + dir.lvar_offset + len(whole_value)
390
+ )
391
+ ] = whole_value
392
+
393
+ def handle_or(self, dir: OrDirective):
394
+ if len(self.stack) < 2:
395
+ return DirectiveErrorCode.STACK_UNDERFLOW
396
+ rhs = self.pop(type=bool, size=1)
397
+ lhs = self.pop(type=bool, size=1)
398
+ self.push(lhs or rhs)
399
+
400
+ def handle_and(self, dir: AndDirective):
401
+ if len(self.stack) < 2:
402
+ return DirectiveErrorCode.STACK_UNDERFLOW
403
+ rhs = self.pop(type=bool, size=1)
404
+ lhs = self.pop(type=bool, size=1)
405
+ self.push(lhs and rhs)
406
+
407
+ def handle_ieq(self, dir: IntEqualDirective):
408
+ if len(self.stack) < 2 * WORD_SIZE:
409
+ return DirectiveErrorCode.STACK_UNDERFLOW
410
+ self.push(self.pop() == self.pop())
411
+
412
+ def handle_ine(self, dir: IntNotEqualDirective):
413
+ if len(self.stack) < 2 * WORD_SIZE:
414
+ return DirectiveErrorCode.STACK_UNDERFLOW
415
+ self.push(self.pop() != self.pop())
416
+
417
+ def handle_ult(self, dir: UnsignedLessThanDirective):
418
+ if len(self.stack) < 2 * WORD_SIZE:
419
+ return DirectiveErrorCode.STACK_UNDERFLOW
420
+ rhs = self.pop(signed=False)
421
+ lhs = self.pop(signed=False)
422
+ self.push(lhs < rhs)
423
+
424
+ def handle_ule(self, dir: UnsignedLessThanOrEqualDirective):
425
+ if len(self.stack) < 2 * WORD_SIZE:
426
+ return DirectiveErrorCode.STACK_UNDERFLOW
427
+ rhs = self.pop(signed=False)
428
+ lhs = self.pop(signed=False)
429
+ self.push(lhs <= rhs)
430
+
431
+ def handle_ugt(self, dir: UnsignedGreaterThanDirective):
432
+ if len(self.stack) < 2 * WORD_SIZE:
433
+ return DirectiveErrorCode.STACK_UNDERFLOW
434
+ rhs = self.pop(signed=False)
435
+ lhs = self.pop(signed=False)
436
+ self.push(lhs > rhs)
437
+
438
+ def handle_uge(self, dir: UnsignedGreaterThanOrEqualDirective):
439
+ if len(self.stack) < 2 * WORD_SIZE:
440
+ return DirectiveErrorCode.STACK_UNDERFLOW
441
+ rhs = self.pop(signed=False)
442
+ lhs = self.pop(signed=False)
443
+ self.push(lhs >= rhs)
444
+
445
+ def handle_slt(self, dir: SignedLessThanDirective):
446
+ if len(self.stack) < 2 * WORD_SIZE:
447
+ return DirectiveErrorCode.STACK_UNDERFLOW
448
+ rhs = self.pop()
449
+ lhs = self.pop()
450
+ self.push(lhs < rhs)
451
+
452
+ def handle_sle(self, dir: SignedLessThanOrEqualDirective):
453
+ if len(self.stack) < 2 * WORD_SIZE:
454
+ return DirectiveErrorCode.STACK_UNDERFLOW
455
+ rhs = self.pop()
456
+ lhs = self.pop()
457
+ self.push(lhs <= rhs)
458
+
459
+ def handle_sgt(self, dir: SignedGreaterThanDirective):
460
+ if len(self.stack) < 2 * WORD_SIZE:
461
+ return DirectiveErrorCode.STACK_UNDERFLOW
462
+ rhs = self.pop()
463
+ lhs = self.pop()
464
+ self.push(lhs > rhs)
465
+
466
+ def handle_sge(self, dir: SignedGreaterThanOrEqualDirective):
467
+ if len(self.stack) < 2 * WORD_SIZE:
468
+ return DirectiveErrorCode.STACK_UNDERFLOW
469
+ rhs = self.pop()
470
+ lhs = self.pop()
471
+ self.push(lhs >= rhs)
472
+
473
+ def handle_feq(self, dir: FloatEqualDirective):
474
+ if len(self.stack) < 2 * WORD_SIZE:
475
+ return DirectiveErrorCode.STACK_UNDERFLOW
476
+ rhs = self.pop(type=float)
477
+ lhs = self.pop(type=float)
478
+ print(rhs, lhs, rhs == lhs)
479
+ self.push(lhs == rhs)
480
+
481
+ def handle_fne(self, dir: FloatNotEqualDirective):
482
+ if len(self.stack) < 2 * WORD_SIZE:
483
+ return DirectiveErrorCode.STACK_UNDERFLOW
484
+ self.push(self.pop(type=float) != self.pop(type=float))
485
+
486
+ def handle_flt(self, dir: FloatLessThanDirective):
487
+ if len(self.stack) < 2 * WORD_SIZE:
488
+ return DirectiveErrorCode.STACK_UNDERFLOW
489
+ rhs = self.pop(type=float)
490
+ lhs = self.pop(type=float)
491
+ self.push(lhs < rhs)
492
+
493
+ def handle_fle(self, dir: FloatLessThanOrEqualDirective):
494
+ if len(self.stack) < 2 * WORD_SIZE:
495
+ return DirectiveErrorCode.STACK_UNDERFLOW
496
+ rhs = self.pop(type=float)
497
+ lhs = self.pop(type=float)
498
+ self.push(lhs <= rhs)
499
+
500
+ def handle_fgt(self, dir: FloatGreaterThanDirective):
501
+ if len(self.stack) < 2 * WORD_SIZE:
502
+ return DirectiveErrorCode.STACK_UNDERFLOW
503
+ rhs = self.pop(type=float)
504
+ lhs = self.pop(type=float)
505
+ self.push(lhs > rhs)
506
+
507
+ def handle_fge(self, dir: FloatGreaterThanOrEqualDirective):
508
+ if len(self.stack) < 2 * WORD_SIZE:
509
+ return DirectiveErrorCode.STACK_UNDERFLOW
510
+ rhs = self.pop(type=float)
511
+ lhs = self.pop(type=float)
512
+ self.push(lhs >= rhs)
513
+
514
+ def handle_not(self, dir: NotDirective):
515
+ if len(self.stack) < 1:
516
+ return DirectiveErrorCode.STACK_UNDERFLOW
517
+ val = self.pop(type=bool, size=1)
518
+ if val:
519
+ self.push(False)
520
+ else:
521
+ self.push(True)
522
+
523
+ def handle_fpext(self, dir: FloatExtendDirective):
524
+ if len(self.stack) < 4:
525
+ return DirectiveErrorCode.STACK_UNDERFLOW
526
+ val_bytes = self.stack[-4:]
527
+ self.stack = self.stack[:-4]
528
+ val_as_float = struct.unpack(">f", val_bytes)[0]
529
+
530
+ self.push(val_as_float)
531
+
532
+ def handle_siext_8_64(self, dir: IntegerSignedExtend8To64Directive):
533
+ if len(self.stack) < 1:
534
+ return DirectiveErrorCode.STACK_UNDERFLOW
535
+ if len(self.stack) + 7 > self.max_stack_size:
536
+ return DirectiveErrorCode.STACK_OVERFLOW
537
+
538
+ # pop val off stack
539
+ val = self.pop(type=int, signed=True, size=1)
540
+
541
+ self.push(val, signed=True, size=8)
542
+
543
+ def handle_siext_16_64(self, dir: IntegerSignedExtend16To64Directive):
544
+ if len(self.stack) < 2:
545
+ return DirectiveErrorCode.STACK_UNDERFLOW
546
+ if len(self.stack) + 6 > self.max_stack_size:
547
+ return DirectiveErrorCode.STACK_OVERFLOW
548
+
549
+ # pop val off stack
550
+ val = self.pop(type=int, signed=True, size=2)
551
+
552
+ self.push(val, signed=True, size=8)
553
+
554
+ def handle_siext_32_64(self, dir: IntegerSignedExtend32To64Directive):
555
+ if len(self.stack) < 4:
556
+ return DirectiveErrorCode.STACK_UNDERFLOW
557
+ if len(self.stack) + 4 > self.max_stack_size:
558
+ return DirectiveErrorCode.STACK_OVERFLOW
559
+
560
+ # pop val off stack
561
+ val = self.pop(type=int, signed=True, size=4)
562
+
563
+ self.push(val, signed=True, size=8)
564
+
565
+ def handle_ziext_8_64(self, dir: IntegerZeroExtend8To64Directive):
566
+ if len(self.stack) < 1:
567
+ return DirectiveErrorCode.STACK_UNDERFLOW
568
+ if len(self.stack) + 7 > self.max_stack_size:
569
+ return DirectiveErrorCode.STACK_OVERFLOW
570
+
571
+ # pop val off stack
572
+ val = self.pop(type=int, signed=False, size=1)
573
+
574
+ self.push(val, signed=False, size=8)
575
+
576
+ def handle_ziext_16_64(self, dir: IntegerZeroExtend16To64Directive):
577
+ if len(self.stack) < 2:
578
+ return DirectiveErrorCode.STACK_UNDERFLOW
579
+ if len(self.stack) + 6 > self.max_stack_size:
580
+ return DirectiveErrorCode.STACK_OVERFLOW
581
+
582
+ # pop val off stack
583
+ val = self.pop(type=int, signed=False, size=2)
584
+
585
+ self.push(val, signed=False, size=8)
586
+
587
+ def handle_ziext_32_64(self, dir: IntegerZeroExtend32To64Directive):
588
+ if len(self.stack) < 4:
589
+ return DirectiveErrorCode.STACK_UNDERFLOW
590
+ if len(self.stack) + 4 > self.max_stack_size:
591
+ return DirectiveErrorCode.STACK_OVERFLOW
592
+
593
+ # pop val off stack
594
+ val = self.pop(type=int, signed=False, size=4)
595
+
596
+ self.push(val, signed=False, size=8)
597
+
598
+ def handle_fptrunc(self, dir: FloatTruncateDirective):
599
+ if len(self.stack) < WORD_SIZE:
600
+ return DirectiveErrorCode.STACK_UNDERFLOW
601
+ val_64 = self.pop(type=float)
602
+ val_32_bytes = struct.pack(">f", val_64)
603
+ self.push(val_32_bytes)
604
+
605
+ def handle_itrunc_64_8(self, dir: IntegerTruncate64To8Directive):
606
+ if len(self.stack) < 8:
607
+ return DirectiveErrorCode.STACK_UNDERFLOW
608
+
609
+ val = self.pop(type=bytes, size=8)
610
+ val = val[-1 :]
611
+ self.push(val)
612
+
613
+ def handle_itrunc_64_16(self, dir: IntegerTruncate64To16Directive):
614
+ if len(self.stack) < 8:
615
+ return DirectiveErrorCode.STACK_UNDERFLOW
616
+
617
+ val = self.pop(type=bytes, size=8)
618
+ val = val[-2 :]
619
+ self.push(val)
620
+
621
+ def handle_itrunc_64_32(self, dir: IntegerTruncate64To32Directive):
622
+ if len(self.stack) < 8:
623
+ return DirectiveErrorCode.STACK_UNDERFLOW
624
+
625
+ val = self.pop(type=bytes, size=8)
626
+ val = val[-4 :]
627
+ self.push(val)
628
+
629
+ def handle_fptosi(self, dir: FloatToSignedIntDirective):
630
+ if len(self.stack) < WORD_SIZE:
631
+ return DirectiveErrorCode.STACK_UNDERFLOW
632
+ val = self.pop(type=float)
633
+ self.push(val)
634
+
635
+ def handle_fptoui(self, dir: FloatToUnsignedIntDirective):
636
+ if len(self.stack) < WORD_SIZE:
637
+ return DirectiveErrorCode.STACK_UNDERFLOW
638
+ val = self.pop(type=float)
639
+ self.push(val)
640
+
641
+ def handle_sitofp(self, dir: SignedIntToFloatDirective):
642
+ if len(self.stack) < WORD_SIZE:
643
+ return DirectiveErrorCode.STACK_UNDERFLOW
644
+ val = self.pop()
645
+ self.push(float(val))
646
+
647
+ def handle_uitofp(self, dir: UnsignedIntToFloatDirective):
648
+ if len(self.stack) < WORD_SIZE:
649
+ return DirectiveErrorCode.STACK_UNDERFLOW
650
+ val = self.pop(signed=False)
651
+ self.push(float(val))
652
+
653
+ def handle_iadd(self, dir: IntAddDirective):
654
+ if len(self.stack) < 2 * WORD_SIZE:
655
+ return DirectiveErrorCode.STACK_UNDERFLOW
656
+ rhs = self.pop()
657
+ lhs = self.pop()
658
+ self.push(overflow_check(lhs + rhs))
659
+
660
+ def handle_isub(self, dir: IntSubtractDirective):
661
+ if len(self.stack) < 2 * WORD_SIZE:
662
+ return DirectiveErrorCode.STACK_UNDERFLOW
663
+ rhs = self.pop()
664
+ lhs = self.pop()
665
+ self.push(overflow_check(lhs - rhs))
666
+
667
+ def handle_imul(self, dir: IntMultiplyDirective):
668
+ if len(self.stack) < 2 * WORD_SIZE:
669
+ return DirectiveErrorCode.STACK_UNDERFLOW
670
+ rhs = self.pop()
671
+ lhs = self.pop()
672
+ self.push(overflow_check(lhs * rhs))
673
+
674
+ def handle_udiv(self, dir: UnsignedIntDivideDirective):
675
+ if len(self.stack) < 2 * WORD_SIZE:
676
+ return DirectiveErrorCode.STACK_UNDERFLOW
677
+ rhs = self.pop(signed=False)
678
+ lhs = self.pop(signed=False)
679
+
680
+ # credit to gemini
681
+ if rhs == 0:
682
+ # C++ behavior for division by zero is undefined.
683
+ return DirectiveErrorCode.DIVIDE_BY_ZERO
684
+
685
+ # Perform division, truncating towards zero
686
+ # This is different from Python's // which floors.
687
+ python_quotient = int(lhs / rhs)
688
+
689
+ # For division, overflow detection isn't typically done with the mask on the result
690
+ # because the quotient itself is within range
691
+ self.push(python_quotient)
692
+
693
+ def handle_sdiv(self, dir: SignedIntDivideDirective):
694
+ if len(self.stack) < 2 * WORD_SIZE:
695
+ return DirectiveErrorCode.STACK_UNDERFLOW
696
+ rhs = self.pop(signed=True)
697
+ lhs = self.pop(signed=True)
698
+
699
+ # credit to gemini
700
+ if rhs == 0:
701
+ # C++ behavior for division by zero is undefined.
702
+ return DirectiveErrorCode.DIVIDE_BY_ZERO
703
+
704
+ # Special overflow case: MIN_INT64 / -1
705
+ # This results in MAX_INT64 + 1, which overflows to MIN_INT64 in C++.
706
+ if lhs == MIN_INT64 and rhs == -1:
707
+ self.push(MIN_INT64) # C++ specific overflow behavior
708
+ return
709
+
710
+ python_quotient = int(lhs / rhs)
711
+
712
+ self.push(python_quotient)
713
+
714
+ def handle_fadd(self, dir: FloatAddDirective):
715
+ if len(self.stack) < 2 * WORD_SIZE:
716
+ return DirectiveErrorCode.STACK_UNDERFLOW
717
+ rhs = self.pop(type=float)
718
+ lhs = self.pop(type=float)
719
+ self.push(lhs + rhs)
720
+
721
+ def handle_fsub(self, dir: FloatSubtractDirective):
722
+ if len(self.stack) < 2 * WORD_SIZE:
723
+ return DirectiveErrorCode.STACK_UNDERFLOW
724
+ rhs = self.pop(type=float)
725
+ lhs = self.pop(type=float)
726
+ self.push(lhs - rhs)
727
+
728
+ def handle_fmul(self, dir: FloatMultiplyDirective):
729
+ if len(self.stack) < 2 * WORD_SIZE:
730
+ return DirectiveErrorCode.STACK_UNDERFLOW
731
+ rhs = self.pop(type=float)
732
+ lhs = self.pop(type=float)
733
+ self.push(lhs * rhs)
734
+
735
+ def handle_fdiv(self, dir: FloatDivideDirective):
736
+ if len(self.stack) < 2 * WORD_SIZE:
737
+ return DirectiveErrorCode.STACK_UNDERFLOW
738
+ rhs = self.pop(type=float)
739
+ lhs = self.pop(type=float)
740
+ self.push(lhs / rhs)
741
+
742
+ def handle_smod(self, dir: SignedModuloDirective):
743
+ if len(self.stack) < 2 * WORD_SIZE:
744
+ return DirectiveErrorCode.STACK_UNDERFLOW
745
+ rhs = self.pop(signed=True)
746
+ lhs = self.pop(signed=True)
747
+ self.push(lhs % rhs, signed=True)
748
+
749
+ def handle_umod(self, dir: UnsignedModuloDirective):
750
+ if len(self.stack) < 2 * WORD_SIZE:
751
+ return DirectiveErrorCode.STACK_UNDERFLOW
752
+ rhs = self.pop(signed=False)
753
+ lhs = self.pop(signed=False)
754
+ self.push(lhs % rhs, signed=False)
755
+
756
+ def handle_fmod(self, dir: FloatModuloDirective):
757
+ if len(self.stack) < 2 * WORD_SIZE:
758
+ return DirectiveErrorCode.STACK_UNDERFLOW
759
+ rhs = self.pop(type=float)
760
+ lhs = self.pop(type=float)
761
+ self.push(lhs % rhs)
762
+
763
+ def handle_fpow(self, dir: FloatExponentDirective):
764
+ if len(self.stack) < 2 * WORD_SIZE:
765
+ return DirectiveErrorCode.STACK_UNDERFLOW
766
+ rhs = self.pop(type=float)
767
+ lhs = self.pop(type=float)
768
+ self.push(lhs**rhs)
769
+
770
+ def handle_log(self, dir: FloatLogDirective):
771
+ if len(self.stack) < WORD_SIZE:
772
+ return DirectiveErrorCode.STACK_UNDERFLOW
773
+ operand = self.pop(type=float)
774
+ self.push(math.log(operand))
775
+
776
+ def handle_float_floor_div(self, dir: FloatFloorDivideDirective):
777
+ if len(self.stack) < 2 * WORD_SIZE:
778
+ return DirectiveErrorCode.STACK_UNDERFLOW
779
+ rhs = self.pop(type=float)
780
+ lhs = self.pop(type=float)
781
+ self.push(lhs // rhs)
782
+
783
+ def handle_exit(self, dir: ExitDirective):
784
+ if len(self.stack) < 1:
785
+ return DirectiveErrorCode.STACK_UNDERFLOW
786
+ success = self.pop(type=bool, size=1)
787
+ if success:
788
+ self.next_dir_idx = len(self.dirs)
789
+ else:
790
+ return DirectiveErrorCode.DELIBERATE_FAILURE
791
+
792
+ def handle_memcmp(self, dir: MemCompareDirective):
793
+ if len(self.stack) < dir.size * 2:
794
+ return DirectiveErrorCode.STACK_UNDERFLOW
795
+
796
+ rhs = self.pop(type=bytes, size=dir.size)
797
+ lhs = self.pop(type=bytes, size=dir.size)
798
+ print(rhs, lhs)
799
+ self.push(rhs == lhs)