aboutsummaryrefslogtreecommitdiffstats
path: root/core/base/action.moon
blob: 7ada4bade070ed57934045101a1ccf149c3076e7 (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
----
-- Builtin / Special Form evaluation Strategy (`builtin`).
--
-- Responsible for quoting/evaluating subexpressions, instantiating and setting
-- up `Op`s, updating the current `Scope`, etc.
-- See `builtin` and `invoke` for examples.
--
-- @classmod Action

class Action
--- Action interface.
--
-- methods that have to be implemented by `Action` implementations.
-- @section interface

  --- create a new instance.
  --
  -- @tparam Cell cell the Cell to evaluate
  -- @tparam Value head the (`AST:eval`d) `head` of the Cell to evaluate
  new: (@cell, @head) =>
    @tag = @cell.tag
    @tag\replace @

  --- perform the actual evaluation.
  --
  -- Implementations should:
  --
  -- - eval or quote `tail` values
  -- - perform scope effects
  -- - wrap all child-results
  --
  -- @tparam Scope scope the active scope
  -- @tparam {AST,...} tail the arguments to this expression
  -- @treturn Result the result of this evaluation
  eval: (scope, tail) => error "not implemented"

  --- free resources
  destroy: =>

  --- setup or copy state from previous instance of same type.
  --
  -- `prev` is only passed if Action types of prev and current expression match.
  -- Otherwise, or when no previous expression exists, `nil` is passed.
  --
  -- @tparam ?Action prev the previous Action instance
  setup: (prev) =>

  --- the `Cell` this Action was created for.
  -- @tfield Cell cell

  --- the evaluated head of `cell`.
  -- @tfield AST head

  --- the identity of `cell`.
  -- @tfield Tag tag

--- static functions
-- @section static

  --- create and setup an `Action` for a given tag, then evaluate it.
  --
  -- Create a new instance using `tag` and `head` and call `setup` on it.
  -- If a previous instance with the same `tag` exists and has the same `head`,
  -- it pass it to `setup`. Register the `Action` with `tag`, evaluate it
  -- and return the `Result`.
  --
  -- @tparam Cell cell the `Cell` being evaluated
  -- @tparam Scope scope the active scope
  -- @tparam Value head the (`AST:eval`d) head of the `Cell` being evaluated
  -- @treturn Result the result of evaluation
  @eval_cell: (cell, scope, head) =>
    last = cell.tag\last!
    compatible = last and (last.__class == @) and last.head == head

    L\trace if compatible
      "reusing #{last} for #{cell.tag} <#{@__name} #{head}>"
    else if last
      "replacing #{last} with new #{cell.tag} <#{@__name} #{head}>"
    else
      "initializing #{cell.tag} <#{@__name} #{head}>"

    action = @ cell, head
    if compatible
      action\setup last
    else
      last\destroy! if last
      action\setup nil

    action\eval scope, cell\tail!

  __tostring: => "<#{@@__name} #{@head}>"
  __inherited: (cls) => cls.__base.__tostring = @__tostring

{
  :Action
}