{-# LANGUAGE UnicodeSyntax #-} -- | Term to graph transformation where variable names are resolved to graph edges (or constants) module Resolver (resolve) where import Prelude.Unicode import Term import Graph import GraphRewriting.Graph import GraphRewriting.Graph.Write import Control.Monad import Data.Maybe (fromMaybe) type Compiler = Rewrite NodeLS type Environment = [Name] data Name = Name {symbol ∷ String, boundByLambda ∷ Bool, reference ∷ Compiler Edge} resolve ∷ Λ → Graph NodeLS resolve term = flip execGraph emptyGraph $ do o ← newEdge i ← newNode Initiator {out = o} compile [] o term compile ∷ Environment → Edge → Λ → Compiler () compile env p term = case term of A func arg → do f ← newEdge x ← newEdge void $ newNode Applicator {inp = p, func = f, arg = x} compile env f func compile env x arg Λ x e → do b ← newEdge (v, name) ← bindName True x void $ newNode Abstractor {inp = p, body = b, var = v, name = x} compile (name : env) b e L binds e → do (es, names) ← liftM unzip $ mapM (bindName False) (map fst binds) let env' = names ⧺ env void $ zipWithM (compile env') es (Prelude.map snd binds) compile env' p e C name [] → case env of [ ] → void $ newNode $ fromMaybe (Constant {inp = p, name = name, args = []}) (operator name p) n:ns → if name ≡ symbol n then mergeEdges p =<< reference n else if boundByLambda n then do p' ← newEdge void $ newNode Delimiter {level = 0, inp = p', out = p} compile ns p' term else compile ns p term Term.Case exp cases → do let (pats, _) = unzip cases alts ← replicateM (length cases) newEdge -- edges going from the Case node to the CaseAlts o ← newEdge void $ newNode Graph.Case {inp = p, out = o, alts = alts, names = map constr pats} mapM_ (\(alt, (pat,exp)) → compile env alt (foldr Λ exp (vars pat))) (zip alts cases) -- compile the different cases compile env o exp -- compile the scrutiny operator ∷ String → Edge → Maybe NodeLS operator n p = case n of "+" → op 2 $ liftM (show . sum) . mapM read "-" → op 2 $ liftM (show . minus) . mapM read where minus [x,y] = x - y "==" → op 2 $ \[x,y] → Just $ if x ≡ y then "T" else "F" _ → Nothing where read ∷ Read a ⇒ String → Maybe a read str = case [ x | (x, "") ← reads str ] of [] → Nothing x:_ → Just x op a f = Just Operator {inp = p, ops = [], arity = a, lmop = 0, function = f, name = n} bindName ∷ Bool → String → Compiler (Edge, Name) bindName lambda sym = do v ← newEdge s ← newNode Multiplexer {out = v, ins = []} let ref = do e ← newEdge modifyNode s $ \s → s {ins = e : ins s} return e return (v, Name {symbol = sym, boundByLambda = lambda, reference = ref})