Coverage for lobster/tools/trlc/text_generation.py: 88%

34 statements  

« prev     ^ index     » next       coverage.py v7.10.5, created at 2025-08-27 13:02 +0000

1from typing import Iterable, List 

2import re 

3from trlc import ast 

4from lobster.tools.trlc.errors import TupleComponentError 

5from lobster.tools.trlc.instruction import ( 

6 Instruction, InstructionType, ConstantInstruction, FieldInstruction, 

7) 

8 

9 

10PATTERN = re.compile(r"\$\([a-z][a-z0-9_]*\)", re.IGNORECASE) 

11 

12 

13def parse_instructions(text: str) -> List[Instruction]: 

14 """Parse a one-line text representing a list of instructions""" 

15 instructions = [] 

16 cpos = 0 

17 for match in PATTERN.finditer(text): 

18 if match.span()[0] > cpos: 

19 instructions.append(ConstantInstruction(text[cpos:match.span()[0]])) 

20 instructions.append(FieldInstruction(match.group(0)[2:-1])) 

21 cpos = match.span()[1] 

22 if cpos < len(text): 

23 instructions.append(ConstantInstruction(text[cpos:])) 

24 return instructions 

25 

26 

27def build_text_from_instructions( 

28 instructions: Iterable[Instruction], 

29 tuple_aggregate: ast.Tuple_Aggregate, 

30) -> str: 

31 tuple_data = tuple_aggregate.to_python_object() 

32 if not tuple_data: 32 ↛ 33line 32 didn't jump to line 33 because the condition on line 32 was never true

33 raise ValueError("Cannot convert empty TRLC tuple to text!") 

34 if not instructions: 34 ↛ 35line 34 didn't jump to line 35 because the condition on line 34 was never true

35 raise ValueError( 

36 f"'to_string' instructions for tuple '{tuple_aggregate.typ.name}' " 

37 f"are empty!", 

38 ) 

39 result = [] 

40 for instruction in instructions: 

41 if instruction.typ == InstructionType.CONSTANT_TEXT: 

42 result.append(instruction.value) 

43 elif instruction.typ == InstructionType.FIELD: 43 ↛ 51line 43 didn't jump to line 51 because the condition on line 43 was always true

44 component_value = tuple_data.get(instruction.value) 

45 # Note: If the field does not exist in the record type OR if the record 

46 # object is not fully populated, we raise an error. 

47 if component_value is None: 

48 raise TupleComponentError(instruction.value, tuple_aggregate) 

49 result.append(str(component_value)) 

50 else: 

51 raise ValueError(f"Unknown instruction type: {instruction.typ}") 

52 return "".join(result)