• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SPF-OST / trnsys-dck-parser / 8926107064

02 May 2024 03:05PM UTC coverage: 94.514% (+3.0%) from 91.521%
8926107064

push

github

zuckerruebe
Satisfy `pylint`.

379 of 401 relevant lines covered (94.51%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.9
/src/trnsys_dck_parser/parse/expression/parse.py
1
import dataclasses as _dc
1✔
2
import typing as _tp
1✔
3

4
import trnsys_dck_parser.model.expression as _exp
1✔
5
import trnsys_dck_parser.parse.common as _pcom
1✔
6
import trnsys_dck_parser.parse.expression.tokenize as _petok
1✔
7
import trnsys_dck_parser.parse.tokens as _ptok
1✔
8

9

10
@_dc.dataclass
1✔
11
class ExpressionWithRemainingStartIndex:
1✔
12
    expression: _exp.Expression
1✔
13
    remaining_input_string_start_index: int
1✔
14

15

16
ParseResult = _pcom.ParseResult[_exp.Expression]
1✔
17

18

19
class Parser(_pcom.ParserBase[_exp.Expression]):
1✔
20
    def __init__(self, input_string: str) -> None:
1✔
21
        lexer = _petok.create_lexer(input_string)
1✔
22
        super().__init__(lexer)
1✔
23

24
    def parse(self) -> ParseResult:
1✔
25
        try:
1✔
26
            expression = self._expression()
1✔
27
            parse_success = _pcom.ParseSuccess(expression, self._remaining_input_string_start_index)
1✔
28
            return parse_success
1✔
29
        except _pcom.ParseErrorException as exception:
1✔
30
            return exception.parse_error
1✔
31

32
    def _expression(self) -> _exp.Expression:
1✔
33
        addend = self._addend()
1✔
34
        while True:
1✔
35
            if self._accept(_petok.Tokens.PLUS):
1✔
36
                next_addend = self._addend()
1✔
37
                addend += next_addend
1✔
38
            elif self._accept(_petok.Tokens.MINUS):
1✔
39
                next_addend = self._addend()
1✔
40
                addend -= next_addend
1✔
41
            else:
42
                break
1✔
43

44
        return addend
1✔
45

46
    def _addend(self) -> _exp.Expression:
1✔
47
        multiplicand = self._multiplicand()
1✔
48
        while True:
1✔
49
            if self._accept(_petok.Tokens.TIMES):
1✔
50
                next_multiplicand = self._multiplicand()
1✔
51
                multiplicand *= next_multiplicand
1✔
52
            elif self._accept(_petok.Tokens.DIVIDE):
1✔
53
                next_multiplicand = self._multiplicand()
1✔
54
                multiplicand /= next_multiplicand
1✔
55
            else:
56
                break
1✔
57

58
        return multiplicand
1✔
59

60
    def _multiplicand(self) -> _exp.Expression:
1✔
61
        base = self._power_operand()
1✔
62

63
        if not self._accept(_petok.Tokens.POWER):
1✔
64
            return base
1✔
65

66
        exponent = self._power_operand()
1✔
67

68
        return base ** exponent
1✔
69

70
    def _power_operand(self) -> _exp.Expression:  # pylint: disable=too-many-return-statements
1✔
71
        if positive_integer := self._accept(_petok.Tokens.POSITIVE_INTEGER):
1✔
72
            return _exp.Literal(int(positive_integer))
1✔
73

74
        if negative_integer := self._accept(_petok.Tokens.NEGATIVE_INTEGER):
1✔
75
            return _exp.Literal(int(negative_integer))
1✔
76

77
        if number := self._accept(_petok.Tokens.FLOAT):
1✔
78
            return _exp.Literal(float(number))
1✔
79

80
        if identifier := self._accept(_ptok.Tokens.IDENTIFIER):
1✔
81
            if not self._accept(_petok.Tokens.LEFT_PAREN):
1✔
82
                return _exp.Variable(identifier)
1✔
83

84
            arguments = self._argument_list()
1✔
85
            self._expect(_petok.Tokens.RIGHT_PAREN)
1✔
86
            return _exp.FunctionCall(identifier, arguments)
1✔
87

88
        if self._accept(_petok.Tokens.LEFT_SQUARE_BRACKET):
1✔
89
            unit_number, output_number = self._unit_and_output_number()
1✔
90
            self._expect(_petok.Tokens.RIGHT_SQUARE_BRACKET)
1✔
91
            return _exp.UnitOutput(unit_number, output_number)
1✔
92

93
        if self._accept(_petok.Tokens.MINUS):
1✔
94
            return -self._expression()
1✔
95

96
        if self._accept(_petok.Tokens.LEFT_PAREN):
1✔
97
            expression = self._expression()
1✔
98
            self._expect(_petok.Tokens.RIGHT_PAREN)
1✔
99
            return expression
1✔
100

101
        self._raise_parsing_error(
1✔
102
            "Expected number, variable, function call, opening square bracket or "
103
            "opening parenthesis but found {actual_token}"
104
        )
105

106
    def _argument_list(self) -> _tp.Sequence[_exp.Expression]:
1✔
107
        arguments = [self._expression()]
1✔
108
        while self._accept(_petok.Tokens.COMMA):
1✔
109
            argument = self._expression()
1✔
110
            arguments.append(argument)
1✔
111

112
        return arguments
1✔
113

114
    def _unit_and_output_number(self) -> _tp.Tuple[int, int]:
1✔
115
        unit_number = int(self._expect(_petok.Tokens.POSITIVE_INTEGER))
1✔
116
        self._check_non_negative(unit_number, "Unit number")
1✔
117

118
        self._expect(_petok.Tokens.COMMA)
1✔
119

120
        output_number = int(self._expect(_petok.Tokens.POSITIVE_INTEGER))
1✔
121
        self._check_non_negative(output_number, "Output number")
1✔
122

123
        return unit_number, output_number
1✔
124

125
    def _check_non_negative(self, integer: int, what: str) -> None:
1✔
126
        if integer >= 0:
1✔
127
            return
1✔
128

129
        self._raise_parsing_error(f"{what} numbers must be non-negative.")
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc