Permalink
Browse files

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

  • Loading branch information...
1 parent 10ed13f commit c41e108bf09e82391763e6a230317b82ddb1c851 @MostAwesomeDude MostAwesomeDude committed Oct 11, 2015
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.