Permalink
Browse files

objects/user: Add "quiet" no-closure objects.

  • Loading branch information...
MostAwesomeDude committed Oct 11, 2015
1 parent 10ed13f commit c41e108bf09e82391763e6a230317b82ddb1c851
Showing with 123 additions and 37 deletions.
  1. +13 −3 typhon/nodes.py
  2. +6 −3 typhon/objects/iteration.py
  3. +104 −31 typhon/objects/user.py
View
@@ -19,6 +19,7 @@
from rpython.rlib import rvmprof
from rpython.rlib.jit import elidable, elidable_promote, look_inside_iff
from rpython.rlib.listsort import make_timsort_class
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rbigint import BASE10
from typhon.atoms import getAtom
@@ -33,7 +34,7 @@
from typhon.objects.ejectors import throw
from typhon.objects.meta import MetaContext
from typhon.objects.root import Object
from typhon.objects.user import Audition, ScriptObject
from typhon.objects.user import Audition, BusyObject, QuietObject
from typhon.pretty import Buffer, LineWriter
from typhon.smallcaps.code import Code
from typhon.smallcaps.ops import ops
@@ -202,6 +203,7 @@ def makeCode(self):
def canCloseOver(self, name):
return name in self.frame or name in self.availableClosure
@specialize.arg(1)
def addInstruction(self, name, index):
self.instructions.append((ops[name], index))
@@ -244,6 +246,7 @@ def callMap(self, verb, arity, lenNamedArgs):
self.addInstruction("BUILD_MAP", lenNamedArgs)
self.addInstruction("CALL_MAP", atom)
@specialize.arg(1)
def markInstruction(self, name):
index = len(self.instructions)
self.addInstruction(name, 0)
@@ -1663,6 +1666,9 @@ def compile(self, compiler):
elif isinstance(self._n, FinalPattern):
slotIndex = compiler.locals.add(self._n._n)
compiler.addInstruction("BINDFINALSLOT", slotIndex)
else:
# Bail!?
assert False, "Shouldn't happen"
def getStaticScope(self):
scope = self._n.getStaticScope()
@@ -1730,8 +1736,12 @@ def __init__(self, displayName, objectAst, numAuditors, availableClosure,
self.auditions = {}
def makeObject(self, closure, globals, auditors):
obj = ScriptObject(self, globals, closure, self.displayName, auditors,
self.fqn)
if len(self.closureNames):
obj = BusyObject(self, globals, closure, self.displayName, auditors,
self.fqn)
else:
obj = QuietObject(self, globals, self.displayName, auditors,
self.fqn)
return obj
# Picking 3 for the common case of:
@@ -21,7 +21,7 @@
from typhon.objects.constants import NullObject
from typhon.objects.ejectors import Ejector
from typhon.objects.root import runnable
from typhon.objects.user import ScriptObject
from typhon.objects.user import BusyObject, ScriptObject
from typhon.smallcaps.machine import SmallCaps
@@ -87,8 +87,11 @@ def loop(args):
# JIT merge point.
loopDriver.jit_merge_point(code=code, consumer=consumer,
ejector=ej, iterator=iterator)
machine = SmallCaps(code, consumer.closure,
promote(consumer.globals))
globals = promote(consumer.globals)
if isinstance(consumer, BusyObject):
machine = SmallCaps(code, consumer.closure, globals)
else:
machine = SmallCaps(code, None, globals)
values = unwrapList(iterator.call(u"next", [ej]))
# Push the arguments onto the stack, backwards.
values.reverse()
View
@@ -149,9 +149,111 @@ def recv(self, atom, args):
class ScriptObject(Object):
"""
An object whose behavior depends on a Monte script.
"""
_immutable_fields_ = ("codeScript", "displayName", "globals[*]",
"closure[*]", "fqn")
_immutable_fields_ = "codeScript", "displayName", "globals[*]", "fqn"
def toString(self):
# Easily the worst part of the entire stringifying experience. We must
# be careful to not recurse here.
try:
printer = Printer()
self.call(u"_printOn", [printer])
return printer.value()
except Refused:
return u"<%s>" % self.displayName
except UserException, e:
return u"<%s (threw exception %s when printed)>" % (self.displayName, e.error())
def printOn(self, printer):
# Note that the printer is a Monte-level object. Also note that, at
# this point, we have had a bad day; we did not respond to _printOn/1.
from typhon.objects.data import StrObject
printer.call(u"print", [StrObject(u"<%s>" % self.displayName)])
def docString(self):
return self.codeScript.doc
def respondingAtoms(self):
# Only do methods for now. Matchers will be dealt with in other ways.
d = {}
for atom in self.codeScript.methods.keys():
d[atom] = self.codeScript.methodDocs.get(atom, None)
return d
class QuietObject(ScriptObject):
"""
An object without a closure.
"""
def __init__(self, codeScript, globals, displayName, auditors, fqn):
self.codeScript = codeScript
self.globals = globals
self.displayName = displayName
self.fqn = fqn
# The first auditor is our as-auditor, and it can be null.
if auditors[0] is NullObject:
auditors = auditors[1:]
# Grab the guards of our globals and send them off for processing.
guards = self.getGuards()
self.stamps = self.codeScript.audit(auditors, guards)[:]
def getGuards(self):
guards = {}
for name, i in self.codeScript.globalNames.items():
guards[name] = self.globals[i].call(u"getGuard", [])
return guards
@unroll_safe
def recvNamed(self, atom, args, namedArgs):
code = self.codeScript.lookupMethod(atom)
if code is None:
# No atoms matched, so there's no prebuilt methods. Instead, we'll
# use our matchers.
for matcher in self.codeScript.matchers:
with Ejector() as ej:
machine = SmallCaps(matcher, None, self.globals)
machine.push(ConstList([StrObject(atom.verb),
ConstList(args), namedArgs]))
machine.push(ej)
try:
machine.run()
return machine.pop()
except Ejecting as e:
if e.ejector is ej:
# Looks like unification failed. On to the next
# matcher!
continue
else:
# It's not ours, cap'n.
raise
raise Refused(self, atom, args)
machine = SmallCaps(code, None, self.globals)
# print "--- Running", self.displayName, atom, args
# Push the arguments onto the stack, backwards.
machine.push(namedArgs)
for arg in reversed(args):
machine.push(arg)
machine.push(NullObject)
machine.push(namedArgs)
machine.run()
return machine.pop()
class BusyObject(ScriptObject):
"""
An object with a closure.
"""
_immutable_fields_ = "closure[*]",
def __init__(self, codeScript, globals, closure, displayName, auditors,
fqn):
@@ -186,35 +288,6 @@ def patchSelf(self, guard):
if selfIndex != -1:
self.closure[selfIndex] = FinalBinding(self, guard)
def toString(self):
# Easily the worst part of the entire stringifying experience. We must
# be careful to not recurse here.
try:
printer = Printer()
self.call(u"_printOn", [printer])
return printer.value()
except Refused:
return u"<%s>" % self.displayName
except UserException, e:
return u"<%s (threw exception %s when printed)>" % (self.displayName, e.error())
def printOn(self, printer):
# Note that the printer is a Monte-level object. Also note that, at
# this point, we have had a bad day; we did not respond to _printOn/1.
from typhon.objects.data import StrObject
printer.call(u"print", [StrObject(u"<%s>" % self.displayName)])
def docString(self):
return self.codeScript.doc
def respondingAtoms(self):
# Only do methods for now. Matchers will be dealt with in other ways.
d = {}
for atom in self.codeScript.methods.keys():
d[atom] = self.codeScript.methodDocs.get(atom, None)
return d
@unroll_safe
def recvNamed(self, atom, args, namedArgs):
code = self.codeScript.lookupMethod(atom)

0 comments on commit c41e108

Please sign in to comment.