{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

module Unison.Symbol where

import Data.Set qualified as Set
import Unison.ABT qualified as ABT
import Unison.Prelude
import Unison.Var (Var (..))
import Unison.Var qualified as Var

data Symbol = Symbol !Word64 Var.Type deriving ((forall x. Symbol -> Rep Symbol x)
-> (forall x. Rep Symbol x -> Symbol) -> Generic Symbol
forall x. Rep Symbol x -> Symbol
forall x. Symbol -> Rep Symbol x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Symbol -> Rep Symbol x
from :: forall x. Symbol -> Rep Symbol x
$cto :: forall x. Rep Symbol x -> Symbol
to :: forall x. Rep Symbol x -> Symbol
Generic)

instance ABT.Var Symbol where
  freshIn :: Set Symbol -> Symbol -> Symbol
freshIn Set Symbol
vs Symbol
s | Set Symbol -> Bool
forall a. Set a -> Bool
Set.null Set Symbol
vs Bool -> Bool -> Bool
|| Symbol -> Set Symbol -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.notMember Symbol
s Set Symbol
vs = Symbol
s -- already fresh!
  freshIn Set Symbol
vs s :: Symbol
s@(Symbol Word64
i Type
n) = case Int -> Set Symbol -> Symbol
forall a. Int -> Set a -> a
Set.elemAt (Set Symbol -> Int
forall a. Set a -> Int
Set.size Set Symbol
vs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Set Symbol
vs of
    Symbol Word64
i2 Type
_ -> if Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> Word64
i2 then Symbol
s else Word64 -> Type -> Symbol
Symbol (Word64
i2 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1) Type
n

instance Var Symbol where
  typed :: Type -> Symbol
typed Type
t = Word64 -> Type -> Symbol
Symbol Word64
0 Type
t
  typeOf :: Symbol -> Type
typeOf (Symbol Word64
_ Type
t) = Type
t
  freshId :: Symbol -> Word64
freshId (Symbol Word64
id Type
_) = Word64
id
  freshenId :: Word64 -> Symbol -> Symbol
freshenId Word64
id (Symbol Word64
_ Type
n) = Word64 -> Type -> Symbol
Symbol Word64
id Type
n

instance Eq Symbol where
  Symbol Word64
id1 Type
name1 == :: Symbol -> Symbol -> Bool
== Symbol Word64
id2 Type
name2 = Word64
id1 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
id2 Bool -> Bool -> Bool
&& Type
name1 Type -> Type -> Bool
forall a. Eq a => a -> a -> Bool
== Type
name2

instance Ord Symbol where
  Symbol Word64
id1 Type
name1 compare :: Symbol -> Symbol -> Ordering
`compare` Symbol Word64
id2 Type
name2 = (Word64
id1, Type
name1) (Word64, Type) -> (Word64, Type) -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (Word64
id2, Type
name2)

instance Show Symbol where
  show :: Symbol -> String
show (Symbol Word64
0 Type
n) = Type -> String
forall a. Show a => a -> String
show Type
n
  show (Symbol Word64
id Type
n) = Type -> String
forall a. Show a => a -> String
show Type
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word64 -> String
forall a. Show a => a -> String
show Word64
id

symbol :: Text -> Symbol
symbol :: Text -> Symbol
symbol = Text -> Symbol
forall v. Var v => Text -> v
Var.named