Example #1
0
    def test_resize_array(self):
        interpreter = interpret('_x = [1,2]; _x resize 4')[0]
        self.assertEqual(Array([N(1), N(2), Nothing(),
                                Nothing()]), interpreter['_x'])

        interpreter = interpret('_x = [1,2,3,4]; _x resize 2')[0]
        self.assertEqual(Array([N(1), N(2)]), interpreter['_x'])
Example #2
0
    def test_select(self):
        _, outcome = interpret('[1, 2] select 0')
        self.assertEqual(N(1), outcome)

        # alternative using floats
        _, outcome = interpret('[1, 2] select 0.5')
        self.assertEqual(N(1), outcome)

        _, outcome = interpret('[1, 2] select 0.6')
        self.assertEqual(N(2), outcome)

        # alternative using booleans
        _, outcome = interpret('[1, 2] select true')
        self.assertEqual(N(2), outcome)

        _, outcome = interpret('[1, 2] select false')
        self.assertEqual(N(1), outcome)

        # alternative using [start, count]
        _, outcome = interpret('[1, 2, 3] select [1, 2]')
        self.assertEqual(Array([N(2), N(3)]), outcome)

        _, outcome = interpret('[1, 2, 3] select [1, 10]')
        self.assertEqual(Array([N(2), N(3)]), outcome)

        with self.assertRaises(SQFParserError):
            _, outcome = interpret('[1, 2, 3] select [4, 10]')

        with self.assertRaises(SQFParserError):
            _, outcome = interpret('[1, 2, 3] select 10')
Example #3
0
    def test_pushBackUnique(self):
        interpreter, outcome = interpret('_x = [1]; _x pushBackUnique 2')
        self.assertEqual(Array([N(1), N(2)]), interpreter['_x'])
        self.assertEqual(N(1), outcome)

        interpreter, outcome = interpret('_x = [1, 2]; _x pushBackUnique 2')
        self.assertEqual(Array([N(1), N(2)]), interpreter['_x'])
        self.assertEqual(N(-1), outcome)
Example #4
0
    def test_reference(self):
        # tests that changing _x affects _y when _y = _x.
        interpreter, _ = interpret('_x = [1, 2]; _y = _x; _x set [0, 2];')
        self.assertEqual(Array([N(2), N(2)]), interpreter['_x'])
        self.assertEqual(Array([N(2), N(2)]), interpreter['_y'])

        interpreter, _ = interpret('_x = [1, 2]; _y = _x; reverse _x;')
        self.assertEqual(Array([N(2), N(1)]), interpreter['_y'])
Example #5
0
    def test_set(self):
        test = '_x = [1, 2]; _x set [0, 2];'
        interpreter, _ = interpret(test)
        self.assertEqual(Array([N(2), N(2)]), interpreter['_x'])

        test = '_x = [1, 2]; _x set [2, 3];'
        interpreter, _ = interpret(test)
        self.assertEqual(Array([N(1), N(2), N(3)]), interpreter['_x'])
Example #6
0
    def value(self, token, namespace_name=None):
        """
        Given a single token, recursively evaluates and returns its value
        """
        if namespace_name is None:
            namespace_name = self.current_namespace.name

        assert (isinstance(token, BaseType))
        if isinstance(token, IfDefResult):
            for x in token.result:
                x.set_position(token.position)
                result = self.value(self.execute_token(x))
        elif isinstance(token, DefineResult):
            token.result.set_position(token.position)
            result = self.value(self.execute_token(token.result))
        elif isinstance(token, Statement):
            result = self.value(self.execute_token(token))
        elif isinstance(token, Variable):
            scope = self.get_scope(token.name, namespace_name)
            if scope.level == 0 and not token.is_global:
                self.exception(
                    SQFWarning(
                        token.position,
                        'Local variable "%s" is not from this scope (not private)'
                        % token))

            try:
                result = scope[token.name]
            except KeyError:
                result = self.private_default_class()
            result.position = token.position

            key = '%s_%s_%s' % (namespace_name, scope.level,
                                scope.normalize(token.name))
            if key in self.variable_uses:
                self.variable_uses[key]['count'] += 1

        elif isinstance(token, Array) and not token.is_undefined:
            result = Array(
                [self.value(self.execute_token(s)) for s in token.value])
            result.position = token.position
        else:
            null_expressions = values_to_expressions([token], EXPRESSIONS_MAP,
                                                     EXPRESSIONS)
            if null_expressions:
                result = null_expressions[0].execute([token], self)
            else:
                result = token
            result.position = token.position

        if isinstance(
                result,
                Code) and self.code_key(result) not in self._unexecuted_codes:
            self._unexecuted_codes[self.code_key(result)] = UnexecutedCode(
                result, self)

        return result
