aboutsummaryrefslogtreecommitdiffstats
path: root/core/base
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-03-24 11:39:25 +0000
committers-ol <s-ol@users.noreply.github.com>2020-03-24 11:39:25 +0000
commit677c0d2f01e14bbeca1583ec7878d80c71c3aa68 (patch)
treecc20e04697da590b546de370599eeaaef647d20c /core/base
parentinternals/plugin-guide: first draft (diff)
downloadalive-677c0d2f01e14bbeca1583ec7878d80c71c3aa68.tar.gz
alive-677c0d2f01e14bbeca1583ec7878d80c71c3aa68.zip
Value -> Value/Event/IO-Stream
Close 12
Diffstat (limited to 'core/base')
-rw-r--r--core/base/init.moon12
-rw-r--r--core/base/input.moon92
-rw-r--r--core/base/io.moon40
-rw-r--r--core/base/op.moon66
4 files changed, 93 insertions, 117 deletions
diff --git a/core/base/init.moon b/core/base/init.moon
index bb35140..8e376fc 100644
--- a/core/base/init.moon
+++ b/core/base/init.moon
@@ -4,28 +4,27 @@
-- This module exports the following classes that extension modules may need:
--
-- @module base
--- @see IO
-- @see Op
-- @see Action
-- @see FnDef
-- @see Input
-- @see match
--- @see Value
+-- @see ValueStream
+-- @see EventStream
+-- @see IOStream
-- @see Result
-- @see Error
-import IO from require 'core.base.io'
import Op from require 'core.base.op'
import Action from require 'core.base.action'
import FnDef from require 'core.base.fndef'
import Input from require 'core.base.input'
import match from require 'core.base.match'
-import Value from require 'core.value'
+import ValueStream, EventStream, IOStream from require 'core.stream'
import Result from require 'core.result'
import Error from require 'core.error'
{
- :IO
:Op
:Action
:FnDef
@@ -33,5 +32,6 @@ import Error from require 'core.error'
:match
-- redundant exports, to keep anything an extension might need in one import
- :Value, :Result, :Error
+ :ValueStream, :EventStream, :IOStream
+ :Result, :Error
}
diff --git a/core/base/input.moon b/core/base/input.moon
index c89337f..6922a4f 100644
--- a/core/base/input.moon
+++ b/core/base/input.moon
@@ -2,10 +2,29 @@
-- Update scheduling policy for `Op` arguments.
--
-- @classmod Input
-import Value from require 'core.value'
+import ValueStream, EventStream, IOStream from require 'core.stream'
import Result from require 'core.result'
-local ColdInput, ValueInput, EventInput, IOInput
+inherits = (klass, frm) ->
+ assert klass, "cant find the ancestor of nil"
+ return true if klass == frm
+ while klass.__parent
+ return true if klass.__parent == frm
+ klass = klass.__parent
+ false
+
+match_parent = (inst, map) ->
+ klass = assert inst and inst.__class, "not an instance"
+ if key = map[klass]
+ return key
+
+ while klass.__parent
+ if key = map[klass.__parent]
+ return key
+
+ klass = klass.__parent
+
+local ColdInput, ValueInput, IOInput, mapping
class Input
--- Input interface.
@@ -15,20 +34,10 @@ class Input
--- create a new Input.
--
- -- `value` is either a `Value` or a `Result` instance and should be
- -- unwrapped and assigned to `stream`.
- --
-- @classmethod
- -- @tparam Value|Result value
- new: (value) =>
- assert value, "nil passed to Input: #{value}"
- @stream = switch value.__class
- when Result
- assert value.value, "Input from result without value!"
- when Value
- value
- else
- error "Input from unknown value: #{value}"
+ -- @tparam Stream stream
+ new: (@stream) =>
+ assert @stream, "nil passed to Input: #{value}"
--- copy state from old instance (optional).
--
@@ -44,7 +53,7 @@ class Input
--
-- must return a boolean indicating whether `Op`s that refer to this instance
-- should be notified (via `Op:tick`). If not overwritten, delegates to
- -- `stream`:@{Value:dirty|dirty}.
+ -- `stream`:@{ValueStream:dirty|dirty}.
--
-- @treturn bool whether processing is necessary
dirty: => @stream\dirty!
@@ -65,7 +74,7 @@ class Input
--- the current value
--
- -- @tfield Value stream
+ -- @tfield ValueStream stream
--- members
-- @section members
@@ -86,33 +95,29 @@ class Input
-- Never marked dirty. Use this for input streams that are only read when
-- another `Input` is dirty.
--
- -- @tparam Value|Result value
- @cold: (value) -> ColdInput value
+ -- @tparam Stream|Result value
+ @cold: (value) ->
+ if value.__class == Result
+ value = assert value.value, "Input from result without value!"
+ ColdInput value
- --- Create a `value` `Input`.
+ --- Create a `hot` `Input`.
--
- -- Marked dirty for the eval-tick if old and new `Value` differ. This is the
- -- most common `Input` strategy. Should be used whenever a
- -- value denotes state.
+ -- Behaviour depends on what kind of `Stream` `value` is:
--
- -- @tparam Value|Result value
- @value: (value) -> ValueInput value
-
- --- Create an `event` `Input`.
+ -- - `ValueStream`: Marked dirty for the eval-tick if old and new `ValueStream` differ.
+ -- - `EventStream` and `IOStream`: Marked dirty only if the current `EventStream` is dirty.
--
- -- Only marked dirty if the `Value` itself is dirty. Should be used whenever
- -- an `Input` denotes a momentary event or impulse.
+ -- This is the most common `Input` strategy.
--
- -- @tparam Value|Result value
- @event: (value) -> EventInput value
+ -- @tparam Stream|Result value
+ @hot: (value) ->
+ if value.__class == Result
+ value = assert value.value, "Input from result without value!"
- --- Create an `IO` `Input`.
- --
- -- Marked dirty only when an `IO` is dirty. Must be used only for `Value`s
- -- which @{Value:unwrap|unwrap} to `IO` instances.
- --
- -- @tparam Value|Result value
- @io: (value) -> IOInput value
+ InputType = match_parent value, mapping
+ assert InputType, "Input from unknown value: #{value}"
+ InputType value
class ColdInput extends Input
dirty: => false
@@ -124,11 +129,14 @@ class ValueInput extends Input
return @dirty_setup if @dirty_setup != nil
@stream\dirty!
-class EventInput extends Input
-
class IOInput extends Input
- impure: true
- dirty: => @stream\unwrap!\dirty!
+ io: true
+
+mapping = {
+ [ValueStream]: ValueInput
+ [EventStream]: Input
+ [IOStream]: IOInput
+}
{
:Input
diff --git a/core/base/io.moon b/core/base/io.moon
deleted file mode 100644
index cbb5823..0000000
--- a/core/base/io.moon
+++ /dev/null
@@ -1,40 +0,0 @@
-----
--- Incoming side-effect adapter, creating events for the dataflow graph.
---
--- Polled by the main event loop to kick of events that cause the the dataflow
--- graph to ripple results.
---
--- @classmod IO
-
-class IO
---- IO interface.
---
--- methods that have to be implemented by `IO` implementations.
--- @section interface
-
- --- construct a new instance.
- --
- -- Must prepare the instance for `dirty` to be called.
- -- @classmethod
- new: =>
-
- --- poll for changes.
- --
- -- Called every frame by the main event loop to update internal state.
- tick: =>
-
- --- check whether this adapter requires processing.
- --
- -- Must return a boolean indicating whether `Op`s that refer to this instance
- -- via `Input.io` should be notified (via `Op:tick`). May be called multiple
- -- times. May be called before `tick` on the first frame after construction.
- --
- -- @treturn bool whether processing is required
- dirty: =>
-
- __tostring: => "<IO #{@@__name}>"
- __inherited: (cls) => cls.__base.__tostring = @__tostring
-
-{
- :IO
-}
diff --git a/core/base/op.moon b/core/base/op.moon
index a8da100..4880afd 100644
--- a/core/base/op.moon
+++ b/core/base/op.moon
@@ -2,16 +2,16 @@
-- Persistent expression Operator.
--
-- @classmod Op
-import Value from require 'core.value'
-ident = (tbl) ->
- mt = getmetatable tbl
- setmetatable tbl, nil
-
- id = tostring tbl
-
- setmetatable tbl, mt
- id\sub #'table: 0x'
+deepcopy = (val) ->
+ switch type val
+ when 'number', 'string', 'boolean'
+ val
+ when 'table'
+ assert (not getmetatable {}), "state should only contain simple tables!"
+ {(deepcopy k), (deepcopy v) for k,v in pairs val}
+ else
+ error "state cannot contain values of type '#{type val}'"
class Op
--- members
@@ -33,23 +33,30 @@ class Op
-- Used to wrap insulate eval-cycles from each other. The copy does not have
-- `inputs` set, since it is expected that this is (re)set in `setup`.
--
- -- @treturn Value
+ -- @treturn Op
fork: =>
- with setmetatable {}, getmetatable @
- .state = {k,v for k,v in pairs @state} if @state
- .out = @out\fork! if @out
+ out = if @out then @out\fork
+ state = if @state then deepcopy state
+ @@ out, state
+
+ --- internal state of this Op.
+ --
+ -- This may be any simple Lua value, including Lua tables, as long as it has
+ -- no metatables, multiple references/loops, userdata etc.
+ --
+ -- @tfield table state
- --- `Value` instance representing this Op's computed output value.
+ --- `Stream` instance representing this Op's computed output value.
--
- -- Must be set to a `Value` instance once `setup` finishes. Must not change
- -- type, be removed or replaced outside of `new` and `setup`. Should have a
- -- value assigned via `set` or the `Value` constructor once `tick` is
- -- called the first time. If `out`'s value is not initialized in `new`
- -- or `setup`, the implementation must make sure `tick``(true)` is called at
- -- least on the first eval-cycle the Op goes through, e.g. by using an
- -- `Input.value`.
+ -- Must be set to a `Stream` instance once `setup` finishes. Must not change
+ -- type, be removed or replaced outside of `new` and `setup`. If it is a
+ -- `ValueStream`, it should have a value assigned via `set` or the
+ -- constructor once `tick` is called the first time. If `out`'s value is not
+ -- initialized in `new` or `setup`, the implementation must make sure
+ -- `tick``(true)` is called at -- least on the first eval-cycle the Op goes
+ -- through, e.g. by using an `Input.value`.
--
- -- @tfield Value out
+ -- @tfield Stream out
--- table containing `Input`s to this Op.
--
@@ -66,10 +73,14 @@ class Op
--- construct a new instance.
--
- -- The super-constructor can be used to construct a `Value` instance in `out`.
+ -- The optional parameters `out` and `state` are used by `fork` to duplicate
+ -- an instance. If the constructor is overriden, these parameters must be
+ -- forwarded to the superconstructor unchanged.
--
-- @function new
-- @classmethod
+ -- @tparam ?Stream out `out`
+ -- @tparam ?table state `state`
--- parse arguments and patch self.
--
@@ -109,12 +120,9 @@ class Op
-- type is not known at this time.
--
-- @classmethod
- -- @tparam[opt] string type the type-name for `out`
- -- @tparam[optchain] any init the initial value for `out`
- new: (type, init) =>
- @state = {}
- if type
- @out = Value type, init
+ -- @tparam ?Stream out `out`
+ -- @tparam ?table state `state`
+ new: (@out, @state) =>
do_setup = (old, cur) ->
for k, cur_val in pairs cur