implement garbage collection
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
from simpleparser import parse
|
||||
from objspace import ObjectSpace
|
||||
import compile
|
||||
from disass import disassemble
|
||||
|
||||
import compile
|
||||
from objspace import ObjectSpace
|
||||
|
||||
|
||||
class ByteCodeError(Exception):
|
||||
pass
|
||||
@ -46,7 +46,6 @@ class Interpreter(object):
|
||||
w_condition = stack.pop()
|
||||
if self.space.isfalse(w_condition):
|
||||
pc += oparg
|
||||
continue
|
||||
elif compile.hasarg(opcode):
|
||||
oparg = ord(code[pc])
|
||||
pc += 1
|
||||
@ -62,20 +61,24 @@ class Interpreter(object):
|
||||
stack.append(obj)
|
||||
elif opcode == compile.MAKE_OBJECT_CALL:
|
||||
self.run(bytecode.subbytecodes[oparg], stack[-1])
|
||||
|
||||
# Project -----
|
||||
elif opcode == compile.INT_LITERAL:
|
||||
w_value = self.space.newint(oparg)
|
||||
stack.append(w_value)
|
||||
elif opcode == compile.BOOL_LITERAL: # Project: Boolean
|
||||
elif opcode == compile.BOOL_LITERAL:
|
||||
w_value = self.space.newbool(oparg) # oparg is 1 or 0
|
||||
stack.append(w_value)
|
||||
elif opcode == compile.STRING_LITERAL: # Project: String
|
||||
elif opcode == compile.STRING_LITERAL:
|
||||
value = bytecode.symbols[oparg]
|
||||
w_value = self.space.newstring(value)
|
||||
stack.append(w_value)
|
||||
elif opcode == compile.DOUBLE_LITERAL: # Project: Double
|
||||
elif opcode == compile.DOUBLE_LITERAL:
|
||||
value = bytecode.symbols[oparg]
|
||||
w_value = self.space.newdouble(value)
|
||||
stack.append(w_value)
|
||||
# -------------
|
||||
|
||||
elif opcode == compile.MAKE_FUNCTION:
|
||||
bc = bytecode.subbytecodes[oparg]
|
||||
w_method = self.space.definemethod(name=bc.name, code=bc, w_target=w_context)
|
||||
@ -85,7 +88,7 @@ class Interpreter(object):
|
||||
w_method = self.space.getvalue(stack[-1], name)
|
||||
stack.append(w_method)
|
||||
elif opcode == compile.METHOD_CALL:
|
||||
arguments_w = [stack.pop() for n in range(oparg)]
|
||||
arguments_w = [stack.pop() for _ in range(oparg)]
|
||||
arguments_w.reverse()
|
||||
#
|
||||
w_method = stack.pop()
|
||||
@ -94,7 +97,7 @@ class Interpreter(object):
|
||||
stack.append(w_result)
|
||||
elif opcode == compile.PRIMITIVE_METHOD_CALL:
|
||||
nargs = self.space.get_number_of_arguments_of_primitive(oparg)
|
||||
arguments_w = [stack.pop() for n in range(nargs)]
|
||||
arguments_w = [stack.pop() for _ in range(nargs)]
|
||||
arguments_w.reverse()
|
||||
w_receiver = stack.pop()
|
||||
w_result = self.space.call_primitive(oparg, w_receiver, arguments_w)
|
||||
@ -126,6 +129,11 @@ class Interpreter(object):
|
||||
stack.append(w_context)
|
||||
elif opcode == compile.DUP:
|
||||
stack.append(stack[-1])
|
||||
|
||||
# Project
|
||||
elif opcode == compile.GC:
|
||||
self.space.gc(w_context)
|
||||
|
||||
else:
|
||||
raise ByteCodeError('Invalid bytecode')
|
||||
assert pc == len(code)
|
||||
|
@ -109,10 +109,10 @@ import simpleast
|
||||
|
||||
# ---------- bytecodes ----------
|
||||
|
||||
BOOL_LITERAL = 1 # 1 or 0 # Project: Boolean
|
||||
BOOL_LITERAL = 1 # 1 or 0
|
||||
INT_LITERAL = 2 # integer value
|
||||
STRING_LITERAL = 3 # Project: String
|
||||
DOUBLE_LITERAL = 17 # Project: Double
|
||||
STRING_LITERAL = 3
|
||||
DOUBLE_LITERAL = 17
|
||||
ASSIGNMENT = 4 # index of attrname
|
||||
METHOD_LOOKUP = 5 # index of method name
|
||||
METHOD_CALL = 6 # number of arguments
|
||||
@ -129,6 +129,7 @@ SET_LOCAL = 16 # index of attrname (optimization)
|
||||
IMPLICIT_SELF = 32 # (no argument)
|
||||
POP = 33 # (no argument)
|
||||
DUP = 34 # (no argument)
|
||||
GC = 35 # (no argument)
|
||||
|
||||
opcode_names = [None] * 256
|
||||
for key, value in list(globals().items()):
|
||||
@ -191,9 +192,9 @@ def compile(ast, argumentnames=[], name=None):
|
||||
|
||||
|
||||
stack_effects = {
|
||||
BOOL_LITERAL: 1, # Project: Boolean
|
||||
STRING_LITERAL: 1, # Project: String
|
||||
DOUBLE_LITERAL: 1, # Project: Double
|
||||
BOOL_LITERAL: 1,
|
||||
STRING_LITERAL: 1,
|
||||
DOUBLE_LITERAL: 1,
|
||||
INT_LITERAL: 1,
|
||||
ASSIGNMENT: -1,
|
||||
METHOD_LOOKUP: 1,
|
||||
@ -208,6 +209,7 @@ stack_effects = {
|
||||
IMPLICIT_SELF: 1,
|
||||
POP: -1,
|
||||
DUP: 1,
|
||||
GC: 0,
|
||||
}
|
||||
|
||||
|
||||
@ -257,6 +259,7 @@ class Compiler(object):
|
||||
stackeffect = stack_effects[opcode]
|
||||
else:
|
||||
assert stackeffect != sys.maxsize
|
||||
|
||||
self.stack_effect(stackeffect)
|
||||
|
||||
def get_position(self):
|
||||
@ -289,18 +292,24 @@ class Compiler(object):
|
||||
def compile_IntLiteral(self, astnode, needsresult):
|
||||
self.emit(INT_LITERAL, astnode.value)
|
||||
|
||||
# Project: Boolean
|
||||
# Project -----
|
||||
def compile_BooleanLiteral(self, astnode, needsresult):
|
||||
self.emit(BOOL_LITERAL, astnode.value)
|
||||
|
||||
# Project: String
|
||||
def compile_StringLiteral(self, astnode, needsresult):
|
||||
self.emit(STRING_LITERAL, self.lookup_symbol(astnode.value)) # save string value to symboltable
|
||||
|
||||
# Project: Double
|
||||
def compile_DoubleLiteral(self, astnode, needsresult):
|
||||
self.emit(DOUBLE_LITERAL, self.lookup_symbol(astnode.value))
|
||||
|
||||
def compile_GCStatement(self, astnode, needsresult):
|
||||
self.emit(GC)
|
||||
|
||||
if needsresult:
|
||||
self.emit(BOOL_LITERAL, True)
|
||||
|
||||
# -------------
|
||||
|
||||
def compile_ImplicitSelf(self, astnode, needsresult):
|
||||
self.emit(IMPLICIT_SELF)
|
||||
|
||||
@ -370,7 +379,7 @@ class Compiler(object):
|
||||
for statement in astnode.statements[:-1]:
|
||||
self.compile(statement, needsresult=False)
|
||||
laststatement = astnode.statements[-1]
|
||||
self.compile(laststatement, needsresult)
|
||||
self.compile(laststatement, needsresult) # return last result
|
||||
|
||||
def compile_FunctionDefinition(self, astnode, needsresult):
|
||||
bytecode = compile(astnode.block, astnode.arguments, astnode.name)
|
||||
|
18
de.churl.simple/garbagecollection.py
Normal file
18
de.churl.simple/garbagecollection.py
Normal file
@ -0,0 +1,18 @@
|
||||
def mark(w_context):
|
||||
w_context.mark = True
|
||||
|
||||
if not hasattr(w_context, "slots"): # skip primitive objects
|
||||
return
|
||||
|
||||
for name, obj in w_context.slots.items():
|
||||
if name != "__parent__": # only descent
|
||||
mark(obj)
|
||||
|
||||
|
||||
def sweep(objects):
|
||||
objects[:] = filter(lambda obj: obj.mark, objects) # inplace
|
||||
|
||||
|
||||
def clear_marks(objects):
|
||||
for obj in objects:
|
||||
obj.mark = False
|
@ -2,6 +2,9 @@ from c3computation import compute_C3_mro as c3
|
||||
|
||||
|
||||
class AbstractObject(object):
|
||||
def __init__(self):
|
||||
self.mark = False # gc marker
|
||||
|
||||
def call(self, w_receiver, args_w):
|
||||
return self
|
||||
|
||||
@ -24,30 +27,9 @@ class AbstractObject(object):
|
||||
return c3(self)
|
||||
|
||||
|
||||
class PrimitiveObject(AbstractObject):
|
||||
def __init__(self, value, trait, space=None):
|
||||
self.value = value
|
||||
self._trait = trait
|
||||
self.space = space
|
||||
|
||||
def getparents(self):
|
||||
if self.space is None:
|
||||
return [] # for tests
|
||||
trait = self.space.getbuiltin(self._trait)
|
||||
assert trait is not None, 'O_o bogus state'
|
||||
return [trait]
|
||||
|
||||
def hasslot(self, name):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
class W_NormalObject(AbstractObject):
|
||||
def __init__(self, name=None, slots=None, parents=None, space=None):
|
||||
super().__init__()
|
||||
self.space = space
|
||||
self.name = name
|
||||
if slots:
|
||||
@ -93,44 +75,59 @@ class W_NormalObject(AbstractObject):
|
||||
slots=self.slots.copy())
|
||||
|
||||
|
||||
class W_Integer(PrimitiveObject):
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(int(value), "inttrait", space)
|
||||
# Project -----
|
||||
class PrimitiveObject(AbstractObject):
|
||||
def __init__(self, value, trait, space=None):
|
||||
super().__init__()
|
||||
self.value = value
|
||||
self._trait = trait
|
||||
self.space = space
|
||||
|
||||
def istrue(self):
|
||||
return self.value != 0
|
||||
def getparents(self):
|
||||
if self.space is None:
|
||||
return [] # for tests
|
||||
trait = self.space.getbuiltin(self._trait)
|
||||
assert trait is not None, 'O_o bogus state'
|
||||
return [trait]
|
||||
|
||||
|
||||
# Project: Boolean
|
||||
class W_Boolean(PrimitiveObject): # don't know if extending is good idea
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(int(value), "booltrait", space=space)
|
||||
def hasslot(self, name):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return str(bool(self.value))
|
||||
return str(self.value)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
def istrue(self):
|
||||
return self.value != 0
|
||||
return bool(self.value)
|
||||
|
||||
|
||||
class W_Integer(PrimitiveObject):
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(int(value), "inttrait", space)
|
||||
|
||||
|
||||
class W_Boolean(PrimitiveObject):
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(int(value), "booltrait", space=space)
|
||||
|
||||
def __str__(self):
|
||||
return str(bool(self.value)) # true instead of 1
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
# Project: String
|
||||
class W_String(PrimitiveObject):
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(str(value), "strtrait", space)
|
||||
|
||||
def istrue(self):
|
||||
return self.value != ""
|
||||
|
||||
|
||||
# Project: Double
|
||||
class W_Double(PrimitiveObject):
|
||||
def __init__(self, value, space=None):
|
||||
super().__init__(float(value), "doubletrait", space)
|
||||
|
||||
def istrue(self):
|
||||
return self.value != 0.
|
||||
|
||||
# -------------
|
||||
|
||||
|
||||
class W_Method(W_NormalObject):
|
||||
|
@ -1,14 +1,15 @@
|
||||
import primitives
|
||||
from garbagecollection import mark, sweep, clear_marks
|
||||
from objmodel import W_Integer, W_Boolean, W_String, W_Double
|
||||
from objmodel import W_Method
|
||||
from objmodel import W_NormalObject
|
||||
|
||||
import primitives
|
||||
|
||||
|
||||
class ObjectSpace(object):
|
||||
|
||||
def __init__(self, interpreter):
|
||||
self.interpreter = interpreter
|
||||
self.objects = []
|
||||
|
||||
def setup_builtins(self, builtincode=None):
|
||||
if builtincode is None:
|
||||
@ -20,6 +21,7 @@ class ObjectSpace(object):
|
||||
ast = parse(builtincode)
|
||||
|
||||
self.interpreter.eval(ast, w_builtins)
|
||||
self.objects.clear() # remove all builtins, lobby from list
|
||||
|
||||
def _load_default_builtins(self):
|
||||
import os
|
||||
@ -40,32 +42,43 @@ class ObjectSpace(object):
|
||||
slots = {}
|
||||
else:
|
||||
slots = {'__parent__': self.getbuiltins()}
|
||||
return W_NormalObject(name=name, slots=slots)
|
||||
|
||||
return W_NormalObject(name=name, slots=slots) # lobby isn't collected
|
||||
|
||||
def newobject(self, name, slots, parentnames):
|
||||
return W_NormalObject(space=self, name=name,
|
||||
slots=slots, parents=parentnames)
|
||||
self.objects.append(W_NormalObject(space=self, name=name,
|
||||
slots=slots, parents=parentnames))
|
||||
return self.objects[-1]
|
||||
|
||||
# Project -----
|
||||
def newint(self, value):
|
||||
return W_Integer(value, space=self)
|
||||
self.objects.append(W_Integer(value, space=self))
|
||||
return self.objects[-1]
|
||||
|
||||
# Project: Boolean
|
||||
def newbool(self, value):
|
||||
return W_Boolean(value, space=self)
|
||||
self.objects.append(W_Boolean(value, space=self))
|
||||
return self.objects[-1]
|
||||
|
||||
# Project: String
|
||||
def newstring(self, value):
|
||||
return W_String(value, space=self)
|
||||
self.objects.append(W_String(value, space=self))
|
||||
return self.objects[-1]
|
||||
|
||||
# Project: Double
|
||||
def newdouble(self, value):
|
||||
return W_Double(value, space=self)
|
||||
self.objects.append(W_Double(value, space=self))
|
||||
return self.objects[-1]
|
||||
|
||||
def gc(self, w_context):
|
||||
clear_marks(self.objects)
|
||||
mark(w_context)
|
||||
sweep(self.objects)
|
||||
|
||||
# -------------
|
||||
|
||||
def definemethod(self, name, code, w_target):
|
||||
w_meth = W_Method(code, name=name,
|
||||
slots={'__parent__': w_target},
|
||||
space=self)
|
||||
return w_meth
|
||||
self.objects.append(W_Method(code, name=name,
|
||||
slots={'__parent__': w_target},
|
||||
space=self))
|
||||
return self.objects[-1]
|
||||
|
||||
def execute(self, code, w_context):
|
||||
return self.interpreter.run(code, w_context)
|
||||
|
@ -93,7 +93,7 @@ class IntLiteral(Expression):
|
||||
self.value = int(value)
|
||||
|
||||
|
||||
# Project: Boolean
|
||||
# Project -----
|
||||
class BooleanLiteral(Expression):
|
||||
""" A boolean literal (like "false") """
|
||||
|
||||
@ -103,7 +103,6 @@ class BooleanLiteral(Expression):
|
||||
self.value = value == "true"
|
||||
|
||||
|
||||
# Project: String
|
||||
class StringLiteral(Expression):
|
||||
""" A string literal (like "hello world") """
|
||||
|
||||
@ -113,7 +112,6 @@ class StringLiteral(Expression):
|
||||
self.value = str(value)
|
||||
|
||||
|
||||
# Project: Double
|
||||
class DoubleLiteral(Expression):
|
||||
""" A double literal (like "1.0", ".0", "1.", "+1.0") """
|
||||
|
||||
@ -123,6 +121,9 @@ class DoubleLiteral(Expression):
|
||||
self.value = float(value)
|
||||
|
||||
|
||||
# -------------
|
||||
|
||||
|
||||
class MethodCall(Expression):
|
||||
""" A call to a method with name 'methodname' on 'receiver' with
|
||||
'arguments' (which is a list of expression ASTs).
|
||||
@ -172,6 +173,11 @@ class Statement(AstNode):
|
||||
""" Base class of all statement nodes. """
|
||||
|
||||
|
||||
# Project
|
||||
class GCStatement(Statement):
|
||||
""" Triggers Garbage Collection """
|
||||
|
||||
|
||||
class Assignment(Statement):
|
||||
""" An assignement: lvalue attrname = expression.
|
||||
|
||||
|
@ -158,7 +158,7 @@ OpenBracket = r'[\[\(\{]'
|
||||
CloseBracket = r'[\]\)\}]'
|
||||
|
||||
# ____________________________________________________________
|
||||
# Project: Boolean, String, Double
|
||||
# Project
|
||||
|
||||
Boolean = r"true|false"
|
||||
String = group(make_single_string(r"\'"), make_single_string(r'\"'))
|
||||
@ -166,11 +166,8 @@ String = group(make_single_string(r"\'"), make_single_string(r'\"'))
|
||||
_sign = r"([+-])?"
|
||||
_int = r"(([1-9][0-9]*)|0)"
|
||||
_dec = r"(([0-9]*[1-9])|0)"
|
||||
Double = group(_sign + group(_int, r"") + r"\." + _dec,
|
||||
_sign + _int + r"\." + group(_dec, r""))
|
||||
|
||||
# ____________________________________________________________
|
||||
# Project: Sugar
|
||||
Double = group(_sign + group(_int, r"") + r"\." + _dec, # 0.1 / .1
|
||||
_sign + _int + r"\." + group(_dec, r"")) # 1.0 / 1.
|
||||
|
||||
Plus = r'\+'
|
||||
Minus = r'-'
|
||||
@ -179,6 +176,8 @@ Divide = r'/'
|
||||
Increment = r'\+\+'
|
||||
Modulo = r'%'
|
||||
|
||||
GC = r'gc'
|
||||
|
||||
# ____________________________________________________________
|
||||
# Keywords
|
||||
|
||||
@ -189,10 +188,11 @@ Def = r'def'
|
||||
Object = r'object'
|
||||
|
||||
tokens = ["If", "Else", "While", "Def", "Object", "Ignore",
|
||||
"String", "Boolean", "Double", # Project: Boolean, String, Double
|
||||
"String", "Boolean", "Double",
|
||||
"Number", # after Double
|
||||
"GC",
|
||||
"NewlineAndWhitespace", "OpenBracket", "CloseBracket", "Comma", "Assign", "Colon",
|
||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo",
|
||||
"Name", "PrimitiveName"]
|
||||
|
||||
|
||||
|
@ -6,10 +6,11 @@ from simplelexer import lex
|
||||
import simpleast
|
||||
|
||||
pg = ParserGenerator(["If", "Else", "While", "Def", "Object", "Number",
|
||||
"String", "Boolean", "Double", # Project: Boolean, String, Double
|
||||
"String", "Boolean", "Double",
|
||||
"GC",
|
||||
"Name", "Indent", "Dedent", "Newline", "OpenBracket",
|
||||
"CloseBracket", "Comma", "Assign", "Colon",
|
||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo",
|
||||
"PrimitiveName", "EOF"],
|
||||
# Operator precedence for ambiguous rules, ascending
|
||||
precedence=[("left", ["Plus", "Minus"]),
|
||||
@ -63,6 +64,12 @@ def newlines(n):
|
||||
return None
|
||||
|
||||
|
||||
@pg.production("statement : GC newlines")
|
||||
@pg.production("statement : GC")
|
||||
def gcstatement(stmt):
|
||||
return simpleast.GCStatement()
|
||||
|
||||
|
||||
@pg.production("statement : simplestatement")
|
||||
@pg.production("statement : ifstatement")
|
||||
@pg.production("statement : whilestatement")
|
||||
@ -198,19 +205,16 @@ def number_expression(stmt):
|
||||
return simpleast.IntLiteral(stmt[0].value)
|
||||
|
||||
|
||||
# Project: Boolean
|
||||
@pg.production("basic_expression : Boolean")
|
||||
def boolean_expression(stmt):
|
||||
return simpleast.BooleanLiteral(stmt[0].value)
|
||||
|
||||
|
||||
# Project: String
|
||||
@pg.production("basic_expression : String")
|
||||
def string_expression(stmt):
|
||||
return simpleast.StringLiteral(stmt[0].value[1:-1]) # cut off delimiters
|
||||
|
||||
|
||||
# Project: Double
|
||||
@pg.production("basic_expression : Double")
|
||||
def double_expression(stmt):
|
||||
return simpleast.DoubleLiteral(stmt[0].value)
|
||||
|
@ -4,33 +4,36 @@ from interpreter import Interpreter
|
||||
|
||||
def test_reassignment_gc():
|
||||
ast = parse("""
|
||||
true
|
||||
x = 2
|
||||
y = 3
|
||||
""")
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc(w_model)
|
||||
|
||||
x = w_model.getvalue("x")
|
||||
y = w_model.getvalue("y")
|
||||
assert x in interpreter.space.realm # Wo alle Objekte leben
|
||||
assert y in interpreter.space.realm
|
||||
assert x in interpreter.space.objects
|
||||
assert y in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
x = y
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc()
|
||||
assert x not in interpreter.space.realm
|
||||
assert y in interpreter.space.realm
|
||||
interpreter.space.gc(w_model)
|
||||
assert x not in interpreter.space.objects
|
||||
assert y in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
x = 0
|
||||
y = 0
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc()
|
||||
assert x not in interpreter.space.realm
|
||||
assert y not in interpreter.space.realm
|
||||
interpreter.space.gc(w_model)
|
||||
assert x not in interpreter.space.objects
|
||||
assert y not in interpreter.space.objects
|
||||
|
||||
|
||||
def test_chain_gc():
|
||||
@ -42,40 +45,25 @@ z = y
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc(w_model)
|
||||
|
||||
x = w_model.getvalue("x")
|
||||
assert x in interpreter.space.realm
|
||||
assert x in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
x = 0
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc()
|
||||
assert x in interpreter.space.realm
|
||||
interpreter.space.gc(w_model)
|
||||
assert x in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
y = x
|
||||
z = y
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc()
|
||||
assert x not in interpreter.space.realm
|
||||
|
||||
|
||||
def test_while_gc():
|
||||
ast = parse("""
|
||||
x = 10
|
||||
while x:
|
||||
x = x $int_add(-1)
|
||||
""")
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
|
||||
count = len(interpreter.space.realm)
|
||||
interpreter.space.gc()
|
||||
|
||||
assert count - len(interpreter.space.realm) == 10
|
||||
interpreter.space.gc(w_model)
|
||||
assert x not in interpreter.space.objects
|
||||
|
||||
|
||||
def test_object_gc():
|
||||
@ -88,19 +76,76 @@ object x:
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc(w_model)
|
||||
|
||||
a = w_model.getvalue("x").getvalue("a")
|
||||
b = w_model.getvalue("x").getvalue("b")
|
||||
c = w_model.getvalue("x").getvalue("c")
|
||||
assert a in interpreter.space.realm
|
||||
assert b in interpreter.space.realm
|
||||
assert c in interpreter.space.realm
|
||||
x = w_model.getvalue("x")
|
||||
assert a in interpreter.space.objects
|
||||
assert b in interpreter.space.objects
|
||||
assert c in interpreter.space.objects
|
||||
assert x in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
x = 0
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc()
|
||||
assert a not in interpreter.space.realm
|
||||
assert b not in interpreter.space.realm
|
||||
assert c not in interpreter.space.realm
|
||||
interpreter.space.gc(w_model)
|
||||
assert a not in interpreter.space.objects
|
||||
assert b not in interpreter.space.objects
|
||||
assert c not in interpreter.space.objects
|
||||
assert x not in interpreter.space.objects
|
||||
|
||||
|
||||
def test_method_gc():
|
||||
ast = parse("""
|
||||
def meth:
|
||||
1
|
||||
""")
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
interpreter.space.gc(w_model)
|
||||
|
||||
meth = w_model.getvalue("meth")
|
||||
assert meth in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
def meth:
|
||||
2
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
|
||||
assert meth in interpreter.space.objects
|
||||
|
||||
interpreter.space.gc(w_model)
|
||||
|
||||
assert meth not in interpreter.space.objects
|
||||
|
||||
|
||||
def test_simple_call_gc():
|
||||
ast = parse("""
|
||||
x = 1
|
||||
gc
|
||||
""")
|
||||
interpreter = Interpreter()
|
||||
w_model = interpreter.make_module()
|
||||
interpreter.eval(ast, w_model)
|
||||
|
||||
x = w_model.getvalue("x")
|
||||
assert x in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
x = 2
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
|
||||
assert x in interpreter.space.objects
|
||||
|
||||
ast = parse("""
|
||||
gc
|
||||
""")
|
||||
interpreter.eval(ast, w_model)
|
||||
|
||||
assert x not in interpreter.space.objects
|
||||
|
Reference in New Issue
Block a user