Example #1
0
    def test_string(self):
        code = "y = 'x' + x"
        analyzer = Analyzer()
        scope = analyzer.get_scope('x')
        scope['x'] = String()

        analyze(parse(code), analyzer)
        self.assertEqual(analyzer.exceptions, [])
        self.assertEqual(analyzer['y'], String())
Example #2
0
 def test_default_and_or(self):
     code = '''
     switch %s do {
         case "0";
         default {"default"};
         case "3": {"3"};
         case "1";
         case "4";
         case "2": {"2"};
     }'''
     self.assertEqual(String('"3"'), interpret(code % '"0"')[1])
     self.assertEqual(String('"default"'), interpret(code % '"5"')[1])
     self.assertEqual(String('"2"'), interpret(code % '"1"')[1])
     self.assertEqual(String('"3"'), interpret(code % '"3"')[1])
Example #3
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 #4
0
def preprocessor_stringify(token, is_variable):
    # Verify that token starts with appropriate char and is alphanumeric
    if not (is_variable or re.match(r'[a-zA-Z_]\w*', str(token))):
        # todo: need to fix the coordinates for errors here
        raise SQFParserError(get_coord(""),
                             'Stringification failed on invalid characters')

    # todo: check for invalid string created (missing ")
    return String("\"" + str(token) + "\"")
Example #5
0
 def __init__(self, variable=None, from_=None, to=None, step=None):
     if step is None:
         step = Number(1)
     if variable is None:
         variable = String()
     assert (variable is None or isinstance(variable, String))
     assert (from_ is None or isinstance(from_, Type))
     assert (to is None or isinstance(to, Type))
     assert (isinstance(step, Type))
     super().__init__(variable)
     self.from_ = from_
     self.to = to
     self.step = step
Example #6
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 #7
0
 def test_add(self):
     test = '_x = "ABA"; _y = "BAB"; _x + _y'
     _, outcome = interpret(test)
     self.assertEqual(String('"ABABAB"'), outcome)
Example #8
0
    def test_assign(self):
        test = '_x = "ABA";'
        interpreter, outcome = interpret(test)

        self.assertEqual(String('"ABA"'), interpreter['_x'])
Example #9
0
 def test_with_default_unused(self):
     analyzer = analyze(parse('[""] params [["_x", 0]]; _x'))
     self.assertEqual(analyzer.exceptions, [])
     self.assertEqual(String('""'), analyzer['_x'])
