0 | module Text.Molfile.Parser
  1 |
  2 | import Data.Array.Mutable
  3 | import Data.SortedMap as SM
  4 | import Data.Finite
  5 | import Syntax.T1
  6 | import Text.Molfile.Parser.KeyVal
  7 | import Text.Molfile.Parser.Util
  8 | import Text.Molfile.Parser.V2000
  9 | import Text.Molfile.Parser.V3000
 10 | import Text.Molfile.Writer.Util
 11 |
 12 | import public Text.Molfile.Parser.Stack
 13 |
 14 | %default total
 15 |
 16 | --------------------------------------------------------------------------------
 17 | -- Parser
 18 | --------------------------------------------------------------------------------
 19 |
 20 | ctabTrans : Lex1 q CSz CSTCK
 21 | ctabTrans =
 22 |   lex1
 23 |     [ E H1       $ dfa [convline (star dot >> newline) h1]
 24 |     , E H2       $ dfa [convline (star dot >> newline) h2]
 25 |     , E H3       $ dfa [convline (star dot >> newline) h3]
 26 |     , E Counts   $ dfa [mv30prefix 2 v3000 CountsV3, convline v2000 countsV2]
 27 |     , E SData    $ dfa sdata
 28 |     , E SDValue  $ dfa sdvalue
 29 |     , E EndMol   $ dfa sdata
 30 |
 31 |     -- V2000
 32 |     , E Coords2  $ spaced Coords2 [conv coordinatesV2 coordsV2]
 33 |     , E Sym2     $ dfa $ valsN (fill 4 . (" "++) . dispIso) (setIso Chrg2) isos
 34 |     , E Chrg2    $ dfa [newline zeroes atomV2, line 2 (sdigits 5) chargeV2]
 35 |     , E Bnd2     $ dfa [line 0 (sdigits 6) bond]
 36 |     , E Prop2    $ dfa prop2
 37 |
 38 |     -- V3000
 39 |     , E CountsV3   $ spaced CountsV3 [cexpr' "COUNTS" ACount]
 40 |     , E EmptyV3    $ dfa emptyEnd
 41 |     , E ACount     $ spaced ACount [conv (plus digit) newV3]
 42 |     , E BCount     $ spaced BCount [conv (plus digit) bondsV3]
 43 |     , E CountEnd   $ dfa [newlines' 2 (dots >> newline >> beginV3 "ATOM") Atom3]
 44 |     -- Atoms V3000
 45 |     , E Atom3      $ dfa [cexpr' mv30 Index3]
 46 |     , E Index3     $ spaced Index3 [conv (plus digit) indexV3]
 47 |     , E Sym3       $ spaced Sym3 (vals dispIso (setIso Coords3) isos)
 48 |     , E Coords3    $ spaced Coords3 [conv coordinatesV3 coordsV3]
 49 |     , E AAMap      $ dfa [conv' (plus ' ' >> plus digit) Prop3]
 50 |     , E Prop3      $ spaced Prop3 prop3
 51 |     , E AtomEnd    $ dfa [newline (endV3 "ATOM") beginBondV3]
 52 |     -- Bonds V3000
 53 |     , E BondBegin  $ dfa [newline' (beginV3 "BOND") Bnd3]
 54 |     , E Bnd3       $ dfa [conv bondExprV3 bondV3]
 55 |     , E BndProp3   $ spaced BndProp3 bondProp3
 56 |     , E BondEnd    $ dfa [newline' (endV3 "BOND") RestV3]
 57 |     , E SGroup     $ dfa sgroup
 58 |     , E RestV3     $ dfa rest3
 59 |     ]
 60 |
 61 | ctabErr : Arr32 CSz (CSTCK q -> F1 q (BoundedErr MolErr))
 62 | ctabErr = arr32 CSz (unexpected []) []
 63 |
 64 | ctabEOI : CST -> CSTCK q -> F1 q (Either (BoundedErr MolErr) (List Molfile))
 65 | ctabEOI st sk =
 66 |   case st == H1 || st == CDone of
 67 |     False => case st == EndMol of
 68 |       False => arrFail CSTCK ctabErr st sk
 69 |       True  => end >> getList sk.stack_ >>= pure . Right
 70 |     True  => getList sk.stack_ >>= pure . Right
 71 |
 72 | ||| A parser for CTab file formats. Can read V2000 and V3000 mol
 73 | ||| and SD files. Suitable for streaming large amounts of data.
 74 | public export
 75 | ctab : P1 q (BoundedErr MolErr) (List Molfile)
 76 | ctab = P H1 init ctabTrans snocChunk ctabErr ctabEOI
 77 |
 78 | parameters {auto has : Has (ParseError MolErr) es}
 79 |
 80 |   ||| Reads a single `Molfile` entry from a string.
 81 |   |||
 82 |   ||| The entry can be either in V2000 or V3000 format or a mixture of both.
 83 |   |||
 84 |   ||| Accepts strings that end with an option SD block
 85 |   ||| and optional SD delimiter (`"$$$$"`).
 86 |   export
 87 |   readMolFrom : Origin -> String -> ChemRes es Molfile
 88 |   readMolFrom o s =
 89 |     case parseString ctab o s of
 90 |       Left x    => Left $ inject x
 91 |       Right []  => Right (MkMolfile "" "" "" (G 0 empty) [])
 92 |       Right [x] => Right x
 93 |       Right _   =>
 94 |         Left (inject $ toParseError o s (B (Custom MEntries) NoBounds))
 95 |
 96 |   ||| Convenience alias for `readMolFrom Virtual`.
 97 |   export %inline
 98 |   readMol : String -> ChemRes es Molfile
 99 |   readMol = readMolFrom Virtual
100 |
101 |   ||| Reads a list of SD entries from a string.
102 |   |||
103 |   ||| The entries can be either in V2000 or V3000 format or a mixture of both.
104 |   export %inline
105 |   readSDFFrom : Origin -> String -> ChemRes es (List Molfile)
106 |   readSDFFrom o = mapFst inject . parseString ctab o
107 |
108 |   ||| Convenience alias for `readSDFFrom Virtual`.
109 |   export %inline
110 |   readSDF : String -> ChemRes es (List Molfile)
111 |   readSDF = readSDFFrom Virtual
112 |
113 |
114 | test : String -> IO ()
115 | test s =
116 |   case readMol {es = [ParseError MolErr]} s of
117 |     Left (Here x) => putStrLn (interpolate x)
118 |     Right (MkMolfile _ _ _  (G s _) _) => putStrLn "\{show s} atoms parsed"
119 |
120 | v3 : String
121 | v3 =
122 |   """
123 |
124 |
125 |
126 |   00000999 V3000
127 |   M  V30 BEGIN CTAB
128 |   M  V30 COUNTS 1 0 1 0 0
129 |   M  V30 BEGIN ATOM
130 |   M  V30 1 H 0 0 0 0
131 |   M  V30 END ATOM
132 |   M  V30 BEGIN BOND
133 |   M  V30 END BOND
134 |   M  V30 BEGIN SGROUP
135 |   M  V30 1 SUP 0 LABEL=a0 ATOMS=(1 1)
136 |   M  V30 END SGROUP
137 |   M  V30 END CTAB
138 |   M  END
139 |   """
140 |