packages feed

zwirn-0.1.0.0: src/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,
    (!),
    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.Modulate
import Zwirn.Core.Random (chooseWithSeed)
import Zwirn.Core.Types
import Zwirn.Language.Environment
import Zwirn.Language.Evaluate.Convert
import Zwirn.Language.Evaluate.Expression
import Zwirn.Language.Simple
import Zwirn.Language.TypeCheck.Types

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

abstract :: Name -> Expression -> Expression
abstract x (EVar _ n) | x == 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 Nothing "scomb") f)

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

combI :: Expression
combI = EVar Nothing "id"

infixl 0 !

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

link :: InterpreterEnv -> Expression -> Expression
link bs (EVar (Just p) n) = addPosExp p $ fromJust (lookupExp n bs)
link bs (EVar Nothing 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 -> SimpleTerm -> Expression
evaluate bs = link bs . compile

addPosExp :: Position -> 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