aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-03-03 10:52:39 +0000
committers-ol <s-ol@users.noreply.github.com>2020-03-05 10:36:22 +0000
commit13fdf952138454184f42f50e15c5c4974b2c7eed (patch)
tree56405051078b17766695cf4b1c659c8fd68d3035
parentdocument more interfaces (diff)
downloadalive-0.0.tar.gz
alive-0.0.zip
refactoring cyclic requiresv0.0
-rw-r--r--core/base.moon3
-rw-r--r--core/cycle.moon26
-rw-r--r--core/init.moon8
-rw-r--r--core/registry.moon3
-rw-r--r--core/result.moon97
-rw-r--r--core/scope.moon3
-rw-r--r--core/value.moon118
-rw-r--r--spec/core/cell_spec.moon3
-rw-r--r--spec/core/parsing_spec.moon3
-rw-r--r--spec/core/pattern_spec.moon2
10 files changed, 149 insertions, 117 deletions
diff --git a/core/base.moon b/core/base.moon
index 8bd6271..7962545 100644
--- a/core/base.moon
+++ b/core/base.moon
@@ -1,5 +1,6 @@
-- base definitions for extensions
-import Value, Result from require 'core.value'
+import Value from require 'core.value'
+import Result from require 'core.result'
import match from require 'core.pattern'
unpack or= table.unpack
diff --git a/core/cycle.moon b/core/cycle.moon
new file mode 100644
index 0000000..57d4a75
--- /dev/null
+++ b/core/cycle.moon
@@ -0,0 +1,26 @@
+-- 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/init.moon b/core/init.moon
index 73f63f9..7122e0f 100644
--- a/core/init.moon
+++ b/core/init.moon
@@ -1,15 +1,17 @@
L or= setmetatable {}, __index: => ->
-import Value, Result, load_ from require 'core.value'
+import Value from require 'core.value'
+import Result from require 'core.result'
import Scope from require 'core.scope'
-load_!
-
import Registry from require 'core.registry'
import Tag from require 'core.tag'
import Cell, RootCell from require 'core.cell'
import cell, program from require 'core.parsing'
+with require 'core.cycle'
+ \load!
+
globals = Scope.from_table require 'core.builtin'
{
diff --git a/core/registry.moon b/core/registry.moon
index ebe429c..fca7e5d 100644
--- a/core/registry.moon
+++ b/core/registry.moon
@@ -1,4 +1,5 @@
-import Result, Value from require 'core.value'
+import Value from require 'core.value'
+import Result from require 'core.result'
class Registry
new: () =>
diff --git a/core/result.moon b/core/result.moon
new file mode 100644
index 0000000..7fda8e5
--- /dev/null
+++ b/core/result.moon
@@ -0,0 +1,97 @@
+import base from require 'core.cycle'
+
+-- Result of evaluating an expression
+-- carries (all optional):
+-- - a Value
+-- - an Op (to update)
+-- - children (results of subexpressions that were evaluated)
+-- - cached list of all Dispatchers affecting all Ops in the subtree
+--
+-- Results form a tree that controls execution order and message passing
+-- between Ops.
+class Result
+ -- params: table with optional keys op, value, children
+ new: (params={}) =>
+ @value = params.value
+ @op = params.op
+ @children = params.children or {}
+
+ @side_inputs, is_child = {}, {}
+ for child in *@children
+ for s, d in pairs child.side_inputs
+ @side_inputs[s] = d
+ if child.value
+ is_child[child.value] = true
+
+ if @op
+ for input in @op\all_inputs!
+ if input.impure or not is_child[input.stream]
+ @side_inputs[input.stream] = input
+
+ is_const: => not next @side_inputs
+
+ -- asserts value-constness and returns the value
+ const: (msg) =>
+ assert not (next @side_inputs), msg or "eval-time const expected"
+ @value
+
+ -- asserts a value exists and returns its type
+ type: =>
+ assert @value, "Result with value expected"
+ @value.type
+
+ -- create a value-copy of this result that has the same impulses but without
+ -- affecting the original's update logic
+ make_ref: =>
+ with Result value: @value
+ .side_inputs = @side_inputs
+
+ -- tick all IO 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
+ if input.__class == base.IOInput
+ io = input!
+ io\tick!
+
+ -- in depth-first order, tick all Ops who have dirty Stream inputs or impulses
+ --
+ -- short-circuits if there are no dirty Streams 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 streams 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 streams from child
+ -- expressions might have changed
+ self_dirty = false
+ for stream in @op\all_inputs!
+ if stream\dirty!
+ self_dirty = true
+ break
+
+ L\trace "#{@op} is #{if self_dirty then 'dirty' else 'clean'}"
+ return unless self_dirty
+
+ @op\tick!
+
+-- static
+ __tostring: =>
+ buf = "<result=#{@value}"
+ buf ..= " #{@op}" if @op
+ buf ..= " (#{#@children} children)" if #@children > 0
+ buf ..= ">"
+ buf
+
+{
+ :Result
+}
diff --git a/core/scope.moon b/core/scope.moon
index 5e73f64..4ed95d1 100644
--- a/core/scope.moon
+++ b/core/scope.moon
@@ -1,4 +1,5 @@
-import Result, Value from require 'core.value'
+import Value from require 'core.value'
+import Result from require 'core.result'
class Scope
new: (@parent, @dynamic_parent) =>
diff --git a/core/value.moon b/core/value.moon
index b01b28f..26771ea 100644
--- a/core/value.moon
+++ b/core/value.moon
@@ -1,9 +1,5 @@
--- ALV Value types
-local Scope, Registry, Op, Action, IOInput, FnDef
-load_ = ->
- import Scope from require 'core.scope'
- import Registry from require 'core.registry'
- import Op, Action, IOInput, FnDef from require 'core.base'
+import Result from require 'core.result'
+import scope, base, registry from require 'core.cycle'
ancestor = (klass) ->
assert klass, "cant find the ancestor of nil"
@@ -11,98 +7,6 @@ ancestor = (klass) ->
klass = klass.__parent
klass
--- Result of evaluating an expression
--- carries (all optional):
--- - a Value
--- - an Op (to update)
--- - children (results of subexpressions that were evaluated)
--- - cached list of all Dispatchers affecting all Ops in the subtree
---
--- Results form a tree that controls execution order and message passing
--- between Ops.
-class Result
- -- params: table with optional keys op, value, children
- new: (params={}) =>
- @value = params.value
- @op = params.op
- @children = params.children or {}
-
- @side_inputs, is_child = {}, {}
- for child in *@children
- for s, d in pairs child.side_inputs
- @side_inputs[s] = d
- if child.value
- is_child[child.value] = true
-
- if @op
- for input in @op\all_inputs!
- if input.impure or not is_child[input.stream]
- @side_inputs[input.stream] = input
-
- is_const: => not next @side_inputs
-
- -- asserts value-constness and returns the value
- const: (msg) =>
- assert not (next @side_inputs), msg or "eval-time const expected"
- @value
-
- -- asserts a value exists and returns its type
- type: =>
- assert @value, "Result with value expected"
- @value.type
-
- -- create a value-copy of this result that has the same impulses but without
- -- affecting the original's update logic
- make_ref: =>
- with Result value: @value
- .side_inputs = @side_inputs
-
- -- tick all IO 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
- if input.__class == IOInput
- io = input!
- io\tick!
-
- -- in depth-first order, tick all Ops who have dirty Stream inputs or impulses
- --
- -- short-circuits if there are no dirty Streams 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 streams 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 streams from child
- -- expressions might have changed
- self_dirty = false
- for stream in @op\all_inputs!
- if stream\dirty!
- self_dirty = true
- break
-
- L\trace "#{@op} is #{if self_dirty then 'dirty' else 'clean'}"
- return unless self_dirty
-
- @op\tick!
-
--- static
- __tostring: =>
- buf = "<result=#{@value}"
- buf ..= " #{@op}" if @op
- buf ..= " (#{#@children} children)" if #@children > 0
- buf ..= ">"
- buf
-
-- ALV Type wrapper
class Value
-- @type - type name.
@@ -112,9 +16,9 @@ class Value
new: (@type, @value, @raw) =>
@updated = nil
- dirty: => @updated == Registry.active!.tick
+ dirty: => @updated == registry.Registry.active!.tick
- set: (@value) => @updated = Registry.active!.tick
+ set: (@value) => @updated = registry.Registry.active!.tick
-- unwrap to the Lua type
-- asserts @type == type, msg if given
@@ -149,29 +53,30 @@ class Value
-- wrap a Lua type
@wrap: (val, name='(unknown)') ->
+
typ = switch type val
when 'number' then 'num'
when 'string' then 'str'
when 'table'
- if base = rawget val, '__base'
+ if rawget val, '__base'
-- a class
switch ancestor val
- when Op then 'opdef'
- when Action then 'builtin'
+ when base.Op then 'opdef'
+ when base.Action then 'builtin'
else
error "#{name}: cannot wrap class '#{val.__name}'"
elseif val.__class
-- an instance
switch ancestor val.__class
- when Scope then 'scope'
- when FnDef then 'fndef'
+ when scope.Scope then 'scope'
+ when base.FnDef then 'fndef'
when Value
return val
else
error "#{name}: cannot wrap '#{val.__class.__name}' instance"
else
-- plain table
- return Value 'scope', Scope.from_table val
+ return Value 'scope', scope.Scope.from_table val
else
error "#{name}: cannot wrap Lua type '#{type val}'"
@@ -190,7 +95,6 @@ class Value
@bool: (bool) -> Value 'bool', bool, tostring bool
{
- :Result
:Value
:load_
}
diff --git a/spec/core/cell_spec.moon b/spec/core/cell_spec.moon
index fcf9861..78861ab 100644
--- a/spec/core/cell_spec.moon
+++ b/spec/core/cell_spec.moon
@@ -1,5 +1,4 @@
-import Cell, RootCell, Value, Scope, globals from require 'core'
-import Registry from require 'core.registry'
+import Cell, RootCell, Value, Scope, Registry, globals from require 'core'
import Logger from require 'logger'
Logger.init 'silent'
diff --git a/spec/core/parsing_spec.moon b/spec/core/parsing_spec.moon
index ddf760f..7f4bb06 100644
--- a/spec/core/parsing_spec.moon
+++ b/spec/core/parsing_spec.moon
@@ -1,4 +1,5 @@
-import space, atom, expr, explist, cell, program, comment from require 'core.parsing'
+import space, atom, expr, explist, cell, program, comment
+ from require 'core.parsing'
import Value from require 'core'
import Logger from require 'logger'
Logger.init 'silent'
diff --git a/spec/core/pattern_spec.moon b/spec/core/pattern_spec.moon
index c218dd2..64dbef2 100644
--- a/spec/core/pattern_spec.moon
+++ b/spec/core/pattern_spec.moon
@@ -1,5 +1,5 @@
import Pattern, match from require 'core.pattern'
-import Result, Value from require 'core.value'
+import Result, Value from require 'core'
-- wrap in non-const result
wrap = (value) ->