Skip to content

Commit b0bfe24

Browse files
authored
Merge pull request #142 from L0neGamer/fixing-rolling
Fixing rolling
2 parents 6418803 + 6fb3b2a commit b0bfe24

6 files changed

Lines changed: 132 additions & 76 deletions

File tree

src/Tablebot/Plugins/Roll/Dice.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
-- vars - "var" spc1 "!"? ("l_" name spcs "=" spcs lstv | name spcs "=" spcs expr)
4141
-- lstv - nbse "#" base | funcBasics | lstb | name | misc
4242
-- lstb - "{" expr ("," expr)* "}" | "(" lstv ")"
43-
-- expr - term ([+-] expr)? | misc
44-
-- term - nega ([*/] term)?
43+
-- expr - term ([+-] term)* | misc
44+
-- term - nega ([*/] nega)*
4545
-- nega - "-" expo | expo
46-
-- expo - func "^" expo | func
46+
-- expo - func ("^" func)*
4747
-- func - funcBasics | base
4848
-- base - dice | nbse | name
4949
-- nbse - "(" expr ")" | [0-9]+

src/Tablebot/Plugins/Roll/Dice/DiceData.hs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE PatternSynonyms #-}
2+
13
-- |
24
-- Module : Tablebot.Plugins.Roll.Dice.DiceData
35
-- Description : Data structures for dice and other expressions.
@@ -45,9 +47,6 @@ data Program = Program [Statement] (Either ListValues Expr) deriving (Show)
4547
data ArgValue = AVExpr Expr | AVListValues ListValues
4648
deriving (Show)
4749

48-
-- | Alias for `MiscData` that returns a `ListValues`.
49-
type ListValuesMisc = MiscData ListValues
50-
5150
-- | The type for list values.
5251
data ListValues
5352
= -- | Represents `N#B`, where N is a NumBase (numbers, parentheses) and B is a Base (numbase or dice value)
@@ -59,7 +58,7 @@ data ListValues
5958
| -- | A variable that has been defined elsewhere.
6059
LVVar Text
6160
| -- | A misc list values expression.
62-
ListValuesMisc ListValuesMisc
61+
ListValuesMisc (MiscData ListValues)
6362
deriving (Show)
6463

6564
-- | The type for basic list values (that can be used as is for custom dice).
@@ -71,18 +70,49 @@ data ListValues
7170
data ListValuesBase = LVBParen (Paren ListValues) | LVBList [Expr]
7271
deriving (Show)
7372

74-
-- | Alias for `MiscData` that returns an `Expr`.
75-
type ExprMisc = MiscData Expr
73+
-- | The type for a binary operator between one or more `sub` values
74+
data BinOp sub typ where
75+
BinOp :: Operation typ => sub -> [(typ, sub)] -> BinOp sub typ
76+
77+
deriving instance (Show sub, Show typ) => Show (BinOp sub typ)
78+
79+
-- | Convenience pattern for the empty list.
80+
pattern SingBinOp :: (Operation typ) => sub -> BinOp sub typ
81+
pattern SingBinOp a <-
82+
BinOp a []
83+
where
84+
SingBinOp a = BinOp a []
85+
86+
-- | The type class that means we can get an operation on integers from a value.
87+
class Operation a where
88+
getOperation :: a -> (forall n. Integral n => n -> n -> n)
7689

77-
-- | The type of the top level expression. Represents one of addition,
78-
-- subtraction, or a single term; or some misc expression statement.
79-
data Expr = ExprMisc ExprMisc | Add Term Expr | Sub Term Expr | NoExpr Term
90+
-- | The type of the top level expression.
91+
--
92+
-- Represents either a misc expression or additive operations between terms.
93+
data Expr = ExprMisc (MiscData Expr) | Expr (BinOp Term ExprType)
8094
deriving (Show)
8195

82-
-- | The type representing multiplication, division, or a single negated term.
83-
data Term = Multi Negation Term | Div Negation Term | NoTerm Negation
96+
-- | The type of the additive expression, either addition or subtraction.
97+
data ExprType = Add | Sub
98+
deriving (Show, Eq)
99+
100+
instance Operation ExprType where
101+
getOperation Sub = (-)
102+
getOperation Add = (+)
103+
104+
-- | Represents multiplicative operations between (possible) negations.
105+
newtype Term = Term (BinOp Negation TermType)
84106
deriving (Show)
85107

108+
-- | The type of the additive expression, either addition or subtraction.
109+
data TermType = Multi | Div
110+
deriving (Show, Eq)
111+
112+
instance Operation TermType where
113+
getOperation Multi = (*)
114+
getOperation Div = div
115+
86116
-- | The type representing a possibly negated value.
87117
data Negation = Neg Expo | NoNeg Expo
88118
deriving (Show)
@@ -181,11 +211,14 @@ class Converter a b where
181211
instance Converter ListValuesBase ListValues where
182212
promote = LVBase
183213

