git @ Cat's Eye Technologies Robin / master src / Language / Robin / Intrinsics.hs
master

Tree @master (Download .tar.gz)

Intrinsics.hs @masterraw · history · blame

-- Copyright (c) 2012-2024, Chris Pressey, Cat's Eye Technologies.
-- This file is distributed under a 2-clause BSD license.  See LICENSES/ dir.
-- SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Robin

module Language.Robin.Intrinsics where

import Language.Robin.Expr
import Language.Robin.Env (Env, fromList, insert)
import Language.Robin.Eval


head_ :: Evaluable
head_ env (List [expr]) cc =
    evalToList cc env expr (\val ->
       case val of
           List (a:_) -> cc a
           other -> errMsg cc "expected-list" other)  -- FIXME: should really be "expected-nonempty-list"
head_ env other cc = errMsg cc "illegal-arguments" other

tail_ :: Evaluable
tail_ env (List [expr]) cc =
    evalToList cc env expr (\val ->
        case val of
            List (_:b) -> cc (List b)
            other -> errMsg cc "expected-list" other)
tail_ env other cc = errMsg cc "illegal-arguments" other

prepend :: Evaluable
prepend env (List [e1, e2]) cc =
    evalB cc env e1 (\x1 ->
        evalToList cc env e2 (\(List x2) -> cc $ List (x1:x2)))
prepend env other cc = errMsg cc "illegal-arguments" other

equalP :: Evaluable
equalP env (List [e1, e2]) cc =
    evalB cc env e1 (\x1 -> evalB cc env e2 (\x2 -> cc $ Boolean (x1 == x2)))
equalP env other cc = errMsg cc "illegal-arguments" other

predP pred env (List [expr]) cc =
    evalB cc env expr (\x -> cc $ Boolean $ pred x)
predP pred env other cc = errMsg cc "illegal-arguments" other

symbolP = predP isSymbol
listP = predP isList
operatorP = predP isOperator
numberP = predP isNumber

subtract_ :: Evaluable
subtract_ = evalTwoNumbers (\x y cc -> cc $ Number (x - y))

sign :: Evaluable
sign env (List [expr]) cc =
    let
        sgn x = if x == 0 then 0 else if x < 0 then -1 else 1
    in
        evalToNumber cc env expr (\(Number xv) ->
            cc $ Number $ sgn xv)
sign env other cc = errMsg cc "illegal-arguments" other

if_ :: Evaluable
if_ env (List [testExpr, trueExpr, falseExpr]) cc =
    evalToBoolean cc env testExpr (\(Boolean b) ->
        if b then eval env trueExpr cc else eval env falseExpr cc)
if_ env other cc = errMsg cc "illegal-arguments" other

eval_ :: Evaluable
eval_ env (List [envlist, form]) cc =
    evalB cc env envlist (\newEnvVal ->
        evalB cc env form (\body ->
            eval newEnvVal body cc))
eval_ env other cc = errMsg cc "illegal-arguments" other

fexpr :: Evaluable
fexpr env (List [args@(List [(Symbol argsS), (Symbol envS)]), body]) cc =
    cc $ Operator "<operator>" $ makeFexpr env args body
fexpr env other cc = errMsg cc "illegal-arguments" other

abort :: Evaluable
abort env (List [expr]) cc =
    eval env expr (\v -> cc $ Abort v)
abort env other cc = errMsg cc "illegal-arguments" other

recover :: Evaluable
recover env (List [expr, (Symbol okName), okExpr, (Symbol abortName), abortExpr]) cc =
    eval env expr (\result ->
        case result of
            e@(Abort contents) ->
                eval (insert abortName contents env) abortExpr cc
            other ->
                eval (insert okName other env) okExpr cc)
recover env other cc = errMsg cc "illegal-arguments" other

robinIntrinsics :: Env
robinIntrinsics = fromList $ map (\(name,bif) -> (name, Operator name bif))
      [
        ("head",     head_),
        ("tail",     tail_),
        ("prepend",  prepend),
        ("list?",    listP),
        ("symbol?",  symbolP),
        ("operator?",operatorP),
        ("number?",  numberP),
        ("equal?",   equalP),
        ("subtract", subtract_),
        ("sign",     sign),
        ("fexpr",    fexpr),
        ("eval",     eval_),
        ("if",       if_),
        ("abort",    abort),
        ("recover",  recover)
      ]