Example #10
0
    def execute_single(self, statement):
        assert (isinstance(statement, Statement))

        outcome = Nothing()
        outcome.position = statement.position

        base_tokens = []
        for token in statement.tokens:
            if not statement.is_base_token(token):
                self.execute_other(token)
            else:
                base_tokens.append(token)

        if not base_tokens:
            return outcome

        # operations that cannot evaluate the value of all base_tokens
        if type(base_tokens[0]) == DefineStatement:
            return base_tokens[0]
        elif base_tokens[0] == Preprocessor("#include"):
            if len(base_tokens) != 2:
                exception = SQFParserError(base_tokens[0].position,
                                           "#include requires one argument")
                self.exception(exception)
            elif type(self.execute_token(base_tokens[1])) != String:
                exception = SQFParserError(
                    base_tokens[0].position,
                    "#include first argument must be a string")
                self.exception(exception)
            return outcome
        elif isinstance(base_tokens[0],
                        Keyword) and base_tokens[0].value in PREPROCESSORS:
            # remaining preprocessors are ignored
            return outcome
        elif len(base_tokens) == 2 and base_tokens[0] == Keyword('private'):
            # the rhs may be a variable, so we cannot get the value
            rhs = self.execute_token(base_tokens[1])
            if isinstance(rhs, String):
                self.add_privates([rhs])
            elif isinstance(rhs, Array):
                value = self.value(rhs)
                if value.is_undefined:
                    self.exception(
                        SQFWarning(
                            base_tokens[0].position,
                            'Obfuscated statement. Consider explicitly set what is private.'
                        ))
                else:
                    self.add_privates(value)
            elif isinstance(rhs, Variable):
                var = String('"' + rhs.name + '"')
                var.position = rhs.position
                self.add_privates([var])
                outcome = PrivateType(rhs)
                outcome.position = rhs.position
                self.privates.add(outcome)
            else:
                self.exception(
                    SQFParserError(base_tokens[0].position,
                                   '`private` used incorrectly'))
            return outcome
        # assignment operator
        elif len(base_tokens) == 3 and base_tokens[1] == Keyword('='):
            lhs = self.execute_token(base_tokens[0])
            if isinstance(lhs, PrivateType):
                self.privates.remove(lhs)
                lhs = lhs.variable
            else:
                lhs = self.get_variable(base_tokens[0])

            if not isinstance(lhs, Variable):
                self.exception(
                    SQFParserError(
                        base_tokens[0].position,
                        'lhs of assignment operator must be a variable'))
            else:
                # if the rhs_v is code and calls `lhs` (recursion) it will assume lhs is anything (and not Nothing)
                scope = self.get_scope(lhs.name)
                if lhs.name not in scope or isinstance(scope[lhs.name],
                                                       Nothing):
                    scope[lhs.name] = Anything()

                rhs_v = self.value(base_tokens[2])
                self.assign(lhs, rhs_v)
                if not statement.ending:
                    outcome = rhs_v
            return outcome
        # A variable can only be evaluated if we need its value, so we will not call its value until the very end.
        elif len(base_tokens) == 1 and type(
                base_tokens[0]) in (Variable, Array):
            return self.execute_token(base_tokens[0])
        # heuristic for defines (that are thus syntactically correct):
        #   - is keyword but upper cased
        #   - first token string starts uppercased
        elif len(base_tokens) == 1 and type(base_tokens[0]) == Keyword and str(
                base_tokens[0])[0].isupper():
            outcome = Variable(str(base_tokens[0]))
            outcome.position = base_tokens[0].position
            return outcome
        elif is_undefined_define(base_tokens):
            # get all arguments and compute their value to analyze them
            if isinstance(base_tokens[1].base_tokens[0], Statement):
                sub_tokens = base_tokens[1].base_tokens[0].base_tokens
            else:
                sub_tokens = base_tokens[0]
            for sub_token in sub_tokens:
                self.value(sub_token)

            # finally, build the outcome
            outcome = Anything()
            outcome.position = base_tokens[0].position
            return outcome

        # evaluate all the base_tokens, trying to obtain their values
        values = []
        tokens = []
        for token in base_tokens:
            t = self.execute_token(token)
            v = self.value(t)
            tokens.append(t)
            values.append(v)

        # try to find a match for any expression, both typed and un-typed
        case_found = None
        possible_expressions = values_to_expressions(values, EXPRESSIONS_MAP,
                                                     EXPRESSIONS)
        for case in possible_expressions:
            if case.is_signature_match(values):  # match first occurrence
                case_found = case
                break
Example #11
0
def parse_strings_and_comments(all_tokens):
    """
    Function that parses the strings of a script, transforming them into `String`.
    """
    string = ''  # the buffer for the activated mode
    tokens = []  # the final result
    in_double = False
    mode = None  # [None, "string_single", "string_double", "comment_line", "comment_bulk"]

    for i, token in enumerate(all_tokens):
        if mode == "string_double":
            string += token
            if token == '"':
                if in_double:
                    in_double = False
                elif not in_double and i != len(all_tokens) - 1 and all_tokens[
                        i + 1] == '"':
                    in_double = True
                else:
                    tokens.append(String(string))
                    mode = None
                    in_double = False
        elif mode == "string_single":
            string += token
            if token == "'":
                if in_double:
                    in_double = False
                elif not in_double and i != len(all_tokens) - 1 and all_tokens[
                        i + 1] == "'":
                    in_double = True
                else:
                    tokens.append(String(string))
                    mode = None
                    in_double = False
        elif mode == "comment_bulk":
            string += token
            if token == '*/':
                mode = None
                tokens.append(Comment(string))
                string = ''
        elif mode == "comment_line":
            string += token
            if token in ('\n', '\r\n'):
                mode = None
                tokens.append(Comment(string))
                string = ''
        else:  # mode is None
            if token == '"':
                string = token
                mode = "string_double"
            elif token == "'":
                string = token
                mode = "string_single"
            elif token == '/*':
                string = token
                mode = "comment_bulk"
            elif token == '//':
                string = token
                mode = "comment_line"
            else:
                tokens.append(token)

    if mode in ("comment_line", "comment_bulk"):
        tokens.append(Comment(string))
    elif mode is not None:
        raise SQFParserError(get_coord(tokens), 'String is not closed')

    return tokens
