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

CityOfZion / neo3-boa / a76b432e-4729-435c-803b-c18de254a895

25 Sep 2025 12:23PM UTC coverage: 91.439% (+0.02%) from 91.423%
a76b432e-4729-435c-803b-c18de254a895

push

circleci

web-flow
Add StringSplit and StrLen methods from StdLib (#1307)

98 of 101 new or added lines in 11 files covered. (97.03%)

22301 of 24389 relevant lines covered (91.44%)

1.83 hits per line

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

98.78
/boa3/internal/model/builtin/method/strsplitmethod.py
1
import ast
2✔
2
from typing import Any, Sized
2✔
3

4
from boa3.internal.model.builtin.method import IBuiltinMethod
2✔
5
from boa3.internal.model.builtin.native.stdlib.stringsplitmethod import \
2✔
6
    StringSplitWithoutRemoveEmptyEntriesMethod
7
from boa3.internal.model.type.type import Type
2✔
8
from boa3.internal.model.variable import Variable
2✔
9
from boa3.internal.neo.vm.opcode.Opcode import Opcode
2✔
10

11

12
class StrSplitMethod(IBuiltinMethod):
2✔
13
    def __init__(self, args: dict[str, Variable] = None, defaults: list[ast.AST] = None):
2✔
14
        identifier = 'split'
2✔
15

16
        if args is None:
2✔
17
            args: dict[str, Variable] = {
2✔
18
                'self': Variable(Type.str),
19
                'sep': Variable(Type.str),
20
                'maxsplit': Variable(Type.int)
21
            }
22

23
        if defaults is None:
2✔
24
            # whitespace is the default separator
25
            separator_default = ast.parse("' '").body[0].value
2✔
26
            # maxsplit the default value is -1
27
            maxsplit_default = ast.parse("-1").body[0].value.operand
2✔
28
            maxsplit_default.n = -1
2✔
29
            defaults = [separator_default, maxsplit_default]
2✔
30

31
        super().__init__(identifier, args, defaults,
2✔
32
                         return_type=Type.list.build_collection(Type.str))
33

34
    @property
2✔
35
    def identifier(self) -> str:
2✔
36
        if 1 <= len(self.args) <= 2:
2✔
37
            return '-{0}_2_args'.format(self._identifier)
2✔
38
        return self._identifier
2✔
39

40
    @property
2✔
41
    def _args_on_stack(self) -> int:
2✔
42
        return len(self.args)
2✔
43

44
    @property
2✔
45
    def _body(self) -> str | None:
2✔
NEW
46
        return None
×
47

48
    @property
2✔
49
    def generation_order(self) -> list[int]:
2✔
50
        # the original string must be the top value in the stack
51
        indexes = list(range(len(self.args)))
2✔
52
        str_index = list(self.args).index('self')
2✔
53

54
        if indexes[-1] != str_index:
2✔
55
            # context must be the last generated argument
56
            indexes.remove(str_index)
2✔
57
            indexes.append(str_index)
2✔
58
        return indexes
2✔
59

60
    def generate_internal_opcodes(self, code_generator):
2✔
61
        from boa3.internal.model.builtin.builtin import Builtin
2✔
62
        from boa3.internal.model.operation.binaryop import BinaryOp
2✔
63

64
        code_generator.duplicate_stack_item(3)
2✔
65
        code_generator.swap_reverse_stack_items(2)
2✔
66

67
        code_generator.convert_builtin_method_call(StringSplitWithoutRemoveEmptyEntriesMethod())
2✔
68

69
        # if maxsplit > 0
70
        code_generator.duplicate_stack_item(2)
2✔
71
        code_generator.convert_literal(0)
2✔
72
        is_valid_split_count = code_generator.convert_begin_if()
2✔
73
        code_generator.change_jump(is_valid_split_count, Opcode.JMPLT)
2✔
74

75
        #   while len(array) < maxsplit + 1:
76
        while_start = code_generator.convert_begin_while()
2✔
77
        code_generator.duplicate_stack_top_item()
2✔
78

79
        #       concat values
80
        concat_operation = BinaryOp.Concat.build(Type.bytearray)  # to return buffer
2✔
81

82
        code_generator.duplicate_stack_item(4)
2✔
83
        code_generator.duplicate_stack_item(2)
2✔
84
        code_generator.insert_opcode(Opcode.POPITEM, pop_from_stack=True, add_to_stack=[Type.str])
2✔
85
        code_generator.convert_operation(concat_operation, is_internal=True)
2✔
86
        code_generator.duplicate_stack_item(2)
2✔
87
        code_generator.insert_opcode(Opcode.POPITEM, pop_from_stack=True, add_to_stack=[Type.str])
2✔
88
        code_generator.swap_reverse_stack_items(2)
2✔
89
        code_generator.convert_operation(concat_operation, is_internal=True)
2✔
90
        code_generator.convert_cast(Type.str, is_internal=True)
2✔
91
        code_generator.convert_builtin_method_call(Builtin.SequenceAppend, is_internal=True)
2✔
92

93
        while_condition = code_generator.bytecode_size
2✔
94
        code_generator.duplicate_stack_top_item()
2✔
95
        code_generator.convert_builtin_method_call(Builtin.Len, is_internal=True)
2✔
96
        code_generator.duplicate_stack_item(3)
2✔
97
        code_generator.insert_opcode(Opcode.INC)
2✔
98
        code_generator.convert_operation(BinaryOp.Gt, is_internal=True)
2✔
99

100
        code_generator.convert_end_while(while_start, while_condition, is_internal=True)
2✔
101

102
        code_generator.convert_end_if(is_valid_split_count, is_internal=True)
2✔
103
        # clean stack
104

105
        code_generator.swap_reverse_stack_items(3)
2✔
106
        code_generator.remove_stack_top_item()
2✔
107
        code_generator.remove_stack_top_item()
2✔
108

109
    def build(self, value: Any) -> IBuiltinMethod:
2✔
110
        if isinstance(value, Sized) and 1 <= len(value) <= 2:
2✔
111
            return StrSplitWithoutMaxsplitMethod()
2✔
112

113
        return self
2✔
114

115

116
class StrSplitWithoutMaxsplitMethod(StrSplitMethod):
2✔
117
    def __init__(self):
2✔
118
        args: dict[str, Variable] = {
2✔
119
            'self': Variable(Type.str),
120
            'sep': Variable(Type.str),
121
        }
122
        # whitespace is the default separator
123
        separator_default = ast.parse("' '").body[0].value
2✔
124

125
        super().__init__(args, defaults=[separator_default])
2✔
126

127
    def generate_internal_opcodes(self, code_generator):
2✔
128
        code_generator.convert_builtin_method_call(StringSplitWithoutRemoveEmptyEntriesMethod())
2✔
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