rev 572 - in trunk: pr/test src

SVN User <[email protected]> Fri, 04 Jun 2004 15:08:42 -0400
Newsgroups gmane.comp.lang.prothon.cvs
Message-ID <[email protected]>
Author: mark
Date: 2004-06-04 15:08:39 -0400 (Fri, 04 Jun 2004)
New Revision: 572

Modified:
   trunk/pr/test/test.pr
   trunk/src/builtins-string.c
   trunk/src/interp.c
Log:
fixed binding permission bug 25

Modified: trunk/pr/test/test.pr
===================================================================
--- trunk/pr/test/test.pr	2004-06-04 18:56:19 UTC (rev 571)
+++ trunk/pr/test/test.pr	2004-06-04 19:08:39 UTC (rev 572)
@@ -1,725 +1,8 @@
 #!/usr/bin/env prothon
 
-"""String format parser"""
+# chiter.pr
+BreakChars = 'abc'
 
-import Re as _re
-/*
-import gettext as _gettext
-import os.path as _path
-try:
-    _MyDir, MyName = _path.split(__file__)
-except:
-    _MyDir = '.'
-_LocalsDir = _path.join(_MyDir, 'locals')
-_TextDomain = 'formatparser'
-_gettext.bindtextdomain(_TextDomain, _LocalsDir)
-_gettext.textdomain(_TextDomain)
-_ = _gettext.gettext
-*/
+ich = BreakChars.iter_().next{}
 