Example #12
0
class Interpreter(BaseInterpreter):
    private_default_class = Nothing

    def __init__(self, all_vars=None):
        super().__init__(all_vars)

        self._simulation = None
        self._client = None

    @property
    def simulation(self):
        return self._simulation

    @property
    def client(self):
        return self._client

    @client.setter
    def client(self, client):
        self._client = client
        self._simulation = client.simulation

    def _add_params(self, token):
        super()._add_params(token)
        lhs = token[0].value
        scope = self.get_scope(lhs)
        scope[lhs] = token[1]

    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)

    def execute_single(self, statement):
        assert (not isinstance(statement, Code))

        outcome = Nothing()
        _outcome = outcome

        # evaluate the types of all tokens
        base_tokens = statement.base_tokens
        values = []
        tokens = []
        types = []

        for token in base_tokens:
            t, v = self.execute_token(token)
            values.append(v)
            tokens.append(t)
            types.append(type(v))

        case_found = None
        for case in EXPRESSIONS:
            if case.is_match(values):
                case_found = case
                break

        if case_found is not None:
            outcome = case_found.execute(values, self)
        # todo: replace all elif below by expressions
        elif len(tokens) == 2 and tokens[0] == Keyword('publicVariable'):
            if not isinstance(tokens[1],
                              String) or tokens[1].value.startswith('_'):
                raise SQFParserError(
                    statement.position,
                    'Interpretation of "%s" failed' % statement)

            var_name = tokens[1].value
            scope = self.get_scope(var_name, 'missionNamespace')
            self.simulation.broadcast(var_name, scope[var_name])

        elif len(tokens) == 2 and tokens[0] == Keyword('publicVariableServer'):
            if not isinstance(tokens[1],
                              String) or tokens[1].value.startswith('_'):
                raise SQFParserError(
                    statement.position,
                    'Interpretation of "%s" failed' % statement)

            var_name = tokens[1].value
            scope = self.get_scope(var_name, 'missionNamespace')
            self.simulation.broadcast(var_name, scope[var_name],
                                      -1)  # -1 => to server

        elif len(tokens) == 2 and tokens[0] == Keyword('private'):
            if isinstance(values[1], String):
                self.add_privates([values[1]])
            elif isinstance(values[1], Array):
                self.add_privates(values[1].value)
            elif isinstance(base_tokens[1], Statement) and isinstance(
                    base_tokens[1].base_tokens[0], Variable):
                var = base_tokens[1].base_tokens[0]
                self.add_privates([String('"' + var.name + '"')])
                outcome = PrivateType(var)
        # binary operators
        elif len(tokens) == 3 and tokens[1] in (
                Keyword('='), Keyword('publicVariableClient')):
            # it is a binary statement: token, operation, token
            lhs = tokens[0]
            lhs_v = values[0]
            lhs_t = types[0]

            op = tokens[1]
            rhs = tokens[2]
            rhs_v = values[2]
            rhs_t = types[2]

            if op == Keyword('='):
                if isinstance(lhs, PrivateType):
                    lhs = lhs.variable
                else:
                    lhs = self.get_variable(base_tokens[0])

                if not isinstance(lhs, Variable) or not isinstance(
                        rhs_v, Type):
                    raise SQFParserError(
                        statement.position,
                        'Interpretation of "%s" failed' % statement)

                scope = self.get_scope(lhs.name)
                scope[lhs.name] = rhs_v
                outcome = rhs
            elif op == Keyword('publicVariableClient'):
                if not lhs_t == Number or rhs.value.startswith('_'):
                    raise SQFParserError(
                        statement.position,
                        'Interpretation of "%s" failed' % statement)
                client_id = lhs.value
                var_name = rhs.value
                scope = self.get_scope(var_name, 'missionNamespace')
                self.simulation.broadcast(var_name, scope[var_name], client_id)
        # code, variables and values
        elif len(tokens) == 1 and isinstance(tokens[0], (Type, Keyword)):
            outcome = values[0]
        else:
            raise SQFParserError(statement.position,
                                 'Interpretation of "%s" failed' % statement)

        if statement.ending:
            outcome = _outcome
        assert (type(outcome) in (Nothing, Keyword)
                or not outcome.is_undefined)
        return outcome