diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-08 09:41:08 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:23:21 +0000 |
| commit | 99ca67938c0145db37182bdb709d9424a20dfee0 (patch) | |
| tree | 6df4e2b5fde650aa3c7e36893eb1780f932d56bd /alv/result | |
| parent | release v0.1 (diff) | |
| download | alive-99ca67938c0145db37182bdb709d9424a20dfee0.tar.gz alive-99ca67938c0145db37182bdb709d9424a20dfee0.zip | |
wip new type system and refactoring
- Result -> RTNode
- Stream -> Result
- ValueStream -> SigStream
- EventStream -> EvtStream
Diffstat (limited to 'alv/result')
| -rw-r--r-- | alv/result/base.moon | 78 | ||||
| -rw-r--r-- | alv/result/const.moon | 196 | ||||
| -rw-r--r-- | alv/result/evt.moon | 95 | ||||
| -rw-r--r-- | alv/result/init.moon | 21 | ||||
| -rw-r--r-- | alv/result/io.moon | 55 | ||||
| -rw-r--r-- | alv/result/sig.moon | 121 |
6 files changed, 566 insertions, 0 deletions
diff --git a/alv/result/base.moon b/alv/result/base.moon new file mode 100644 index 0000000..26af4b4 --- /dev/null +++ b/alv/result/base.moon @@ -0,0 +1,78 @@ +---- +-- base Stream interface. +-- +-- implemented by `Constant`, `SigStream`, `EvtStream`, and `IOStream`. +-- +-- @classmod Stream + +class Stream +--- Stream interface. +-- +-- Methods that have to be implemented by `Stream` implementations +-- (`SigStream`, `EvtStream`, `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 + + __tostring: => "<#{@type}#{@metatype} #{@type\pp @value}>" + __inherited: (cls) => cls.__base.__tostring or= @__tostring + + --- 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 + + --- the metatype string for this Stream. + -- + -- one of `=` (`Constant`), `~` (`SigStream`), + -- `!` (`EvtStream` and `IOStream`). + -- + -- @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/alv/result/const.moon b/alv/result/const.moon new file mode 100644 index 0000000..10bc943 --- /dev/null +++ b/alv/result/const.moon @@ -0,0 +1,196 @@ +---- +-- Constant Value. +-- +-- Implements the `Stream` and `AST` inteface. +-- +-- @classmod Constant +import Stream from require 'alv.result.base' +import RTNode from require 'alv.rtnode' +import Error from require 'alv.error' +import scope, base from require 'alv.cycle' +import Primitive from require 'alv.types' + +num = Primitive 'num' +str = Primitive 'str' +sym = Primitive 'sym' +bool = Primitive 'bool' + +ancestor = (klass) -> + assert klass, "cant find the ancestor of nil" + while klass.__parent + klass = klass.__parent + klass + +class Constant extends Stream + --- Whether this Result is dirty. + -- + -- @tresult bool always `false`. + dirty: => false + + --- 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 Constant + fork: => @ + + --- alias for `unwrap`. + __call: (...) => @unwrap ... + + --- compare two values. + -- + -- Compares two `SigStream`s by comparing their types and their Lua values. + __eq: (other) => other.type == @type and other.value == @value + + --- Stream metatype. + -- + -- @tfield string metatype (`=`) + metatype: '=' + +--- AST interface +-- +-- `SignStream` 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 RTNode the evaluation result + eval: (scope) => + return RTNode value: @ if @literal + + switch @type + when num, str + RTNode value: @ + when sym + Error.wrap "resolving symbol '#{@value}'", scope\get, @value + else + error "cannot evaluate #{@}" + + --- stringify this literal constant. + -- + -- Throws an error if `raw` is not set. + -- + -- @treturn string the exact string this stream was parsed from + stringify: => @raw + + --- clone this literal constant. + -- + -- @treturn SignStream self + clone: (prefix) => @ + +--- static functions +-- @section static + + --- construct a new Constant. + -- + -- @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 Constant + @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 + val = scope.Scope.from_table val + 'scope' + else + error "#{name}: cannot wrap Lua type '#{type val}'" + + Constant (Primitive typ), val + + --- create a constant number. + -- @tparam number val the number + -- @treturn Constant + @num: (val) -> Constant num, val, tostring val + + --- create a constant string. + -- @tparam string val the string + -- @treturn Constant + @str: (val) -> Constant str, val, "'#{val}'" + + --- create a constant symbol. + -- @tparam string val the symbol + -- @treturn Constant + @sym: (val) -> Constant sym, val, val + + --- create a constant boolean. + -- @tparam boolean val the boolean + -- @treturn Constant + @bool: (val) -> Constant bool, val, tostring val + + --- create a forced-literal Constant. + -- + -- For internal use in `Builtin`s only. + -- + -- @treturn Constant + @literal: (...) -> + with Constant ... + .literal = true + + --- wrap and document a value. + -- + -- wraps `args.value` using `wrap`, then assigns `meta`. + -- + -- @tparam table args table with keys `value` and `meta` + -- @treturn Constant + @meta: (args) -> + with Constant.wrap args.value + .meta = args.meta if args.meta + +{ + :Constant +} diff --git a/alv/result/evt.moon b/alv/result/evt.moon new file mode 100644 index 0000000..0559a70 --- /dev/null +++ b/alv/result/evt.moon @@ -0,0 +1,95 @@ +---- +-- Stream of momentary events. +-- +-- @classmod EvtStream +import Stream from require 'alv.result.base' + +class EvtStream extends Stream +--- members +-- @section members + + --- return whether this stream was changed in the current tick. + -- + -- @treturn bool + dirty: => @updated == COPILOT.T + + --- 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 = COPILOT.T + 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 EvtStream + fork: => @@ @type + + --- alias for `unwrap`. + __call: (...) => @unwrap ... + __tostring: => "<#{@type}#{@metatype} #{@type\pp @value}>" + + --- Stream metatype. + -- + -- @tfield string metatype (`!`) + metatype: '!' + + --- 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 EvtStream. + -- + -- @classmethod + -- @tparam string type the type name + new: (type) => super type + +{ + :EvtStream +} diff --git a/alv/result/init.moon b/alv/result/init.moon new file mode 100644 index 0000000..aa7a115 --- /dev/null +++ b/alv/result/init.moon @@ -0,0 +1,21 @@ +---- +-- `Stream` interface and implementations. +-- +-- @see Stream +-- @see Constant +-- @see SigStream +-- @see EvtStream +-- @see IOStream +-- +-- @module stream +import Constant from require 'alv.result.const' +import SigStream from require 'alv.result.sig' +import EvtStream from require 'alv.result.evt' +import IOStream from require 'alv.result.io' + +{ + :Constant + :SigStream + :EvtStream + :IOStream +} diff --git a/alv/result/io.moon b/alv/result/io.moon new file mode 100644 index 0000000..b12322c --- /dev/null +++ b/alv/result/io.moon @@ -0,0 +1,55 @@ +---- +-- 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 `RTNode` tree. +-- +-- @classmod IOStream +import EvtStream from require 'alv.result.evt' + +class IOStream extends EvtStream +--- 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. + poll: => + + --- 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 `poll` on the first frame after construction. + -- + -- If this is not overriden, the `EvtStream` interface can be used, see + -- `EvtStream.add`, `EvtStream.unwrap`, and `EvtStream.dirty`. + -- + -- @function dirty + -- @treturn bool whether processing is required + + __inherited: (cls) => cls.__base.__tostring or= @__tostring + +{ + :IOStream +} diff --git a/alv/result/sig.moon b/alv/result/sig.moon new file mode 100644 index 0000000..d7c18a3 --- /dev/null +++ b/alv/result/sig.moon @@ -0,0 +1,121 @@ +---- +-- Continuous stream of values. +-- +-- @classmod SigStream +import Stream from require 'alv.result.base' +import Primitive from require 'alv.types' + +class SigStream extends Stream +--- members +-- @section members + + --- return whether this stream was changed in the current tick. + -- + -- @treturn bool + dirty: => @updated == COPILOT.T + + --- update this stream's value. + -- + -- Marks this stream as dirty for the remainder of the current tick. + set: (value) => + if value != @value + @value = value + @updated = COPILOT.T + + --- 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 SigStream + fork: => + with @@ @type, @value + .updated = @updated + + --- alias for `unwrap`. + __call: (...) => @unwrap ... + + --- compare two values. + -- + -- Compares two `SigStream`s by comparing their types and their Lua values. + __eq: (other) => other.type == @type and other.value == @value + + --- Stream metatype. + -- + -- @tfield string metatype (`~`) + metatype: '~' + + --- 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 + +--- static functions +-- @section static + + --- construct a new SigStream. + -- + -- @classmethod + -- @tparam string type the type name + -- @tparam any value the Lua value to be accessed through `unwrap` + new: (type, @value) => super type + + --- create a number stream. + -- @tparam number val the number + -- @treturn SigStream + @num: (val) -> SigStream Primitive'num', val + + --- create a string stream. + -- @tparam string val the string + -- @treturn SigStream + @str: (val) -> SigStream Primitive'str', val + + --- create a symbol stream. + -- @tparam string val the symbol + -- @treturn symbol + @sym: (val) -> SigStream Primitive'sym', val + + --- create a boolean stream. + -- @tparam boolean val the boolean + -- @treturn SigStream + @bool: (val) -> SigStream Primitive'bool', val + +{ + :SigStream +} |
