Coverage for src/starlord/code_components.py: 72%

40 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-01 05:55 +0000

1from __future__ import annotations 

2 

3import re 

4from dataclasses import dataclass 

5from typing import Union 

6 

7 

8class Symb(str): 

9 

10 def __new__(cls, source: str) -> Symb: 

11 if re.fullmatch(r"[pcbla]\.[A-Za-z_]\w*", source) is not None: 

12 return super().__new__(cls, source) 

13 try: 

14 value: float = float(source) 

15 except ValueError: 

16 raise ValueError(f'Could not interpret "{source}" as a symbol or literal.') from None 

17 return super().__new__(cls, str(value)) 

18 

19 @property 

20 def name(self) -> str: 

21 return self[2:] 

22 

23 @property 

24 def label(self) -> str: 

25 return self[0] 

26 

27 @property 

28 def var(self) -> str: 

29 return self.label + "_" + self.name 

30 

31 

32@dataclass(frozen=True) 

33class Component: 

34 '''Represents a section of code for CodeGenerator.''' 

35 requires: set[Symb] 

36 provides: set[Symb] 

37 code: str 

38 

39 def __repr__(self) -> str: 

40 return f"ExprComponent({', '.join(self.requires)}) -> ({', '.join(self.provides)})" 

41 

42 def generate_code(self, name_map: Union[dict, None] = None) -> str: 

43 if name_map is None: 

44 return self.code 

45 else: 

46 return self.code.format_map(name_map) 

47 

48 

49class AssignmentComponent(Component): 

50 def __repr__(self) -> str: 

51 return f"{list(self.requires)[0]} = {self.code}" 

52 

53 

54class DistributionComponent(Component): 

55 pass 

56 

57 

58class InterpolateComponent(Component): 

59 pass