(self)
return None
Parse a stat.

        stat ::=  varlist '=' explist |
         functioncall |
         do block end |
         while exp do block end |
         repeat block until exp |
         if exp then block {elseif exp then block} [else block] end |
         for Name '=' exp ',' exp [',' exp] do block end |
         for namelist in explist do block end |
         function funcname funcbody |
         local function Name funcbody |
         local namelist ['=' explist] |
         ::label::

        Returns:
          StatAssignment(varlist, assignop, explist)
          StatFunctionCall(functioncall)
          StatDo(block)
          StatWhile(exp, block)
          StatRepeat(block, exp)
          StatIf(exp_block_pairs)
          StatForStep(name, exp_init, exp_end, exp_step, block)
          StatForIn(namelist, explist, block)
          StatFunction(funcname, funcbody)
          StatLocalFunction(funcname, funcbody)
          StatLocalAssignment(namelist, explist)
          StatGoto(label)
          StatLabel(label)
Parse a stat.
Parse a stat .
def _stat(self):
        """Parse a stat.

        stat ::=  varlist '=' explist |
         functioncall |
         do block end |
         while exp do block end |
         repeat block until exp |
         if exp then block {elseif exp then block} [else block] end |
         for Name '=' exp ',' exp [',' exp] do block end |
         for namelist in explist do block end |
         function funcname funcbody |
         local function Name funcbody |
         local namelist ['=' explist] |
         ::label::

        Returns:
          StatAssignment(varlist, assignop, explist)
          StatFunctionCall(functioncall)
          StatDo(block)
          StatWhile(exp, block)
          StatRepeat(block, exp)
          StatIf(exp_block_pairs)
          StatForStep(name, exp_init, exp_end, exp_step, block)
          StatForIn(namelist, explist, block)
          StatFunction(funcname, funcbody)
          StatLocalFunction(funcname, funcbody)
          StatLocalAssignment(namelist, explist)
          StatGoto(label)
          StatLabel(label)
        """
        pos = self._pos

        varlist = self._varlist()
        if varlist is not None:
            # (Missing '=' is not a fatal error because varlist might also
            # match the beginning of a functioncall.)
            assign_op = (self._accept(lexer.TokSymbol(b'=')) or
                         self._accept(lexer.TokSymbol(b'+=')) or
                         self._accept(lexer.TokSymbol(b'-=')) or
                         self._accept(lexer.TokSymbol(b'*=')) or
                         self._accept(lexer.TokSymbol(b'/=')) or
                         self._accept(lexer.TokSymbol(b'%=')) or
                         self._accept(lexer.TokSymbol(b'..=')))
            if assign_op is not None:
                explist = self._assert(self._explist(),
                                       'Expected expression in assignment')
                return StatAssignment(varlist, assign_op, explist,
                                      start=pos, end=self._pos)
        self._pos = pos

        functioncall = self._functioncall()
        if functioncall is not None:
            return StatFunctionCall(functioncall, start=pos, end=self._pos)
        self._pos = pos

        if self._accept(lexer.TokKeyword(b'do')) is not None:
            block = self._assert(self._chunk(), 'block in do')
            self._expect(lexer.TokKeyword(b'end'))
            return StatDo(block, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'while')) is not None:
            exp = self._assert(self._exp(), 'exp in while')
            self._expect(lexer.TokKeyword(b'do'))
            block = self._assert(self._chunk(), 'block in while')
            self._expect(lexer.TokKeyword(b'end'))
            return StatWhile(exp, block, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'repeat')) is not None:
            block = self._assert(self._chunk(),
                                 'block in repeat')
            self._expect(lexer.TokKeyword(b'until'))
            exp = self._assert(self._exp(),
                               'expression in repeat')
            return StatRepeat(block, exp, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'if')) is not None:
            exp_block_pairs = []
            exp = self._exp()

            then_pos = self._pos
            if (self._accept(lexer.TokKeyword(b'then')) is None and
                self._accept(lexer.TokKeyword(b'do')) is None and
                    (self._tokens[exp._end_token_pos - 1] == lexer.TokSymbol(b')'))):
                # Check for PICO-8 short form.

                then_end_pos = exp._end_token_pos
                while (then_end_pos < len(self._tokens) and
                       not self._tokens[then_end_pos].matches(lexer.TokNewline)):
                    then_end_pos += 1

                try:
                    self._max_pos = then_end_pos
                    block = self._assert(self._chunk(),
                                         'valid chunk in short-if')
                    else_block = None
                    if self._accept(lexer.TokKeyword(b'else')) is not None:
                        # PICO-8 accepts an else with nothing after it.
                        else_block = self._chunk()
                finally:
                    self._max_pos = None

                # (Use exp.value here to unwrap the condition from the
                # bracketed expression.)
                exp_block_pairs = [(exp.value, block)]
                if else_block is not None and len(else_block.stats) > 0:
                    exp_block_pairs.append((None, else_block))
                return StatIf(exp_block_pairs, start=pos, end=self._pos,
                              short_if=True)

            self._pos = then_pos

            # Hack: accept "do" for "then" to support oddball carts that
            # exploit an accidental loophole in short-if. Note that this
            # is not how PICO-8 works: the accident comes from how PICO-8
            # uses a preprocessing pass to convert short-if syntax to regular
            # if syntax. The erroneous
            #   if (cond) do
            #     ...
            #   end
            # becomes
            #   if (cond) then do end
            #     ...
            #   end
            # Here, we pretend it's part of the grammar.
            if self._accept(lexer.TokKeyword(b'do')) is None:
                self._expect(lexer.TokKeyword(b'then'))
            block = self._chunk()
            self._assert(block, 'Expected block in if')
            exp_block_pairs.append((exp, block))
            while self._accept(lexer.TokKeyword(b'elseif')) is not None:
                exp = self._exp()
                self._expect(lexer.TokKeyword(b'then'))
                block = self._chunk()
                self._assert(block, 'Expected block in elseif')
                exp_block_pairs.append((exp, block))
            if self._accept(lexer.TokKeyword(b'else')) is not None:
                block = self._chunk()
                self._assert(block, 'Expected block in else')
                exp_block_pairs.append((None, block))
            self._expect(lexer.TokKeyword(b'end'))
            return StatIf(exp_block_pairs, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'for')) is not None:
            for_pos = self._pos

            name = self._accept(lexer.TokName)
            eq_sym = self._accept(lexer.TokSymbol(b'='))
            if eq_sym is not None:
                exp_init = self._assert(self._exp(), 'exp-init in for')
                self._expect(lexer.TokSymbol(b','))
                exp_end = self._assert(self._exp(), 'exp-end in for')
                exp_step = None
                if self._accept(lexer.TokSymbol(b',')):
                    exp_step = self._assert(self._exp(), 'exp-step in for')
                self._expect(lexer.TokKeyword(b'do'))
                block = self._assert(self._chunk(), 'block in for')
                self._expect(lexer.TokKeyword(b'end'))
                return StatForStep(name, exp_init, exp_end, exp_step, block,
                                   start=pos, end=self._pos)
            self._pos = for_pos

            namelist = self._assert(self._namelist(), 'namelist in for-in')
            self._expect(lexer.TokKeyword(b'in'))
            explist = self._assert(self._explist(), 'explist in for-in')
            self._expect(lexer.TokKeyword(b'do'))
            block = self._assert(self._chunk(), 'block in for-in')
            self._expect(lexer.TokKeyword(b'end'))
            return StatForIn(namelist, explist, block, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'function')) is not None:
            funcname = self._assert(self._funcname(), 'funcname in function')
            funcbody = self._assert(self._funcbody(), 'funcbody in function')
            return StatFunction(funcname, funcbody, start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'local')) is not None:
            if self._accept(lexer.TokKeyword(b'function')) is not None:
                funcname = self._expect(lexer.TokName)
                funcbody = self._assert(self._funcbody(),
                                        'funcbody in local function')
                return StatLocalFunction(funcname, funcbody,
                                         start=pos, end=self._pos)
            namelist = self._assert(self._namelist(),
                                    'namelist in local assignment')
            explist = None
            if self._accept(lexer.TokSymbol(b'=')) is not None:
                explist = self._assert(self._explist(),
                                       'explist in local assignment')
            return StatLocalAssignment(namelist, explist,
                                       start=pos, end=self._pos)

        if self._accept(lexer.TokKeyword(b'goto')) is not None:
            label = self._expect(lexer.TokName)
            return StatGoto(label.value, start=pos, end=self._pos)

        label = self._accept(lexer.TokLabel)
        if label is not None:
            # Remove colons from label.
            label_name = label.value[2:-2]
            return StatLabel(label_name, start=pos, end=self._pos)

        self._pos = pos
        return None
