aboutsummaryrefslogtreecommitdiffstats
path: root/alv-lib/struct-.moon
blob: 94bd82fbb8d16583111ce502a787288fbe14c511 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
import Struct, Op, PureOp, Constant, Error, const, sig, evt from require 'alv.base'

any = sig! / evt!
key_type = const.str / const.sym

get = Constant.meta
  meta:
    name: 'get'
    summary: "Index into a struct."
    examples: { '(get struct key)' }
    description: "Get the value at `key`.

`key` has to be a constant expression."

  value: class extends PureOp
    pattern: any + key_type
    type: (inputs) =>
      { struct, key } = inputs
      struct\type!\get key.result!

    tick: =>
      { struct, key } = @unwrap_all!
      @out\set struct[key]

set = Constant.meta
  meta:
    name: 'set'
    summary: "Update values in a struct."
    examples: { '(set struct key val)' }
    description: "Set the value for `key` to `val`.

`key` has to be a constant expression. This is a pure op, so at most one of
`struct` and `val` may be a !-stream."

  value: class extends PureOp
    pattern: any + key_type + any
    type: (inputs) =>
      { struct, key, val } = inputs
      type = struct\type!
      expected = type\get key.result!

      if expected ~= val\type!
        msg = string.format "expected value for key '%s' to be %s, not %s",
                            key.result!, expected, val\type!
        error Error 'argument', msg

      type

    tick: =>
      { struct, key, val } = @unwrap_all!

      struct = {k,v for k,v in pairs struct}
      struct[key] = val

      @out\set struct

insert = Constant.meta
  meta:
    name: 'insert'
    summary: "Insert a new value into a struct."
    examples: { '(insert struct key val)' }
    description: "Insert `val` into `struct` at `key`.

`key` has to be a constant expression. This is a pure op, so at most one of
`struct` and `val` may be a !-stream."

  value: class extends PureOp
    pattern: any + key_type + any
    type: (inputs) =>
      { struct, key, val } = inputs
      type = struct\type!
      key = key.result!

      if type.types[key]
        msg = string.format "key '%s' already exists in value of type %s",
                            key, type
        error Error 'argument', msg

      types = {k,v for k,v in pairs type.types}
      types[key] = val\type!
      Struct types

    tick: =>
      { struct, key, val } = @unwrap_all!

      struct = {k,v for k,v in pairs struct}
      struct[key] = val

      @out\set struct

remove = Constant.meta
  meta:
    name: 'remove'
    summary: "Remove values from a struct."
    examples: { '(remove struct key)' }
    description: "Removes the value at index `key` from `struct`.

`key` has to be a constant expression."

  value: class extends PureOp
    pattern: any + key_type
    type: (inputs) =>
      { struct, key } = inputs
      type = struct\type!
      key = key.result!

      -- check key exists
      type\get key

      types = {k,v for k,v in pairs type.types}
      types[key] = nil
      Struct types

    tick: =>
      { struct, key, val } = @unwrap_all!

      struct = {k,v for k,v in pairs struct}
      struct[key] = nil

      @out\set struct

Constant.meta
  meta:
    name: 'struct'
    summary: "Utilities for dealing with structs."

  value:
    :get, :set
    :insert, :remove