This adds 0-point dings which decline to print out any score modifiers.
from the generated skeleton and this initial ``!`` will be stripped
from the type before consulting the following choices.
- * The word ``simple`` defines a section of define flags whose invoked
- scores are simply summed. ``extra`` here should be the section's
- maximum value.
+ There are a few base-case scoring engines:
- * The word ``equal`` defines a section of equally-weighted flags; again,
- ``extra`` should be the section's maximum value.
+ * The word ``simple`` defines a section of define flags whose invoked
+ scores are simply summed. ``extra`` here should be the section's
+ maximum value.
- * The word ``bounding`` followed by (whitespace and) another ``type`` will
- behave as that type except that the score will be between zero and that
- type's derived maximum. That is, this section will behave as if it had
- that ``type`` but will yield no scores below zero and no extra credit.
+ * The word ``equal`` defines a section of equally-weighted flags; again,
+ ``extra`` should be the section's maximum value.
- * The word ``nonneg`` bounds the section's score from below at ``0``; that
- is, it permits extra credit but not extra loss.
+ * The word ``seconly`` defines a section with no flags (unless possibly
+ combined with one of the modifiers below) but instead just takes a
+ literal score after the ``@section`` line in the data file. (The
+ parser also accepts a literal ``!`` in this position, in which case it
+ will raise an error unless some modifier below overrides the score;
+ this facilitates common rationale text even in this kind of section.)
- * The word ``zeroing`` followed by (whitespace and) another ``type`` will
- permit the definitions of flags with argument ``!0`` which will set the
- section score to zero.
+ There are, additionally, some modifiers available:
- * The word ``0`` is a shorthand for ``zeroing bounding simple``.
+ * The word ``bounding`` followed by (whitespace and) another ``type``
+ will behave as that type except that the score will be between zero
+ and that type's derived maximum. That is, this section will behave as
+ if it had that ``type`` but will yield no scores below zero and no
+ extra credit.
+
+ * The word ``nonneg`` behaves like ``bounding`` but bounds the section's
+ score from below at ``0``; that is, it permits extra credit but not
+ extra loss.
+
+ * The word ``commenting`` followed by (whitespace and) another ``type``
+ will permit the definitions of flags with argument ``!C`` which will
+ not influence the score at all and will not print out a score modifier
+ before the flag text in generated reports.
+
+ * The word ``zeroing`` followed by (whitespace and) another ``type``
+ will permit the definitions of flags with argument ``!0`` which will
+ set the section score to zero.
+
+ Some shorthands are defined:
+
+ * The word ``0`` is a shorthand for ``zeroing bounding commenting simple``.
* ``friendly-name`` is the section heading as presented to students. It may
contain spaces, and is in fact the remainder of the @ line.
Grade.Score.Zeroing,
Grade.Score.Setting,
Grade.Score.Bounding,
+ Grade.Score.Commenting,
Grade.Score.SectionOnly,
Grade.Score.Simple,
Grade.Score.EqualWeighted,
--- /dev/null
+-- | Allow the definition of dings that do not affect the score
+-- in any way.
+--
+-- When it comes time to print, there won't be any (0.0) or
+-- similar at the top of the comment block.
+
+module Grade.Score.Commenting (commenting) where
+
+import Control.Monad (join)
+import qualified Text.Trifecta as T
+import Grade.Types (ExSecCallback(..), SecCallback(..))
+
+parseCommented :: (T.TokenParsing f, Monoid sds)
+ => f () -- ^ How do we parse a comment-only ding?
+ -> f (sdt,sds) -- ^ What is the underlying ding parser?
+ -> f (Maybe sdt, sds)
+parseCommented pc pd = T.choice
+ [ -- Try parsing a zeroizing form
+ T.try pc *> pure (Nothing, mempty)
+ , -- Otherwise, invoke the underlying parser
+ (\(a,b) -> (Just a, b)) <$> pd
+ ]
+
+printCommented :: (sds -> sat -> sdt -> Maybe String)
+ -> sds -> sat -> Maybe sdt -> Maybe String
+printCommented po ss sa = join . fmap (po ss sa)
+
+scoreCommented :: Monoid sdt
+ => (sds -> sat -> sdt -> Either String Double)
+ -> sds -> sat -> Maybe sdt -> Either String Double
+scoreCommented ug ss sa = ug ss sa . maybe mempty id
+
+commenting :: (T.TokenParsing f) => f () -> ExSecCallback f -> ExSecCallback f
+commenting pc shp =
+ case shp of
+ ExSecCB (SC us up uo ug um) ->
+ ExSecCB (SC us
+ (parseCommented pc up)
+ (printCommented uo)
+ (scoreCommented ug)
+ um)
import qualified Grade.Score.EqualWeighted as GSE
import qualified Grade.Score.Simple as GSS
+import qualified Grade.Score.SectionOnly as GSSO
import qualified Grade.Score.Bounding as GSB
+import qualified Grade.Score.Commenting as GSC
import qualified Grade.Score.Zeroing as GSZ
import Grade.Types
sectys :: T.TokenParsing m => m (ExSecCallback m)
sectys = T.choice
[ -- A shortcut
- T.symbolic '0' *> (GSZ.zeroing zs <$> GSB.bounding GSB.Both <$> GSS.sectySimple)
+ T.symbolic '0' *> ( GSZ.zeroing zs
+ <$> GSB.bounding GSB.Both
+ <$> GSC.commenting cs
+ <$> GSS.sectySimple)
, -- Look ma, a little language
-- Base cases
T.symbol "simple" *> GSS.sectySimple
, T.symbol "equal" *> GSE.sectyEqualWeighted
+ , T.symbol "seconly" *> GSSO.sectySectionOnly
, -- Recursive cases
- T.symbol "bounding" *> (GSB.bounding GSB.Both <$> sectys)
- , T.symbol "nonneg" *> (GSB.bounding GSB.Below <$> sectys)
- , T.symbol "zeroing" *> (GSZ.zeroing zs <$> sectys)
+ T.symbol "bounding" *> (GSB.bounding GSB.Both <$> sectys)
+ , T.symbol "nonneg" *> (GSB.bounding GSB.Below <$> sectys)
+ , T.symbol "commenting" *> (GSC.commenting cs <$> sectys)
+ , T.symbol "zeroing" *> (GSZ.zeroing zs <$> sectys)
]
where
zs = T.symbol "!0" *> pure ()
+ cs = T.symbol "!C" *> pure ()
---