1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
----
-- Per-file execution context.
--
-- @classmod Module
import Registry from require 'alv.registry'
import Error from require 'alv.error'
import Scope from require 'alv.scope'
import program from require 'alv.parsing'
builtin = require 'alv.builtin'
slurp = (file) ->
file = assert (io.open file, 'r'), Error 'io', "couldn't open '#{file}'"
with file\read '*all'
file\close!
spit = (file, str) ->
file = io.open file, 'w'
file\write str
file\close!
class Module
--- static functions
-- @section static
--- create a new Module.
-- @classmethod
new: (@file) =>
@registry = Registry!
--- members
-- @section members
--- check whether file was changed.
-- @treturn bool whether the file was changed since the last call
poll: =>
{ :mode, :modification } = (lfs.attributes @file) or {}
assert mode == 'file', Error 'io', "not a file: '#{file}'"
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: =>
@registry\begin_eval!
@ast = Error.wrap "parsing '#{@file}'", -> program\match slurp @file
assert @ast, Error 'syntax', "failed to parse"
scope = Scope builtin
@root = Error.wrap "evaluating '#{@file}'", @ast\eval, scope, @registry
--- rollback the last evaluation cycle.
rollback: => @registry\rollback_eval!
--- finish the last evaluation cycle.
finish: =>
tags_changed = @registry\end_eval!
if tags_changed
spit @file, @ast\stringify!
--- destroy this module.
destroy: =>
@registry\destroy!
__tostring: => "<Module #{@file}>"
--- the last updated AST tree for this module.
-- @tfield ?AST ast
--- the root Result of this module.
-- @tfield ?Result root
{
:Module
}
|