summaryrefslogtreecommitdiff
path: root/src/lib/Codec/Pesto/Serialize.lhs
blob: f07e871bbb0482f9df230e37eefa518a759a2a5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Serializing
-----------

.. class:: nodoc

> module Codec.Pesto.Serialize (serialize) where
> import Data.Char (isSpace, isLetter)
> import Data.Ratio (numerator, denominator)
>
> import {-# SOURCE #-} Codec.Pesto.Parse

> class Serializeable a where
> 	serialize :: a -> String

.. class:: todo

- Add instance for graph
- use :math:`\mathcal{O}(1)` string builder

Finally transform linear stream of instructions into a string again:

> instance Serializeable a => Serializeable [a] where
> 	serialize ops = unlines $ map serialize ops

> instance Serializeable Instruction where
> 	serialize (Annotation s) = quote '(' ')' s
> 	serialize (Ingredient q) = '+':serialize q
> 	serialize (Tool q) = '&':serialize q
> 	serialize (Action s) = quote '[' ']' s
> 	serialize (Reference q) = '*':serialize q
> 	serialize (Result q) = '>':serialize q
> 	serialize (Alternative q) = '|':serialize q
> 	serialize (Directive s) = '%':serializeQstr s
> 	serialize (Unknown s) = s

> instance Serializeable Quantity where
> 	serialize (Quantity a b "") = serialize a ++ " " ++ serializeQstr b
> 	serialize (Quantity (Exact (AmountStr "")) "" c) = serializeQstr c
> 	serialize (Quantity a "" c) = serialize a ++ " _ " ++ serializeQstr c
> 	serialize (Quantity a b c) = serialize a ++ " " ++ serializeQstr b ++ " " ++ serializeQstr c

> instance Serializeable Approximately where
> 	serialize (Range a b) = serialize a ++ "-" ++ serialize b
> 	serialize (Approx a) = '~':serialize a
> 	serialize (Exact a) = serialize a

There are two special cases here, both for aesthetic reasons:

1) If the denominator is one we can just skip printing it, because
   :math:`\frac{2}{1} = 2` and
2) if the numerator is larger than the denominator use mixed fraction notation,
   because :math:`\frac{7}{2} = 3+\frac{1}{2}`

> instance Serializeable Amount where
> 	serialize (AmountRatio a) | denominator a == 1 = show (numerator a)
> 	serialize (AmountRatio a) | numerator a > denominator a =
> 		show full ++ "/" ++ show num ++ "/" ++ show denom
> 		where
> 			full = numerator a `div` denom
> 			num = numerator a - full * denom
> 			denom = denominator a
> 	serialize (AmountRatio a) = show (numerator a) ++ "/" ++ show (denominator a)
> 	serialize (AmountStr s) = serializeQstr s

> serializeQstr "" = "_"
> serializeQstr s | (not . isLetter . head) s || hasSpaces s = quote '"' '"' s
> serializeQstr s = s
> hasSpaces = any isSpace
> quote start end s = [start] ++ concatMap (\c -> if c == end then ['\\', end] else [c]) s ++ [end]