-# Exception types.
-object FPParseError(ParseError):
-    pass
-
-object FPIndexError(IndexError):
-    pass
-
-object FPTypeError(TypeError):
-    pass
-
-object Tokenizer:
-    """Break a string into tokens"""
-
-    def makeFactory(re):
-        pat = _re.compile(re)
-        def Factory(s='', psn=0, next=''):
-            return self(pat, s, psn, next)
-        Factory.regex = re
-        return Factory{}
-
-    def init_(pat, s='', psn=0, next='', end=None):
-        self.pat = pat
-        self.s = s
-        if end is None:
-            self.end = s.len()
-        else:
-            self.end = end
-        self.psn = psn
-        self.next = next
-        self.rejected = False
-
-    def synchronize(other):
-        if not self is other:
-            self.s = other.s
-            self.psn = other.psn
-            self.end = other.end
-            self.next = other.next
-
-    def nextToken():
-        if self.rejected:
-            self.rejected = False
-        elif self.psn < self.end:
-            m = self.pat.search(self.s, self.psn)
-            if m is None:
-                self.next = ''
-                self.psn = self.end
-            else:
-                self.psn = m.end()
-                self.next = self.s[m.start():self.psn]
-
-    def reject():
-        self.rejected = True
-
-    def peekNextCh():
-        if self.psn is not None:
-            try:
-                return self.s[self.psn]
-            except IndexError:
-                self.psn = None
-        return ''
-
-    def skipCh():
-        self.psn += 1
-        
-    def isEnd():
-        return self.psn >= self.end
-
-    def clear():
-        self.next = self.s = ''
-        self.psn = self.end = 0
-
-# Regular expression stuff
-# Please udate the break table if any changes made here.
-#
-# Find specifiers within a format string.
-RegEx = r"[^%]+"
-RootTokenizer = Tokenizer.makeFactory(RegEx)
-
-# Break a specifier into tokens.
-# A tokens is one of:
-# - "'" delimited string
-# - positive integer preceded by '@'
-# - character sequence starting with '%',
-#   not containing break characters or white space,
-#   and optionally ending with '%'
-# - character sequence not containing white space
-#   or break characters
-# - break character
-# Tokens can be any break character,
-# a "'" delimited string, a positive integer
-# preceded by a "@", an name starting with,
-# and optionally ending with, a '%',
-# or any character sequence not containing
-# a break character or whitespace.
-RegEx = (r"'(''|[^'])*'|"  +
-         r"@[0-9]+|"  +
-         r"%[^-\s%(),.@:'!=><+*/]*%?|"  +
-         r"[^-\s%(),.@:'!=><+*/]+|"  +
-         r"==|!=|>=|<=|"  +
-         r"[^\s]"
-         )
-FormatTokenizer = Tokenizer.makeFactory(RegEx)
-del RegEx
-    
-# Reserved characters in a specifier.
-# These form a break table.
-# Please modify the regular expressions if any
-# changes made here.
-BreakChars = r"%(),.@:'!=><+-*/"
-
-ich = BreakChars.iter_()
-Escape = ich.next()       # Marks special names at format level
-ArgListStart = ich.next() # Encloses function arguments
-ArgListEnd = ich.next()
-ArgSep = ich.next()       # Separates function arguments
-AttribRefOp = ich.next()  # References an anttribute
-PositionOp = ich.next()   # Starts a position indentifier
-ExprLitOp = ich.next()    # Leaves an expression unevaluated
-Quote = ich.next()        # Delimits a character string
-# Arithmetic / comparison operator primitives
-NotSign = ich.next()
-EqualSign = ich.next()
-GreaterThanSign = ich.next()
-LessThanSign = ich.next()
-PlusSign = ich.next()
-MinusSign = ich.next()
-TimesSign = ich.next()
-DivideSign = ich.next()
-del ich
-
-# Arithmetic / comparison operators
-EqualOp = EqualSign + EqualSign
-NotEqualOp = NotSign + EqualSign
-GreaterThanOp = GreaterThanSign
-GreaterThanOrEqualOp = GreaterThanSign + EqualSign
-LessThanOp = LessThanSign
-LessThanOrEqualOp = LessThanSign + EqualSign
-AdditionOp = PlusSign
-SubtractionOp = MinusSign
-MultiplicationOp = TimesSign
-DivisionOp = DivideSign
-
-object Node:
-    """Abstract base type for parse tree node"""
-
-    # Abstract methods.
-    def parse(tokens):
-        """Abstract parse method"""
-        raise NameError #, \
-              #"parse required for " + String(type(self))
-
-    def eval(context=None):
-        """Abstract eval method"""
-        # Though most node subclasses implement eval, it is not required.
-        # Catch unintensional calls.
-        raise NameError #, \
-              #"eval not implemented for " + String(type(self))
-    
-object Tree(Node):
-    """Abstract base type for none-leaf nodes"""
-
-    # Default methods.
-    def init_(tokens=None, parts=None):
-        if parts is None:
-            self.parts = []
-        else:
-            self.parts = list(parts)
-        self.parse(tokens)
-
-    def str_():
-        return ''.join([String(p) for p in self.iterParts()])
-
-    def addPart(part):
-        self.parts.append(part)
-
-    def iterParts(psn=0):
-        return iter(self.parts[psn:])
-    
-    def getPart(idx):
-        return self.parts[idx]
-
-    def getParts(start):
-        return self.parts[start:]
-
-object String(Node):
-    """Wrap a string in a node-like object."""
-    def init_(s):
-        self.s = s
-
-    def eval(*args):
-        return self.s
-
-    def str_():
-        return self.s
-
-object QuotedString(String):
-    """A quoted string"""
-    def init_(tokens):
-        super.init_(tokens.next[1:-1].replace(Quote*2, Quote))
-    def str_():
-        return (Quote +
-                super.str_().replace(Quote, Quote*2) +
-                Quote)
-        
-object Keyword(String):
-    """Keyword identifier node-like object"""
-    def init_(s):
-        super.init_(s)
-
-    def eval(context):
-        try:
-            obj = context.getObject(self.s)
-        except IndexError:
-            raise FPIndexError #, \
-                  #fmt(_("Identifier %(s) not found"), s=self.s)
-        return obj
-
-    def getValue():
-        return self.s
-
-    def evalAttribute(obj, context):
-        return context.getAttribute(obj, self.s)
-
-EmptyKeywordInstance = Keyword('')
-
-object IntegerLiteral(Node):
-    """Wrap an integer in a node-like object"""
-    def init_(i):
-        self.i = i
-
-    def eval(*args):
-        return self.i
-
-    def str_():
-        return String(self.i)
-
-object ArgumentPosition(Node):
-    """Argument position node-like object"""
-    def init_(tokens):
-        self.p = int(tokens.next[1:])
-
-    def eval(context):
-        return context.getObjectIdx(self.p)
-
-    def str_():
-        return PositionOp + String(self.p)
-
-def Identifier(tokens):
-    """Return token as a node"""
-    ch = tokens.next[0]
-    if ch == PositionOp:
-        node = ArgumentPosition(tokens)
-    elif ch == Quote:
-        node = QuotedString(tokens)
-    elif ch == Escape:
-        node = Keyword(tokens.next)
-    elif ch in BreakChars:
-        node = EmptyKeywordInstance
-        tokens.reject()
-    else:
-        s = tokens.next
-        try:
-            node = IntegerLiteral(int(s))
-        except ValueError:
-            node = Keyword(s)
-    return node
-
-# Accepts node in parts. Leaves token in next if any.
-object References(Tree):
-    """Reference an identifier"""
-
-    def parse(tokens):
-        while tokens.next == AttribRefOp:
-            tokens.nextToken()
-            if tokens.isEnd():
-                raise FPParseError #, \
-                      #_("Reference missing attribute keyword.")
-            node = Identifier(tokens)
-            if not isinstance(node, Keyword):
-                raise FPParseError #, \
-                      #fmt(_("Require a keyword for attribute name: got '%(n)'"),
-                      #    n=node)
-            if node is EmptyKeywordInstance:
-                raise FPParseError #, \
-                      #_("Require an attribute name: got nothing")
-            tokens.nextToken()
-            if tokens.next == ArgListStart:
-                self.addPart(FunctionCall(tokens, [node]))
-                tokens.nextToken()
-            else:
-                self.addPart(node)
-
-    def eval(context):
-        value = self.getPart(0).eval(context)
-        for attr in self.iterParts(1):
-            value = attr.evalAttribute(value, context)
-        return value
-
-    def str_():
-        return AttribRefOp.join([String(p) for p in self.iterParts()])
-
-object ExpressionClosure:
-    def init_(expr, context):
-        self.expr = expr
-        self.context = context
-
-    def getValue():
-        return self.expr.eval(self.context)
-
-    def str_():
-        return String(self.expr)
-
-# Accepts nothing. Leaves token in next, if any.
-object ExpressionLiteral(Tree):
-    def parse(tokens):
-        tokens.nextToken()
-        if tokens.next == '':
-            raise FPParseError #, \
-                  #_("Expecting an expression after a literal op.: got nothing")
-        self.addPart(QuotedExpression(tokens))
-
-    def eval(context):
-        return ExpressionClosure(self.getPart(0), context) 
-
-    def str_():
-        return ExprLitOp + String(self.getPart(0))
-
-object Negate(Node):
-    def init_(node):
-        self._node = node
-    def eval(context):
-        return context.doMethod(self._node.eval(context), '_minus_')
-    def str_():
-        return '-' + String(self._node)
-    
-# Accepts token in tokens. Leaves token in next, if any.
-def FullIdentifier(tokens):
-    if tokens.next == SubtractionOp:
-        tokens.nextToken()
-        if tokens.next is '':
-            raise FPParseError #, \
-                  #_("Unexpected end-of-negation op.")
-        node = FullIdentifier(tokens)
-        if node is EmptyKeywordInstance:
-            raise FPParseError #, \
-                  #_("Expected identifier after negation op.")
-        node = Negate(node)
-    else:
-        node = Identifier(tokens)
-        tokens.nextToken()
-        if tokens.next == ArgListStart:
-            node = FunctionCall(tokens, [node])
-            tokens.nextToken()
-        if tokens.next == AttribRefOp:
-            node = References(tokens, [node])
-    return node
-
-object BinaryOperator(Node):
-    # To be defined by subclasses
-    Op = ''
-    Method = ''
-    def getNode():
-        raise NameError #, \
-              #("BinaryOperator attribute getNode missing for %s" %
-              # type(self))
-
-    def init_(tokens, left, getNode):
-        if left is EmptyKeywordInstance:
-            raise FPParseError #, \
-                  #fmt(_("Expecting an expression before '%(s)' op."),
-                  #    s=self.Op)
-        self._left = left
-        tokens.nextToken()
-        if tokens.next == '':
-            raise FPParseError #, \
-                  #fmt(_("Unexpected end of '%(s)' expression"),
-                  #    s=self.Op)
-        right = getNode(tokens)
-        if right is EmptyKeywordInstance:
-            raise FPParseError#, \
-                  #fmt(_("Expecting an expression after '%(s)' op."),
-                  #    s=self.Op)
-        self._right = right
-
-    def eval(context):
-        return context.doMethod(self._left.eval(context),
-                                self.Method,
-                                self._right.eval(context))
-
-    def str_():
-        return "%s %s %s" % (self._left, self.Op, self._right)
-    
-object Divide(BinaryOperator):
-    Op = DivisionOp
-    Method = '_div_'
-
-object Multiply(BinaryOperator):
-    Op = MultiplicationOp
-    Method = '_mult_'
-
-# Accepts token in tokens. Leaves token in next, if any.
-def Multiplication(tokens):
-    node = FullIdentifier(tokens)
-    cont = True
-    while cont:
-        if tokens.next == MultiplicationOp:
-            node = Multiply(tokens, node, FullIdentifier)
-        elif tokens.next == DivisionOp:
-            node = Divide(tokens, node, FullIdentifier)
-        else:
-            cont = False
-    return node
-
-object Subtract(BinaryOperator):
-    Op = SubtractionOp
-    Method = '_sub_'
-
-object Add(BinaryOperator):
-    Op = AdditionOp
-    Method = '_add_'
-
-# Accepts token in tokens. Leaves token in next, if any.
-def Addition(tokens):
-    node = Multiplication(tokens)
-    cont = True
-    while cont:
-        if tokens.next == AdditionOp:
-            node = Add(tokens, node, Multiplication)
-        elif tokens.next == SubtractionOp:
-            node = Subtract(tokens, node, Multiplication)
-        else:
-            cont = False
-    return node
-
-object IsLessThanOrEqual(BinaryOperator):
-    Op = LessThanOrEqualOp
-    Method = '_le_'
-
-object IsLessThan(BinaryOperator):
-    Op = LessThanOp
-    Method = '_lt_'
-
-object IsGreaterThanOrEqual(BinaryOperator):
-    Op = GreaterThanOrEqualOp
-    Method = '_ge_'
-
-object IsGreaterThan(BinaryOperator):
-    Op = GreaterThanOp
-    Method = '_gt_'
-
-object IsNotEqual(BinaryOperator):
-    Op = NotEqualOp
-    Method = '_ne_'
-
-# Accepts node; returns token in next.
-object IsEqual(BinaryOperator):
-    Op = EqualOp
-    Method = '_eq_'
-
-# Accepts token in tokens. Leaves token in next, if any.
-def Comparison(tokens):
-    node = Addition(tokens)
-    if tokens.next == EqualOp:
-        node = IsEqual(tokens, node, Addition)
-    elif tokens.next == NotEqualOp:
-        node = IsNotEqual(tokens, node, Addition)
-    elif tokens.next == GreaterThanOp:
-        node = IsGreaterThan(tokens, node, Addition)
-    elif tokens.next == GreaterThanOrEqualOp:
-        node = IsGreaterThanOrEqual(tokens, node, Addition)
-    elif tokens.next == LessThanOp:
-        node = IsLessThan(tokens, node, Addition)
-    elif tokens.next == LessThanOrEqualOp:
-        node = IsLessThanOrEqual(tokens, node, Addition)
-    return node
-
-# Accepts token in tokens. Leaves token in next, if any.
-def QuotedExpression(tokens):
-    """Reference an identifier"""
-    if tokens.next == ExprLitOp:
-        node = ExpressionLiteral(tokens)
-    else:
-        node = Comparison(tokens)
-    return node
-
-# Accepts node in parts; ignores token in tokens;
-# leaves ArgListEnd in tokens.
-object FunctionCall(Tree):
-    """Call a function"""
-    def parse(tokens):
-        if not isinstance(self.getPart(0), Keyword):
-            raise FPParseError #, \
-                  #fmt(_("Function call requires keyword: got %(s)"),
-                  #    s=self.getPart(0))
-        while True:
-            tokens.nextToken()
-            if tokens.next == '':
-                raise FPParseError #, _("Unexpected end of arg. list")
-            node = QuotedExpression(tokens)
-            if not tokens.next:
-                raise FPParseError #, _("Unexpected end of arg. list")
-            if tokens.next == ArgListEnd: # Loop test
-                break
-            if tokens.next == ArgSep:
-                self.addPart(node)
-            else:
-                raise FPParseError #, \
-                      #fmt(_("Unexpected character %(c) in argument list"),
-                      #    c=tokens.next[0])
-        if node is not EmptyKeywordInstance:
-            self.addPart(node)
-    
-    def eval(context):
-        return context.doFunction(self.getPart(0).getValue(),
-                                  *[arg.eval(context) for arg in self.iterParts(1)])
-
-    def evalAttribute(obj, context):
-        return context.doMethod(obj, self.getPart(0).getValue(), 
-                                *[arg.eval(context) for arg in self.iterParts(1)])
-
-    def str_():
-        if self.getPart(-1) is EmptyKeywordInstance:
-            term=ArgSep
-        else:
-            term=''
-        return ("%s(%s%s)" %
-                (String(self.getPart(0)),
-                 ArgSep.join([String(p) for p in self.iterParts(1)]),
-                 term))
-
-SpecifierTokens = FormatTokenizer()  # Share with subtree node
-
-def Specifier(tokens):
-    """Parse a single format specifier"""
-    SpecifierTokens.synchronize(tokens)
-    SpecifierTokens.nextToken()
-    node = Identifier(SpecifierTokens)
-    if SpecifierTokens.next == Escape or SpecifierTokens.next[-1] != Escape:
-        SpecifierTokens.nextToken()
-        if SpecifierTokens.next == ArgListStart:
-            node = FunctionCall(SpecifierTokens, [node])
-        else:
-            raise FPParseError #, "Format specification missing arg. list."
-    tokens.synchronize(SpecifierTokens)
-    return node
-
-gen iterFormat(s):
-    """Iterate over the specifier and non-specifier parts
-       of a format."""
-    tokens = RootTokenizer(s)
-    while not tokens.isEnd():
-        if tokens.peekNextCh() == Escape:
-            yield Specifier(tokens)
-        else:
-            tokens.nextToken()
-            yield String(tokens.next)
-
-object Context:
-    """Execution environment of a specifier"""
-    
-    def init_(next, namedobjs=None, funcs=None, idxobjs=None):
-        self._nxtgetObject = next.getObject
-        if namedobjs is None or namedobjs.len() == 0:  # None or empty map
-            self._namedobjects = None
-            self.getObject = next.getObject
-        else:
-            self._namedobjects = Dict(namedobjs)
-        self._nxtdoFunction = next.doFunction
-        if not funcs: # None or empty map
-            self._functions = None
-            self.doFunction = next.doFunction
-        else:
-            self._functions = Dict(funcs)
-        self._nxtgetObjectIdx = next.getObjectIdx
-        if not idxobjs:
-            self._indexedobjects = None
-            self.getObjectIdx = next.getObjectIdx
-        else:
-            self._indexedobjects = Tuple(idxobjs)
-        self.getAttribute = next.getAttribute
-        self.doMethod = next.doMethod
-
-    # Default context interface methods;
-    # may be overridden by instance versions.
-    def getObject(name):
-        try:
-            obj = self._namedobjects[name]
-        except IndexError:
-            obj = self._nxtgetObject(name)
-        return obj
-
-    def getObjectIdx(idx):
-        try:
-            obj = self._indexedobjects[idx]
-        except IndexError:
-            obj = self._nxtgetObjectIdx(idx)
-        return obj
-    
-    def doFunction(name, *args):
-        try:
-            fn = self._functions[name]
-        except IndexError:
-            return self._nxtdoFunction(name, *args)
-        return fn(*args)
-
-# Foratter for internal user.
-object SimpleFormatter:
-
-    def init_(map=None):
-        self._recurselevel = 0
-        if map is None:
-            self._map = {}
-        else:
-            self._map = dict(map)
-        self._map.update!({Escape: self._doFormat,
-                           '':None,
-                           Escape*2:Escape,
-                           '%sn%s' % (Escape, Escape): '\n'})
-
-    def call_(*args, **kwds):
-        """(fmt, id1=arg1, id2=arg2, ...) ==> string."""
-        if self._recurselevel > 1:
-            # We have a problem.
-            return "fmt: %s\n" +
-                   "args: %s\n" +
-                   "kwds: %s\n" % (repr(args[0]), String(args[1:]), String(kwds))
-        try:
-            fmt = args[0]
-        except IndexError:
-            raise FMTTypeError #, \
-                  #fmt(_("Formatter() takes at least 1 argument (%(n) given)"),
-                  #    n=args.len()
-        try:
-            for idx, arg in enumerate(args[1:]):
-                kwds[idx] = arg
-        except NameError:
-            for idx in args.len()-1:
-                kwds[idx] = args[idx+1]
-#            for idx, arg in zip(range(args.len()-1), args[1:]):
-#                kwds[idx] = arg
-        # Join upgrades to unicode if one of the
-        # sequence items is unicode.
-        context = self.newContext(kwds)
-        self._recurselevel += 1
-        try:
-            return ''.join([f.eval(context) for f in iterFormat(fmt)])
-        finally:
-            self._recurselevel -= 1
-
-    # Context interface.
-    def newContext(namedobjs=None, funcs=None, idxobjs=None):
-        return Context(self, namedobjs, funcs, idxobjs)
-    
-    def getObject(obj):
-        return self._map[obj]
-
-    def getObjectIdx(idx):
-        raise IndexError #, \
-              #fmt(_("Argument index @%(i) out-of-range"), i=idx)
-
-    def getAttribute(obj, attr):
-        if attr == 'type':
-            return type(obj)
-        if attr == 'str':
-            return String(obj)
-        if attr == 'unicode':
-            return unicode(obj)
-        if attr ==  'repr':
-            return repr(obj)
-        raise NameError #, \
-              #fmt(_("Unsupported attribute %(attr)"), attr=attr)
-        return '' # Never gets here
-
-    def doFunction(name, *args):
-        return self._map[name](*args)
-
-    def doMethod(obj, attr, *args):
-        if attr == 'center':
-            if isinstance(obj, unicode):
-                return obj.center(args[0])
-            return String(obj).center(args[0])
-        raise NameError #, \
-              #fmt(_("Unsupported method %(attr)"), attr=attr)
-        return '' # Never gets here
-
-    def close():
-        pass
-    
-    # Formatting function.
-    def _doFormat(obj, width=None, precision=None):
-        s = String(obj)
-        if not precision:
-            if not width:
-                return s
-            return "%*s" % (width, s)
-        if not width:
-            return "%.*s" % (precision, s)
-        return "%*.*s" % (width, precision, s)
-
-object fmt(SimpleFormatter): pass
-fmt.init_()
-
-print "Starting test now"
-print fmt("Version 0.4.3")
-print fmt("The value of pi to %(p) decimal places is %(pi,,p) .",
-          pi=3.141592658, p=4)
\ No newline at end of file
+print ich(), ich(), ich()

