aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-04-24 21:16:01 +0000
committers-ol <s-ol@users.noreply.github.com>2020-04-26 09:36:07 +0000
commitc106b5d8503fe6ac1c8f45f0e4e2dcf819e3c973 (patch)
tree4239fd2b8fa2eee769bcbd40e0b797186a759be8
parentrelative imports (diff)
downloadalive-c106b5d8503fe6ac1c8f45f0e4e2dcf819e3c973.tar.gz
alive-c106b5d8503fe6ac1c8f45f0e4e2dcf819e3c973.zip
fix registry/module bugs
- registry not released when errors occur - registry is no longer grabbed, problem solved ;) - ops not reliably destroyed - only destroy ops who were *not* forked
-rw-r--r--alv/base/builtin.moon1
-rw-r--r--alv/copilot.moon8
-rw-r--r--alv/invoke.moon5
-rw-r--r--alv/module.moon9
-rw-r--r--alv/registry.moon31
-rw-r--r--alv/tag.moon6
6 files changed, 18 insertions, 42 deletions
diff --git a/alv/base/builtin.moon b/alv/base/builtin.moon
index b9e7e55..f675207 100644
--- a/alv/base/builtin.moon
+++ b/alv/base/builtin.moon
@@ -83,7 +83,6 @@ class Builtin
if compatible
builtin\setup last
else
- last\destroy! if last
builtin\setup nil
builtin\eval scope, cell\tail!
diff --git a/alv/copilot.moon b/alv/copilot.moon
index 2b97d48..7ef2134 100644
--- a/alv/copilot.moon
+++ b/alv/copilot.moon
@@ -20,6 +20,7 @@ class Copilot
-- @tparam string file name/path of the alive file to watch and execute
new: (file) =>
@T = 0
+ @last_modification = 0
@last_modules = {}
@open file if file
@@ -54,8 +55,11 @@ class Copilot
last = @active_module
prefix = @active_module.file\match('(.*)/[^/]*$') .. '/' or ''
mod = @last_modules[name] or Module "#{prefix}#{name}.alv"
+ L\trace "entering module #{mod}"
+ @modules[name] = mod
@active_module = mod
ok, err = pcall mod\eval
+ L\trace "returning to module #{mod}"
@active_module = last
if ok
mod.root
@@ -90,11 +94,12 @@ class Copilot
poll: =>
dirty = {}
for name, mod in pairs @last_modules
- if mod\poll!
+ if mod\poll! > @last_modification
table.insert dirty, mod
return if #dirty == 0
+ @last_modification = os.time!
L\set_time 'eval'
L\print "changes to files: #{table.concat [m.file for m in *dirty], ', '}"
@@ -115,6 +120,7 @@ class Copilot
for name, mod in pairs @modules
mod\finish!
+ @last_modification = os.time!
@last_modules, @modules = @modules, nil
{
diff --git a/alv/invoke.moon b/alv/invoke.moon
index fba6485..439af49 100644
--- a/alv/invoke.moon
+++ b/alv/invoke.moon
@@ -32,6 +32,7 @@ class op_invoke extends Builtin
setup: (prev) =>
if prev
@op = prev.op\fork!
+ prev.forked = COPILOT.T
else
def = @head\unwrap 'opdef', "cant op-invoke #{@head}"
@op = def!
@@ -39,7 +40,9 @@ class op_invoke extends Builtin
--- `Builtin:destroy` implementation.
--
-- calls `op`:@{Op:destroy|destroy}.
- destroy: => @op\destroy!
+ destroy: =>
+ if @forked ~= COPILOT.T
+ @op\destroy!
--- perform an `Op` invocation.
--
diff --git a/alv/module.moon b/alv/module.moon
index 356bcf5..8fc3ba7 100644
--- a/alv/module.moon
+++ b/alv/module.moon
@@ -26,7 +26,6 @@ class Module
-- @classmethod
new: (@file) =>
@registry = Registry!
- @last_modification = 0
--- members
-- @section members
@@ -36,23 +35,19 @@ class Module
poll: =>
{ :mode, :modification } = (lfs.attributes @file) or {}
assert mode == 'file', Error 'io', "not a file: '#{file}'"
-
- if @last_modification < modification
- true
+ modification
--- start an evaluation cycle.
--
-- If the module has already been evaluated this tick, this is a noop.
-- Otherwise, register the module with the `Copilot`. Updates `root`.
eval: =>
- @last_modification = os.time!
+ @registry\begin_eval!
@ast = Error.wrap "parsing '#{@file}'", -> program\match slurp @file
assert @ast, Error 'syntax', "failed to parse"
scope = Scope builtin
- @registry\begin_eval!
@root = Error.wrap "evaluating '#{@file}'", @ast\eval, scope, @registry
- @registry\release!
--- rollback the last evaluation cycle.
rollback: => @registry\rollback_eval!
diff --git a/alv/registry.moon b/alv/registry.moon
index d4dcccc..1b24e9a 100644
--- a/alv/registry.moon
+++ b/alv/registry.moon
@@ -40,19 +40,15 @@ class Registry
--- begin an evaluation cycle.
--
- -- 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: =>
- @grab!
assert not @map, "unfinished evaluation cycle"
@map, @pending = {}, {}
--- abort an evaluation cycle.
- --
- -- Unset the active Registry.
rollback_eval: =>
+ assert @map, "no eval cycle to abort"
for { :tag, :expr } in *@pending
expr\destroy!
@@ -61,11 +57,10 @@ class Registry
--- end an evaluation cycle.
--
-- Register all pending `Tag`s and destroy all orphaned registrations.
- -- Unset the active Registry.
-- @treturn bool whether any changes to the AST were made
end_eval: =>
for tag, val in pairs @last_map
- val\destroy! unless @map[tag]
+ val\destroy!
for { :tag, :expr } in *@pending
-- tag was solved by another pending registration
@@ -82,16 +77,6 @@ class Registry
dirty
- --- 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
-
--- destroy this Registry and all associated Registrations.
-- needs to be called *after* `:eval`.
destroy: =>
@@ -109,13 +94,6 @@ class Registry
new: =>
@last_map = {}
- --- get the active Registry.
- --
- -- Raises an error when there is no active Registry.
- --
- -- @treturn Registry
- @active: -> assert Registry.active_registry, "no active Registry!"
-
class SimpleRegistry extends Registry
new: =>
@cnt = 1
@@ -127,11 +105,6 @@ class SimpleRegistry extends Registry
last: (index) =>
register: (index, expr) =>
- wrap: (fn) => (...) ->
- @grab!
- with fn ...
- @release!
-
{
:Registry
:SimpleRegistry
diff --git a/alv/tag.moon b/alv/tag.moon
index d7becab..4b39bcb 100644
--- a/alv/tag.moon
+++ b/alv/tag.moon
@@ -30,14 +30,14 @@ class Tag
-- @treturn ?any
last: =>
if index = @index!
- Registry.active!\last index
+ COPILOT.active_module.registry\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) => Registry.active!\register @, expr
+ register: (expr) => COPILOT.active_module.registry\register @, expr
--- create a copy of this tag scoped to a `parent` tag.
--
@@ -48,7 +48,7 @@ class Tag
clone: (parent) =>
-- ensure this tag is registered for the current eval cycle,
-- even if it is blank and has no associated value
- Registry.active!\register @, dummy, true
+ COPILOT.active_module.registry\register @, dummy, true
assert parent, "need parent to clone!"
ClonedTag @, parent