Skip to content

Instantly share code, notes, and snippets.

@eleses
Created March 8, 2020 06:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eleses/3e34af40443a7faab5d8f08a3d251ff3 to your computer and use it in GitHub Desktop.
Save eleses/3e34af40443a7faab5d8f08a3d251ff3 to your computer and use it in GitHub Desktop.
Fixing the user-supplied cleanup function behavior in Pproto (working draft; there's an inherited "double cleanup.exit" bug unresolved)
PprotoU : Pattern {
var <>makeFunction, <>pattern, <>userCleanupFunc; // distinguish from the combo one we'll generate
*new { | makeFunction, pattern, cleanupFunc|
^super.newCopyArgs( makeFunction, pattern, cleanupFunc)
}
storeArgs { ^[makeFunction,pattern,userCleanupFunc] }
embedInStream { | event |
var stream, ev, evType;
var cleanup, cleanupList, eventCleanupFunc, comboCleanupFunc;
var proto; // temporary proto event used in allocation
var makeRoutine; // routine wrapper for function that makes protoEvent
var protoEvent; // protoEvent created by function
// Step 1: generate resources from function
proto = (
delta: 0, // events occur simultaneously
finish: { ev = currentEnvironment} // get copy of event object actually played
);
protoEvent = ();
makeRoutine = Routine({ protoEvent.make (makeFunction) });
while {
(ev = makeRoutine.next(ev)).notNil;
} {
event = ev.proto_(proto).yield;
ev.proto = nil;
cleanupList = cleanupList.add(ev)
};
// Step 2: generate the default cleanup
cleanup = EventStreamCleanup.new;
eventCleanupFunc = { | flag | // generated purely from init event data
cleanupList.do { | ev |
EventTypesWithCleanup.cleanup(ev, flag)
}
};
// Step 3: combine with user cleanup by passing the default cleanup produced above to userCleanupFunc. I.e.
// if there's a user-cleanup set, we pass the auto-gen'd eventCleanupFunc to the user cleanup function
// so they can call the default cleanup when they see fit in their cleanup logic.
// Addtionally, we pass userCleanupFunc the actual cleanupList, which gives the user even more control, e.g.
// they could reorder or filter the augo-gen'd cleanups.
// The userCleanupFunc is actually a functOR, i.e. we expect it to return a function that does the a cleanup
// when its return value is itself even'd (with .value) later on.
if (userCleanupFunc.isNil) { // could be written more cleverly
comboCleanupFunc = eventCleanupFunc; // but this makes the logic very explicit
} { // not sure if passing protoEvent and proto adds any useful info, but can't hurt...
comboCleanupFunc = userCleanupFunc.value(eventCleanupFunc, cleanupList, protoEvent, proto);
};
cleanup.addFunction(event, comboCleanupFunc);
stream = Pfpar(pattern.asArray).asStream;
loop {
ev = event.copy.putAll(protoEvent);
ev = stream.next(ev) ?? { ^cleanup.exit(event) };
event = ev.yield;
};
^event
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment