aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/target/jvm/bytecode/environment.lux
blob: 222bd7c0e3a22caa0508672758de448013c71dc0 (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
(.using
 [library
  [lux {"-" Type static has}
   [abstract
    [monad {"+" do}]
    [monoid {"+" Monoid}]]
   [control
    ["[0]" try {"+" Try}]
    ["[0]" exception {"+" exception:}]]]]
 [/
  ["/[0]" limit {"+" Limit}
   ["/[0]" stack {"+" Stack}]
   ["/[0]" registry {"+" Registry}]]
  [///
   [encoding
    [unsigned {"+" U2}]]
   [type {"+" Type}
    [category {"+" Method}]]]])

(type: .public Environment
  (Record
   [#limit Limit
    #stack (Maybe Stack)]))

(template [<name> <limit>]
  [(def: .public (<name> type)
     (-> (Type Method) (Try Environment))
     (do try.monad
       [limit (<limit> type)]
       (in [#limit limit
            #stack {.#Some /stack.empty}])))]

  [static /limit.static]
  [virtual /limit.virtual]
  )

(type: .public Condition
  (-> Environment (Try Environment)))

(implementation: .public monoid
  (Monoid Condition)

  (def: identity
    (|>> {try.#Success}))

  (def: (composite left right)
    (function (_ environment)
      (do try.monad
        [environment (left environment)]
        (right environment)))))

(exception: .public discontinuity)

(def: .public (stack environment)
  (-> Environment (Try Stack))
  (case (the ..#stack environment)
    {.#Some stack}
    {try.#Success stack}

    {.#None}
    (exception.except ..discontinuity [])))

(def: .public discontinue
  (-> Environment Environment)
  (.has ..#stack {.#None}))

(exception: .public (mismatched_stacks [expected Stack
                                        actual Stack])
  (exception.report
   ["Expected" (/stack.format expected)]
   ["Actual" (/stack.format actual)]))

(def: .public (continue expected environment)
  (-> Stack Environment (Try [Stack Environment]))
  (case (the ..#stack environment)
    {.#Some actual}
    (if (# /stack.equivalence = expected actual)
      {try.#Success [actual environment]}
      (exception.except ..mismatched_stacks [expected actual]))

    {.#None}
    {try.#Success [expected (.has ..#stack {.#Some expected} environment)]}))

(def: .public (consumes amount)
  (-> U2 Condition)
  ... TODO: Revisit this definition once lenses/optics have been implemented,
  ... since it can probably be simplified with them.
  (function (_ environment)
    (do try.monad
      [previous (..stack environment)
       current (/stack.pop amount previous)]
      (in (.has ..#stack {.#Some current} environment)))))

(def: .public (produces amount)
  (-> U2 Condition)
  (function (_ environment)
    (do try.monad
      [previous (..stack environment)
       current (/stack.push amount previous)
       .let [limit (|> environment
                       (the [..#limit /limit.#stack])
                       (/stack.max current))]]
      (in (|> environment
              (.has ..#stack {.#Some current})
              (.has [..#limit /limit.#stack] limit))))))

(def: .public (has registry)
  (-> Registry Condition)
  (|>> (revised [..#limit /limit.#registry] (/registry.has registry))
       {try.#Success}))