aboutsummaryrefslogtreecommitdiffstats
path: root/core/invoke.moon
blob: 5ec4a82a98ff974ece69ec3e0d1dd7545d60a03c (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
import Const from require 'core.const'
import Action from require 'core.base'
import Scope from require 'core.scope'

class UpdateChildren
  new: (@children) =>

  update: (dt) =>
    for child in *@children
      -- L\trace "updating #{child}"
      L\push child\update, dt

  get: => @children[#@children]\get!
  getc: => @children[#@children]\getc!

  __tostring: => '<forwarder>'

class op_invoke extends Action
  patch: (head) =>
    return true if head == @head

    @op\destroy! if @op

    @head = head
    assert @head.type == 'opdef', "cant op-invoke #{@head}"
    @op = @head\getc!!
  
    true
    
  eval: (scope, tail) =>
    L\trace "evaling #{@}"
    args = L\push -> [L\push expr\eval, scope for expr in *tail]

    -- Const 'op', with @op
    with @op
      \setup unpack args

class fn_invoke extends Action
  -- @TODO:
  -- need to :patch() the case where the new head is a new fndef
  -- but corresponds to the last head over time

  patch: (head) =>
    return true if head == @head

    @head = head

    true

  eval: (outer_scope, tail) =>
    assert @head.type == 'fndef', "cant fn-invoke #{@head}"
    { :params, :body, :scope } = @head\getc!

    assert #params == #tail, "argument count mismatch in #{@head}"

    fn_scope = Scope @, scope

    for i=1,#params
      name = params[i]\getc!
      argm = tail[i]
      fn_scope\set name, L\push argm\eval, outer_scope

    body = body\clone @tag

    body\eval fn_scope

class do_expr extends Action
  eval: (scope, tail) =>
    UpdateChildren [(expr\eval scope) or Const.empty! for expr in *tail]

{
  :op_invoke, :fn_invoke
  :UpdateChildren
}