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