(self, ins)
Parse and evaluate tokenised (sub-)expression.
Parse and evaluate tokenised (sub-)expression.
Parse and evaluate tokenised ( sub - ) expression .
def parse(self, ins):
        """Parse and evaluate tokenised (sub-)expression."""
        operations = deque()
        with self._memory.get_stack() as units:
            final = True
            # see https://en.wikipedia.org/wiki/Shunting-yard_algorithm
            d = b''
            while True:
                last = d
                ins.skip_blank()
                d = ins.read_keyword_token()
                ins.seek(-len(d), 1)
                if d == tk.NOT and not (last in op.OPERATORS or last == b''):
                    # unary NOT ends expression except after another operator or at start
                    break
                elif d in op.OPERATORS:
                    ins.read(len(d))
                    # get combined operators such as >=
                    if d in op.COMBINABLE:
                        nxt = ins.skip_blank()
                        if nxt in op.COMBINABLE:
                            d += ins.read(len(nxt))
                    if last in op.OPERATORS or last == b'' or d == tk.NOT:
                        # also if last is ( but that leads to recursive call and last == ''
                        nargs = 1
                        # zero operands for a binary operator is always syntax error
                        # because it will be seen as an illegal unary
                        try:
                            oper = op.UNARY[d]
                            prec = op.PRECEDENCE[(d, nargs)]
                        except KeyError:
                            raise error.BASICError(error.STX)
                    else:
                        nargs = 2
                        try:
                            oper = op.BINARY[d]
                            prec = op.PRECEDENCE[(d, nargs)]
                        except KeyError:
                            # illegal combined ops like == raise syntax error here
                            raise error.BASICError(error.STX)
                        self._drain(prec, operations, units)
                    operations.append((oper, nargs, prec))
                elif not (last in op.OPERATORS or last == b''):
                    # repeated unit ends expression
                    # repeated literals or variables or non-keywords like 'AS'
                    break
                elif d == b'(':
                    ins.read(len(d))
                    # we need to create a new object or we'll overwrite our own stacks
                    # this will not be needed if we localise stacks in the expression parser
                    # either a separate class of just as local variables
                    units.append(self.parse(ins))
                    ins.require_read((b')',))
                elif d and d in LETTERS:
                    name = ins.read_name()
                    error.throw_if(not name, error.STX)
                    indices = self.parse_indices(ins)
                    view = self._memory.view_or_create_variable(name, indices)
                    # should make a shallow copy? but .clone here breaks circular MID$
                    units.append(view)
                elif d in self._functions:
                    units.append(self._parse_function(ins, d))
                    #if not isinstance(units[-1], values.String):
                    #    self._memory.strings.reset_temporaries()
                elif d in tk.END_STATEMENT:
                    break
                elif d in tk.END_EXPRESSION:
                    # missing operand inside brackets or before comma is syntax error
                    final = False
                    break
                elif d == b'"':
                    units.append(self.read_string_literal(ins))
                else:
                    units.append(self.read_number_literal(ins))
            # raises IndexError for insufficient operators
            try:
                self._drain(0, operations, units)
                return units[0]
            except IndexError:
                # empty expression is a syntax error (inside brackets)
                # or Missing Operand (in an assignment)
                if final:
                    raise error.BASICError(error.MISSING_OPERAND)
                raise error.BASICError(error.STX)
def parse ( self , ins ) : operations = deque ( ) with self . _memory . get_stack ( ) as units : final = True # see https://en.wikipedia.org/wiki/Shunting-yard_algorithm d = b'' while True : last = d ins . skip_blank ( ) d = ins . read_keyword_token ( ) ins . seek ( - len ( d ) , 1 ) if d == tk . NOT and not ( last in op . OPERATORS or last == b'' ) : # unary NOT ends expression except after another operator or at start break elif d in op . OPERATORS : ins . read ( len ( d ) ) # get combined operators such as >= if d in op . COMBINABLE : nxt = ins . skip_blank ( ) if nxt in op . COMBINABLE : d += ins . read ( len ( nxt ) ) if last in op . OPERATORS or last == b'' or d == tk . NOT : # also if last is ( but that leads to recursive call and last == '' nargs = 1 # zero operands for a binary operator is always syntax error # because it will be seen as an illegal unary try : oper = op . UNARY [ d ] prec = op . PRECEDENCE [ ( d , nargs ) ] except KeyError : raise error . BASICError ( error . STX ) else : nargs = 2 try : oper = op . BINARY [ d ] prec = op . PRECEDENCE [ ( d , nargs ) ] except KeyError : # illegal combined ops like == raise syntax error here raise error . BASICError ( error . STX ) self . _drain ( prec , operations , units ) operations . append ( ( oper , nargs , prec ) ) elif not ( last in op . OPERATORS or last == b'' ) : # repeated unit ends expression # repeated literals or variables or non-keywords like 'AS' break elif d == b'(' : ins . read ( len ( d ) ) # we need to create a new object or we'll overwrite our own stacks # this will not be needed if we localise stacks in the expression parser # either a separate class of just as local variables units . append ( self . parse ( ins ) ) ins . require_read ( ( b')' , ) ) elif d and d in LETTERS : name = ins . read_name ( ) error . throw_if ( not name , error . STX ) indices = self . parse_indices ( ins ) view = self . _memory . view_or_create_variable ( name , indices ) # should make a shallow copy? but .clone here breaks circular MID$ units . append ( view ) elif d in self . _functions : units . append ( self . _parse_function ( ins , d ) ) #if not isinstance(units[-1], values.String): #    self._memory.strings.reset_temporaries() elif d in tk . END_STATEMENT : break elif d in tk . END_EXPRESSION : # missing operand inside brackets or before comma is syntax error final = False break elif d == b'"' : units . append ( self . read_string_literal ( ins ) ) else : units . append ( self . read_number_literal ( ins ) ) # raises IndexError for insufficient operators try : self . _drain ( 0 , operations , units ) return units [ 0 ] except IndexError : # empty expression is a syntax error (inside brackets) # or Missing Operand (in an assignment) if final : raise error . BASICError ( error . MISSING_OPERAND ) raise error . BASICError ( error . STX )