aboutsummaryrefslogtreecommitdiffstats
path: root/lib/logic.moon
blob: adff5ee73a2db4a14a65268d3b41954894a6fcd1 (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 Op, ValueInput, match from require 'core.base'

all_same = (first, list) ->
  for v in *list
    if v != first
      return false

  first

tobool = (val) ->
  switch val
    when false, nil, 0
      false
    else
      true

class ReduceOp extends Op
  new: => super 'bool'

  setup: (inputs) =>
    { first, rest } = match "any *any", inputs
    super
      first: ValueInput first
      rest: [ValueInput v for v in *rest]

  tick: =>
    { :first, :rest } = @unwrap_all!
    accum = tobool first
    for val in *rest
      accum = @.fn accum, tobool val

    @out\set accum

class eq extends Op
  @doc: "(eq a b [c]...)
(== a b [c]...) - check for equality

If the value types dont match, the result is an eval-time constant 'false'."

  new: => super 'bool', false

  setup: (inputs) =>
    { first, rest } = match "any *any", inputs
    same = all_same first\type!, [i\type! for i in *rest]

    super if same
      {
        first: ValueInput first
        rest: [ValueInput v for v in *rest]
      }
    else
      {}

  tick: =>
    if not @inputs.first
      @out\set false
      return

    { :first, :rest } = @unwrap_all!

    equal = true
    for other in *rest
      if first != other
        equal = false
        break

    @out\set equal

class not_eq extends Op
  @doc: "(not-eq a b [c]...)
(!= a b [c]...) - check for inequality"
  new: => super 'bool'

  setup: (inputs) =>
    assert #inputs > 1, "neq need at least two values"
    super [ValueInput v for v in *inputs]

  tick: =>
    if not @inputs[1]
      @out\set true
      return

    diff = true
    for a=1, #@inputs-1
      for b=a+1, #@inputs
        if @inputs[a].stream == @inputs[b].stream
          diff = false
          break

      break unless diff

    @out\set diff

class and_ extends ReduceOp
  @doc: "(and a b [c]...) - AND values"
  fn: (a, b) -> a and b

class or_ extends ReduceOp
  @doc: "(or a b [c]...) - OR values"
  fn: (a, b) -> a or b

class not_ extends Op
  @doc: "(not a) - boolean opposite"
  new: => super 'bool'

  setup: (inputs) =>
    { value } = match 'any', inputs
    super value: ValueInput value

  tick: => @out\set not tobool @inputs.value!

class bool extends Op
  @doc: "(bool a) - convert to bool"
  new: => super 'bool'

  setup: (inputs) =>
    { value } = match 'any', inputs
    super value: ValueInput value

  tick: => @out\set tobool @inputs\value!

{
  :eq, '==': eq
  'not-eq': not_eq, '!=': not_eq
  and: and_
  or: or_
  not: not_
  :bool
}