214+
instance (Converter a sub, Operation typ) => Converter a (BinOp sub typ) where
215+
promote = SingBinOp . promote
216+
184217
instance (Converter a Term) => Converter a Expr where
185-
promote = NoExpr . promote
218+
promote = Expr . promote
186219

187220
instance (Converter a Negation) => Converter a Term where
188-
promote = NoTerm . promote
221+
promote = Term . promote
189222

190223
instance (Converter a Expo) => Converter a Negation where
191224
promote = NoNeg . promote

src/Tablebot/Plugins/Roll/Dice/DiceEval.hs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -205,21 +205,21 @@ instance IOEvalList ListValuesBase where
205205
return (vs, Nothing)
206206
evalShowL' (LVBParen (Paren lv)) = evalShowL lv
207207

208-
instance IOEvalList ListValuesMisc where
208+
instance IOEvalList (MiscData ListValues) where
209209
evalShowL' (MiscVar l) = evalShowL l
210210
evalShowL' (MiscIf l) = evalShowL l
211211

212212
-- | This type class gives a function which evaluates the value to an integer
213213
-- and a string.
214-
class IOEval a where
214+
class ParseShow a => IOEval a where
215215
-- | Evaluate the given item to an integer, a string representation of the
216216
-- value, and the number of RNG calls it took. If the `a` value is a dice
217217
-- value, the values of the dice should be displayed. This function adds
218218
-- the current location to the exception callstack.
219-
evalShow :: (ParseShow a) => a -> ProgramStateM (Integer, Text)
219+
evalShow :: a -> ProgramStateM (Integer, Text)
220220
evalShow a = propagateException (parseShow a) (evalShow' a)
221221

222-
evalShow' :: (ParseShow a) => a -> ProgramStateM (Integer, Text)
222+
evalShow' :: a -> ProgramStateM (Integer, Text)
223223

224224
instance IOEval Base where
225225
evalShow' (NBase nb) = evalShow nb
@@ -384,32 +384,35 @@ evalDieOpHelpKD kd lh is = do
384384
--- Pure evaluation functions for non-dice calculations
385385
-- Was previously its own type class that wouldn't work for evaluating Base values.
386386

387-
-- | Utility function to evaluate a binary operator.
388-
binOpHelp :: (IOEval a, IOEval b, ParseShow a, ParseShow b) => a -> b -> Text -> (Integer -> Integer -> Integer) -> ProgramStateM (Integer, Text)
389-
binOpHelp a b opS op = do
390-
(a', a's) <- evalShow a
391-
(b', b's) <- evalShow b
392-
return (op a' b', a's <> " " <> opS <> " " <> b's)
393-
394-
instance IOEval ExprMisc where
387+
instance IOEval (MiscData Expr) where
395388
evalShow' (MiscVar l) = evalShow l
396389
evalShow' (MiscIf l) = evalShow l
397390

391+
instance (IOEval sub, Operation typ, ParseShow typ) => IOEval (BinOp sub typ) where
392+
evalShow' (BinOp a tas) = foldl' foldel (evalShow a) tas
393+
where
394+
foldel at (typ, b) = do
395+
(a', t) <- at
396+
(b', t') <- evalShow b
397+
return (getOperation typ a' b', t <> " " <> parseShow typ <> " " <> t')
398+
398399
instance IOEval Expr where
399-
evalShow' (NoExpr t) = evalShow t
400400
evalShow' (ExprMisc e) = evalShow e
401-
evalShow' (Add t e) = binOpHelp t e "+" (+)
402-
evalShow' (Sub t e) = binOpHelp t e "-" (-)
401+
evalShow' (Expr e) = evalShow e
403402

404403
instance IOEval Term where
405-
evalShow' (NoTerm f) = evalShow f
406-
evalShow' (Multi f t) = binOpHelp f t "*" (*)
407-
evalShow' (Div f t) = do
408-
(f', f's) <- evalShow f
409-
(t', t's) <- evalShow t
410-
if t' == 0
411-
then evaluationException "division by zero" [parseShow t]
412-
else return (div f' t', f's <> " / " <> t's)
404+
evalShow' (Term (BinOp a tas)) = foldl' foldel (evalShow a) tas
405+
where
406+
foldel at (Div, b) = do
407+
(a', t) <- at
408+
(b', t') <- evalShow b
409+
if b' == 0
410+
then evaluationException "division by zero" [parseShow b]
411+
else return (getOperation Div a' b', t <> " " <> parseShow Div <> " " <> t')
412+
foldel at (typ, b) = do
413+
(a', t) <- at
414+
(b', t') <- evalShow b
415+
return (getOperation typ a' b', t <> " " <> parseShow typ <> " " <> t')
413416

414417
instance IOEval Func where
415418
evalShow' (Func s exprs) = evaluateFunction s exprs

src/Tablebot/Plugins/Roll/Dice/DiceParsing.hs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import Tablebot.Plugins.Roll.Dice.DiceFunctions
2929
import Tablebot.Utility.Parser
3030
import Tablebot.Utility.SmartParser (CanParse (..), (<??>))
3131
import Tablebot.Utility.Types (Parser)
32-
import Text.Megaparsec (MonadParsec (try), choice, failure, optional, some, (<?>), (<|>))
32+
import Text.Megaparsec (MonadParsec (try), choice, failure, many, optional, some, (<?>), (<|>))
3333
import Text.Megaparsec.Char (char, string)
3434
import Text.Megaparsec.Error (ErrorItem (Tokens))
3535

@@ -127,18 +127,29 @@ instance (CanParse b) => CanParse (If b) where
127127
instance (CanParse a) => CanParse (MiscData a) where
128128
pars = (MiscVar <$> pars) <|> (MiscIf <$> pars)
129129

130+
instance (CanParse sub, CanParse typ, Operation typ) => CanParse (BinOp sub typ) where
131+
pars = do
132+
a <- pars
133+
tas <- many parseTas
134+
return $ BinOp a tas
135+
where
136+
parseTas = try $ do
137+
t <- skipSpace *> pars
138+
a' <- skipSpace *> pars
139+
return (t, a')
140+
141+
instance CanParse ExprType where
142+
pars = try (char '+' $> Add) <|> try (char '-' $> Sub)
143+
130144
instance CanParse Expr where
131145
pars =
132-
(ExprMisc <$> pars)
133-
<|> ( do
134-
t <- pars
135-
binOpParseHelp '+' (Add t) <|> binOpParseHelp '-' (Sub t) <|> (return . NoExpr) t
136-
)
146+
(ExprMisc <$> pars) <|> (Expr <$> pars)
147+
148+
instance CanParse TermType where
149+
pars = try (char '*' $> Multi) <|> try (char '/' $> Div)
137150

138151
instance CanParse Term where
139-
pars = do
140-
t <- pars
141-
binOpParseHelp '*' (Multi t) <|> binOpParseHelp '/' (Div t) <|> (return . NoTerm) t
152+
pars = Term <$> pars
142153

143154
instance CanParse Func where
144155
pars = functionParser integerFunctions Func <|> NoFunc <$> pars
@@ -176,7 +187,7 @@ instance CanParse NumBase where
176187
<|> Value
177188
<$> integer <??> "could not parse integer"
178189
where
179-
unnest (Paren (NoExpr (NoTerm (NoNeg (NoExpo (NoFunc (NBase (NBParen e)))))))) = e
190+
unnest (Paren (Expr (SingBinOp (Term (SingBinOp (NoNeg (NoExpo (NoFunc (NBase (NBParen e)))))))))) = e
180191
unnest e = e
181192

182193
instance (CanParse a) => CanParse (Paren a) where
@@ -282,7 +293,7 @@ instance ParseShow ArgValue where
282293
instance ParseShow ListValues where
283294
parseShow (LVBase e) = parseShow e
284295
parseShow (MultipleValues nb b) = parseShow nb <> "#" <> parseShow b
285-
parseShow (LVFunc s n) = funcInfoName s <> "(" <> T.intercalate "," (parseShow <$> n) <> ")"
296+
parseShow (LVFunc s n) = funcInfoName s <> "(" <> T.intercalate ", " (parseShow <$> n) <> ")"
286297
parseShow (LVVar t) = t
287298
parseShow (ListValuesMisc l) = parseShow l
288299

@@ -294,19 +305,26 @@ instance (ParseShow a) => ParseShow (MiscData a) where
294305
parseShow (MiscVar l) = parseShow l
295306
parseShow (MiscIf l) = parseShow l
296307

308+
instance (ParseShow sub, ParseShow typ) => ParseShow (BinOp sub typ) where
309+
parseShow (BinOp a tas) = parseShow a <> T.concat (fmap (\(t, a') -> " " <> parseShow t <> " " <> parseShow a') tas)
310+
311+
instance ParseShow ExprType where
312+
parseShow Add = "+"
313+
parseShow Sub = "-"
314+
315+
instance ParseShow TermType where
316+
parseShow Multi = "*"
317+
parseShow Div = "/"
318+
297319
instance ParseShow Expr where
298-
parseShow (Add t e) = parseShow t <> " + " <> parseShow e
299-
parseShow (Sub t e) = parseShow t <> " - " <> parseShow e
300-
parseShow (NoExpr t) = parseShow t
320+
parseShow (Expr e) = parseShow e
301321
parseShow (ExprMisc e) = parseShow e
302322

303323
instance ParseShow Term where
304-
parseShow (Multi f t) = parseShow f <> " * " <> parseShow t
305-
parseShow (Div f t) = parseShow f <> " / " <> parseShow t
306-
parseShow (NoTerm f) = parseShow f
324+
parseShow (Term f) = parseShow f
307325

308326
instance ParseShow Func where
309-
parseShow (Func s n) = funcInfoName s <> "(" <> T.intercalate "," (parseShow <$> n) <> ")"
327+
parseShow (Func s n) = funcInfoName s <> "(" <> T.intercalate ", " (parseShow <$> n) <> ")"
310328
parseShow (NoFunc b) = parseShow b
311329

312330
instance ParseShow Negation where

src/Tablebot/Plugins/Roll/Dice/DiceStats.hs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,6 @@ getStats d = (modalOrder, expectation d, standardDeviation d)
4444
vals = toList d
4545
modalOrder = fst <$> sortBy (\(_, r) (_, r') -> compare r' r) vals
4646

47-
-- | Convenience wrapper which gets the range of the given values then applies
48-
-- the function to the resultant distributions.
49-
combineRangesBinOp :: (MonadException m, Range a, Range b, ParseShow a, ParseShow b) => (Integer -> Integer -> Integer) -> a -> b -> m Experiment
50-
combineRangesBinOp f a b = do
51-
d <- range a
52-
d' <- range b
53-
return $ f <$> d <*> d'
54-
5547
rangeExpr :: (MonadException m) => Expr -> m Distribution
5648
rangeExpr e = do
5749
ex <- range e
@@ -114,20 +106,30 @@ instance (RangeList a) => RangeList (Var a) where
114106
rangeList' (Var _ a) = rangeList a
115107
rangeList' (VarLazy _ a) = rangeList a
116108

109+
instance (ParseShow typ, Range sub) => Range (BinOp sub typ) where
110+
range' (BinOp a tas) = foldl' foldel (range a) tas
111+
where
112+
foldel at (typ, b) = do
113+
a' <- at
114+
b' <- range b
115+
return $ getOperation typ <$> a' <*> b'
116+
117117
instance Range Expr where
118-
range' (NoExpr t) = range t
119-
range' (Add t e) = combineRangesBinOp (+) t e
120-
range' (Sub t e) = combineRangesBinOp (-) t e
118+
range' (Expr e) = range e
121119
range' (ExprMisc t) = range t
122120

123121
instance Range Term where
124-
range' (NoTerm t) = range t
125-
range' (Multi t e) = combineRangesBinOp (*) t e
126-
range' (Div t e) = do
127-
d <- range t
128-
d' <- range e
129-
-- If 0 is always the denominator, the distribution will be empty.
130-
return $ div <$> d <*> from (assuming (/= 0) (run d'))
122+
range' (Term (BinOp a tas)) = foldl' foldel (range a) tas
123+
where
124+
foldel at (Div, b) = do
125+
a' <- at
126+
b' <- range b
127+
-- If 0 is always the denominator, the distribution will be empty.
128+
return $ getOperation Div <$> a' <*> from (assuming (/= 0) (run b'))
129+
foldel at (typ, b) = do
130+
a' <- at
131+
b' <- range b
132+
return $ getOperation typ <$> a' <*> b'
131133

132134
instance Range Negation where
133135
range' (Neg t) = fmap negate <$> range t

src/Tablebot/Plugins/Roll/Plugin.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ genchar = Command "genchar" (snd $ head rpgSystems') (toCommand <$> rpgSystems')
204204
rpgSystems :: [(Text, ListValues)]
205205
rpgSystems =
206206
[ ("dnd", MultipleValues (Value 6) (DiceBase (Dice (NBase (Value 4)) (Die (Value 6)) (Just (DieOpRecur (DieOpOptionKD Drop (Low (Value 1))) Nothing))))),
207-
("wfrp", MultipleValues (Value 8) (NBase (NBParen (Paren (Add (promote (Value 20)) (promote (Die (Value 10))))))))
207+
("wfrp", MultipleValues (Value 8) (NBase (NBParen (Paren (Expr (BinOp (promote (Value 20)) [(Add, promote (Die (Value 10)))]))))))
208208
]
209209

210210
-- | Small help page for gen char.

0 commit comments

Comments
 (0)