Example #7
0
    def set_variable(self, var_name, value, broadcast=True):
        self._interpreter.set_global_variable(var_name, value)

        if broadcast:
            if var_name in self._listening_variables:
                self._interpreter.execute_code(self._listening_variables[var_name],
                                               params=Array([String('"'+var_name+'"'), value]))
Example #8
0
    def execute_token(self, token):
        """
        Given a single token, recursively evaluate it without returning its value (only type)
        """
        # interpret the statement recursively
        if isinstance(token, Statement):
            result = self.execute_single(statement=token)
            # we do not want the position of the statement, but of the token, so we do not
            # store it here
        elif isinstance(token, Array) and token.value is not None:
            result = Array([self.execute_token(s) for s in token.value])
            result.position = token.position
        else:
            result = token
            result.position = token.position

        return result
Example #9
0
    def test_array(self):
        code = "y = x select 2"

        analyzer = Analyzer()
        scope = analyzer.get_scope('x')
        scope['x'] = Array()

        analyze(parse(code), analyzer)
        self.assertEqual(len(analyzer.exceptions), 0)
        self.assertEqual(analyzer['y'], Anything())
Example #10
0
    def execute_token(self, token):
        """
        Given a single token, recursively evaluate it and return its value.
        """
        # interpret the statement recursively
        if isinstance(token, Statement):
            result = self.execute_single(statement=token)
        elif isinstance(token, Array):
            # empty statements are ignored
            result = Array(
                [self.execute_token(s)[1] for s in token.value if s])
        elif token == Keyword('isServer'):
            result = Boolean(self.client.is_server)
        elif token == Keyword('isDedicated'):
            result = Boolean(self.client.is_dedicated)
        else:
            result = token

        result.position = token.position
        return result, self.value(result)
Example #11
0
    def test_forvar_edges(self):
        # see comments on https://community.bistudio.com/wiki/for_var

        # start = end => runs once
        test = 'y = -10; for "_i" from 0 to 0 do {y = _i;};'
        interpreter, _ = interpret(test)
        self.assertEqual(N(0), interpreter['y'])

        # start < end => never runs
        interpreter, _ = interpret(
            'y = -10; for "_i" from 0 to -1 do {y = _i;};')
        self.assertEqual(N(-10), interpreter['y'])

        # do not overwrite globals
        interpreter, _ = interpret('for "x" from 0 to 0 do {};')
        self.assertEqual(Nothing(), interpreter['x'])

        # nested
        test = '_array = []; for "_i" from 0 to 1 do {for "_i" from 0 to 1 do {_array pushBack _i;}; _array pushBack _i;};'
        interpreter, _ = interpret(test)
        self.assertEqual(Array([N(0), N(1), N(0),
                                N(0), N(1), N(1)]), interpreter['_array'])
Example #12
0
 def test_defines_in_array2(self):
     code = '#define x  (0.1)\n#define y  (0.02)\nz = [2 * x, 2 * y, 2 * x];'
     analyzer = analyze(parse(code))
     self.assertEqual(len(analyzer.exceptions), 0)
     self.assertEqual(Array(), analyzer['z'])
