{-# LANGUAGE OverloadedStrings #-}
-- | Evaluates CSS media queries for @import & @media.
-- INTERNAL MODULE
module Data.CSS.Preprocessor.Conditions.Expr(
        Expr, Op(..), parse, parse', eval, Datum(..)
    ) where

import Data.CSS.Syntax.Tokens(Token(..))
import Data.Text.Internal (Text(..))
import Data.Text (stripPrefix)

-- | A parsed (post-order) expression.
type Expr = [Op]
-- | Operators understood by media queries.
data Op = And -- ^ Is true if both operands are true
    | Or -- ^ Is true if either operand is true
    | Not -- ^ Is true if it's operand isn't.
    | Var Text -- ^ Queries the value of an externally-specified parameter.
    | Tok Token -- ^ Tokens to be evaluated as specified by caller.
    | MkRatio -- ^ Pushes a ratio value to stack, for querying screensize.
    | Less -- ^ Is the left operand smaller than right?
    | LessEq -- ^ Is the left operand smaller or the same as right?
    | Equal -- ^ Are the operands the same?
    | Greater -- ^ Is the left operand bigger than right?
    | GreaterEq -- ^ Is the left operand bigger or the same as right?
    deriving (Int -> Op -> ShowS
[Op] -> ShowS
Op -> String
(Int -> Op -> ShowS)
-> (Op -> String) -> ([Op] -> ShowS) -> Show Op
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Op] -> ShowS
$cshowList :: [Op] -> ShowS
show :: Op -> String
$cshow :: Op -> String
showsPrec :: Int -> Op -> ShowS
$cshowsPrec :: Int -> Op -> ShowS
Show, Op -> Op -> Bool
(Op -> Op -> Bool) -> (Op -> Op -> Bool) -> Eq Op
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Op -> Op -> Bool
$c/= :: Op -> Op -> Bool
== :: Op -> Op -> Bool
$c== :: Op -> Op -> Bool
Eq)