def _stat ( self ) : pos = self . _pos varlist = self . _varlist ( ) if varlist is not None : # (Missing '=' is not a fatal error because varlist might also # match the beginning of a functioncall.) assign_op = ( self . _accept ( lexer . TokSymbol ( b'=' ) ) or self . _accept ( lexer . TokSymbol ( b'+=' ) ) or self . _accept ( lexer . TokSymbol ( b'-=' ) ) or self . _accept ( lexer . TokSymbol ( b'*=' ) ) or self . _accept ( lexer . TokSymbol ( b'/=' ) ) or self . _accept ( lexer . TokSymbol ( b'%=' ) ) or self . _accept ( lexer . TokSymbol ( b'..=' ) ) ) if assign_op is not None : explist = self . _assert ( self . _explist ( ) , 'Expected expression in assignment' ) return StatAssignment ( varlist , assign_op , explist , start = pos , end = self . _pos ) self . _pos = pos functioncall = self . _functioncall ( ) if functioncall is not None : return StatFunctionCall ( functioncall , start = pos , end = self . _pos ) self . _pos = pos if self . _accept ( lexer . TokKeyword ( b'do' ) ) is not None : block = self . _assert ( self . _chunk ( ) , 'block in do' ) self . _expect ( lexer . TokKeyword ( b'end' ) ) return StatDo ( block , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'while' ) ) is not None : exp = self . _assert ( self . _exp ( ) , 'exp in while' ) self . _expect ( lexer . TokKeyword ( b'do' ) ) block = self . _assert ( self . _chunk ( ) , 'block in while' ) self . _expect ( lexer . TokKeyword ( b'end' ) ) return StatWhile ( exp , block , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'repeat' ) ) is not None : block = self . _assert ( self . _chunk ( ) , 'block in repeat' ) self . _expect ( lexer . TokKeyword ( b'until' ) ) exp = self . _assert ( self . _exp ( ) , 'expression in repeat' ) return StatRepeat ( block , exp , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'if' ) ) is not None : exp_block_pairs = [ ] exp = self . _exp ( ) then_pos = self . _pos if ( self . _accept ( lexer . TokKeyword ( b'then' ) ) is None and self . _accept ( lexer . TokKeyword ( b'do' ) ) is None and ( self . _tokens [ exp . _end_token_pos - 1 ] == lexer . TokSymbol ( b')' ) ) ) : # Check for PICO-8 short form. then_end_pos = exp . _end_token_pos while ( then_end_pos < len ( self . _tokens ) and not self . _tokens [ then_end_pos ] . matches ( lexer . TokNewline ) ) : then_end_pos += 1 try : self . _max_pos = then_end_pos block = self . _assert ( self . _chunk ( ) , 'valid chunk in short-if' ) else_block = None if self . _accept ( lexer . TokKeyword ( b'else' ) ) is not None : # PICO-8 accepts an else with nothing after it. else_block = self . _chunk ( ) finally : self . _max_pos = None # (Use exp.value here to unwrap the condition from the # bracketed expression.) exp_block_pairs = [ ( exp . value , block ) ] if else_block is not None and len ( else_block . stats ) > 0 : exp_block_pairs . append ( ( None , else_block ) ) return StatIf ( exp_block_pairs , start = pos , end = self . _pos , short_if = True ) self . _pos = then_pos # Hack: accept "do" for "then" to support oddball carts that # exploit an accidental loophole in short-if. Note that this # is not how PICO-8 works: the accident comes from how PICO-8 # uses a preprocessing pass to convert short-if syntax to regular # if syntax. The erroneous #   if (cond) do #     ... #   end # becomes #   if (cond) then do end #     ... #   end # Here, we pretend it's part of the grammar. if self . _accept ( lexer . TokKeyword ( b'do' ) ) is None : self . _expect ( lexer . TokKeyword ( b'then' ) ) block = self . _chunk ( ) self . _assert ( block , 'Expected block in if' ) exp_block_pairs . append ( ( exp , block ) ) while self . _accept ( lexer . TokKeyword ( b'elseif' ) ) is not None : exp = self . _exp ( ) self . _expect ( lexer . TokKeyword ( b'then' ) ) block = self . _chunk ( ) self . _assert ( block , 'Expected block in elseif' ) exp_block_pairs . append ( ( exp , block ) ) if self . _accept ( lexer . TokKeyword ( b'else' ) ) is not None : block = self . _chunk ( ) self . _assert ( block , 'Expected block in else' ) exp_block_pairs . append ( ( None , block ) ) self . _expect ( lexer . TokKeyword ( b'end' ) ) return StatIf ( exp_block_pairs , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'for' ) ) is not None : for_pos = self . _pos name = self . _accept ( lexer . TokName ) eq_sym = self . _accept ( lexer . TokSymbol ( b'=' ) ) if eq_sym is not None : exp_init = self . _assert ( self . _exp ( ) , 'exp-init in for' ) self . _expect ( lexer . TokSymbol ( b',' ) ) exp_end = self . _assert ( self . _exp ( ) , 'exp-end in for' ) exp_step = None if self . _accept ( lexer . TokSymbol ( b',' ) ) : exp_step = self . _assert ( self . _exp ( ) , 'exp-step in for' ) self . _expect ( lexer . TokKeyword ( b'do' ) ) block = self . _assert ( self . _chunk ( ) , 'block in for' ) self . _expect ( lexer . TokKeyword ( b'end' ) ) return StatForStep ( name , exp_init , exp_end , exp_step , block , start = pos , end = self . _pos ) self . _pos = for_pos namelist = self . _assert ( self . _namelist ( ) , 'namelist in for-in' ) self . _expect ( lexer . TokKeyword ( b'in' ) ) explist = self . _assert ( self . _explist ( ) , 'explist in for-in' ) self . _expect ( lexer . TokKeyword ( b'do' ) ) block = self . _assert ( self . _chunk ( ) , 'block in for-in' ) self . _expect ( lexer . TokKeyword ( b'end' ) ) return StatForIn ( namelist , explist , block , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'function' ) ) is not None : funcname = self . _assert ( self . _funcname ( ) , 'funcname in function' ) funcbody = self . _assert ( self . _funcbody ( ) , 'funcbody in function' ) return StatFunction ( funcname , funcbody , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'local' ) ) is not None : if self . _accept ( lexer . TokKeyword ( b'function' ) ) is not None : funcname = self . _expect ( lexer . TokName ) funcbody = self . _assert ( self . _funcbody ( ) , 'funcbody in local function' ) return StatLocalFunction ( funcname , funcbody , start = pos , end = self . _pos ) namelist = self . _assert ( self . _namelist ( ) , 'namelist in local assignment' ) explist = None if self . _accept ( lexer . TokSymbol ( b'=' ) ) is not None : explist = self . _assert ( self . _explist ( ) , 'explist in local assignment' ) return StatLocalAssignment ( namelist , explist , start = pos , end = self . _pos ) if self . _accept ( lexer . TokKeyword ( b'goto' ) ) is not None : label = self . _expect ( lexer . TokName ) return StatGoto ( label . value , start = pos , end = self . _pos ) label = self . _accept ( lexer . TokLabel ) if label is not None : # Remove colons from label. label_name = label . value [ 2 : - 2 ] return StatLabel ( label_name , start = pos , end = self . _pos ) self . _pos = pos return None