aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-04-13 18:40:35 +0000
committers-ol <s-ol@users.noreply.github.com>2020-04-14 08:46:54 +0000
commit1a8debe87762072b3a63b769aa515ebf63b4c70d (patch)
tree33b42866307d11d2c0878b23e0ec0bb8925d3fcc /core
parentspec base.match __tostring (diff)
downloadalive-1a8debe87762072b3a63b769aa515ebf63b4c70d.tar.gz
alive-1a8debe87762072b3a63b769aa515ebf63b4c70d.zip
move into proper Lua module (`alv`)
Diffstat (limited to 'core')
-rw-r--r--core/ast.moon40
-rw-r--r--core/base/builtin.moon96
-rw-r--r--core/base/fndef.moon26
-rw-r--r--core/base/init.moon39
-rw-r--r--core/base/input.moon146
-rw-r--r--core/base/match.moon302
-rw-r--r--core/base/op.moon168
-rw-r--r--core/builtin.moon333
-rw-r--r--core/cell.moon189
-rw-r--r--core/config.ld16
-rw-r--r--core/cycle.moon26
-rw-r--r--core/error.moon94
-rw-r--r--core/extensions.md221
-rw-r--r--core/init.moon55
-rw-r--r--core/invoke.moon124
-rw-r--r--core/parsing.moon73
-rw-r--r--core/registry.moon145
-rw-r--r--core/result.moon126
-rw-r--r--core/scope.moon118
-rw-r--r--core/stream/base.moon68
-rw-r--r--core/stream/event.moon100
-rw-r--r--core/stream/init.moon18
-rw-r--r--core/stream/io.moon55
-rw-r--r--core/stream/value.moon237
-rw-r--r--core/tag.moon122
-rw-r--r--core/version.moon17
26 files changed, 0 insertions, 2954 deletions
diff --git a/core/ast.moon b/core/ast.moon
deleted file mode 100644
index a25d1cd..0000000
--- a/core/ast.moon
+++ /dev/null
@@ -1,40 +0,0 @@
-----
--- AST Node Interface.
---
--- implemented by `Value` and `Cell`.
---
--- @classmod AST
-
---- members
--- @section members
-
- --- evaluate this AST Node.
- --
- -- Evaluate this node and return a `Result`.
- --
- -- @function eval
- -- @tparam Scope scope the scope to evaluate in
- -- @treturn Result the evaluation result
-
- --- quote this AST Node, preserving its identity.
- --
- --- Returns a mutable copy of this Node that shares its identity.
- --
- -- @function quote
- -- @treturn AST
-
- --- create a clone with its own identity.
- --
- -- creates a clone of this Cell with its own identity by prepending a `parent`
- -- Tag (and cloning all child expressions recursively).
- --
- -- @function clone
- -- @tparam Tag parent
- -- @treturn AST
-
- --- stringify this AST Node.
- --
- -- Should return the exact string this node was parsed from (if it was parsed).
- --
- -- @function stringify
- -- @treturn string the exact string this Node was parsed from
diff --git a/core/base/builtin.moon b/core/base/builtin.moon
deleted file mode 100644
index fd36c69..0000000
--- a/core/base/builtin.moon
+++ /dev/null
@@ -1,96 +0,0 @@
-----
--- Builtin / Special Form evaluation Strategy (`builtin`).
---
--- Responsible for quoting/evaluating subexpressions, instantiating and setting
--- up `Op`s, updating the current `Scope`, etc.
--- See `builtin` and `invoke` for examples.
---
--- @classmod Builtin
-
-class Builtin
---- Builtin interface.
---
--- methods that have to be implemented by `Builtin` implementations.
--- @section interface
-
- --- create a new instance.
- --
- -- @tparam Cell cell the Cell to evaluate
- -- @tparam Value head the (`AST:eval`d) `head` of the Cell to evaluate
- new: (@cell, @head) =>
- @tag = @cell.tag
- @tag\register @
-
- --- perform the actual evaluation.
- --
- -- Implementations should:
- --
- -- - eval or quote `tail` values
- -- - perform scope effects
- -- - wrap all child-results
- --
- -- @tparam Scope scope the active scope
- -- @tparam {AST,...} tail the arguments to this expression
- -- @treturn Result the result of this evaluation
- eval: (scope, tail) => error "not implemented"
-
- --- free resources
- destroy: =>
-
- --- setup or copy state from previous instance of same type.
- --
- -- `prev` is only passed if Builtin types of prev and current expression match.
- -- Otherwise, or when no previous expression exists, `nil` is passed.
- --
- -- @tparam ?Builtin prev the previous Builtin instance
- setup: (prev) =>
-
- --- the `Cell` this Builtin was created for.
- -- @tfield Cell cell
-
- --- the evaluated head of `cell`.
- -- @tfield AST head
-
- --- the identity of `cell`.
- -- @tfield Tag tag
-
---- static functions
--- @section static
-
- --- create and setup a `Builtin` for a given tag, then evaluate it.
- --
- -- Create a new instance using `tag` and `head` and call `setup` on it.
- -- If a previous instance with the same `tag` exists and has the same `head`,
- -- it pass it to `setup`. Register the `Builtin` with `tag`, evaluate it
- -- and return the `Result`.
- --
- -- @tparam Cell cell the `Cell` being evaluated
- -- @tparam Scope scope the active scope
- -- @tparam Value head the (`AST:eval`d) head of the `Cell` being evaluated
- -- @treturn Result the result of evaluation
- @eval_cell: (cell, scope, head) =>
- last = cell.tag\last!
- compatible = last and (last.__class == @) and last.head == head
-
- L\trace if compatible
- "reusing #{last} for #{cell.tag} <#{@__name} #{head}>"
- else if last
- "replacing #{last} with new #{cell.tag} <#{@__name} #{head}>"
- else
- "initializing #{cell.tag} <#{@__name} #{head}>"
-
- builtin = @ cell, head
- if compatible
- builtin\setup last
- else
- last\destroy! if last
- builtin\setup nil
-
- builtin\eval scope, cell\tail!
-
- __tostring: => "<#{@@__name} #{@head}>"
- __inherited: (cls) => cls.__base.__tostring = @__tostring
-
-{
- :Builtin
-}
diff --git a/core/base/fndef.moon b/core/base/fndef.moon
deleted file mode 100644
index b79ad85..0000000
--- a/core/base/fndef.moon
+++ /dev/null
@@ -1,26 +0,0 @@
-----
--- user-function definition (`fndef`).
---
--- When called, expands to its body with params bound to the fn arguments (see
--- `invoke.fn_invoke`).
---
--- @classmod FnDef
-
-class FnDef
---- static functions
--- @section static
-
- --- create a new instance
- --
- -- @classmethod
- -- @tparam {Value,...} params (`AST:quote`d) naming the function parameters
- -- @tparam AST body (`AST:quote`d) expression the function evaluates to
- -- @tparam Scope scope the lexical scope the function was defined in (closure)
- new: (@params, @body, @scope) =>
-
- __tostring: =>
- "(fn (#{table.concat [p\stringify! for p in *@params], ' '}) ...)"
-
-{
- :FnDef
-}
diff --git a/core/base/init.moon b/core/base/init.moon
deleted file mode 100644
index 9153f79..0000000
--- a/core/base/init.moon
+++ /dev/null
@@ -1,39 +0,0 @@
-----
--- Base definitions for extensions.
---
--- This module exports the following classes and tables that extension modules
--- may need:
---
--- @module base
--- @see Op
--- @see Builtin
--- @see FnDef
--- @see Input
--- @see base.match.val
--- @see base.match.evt
--- @see ValueStream
--- @see EventStream
--- @see IOStream
--- @see Result
--- @see Error
-
-import Op from require 'core.base.op'
-import Builtin from require 'core.base.builtin'
-import FnDef from require 'core.base.fndef'
-import Input from require 'core.base.input'
-import val, evt from require 'core.base.match'
-import ValueStream, EventStream, IOStream from require 'core.stream'
-import Result from require 'core.result'
-import Error from require 'core.error'
-
-{
- :Op
- :Builtin
- :FnDef
- :Input
- :val, :evt
-
- -- redundant exports, to keep anything an extension might need in one import
- :ValueStream, :EventStream, :IOStream
- :Result, :Error
-}
diff --git a/core/base/input.moon b/core/base/input.moon
deleted file mode 100644
index bcf188e..0000000
--- a/core/base/input.moon
+++ /dev/null
@@ -1,146 +0,0 @@
-----
--- Update scheduling policy for `Op` arguments.
---
--- @classmod Input
-import ValueStream, EventStream, IOStream from require 'core.stream'
-import Result from require 'core.result'
-
-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.
---
--- Methods that have to be implemented by `Input` implementations.
--- @section interface
-
- --- create a new Input.
- --
- -- @classmethod
- -- @tparam Stream stream
- new: (@stream) =>
- assert @stream, "nil passed to Input: #{value}"
-
- --- copy state from old instance (optional).
- --
- -- called by `Op:setup` with another `Input` instance or `nil` once this instance is
- -- registered. Must prepare this instance for `dirty`.
- --
- -- May enter a 'setup state' that is exited using `finish_setup`.
- --
- -- @tparam ?Input prev previous `Input` intance or nil
- setup: (prev) =>
-
- --- whether this input requires processing (optional).
- --
- -- 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`:@{ValueStream:dirty|dirty}.
- --
- -- @treturn bool whether processing is necessary
- dirty: => @stream\dirty!
-
- --- leave setup state (optional).
- --
- -- called after the `Op` has completed (or skipped) its first `Op:tick` after
- -- `Op:setup`. Must prepare this instance for dataflow operation.
- finish_setup: =>
-
- --- unwrap to Lua value (optional).
- --
- -- @treturn any the raw Lua value
- unwrap: => @stream\unwrap!
-
- --- return the type name of this `Input` (optional).
- type: => @stream.type
-
- --- return the metatype name of this `Input` (optional).
- metatype: => @stream.metatype
-
- --- the current value
- --
- -- @tfield ValueStream stream
-
---- members
--- @section members
-
- --- alias for `unwrap`.
- __call: => @stream\unwrap!
-
- __tostring: => "#{@@__name}:#{@stream}"
- __inherited: (cls) =>
- cls.__base.__call = @__call
- cls.__base.__tostring = @__tostring
-
---- static functions
--- @section static
-
- --- Create a `cold` `Input`.
- --
- -- Never marked dirty. Use this for input streams that are only read when
- -- another `Input` is dirty.
- --
- -- @tparam Stream|Result value
- @cold: (value) ->
- if value.__class == Result
- value = assert value.value, "Input from result without value!"
- ColdInput value
-
- --- Create a `hot` `Input`.
- --
- -- Behaviour depends on what kind of `Stream` `value` is:
- --
- -- - `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.
- --
- -- This is the most common `Input` strategy.
- --
- -- @tparam Stream|Result value
- @hot: (value) ->
- if value.__class == Result
- value = assert value.value, "Input from result without value!"
-
- InputType = match_parent value, mapping
- assert InputType, "Input from unknown value: #{value}"
- InputType value
-
-class ColdInput extends Input
- dirty: => false
-
-class ValueInput extends Input
- setup: (old) => @dirty_setup = not old or @stream != old.stream
- finish_setup: => @dirty_setup = nil
- dirty: =>
- return @dirty_setup if @dirty_setup != nil
- @stream\dirty!
-
-class IOInput extends Input
- io: true
-
-mapping = {
- [ValueStream]: ValueInput
- [EventStream]: Input
- [IOStream]: IOInput
-}
-
-{
- :Input
-}
diff --git a/core/base/match.moon b/core/base/match.moon
deleted file mode 100644
index 700b50d..0000000
--- a/core/base/match.moon
+++ /dev/null
@@ -1,302 +0,0 @@
------
---- Pattern capturing for Op argument parsing.
---
--- There is only one basic buildings block for assembling patterns:
--- `Type`. It can match `ValueStream`s and `EventStream`s depending on its
--- metatype argument and can take an optional type name to match as an argument.
---
--- In addition to this primitive, the following modifiers are available:
--- `Repeat`, `Sequence`, `Choice`, and `Optional`. They can be used directly,
--- but there is also a number of shorthands for assembling patterns quickly:
---
--- - `val()` and `evt()`: Shorthands for `Type('value')` and `Type('event')`
--- - `val.num`: Shorthand for `Type('value', 'num')`
--- - `evt.str`: Shorthand for `Type('event', 'str')`
--- - `pat * 2`: Shorthand for `Repeat(pat, 1, 2)` (1-4 times `pat`)
--- - `pat * 0`: Shorthand for `Repeat(pat, 1, nil)` (1-* times `pat`)
--- - `pat ^ 2`: Shorthand for `Repeat(pat, 0, 2)` (0-4 times `pat`)
--- - `pat ^ 0`: Shorthand for `Repeat(pat, 0, nil)` (0-* times `pat`)
--- - `a + b + … + z`: Shorthand for `Sequence{ a, b, ..., z }`
--- - `a / b / … / z`: Shorthand for `Choice{ a, b, ..., z }`
--- - `-pat`: Shorthand for `Optional(pat)`
---
--- To perform the actual matching, call the `:match` method on a pattern and
--- pass a sequence of `Result`s. The method will either return the captured
--- `Result`s (or a table structuring them)
---
--- Any ambiguous pattern can be set to 'recall mode' by invoking it.
--- Recalling patterns will memorize the first Result they match, and
--- only match further Results of the same type. For example
---
--- arg = (val.num / val.str)!
--- pattern = arg + arg
---
--- ...will match either two numbers or two strings, but not one number and one
--- string. Recalling works on `Choice` and `Type` patterns. `Type` patterns
--- without a type (`val!` and `evt!`) always behave like this.
---
--- On `Sequence` patterns, a special method `:named` exists. It takes a
--- sequence of keys that are used instead of integers when constructing the
--- capture table:
---
--- pattern = (val.str + val.num):named('key', 'value')
--- pattern:match(...)
--- -- returns { {key='a', value=1}, {key='b', value=2}, ...}
---
--- @module base.match
-import Error from require 'core.error'
-import ValueStream, EventStream from require 'core.stream'
-
-local Repeat, Sequence, Choice, Optional
-
-typestr = (result) ->
- str = result\type!
- str ..= '!' if result\metatype! == 'event'
- str
-
-class Pattern
- match: (seq) =>
- @reset!
- num, cap = @capture seq, 1
- if num != #seq
- args = table.concat [typestr arg for arg in *seq], ' '
- msg = "couldn't match arguments (#{args}) against pattern #{@}"
- error Error 'argument', msg
- cap
-
- remember: (key) =>
- return true unless @recall
-
- @recalled or= key
- @recalled == key
-
- rep: (min, max) => Repeat @, min, max
-
- reset: => @recalled = nil
-
- __call: => @
- __mul: (num) => Repeat @, 1, if num != 0 then num
- __pow: (num) => Repeat @, 0, if num != 0 then num
- __add: (other) => Sequence { @, other }
- __div: (other) => Choice { @, other }
- __unm: => Optional @
-
- __inherited: (cls) =>
- cls.__base.__call or= @__call
- cls.__base.__mul or= @__mul
- cls.__base.__pow or= @__pow
- cls.__base.__add or= @__add
- cls.__base.__div or= @__div
- cls.__base.__unm or= @__unm
-
---- Base Stream Pattern.
---
--- When instantiated with `type`, only succeeds for `Stream`s whose value and
--- meta types match.
---
--- Otherwise, matches Streams based only on `metatype` for the first match, but
--- using both afterwards (recall mode).
---
--- @function Stream
--- @tparam string metatype "value" or "event"
--- @tparam ?string type type name
-class Type extends Pattern
- new: (@metatype, @type) =>
- @recall = not @type
-
- capture: (seq, i) =>
- return unless seq[i]
- type, mt = seq[i]\type!, seq[i]\metatype!
- return unless @metatype == mt
- match = if @type then type == @type else @remember type
- if match
- 1, seq[i]
-
- __tostring: =>
- str = @type or @metatype
- str ..= '!' if @metatype == 'event'
- str
-
---- Repeat a pattern.
---
--- Matches a given `inner` pattern as many times as possible, within the given
--- minimum/maximum counts. Matching this pattern results in a sequence of the
--- individual captures produced by the inner pattern.
---
--- @function Repeat
--- @tparam Pattern inner the original pattern
--- @tparam ?number min minimum amount of repetitions
--- @tparam ?number max maximum amount of repetitions (default infinite)
-class Repeat extends Pattern
- new: (@inner, @min, @max) =>
-
- capture: (seq, i) =>
- take, all = 0, {}
- while true
- num, cap = @inner\capture seq, i+take
- break unless num
-
- take += num
- table.insert all, cap
-
- break if @max and take >= @max
-
- return if @min and take < @min
- return if @max and take > @max
-
- take, all
-
- reset: =>
- @inner\reset!
-
- __call: =>
- @@ @inner!, @min, @max
-
- __tostring: =>
- min = @min or '0'
- max = @max or '*'
- "#{@inner}{#{min}-#{max}}"
-
---- Match multiple patterns in order.
---
--- Matches the inner patterns in order, only succeeds if all of them match.
--- Captures the individual captures produced by the inner patterns in a
--- sequence, or table with keys specified in `keys` or using the `:named(...)`
--- modifier.
---
--- @function Sequence
--- @tparam {Pattern,...} elements the inner patterns
--- @tparam ?{string,...} keys the keys to use when capturing matches
-class Sequence extends Pattern
- new: (@elements, @keys) =>
-
- capture: (seq, i) =>
- take, all = 0, {}
- for key, elem in ipairs @elements
- num, cap = elem\capture seq, i+take
- return unless num
-
- take += num
- key = @keys[key] if @keys
- all[key] = cap
-
- take, all
-
- reset: =>
- for elem in *@elements
- elem\reset!
-
- named: (...) =>
- @@ [e for e in *@elements], { ... }
-
- __call: =>
- @@ [e! for e in *@elements]
-
- __add: (other) =>
- elements = [e for e in *@elements]
- table.insert elements, other
- @@ elements
-
- __tostring: =>
- core = table.concat [tostring e for e in *@elements], ' '
- "(#{core})"
-
---- Match one of multiple options.
---
--- Matches using the first matching pattern in `elements` and returns its
--- captured value. Supports recalling the matched subpattern.
---
--- @function Choice
--- @tparam {Pattern,...} elements the inner patterns
--- @tparam ?{string,...} keys the keys to use when capturing matches
-class Choice extends Pattern
- new: (@elements, @recall=false) =>
-
- capture: (seq, i) =>
- for key, elem in ipairs @elements
- num, cap = elem\capture seq, i
- if num and @remember key
- return num, cap
-
- reset: =>
- super!
- for elem in *@elements
- elem\reset!
-
- __call: =>
- @@ [e! for e in *@elements], true
-
- __div: (other) =>
- elements = [e for e in *@elements]
- table.insert elements, other
- @@ elements
-
- __tostring: =>
- core = table.concat [tostring e for e in *@elements], ' | '
- "(#{core})"
-
---- Optionally match a pattern.
---
--- Matches using the first matching pattern in `elements` and returns its
--- captured value. Supports recalling the matched subpattern.
---
--- @function Optional
--- @tparam {Pattern,...} elements the inner patterns
--- @tparam ?{string,...} keys the keys to use when capturing matches
-class Optional extends Pattern
- new: (@inner) =>
-
- capture: (seq, i) =>
- num, cap = @inner\capture seq, i
- num or 0, cap
-
- reset: =>
- @inner\reset!
-
- __call: =>
- @@ @inner!
-
- __unm: => @
-
- __tostring: => "#{@inner}?"
-
---- `Value` shorthands.
---
--- Call or index with a string to obtain a `Type` instance.
--- Call to obtain a wildcard pattern.
---
--- val.str, val.num
--- val['vec3'], val('vec3')
--- val()
---
--- @table val
-val = setmetatable {}, {
- __index: (key) =>
- with v = Type 'value', key
- @[key] = v
-
- __call: (...) => Type 'value', ...
-}
-
---- `Event` shorthands.
---
--- Call or index with a string to obtain an `Type` instance.
--- Call to obtain a wildcard pattern.
---
--- evt.bang, evt.str, evt.num
--- evt['midi/message'], evt('midi/message')
--- evt()
---
--- @table evt
-evt = setmetatable {}, {
- __index: (key) =>
- with v = Type 'event', key
- @[key] = v
-
- __call: (...) => Type 'event', ...
-}
-
-{
- :Type, :Repeat, :Sequence, :Choice, :Optional
- :val, :evt
-}
diff --git a/core/base/op.moon b/core/base/op.moon
deleted file mode 100644
index b0a83dc..0000000
--- a/core/base/op.moon
+++ /dev/null
@@ -1,168 +0,0 @@
-----
--- Persistent expression Operator.
---
--- @classmod Op
-
-deepcopy = (val) ->
- switch type val
- when 'number', 'string', 'boolean', 'nil'
- 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
--- @section members
-
- do_yield = (table) ->
- for k, v in pairs table
- if v.__class
- coroutine.yield v
- else
- do_yield v
- --- yield all `Input`s from the (potentially nested) `inputs` table
- --
- -- @treturn iterator iterator over `inputs`
- all_inputs: => coroutine.wrap -> do_yield @inputs
-
- --- create a mutable copy of this 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 Op
- fork: =>
- 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
-
- --- `Stream` instance representing this Op's computed output 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.hot` with a `ValueStream`.
- --
- -- @tfield Stream out
-
- --- table containing `Input`s to this Op.
- --
- -- The `inputs` table can be nested with string or integer keys,
- -- but all leaf-entries must be `Input` instances. It must not contain loops
- -- or instances of other classes.
- --
- -- @tfield {Input,...} inputs
-
---- Op interface.
---
--- methods that have to be implemented by `Op` implementations.
--- @section interface
-
- --- construct a new instance.
- --
- -- 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.
- --
- -- Called once every eval-cycle. `inputs` is a list of `Result`s that are the
- -- argument to this op. The `inputs` have to be wrapped in `Input` instances
- -- to define update behaviour. Use `base.match` to parse them, then delegate to
- -- `super:setup` to patch the `Input` instances.
- --
- -- @function setup
- -- @tparam {Result,...} inputs a sequence of `Result`s
- -- @tparam Scope scope the active scope
-
- --- handle incoming events and update `out` (optional).
- --
- -- Called once per frame if any `Input`s are dirty. Some `Input`s may have
- -- special behaviour immediately after `setup` that can cause them to become
- -- dirty at eval-time. In this case, an eval-time tick is executed. You can
- -- detect this using the `setup` parameter.
- --
- -- `tick` is called after `setup`. `tick` is not called immediately after
- -- `setup` if no `inputs` are dirty. Update `out` here.
- --
- -- @tparam bool setup whether this is an eval-time tick
- tick: =>
-
- --- called when the Op is destroyed (optional).
- destroy: =>
-
---- implementation utilities.
---
--- super-methods and utilities for use by implementations.
--- @section super
-
- --- if `type` is passed, an output stream is instantiated.
- -- if `init` is passed, the stream is initialized to that Lua value.
- -- it is okay not to use this and create the output stream in :setup() if the
- -- type is not known at this time.
- --
- -- @classmethod
- -- @tparam ?Stream out `out`
- -- @tparam ?table state `state`
- new: (@out, @state) =>
-
- do_setup = (old, cur) ->
- for k, cur_val in pairs cur
- old_val = old and old[k]
-
- -- are these inputs or nested tables?
- cur_plain = cur_val and not cur_val.__class
- old_plain = old_val and not old_val.__class
-
- if cur_plain and old_plain
- -- both are tables, recurse
- do_setup old_val, cur_val
- elseif not (cur_plain or old_plain)
- -- both are streams (or nil), setup them
- cur_val\setup old_val
- --- setup previous `inputs`, if any, with the new inputs, and write them to
- -- `inputs`. The `inputs` table can be nested with string or integer keys,
- -- but all leaf-entries must be `Input` instances. It must not contain loops
- -- or instances of other classes.
- --
- -- @tparam table inputs table of `Input`s
- setup: (inputs) =>
- old_inputs = @inputs
- @inputs = inputs
- do_setup old_inputs, @inputs
-
- do_unwrap = (value) ->
- if value.__class
- value\unwrap!
- else
- {k, do_unwrap v for k,v in pairs value}
- --- `\unwrap` all `Input`s in `@inputs` and return a table with the same
- -- shape.
- --
- -- @treturn table the values of all `Input`s
- unwrap_all: => do_unwrap @inputs
-
- __tostring: => "<op: #{@@__name}>"
- __inherited: (cls) => cls.__base.__tostring = @__tostring
-
-{
- :Op
-}
diff --git a/core/builtin.moon b/core/builtin.moon
deleted file mode 100644
index 68b825c..0000000
--- a/core/builtin.moon
+++ /dev/null
@@ -1,333 +0,0 @@
-----
--- Builtin `Builtin`s and `Op`s.
---
--- Please see the [reference](../../reference/index.html#builtins) for
--- documentation.
---
--- @module builtin
-import Builtin, Op, FnDef, Input, val, evt from require 'core.base'
-import ValueStream, LiteralValue from require 'core.stream.value'
-import Result from require 'core.result'
-import Cell from require 'core.cell'
-import Scope from require 'core.scope'
-import Tag from require 'core.tag'
-import op_invoke from require 'core.invoke'
-
-doc = ValueStream.meta
- meta:
- name: 'doc'
- summary: "Print documentation in console."
- examples: { '(doc sym)' }
- description: "Print the documentation for `sym` to the console"
-
- value: class extends Builtin
- format_meta = =>
- str = @summary
- if @examples
- for example in *@examples
- str ..= '\n' .. example
- if @description
- str ..= '\n' .. @description\match '^\n*(.+)\n*$'
- str
-
- eval: (scope, tail) =>
- assert #tail == 1, "'doc' takes exactly one parameter"
-
- result = L\push tail[1]\eval, scope
- with Result children: { def }
- meta = result.value.meta
- L\print "(doc #{tail[1]}):\n#{format_meta meta}\n"
-
-def = ValueStream.meta
- meta:
- name: 'def'
- summary: "Declare symbols in current scope."
- examples: { '(def sym1 val-expr1 [sym2 val-expr2…])' }
- description: "
-Define the symbols `sym1`, `sym2`, … to resolve to the values of `val-expr1`,
-`val-expr2`, …."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 1, "'def' requires at least 2 arguments"
- assert #tail % 2 == 0, "'def' requires an even number of arguments"
-
- children = L\push ->
- return for i=1,#tail,2
- name, val_expr = tail[i], tail[i+1]
- name = (name\quote scope)\unwrap 'sym'
-
- with val_expr\eval scope
- scope\set name, \make_ref!
-
- Result :children
-
-use = ValueStream.meta
- meta:
- name: 'use'
- summary: "Merge scopes into current scope."
- examples: { '(use scope1 [scope2…])' }
- description: "
-Copy all symbol definitions from `scope1`, `scope2`, … to the current scope.
-All arguments have to be evaltime constant."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- for child in *tail
- result = L\push child\eval, scope
- value = result\const!
- scope\use value\unwrap 'scope', "'use' only works on scopes"
-
- Result!
-
-require_ = ValueStream.meta
- meta:
- name: 'require'
- summary: "Load a module."
- examples: { '(require name)' }
- description: "Load a module and return its scope."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'require' takes exactly one parameter"
-
- result = L\push tail[1]\eval, scope
- name = result\const!
-
- L\trace @, "loading module #{name}"
- scope = ValueStream.wrap require "lib.#{name\unwrap 'str'}"
- Result :value
-
-import_ = ValueStream.meta
- meta:
- name: 'import'
- summary: "Require and define modules."
- examples: { '(import sym1 [sym2…])' }
- description: "
-Requires modules `sym1`, `sym2`, … and define them as `sym1`, `sym2`, … in the
-current scope."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 0, "'import' requires at least one arguments"
-
- for child in *tail
- name = (child\quote scope)\unwrap 'sym'
- value = ValueStream.wrap require "lib.#{name}"
- scope\set name, Result :value -- (require "lib.#{name})\unwrap 'scope'
- Result!
-
-import_star = ValueStream.meta
- meta:
- name: 'import*'
- summary: "Require and use modules."
- examples: { '(import* sym1 [sym2…])' }
- description: "
-Requires modules `sym1`, `sym2`, … and merges them into the current scope."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 0, "'import' requires at least one arguments"
-
-
- for child in *tail
- name = (child\quote scope)\unwrap 'sym'
- value = ValueStream.wrap require "lib.#{name}"
- scope\use value\unwrap 'scope' -- (require "lib.#{name}")\unwrap 'scope'
-
- Result!
-
-fn = ValueStream.meta
- meta:
- name: 'fn'
- summary: "Declare a function."
- examples: { '(fn (p1 [p2…]) body-expr)' }
- description: "
-The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
-function is invoked."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 2, "'fn' takes exactly two arguments"
- { params, body } = tail
-
- assert params.__class == Cell, "'fn's first argument has to be an expression"
- param_symbols = for param in *params.children
- assert param.type == 'sym', "function parameter declaration has to be a symbol"
- param\quote scope
-
- body = body\quote scope
- Result value: with ValueStream.wrap FnDef param_symbols, body, scope
- .meta = {
- summary: "(user defined function)"
- examples: { "(??? #{table.concat [p! for p in *param_symbols], ' '})" }
- }
-
-defn = ValueStream.meta
- meta:
- name: 'defn'
- summary: "Define a function."
- examples: { '(defn name-sym (p1 [p2…]) body-expr)' }
- description: "
-Declare a function and define it as `name-sym` in the current scope.
-The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
-function is invoked."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 3, "'defn' takes exactly three arguments"
- { name, params, body } = tail
-
- name = (name\quote scope)\unwrap 'sym'
- assert params.__class == Cell, "'defn's second argument has to be an expression"
- param_symbols = for param in *params.children
- assert param.type == 'sym', "function parameter declaration has to be a symbol"
- param\quote scope
-
- body = body\quote scope
-
- value = with ValueStream.wrap FnDef param_symbols, body, scope
- .meta =
- :name
- summary: "(user defined function)"
- examples: { "(#{name} #{table.concat [p! for p in *param_symbols], ' '})" }
-
- scope\set name, Result :value
- Result!
-
-do_expr = ValueStream.meta
- meta:
- name: 'do_expr'
- summary: "Evaluate multiple expressions in a new scope."
- examples: { '(do expr1 [expr2…])' }
- description: "
-Evaluate `expr1`, `expr2`, … and return the value of the last expression."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- scope = Scope scope
- Result children: [expr\eval scope for expr in *tail]
-
-if_ = ValueStream.meta
- meta:
- name: 'if'
- summary: "Make an evaltime const choice."
- examples: { '(if bool then-expr [else-expr])' }
- description: "
-`bool` has to be an evaltime constant. If it is truthy, this expression is equivalent
-to `then-expr`, otherwise it is equivalent to `else-xpr` if given, or nil otherwise."
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail >= 2, "'if' needs at least two parameters"
- assert #tail <= 3, "'if' needs at most three parameters"
-
- { xif, xthen, xelse } = tail
-
- xif = L\push xif\eval, scope
- xif = xif\const!\unwrap!
-
- if xif
- xthen\eval scope
- elseif xelse
- xelse\eval scope
-
-trace_ = ValueStream.meta
- meta:
- name: 'trace!'
- summary: "Trace an expression's value at evaltime."
- examples: { '(trace! expr)' }
-
- value: class extends Builtin
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'trace!' takes exactly one parameter"
-
- with result = L\push tail[1]\eval, scope
- L\print "trace! #{tail[1]\stringify!}: #{result.value}"
-
-trace = ValueStream.meta
- meta:
- name: 'trace'
- summary: "Trace an expression's values at runtime."
- examples: { '(trace expr)' }
-
- value: class extends Builtin
- class traceOp extends Op
- setup: (inputs) =>
- super
- prefix: Input.cold inputs[1]
- value: Input.hot inputs[2]
-
- tick: =>
- L\print "trace #{@inputs.prefix!}: #{@inputs.value.stream}"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'trace!' takes exactly one parameter"
-
- tag = @tag\clone Tag.parse '-1'
- inner = Cell tag, {
- LiteralValue 'opdef', traceOp, 'trace'
- ValueStream.str tostring tail[1]
- tail[1]
- }
- inner\eval scope
-
-print = ValueStream.meta
- meta:
- name: 'print'
- summary: "Print string values."
- examples: { '(print str)' }
-
- value: class extends Op
- setup: (inputs) =>
- value = (val.str / evt.str)\match inputs
- super value: Input.hot value
-
- tick: =>
- if @inputs.value\metatype! == 'event'
- for msg in *@inputs.value!
- print msg
- else
- print @inputs.value!
-
-{
- :doc
- :trace, 'trace!': trace_, :print
-
- :def, :use
- require: require_
- import: import_
- 'import*': import_star
-
- true: ValueStream.meta
- meta:
- name: 'true'
- summary: "The boolean constant `true`."
- value: ValueStream.bool true
-
- false: ValueStream.meta
- meta:
- name: 'false'
- summary: "The boolean constant `false`."
- value: ValueStream.bool false
-
- bang: ValueStream.meta
- meta:
- name: 'bang'
- summary: "A `bang` value-constant."
- value: ValueStream 'bang', true
-
- :fn, :defn
- 'do': do_expr
- if: if_
-}
diff --git a/core/cell.moon b/core/cell.moon
deleted file mode 100644
index b028f14..0000000
--- a/core/cell.moon
+++ /dev/null
@@ -1,189 +0,0 @@
-----
--- S-Expression Cell, implements the `AST` interface.
---
--- Consists of a head expression and any number of tail expressions (both `AST`
--- nodes), a `Tag`, and optionally the internal whitespace as parsed.
---
--- @classmod Cell
-import ValueStream from require 'core.stream'
-import Error from require 'core.error'
-import op_invoke, fn_invoke from require 'core.invoke'
-import Tag from require 'core.tag'
-
-local RootCell
-
-class Cell
---- members
--- @section members
-
- new: (@tag=Tag.blank!, @children, @white) =>
- if not @white
- @white = [' ' for i=1,#@children]
- @white[0] = ''
-
- assert #@white == #@children, "mismatched whitespace length"
-
- --- get the head of the cell.
- --
- -- @treturn AST
- head: => @children[1]
-
- --- get the tail of the cell.
- --
- -- @treturn {AST,...}
- tail: => [c for c in *@children[2,]]
-
- __tostring: => @stringify 2
-
- --- the parsed Tag.
- --
- -- @tfield Tag tag
-
- --- sequence of child AST Nodes
- --
- -- @tfield {AST,...} children
-
- --- optional sequence of whitespace segments.
- --
- -- If set, `whitespace[i]` is the whitespace between `children[i]` and
- -- `children[i+1]`, or the closing parenthesis of this Cell. `whitespace[0]`
- -- is the space between the opening parenthesis and `children[1]`.
- --
- -- @tfield ?{string,...} whitespace
-
---- AST interface
---
--- `Cell` implements the `AST` interface.
--- @section ast
-
- --- evaluate this Cell.
- --
- -- `AST:eval`uates the head of the expression, and finds the appropriate
- -- `Builtin` to invoke:
- --
- -- - if head is an `opdef`, use `invoke.op_invoke`
- -- - if head is a `fndef`, use `invoke.fn_invoke`
- -- - if head is a `builtin`, unwrap it
- --
- -- then calls `Builtin:eval_cell` on it.
- --
- -- @tparam Scope scope the scope to evaluate in
- -- @treturn Result the evaluation result
- eval: (scope) =>
- head = assert @head!, Error 'syntax', "cannot evaluate empty expr"
- head = (head\eval scope)\const!
- Builtin = switch head.type
- when 'opdef'
- -- scope\get 'op-invoke'
- op_invoke
- when 'fndef'
- -- scope\get 'fn-invoke'
- fn_invoke
- when 'builtin'
- head\unwrap!
- else
- error Error 'type', "#{head} is not an opdef, fndef or builtin"
-
- Builtin\eval_cell @, scope, head
-
- --- quote this Cell, preserving its identity.
- --
- -- Recursively quotes children, but preserves identity (i.e, shares the
- -- `Tag`). A quoted Cell may only be 'used' once. If you want to `eval` a
- -- `Cell` multiple times, use `clone`.
- --
- -- @treturn Cell
- quote: =>
- children = [child\quote scope for child in *@children]
- Cell @tag, children, @white
-
- --- create a clone with its own identity.
- --
- -- creates a clone of this Cell with its own identity by prepending a `parent`
- -- to `tag` and cloning all child expressions recursively.
- --
- -- @tparam Tag parent
- -- @treturn Cell
- clone: (parent) =>
- tag = @tag\clone parent
- children = [child\clone parent for child in *@children]
- Cell tag, children, @white
-
- --- stringify this Cell.
- --
- -- if `depth` is passed, does not faithfully recreate the original string but
- -- rather create useful debug output.
- --
- -- @tparam[opt] int depth the maximum depth, defaults to infinite
- -- @treturn string the exact string this Cell was parsed from, unless `@tag`
- -- changed
- stringify: (depth=-1) =>
- buf = ''
- buf ..= if depth > 0 then '' else @white[0]
- if depth == 0
- buf ..= '...'
- else
- for i, child in ipairs @children
- buf ..= child\stringify if depth == -1 then -1 else depth - 1
- buf ..= if depth > 0 then ' ' else @white[i]
-
- if depth > 0
- buf = buf\sub 1, #buf - 1
-
- tag = if depth == -1 then @tag\stringify! else ''
-
- '(' .. tag .. buf .. ')'
-
---- static functions
--- @section static
-
- parse_args = (tag, parts) ->
- if not parts
- parts, tag = tag, nil
-
- children, white = {}, { [0]: parts[1] }
-
- for i = 2,#parts,2
- children[i/2] = parts[i]
- white[i/2] = parts[i+1]
-
- tag, children, white
- --- parse a Cell (for parsing with Lpeg).
- --
- -- @tparam[opt] Tag tag
- -- @tparam table parts
- -- @treturn Cell
- @parse: (...) ->
- tag, children, white = parse_args ...
- Cell tag, children, white
-
- --- parse a root Cell (for parsing with Lpeg).
- --
- -- Root-Cells are at the root of an ALV document.
- -- They have an implicit head of 'do' and a `[0]` tag.
- --
- -- @tparam table parts
- -- @treturn Cell
- @parse_root: (...) ->
- tag, children, white = parse_args (Tag.parse '0'), ...
- RootCell tag, children, white
-
--- @type RootCell
-class RootCell extends Cell
- head: => ValueStream.sym 'do'
- tail: => @children
-
- stringify: =>
- buf = ''
- buf ..= @white[0]
-
- for i, child in ipairs @children
- buf ..= child\stringify!
- buf ..= @white[i]
-
- buf
-
-{
- :Cell
- :RootCell
-}
diff --git a/core/config.ld b/core/config.ld
deleted file mode 100644
index f00deba..0000000
--- a/core/config.ld
+++ /dev/null
@@ -1,16 +0,0 @@
-project = 'alive internals'
-title = 'developer docs'
-
-description = "`alive` developer documentation"
-full_description = [[This section documents the *implementation* of the alive
-language and copilot. It is relevant to everyone who is looking to modify,
-improve or extend alive with new modules, language or interpreter features.
-
-If you are looking for the language reference for users, head over to the
-[reference](../reference/index.html) section of the documentation.]]
-
-format = 'discount'
-style = 'docs'
-template = 'docs'
-topics={'core/extensions.md'}
-dir = 'docs/internals'
diff --git a/core/cycle.moon b/core/cycle.moon
deleted file mode 100644
index 57d4a75..0000000
--- a/core/cycle.moon
+++ /dev/null
@@ -1,26 +0,0 @@
--- late-resolve cyclic dependencies
---
--- this module provides a proxy for resolving values from modules which cannot
--- be loaded due to cyclic dependencies. Instead of
---
--- import Something from require 'core.somewhere'
--- Something ...
---
--- use
---
--- import somewhere from require 'core.cycle'
--- somewhere.Something ...
---
--- Make sure cycle:load() is called before you access or dereference
--- `somewhere`.
-
-load = =>
- for name, module in pairs @
- for k, v in pairs require "core.#{name}"
- module[k] = v
-
-setmetatable {}, __index: (key) =>
- return load if key == 'load'
-
- with v = {}
- rawset @, key, v
diff --git a/core/error.moon b/core/error.moon
deleted file mode 100644
index e72cc5f..0000000
--- a/core/error.moon
+++ /dev/null
@@ -1,94 +0,0 @@
-----
--- Language error and traceback.
---
--- @classmod Error
-
-unpack or= table.unpack
-
-class Error
---- members
--- @section members
-
- --- append a traceback frame.
- --
- -- `where` should denote where the Error occured and fit grammatically to
- -- complete the sentence `"{error} occured while {where}"`
- --
- -- @tparam string where
- add_frame: (where) => @trace ..= "\n while #{where}"
-
- __tostring: =>
- str = "#{@kind} error: #{@message}"
- if @detail
- str ..= "\n#{@detail}"
- if @trace
- str ..= @trace
- str
-
---- static functions
--- @section static
-
- --- create a new Error.
- --
- -- `kind` should be one of:
- --
- -- - `'reference'`: error concerning symbol resolution
- -- - `'argument'`: error concerning Op argument matching
- -- - `'implementation'`: error in the Lua/MoonScript implementation of alive.
- -- Should not occur in normal operation, and constitutes a bug.
- --
- -- @classmethod
- -- @tparam string kind
- -- @tparam string message
- -- @tparam ?string detail
- new: (@kind, @message, @detail) =>
- @trace = ''
-
- handler = (err) ->
- if err.__class == Error
- err
- else
- Error 'implementation', err, debug.traceback "Lua error below:", 2
- --- Wrap function errors in a traceback frame.
- --
- -- Execute `fn(...)`, and turn any error thrown as a result into an
- -- `Error` instance, before re-throwing it.
- --
- -- When `Error` instances are caught, `frame` is added to the traceback.
- -- All other error values are turned into `'implementation'` Errors.
- --
- -- @tparam string frame
- -- @tparam function fn
- @wrap: (frame, fn, ...) ->
- results = { xpcall fn, handler, ... }
- ok = table.remove results, 1
- if ok
- unpack results
- else
- error with results[1]
- \add_frame frame
-
- --- Capture and wrap function errors in traceback frame.
- --
- -- Execute `fn(...)`, and turn any error thrown as a result into an
- -- `Error` instance, before re-throwing it.
- --
- -- When `Error` instances are caught, `frame` is added to the traceback.
- -- All other error values are turned into `'implementation'` Errors.
- --
- -- @tparam string frame
- -- @tparam function fn
- -- @treturn boolean `ok` true if exeuction suceeded without errors
- -- @treturn Error|any `error_or_results` the `Error` instance or results
- @try: (frame, fn, ...) ->
- results = { xpcall fn, handler, ... }
- ok = table.remove results, 1
- if ok
- ok, unpack results
- else
- ok, with results[1]
- \add_frame frame
-
-{
- :Error
-}
diff --git a/core/extensions.md b/core/extensions.md
deleted file mode 100644
index 6af9bca..0000000
--- a/core/extensions.md
+++ /dev/null
@@ -1,221 +0,0 @@
-# writing `alive` extensions
-
-Extensions for `alive` are implemented in [Lua][lua] or [MoonScript][moonscript]
-(which runs as Lua). When an `alive` module is [`(require)`][builtins-req]d,
-alive looks for a Lua module `lib.[module]`. You can simply add a new file with
-extension `.lua` or `.moon` in the `lib` directory of your alive installation or
-somewhere else in your `LUA_PATH`.
-
-To write extensions, a number of classes and utilities are required. All of
-these are exported in the `base` module.
-
-## documentation metadata
-The lua module should return a `Scope` or a table that will be converted using
-`Scope.from_table`. All exports should be documented using `ValueStream.meta`,
-which attaches a `meta` table to the value that is used for error messages,
-documentation generation and [`(doc)`][builtins-doc].
-
- import ValueStream from require 'core.base'
-
- two = ValueStream.meta
- meta:
- name: 'two'
- summary: "the number two"
- value: 2
-
- {
- :two
- }
-
-In the `meta` table `summary` is the only required key, but all of the
-information that applies should be provided.
-
-- `name`: the name of this export (for error reporting).
-- `summary`: a one-line plain-text description of this entry. Should be
- capitalized and end with a period.
-- `examples`: a table of strings, each of which is a short one-line code
- example illustrating the argument names for an Op.
-- `description`: a longer markdown-formatted description of the functionality
- of this entry.
-
-## defining `Op`s
-Most extensions will want to define a number of *Op*s to be used by the user.
-They are implemented by deriving from the `Op` class and implementing at least
-the `Op:setup` and `Op:tick` methods.
-
- import ValueStream, Op, Input, evt from require 'core.base'
-
- total_sum = ValueStream.meta
- meta:
- name: 'total-sum'
- summary: "Keep a total of incoming numbers."
- examples: { '(total-sum num!)' }
- description: "Keep a total sum of incoming number events, extension-style."
-
- value: class extends Op
- new: (...) =>
- super ...
- @state or= { total: 0 }
- @out or= ValueStream 'num', @state.total
-
- setup: (inputs, scope) =>
- num = evt.num\match inputs
- super num: Inputs.hot num
-
- tick: =>
- @state.total += @inputs.num!
- @out\set @state.total
-
- {
- 'total-sum': total_sum
- }
-
-### Op:setup
-`Op:setup` is called once every *eval cycle* to parse the Op's arguments, check
-their types, choose the updating behaviour and define the output type.
-
-The arguments to `:setup` are a list of inputs (each is a `Result` instance),
-and the `Scope` the evaluation happened in. Ops generally shouldn't use the
-scope, but might look up 'magic' dynamic symbols like `\*clock\*`.
-
-#### argument parsing
-Arguments should be parsed using `base.match`. The two exports `base.match.val`
-and `base.match.evt` are used to build complex patterns that can parse and
-validate the Op arguments into complex structures (see the module documentation
-for more information).
-
- import val, evt from require 'core.base'
-
- pattern = evt.bang + val.str + val.num*3 + -evt!
- { trig, str, numbers, optional } = pattern\match inputs
-
-This example matches first an `EventStream` of type `bang`, then a `ValueStream`
-of type `str`, followed by one, two or three `num`-values and finally an
-optional argument `EventStream` of any type. `:match` will throw an error if it
-couldn't (fully) match the arguments and otherwise return a structured mapping
-of the inputs.
-
-If there are more complex dependencies between arguments, it is recommended to
-do as much of the parsing as possible using the `base.match` and then continue
-manually. For invalid or missing arguments, `Error` instances should be thrown
-using `error` or `assert`.
-
-#### input setup
-There are two types of inputs: `Input.hot` and `Input.cold`:
-
-*Cold* inputs do not cause the Op to update when changes to the input stream
-are made. They are useful to 'ignore' changes to inputs which are only relevant
-when another input changed value. Imagine for example a `send-value-when` Op,
-which sends a value only when a `bang!` input is live. This Op doesn't have to
-update when the value changes, it's enough to update only when the trigger
-input changes and simply read the value in that moment.
-
-*Hot* inputs on the other hand mark the input stream as a dependency for the
-Op. Depending on the type of `Stream`, the semantics are a little different:
-
-- For `ValueStream`s, the Op updates whenever the current value changes. When
- an input stream is swapped out for another one at evaltime, but their values
- are momentarily equal, the input is not considered dirty.
-- For `EventStream`s and `IOStream`s, the Op updates whenever the stream is
- dirty. There is no special handling when the stream is swapped out at
- evaltime.
-
-All `Result`s from the `inputs` argument that are taken into consideration
-should be wrapped in an `Input` instance using either `Input.hot` or
-`Input.cold`, and need to be passed to the `Op:setup` super implementation.
-To illustrate with the `send-value-when` example:
-
- setup: (inputs, scope) =>
- { trig, value } = match 'bang! any', inputs
-
- super
- trig: Inputs.hot trig
- value: Inputs.cold value
-
-`Op:setup` takes a table that can have any (even nested) shape you want, as
-long as all 'leaf values' are `Input` instances. The following are both valid:
-
- super { (Inputs.hot trig), (Inputs.cold value) }
-
- super
- trigger: Inputs.hot trig
- values: { (Inputs.cold a), (Inputs.cold b), (Inputs.cold c) }
-
-#### output setup
-When `Op:setup` finishes, `@out` has to be set to a `Stream` instance. The
-instance can be created in `Op:setup`, or by overriding the constructor and
-delegating to the original one using `super`. In general setting it in the
-constructor is preferred, and it is only moved to `Op:setup` if the output
-type depends on the arguments received.
-
-There are three types of `Stream`s that can be created:
-
-- `ValueStream`s track *continuous values*. They can only have one value per
- tick, and downstream Ops will not update when a *ValueStream* has been set
- to the same value it already had. They are updated using `ValueStream:set`.
-- `EventStream`s transmit *momentary events*. They can transmit multiple events
- in a single tick. `EventStream`s do not keep a value set on the last tick on
- the next tick. They are updated using `EventStream:add`.
-- `IOStream`s are like `EventStream`s, but their `IOStream:tick` method is
- polled by the event loop at the start of every tick. This gives them a chance
- to effectively create changes 'out of thin air' and kickstart the execution
- of the dataflow engine. All *runtime* execution is due to an `IOStream`
- becoming dirty somewhere. See the section on implementing `IOStream`s below
- for more information.
-
-### Op:tick
-`Op:tick` is called whenever any of the inputs are *dirty*. This is where the
-Op's main logic will go. Generally here it should be checked which input(s)
-changed, and then internal state and the output value may be updated.
-
-## defining `Builtin`s
-Builtins are more powerful than Ops, because they control whether, which and
-how their arguments are evaluated. They roughly correspond to *macros* in Lisps.
-There is less of a concrete guideline for implementing Builtins because there
-are a lot more options, and it really depends a lot on what the Builtin should
-achieve. Nevertheless, a good starting point is to read the `Builtin` class
-documentation, take a look at `Builtin`s in `core/builtin.moon` and get
-familiar with the relevant internal interfaces (especially `AST`, `Result`, and
-`Scope`).
-
-## defining `IOStream`s
-`IOStream`s are `EventStream`s that can 'magically' create events out of
-nothing. They are the source of all processing in alive. Whenever you want to
-bring events into alive from an external protocol or application, an IOStream
-will be necessary.
-
-To implement a custom IOStream, create it as a class that inherits from the
-`IOStream` base and implement the constructor and `IOStream:tick`:
-
- import IOStream from require 'core.base'
-
- class UnreliableStream extends IOStream
- new: => super 'bang'
-
- tick: =>
- if math.random! < 0.1
- @add true
-
-In the constructor, you should call the super-constructor `EventStream.new` to
-set the event type. Often this will be a custom event that is only used inside
-your extension (such as e.g. the `midi/port` type in the [midi][modules-midi]
-module), but it can also be a primitive type like `'num'` in this example. In
-`:tick`, your IOStream is given a chance to communicate with the external world
-and create any resulting events. The example stream above randomly sends bang
-events out, with a 10% chance each 'tick' of the system. Note that there is no
-guarantee about when or how often ticks occur, so you really shouldn't rely on
-them this way in a real extension.
-
-### using `IOStream`s
-There's a couple of ways IOStreams can be used and exposed to the user of your
-extension. You can either expose an instance of your IOStream directly
-(documented using `ValueStream.meta`), or offer an Op that creates and returns
-an instance in `Op.out` - that way the IOStream can be created only on demand
-and take parameters. It is also possible to not exepose the IOStream at all,
-and rather pass it as a hardcoded input into an Op's `Op.inputs`.
-
-[lua]: https://www.lua.org/
-[moonscript]: http://moonscript.org/
-[builtins-req]: ../../reference/index.html#require
-[builtins-doc]: ../../reference/index.html#doc
-[modules-midi]: ../../reference/midi.html
diff --git a/core/init.moon b/core/init.moon
deleted file mode 100644
index 6e23fa7..0000000
--- a/core/init.moon
+++ /dev/null
@@ -1,55 +0,0 @@
-----
--- `alive` public API.
---
--- @module init
-L or= setmetatable {}, __index: => ->
-
-import ValueStream, EventStream, IOStream from require 'core.stream'
-import Result from require 'core.result'
-import Scope from require 'core.scope'
-import Error from require 'core.error'
-import Registry, SimpleRegistry from require 'core.registry'
-import Tag from require 'core.tag'
-
-import Cell from require 'core.cell'
-import cell, program from require 'core.parsing'
-
-with require 'core.cycle'
- \load!
-
-globals = Scope.from_table require 'core.builtin'
-
---- exports
--- @table exports
--- @tfield ValueStream ValueStream
--- @tfield EventStream EventStream
--- @tfield IOStream IOStream
--- @tfield Result Result
--- @tfield Cell Cell
--- @tfield RootCell RootCell
--- @tfield Scope Scope
--- @tfield Error Error
--- @tfield Registry Registry
--- @tfield Tag Tag
--- @tfield Scope globals global definitons
--- @tfield parse function to turn a `string` into a root `Cell`
-{
- :ValueStream, :EventStream, :IOStream
- :Cell, :RootCell
- :Result, :Scope, :Error
-
- :Registry, :SimpleRegistry, :Tag
-
- :globals
-
- parse: (str) ->
- assert (program\match str), Error 'syntax', "failed to parse"
-
- eval: (str, inject) ->
- scope = Scope nil, globals
- scope\use inject if inject
-
- ast = assert (program\match str), "failed to parse"
- result = ast\eval scope
- result\const!
-}
diff --git a/core/invoke.moon b/core/invoke.moon
deleted file mode 100644
index 8fcb525..0000000
--- a/core/invoke.moon
+++ /dev/null
@@ -1,124 +0,0 @@
-----
--- Builtins for invoking `Op`s and `FnDef`s.
---
--- @module invoke
-import Result from require 'core.result'
-import Builtin from require 'core.base'
-import Scope from require 'core.scope'
-import Error from require 'core.error'
-
-get_name = (value, raw) ->
- meta = if value.meta then value.meta.name
- locl = if raw and raw.type == 'sym' then raw!
-
- if locl
- if meta and meta != locl
- "'#{meta}' (local '#{locl}')"
- else
- "'#{locl}'"
- else if meta
- "'#{meta}'"
- else
- "(unnamed)"
-
---- `Builtin` implementation that invokes an `Op`.
---
--- @type op_invoke
-class op_invoke extends Builtin
- --- `Builtin:setup` implementation.
- --
- -- `Op:fork`s the `prev`'s `Op` instance if given. Creates a new instance
- -- otherwise.
- setup: (prev) =>
- if prev
- @op = prev.op\fork!
- else
- def = @head\unwrap 'opdef', "cant op-invoke #{@head}"
- @op = def!
-
- --- `Builtin:destroy` implementation.
- --
- -- calls `op`:@{Op:destroy|destroy}.
- destroy: => @op\destroy!
-
- --- evaluate an `Op` invocation.
- --
- -- `AST:eval`s the tail, and passes the result to `op`:@{Op:setup|setup}. Then
- -- checks if any of `op`:@{Op:all_inputs|all_inputs} are @{Input:dirty|dirty},
- -- and if so, calls `op`:@{Op:tick|tick}.
- --
- -- The `Result` contains `op`, `Op.value` and all the `Result`s from the tail.
- --
- -- @tparam Scope scope the active scope
- -- @tparam {AST,...} tail the arguments to this expression
- -- @treturn Result
- eval: (scope, tail) =>
- children = [L\push expr\eval, scope for expr in *tail]
-
- frame = "invoking op #{get_name @head, @cell\head!} at [#{@tag}]"
- Error.wrap frame, @op\setup, [result for result in *children], scope
-
- any_dirty = false
- for input in @op\all_inputs!
- if input\dirty!
- any_dirty = true
- break
-
- if any_dirty
- @op\tick true
-
- for input in @op\all_inputs!
- input\finish_setup!
-
- Result :children, value: @op.out, op: @op
-
- --- The `Op` instance.
- --
- -- @tfield Op op
-
---- `Builtin` implementation that invokes a `FnDef`.
---
--- @type fn_invoke
-class fn_invoke extends Builtin
- --- evaluate a user-function invocation.
- --
- -- Creates a new `Scope` that inherits from `FnDef.scope` and has
- -- `outer_scope` as an additional parent for dynamic symbol resolution.
- -- Then `AST:eval`s the tail in `outer_scope`, and defines the results to the
- -- names in `FnDef.params` in the newly created scope. Lastly, `AST:clone`s
- -- `FnDef.body` with the prefix `Builtin.tag`, and `AST:eval`s it in the newly
- -- created `Scope`.
- --
- -- The `Result` contains the `Stream` from the cloned AST, and its children
- -- are all the `Result`s from evaluating the tail as well as the cloned
- -- `AST`s.
- --
- -- @tparam Scope outer_scope the active scope
- -- @tparam {AST,...} tail the arguments to this expression
- -- @treturn Result the result of this evaluation
- eval: (outer_scope, tail) =>
- name = get_name @head, @cell\head!
- frame = "invoking function #{name} at [#{@tag}]"
-
- { :params, :body, :scope } = @head\unwrap 'fndef', "cant fn-invoke #{@head}"
- if #params != #tail
- err = Error 'argument', "expected #{#params} arguments, found #{#tail}"
- err\add_frame frame
- error err
-
- fn_scope = Scope scope, outer_scope
-
- children = for i=1,#params
- name = params[i]\unwrap 'sym'
- with L\push tail[i]\eval, outer_scope
- fn_scope\set name, \make_ref!
-
- clone = body\clone @tag
- result = Error.wrap frame, clone\eval, fn_scope
-
- table.insert children, result
- Result :children, value: result.value
-
-{
- :op_invoke, :fn_invoke
-}
diff --git a/core/parsing.moon b/core/parsing.moon
deleted file mode 100644
index aadcab4..0000000
--- a/core/parsing.moon
+++ /dev/null
@@ -1,73 +0,0 @@
-----
--- Lpeg Grammar for parsing `alive` code.
---
--- @module parsing
-import ValueStream from require 'core.stream'
-import Cell from require 'core.cell'
-import Tag from require 'core.tag'
-import R, S, P, V, C, Ct from require 'lpeg'
-
--- whitespace
-wc = S ' \t\r\n'
-comment = P {
- 'comment',
- expr: (P '(') * ((V 'expr') + (1 - P ')'))^0 * (P ')')
- comment: (P '#(') * ((V 'expr') + (1 - P ')'))^0 * (P ')')
-}
-space = (wc^1 * (comment * wc^1)^0) / 1 -- required whitespace
-mspace = (comment + wc)^0 / 1 -- optional whitespace
-
--- atoms
-digit = R '09'
-first = (R 'az', 'AZ') + S '-_+*/.!?=%'
-sym = first * (first + digit)^0 / ValueStream\parse 'sym'
-
-strd = '"' * (C ((P '\\"') + (P '\\\\') + (1 - P '"'))^0) * '"' / ValueStream\parse 'str', '\"'
-strq = "'" * (C ((P "\\'") + (P '\\\\') + (1 - P "'"))^0) * "'" / ValueStream\parse 'str', '\''
-str = strd + strq
-
-int = digit^1
-float = (digit^1 * '.' * digit^0) + (digit^0 * '.' * digit^1)
-num = ((P '-')^-1 * (float + int)) / ValueStream\parse 'num'
-
-atom = num + sym + str
-
-expr = (V 'cell') + atom
-explist = Ct mspace * ((V 'expr') * (space * (V 'expr'))^0 * mspace)^-1
-
-tag = (P '[') * (digit^1 / Tag.parse) * (P ']')
-cell = (P '(') * tag^-1 * (V 'explist') * (P ')') / Cell.parse
-
-root = P {
- (V 'explist') / Cell.parse_root
- :expr, :explist, :cell
-}
-
-cell = P {
- 'cell'
- :expr, :explist, :cell
-}
-
-program = root * -1
-
---- exports
--- @table exports
--- @tfield pattern comment
--- @tfield pattern space
--- @tfield pattern atom
--- @tfield pattern expr
--- @tfield pattern explist
--- @tfield pattern explist
--- @tfield pattern cell
--- @tfield pattern root
--- @tfield pattern program the main parsing entrypoint
-{
- :comment
- :space
- :atom
- :expr
- :explist
- :cell
- :root
- :program
-}
diff --git a/core/registry.moon b/core/registry.moon
deleted file mode 100644
index a0134ec..0000000
--- a/core/registry.moon
+++ /dev/null
@@ -1,145 +0,0 @@
-----
--- `Tag` Registry.
---
--- @classmod Registry
-import Result from require 'core.result'
-import Error from require 'core.error'
-
-class Registry
---- internals for `Tag`
--- @section internals
-
- --- lookup the last registration.
- --
- -- @tparam number|string index the registration index
- -- @treturn any
- last: (index) => @last_map[index]
-
- --- set the current registration.
- --
- -- @tparam string\number index the registration index
- -- @tparam any expr the registration value
- -- @tparam[default=false] boolean ignore_dup ignore duplicate registrations
- register: (index, expr, ignore_dup=false) =>
- L\trace "reg: setting #{index} to #{expr}"
- if not ignore_dup and @map[index]
- error Error 'tag', "duplicate tags [#{index}]!"
- @map[index] = expr
-
- --- request identity and registration for blank tag.
- --
- -- @tparam Tag tag the blank tag
- -- @tparam any expr the registration value
- init: (tag, expr) =>
- L\trace "reg: init pending to #{expr}"
- table.insert @pending, { :tag, :expr }
-
---- members
--- @section members
-
- --- begin an evaluation cycle.
- --
- -- Begin an evaltime cycle (and tick).
- -- Set the active Registry and clear out pending registrations.
- --
- -- All calls go `begin_eval` must be matched with either a call to
- -- `end_eval` or `rollback_eval`.
- begin_eval: =>
- @latest_map = @last_map
- @begin_tick!
- @map, @pending = {}, {}
-
- --- end an evaluation cycle.
- --
- -- Register all pending `Tag`s and destroy all orphaned registrations.
- -- Unset the active Registry.
- end_eval: =>
- for tag, val in pairs @last_map
- val\destroy! unless @map[tag]
-
- for { :tag, :expr } in *@pending
- -- tag was solved by another pending registration
- -- (e.g. first [A] is solved, then [5.A] is solved)
- continue if tag\index!
-
- next_tag = #@map + 1
- L\trace "assigned new tag #{next_tag} to #{tag} #{expr}"
- tag\set next_tag
- @map[tag\index!] = expr
-
- @last_map = @map
- @end_tick!
-
- --- abort an evaluation cycle.
- --
- -- Unset the active Registry.
- rollback_eval: =>
- @end_tick!
-
- --- begin a run cycle.
- --
- -- Increment the tick index and set the active Registry.
- begin_tick: =>
- @grab!
- @next_tick!
-
- --- end a run cycle.
- --
- -- Unset the active Registry.
- end_tick: =>
- @release!
-
- --- manually increment the tick index (for testing).
- next_tick: =>
- @tick += 1
-
- --- set the active Registry.
- grab: =>
- assert not @prev, "already have a previous registry? #{@prev}"
- @prev, Registry.active_registry = Registry.active_registry, @
-
- --- unset the active Registry.
- release: =>
- assert @ == Registry.active_registry, "not the active registry!"
- Registry.active_registry, @prev = @prev, nil
-
---- static functions
--- @section static
-
- --- create a new Registry.
- -- @classmethod
- new: =>
- @last_map, @map = {}, {}
- @tick = 0
-
- --- get the active Registry.
- --
- -- Raises an erro when there is no active Regsitry.
- --
- -- @treturn Registry
- @active: -> assert Registry.active_registry, "no active Registry!"
-
-class SimpleRegistry extends Registry
- new: =>
- @cnt = 1
- @tick = 0
-
- next_tick: =>
- @tick += 1
-
- init: (tag, expr) =>
- tag\set @cnt
- @cnt += 1
-
- last: (index) =>
- register: (index, expr) =>
-
- wrap: (fn) => (...) ->
- @grab!
- with fn ...
- @release!
-
-{
- :Registry
- :SimpleRegistry
-}
diff --git a/core/result.moon b/core/result.moon
deleted file mode 100644
index 6c994cb..0000000
--- a/core/result.moon
+++ /dev/null
@@ -1,126 +0,0 @@
-----
--- Result of evaluating an expression.
---
--- `Result`s form a tree that controls execution order and message passing
--- between `Op`s.
---
--- @classmod Result
-class Result
---- members
--- @section members
-
- --- return whether this Result's value is const.
- is_const: => not next @side_inputs
-
- --- assert value-constness and return the value.
- -- @tparam[opt] string msg the error message to throw
- -- @treturn any
- const: (msg) =>
- assert not (next @side_inputs), msg or "eval-time const expected"
- @value
-
- --- assert this result has a value, return its type.
- -- @treturn string
- type: =>
- assert @value, "Result with value expected"
- @value.type
-
- --- assert this result has a value, returns its metatype.
- -- @treturn string `"value"` or `"event"`
- metatype: =>
- assert @value, "Result with value expected"
- @value.metatype
-
- --- create a copy of this result with value-copy semantics.
- -- the copy has the same @value and @side_inputs, but will not update
- -- anything on \tick.
- make_ref: =>
- with Result value: @value
- .side_inputs = @side_inputs
-
- --- tick all IOStream instances that are effecting this (sub)tree.
- -- should be called once per frame on the root, right before tick.
- tick_io: =>
- for stream, input in pairs @side_inputs
- stream\tick! if input.io
-
- --- in depth-first order, tick all Ops which have dirty Inputs.
- --
- -- short-circuits if there are no dirty Inputs in the entire subtree
- tick: =>
- any_dirty = false
- for stream, input in pairs @side_inputs
- if input\dirty!
- any_dirty = true
- break
-
- -- early-out if no Inputs are dirty in this whole subtree
- return unless any_dirty
-
- for child in *@children
- child\tick!
-
- if @op
- -- we have to check self_dirty here, because Inputs from children may
- -- have become dirty due to \tick
- self_dirty = false
- for stream in @op\all_inputs!
- if stream\dirty!
- self_dirty = true
-
- return unless self_dirty
-
- @op\tick!
-
- __tostring: =>
- buf = "<result=#{@value}"
- buf ..= " #{@op}" if @op
- buf ..= " (#{#@children} children)" if #@children > 0
- buf ..= ">"
- buf
-
- --- the `Stream` result
- --
- -- @tfield ?Stream value
-
- --- an Op
- --
- -- @tfield ?Op op
-
- --- list of child `Result`s from subexpressions
- --
- -- @tfield {}|{Result,...} children
-
- --- cached mapping of all `Stream`/`Input` pairs affecting this Result.
- --
- -- This is the union of all `children`s `side_inputs` and all `Input`s from
- -- `op` that are not the `value` of any child.
- --
- -- @tfield {[Stream]=Input,...} side_inputs
-
---- static functions
--- @section static
-
- --- create a new Result.
- -- @classmethod
- -- @param params table with optional keys op, value, children. default: {}
- new: (params={}) =>
- @value = params.value
- @op = params.op
- @children = params.children or {}
-
- @side_inputs, is_child = {}, {}
- for child in *@children
- for stream, input in pairs child.side_inputs
- @side_inputs[stream] = input
- if child.value
- is_child[child.value] = true
-
- if @op
- for input in @op\all_inputs!
- if input.io or not is_child[input.stream]
- @side_inputs[input.stream] = input
-
-{
- :Result
-}
diff --git a/core/scope.moon b/core/scope.moon
deleted file mode 100644
index 526ca8d..0000000
--- a/core/scope.moon
+++ /dev/null
@@ -1,118 +0,0 @@
-----
--- Mapping from `sym`s to `Result`s.
---
--- @classmod Scope
-import ValueStream from require 'core.stream'
-import Result from require 'core.result'
-import Error from require 'core.error'
-
-class Scope
---- members
--- @section members
-
- --- set a Lua value in the scope.
- --
- -- wraps `val` in a `ValueStream` and `Result` before calling `set`.
- --
- -- @tparam string key
- -- @tparam any val
- set_raw: (key, val) =>
- value = ValueStream.wrap val, key
- @values[key] = Result :value
-
- --- set a symbol to a `Result`.
- --
- -- @tparam string key
- -- @tparam Result val
- set: (key, val) =>
- L\trace "setting #{key} = #{val} in #{@}"
- assert val.__class == Result, "expected #{key}=#{val} to be Result"
- assert val.value, Error 'type', "cannot define symbol to nil"
- assert not @values[key], Error 'type', "cannot redefine symbol '#{key}'!"
- @values[key] = val
-
- recurse: (key) =>
- parent = if key\match '^%*.*%*$' then @dynamic_parent else @parent
- parent or= @parent
- if parent
- L\push parent\get, key
- else
- error Error 'reference', "undefined symbol '#{key}'"
-
- --- resolve a key in this Scope.
- --
- -- @tparam string key the key to resolve
- -- @treturn ?Result the value of the definition that was found, or `nil`
- get: (key) =>
- L\debug "checking for #{key} in #{@}"
- if val = @values[key]
- L\trace "found #{val} in #{@}"
- return val
-
- start, rest = key\match '^(.-)/(.+)'
- if not start
- return @recurse key
-
- child = @get start
- if not child
- error Error 'reference', "undefined symbol '#{start}'"
- if child\type! != 'scope'
- error Error 'reference', "'#{start}' is not a scope"
- child.value!\get rest, while_msg
-
- --- copy definitions from another scope.
- --
- -- copies all definitions from `other`. Does not copy inherited definitions.
- --
- -- @tparam Scope other
- use: (other) =>
- L\trace "using defs from #{other} in #{@}"
- for k, v in pairs other.values
- @values[k] = v
-
- __tostring: =>
- buf = "<Scope"
-
- depth = -1
- parent = @parent
- while parent
- depth += 1
- parent = parent.parent
- buf ..= " ^#{depth}" if depth != 0
-
- keys = [key for key in pairs @values]
- if #keys > 5
- keys = [key for key in *keys[,5]]
- keys[6] = '...'
- buf ..= " [#{table.concat keys, ', '}]"
-
- buf ..= ">"
- buf
-
---- static functions
--- @section static
-
- --- create a new Scope.
- --
- -- @classmethod
- -- @tparam[opt] Scope parent a parent this scope inherits definitions from
- -- @tparam[opt] Scope dynamic_parent a parent scope that should be checked for
- -- dynamic definitions
- new: (@parent, @dynamic_parent) =>
- @values = {}
-
- --- convert a Lua table to a Scope.
- --
- -- `tbl` may contain more tables (or `Scope`s).
- -- Uses `ValueStream.wrap` on the values recursively.
- --
- -- @tparam table tbl the table to convert
- -- @treturn Scope
- @from_table: (tbl) ->
- with Scope!
- for k, v in pairs tbl
- \set_raw k, v
-
-{
- :Scope
-}
diff --git a/core/stream/base.moon b/core/stream/base.moon
deleted file mode 100644
index 37cc8a4..0000000
--- a/core/stream/base.moon
+++ /dev/null
@@ -1,68 +0,0 @@
-----
--- base Stream interface.
---
--- implemented by `ValueStream`, `EventStream`, and `IOStream`.
---
--- @classmod Stream
-
-class Stream
---- Stream interface.
---
--- Methods that have to be implemented by `Stream` implementations
--- (`ValueStream`, `EventStream`, `IOStream`).
---
--- @section interface
-
- --- return whether this Stream was changed in the current tick.
- --
- -- @function dirty
- -- @treturn boolean
-
- --- create a mutable copy of this Stream.
- --
- -- Used to insulate eval-cycles from each other.
- --
- -- @function fork
- -- @treturn Stream
-
- --- the type name of this Stream's value.
- --
- -- the following builtin typenames are used:
- --
- -- - `str` - strings, `value` is a Lua string
- -- - `sym` - symbols, `value` is a Lua string
- -- - `num` - numbers, `value` is a Lua number
- -- - `bool` - booleans, `value` is a Lua boolean
- -- - `bang` - trigger signals, `value` is a Lua boolean
- -- - `opdef` - `value` is an `Op` subclass
- -- - `builtin` - `value` is a `Builtin` subclass
- -- - `fndef` - `value` is a `FnDef` instance
- -- - `scope` - `value` is a `Scope` instance
- --
- -- @tfield string type
-
- --- documentation metadata.
- --
- -- an optional table containing metadata for error messages and
- -- documentation. The following keys are recognized:
- --
- -- - `name`: optional name
- -- - `summary`: single-line description (markdown)
- -- - `examples`: optional list of single-line code examples
- -- - `description`: optional full-text description (markdown)
- --
- -- @tfield ?table meta
-
---- static functions
--- @section static
-
- --- construct a new Stream.
- --
- -- @classmethod
- -- @tparam string type the type name
- -- @tparam ?table meta the `meta` table
- new: (@type, @meta={}) =>
-
-{
- :Stream
-}
diff --git a/core/stream/event.moon b/core/stream/event.moon
deleted file mode 100644
index 7712fc4..0000000
--- a/core/stream/event.moon
+++ /dev/null
@@ -1,100 +0,0 @@
-----
--- Stream of momentary events.
---
--- @classmod EventStream
-import Stream from require 'core.stream.base'
-import Result from require 'core.result'
-import Error from require 'core.error'
-import scope, base, registry from require 'core.cycle'
-
-class EventStream extends Stream
---- members
--- @section members
-
- --- return whether this stream was changed in the current tick.
- --
- -- @treturn bool
- dirty: => @updated == registry.Registry.active!.tick
-
- --- push an event value into the stream.
- --
- -- Marks this stream as dirty for the remainder of the current tick.
- --
- -- @tparam any event
- add: (event) =>
- if not @dirty!
- @events = {}
-
- @updated = registry.Registry.active!.tick
- table.insert @events, event
-
- --- get the sequence of current events (if any).
- --
- -- Returns `events` if `dirty`, or an empty table otherwise.
- -- Asserts `@type == type` if `type` is given.
- --
- -- @tparam[opt] string type the type to check for
- -- @tparam[optchain] string msg message to throw if type don't match
- -- @treturn {any,...} `events`
- unwrap: (type, msg) =>
- assert type == @type, msg or "#{@} is not a #{type}" if type
- if @dirty! then @events else {}
-
- --- create a mutable copy of this stream.
- --
- -- Used to wrap insulate eval-cycles from each other.
- --
- -- @treturn EventStream
- fork: => @@ @type
-
- --- alias for `unwrap`.
- __call: (...) => @unwrap ...
-
- __tostring: =>
- "<#{@@__name} #{@type}>"
-
- --- Stream metatype.
- --
- -- @tfield string metatype
- metatype: 'event'
-
- --- the type name of the stream.
- --
- -- the following builtin typenames are used:
- --
- -- - `str` - strings, `value` is a Lua string
- -- - `sym` - symbols, `value` is a Lua string
- -- - `num` - numbers, `value` is a Lua number
- -- - `bool` - booleans, `value` is a Lua boolean
- -- - `bang` - trigger signals, `value` is a Lua boolean
- -- - `opdef` - `value` is an `Op` subclass
- -- - `builtin` - `value` is a `Builtin` subclass
- -- - `fndef` - `value` is a `FnDef` instance
- -- - `scope` - `value` is a `Scope` instance
- --
- -- @tfield string type
-
- --- documentation metadata.
- --
- -- an optional table containing metadata for error messages and
- -- documentation. The following keys are recognized:
- --
- -- - `name`: optional name
- -- - `summary`: single-line description (markdown)
- -- - `examples`: optional list of single-line code examples
- -- - `description`: optional full-text description (markdown)
- --
- -- @tfield ?table meta
-
---- static functions
--- @section static
-
- --- construct a new EventStream.
- --
- -- @classmethod
- -- @tparam string type the type name
- new: (type) => super type
-
-{
- :EventStream
-}
diff --git a/core/stream/init.moon b/core/stream/init.moon
deleted file mode 100644
index 3fff136..0000000
--- a/core/stream/init.moon
+++ /dev/null
@@ -1,18 +0,0 @@
-----
--- `Stream` interface and implementations.
---
--- @see Stream
--- @see ValueStream
--- @see EventStream
--- @see IOStream
---
--- @module stream
-import ValueStream from require 'core.stream.value'
-import EventStream from require 'core.stream.event'
-import IOStream from require 'core.stream.io'
-
-{
- :ValueStream
- :EventStream
- :IOStream
-}
diff --git a/core/stream/io.moon b/core/stream/io.moon
deleted file mode 100644
index e3e59a2..0000000
--- a/core/stream/io.moon
+++ /dev/null
@@ -1,55 +0,0 @@
-----
--- Stream of external side-effects.
---
--- Unlike other `Stream`s, this is not updated/set by an `Op` instace, but is
--- continuously polled for changes by the runtime and may mark itself as
--- *dirty* at any point in time. All runtime execution happens due to IOStream
--- updates, which ripple through the `Result` tree.
---
--- @classmod IOStream
-import EventStream from require 'core.stream.event'
-
-class IOStream extends EventStream
---- IOStream interface.
---
--- methods that have to be implemented by `IOStream` implementations.
--- @section interface
-
- --- construct a new IOStream.
- --
- -- Must prepare the instance for `dirty` to be called.
- -- The super-constructor should be called to set `Stream.type`.
- --
- -- @classmethod
- -- @tparam string type the typename of this stream.
- new: (type) => super type
-
- --- create a mutable copy of this stream.
- --
- -- Used to wrap insulate eval-cycles from each other.
- --
- -- @treturn IOStream
- fork: => @
-
- --- 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.hot` should be notified (via `Op:tick`). May be called multiple
- -- times. May be called before `tick` on the first frame after construction.
- --
- -- If this is not overrided, the `EventStream` interface can be used, see
- -- `EventStream.add`, `EventStream.unwrap`, and `EventStream.dirty`.
- --
- -- @function dirty
- -- @treturn bool whether processing is required
-
- __inherited: (cls) => cls.__base.__tostring = @__tostring
-
-{
- :IOStream
-}
diff --git a/core/stream/value.moon b/core/stream/value.moon
deleted file mode 100644
index 68e16b0..0000000
--- a/core/stream/value.moon
+++ /dev/null
@@ -1,237 +0,0 @@
-----
--- Continuous stream of values.
---
--- Implements the `Stream` and `AST` intefaces.
---
--- @classmod ValueStream
-import Stream from require 'core.stream.base'
-import Result from require 'core.result'
-import Error from require 'core.error'
-import scope, base, registry from require 'core.cycle'
-
-ancestor = (klass) ->
- assert klass, "cant find the ancestor of nil"
- while klass.__parent
- klass = klass.__parent
- klass
-
-class ValueStream extends Stream
---- members
--- @section members
-
- --- return whether this stream was changed in the current tick.
- --
- -- @treturn bool
- dirty: => @updated == registry.Registry.active!.tick
-
- --- update this stream's value.
- --
- -- Marks this stream as dirty for the remainder of the current tick.
- set: (@value) => @updated = registry.Registry.active!.tick
-
- --- unwrap to the Lua type.
- --
- -- Asserts `@type == type` if `type` is given.
- --
- -- @tparam[opt] string type the type to check for
- -- @tparam[optchain] string msg message to throw if type don't match
- -- @treturn any `value`
- unwrap: (type, msg) =>
- assert type == @type, msg or "#{@} is not a #{type}" if type
- @value
-
- --- create a mutable copy of this stream.
- --
- -- Used to insulate eval-cycles from each other.
- --
- -- @treturn ValueStream
- fork: =>
- with ValueStream @type, @value, @raw
- .updated = @updated
-
- --- alias for `unwrap`.
- __call: (...) => @unwrap ...
-
- --- compare two values.
- --
- -- Compares two `ValueStream`s by comparing their types and their Lua values.
- __eq: (other) => other.type == @type and other.value == @value
-
- __tostring: =>
- value = if @meta.name
- @meta.name
- else if 'table' == (type @value) and rawget @value, '__base'
- @value.__name
- else
- tostring @value
- "<#{@@__name} #{@type}: #{value}>"
-
- --- Stream metatype.
- --
- -- @tfield string metatype
- metatype: 'value'
-
- --- the type name of this stream.
- --
- -- the following builtin typenames are used:
- --
- -- - `str` - strings, `value` is a Lua string
- -- - `sym` - symbols, `value` is a Lua string
- -- - `num` - numbers, `value` is a Lua number
- -- - `bool` - booleans, `value` is a Lua boolean
- -- - `bang` - trigger signals, `value` is a Lua boolean
- -- - `opdef` - `value` is an `Op` subclass
- -- - `builtin` - `value` is a `Builtin` subclass
- -- - `fndef` - `value` is a `FnDef` instance
- -- - `scope` - `value` is a `Scope` instance
- --
- -- @tfield string type
-
- --- the wrapped Lua value.
- -- @tfield any value
-
- --- documentation metadata.
- --
- -- an optional table containing metadata for error messages and
- -- documentation. The following keys are recognized:
- --
- -- - `name`: optional name
- -- - `summary`: single-line description (markdown)
- -- - `examples`: optional list of single-line code examples
- -- - `description`: optional full-text description (markdown)
- --
- -- @tfield ?table meta
-
---- AST interface
---
--- `ValueStream` implements the `AST` interface.
--- @section ast
-
- --- evaluate this literal constant.
- --
- -- Throws an error if `type` is not a literal (`num`, `str` or `sym`).
- -- Returns an eval-time const result for `num` and `str`.
- -- Resolves `sym`s in `scope` and returns a reference to them.
- --
- -- @tparam Scope scope the scope to evaluate in
- -- @treturn Result the evaluation result
- eval: (scope) =>
- switch @type
- when 'num', 'str'
- Result value: @
- when 'sym'
- Error.wrap "resolving symbol '#{@value}'", scope\get, @value
- else
- error "cannot evaluate #{@}"
-
- --- quote this literal constant.
- --
- -- @treturn ValueStream self
- quote: => @
-
- --- stringify this literal constant.
- --
- -- Throws an error if `raw` is not set.
- --
- -- @treturn string the exact string this stream was parsed from
- stringify: => assert @raw, "stringifying ValueStream that wasn't parsed"
-
- --- clone this literal constant.
- --
- -- @treturn ValueStream self
- clone: (prefix) => @
-
---- static functions
--- @section static
-
- --- construct a new ValueStream.
- --
- -- @classmethod
- -- @tparam string type the type name
- -- @tparam any value the Lua value to be accessed through `unwrap`
- -- @tparam string raw the raw string that resulted in this value. Used by `parsing`.
- new: (type, @value, @raw) => super type
-
- unescape = (str) -> str\gsub '\\([\'"\\])', '%1'
- --- create a capture-function (for parsing with Lpeg).
- --
- -- @tparam string type the type name (one of `num`, `sym` or `str`)
- -- @tparam string sep the seperator char (only for `str`)
- @parse: (type, sep) =>
- switch type
- when 'num' then (match) -> @ 'num', (tonumber match), match
- when 'sym' then (match) -> @ 'sym', match, match
- when 'str' then (match) -> @ 'str', (unescape match), sep .. match .. sep
-
- --- wrap a Lua value.
- --
- -- Attempts to guess the type and wrap a Lua value.
- --
- -- @tparam any val the value to wrap
- -- @tparam[opt] string name the name of this value (for error logging)
- -- @treturn ValueStream
- @wrap: (val, name='(unknown)') ->
- typ = switch type val
- when 'number' then 'num'
- when 'string' then 'str'
- when 'table'
- if rawget val, '__base'
- -- a class
- switch ancestor val
- when base.Op then 'opdef'
- when base.Builtin then 'builtin'
- else
- error "#{name}: cannot wrap class '#{val.__name}'"
- elseif val.__class
- -- an instance
- switch ancestor val.__class
- when scope.Scope then 'scope'
- when base.FnDef then 'fndef'
- when Stream then return val
- else
- error "#{name}: cannot wrap '#{val.__class.__name}' instance"
- else
- -- plain table
- return ValueStream 'scope', scope.Scope.from_table val
- else
- error "#{name}: cannot wrap Lua type '#{type val}'"
-
- ValueStream typ, val
-
- --- create a constant number.
- -- @tparam number num the number
- -- @treturn ValueStream
- @num: (num) -> ValueStream 'num', num, tostring num
-
- --- create a constant string.
- -- @tparam string str the string
- -- @treturn ValueStream
- @str: (str) -> ValueStream 'str', str, "'#{str}'"
-
- --- create a constant symbol.
- -- @tparam string sym the symbol
- -- @treturn ValueStream
- @sym: (sym) -> ValueStream 'sym', sym, sym
-
- --- create a constant boolean.
- -- @tparam boolean bool the boolean
- -- @treturn ValueStream
- @bool: (bool) -> ValueStream 'bool', bool, tostring bool
-
- --- wrap and document a value.
- --
- -- wraps `args.value` using `wrap`, then assigns `meta`.
- --
- -- @tparam table args table with keys `value` and `meta`
- -- @treturn ValueStream
- @meta: (args) ->
- with ValueStream.wrap args.value
- .meta = args.meta if args.meta
-
-class LiteralValue extends ValueStream
- eval: => Result value: @
-
-{
- :ValueStream
- :LiteralValue
-}
diff --git a/core/tag.moon b/core/tag.moon
deleted file mode 100644
index 3c90998..0000000
--- a/core/tag.moon
+++ /dev/null
@@ -1,122 +0,0 @@
-----
--- Identity provider for `Cell`s and `Builtin`s.
---
--- Tags are one of:
--- - 'blank' (`[?]`, to be auto-assigned by the Copilot)
--- - literal (`[1]`)
--- - cloned (`[X.Y]`, obtained by cloning Y with parent X)
---
--- @classmod Tag
-import Registry from require 'core.registry'
-
-local ClonedTag
-
-class DummyReg
- destroy: =>
-
- __tostring: => "<dummy>"
-
-dummy = DummyReg!
-
-class Tag
---- members
--- @section members
-
- --- obtain the registered value of the last eval-cycle.
- --
- -- Obtain the value that was previously registered for this tag on the last
- -- eval-cylce.
- --
- -- @treturn ?any
- last: =>
- if index = @index!
- Registry.active!\last index
-
- --- register `expr` for this tag for the current eval cycle.
- --
- -- Will mark blank tags for auto-assignment at the end of the eval cycle.
- --
- -- @tparam any expr the value to register
- register: (expr) =>
- if index = @index!
- Registry.active!\register index, expr
- else
- Registry.active!\init @, expr
-
- --- create a copy of this tag scoped to a `parent` tag.
- --
- -- Will mark blank tags for auto-assignment at the end of the eval cycle.
- --
- -- @tparam Tag parent the parent tag
- -- @treturn Tag the cloned tag
- clone: (parent) =>
- -- ensure this tag is registered for the current eval cycle,
- -- even if it is blank and has no associated value
- if index = @index!
- Registry.active!\register index, dummy, true
- else
- Registry.active!\init @, dummy
-
- assert parent, "need parent to clone!"
- ClonedTag @, parent
-
- stringify: => if @value then "[#{@value}]" else ''
- __tostring: => if @value then "#{@value}" else '?'
-
---- internals for `Registry`
--- @section internals
-
- new: (@value) =>
-
- --- get a unique index value for this Tag.
- --
- -- The index is equal to `value` for simple tags and a path-like string for
- -- cloned tags.
- --
- -- @treturn ?number|string
- index: => @value
-
- --- callback to set value for blank tags.
- -- @tparam number value
- set: (value) =>
- assert not @value, "#{@} is not blank"
- @value = value
-
---- static functions
--- @section static
-
- --- create a blank `Tag`.
- --
- -- @treturn Tag
- @blank: -> Tag!
-
- --- parse a `Tag` (for Lpeg parsing).
- --
- -- @tparam string num the number-string
- -- @treturn Tag
- @parse: (num) -> Tag tonumber num
-
-class ClonedTag extends Tag
- new: (@original, @parent) =>
-
- index: =>
- orig = @original\index!
- parent = @parent\index!
- if orig and parent
- "#{parent}.#{orig}"
-
- set: (value) =>
- assert @parent.value, "cloned tag #{@} set before parent"
- @original\set value
-
- stringify: => error "cant stringify ClonedTag"
-
- __tostring: =>
- if @parent
- "#{@parent}.#{@original}"
- else
- tostring @original
-
-{
- :Tag
-}
diff --git a/core/version.moon b/core/version.moon
deleted file mode 100644
index 6cee1b1..0000000
--- a/core/version.moon
+++ /dev/null
@@ -1,17 +0,0 @@
-----
--- `alive` source code version information.
---
--- @module version
-
---- exports
--- @table exports
--- @tfield string tag the last versions git tag
--- @tfield string web the repo web URL
--- @tfield string repo the git repo URL
--- @tfield string release the web URL of this release
-{
- tag: "v0.1-rc2"
- web: "https://github.com/s-ol/alivecoding"
- repo: "https://github.com/s-ol/alivecoding.git"
- release: "https://github.com/s-ol/alivecoding/releases/tag/v0.1-rc2"
-}