-- | Parses a media query to postorder form, returning the tokens after the given delimiter.
parse :: Token -> [Token] -> (Expr, [Token])
parse :: Token -> [Token] -> ([Op], [Token])
parse Token
end [Token]
toks = let ([Token]
toks', [Token]
rest) = (Token -> Bool) -> [Token] -> ([Token], [Token])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
end) [Token]
toks in ([Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks' [], [Token]
rest)

--------
---- Shunting Yard parser
--------
-- | Parses a media query to postorder form, given an operator stack.
parse' :: [Token] -> [(Op, Int)] -> Expr
parse' :: [Token] -> [(Op, Int)] -> [Op]
parse' (Token
Whitespace:[Token]
toks) [(Op, Int)]
ops = [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops

parse' (Token
Comma:[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Or Int
10 [(Op, Int)]
ops
parse' (Ident Text
"not":[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Not Int
20 [(Op, Int)]
ops
parse' (Function Text
"not":[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Not Int
0 [(Op, Int)]
ops
parse' (Ident Text
"only":[Token]
toks) [(Op, Int)]
ops = [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops
parse' (Ident Text
"and":[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
And Int
30 [(Op, Int)]
ops
parse' (Ident Text
"or":[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Or Int
30 [(Op, Int)]
ops
parse' (Delim Char
'<':Delim Char
'=':[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
LessEq Int
40 [(Op, Int)]
ops
parse' (Delim Char
'<':[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Less Int
40 [(Op, Int)]
ops
parse' (Delim Char
'>':Delim Char
'=':[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
GreaterEq Int
40 [(Op, Int)]
ops
parse' (Delim Char
'>':[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Greater Int
40 [(Op, Int)]
ops
parse' (Token
Colon:Token
tok:[Token]
toks) [(Op, Int)]
ops = Token -> Op
Tok Token
tok Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
Equal Int
40 [(Op, Int)]
ops
parse' (Delim Char
'/':[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
MkRatio Int
50 [(Op, Int)]
ops

parse' (Token
LeftParen:[Token]
toks) [(Op, Int)]
ops = [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks (Text -> Op
Var Text
")") Int
0 [(Op, Int)]
ops
parse' (Token
RightParen:[Token]
toks) ((Var Text
")", Int
0):[(Op, Int)]
ops) = [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops
parse' (Token
RightParen:[Token]
toks) ((Op
Not, Int
0):[(Op, Int)]
ops) = Op
Not Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops -- Functional not syntax
parse' toks :: [Token]
toks@(Token
RightParen:[Token]
_) ((Op
op, Int
_):[(Op, Int)]
ops) = Op
op Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops
parse' (Token
RightParen:[Token]
_) [] = [] -- Invalid!
parse' (Ident Text
var:[Token]
toks) ops :: [(Op, Int)]
ops@((Op
peek, Int
_):[(Op, Int)]
ops')
    -- First, fix up various range syntaxes.
    | Op
peek Op -> [Op] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Op
Less, Op
LessEq, Op
Greater, Op
GreaterEq] = -- Chained conditions
        Text -> Op
Var Text
var Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: Op
peek Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: Text -> Op
Var Text
var Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops'
    | Just Text
var' <- Text -> Text -> Maybe Text
stripPrefix Text
"max-" Text
var = Text -> Op
Var Text
var' Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
LessEq Int
1000 [(Op, Int)]
ops
    | Just Text
var' <- Text -> Text -> Maybe Text
stripPrefix Text
"min-" Text
var = Text -> Op
Var Text
var' Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
GreaterEq Int
1000 [(Op, Int)]
ops
    | Bool
otherwise = Text -> Op
Var Text
var Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops
parse' (Token
tok:[Token]
toks) [(Op, Int)]
ops = Token -> Op
Tok Token
tok Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks [(Op, Int)]
ops
parse' [] [(Op, Int)]
ops = [Op
op | (Op
op, Int
_) <- [(Op, Int)]
ops]

pushOp :: [Token] -> Op -> Int -> [(Op, Int)] -> Expr
pushOp :: [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
op Int
b ((Op
peek, Int
b'):[(Op, Int)]
ops') | Int
b' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
b = Op
peek Op -> [Op] -> [Op]
forall a. a -> [a] -> [a]
: [Token] -> Op -> Int -> [(Op, Int)] -> [Op]
pushOp [Token]
toks Op
op Int
b [(Op, Int)]
ops'
pushOp [Token]
toks Op
op Int
b [(Op, Int)]
ops = [Token] -> [(Op, Int)] -> [Op]
parse' [Token]
toks ((Op
op, Int
b)(Op, Int) -> [(Op, Int)] -> [(Op, Int)]
forall a. a -> [a] -> [a]
:[(Op, Int)]
ops)

--------
---- Shunting Yard Evaluator
--------
-- | Dynamic types for evaluating media queries.
data Datum = B Bool | N Float | R {Datum -> Float
minv :: Float, Datum -> Float
maxv :: Float} deriving Datum -> Datum -> Bool
(Datum -> Datum -> Bool) -> (Datum -> Datum -> Bool) -> Eq Datum
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Datum -> Datum -> Bool
$c/= :: Datum -> Datum -> Bool
== :: Datum -> Datum -> Bool
$c== :: Datum -> Datum -> Bool
Eq

-- | Evaluates a media query with the given functions for evaluating vars & tokens.
eval :: (Text -> Datum) -> (Token -> Datum) -> Expr -> Bool
eval :: (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' []

eval' :: [Datum] -> (Text -> Datum) -> (Token -> Datum) -> Expr -> Bool
eval' :: [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (B Bool
y:B Bool
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
And:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Bool
x Bool -> Bool -> Bool
&& Bool
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (B Bool
y:B Bool
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Or:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Bool
x Bool -> Bool -> Bool
|| Bool
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (B Bool
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Not:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Bool -> Bool
not Bool
x)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' [Datum]
stack Text -> Datum
v Token -> Datum
t (Var Text
name:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Text -> Datum
v Text
nameDatum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
-- Have tokens lower to variables, to make things easier for the callee.
eval' [Datum]
stack Text -> Datum
v Token -> Datum
t (Tok Token
tok:[Op]
ops) | Token -> Datum
t Token
tok Datum -> Datum -> Bool
forall a. Eq a => a -> a -> Bool
/= Bool -> Datum
B Bool
False = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Token -> Datum
t Token
tokDatum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' [Datum]
stack Text -> Datum
v Token -> Datum
t (Tok (Ident Text
name):[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Text -> Datum
v Text
nameDatum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
-- Ratios should be compared as floating point...
eval' (N Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
MkRatio:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Float -> Datum
N (Float
x Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Less:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
_ Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Less:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y: R Float
x Float
_:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Less:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
_ Float
y:R Float
x Float
_:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Less:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
LessEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
_ Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
LessEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y: R Float
x Float
_:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
LessEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
_ Float
y:R Float
x Float
_:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
LessEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
yMin Float
yMax:R Float
xMin Float
xMax:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Equal:[Op]
ops) =
    [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
xMax Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
yMin Bool -> Bool -> Bool
&& Float
xMin Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
yMax) Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
: [Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y: N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Equal:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Greater:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
y Float
_:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Greater:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:R Float
_ Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Greater:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
y Float
_:R Float
_ Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
Greater:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
GreaterEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
y Float
_:N Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
GreaterEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (N Float
y:R Float
_ Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
GreaterEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (R Float
y Float
_:R Float
_ Float
x:[Datum]
stack) Text -> Datum
v Token -> Datum
t (Op
GreaterEq:[Op]
ops) = [Datum] -> (Text -> Datum) -> (Token -> Datum) -> [Op] -> Bool
eval' (Bool -> Datum
B (Float
x Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
y)Datum -> [Datum] -> [Datum]
forall a. a -> [a] -> [a]
:[Datum]
stack) Text -> Datum
v Token -> Datum
t [Op]
ops
eval' (B Bool
ret:[Datum]
_) Text -> Datum
_ Token -> Datum
_ [] = Bool
ret
eval' [] Text -> Datum
_ Token -> Datum
_ [] = Bool
True -- Special case
eval' [Datum]
_ Text -> Datum
_ Token -> Datum
_ [Op]
_ = Bool
False -- Error handling fallback.