class Novika::Engine
- Novika::Engine
- Reference
- Object
Overview
An engine object is responsible for managing a continuations block.
Continuations block consists of continuation blocks.
Canonical continuation blocks themselves contain two blocks
(see Engine.cont
):
-
Code block, more commonly known as simply the block (and as active block when its continuation is active, i.e., when it's being evaluated),
-
Stack block, more commonly known as simply the stack (and as active stack when its continuation is active, i.e., when it's being evaluated).
Engine#schedule
is used to create a continuation block
given a Schedulable
object (usually a Form
, and in rarer
cases an Entry
) and a stack block. It then adds the
continuation block to the continuations block -- effectively
scheduling it for execution on the next exhaust loop cycle.
Note that there are two other methods linked with execution
and implemented by all forms: on_open
, and on_parent_open
.
They perform whatever action the form wants rather than
simply scheduling it to be performed some time in the
future. Namely, on_open
is invoked whenever the form at
hand is itself the target of opening (aka execution, aka
evaluation), and on_parent_open
is invoked when a block
containing the form at hand (its parent block) is the target
of opening.
An engine's exhaust loop is where most of the magic happens. It is organized very much like the fetch-decode-execute cycle in CPUs.
For fetch, the engine finds the top (see Block#top
)
continuation block, then finds the top form on the code
block, and invokes the on_parent_open
method on it.
This method is analogous to decoding followed by execution.
The form is free to choose how it wants to make sense of itself,
given an engine. Some forms (e.g. words) end up scheduling
new continuation blocks on_parent_open
, making the engine
go through them first.
After the cursor of the active block hits the end, Engine
drops (see Block#drop
) the continuation block (thereby
closing the code block).
caps = CapabilityCollection.with_default.enable_all
block = Block.new(caps.block).slurp("1 2 +")
stack = Block.new
engine = Engine.new(caps)
engine.schedule(block, stack)
engine.exhaust
puts stack # [ 3 ]
# Or, shorter:
caps = CapabilityCollection.with_default.enable_all
block = Block.new(caps.block).slurp("1 2 +")
puts Engine.exhaust(caps, block) # [ 3 ]
Defined in:
novika/engine.crConstant Summary
-
C_BLOCK_AT =
0
-
Index of the code block in a continuation block.
-
C_STACK_AT =
1
-
Index of the stack block in a continuation block.
-
MAX_CONTS =
1024
-
Maximum amount of scheduled continuations in
#conts
. After passing this number,Error
is raised to bring attention to such dangerous depth. -
MAX_ENGINES =
1024
-
Maximum number of engines that can be created.
This is for safety reasons only, particularly to prevent infinite recursion in e.g. asserts which are called from Crystal rather than Novika, thereby circumventing
MAX_CONTS
checks. SeeEngine.count
.
Constructors
-
.new(capabilities : CapabilityCollection, &)
Yields an instance of
Engine
. -
.push(engine : Engine) : Engine
Pushes engine onto the engine stack.
Class Method Summary
-
.cont(*, block, stack)
Creates and returns a canonical continuation block.
-
.current
Returns the current engine.
-
.exhaust(capabilities : CapabilityCollection, schedulable, stack = nil) : Block
Schedules schedulable and exhausts immediately.
-
.exhaust!(capabilities : CapabilityCollection, schedulable, stack = nil) : Block
Schedules schedulable and exhausts immediately.
-
.pop(engine : Engine) : Engine | Nil
Pops engine from the engine stack.
-
.push(caps : CapabilityCollection)
Pushes a new engine with the given capability collection caps.
-
.trackers
Holds an array of exhaust tracker objects associated with all instances of
Engine
.
Instance Method Summary
-
#block
Returns the block of the active continuation.
-
#capabilities : CapabilityCollection
Returns the capability collection used by this engine.
-
#cont
Returns the active continuation.
-
#conts : Novika::Block
Holds the continuations block (aka continuations stack).
-
#conts=(conts : Novika::Block)
Holds the continuations block (aka continuations stack).
-
#die(*args, **options)
See
Form#die
. -
#die(*args, **options, &)
See
Form#die
. -
#drop_until_death_handler?(avoid_prototype = nil)
Returns the relevant death handler, or nil.
-
#each_active_block(&)
Yields active blocks, starting from the oldest active block up to the current active block.
- #execute(form : Form)
- #exhaust
-
#schedule(schedulable : Schedulable, stack : Block)
See
Schedulable#schedule
. - #schedule!(schedulable : Schedulable, stack : Block)
-
#schedule!(other : Block)
Main authorized point for adding continuations unsafely.
-
#schedule!(*, block : Block, stack : Block)
Schedules a continuation with the given block and stack.
-
#stack
Returns the stack block of the active continuation.
Constructor Detail
Class Method Detail
Creates and returns a canonical continuation block.
A continuation block must include two blocks: the first is
called simply the block (found at C_BLOCK_AT
), and the
second is called the stack block (found at C_STACK_AT
).
Returns the current engine. Raises a BUG exception if there is no current engine.
Schedules schedulable and exhausts immediately. Returns the
resulting stack (creates one if nil
).
Useful for when you need the result of schedulable immediately.
For details see Engine#schedule
.
caps = CapabilityCollection.with_default.enable_all
result = Engine.exhaust(caps, Block.new(caps.block).slurp("1 2 +"))
result.top # 3 : Novika::Decimal
Schedules schedulable and exhausts immediately. Returns the
resulting stack (creates one if nil
).
Useful for when you need the result of schedulable immediately.
For details see Engine#schedule!
.
caps = CapabilityCollection.with_default.enable_all
result = Engine.exhaust(caps, Block.new(caps.block).slurp("1 2 +"))
result.top # 3 : Novika::Decimal
Pops engine from the engine stack. Raises a BUG exception (and does not pop!) if the current engine is not engine (or if it is absent).
Pushes a new engine with the given capability collection caps.
Make sure that you .pop
it yourself or that you know what
you're doing!
Holds an array of exhaust tracker objects associated with
all instances of Engine
. These objects intercept forms
before/after opening in Engine#exhaust
. This e.g. allows
frontends to analyze/track forms and/or matching blocks.
Instance Method Detail
Returns the relevant death handler, or nil. Avoids handlers whose prototype is avoid_prototype.
To find the relevant death handler, the continuations
block is inspected right-to-left (back-to-front); each
code block is then asked to retrieve Word::DIED
using Block#at?
. Regardless of the result, the
continuation block is then dropped.
If succeeded in retrieving Word::DIED
, converts the
resulting entry to block (does not distinguish between
openers and pushers). Returns that block.
If all continuations were exhausted and no Hook.died
had been found, returns nil.
Yields active blocks, starting from the oldest active block up to the current active block.
Exhausts all scheduled continuations, starting from the
topmost (see Block#top
) continuation in #conts
.
Main authorized point for adding continuations unsafely. Returns self.
Provides protection from continuations stack overflow.
Adding to #conts
(the unauthorized way) does not protect
one from continuations stack overflow, and therefore from
a memory usage explosion.
Schedules a continuation with the given block and stack.