Example #13
0
 def test_defines_in_array(self):
     code = '#define x 1\ny=[x,x]'
     analyzer = analyze(parse(code))
     errors = analyzer.exceptions
     self.assertEqual(len(errors), 0)
     self.assertEqual(Array(), analyzer['y'])
Example #14
0
 def test_defines_in_array(self):
     code = '#define x 1\ny=[x,x]'
     analyzer = analyze(parse(code))
     self.assertEqual(analyzer.exceptions, [])
     self.assertEqual(Array(), analyzer['y'])
Example #15
0
 def test_assign_array(self):
     interpreter = interpret('_y = [];')[0]
     self.assertEqual(Array([]), interpreter['_y'])
Example #16
0
 def test_array(self):
     self.assertEqual('[1,1]', str(Array([N(1), N(1)])))
Example #17
0
    def test_to_array_string(self):
        outcome = interpret('toArray("AaŒ")')[1]
        self.assertEqual(Array([N(65), N(97), N(338)]), outcome)

        outcome = interpret('toString([65,97,338])')[1]
        self.assertEqual(String('"AaŒ"'), outcome)
Example #18
0
 def test_for_var_step(self):
     test = 'y = []; for "_i" from 1 to 10 step 2 do {y pushBack _i;};'
     interpreter, outcome = interpret(test)
     self.assertEqual(Array([N(1), N(3), N(5), N(7),
                             N(9)]), interpreter['y'])
Example #19
0
 def test_assign(self):
     interpreter, outcome = interpret('_x = [1, 2];')
     self.assertEqual(Array([N(1), N(2)]), interpreter['_x'])
Example #20
0
 def test_for_var(self):
     test = 'y = []; for "_i" from 1 to 10 do {y pushBack _i;};'
     interpreter, outcome = interpret(test)
     self.assertEqual(Array([N(i) for i in range(1, 11)]), interpreter['y'])
Example #21
0
 def test_reverse(self):
     interpreter, outcome = interpret('_x = [1, 2]; reverse _x')
     self.assertEqual(Nothing(), outcome)
     self.assertEqual(Array([N(2), N(1)]), interpreter['_x'])
Example #22
0
    def test_add(self):
        test = '_x = [1, 2]; _y = [3, 4]; _z = _x + _y'
        _, outcome = interpret(test)

        self.assertEqual(Array([N(1), N(2), N(3), N(4)]), outcome)
