packages feed

zwirn-0.2.2.0: src/zwirn-lang/Zwirn/Language/Evaluate/SKI.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}

module Zwirn.Language.Evaluate.SKI
  ( evaluate,
    compile,
    (!),
    removePosExp,
  )
where

{-
    SKI.hs - evaluate epxressions via the SKI combinator calculus,
    code adapted from https://kseo.github.io/posts/2016-12-30-write-you-an-interpreter.html
    Copyright (C) 2023, Martin Gius

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
-}

import Data.Maybe (fromJust)
import Data.Text (unpack)
import Zwirn.Core.Cord
import Zwirn.Core.Core
import Zwirn.Core.Lib.Core
import Zwirn.Core.Lib.Modulate
import Zwirn.Core.Lib.Random (chooseWithSeed)
import Zwirn.Core.Types
import Zwirn.Language.Environment
import Zwirn.Language.Evaluate.Convert
import Zwirn.Language.Evaluate.Expression
import Zwirn.Language.Location
import Zwirn.Language.Simple
import Zwirn.Language.TypeCheck.Types

compile :: LocSimpleTerm -> Expression
compile (Located p (SVar n)) = EVar (Located p n)
compile (Located _ (SApp fun arg)) = EApp (compile fun) (compile arg)
compile (Located _ (SLambda x body)) = abstract x (compile body)
compile (Located p (SNum x)) = EZwirn $ addInfo p $ pure $ ENum $ read $ unpack x
compile (Located p (SText x)) = EZwirn $ addInfo p $ pure $ EText x
compile (Located _ (SSeq xs)) = ESeq $ map compile xs
compile (Located _ (SStack xs)) = EStack $ map compile xs
compile (Located _ (SChoice i xs)) = EChoice i $ map compile xs
compile (Located _ (SInfix s1 n s2)) = EApp (EApp (EVar n) (compile s1)) (compile s2)
compile (Located _ (SBracket s)) = compile s
compile (Located _ SRest) = EZwirn silence

abstract :: Name -> Expression -> Expression
abstract x (EVar n) | x == lValue n = combI
abstract x (EApp fun arg) = combS (abstract x fun) (abstract x arg)
abstract x (ESeq xs) = ESeq $ map (abstract x) xs
abstract x (EStack xs) = EStack $ map (abstract x) xs
abstract x (EChoice i xs) = EChoice i $ map (abstract x) xs
abstract _ k = combK k

combS :: Expression -> Expression -> Expression
combS f = EApp (EApp (EVar $ noLoc "scomb") f)

combK :: Expression -> Expression
combK = EApp (EVar $ noLoc "const")

combI :: Expression
combI = EVar (noLoc "id")

infixl 0 !

(!) :: Expression -> Expression -> Expression
(EZwirn fp) ! (EZwirn x) = EZwirn $ apply (fmap (\(ELam f) -> toZwirn . f . fromZwirn) fp) x
_ ! _ = error "Error in (!)"

link :: InterpreterEnv -> Expression -> Expression
link bs (EVar n) = addPosExp (lLoc n) $ fromJust (lookupExp (lValue n) bs)
-- link bs (EVar  n) = fromJust (lookupExp n bs)
link bs (EApp f x) = link bs f ! link bs x
link bs (ESeq xs) = EZwirn $ fastcat $ map (toZwirn . link bs) xs
link bs (EStack xs) = EZwirn $ stack $ map (toZwirn . link bs) xs
link bs (EChoice i xs) = EZwirn $ chooseWithSeed i $ map (toZwirn . link bs) xs
link _ e = e

evaluate :: InterpreterEnv -> LocSimpleTerm -> Expression
evaluate bs = link bs . compile

addPosExp :: SrcLoc -> Expression -> Expression
addPosExp p (EZwirn x) = EZwirn $ withInfos (p :) x
addPosExp _ x = x

removePosExp :: Expression -> Expression
removePosExp (EZwirn z) = EZwirn $ removeInfo z
removePosExp x = x