... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

(.require
 [library
  [lux (.except #Local)
   [abstract
    [equivalence (.only Equivalence)]
    [hash (.only Hash)]]
   [control
    ["[0]" pipe]
    [function
     [predicate (.only Predicate)]]]
   [data
    [text (.only Injection)
     ["%" \\injection]]]
   [math
    [number
     ["n" natural]
     ["i" integer]]]
   [meta
    [macro
     ["[0]" template]]]]]
 [//
  ["[0]" register (.only Register)]])

(every .public Variable
  (Variant
   {#Local Register}
   {#Foreign Register}))

(the .public equivalence
  (Equivalence Variable)
  (implementation
   (the (= expected actual)
     (`` (when [expected actual]
           (,, (template.with [<tag>]
                 [[{<tag> expected'} {<tag> actual'}]
                  (n.= expected' actual')]

                 [#Local]
                 [#Foreign]))

           _
           false)))))

(alias [=]
       ..equivalence)

(the .public hash
  (Hash Variable)
  (implementation
   (the equivalence
     ..equivalence)
   
   (the hash
     (|>> (pipe.when
            (,, (template.with [<factor> <tag>]
                  [{<tag> register}
                   (|> register
                       (of n.hash hash)
                       (n.* <factor>))]

                  [2 #Local]
                  [3 #Foreign])))
          ``))))

(the .public self
  (template.macro (self)
    [{..#Local register.first}]))

(the .public self?
  (Predicate Variable)
  (|>> (pipe.when
         (..self)
         true

         _
         false)))

(the .public injection
  (Injection Variable)
  (|>> (pipe.when
         {#Local local}
         (%.message "+" (%.natural local))
         
         {#Foreign foreign}
         (%.message "-" (%.natural foreign)))))