Modified: trunk/src/builtins-string.c
===================================================================
--- trunk/src/builtins-string.c	2004-06-04 18:56:19 UTC (rev 571)
+++ trunk/src/builtins-string.c	2004-06-04 19:08:39 UTC (rev 572)
@@ -367,15 +367,6 @@
 	return res;
 }
 
-DEF(String, iter_, NULL) {
-	obj_p gen_obj = NEW_OBJ(StringGen_OBJ);
-	BIN_CONTENT_CHK(String);
-	gen_obj->data_type = DATA_TYPE_DATAPTR;
-	gen_obj->data.ptr = pr_strptr(self);
-	set_attr(ist, gen_obj, sym(ist, "saved_string"), self);
-	return gen_obj;
-}
-
 DEF(String, ord, NULL) {
 	BIN_CONTENT_CHK(String);
 	return NEW_INT((int)(*pr_strptr(self)));
@@ -732,6 +723,17 @@
 	return list_obj;
 }
 
+DEF(String, iter_, NULL) {
+	obj_p gen_obj;
+	BIN_CONTENT_CHK(String);
+	gen_obj = NEW_OBJ(StringGen_OBJ);
+	gen_obj->data_type = DATA_TYPE_DATAPTR;
+	gen_obj->data.ptr = pr_strptr(self);
+	set_attr(ist, gen_obj, sym(ist, "savedString"), self);
+	return gen_obj;
+}
+
+
 DEF(String, cDataLen_, NULL) {
 	BIN_CONTENT_CHK(String);
 	return NEW_INT(sizeof(pr_str_t) + pr_strlen(self) + 1);

Modified: trunk/src/interp.c
===================================================================
--- trunk/src/interp.c	2004-06-04 18:56:19 UTC (rev 571)
+++ trunk/src/interp.c	2004-06-04 19:08:39 UTC (rev 572)
@@ -1172,7 +1172,10 @@
 				if (!(bindee = fr_stack[fr_sp+2])) bindee = fr_stack[fr_sp];
 				obj = get_item(ist, fr_stack[fr_sp], fr_stack[fr_sp+1]); IF_EXC_BREAK;
 				bound_meth = copy_object(ist, obj);
-				set_attr(ist, bound_meth, SYM(BINDOBJ_), bindee); IF_EXC_BREAK;
+				su(i);
+				set_attr(ist, bound_meth, SYM(BINDOBJ_), bindee); 
+				un_su(i);
+				IF_EXC_BREAK;
 				fr_push(bound_meth);
 			}	break;
 			case OP_OBJCALL: {