Esempio n. 1
0
    def compile_test_function(self, call_node: ast.Call, equals=None):
        if call_node.keywords:
            raise EsdSyntaxError(call_node.lineno, "You cannot use keyword arguments in test functions (yet).")
        try:
            f_id = TEST_FUNCTIONS_ID_BY_TYPE_NAME[self.ESD.esd_type, call_node.func.id]
        except KeyError:
            try:
                f_id = int(self._TEST_DEFAULT_RE.match(call_node.func.id).group(1))
            except AttributeError:
                raise EsdValueError(call_node.lineno, f"Invalid ESD function name: '{call_node.func.id}'.")
        args = self.parse_args(call_node.args)
        call = (f_id, *args)

        if call in self.registers:
            # Load from register.
            return struct.pack('B', self.registers.index(call) + 175)

        compiled = self.compile_number(f_id) + b''.join(self.compile_ezl(arg) for arg in args)
        compiled += FUNCTION_ARG_BYTES_BY_COUNT[len(args)]
        if call in self.current_to_write:
            compiled += self.save_into_next_available_register(call)
            self.current_to_write.remove(call)
        if equals is not None:
            if equals == 0:
                compiled += b'\x40\x95'
            elif equals == 1:
                compiled += b'\x41\x95'
            else:
                raise ValueError("Internal error: 'equals' arg should only be 0 or 1 (or None).")
        return compiled
Esempio n. 2
0
 def build_command(self, node):
     """Pass in the body of a function def, or a list of nodes before 'return' in a test block."""
     if self.is_state_machine_call(node):
         bank = 6  # TODO: True in every game/file?
         f_id = 0x80000000 - node.value.func.slice.value.n
         if not isinstance(f_id, int):
             raise EsdValueError(
                 node.lineno,
                 "State machine call must have an integer index.")
     elif self.is_call(node):
         try:
             bank, f_id = COMMANDS_BANK_ID_BY_TYPE_NAME[self.ESD.esd_type,
                                                        node.value.func.id]
         except KeyError:
             command_match = self._COMMAND_DEFAULT_RE.match(
                 node.value.func.id)
             if not command_match:
                 raise EsdError(
                     node.lineno,
                     f"Invalid enter/exit/ongoing command: {node.value.func.id}"
                 )
             bank, f_id = command_match.group(1, 2)
             bank, f_id = int(bank), int(f_id)
     else:
         raise EsdSyntaxError(
             node.lineno,
             f"Expected only function calls, not node type {type(node)}.")
     # TODO: Check arg count against canonical function, once available, and order keyword args.
     args = node.value.args + [
         keyword.value for keyword in node.value.keywords
     ]
     command_args = [self.compile_ezl(arg) + b"\xa1" for arg in args]
     return self.ESD.Command(self.ESD.esd_type, bank, f_id, command_args)
Esempio n. 3
0
 def parse_args(arg_nodes):
     args = []
     for node in arg_nodes:
         if isinstance(node, ast.Num):
             args.append(node.n)
         elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
             args.append(-node.operand.n)
         elif isinstance(node, (ast.Subscript, ast.Name)):
             args.append(node)
         else:
             raise EsdValueError(node.lineno, "Function arguments must be numeric literals.")
     return tuple(args)
Esempio n. 4
0
 def get_ast_sequence(node):
     """ List/tuple can only contain literals. """
     if isinstance(node, (ast.Tuple, ast.List)):
         t = []
         for e in node.elts:
             if isinstance(e, ast.Num):
                 t.append(e.n)
             elif isinstance(e, ast.Str):
                 t.append(e.s)
             else:
                 raise EsdValueError(node.lineno, f"Sequences must contain only numeric/string literals.")
         return t
     raise EsdSyntaxError(node.lineno, f"Expected a list or tuple node, but found: {type(node)}")