Example #23
0
def parse_block(all_tokens,
                analyze_tokens,
                start=0,
                initial_lvls=None,
                stop_statement='both',
                defines=None):
    if not initial_lvls:
        initial_lvls = _LEVELS
    if defines is None:
        defines = defaultdict(dict)
    lvls = initial_lvls.copy()

    statements = []
    tokens = []
    i = start
    if not all_tokens:
        return Statement([]), 0

    while i < len(all_tokens):
        token = all_tokens[i]

        # begin #ifdef controls
        if lvls['ifdef'] and token in OPEN_PARENTHESIS:
            lvls['ifdef_open_close'] += 1

        stop = False
        if token in (Preprocessor('#ifdef'), Preprocessor('#ifndef')):
            stop = True
            lvls['ifdef'] += 1
            expression, size = parse_block(all_tokens,
                                           _analyze_simple,
                                           i + 1,
                                           lvls,
                                           stop_statement,
                                           defines=defines)
            lvls['ifdef'] -= 1
            if lvls['ifdef'] == 0:
                assert (isinstance(expression, IfDefStatement))
                replacing_expression = parse_ifdef_block(
                    expression, defines, get_coord(all_tokens[:i - 1]))

                new_all_tokens = sqf.base_type.get_all_tokens(
                    tokens + replacing_expression)

                result, _ = parse_block(new_all_tokens,
                                        analyze_tokens,
                                        0,
                                        None,
                                        stop_statement,
                                        defines=defines)

                expression.prepend(tokens)

                expression = IfDefResult(expression, result.tokens)
                statements.append(expression)

                len_expression = len(expression.get_all_tokens())

                i += len_expression - len(tokens) - 1
                tokens = []
            else:
                tokens.append(expression)
                i += size + 1
        # finish ifdef
        elif is_finish_ifdef_condition(tokens, lvls) and (
                is_end_statement(token, stop_statement)
                or is_finish_ifdef_parenthesis(token, lvls)
        ) or lvls['ifdef'] > 1 and token == Preprocessor('#endif'):

            if token != EndOfFile() and token not in CLOSE_PARENTHESIS:
                tokens.append(token)

            if_def = finish_ifdef(tokens, all_tokens, start, statements)
            return if_def, i - start
        # parse during ifdef
        elif lvls['ifdef'] != 0:
            stop = True
            tokens.append(token)

        # end ifdef controls
        if lvls['ifdef'] and token in (STOP_KEYWORDS['single'] +
                                       CLOSE_PARENTHESIS):
            lvls['ifdef_open_close'] -= 1
            if lvls['ifdef_open_close'] < 0:
                lvls['ifdef_open_close'] = 0

        if stop:
            pass
        # try to match a #defined and get the arguments
        elif str(token) in defines:  # is a define
            stop, define_statement, arg_indexes = find_match_if_def(
                all_tokens, i, defines, token)

            if stop:
                arg_number = len(define_statement.args)

                extra_tokens_to_move = 1 + 2 * (
                    arg_number != 0) + 2 * arg_number - 1 * (arg_number != 0)

                replaced_expression = all_tokens[i:i + extra_tokens_to_move]

                # the `all_tokens` after replacement
                replacing_expression = replace_in_expression(
                    define_statement.expression, define_statement.args,
                    arg_indexes, all_tokens)

                new_all_tokens = all_tokens[:i - len(
                    tokens)] + tokens + replacing_expression + all_tokens[
                        i + extra_tokens_to_move:]

                new_start = i - len(tokens)

                expression, size = parse_block(new_all_tokens,
                                               analyze_tokens,
                                               new_start,
                                               lvls,
                                               stop_statement,
                                               defines=defines)

                # the all_tokens of the statement before replacement
                original_tokens_taken = len(replaced_expression) - len(
                    replacing_expression) + size

                original_tokens = all_tokens[i - len(tokens):i - len(tokens) +
                                             original_tokens_taken]

                if isinstance(expression, Statement):
                    expression = expression.content[0]

                if type(original_tokens[-1]) in (EndOfLine, Comment,
                                                 EndOfFile):
                    del original_tokens[-1]
                    original_tokens_taken -= 1

                expression = DefineResult(original_tokens, define_statement,
                                          expression)
                statements.append(expression)

                i += original_tokens_taken - len(tokens) - 1

                tokens = []
        if stop:
            pass
        elif token == ParserKeyword('['):
            lvls['[]'] += 1
            expression, size = parse_block(all_tokens,
                                           analyze_tokens,
                                           i + 1,
                                           lvls,
                                           stop_statement='single',
                                           defines=defines)
            lvls['[]'] -= 1
            tokens.append(expression)
            i += size + 1
        elif token == ParserKeyword('('):
            lvls['()'] += 1
            expression, size = parse_block(all_tokens,
                                           analyze_tokens,
                                           i + 1,
                                           lvls,
                                           stop_statement,
                                           defines=defines)
            lvls['()'] -= 1
            tokens.append(expression)
            i += size + 1
        elif token == ParserKeyword('{'):
            lvls['{}'] += 1
            expression, size = parse_block(all_tokens,
                                           analyze_tokens,
                                           i + 1,
                                           lvls,
                                           stop_statement,
                                           defines=defines)
            lvls['{}'] -= 1
            tokens.append(expression)
            i += size + 1
        elif token == ParserKeyword(']'):
            if lvls['[]'] == 0:
                raise SQFParenthesisError(
                    get_coord(all_tokens[:i]),
                    'Trying to close right parenthesis without them opened.')

            if statements:
                if isinstance(statements[0], DefineResult):
                    statements[0]._tokens = [
                        Array(
                            _analyze_array(statements[0]._tokens,
                                           analyze_tokens, all_tokens[:i]))
                    ]
                    return statements[0], i - start
                else:
                    raise SQFParserError(
                        get_coord(all_tokens[:i]),
                        'A statement %s cannot be in an array' %
                        Statement(statements))

            return Array(_analyze_array(tokens, analyze_tokens,
                                        all_tokens[:i])), i - start
        elif token == ParserKeyword(')'):
            if lvls['()'] == 0:
                raise SQFParenthesisError(
                    get_coord(all_tokens[:i]),
                    'Trying to close parenthesis without opened parenthesis.')

            if tokens:
                statements.append(analyze_tokens(tokens))

            return Statement(statements, parenthesis=True), i - start
        elif token == ParserKeyword('}'):
            if lvls['{}'] == 0:
                raise SQFParenthesisError(
                    get_coord(all_tokens[:i]),
                    'Trying to close brackets without opened brackets.')

            if tokens:
                statements.append(analyze_tokens(tokens))

            return Code(statements), i - start
        # end of statement when not in preprocessor states
        elif all(lvls[lvl_type] == 0
                 for lvl_type in ('#define', '#include')) and is_end_statement(
                     token, stop_statement):
            if type(token) != EndOfFile:
                tokens.append(token)
            if tokens:
                statements.append(analyze_tokens(tokens))

            tokens = []
        elif token in (Preprocessor('#define'), Preprocessor('#include')):
            # notice that `token` is ignored here. It will be picked up in the end
            if tokens:
                # a pre-processor starts a new statement
                statements.append(analyze_tokens(tokens))
                tokens = []

            lvls[token.value] += 1
            expression, size = parse_block(all_tokens,
                                           analyze_tokens,
                                           i + 1,
                                           lvls,
                                           stop_statement,
                                           defines=defines)
            lvls[token.value] -= 1

            statements.append(expression)
            i += size
        elif token == Keyword('#') and lvls['#define'] != 0:
            # The # sqf command is superseded by the preprocessor directive's stringification command
            tokens.append(Preprocessor('#'))
        elif type(token) in (EndOfLine, Comment, EndOfFile) and any(
                lvls[x] != 0 for x in {'#define', '#include'}):
            tokens.insert(
                0,
                all_tokens[start -
                           1])  # pick the token that triggered the statement
            if tokens[0] == Preprocessor('#define'):
                define_statement = _analyze_define(tokens)
                defines[define_statement.variable_name][len(
                    define_statement.args)] = define_statement
                statements.append(define_statement)
            else:
                statements.append(analyze_tokens(tokens))

            return Statement(statements), i - start
        elif type(token) != EndOfFile:
            tokens.append(token)
        i += 1

    if is_finish_ifdef_condition(tokens, lvls):
        return finish_ifdef(tokens, all_tokens, start, statements), i - start

    for lvl_type in ('[]', '()', '{}', 'ifdef'):
        if lvls[lvl_type] != 0:
            message = 'Parenthesis "%s" not closed' % lvl_type[0]
            if lvl_type == 'ifdef':
                message = '#ifdef statement not closed'

            raise SQFParenthesisError(get_coord(all_tokens[:start - 1]),
                                      message)

    if tokens:
        statements.append(analyze_tokens(tokens))

    return Statement(statements), i - start
Example #24
0
 def test_append(self):
     interpreter, outcome = interpret('_x = [1,2]; _x append [3,4]')
     self.assertEqual(Nothing(), outcome)
     self.assertEqual(Array([N(1), N(2), N(3), N(4)]), interpreter['_x'])
Example #25
0
    def test_subtract(self):
        test = '_x = [1, 2, 3, 2, 4]; _y = [2, 3]; _z = _x - _y'
        _, outcome = interpret(test)

        self.assertEqual(Array([N(1), N(4)]), outcome)