jl-0.1.0: src/JL/Interpreter.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
-- |
module JL.Interpreter where
import qualified Data.Text as T
import JL.Printer
import JL.Types
-- | Eval core.
eval :: Core -> Core
eval (ApplicationCore op arg) =
case eval op of
LambdaCore param expr ->
case eval arg of
a@VariableCore {} ->
error (T.unpack (prettyCore a <> " is not in scope!"))
a -> eval (subst param a expr)
EvalCore f -> f (eval arg)
_ -> error (T.unpack (prettyCore op <> " is not a function!"))
eval (IfCore c a b) =
case eval c of
ConstantCore (BoolConstant True) -> eval a
ConstantCore (BoolConstant False) -> eval b
_ -> error ("type error for if condition, should be bool")
eval (RecordCore hms) =
RecordCore (fmap eval hms)
eval (ArrayCore hms) =
ArrayCore (fmap eval hms)
eval e = e
-- | Substitute name in function body.
subst :: Variable -> Core -> Core -> Core
subst name val e@(VariableCore name')
| name == name' = val
| otherwise = e
subst name val (LambdaCore name' e)
| name /= name' = LambdaCore name' (subst name val e)
subst name val (ApplicationCore f a) =
ApplicationCore (subst name val f) (subst name val a)
subst name val (IfCore f a b) =
IfCore (subst name val f) (subst name val a) (subst name val b)
subst name val (RecordCore hm) = RecordCore (fmap (subst name val) hm)
subst name val (ArrayCore hm) = ArrayCore (fmap (subst name val) hm)
subst _ _ e = e
-- | Remove syntactic sugar and convert into executable form.
desugar :: Expression -> Core
desugar =
\case
(InfixExpression a f b) ->
ApplicationCore (ApplicationCore (VariableCore f) (desugar a)) (desugar b)
VariableExpression v -> VariableCore v
LambdaExpression v e -> LambdaCore v (desugar e)
ApplicationExpression f a -> ApplicationCore (desugar f) (desugar a)
IfExpression a b c -> IfCore (desugar a) (desugar b) (desugar c)
RecordExpression pars -> RecordCore (fmap desugar pars)
ArrayExpression as -> ArrayCore (fmap desugar as)
ConstantExpression c -> ConstantCore c
SubscriptExpression subscripted subscripts ->
let index =
\c k ->
ApplicationCore
(ApplicationCore
(VariableCore (Variable "get"))
(case k of
ExpressionSubscript e -> desugar e
PropertySubscript t -> ConstantCore (StringConstant t)))
c
in case subscripted of
WildcardSubscripted ->
LambdaCore
(Variable "a'")
(foldl index (VariableCore (Variable "a'")) subscripts)
ExpressionSubscripted e -> foldl index (desugar e) subscripts