aboutsummaryrefslogtreecommitdiffstats
path: root/alv/tag.moon
blob: 070b0cd28a29da9896c649069a0b224e9af88edb (plain)
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
----
-- Identity provider for `Cell`s and `Builtin`s.
--
-- Tags are one of:
-- - 'blank' (`[?]`, to be auto-assigned by the Copilot)
-- - literal (`[1]`)
-- - virtual (`[str]`, won't be tracked)
-- - cloned (`[X.Y]`, obtained by cloning Y with parent X)
--
-- @classmod Tag

local ClonedTag

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: =>
    return if @pending
    if index = @index!
      COPILOT.active_module.registry\last index

  --- 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) =>
    @builtin or= false
    assert parent, "need parent to clone!"
    ClonedTag @, parent

  --- get a globally-unique identifier for this tag
  --
  -- prepends the module name to the tag string
  --
  -- @treturn string a unique string
  ident: => "#{@registry.module\name!}:#{@}"

  stringify: (depth=-1) => if @value and depth == -1 then "[#{@value}]" else ''
  __tostring: => if @value then "#{@value}" else '?'

--- internals for `Registry`
-- @section internals

  new: (@value) =>
    if COPILOT and "string" != type @value
      @registry = COPILOT.active_module.registry
      @pending = @registry\register @

  --- 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.
  --
  -- `value` may be blank to reassign duplicate tags.
  --
  -- @tparam ?number value
  set: (value) =>
    either_or = (@value or value) and not (@value and value)
    assert either_or, "unexpected :set #{value} on #{@}"
    @value = value

  --- the Registry associated with this Tag
  -- @tfield Registry registry

  --- whether this Tag is newly assigned this tick
  -- @tfield bool pending

--- static functions
-- @section static

  --- 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) =>
    if 'string' == type @original.value
      return

    @registry = COPILOT.active_module.registry
    @registry\register @

    @pending = @original.pending or @parent.pending

  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: => "#{@parent}.#{@original}"

{
  :Tag
}