]> Git — Sourcephile - haskell/symantic-xml.git/commitdiff
Rewrite to categorical symantic master
authorJulien Moutinho <julm+symantic-xml@sourcephile.fr>
Sun, 19 Apr 2020 08:45:29 +0000 (10:45 +0200)
committerJulien Moutinho <julm+symantic-xml@sourcephile.fr>
Tue, 26 May 2020 01:28:23 +0000 (03:28 +0200)
346 files changed:
.hlint.yaml [new file with mode: 0644]
GNUmakefile
HLint.hs [deleted file]
Symantic/HLint.hs [deleted symlink]
Symantic/RNC.hs [deleted file]
Symantic/RNC/HLint.hs [deleted symlink]
Symantic/RNC/Sym.hs [deleted file]
Symantic/RNC/Validate.hs [deleted file]
Symantic/RNC/Write.hs [deleted file]
Symantic/RNC/Write/Fixity.hs [deleted file]
Symantic/RNC/Write/Namespaces.hs [deleted file]
Symantic/XML.hs [deleted file]
Symantic/XML/Document.hs [deleted file]
Symantic/XML/HLint.hs [deleted symlink]
Symantic/XML/Read.hs [deleted file]
Symantic/XML/Read/HLint.hs [deleted symlink]
Symantic/XML/Read/Parser.hs [deleted file]
Symantic/XML/Write.hs [deleted file]
hie.yaml [new file with mode: 0644]
src/Symantic/XML.hs [new file with mode: 0644]
src/Symantic/XML/Language.hs [new file with mode: 0644]
src/Symantic/XML/Namespace.hs [new file with mode: 0644]
src/Symantic/XML/Read.hs [new file with mode: 0644]
src/Symantic/XML/RelaxNG.hs [new file with mode: 0644]
src/Symantic/XML/RelaxNG/Compact/Write.hs [new file with mode: 0644]
src/Symantic/XML/RelaxNG/Language.hs [new file with mode: 0644]
src/Symantic/XML/Text.hs [new file with mode: 0644]
src/Symantic/XML/Tree.hs [new file with mode: 0644]
src/Symantic/XML/Tree/Data.hs [new file with mode: 0644]
src/Symantic/XML/Tree/Read.hs [new file with mode: 0644]
src/Symantic/XML/Tree/Source.hs [new file with mode: 0644]
src/Symantic/XML/Tree/Write.hs [new file with mode: 0644]
src/Symantic/XML/Write.hs [new file with mode: 0644]
stack.yaml
stack.yaml.lock [new file with mode: 0644]
symantic-xml.cabal
test/Golden.hs
test/Golden/RelaxNG/Commoning.rnc [new file with mode: 0644]
test/Golden/RelaxNG/Commoning/0000.xml [moved from test/Golden/RNC/Commoning/0000.xml with 68% similarity]
test/Golden/RelaxNG/Commoning/0000.xml.read [moved from test/Golden/RNC/Commoning/0000.xml.read with 100% similarity]
test/Golden/RelaxNG/Commoning/0000.xml.write [new file with mode: 0644]
test/Golden/RelaxNG/Commoning/0001.xml [moved from test/Golden/RNC/Commoning/0001.xml with 94% similarity]
test/Golden/RelaxNG/Commoning/0001.xml.read [moved from test/Golden/RNC/Commoning/0001.xml.read with 100% similarity]
test/Golden/RelaxNG/Commoning/0001.xml.write [new file with mode: 0644]
test/Golden/RelaxNG/Commoning/0002.xml [moved from test/Golden/RNC/Commoning/0002.xml with 95% similarity]
test/Golden/RelaxNG/Commoning/0002.xml.read [moved from test/Golden/RNC/Commoning/0002.xml.read with 96% similarity]
test/Golden/RelaxNG/Commoning/0002.xml.write [new file with mode: 0644]
test/Golden/RelaxNG/Whatever.rnc [new file with mode: 0644]
test/Golden/RelaxNG/Whatever/00.xml [new file with mode: 0644]
test/Golden/RelaxNG/Whatever/00.xml.read [new file with mode: 0644]
test/Golden/RelaxNG/Whatever/00.xml.write [new file with mode: 0644]
test/Golden/XML/0001.xml.ast [deleted file]
test/Golden/XML/0001.xml.read
test/Golden/XML/0001.xml.write.indented
test/Golden/XML/0002.xml.ast [deleted file]
test/Golden/XML/0002.xml.read
test/Golden/XML/0002.xml.write.indented
test/Golden/XML/0003.xml.ast [deleted file]
test/Golden/XML/0003.xml.read
test/Golden/XML/0003.xml.write.indented
test/Golden/XML/0004.xml.read
test/Golden/XML/0004.xml.write
test/Golden/XML/0004.xml.write.indented
test/Golden/XML/0005.xml.read
test/Golden/XML/0005.xml.write
test/Golden/XML/0005.xml.write.indented
test/Golden/XML/0006.xml.read
test/Golden/XML/0006.xml.write
test/Golden/XML/0006.xml.write.indented
test/Golden/XML/0007.xml.read
test/Golden/XML/0007.xml.write
test/Golden/XML/0007.xml.write.indented
test/Golden/XML/0008.xml.read
test/Golden/XML/0008.xml.write.indented
test/Golden/XML/0009.xml.read
test/Golden/XML/0009.xml.write
test/Golden/XML/0009.xml.write.indented
test/Golden/XML/0010.xml.read
test/Golden/XML/0010.xml.write
test/Golden/XML/0010.xml.write.indented
test/Golden/XML/0011.xml.read
test/Golden/XML/0011.xml.write.indented
test/Golden/XML/0012.xml.read
test/Golden/XML/0012.xml.write.indented
test/Golden/XML/0013.xml.read
test/Golden/XML/0013.xml.write
test/Golden/XML/0013.xml.write.indented
test/Golden/XML/0014.xml.read
test/Golden/XML/0014.xml.write.indented
test/Golden/XML/0015.xml.read
test/Golden/XML/0015.xml.write.indented
test/Golden/XML/0016.xml.read
test/Golden/XML/0016.xml.write.indented
test/Golden/XML/0017.xml.read
test/Golden/XML/0017.xml.write.indented
test/Golden/XML/0018.xml.read
test/Golden/XML/0018.xml.write.indented
test/Golden/XML/0019.xml.read
test/Golden/XML/0019.xml.write.indented
test/Golden/XML/0020.xml.read
test/Golden/XML/0020.xml.write.indented
test/Golden/XML/0021.xml.read
test/Golden/XML/0021.xml.write.indented
test/Golden/XML/0022.xml.read
test/Golden/XML/0022.xml.write.indented
test/Golden/XML/0023.xml.read
test/Golden/XML/0023.xml.write.indented
test/Golden/XML/0024.xml.read
test/Golden/XML/0024.xml.write.indented
test/Golden/XML/0025.xml.read
test/Golden/XML/0025.xml.write.indented
test/Golden/XML/0026.xml.read
test/Golden/XML/0026.xml.write.indented
test/Golden/XML/0027.xml.read
test/Golden/XML/0027.xml.write
test/Golden/XML/0027.xml.write.indented
test/Golden/XML/0028.xml.read
test/Golden/XML/0028.xml.write
test/Golden/XML/0028.xml.write.indented
test/Golden/XML/0029.xml.read
test/Golden/XML/0029.xml.write.indented
test/Golden/XML/0030.xml.read
test/Golden/XML/0030.xml.write.indented
test/Golden/XML/0031.xml.read
test/Golden/XML/0031.xml.write
test/Golden/XML/0031.xml.write.indented
test/Golden/XML/0032.xml.read
test/Golden/XML/0032.xml.write
test/Golden/XML/0032.xml.write.indented
test/Golden/XML/0033.xml.read
test/Golden/XML/0033.xml.write
test/Golden/XML/0033.xml.write.indented
test/Golden/XML/0034.xml.read
test/Golden/XML/0034.xml.write
test/Golden/XML/0034.xml.write.indented
test/Golden/XML/0035.xml.read
test/Golden/XML/0035.xml.write
test/Golden/XML/0035.xml.write.indented
test/Golden/XML/0036.xml.read
test/Golden/XML/0036.xml.write
test/Golden/XML/0036.xml.write.indented
test/Golden/XML/0037.xml.read
test/Golden/XML/0037.xml.write
test/Golden/XML/0037.xml.write.indented
test/Golden/XML/0038.xml.read
test/Golden/XML/0038.xml.write
test/Golden/XML/0038.xml.write.indented
test/Golden/XML/0039.xml.read
test/Golden/XML/0039.xml.write
test/Golden/XML/0039.xml.write.indented
test/Golden/XML/0040.xml.read
test/Golden/XML/0040.xml.write
test/Golden/XML/0040.xml.write.indented
test/Golden/XML/0041.xml.read
test/Golden/XML/0041.xml.write
test/Golden/XML/0041.xml.write.indented
test/Golden/XML/0042.xml.read
test/Golden/XML/0042.xml.write
test/Golden/XML/0042.xml.write.indented
test/Golden/XML/0043.xml.read
test/Golden/XML/0043.xml.write
test/Golden/XML/0043.xml.write.indented
test/Golden/XML/0044.xml.read
test/Golden/XML/0044.xml.write
test/Golden/XML/0044.xml.write.indented
test/Golden/XML/0045.xml.read
test/Golden/XML/0045.xml.write
test/Golden/XML/0045.xml.write.indented
test/Golden/XML/0046.xml.read
test/Golden/XML/0046.xml.write
test/Golden/XML/0046.xml.write.indented
test/Golden/XML/0047.xml [new file with mode: 0644]
test/Golden/XML/0047.xml.read [new file with mode: 0644]
test/Golden/XML/0047.xml.write [new file with mode: 0644]
test/Golden/XML/0047.xml.write.indented [new file with mode: 0644]
test/Golden/XML/Error/0009.xml.read
test/Golden/XML/Error/0010.xml.read
test/Golden/XML/Error/0018.xml.read
test/Golden/XML/Error/0019.xml.read
test/Golden/XML/Error/0020.xml.read
test/Golden/XML/Error/0021.xml.read
test/Golden/XML/Error/0022.xml.read
test/Golden/XML/Error/0026.xml.read
test/Golden/XML/Error/0027.xml.read
test/Golden/XML/Error/0028.xml.read
test/Golden/XML/Error/0029.xml.read
test/Golden/XML/Error/0031.xml.read
test/Golden/XML/Error/0037.xml.read
test/Golden/XML/Error/0040.xml.read
test/Golden/XML/Error/0041.xml.read
test/Golden/XML/Error/0042.xml.read
test/Golden/XML/Error/0043.xml.read
test/Golden/XML/Error/0044.xml.read
test/Golden/XML/Error/0047.xml.read
test/Golden/XML/Error/0048.xml.read
test/Golden/XML/Error/0049.xml.read
test/Golden/XML/Error/0050.xml.read
test/Golden/XML/Error/0051.xml.read
test/Golden/XML/Error/0052.xml.read
test/Golden/XML/Error/0053.xml.read
test/Golden/XML/Error/0055.xml.read
test/Golden/XML/Error/0057.xml.read
test/Golden/XML/Error/0058.xml.read
test/Golden/XML/Error/0059.xml.read
test/Golden/XML/Error/0061.xml.read
test/Golden/XML/Error/0063.xml.read
test/Golden/XML/Error/0065.xml.read
test/Golden/XML/Error/0066.xml.read
test/Golden/XML/Error/0067.xml.read
test/Golden/XML/Error/0074.xml.read
test/Golden/XML/Error/0075.xml.read
test/Golden/XML/Error/0078.xml.read
test/Golden/XML/Error/0079.xml.read
test/Golden/XML/Error/0081.xml.read
test/Golden/XML/Error/0082.xml.read
test/Golden/XML/Error/0083.xml.read
test/Golden/XML/Error/0084.xml.read
test/Golden/XML/Error/0087.xml.read
test/Golden/XML/Error/0088.xml.read
test/Golden/XML/Error/0092.xml.read
test/Golden/XML/Error/0093.xml.read
test/Golden/XML/Error/0094.xml.read
test/Golden/XML/Error/0095.xml.read
test/Golden/XML/Error/0096.xml.read
test/Golden/XML/Error/0097.xml.read
test/Golden/XML/Error/0098.xml.read
test/Golden/XML/Error/0099.xml.read
test/Golden/XML/Error/0131.xml.read
test/Golden/XML/Error/0132.xml.read
test/Golden/XML/Error/0133.xml.read
test/Golden/XML/Error/0134.xml.read
test/Golden/XML/Error/0135.xml.read
test/Golden/XML/Error/0136.xml.read
test/Golden/XML/Error/0137.xml.read
test/Golden/XML/Error/0138.xml.read
test/Golden/XML/Error/0139.xml.read
test/Golden/XML/Error/0140.xml.read
test/Golden/XML/Error/0141.xml.read
test/Golden/XML/Error/0142.xml.read
test/Golden/XML/Error/0143.xml.read
test/Golden/XML/Error/0144.xml.read
test/Golden/XML/Error/0145.xml.read
test/Golden/XML/Error/0146.xml.read
test/Golden/XML/Error/0147.xml.read
test/Golden/XML/Error/0148.xml.read
test/Golden/XML/Error/0149.xml.read
test/Golden/XML/Error/0150.xml.read
test/Golden/XML/Error/0151.xml.read
test/Golden/XML/Error/0152.xml.read
test/Golden/XML/Error/0153.xml.read
test/Golden/XML/Error/0154.xml.read
test/Golden/XML/Error/0155.xml.read
test/Golden/XML/Error/0156.xml.read
test/Golden/XML/Error/0157.xml.read
test/Golden/XML/Error/0158.xml.read
test/Golden/XML/Error/0159.xml.read
test/Golden/XML/Error/0160.xml.read
test/Golden/XML/Error/0161.xml.read
test/Golden/XML/Error/0162.xml.read
test/Golden/XML/Error/0163.xml.read
test/Golden/XML/Error/0164.xml.read
test/Golden/XML/Error/0165.xml.read
test/Golden/XML/Error/0166.xml.read
test/Golden/XML/Error/0167.xml.read
test/Golden/XML/Error/0168.xml.read
test/Golden/XML/Error/0169.xml.read
test/Golden/XML/Error/0170.xml.read
test/Golden/XML/Error/0173.xml.read
test/Golden/XML/Error/0174.xml.read
test/Golden/XML/Error/0175.xml.read
test/Golden/XML/Error/0176.xml.read
test/Golden/XML/Error/0177.xml.read
test/Golden/XML/Error/0178.xml.read
test/Golden/XML/Error/0182.xml.read
test/Golden/XML/Error/0183.xml.read
test/Golden/XML/Error/0184.xml.read
test/Golden/XML/Error/0185.xml.read
test/Golden/XML/Error/0187.xml.read
test/Golden/XML/Error/0190.xml.read
test/Golden/XML/Error/0193.xml.read
test/Golden/XML/Error/0196.xml.read
test/Golden/XML/Error/0199.xml.read
test/Golden/XML/Error/0201.xml.read
test/Golden/XML/Error/0202.xml.read
test/Golden/XML/Error/0203.xml.read
test/Golden/XML/Error/0204.xml.read
test/Golden/XML/Error/0205.xml.read
test/Golden/XML/Error/0206.xml.read
test/Golden/XML/Error/0207.xml.read
test/Golden/XML/Error/0208.xml.read
test/Golden/XML/Error/0210.xml.read
test/Golden/XML/Error/0211.xml.read
test/Golden/XML/Error/0212.xml.read
test/Golden/XML/Error/0214.xml.read
test/Golden/XML/Error/0222.xml.read
test/Golden/XML/Error/0223.xml.read
test/Golden/XML/Error/0224.xml [new file with mode: 0644]
test/Golden/XML/Error/0224.xml.read [new file with mode: 0644]
test/Golden/XML/Error/0225.xml [new file with mode: 0644]
test/Golden/XML/Error/0225.xml.read [new file with mode: 0644]
test/Golden/XML/NS/0001.xml
test/Golden/XML/NS/0001.xml.ast [deleted file]
test/Golden/XML/NS/0001.xml.read
test/Golden/XML/NS/0001.xml.write
test/Golden/XML/NS/0001.xml.write.indented
test/Golden/XML/NS/0002.xml.ast [deleted file]
test/Golden/XML/NS/0002.xml.read
test/Golden/XML/NS/0002.xml.write
test/Golden/XML/NS/0002.xml.write.indented
test/Golden/XML/NS/0003.xml.ast [deleted file]
test/Golden/XML/NS/0003.xml.read
test/Golden/XML/NS/0003.xml.write.indented
test/Golden/XML/NS/0004.xml.ast [deleted file]
test/Golden/XML/NS/0004.xml.read
test/Golden/XML/NS/0004.xml.write
test/Golden/XML/NS/0004.xml.write.indented
test/Golden/XML/NS/0005.xml.ast [deleted file]
test/Golden/XML/NS/0005.xml.read
test/Golden/XML/NS/0005.xml.write
test/Golden/XML/NS/0005.xml.write.indented
test/Golden/XML/NS/0006.xml.ast [deleted file]
test/Golden/XML/NS/0006.xml.read
test/Golden/XML/NS/0006.xml.write
test/Golden/XML/NS/0006.xml.write.indented
test/Golden/XML/NS/0007.xml.ast [deleted file]
test/Golden/XML/NS/0007.xml.read
test/Golden/XML/NS/0007.xml.write
test/Golden/XML/NS/0007.xml.write.indented
test/Golden/XML/NS/0008.xml.ast [deleted file]
test/Golden/XML/NS/0008.xml.read
test/Golden/XML/NS/0008.xml.write
test/Golden/XML/NS/0008.xml.write.indented
test/Golden/XML/NS/0009.xml.ast [deleted file]
test/Golden/XML/NS/0009.xml.read
test/Golden/XML/NS/0009.xml.write
test/Golden/XML/NS/0009.xml.write.indented
test/Golden/XML/NS/0010.xml.ast [deleted file]
test/Golden/XML/NS/0010.xml.read
test/Golden/XML/NS/0010.xml.write
test/Golden/XML/NS/0010.xml.write.indented
test/Golden/XML/NS/Error/0001.xml.ast [deleted file]
test/Main.hs
test/RNC/Commoning.hs [deleted file]
test/RNC/Parser.hs [deleted file]
test/RelaxNG/Commoning.hs [new file with mode: 0644]
test/RelaxNG/Whatever.hs [new file with mode: 0644]

diff --git a/.hlint.yaml b/.hlint.yaml
new file mode 100644 (file)
index 0000000..c0f0130
--- /dev/null
@@ -0,0 +1,22 @@
+- arguments: [
+  -XHaskell2010
+  -XNoCPP
+  -XTypeApplications
+]
+- ignore: {name: Avoid lambda using `infix`}
+- ignore: {name: Move brackets to avoid $}
+- ignore: {name: Reduce duplication}
+- ignore: {name: Redundant $}
+- ignore: {name: Redundant bracket}
+- ignore: {name: Redundant do}
+- ignore: {name: Redundant lambda}
+- ignore: {name: Use camelCase}
+- ignore: {name: Use const}
+- ignore: {name: Use fmap}
+- ignore: {name: Use if}
+- ignore: {name: Use import/export shortcut}
+- ignore: {name: Use list literal pattern}
+- ignore: {name: Use list literal}
+
+# BEGIN: generated hints
+# END: generated hints
index d6eb792e87614035a0a7a9df3e9d95df9c7e0ec8..cfcdba119ab5695f13275e5290efd31fa36061d2 100644 (file)
@@ -51,15 +51,14 @@ doc:
 %.html/view: %.html
        sensible-browser $*.html
 
 %.html/view: %.html
        sensible-browser $*.html
 
-HLint.hs: $(shell find . -name '*.hs' -not -name 'HLint.hs')
-       sed -i -e '/^-- BEGIN: generated hints/,/^-- END: Generated by hlint/d' HLint.hs
-       echo '-- BEGIN: generated hints' >> HLint.hs
-       hlint --find . | sed -ne 's/^- infix: \(.*\)/\1/p' | sort -u >>HLint.hs
-       echo '-- END: generated hints' >> HLint.hs
+.hlint.yaml: $(shell find src -name '*.hs' -not -name 'HLint.hs')
+       sed -i -e '/^# BEGIN: generated hints/,/^# END: Generated by hlint/d' $@
+       echo >>$@ '# BEGIN: generated hints'
+       hlint --find . | grep -- '- fixity:' | sort -u >>$@
+       echo >>$@ '# END: generated hints'
 
 
-lint: HLint.hs
-       if hlint --quiet --report=hlint.html -XNoCPP \
-        $(shell cabal-cargs --format=ghc --only=default_extensions --sourcefile=$(cabal)) $(HLINT_FLAGS) .; \
+lint: .hlint.yaml
+       if hlint --quiet --report=hlint.html -XNoCPP $(HLINT_FLAGS) .; \
        then rm -f hlint.html; \
        else sensible-browser ./hlint.html & fi
 
        then rm -f hlint.html; \
        else sensible-browser ./hlint.html & fi
 
diff --git a/HLint.hs b/HLint.hs
deleted file mode 100644 (file)
index 3cb2542..0000000
--- a/HLint.hs
+++ /dev/null
@@ -1,16 +0,0 @@
-import "hint" HLint.HLint
-ignore "Move brackets to avoid $"
-ignore "Reduce duplication"
-ignore "Redundant $"
-ignore "Redundant bracket"
-ignore "Redundant do"
-ignore "Use camelCase"
-ignore "Use const"
-ignore "Use fmap"
-ignore "Use if"
-ignore "Use import/export shortcut"
-ignore "Use list literal pattern"
-ignore "Use list literal"
-
--- BEGIN: generated hints
--- END: generated hints
diff --git a/Symantic/HLint.hs b/Symantic/HLint.hs
deleted file mode 120000 (symlink)
index ab18269..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../HLint.hs
\ No newline at end of file
diff --git a/Symantic/RNC.hs b/Symantic/RNC.hs
deleted file mode 100644 (file)
index af01b86..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-module Symantic.RNC
- ( module Symantic.RNC.Sym
- , module Symantic.RNC.Validate
- , module Symantic.RNC.Write
- , Functor(..)
- , Applicative(..)
- , Alternative((<|>))
- ) where
-import Data.Functor
-import Control.Applicative
-
-import Symantic.RNC.Sym
-import Symantic.RNC.Write
-import Symantic.RNC.Validate
diff --git a/Symantic/RNC/HLint.hs b/Symantic/RNC/HLint.hs
deleted file mode 120000 (symlink)
index ab18269..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../HLint.hs
\ No newline at end of file
diff --git a/Symantic/RNC/Sym.hs b/Symantic/RNC/Sym.hs
deleted file mode 100644 (file)
index 662b8e1..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-{-# LANGUAGE TypeFamilyDependencies #-}
-module Symantic.RNC.Sym
- ( module Symantic.RNC.Sym
- , Functor(..), (<$>)
- , Applicative(..)
- , Alternative(..)
- ) where
-
-import Control.Applicative (Applicative(..), Alternative(..))
-import Data.Eq (Eq)
-import Data.Function ((.), id)
-import Data.Functor (Functor(..), (<$>))
-import Data.Maybe (Maybe(..))
-import Data.Sequence (Seq)
-import Data.String (String)
-import Text.Show (Show(..))
-import qualified Data.Sequence as Seq
-import qualified Data.Text.Lazy as TL
-
-import qualified Symantic.XML as XML
-
--- * Class 'Sym_RNC'
-class
- ( Applicative repr
- , Alternative repr
- , Sym_Rule repr
- , Sym_Permutation repr
- ) => Sym_RNC repr where
-       namespace   :: Maybe XML.NCName -> XML.Namespace -> repr ()
-       element     :: XML.QName -> repr a -> repr a
-       attribute   :: XML.QName -> repr a -> repr a
-       any         :: repr ()
-       anyElem     :: XML.Namespace -> (XML.NCName -> repr a) -> repr a
-       escapedText :: repr XML.EscapedText
-       text        :: repr TL.Text
-       text = XML.unescapeText <$> escapedText
-       fail        :: repr a
-       try         :: repr a -> repr a
-       option      :: a -> repr a -> repr a
-       optional    :: repr a -> repr (Maybe a)
-       choice      :: [repr a] -> repr a
-       intermany   :: [repr a] -> repr [a]
-       intermany = many . choice . (try <$>)
-       manySeq :: repr a -> repr (Seq a)
-       manySeq r = Seq.fromList <$> many r
-       someSeq :: repr a -> repr (Seq a)
-       someSeq r = Seq.fromList <$> some r
-
--- * Class 'Sym_Rule'
-class Sym_Rule repr where
-       rule :: Show a => String -> repr a -> repr a
-       rule _n = id
-       arg :: String -> repr ()
-
--- ** Type 'RuleMode'
-data RuleMode
- =   RuleMode_Body -- ^ Request to generate the body of the rule.
- |   RuleMode_Ref  -- ^ Request to generate a reference to the rule.
- |   RuleMode_Def  -- ^ Request to generate a definition of the rule.
- deriving (Eq, Show)
-
--- * Class 'Sym_Permutation'
-class (Alternative repr, Applicative (Permutation repr)) => Sym_Permutation repr where
-       runPermutation :: Permutation repr a -> repr a
-       toPermutation :: repr a -> Permutation repr a
-       toPermutationWithDefault :: a -> repr a -> Permutation repr a
-       
-       (<$$>) :: (a -> b) -> repr a -> Permutation repr b
-       (<$?>) :: (a -> b) -> (a, repr a) -> Permutation repr b
-       (<$*>) :: ([a] -> b) -> repr a -> Permutation repr b
-       (<$:>) :: (Seq a -> b) -> repr a -> Permutation repr b
-       infixl 2 <$$>, <$?>, <$*>, <$:>
-       {-# INLINE (<$$>) #-}
-       {-# INLINE (<$?>) #-}
-       {-# INLINE (<$*>) #-}
-       {-# INLINE (<$:>) #-}
-       
-       (<||>) :: Permutation repr (a -> b) -> repr a -> Permutation repr b
-       (<|?>) :: Permutation repr (a -> b) -> (a, repr a) -> Permutation repr b
-       (<|*>) :: Permutation repr ([a] -> b) -> repr a -> Permutation repr b
-       (<|:>) :: Permutation repr (Seq a -> b) -> repr a -> Permutation repr b
-       infixl 1 <||>, <|?>, <|*>, <|:>
-       {-# INLINE (<||>) #-}
-       {-# INLINE (<|?>) #-}
-       {-# INLINE (<|*>) #-}
-       {-# INLINE (<|:>) #-}
-       
-       f <$$> x = f <$> toPermutation x
-       f <$?> (d,x) = f <$> toPermutationWithDefault d x
-       f <$*> x = f <$> toPermutationWithDefault [] (some x)
-       f <$:> x = f . Seq.fromList <$> toPermutationWithDefault [] (some x)
-       
-       f <||> x = f <*> toPermutation x
-       f <|?> (d,x) = f <*> toPermutationWithDefault d x
-       f <|*> x = f <*> toPermutationWithDefault [] (some x)
-       f <|:> x = f <*> toPermutationWithDefault Seq.empty (Seq.fromList <$> some x)
-
--- ** Type family 'Permutation'
--- | Type of permutations, depending on the representation.
-type family Permutation (repr:: * -> *) = (r :: * -> *) | r -> repr
diff --git a/Symantic/RNC/Validate.hs b/Symantic/RNC/Validate.hs
deleted file mode 100644 (file)
index 103ebcb..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE ViewPatterns #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Symantic.RNC.Validate where
-
-import Control.Applicative (Applicative(..), Alternative(..), optional)
-import Control.Monad (Monad(..))
-import Data.Bool
-import Data.Either (Either(..))
-import Data.Eq (Eq(..))
-import Data.Foldable (Foldable(..), all)
-import Data.Function (($), const, id)
-import Data.Functor (Functor(..), (<$>))
-import Data.Maybe (Maybe(..), maybe)
-import Data.Monoid (Monoid(..))
-import Data.Ord (Ord(..))
-import Data.Semigroup (Semigroup(..))
-import Data.Tuple (snd)
-import Prelude (error)
-import Data.Sequence (Seq)
-import qualified Data.Char as Char
-import qualified Data.List.NonEmpty as NonEmpty
-import qualified Data.Sequence as Seq
-import qualified Data.Set as Set
-import qualified Data.Text.Lazy as TL
-import qualified Text.Megaparsec as P
-
-import Symantic.XML (XMLs)
-import qualified Symantic.XML as XML
-import qualified Symantic.RNC.Sym as RNC
-
-validateXML ::
- Ord e => P.Parsec e (XMLs src) a -> XMLs src ->
- Either (P.ParseErrorBundle (XMLs src) e) a
-validateXML p stateInput =
-       snd $
-       P.runParser' p P.State
-        { P.stateInput
-        , P.stateOffset = 0
-        , P.statePosState = error "[BUG] validateXML: getSourcePos is not helpful here, please use annotated source locations"
-         -- NOTE: reporting the node number is less helpful
-               -- than the source text line and number where the node is;
-               -- P.statePosState is only used by P.getSourcePos.
-        }
-
-instance
- ( Ord err
- , Ord src
- , XML.NoSource src
- , P.Stream (Seq (XML.XML src))
- , P.Token  (Seq (XML.XML src)) ~ XML.Tree (XML.Sourced src XML.Node)
- ) => RNC.Sym_RNC (P.Parsec err (XMLs src)) where
-       {-
-       none = P.label "none" $ P.eof
-       -}
-       namespace _p _n = pure ()
-       element n p = do
-               ts <- P.token check $ Set.singleton $ P.Tokens $ pure expected
-               p_XMLs p ts
-               where
-               expected = XML.Tree (XML.notSourced $ XML.NodeElem n) mempty
-               check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
-                | e == n
-                = Just $ removePI $ removeXMLNS $ removeSpaces ts
-                       where
-                       removePI xs =
-                               (`Seq.filter` xs) $ \case
-                                        XML.Tree (XML.unSourced -> XML.NodePI{}) _ts -> False
-                                        _ -> True
-                       removeSpaces xs =
-                               if (`all` xs) $ \case
-                                XML.Tree (XML.unSourced -> XML.NodeText (XML.EscapedText et)) _ts ->
-                                       all (\case
-                                        XML.EscapedPlain t -> TL.all Char.isSpace t
-                                        _ -> False) et
-                                _ -> True
-                               then (`Seq.filter` xs) $ \case
-                                        XML.Tree (XML.unSourced -> XML.NodeText{}) _ts -> False
-                                        _ -> True
-                               else xs
-                       removeXMLNS xs =
-                               let (attrs,rest) = (`Seq.spanl` xs) $ \case
-                                        XML.Tree (XML.unSourced -> XML.NodeAttr{}) _ts -> True
-                                        _ -> False in
-                               let attrs' = (`Seq.filter` attrs) $ \case
-                                        XML.Tree (XML.unSourced -> XML.NodeAttr a) _ts ->
-                                               case a of
-                                                XML.QName "" "xmlns" -> False
-                                                XML.QName ns _l -> ns /= XML.xmlns_xmlns
-                                        _ -> True in
-                               attrs' <> rest
-               check _t = Nothing
-       attribute n p = do
-               v <- P.token check $ Set.singleton $ P.Tokens $ pure expected
-               p_XMLs p v
-               where
-               expected = XML.Tree0 (XML.notSourced $ XML.NodeAttr n)
-               check (XML.Tree (XML.unSourced -> XML.NodeAttr k)
-                     v@(toList -> [XML.Tree0 (XML.unSourced -> XML.NodeText _v)])) | k == n =
-                       Just v
-               check _t = Nothing
-       any  = P.label "any" $
-               P.token (const $ Just ())  Set.empty
-       anyElem ns p = P.label "anyElem" $ do
-               (n,ts) <- P.token check $ Set.singleton $ P.Tokens $ pure expected
-               p_XMLs (p $ XML.qNameLocal n) ts
-               where
-               expected = XML.Tree (XML.notSourced $ XML.NodeElem $ XML.QName ns $ XML.NCName "*") mempty
-               check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
-                | XML.qNameSpace e == ns
-                = Just $ (e,ts)
-               check _t = Nothing
-       {-
-       comment = do
-               s <- P.getInput
-               case Seq.viewl s of
-                XML.Tree0 (XML.unSourced -> XML.NodeComment c) :< ts -> do
-                       P.setInput ts
-                       c <$ XML.setFilePosToNextNode
-                t :< _ts -> P.failure (Just $ P.Tokens $ pure t) ex
-                EmptyL -> P.failure Nothing ex
-               where
-               ex = Set.singleton $ P.Tokens $ pure expected
-               expected = XML.Tree0 (XML.notSourced $ XML.NodeComment "")
-       -}
-       escapedText = do
-               P.token check $ Set.singleton $ P.Tokens $ pure expected
-               where
-               expected = XML.Tree0 (XML.notSourced $ XML.NodeText $ XML.EscapedText mempty)
-               check (XML.Tree0 (XML.unSourced -> XML.NodeText t)) = Just t
-               check _t = Nothing
-       optional = P.optional
-       option   = P.option
-       choice   = P.choice
-       try      = P.try
-       fail     = P.label "fail" $ P.failure Nothing mempty
-
--- | @p_XMLs p xs@ returns a parser parsing @xs@ entirely with @p@,
--- updating 'P.stateOffset' and re-raising any exception.
-p_XMLs ::
- Ord err => Ord src =>
- P.Stream (Seq (XML.XML src)) =>
- P.Parsec err (XMLs src) a -> XMLs src -> P.Parsec err (XMLs src) a
-p_XMLs p stateInput = do
-       st <- P.getParserState
-       let (st', res) = P.runParser' (p <* P.eof) st
-                { P.stateInput  = stateInput
-                , P.stateOffset = P.stateOffset st
-                }
-       P.updateParserState (\s -> s{P.stateOffset = P.stateOffset st'})
-       case res of
-        Right a -> return a
-        Left (P.ParseErrorBundle errs _) ->
-               case NonEmpty.head errs of
-                P.TrivialError _o us es -> P.failure us es
-                P.FancyError _o es -> P.fancyFailure es
-
--- | Whether the given 'XML.Node' must be ignored by the RNC parser.
-isIgnoredNode :: XML.Node -> Bool
-isIgnoredNode = \case
- XML.NodeComment{} -> True
- XML.NodePI{}      -> True
- XML.NodeCDATA{}   -> True
- _ -> False
-
-instance
- ( Ord err
- , Ord src
- , P.Stream (Seq (XML.XML src))
- ) => RNC.Sym_Permutation (P.ParsecT err (XMLs src) m) where
-       runPermutation (Perm value parser) = optional parser >>= f
-               where
-               -- NOTE: copy Control.Applicative.Permutations.runPermutation
-               -- to replace the commented empty below so that P.TrivialError
-               -- has the unexpected token.
-               f  Nothing = maybe {-empty-}(P.token (const Nothing) Set.empty) pure value
-               f (Just p) = RNC.runPermutation p
-       toPermutation p = Perm Nothing $ pure <$> p
-       toPermutationWithDefault v p = Perm (Just v) $ pure <$> p
-
--- | Unprivatized 'Control.Applicative.Permutations.Permutation' to fix 'runPermutation'.
--- so that the 'P.TrivialError' has an unexpected token
--- which is an 'XML.Node' containing a 'XML.FileSource' useful when reporting errors.
-data Perm m a = Perm (Maybe a) (m (Perm m a))
-type instance RNC.Permutation (P.ParsecT err (XMLs src) m) = Perm (P.ParsecT err (XMLs src) m)
-instance Functor m => Functor (Perm m) where
-       fmap f (Perm v p) = Perm (f <$> v) (fmap f <$> p)
-instance Alternative m => Applicative (Perm m) where
-       pure value = Perm (Just value) empty
-       lhs@(Perm f v) <*> rhs@(Perm g w) = Perm (f <*> g) (lhsAlt <|> rhsAlt)
-               where
-               lhsAlt = (<*> rhs) <$> v
-               rhsAlt = (lhs <*>) <$> w
-
-instance
- ( Ord err
- , Ord src
- , P.Stream (Seq (XML.XML src))
- ) => RNC.Sym_Rule (P.ParsecT err (XMLs src) m) where
-       -- rule n p = P.dbg s p {-(p P.<?> s)-} where s = Text.unpack n
-       rule _n = id
-       arg _n = pure ()
diff --git a/Symantic/RNC/Write.hs b/Symantic/RNC/Write.hs
deleted file mode 100644 (file)
index 5f28d9a..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE OverloadedStrings #-}
-module Symantic.RNC.Write
- ( module Symantic.RNC.Write
- , module Symantic.RNC.Write.Fixity
- , module Symantic.RNC.Write.Namespaces
- ) where
-
-import Control.Applicative (Applicative(..), Alternative(..))
-import Control.Monad
-import Data.Bool
-import Data.Function (($), (.), id)
-import Data.Functor ((<$>))
-import Data.Functor.Compose (Compose(..))
-import Data.Semigroup (Semigroup(..))
-import Data.String (IsString(..))
-import Text.Show (Show(..))
-import qualified Data.HashMap.Strict as HM
-import qualified Data.List as List
-import qualified Data.Text.Lazy as TL
--- import qualified Data.Text.Lazy.Builder as TLB
-
-import Symantic.RNC.Sym
-import Symantic.RNC.Write.Fixity
-import Symantic.RNC.Write.Namespaces
-import qualified Symantic.XML as XML
-
--- | Get textual rendition of given 'RuleWriter'.
-writeRNC :: [NS a] -> [Writer a] -> TL.Text
-writeRNC ns ws =
-       let namespaces@XML.Namespaces{..} = runNS ns in
-       TL.unlines $ List.concat
-        [ [ "default namespace = \""<>XML.unNamespace namespaces_default<>"\""
-                | not $ TL.null $ XML.unNamespace namespaces_default
-                ]
-        , [ "namespace "<>p<>" = \""<>n<>"\""
-                | (XML.Namespace n, XML.NCName p) <- HM.toList namespaces_prefixes
-                ]
-        , runWriter namespaces <$> ws
-        ]
-
--- * Type 'Writer'
-newtype Writer a
- = Writer { unWriter :: XML.Namespaces XML.NCName ->
-                        RuleMode ->
-                        (Infix, Side) ->
-                        Pair -> TL.Text }
-
--- | Get textual rendition of given 'Writer'.
-runWriter :: XML.Namespaces XML.NCName -> Writer a -> TL.Text
-runWriter ns (Writer w) =
-       w ns RuleMode_Def (infixN0, SideL) pairParen
-
-coerceWriter :: Writer a -> Writer b
-coerceWriter = Writer . unWriter
-{-# INLINE coerceWriter #-}
-
-{-
-instance Show (Writer a) where
-       show = TL.unpack . runWriter
--}
-instance Functor Writer where
-       fmap _f (Writer x) = Writer x
-instance Applicative Writer where
-       pure _ = writeText $ "\"\""
-       Writer f <*> Writer x = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               TL.intercalate ", " $
-               List.filter (not . TL.null) $
-                [ f ns rm (op, SideL) pairParen
-                , x ns rm (op, SideR) pairParen ]
-               where op = infixB SideL 2
-instance Alternative Writer where
-       empty = writeText "empty"
-       Writer wl <|> Writer wr = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               wl ns rm (op, SideL) pairParen <> " | " <> wr ns rm (op, SideR) pairParen
-               where op = infixB SideL 2
-       many (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               w ns rm (op, SideL) pairParen <> "*"
-               where op = infixN 9
-       some (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               w ns rm (op, SideL) pairParen <> "+"
-               where op = infixN 9
-instance Sym_Rule Writer where
-       rule n wr@(Writer w) = Writer $ \ns rm po pp ->
-               case rm of
-                RuleMode_Ref ->
-                       pairIfNeeded pp po op $
-                       fromString n
-                       where op = infixN 10
-                RuleMode_Body -> w ns RuleMode_Ref po pp
-                RuleMode_Def ->
-                       TL.intercalate " "
-                        [ fromString n
-                        , "="
-                        , unWriter (rule n wr) ns RuleMode_Body (infixN0, SideR) pp
-                        ]
-       arg n =
-               Writer $ \_ns rm _po _pp ->
-                       case rm of
-                        RuleMode_Ref  -> fromString n
-                        RuleMode_Body -> ""
-                        RuleMode_Def  -> ""
-type instance Permutation Writer = Compose [] Writer
-instance Sym_Permutation Writer where
-       runPermutation (Compose []) = writeText "empty"
-       runPermutation (Compose [Writer w]) = Writer w
-       runPermutation (Compose l@(_:_)) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               TL.intercalate " & " $
-               List.filter (not . TL.null) $
-               (unWriter <$> l) <*> pure ns <*> pure rm <*> pure (op, SideL) <*> pure pairParen
-               where op = infixB SideL 1
-       toPermutation = Compose . pure
-       toPermutationWithDefault _ = Compose . pure
-instance Sym_RNC Writer where
-       namespace _p _n = writeText ""
-       element n (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               "element "<>TL.pack (show $ XML.prefixifyQName ns n)
-                <>" "<>w ns rm (op,SideR) pairBrace
-               where op = infixN 10
-       anyElem (XML.Namespace n) f = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               (if TL.null n then "" else n<>":") <>
-               "* "<>w ns rm (op,SideR) pairBrace
-               where
-               op = infixN 0
-               Writer w = f ""
-       attribute n (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               "attribute "<>TL.pack (show $ XML.prefixifyQName ns n)
-                <>" "<>w ns rm (op,SideR) pairBrace
-               where op = infixN 10
-       try         = id
-       fail        = writeText "fail"
-       escapedText = writeText "text"
-       text        = writeText "text"
-       any         = writeText "any"
-       choice []   = writeText "empty"
-       choice [w]  = w
-       choice l@(_:_) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               TL.intercalate " | " $
-               (unWriter <$> l) <*> pure ns <*> pure rm <*> pure (op, SideL) <*> pure pairParen
-               where op = infixB SideL 2
-       option _x (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               w ns rm (op, SideL) pairParen <> "?"
-               where op = infixN 9
-       optional (Writer w) = Writer $ \ns rm po pp ->
-               pairIfNeeded pp po op $
-               w ns rm (op, SideL) pairParen <> "?"
-               where op = infixN 9
-       manySeq = coerceWriter . many
-       someSeq = coerceWriter . some
-
--- | 'Writer' returns a constant rendition.
-writeText :: TL.Text -> Writer a
-writeText t = Writer $ \_ns _rm po pp ->
-       pairIfNeeded pp po op t
-       where op = infixN 10
diff --git a/Symantic/RNC/Write/Fixity.hs b/Symantic/RNC/Write/Fixity.hs
deleted file mode 100644 (file)
index 10d6a76..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-module Symantic.RNC.Write.Fixity where
-
-import Data.Bool
-import Data.Eq (Eq(..))
-import Data.Function ((.))
-import Data.Int (Int)
-import Data.Maybe (Maybe(..))
-import Data.Ord (Ord(..))
-import Data.Semigroup
-import Data.String (String, IsString(..))
-import Text.Show (Show(..))
-
--- * Type 'Fixity'
-data Fixity
- =   Fixity1 Unifix
- |   Fixity2 Infix
- deriving (Eq, Show)
-
--- ** Type 'Unifix'
-data Unifix
- =   Prefix  { unifix_precedence :: Precedence }
- |   Postfix { unifix_precedence :: Precedence }
- deriving (Eq, Show)
-
--- ** Type 'Infix'
-data Infix
- =   Infix
- {   infix_associativity :: Maybe Associativity
- ,   infix_precedence    :: Precedence
- } deriving (Eq, Show)
-
-infixL :: Precedence -> Infix
-infixL = Infix (Just AssocL)
-
-infixR :: Precedence -> Infix
-infixR = Infix (Just AssocR)
-
-infixB :: Side -> Precedence -> Infix
-infixB = Infix . Just . AssocB
-
-infixN :: Precedence -> Infix
-infixN = Infix Nothing
-
-infixN0 :: Infix
-infixN0 = infixN 0
-
-infixN5 :: Infix
-infixN5 = infixN 5
-
--- | Given 'Precedence' and 'Associativity' of its parent operator,
--- and the operand 'Side' it is in,
--- return whether an 'Infix' operator
--- needs to be enclosed by a 'Pair'.
-isPairNeeded :: (Infix, Side) -> Infix -> Bool
-isPairNeeded (po, lr) op =
-       infix_precedence op < infix_precedence po
-       || infix_precedence op == infix_precedence po
-       && not associate
-       where
-       associate =
-               case (lr, infix_associativity po) of
-                (_, Just AssocB{})   -> True
-                (SideL, Just AssocL) -> True
-                (SideR, Just AssocR) -> True
-                _ -> False
-
--- | If 'isPairNeeded' is 'True',
--- enclose the given 'IsString' by given 'Pair',
--- otherwise returns the same 'IsString'.
-pairIfNeeded ::
- Semigroup s => IsString s =>
- Pair -> (Infix, Side) -> Infix ->
- s -> s
-pairIfNeeded (o,c) po op s =
-       if isPairNeeded po op
-       then fromString o <> s <> fromString c
-       else s
-
--- * Type 'Precedence'
-type Precedence = Int
-
--- ** Class 'PrecedenceOf'
-class PrecedenceOf a where
-       precedence :: a -> Precedence
-instance PrecedenceOf Fixity where
-       precedence (Fixity1 uni) = precedence uni
-       precedence (Fixity2 inf) = precedence inf
-instance PrecedenceOf Unifix where
-       precedence = unifix_precedence
-instance PrecedenceOf Infix where
-       precedence = infix_precedence
-
--- * Type 'Associativity'
-data Associativity
- =   AssocL      -- ^ Associate to the left:  @a ¹ b ² c == (a ¹ b) ² c@
- |   AssocR      -- ^ Associate to the right: @a ¹ b ² c == a ¹ (b ² c)@
- |   AssocB Side -- ^ Associate to both sides, but to 'Side' when reading.
- deriving (Eq, Show)
-
--- ** Type 'Side'
-data Side
- =   SideL -- ^ Left
- |   SideR -- ^ Right
- deriving (Eq, Show)
-
--- ** Type 'Pair'
-type Pair = (String, String)
-pairParen, pairBrace :: Pair
-pairParen = ("(",")")
-pairBrace = ("{","}")
diff --git a/Symantic/RNC/Write/Namespaces.hs b/Symantic/RNC/Write/Namespaces.hs
deleted file mode 100644 (file)
index 5d7077e..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE OverloadedStrings #-}
-module Symantic.RNC.Write.Namespaces where
-
-import Control.Applicative (Applicative(..), Alternative(..), (<$>))
-import Control.Monad (Monad(..), forM, sequence)
-import Data.Default.Class (Default(..))
-import Data.Function (($), (.), id)
-import Data.Functor (Functor(..))
-import Data.Maybe (Maybe(..), maybe, isNothing)
-import Data.Monoid (Monoid(..))
-import Data.Semigroup (Semigroup(..))
-import Text.Show (Show(..))
-import Data.String (String)
-import qualified Data.HashMap.Strict as HM
-import qualified Data.HashSet as HS
-import qualified Control.Monad.Trans.State.Strict as S
-
-import qualified Symantic.XML as XML
-import Symantic.RNC.Sym
-
--- | Collect 'XML.Namespace's used and get them a dedicated prefix.
-runNS :: forall a. [NS a] -> XML.Namespaces XML.NCName
-runNS ns =
-       namespaces
-        { XML.namespaces_prefixes =
-               (`S.evalState` HS.empty) $
-                       let prefixesByNamespace =
-                               HM.delete "" $ -- NOTE: no prefix when there is no namespace.
-                               HM.update -- NOTE: no prefix when this is the default namespace.
-                                (\p -> if isNothing p then Nothing else Just p)
-                                (XML.namespaces_default namespaces) $
-                               XML.namespaces_prefixes namespaces in
-                       forM prefixesByNamespace $ \mp -> do
-                               usedPrefixes <- S.get
-                               let fp = maybe
-                                        (XML.freshNCName usedPrefixes)
-                                        (XML.freshifyNCName usedPrefixes)
-                                        mp
-                               S.modify' $ HS.insert fp
-                               return fp
-        }
-       where
-       namespaces :: XML.Namespaces (Maybe XML.NCName)
-       namespaces = mconcat $ (`S.evalState` def) $ sequence $ unNS <$> ns
-
-coerceNS :: NS a -> NS b
-coerceNS = NS . unNS
-{-# INLINE coerceNS #-}
-
--- * Type 'NS'
--- | Collect 'XML.Namespaces's and any prefixes associated with it,
--- using 'State' to avoid recurring into already visited 'rule's.
-newtype NS a = NS { unNS :: S.State State (XML.Namespaces (Maybe XML.NCName)) }
-
--- ** Type 'State'
-newtype State = State
- { state_rules :: {-!-}(HS.HashSet String)
- } deriving (Show)
-instance Default State where
-       def = State
-        { state_rules = HS.empty
-        }
-
-instance Show (NS a) where
-       showsPrec p = showsPrec p . runNS . pure
-instance Semigroup (NS a) where
-       NS x <> NS y = NS $ (<>) <$> x <*> y
-instance Monoid (NS a) where
-       mempty  = NS $ return mempty
-       mappend = (<>)
-instance Functor NS where
-       fmap _f = coerceNS
-instance Applicative NS where
-       pure _ = mempty
-       NS f <*> NS x = NS f <> NS x
-       NS f <*  NS x = NS f <> NS x
-       NS f  *> NS x = NS f <> NS x
-instance Alternative NS where
-       empty = mempty
-       NS f <|> NS x = NS f <> NS x
-       many = coerceNS
-       some = coerceNS
-instance Sym_Rule NS where
-       rule n (NS ns) = NS $ do
-               -- NOTE: avoid infinite loops
-               -- by not reentering into already visited rules.
-               st@State{..} <- S.get
-               if HS.member n state_rules
-                then return mempty
-                else do
-                       S.put $ st{state_rules = HS.insert n state_rules}
-                       ns
-       arg _n = mempty
-type instance Permutation NS = NS
-instance Sym_Permutation NS where
-       runPermutation = coerceNS
-       toPermutation = id
-       toPermutationWithDefault _def = id
-instance Sym_RNC NS where
-       -- namespace n ns =
-       --      NS $ return $ HM.singleton ns $ HS.singleton n
-       namespace mp n =
-               NS $ return $
-               case mp of
-                Just p  -> XML.Namespaces{XML.namespaces_prefixes = HM.singleton n $ Just p, XML.namespaces_default = ""}
-                Nothing -> def{XML.namespaces_default = n}
-       element XML.QName{..} (NS nsM) =
-               NS $ (<$> nsM) $ \ns -> ns{XML.namespaces_prefixes =
-                       HM.insert qNameSpace Nothing $ XML.namespaces_prefixes ns}
-       attribute XML.QName{..} (NS nsM) =
-               NS $ (<$> nsM) $ \ns -> ns{XML.namespaces_prefixes =
-                       HM.insert qNameSpace Nothing $ XML.namespaces_prefixes ns}
-       anyElem qNameSpace f =
-               let NS nsM = f $ XML.NCName "*" in
-               NS $ (<$> nsM) $ \ns -> ns{XML.namespaces_prefixes =
-                       HM.insert qNameSpace Nothing $ XML.namespaces_prefixes ns}
-       try         = id
-       fail        = mempty
-       escapedText = mempty
-       text        = mempty
-       any         = mempty
-       choice      = mconcat
-       option _def = coerceNS
-       optional    = coerceNS
-       manySeq     = coerceNS
-       someSeq     = coerceNS
diff --git a/Symantic/XML.hs b/Symantic/XML.hs
deleted file mode 100644 (file)
index 8ecde28..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-module Symantic.XML
- ( module Symantic.XML.Document
- , readXML
- , readFile
- , writeXML
- , writeXMLIndented
- , writeFile
- ) where
-import Symantic.XML.Document
-import Symantic.XML.Read
-import Symantic.XML.Write
diff --git a/Symantic/XML/Document.hs b/Symantic/XML/Document.hs
deleted file mode 100644 (file)
index 562dc55..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE PatternSynonyms #-}
-{-# LANGUAGE StrictData #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE ViewPatterns #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Symantic.XML.Document
- ( module Symantic.XML.Document
- , TS.Tree(..)
- , TS.Trees
- , TS.tree0
- ) where
-
-import Control.Applicative (Alternative(..))
-import Data.Bool
-import Data.Char (Char)
-import Data.Default.Class (Default(..))
-import Data.Eq (Eq(..))
-import Data.Foldable (Foldable(..), all)
-import Data.Function (($), (.), id)
-import Data.Functor (Functor(..), (<$>))
-import Data.Hashable (Hashable(..))
-import Data.Int (Int)
-import Data.List.NonEmpty (NonEmpty(..))
-import Data.Maybe (Maybe(..), fromMaybe)
-import Data.Monoid (Monoid(..))
-import Data.Ord (Ord(..))
-import Data.Semigroup (Semigroup(..))
-import Data.Sequence (Seq)
-import Data.String (String, IsString(..))
-import GHC.Generics (Generic)
-import Prelude ((+), error)
-import System.IO (FilePath)
-import Text.Show (Show(..), showsPrec, showChar, showParen, showString)
-import qualified Data.Char.Properties.XMLCharProps as XC
-import qualified Data.HashMap.Strict as HM
-import qualified Data.HashSet as HS
-import qualified Data.List as List
-import qualified Data.Sequence as Seq
-import qualified Data.Text.Lazy as TL
-import qualified Data.TreeSeq.Strict as TS
-
--- * Type 'XML'
-type XML src = TS.Tree (Sourced src Node)
-type XMLs src = Seq (XML src)
-
--- | Unify two 'XMLs', merging border 'NodeText's if any.
-union :: Semigroup (Sourced src EscapedText) => XMLs src -> XMLs src -> XMLs src
-union x y =
-       case (Seq.viewr x, Seq.viewl y) of
-        (xs Seq.:> x0, y0 Seq.:< ys) ->
-               case (x0,y0) of
-                (  Tree0 (Sourced sx (NodeText tx))
-                 , Tree0 (Sourced sy (NodeText ty)) ) ->
-                       xs `union`
-                       Seq.singleton (Tree0 $ (NodeText <$>) $ Sourced sx tx <> Sourced sy ty) `union`
-                       ys
-                _ -> x <> y
-        (Seq.EmptyR, _) -> y
-        (_, Seq.EmptyL) -> x
-
-unions ::
- Semigroup (Sourced src EscapedText) =>
- Foldable f => f (XMLs src) -> XMLs src
-unions = foldl' union mempty
-
-pattern Tree0 :: a -> TS.Tree a
-pattern Tree0 a <- TS.Tree a (null -> True)
-       where Tree0 a = TS.Tree a Seq.empty
-
--- ** Type 'Node'
-data Node
- =   NodeElem    QName         -- ^ Node with some 'NodeAttr' and then other 'Node's as children.
- |   NodeAttr    QName         -- ^ Node with a 'NodeText' child.
- |   NodePI      PName TL.Text -- ^ Leaf (except for @<?xml?>@ which has 'NodeAttr's.
- |   NodeText    EscapedText   -- ^ Leaf.
- |   NodeComment TL.Text       -- ^ Leaf.
- |   NodeCDATA   TL.Text       -- ^ Leaf.
- deriving (Eq, Ord, Show)
-
--- ** Type 'EscapedText'
-newtype EscapedText = EscapedText (Seq Escaped)
- deriving (Eq, Ord, Show)
-
-escapeText :: TL.Text -> EscapedText
-escapeText s =
-       EscapedText $
-       case TL.span (`List.notElem` ("<>&'\""::String)) s of
-        (t, r) | TL.null t -> escape r
-               | otherwise -> EscapedPlain t Seq.<| escape r
-       where
-       escape t = case TL.uncons t of
-        Nothing -> mempty
-        Just (c, cs) -> escapeChar c Seq.<| et where EscapedText et = escapeText cs
-
-escapeChar :: Char -> Escaped
-escapeChar c =
-       case c of
-        '<'  -> EscapedEntityRef entityRef_lt
-        '>'  -> EscapedEntityRef entityRef_gt
-        '&'  -> EscapedEntityRef entityRef_amp
-        '\'' -> EscapedEntityRef entityRef_apos
-        '"'  -> EscapedEntityRef entityRef_quot
-        _    -> EscapedPlain $ TL.singleton c
-
-unescapeText :: EscapedText -> TL.Text
-unescapeText (EscapedText et) = (`foldMap` et) $ \case
- EscapedPlain t -> t
- EscapedEntityRef EntityRef{..} -> entityRef_value
- EscapedCharRef (CharRef c) -> TL.singleton c
-
-instance Semigroup EscapedText where
- EscapedText x <> EscapedText y =
-               case (x,y) of
-                (xl Seq.:|> EscapedPlain xr, EscapedPlain yl Seq.:<|yr) ->
-                       (EscapedText $ xl Seq.|> EscapedPlain (xr<>yl)) <> EscapedText yr
-                _ -> EscapedText $ x <> y
-instance Monoid EscapedText where
-       mempty  = EscapedText mempty
-       mappend = (<>)
-
--- *** Type 'Escaped'
--- | 'EscapedText' lexemes.
-data Escaped
-  =  EscapedPlain     TL.Text
-  |  EscapedEntityRef EntityRef
-  |  EscapedCharRef   CharRef
-  deriving (Eq, Ord, Show)
-
--- *** Type 'EntityRef'
-data EntityRef = EntityRef
- { entityRef_name  :: NCName
- , entityRef_value :: TL.Text
- } deriving (Eq, Ord, Show)
-
-entityRef_lt, entityRef_gt, entityRef_amp, entityRef_quot, entityRef_apos :: EntityRef
-entityRef_lt   = EntityRef (NCName "lt") "<"
-entityRef_gt   = EntityRef (NCName "gt") ">"
-entityRef_amp  = EntityRef (NCName "amp") "&"
-entityRef_quot = EntityRef (NCName "quot") "\""
-entityRef_apos = EntityRef (NCName "apos") "'"
-
--- *** Type 'CharRef'
-newtype CharRef = CharRef Char
- deriving (Eq, Ord, Show)
-
--- ** Type 'Name'
-newtype Name = Name { unName :: TL.Text }
- deriving (Eq, Ord, Hashable)
-instance Show Name where
-       showsPrec _p = showString . TL.unpack . unName
-instance IsString Name where
-       fromString s
-        | c:cs <- s
-        , XC.isXmlNameStartChar c
-        && all XC.isXmlNameChar cs
-        = Name (TL.pack s)
-        | otherwise = error $ "Invalid XML Name: "<>show s
-
--- ** Type 'Namespace'
-newtype Namespace = Namespace { unNamespace :: TL.Text }
- deriving (Eq, Ord, Show, Hashable)
-instance IsString Namespace where
-       fromString s =
-               if all (\c -> XC.isXmlChar c && c `List.notElem` ("'\"<&"::String)) s
-               then Namespace (fromString s)
-               else error $ "Invalid XML Namespace: "<>show s
-
-xmlns_xml, xmlns_xmlns, xmlns_empty :: Namespace
-xmlns_xml   = Namespace "http://www.w3.org/XML/1998/namespace"
-xmlns_xmlns = Namespace "http://www.w3.org/2000/xmlns/"
-xmlns_empty = Namespace ""
-
--- * Type 'Namespaces'
-data Namespaces prefix = Namespaces
- { namespaces_prefixes :: (HM.HashMap Namespace prefix)
- , namespaces_default  :: Namespace
- } deriving (Show)
-instance Default (Namespaces NCName) where
-       def = Namespaces
-        { namespaces_prefixes = HM.fromList
-                [ (xmlns_xml  , "xml")
-                , (xmlns_xmlns, "xmlns")
-                ]
-        , namespaces_default  = ""
-        }
-instance Default (Namespaces (Maybe NCName)) where
-       def = Namespaces
-        { namespaces_prefixes = HM.fromList
-                [ (xmlns_xml  , Just "xml")
-                , (xmlns_xmlns, Just "xmlns")
-                ]
-        , namespaces_default  = ""
-        }
-instance Semigroup (Namespaces NCName) where
-       x <> y = Namespaces
-        { namespaces_prefixes = namespaces_prefixes x <> namespaces_prefixes y
-        , namespaces_default  = namespaces_default x
-        }
-instance Semigroup (Namespaces (Maybe NCName)) where
-       x <> y = Namespaces
-        { namespaces_prefixes = HM.unionWith (<|>) (namespaces_prefixes x) (namespaces_prefixes y)
-        , namespaces_default  = namespaces_default x
-        }
-instance Monoid (Namespaces NCName) where
-       mempty  = def
-       mappend = (<>)
-instance Monoid (Namespaces (Maybe NCName)) where
-       mempty  = def
-       mappend = (<>)
-
-prefixifyQName :: Namespaces NCName -> QName -> PName
-prefixifyQName Namespaces{..} QName{..} =
-       PName
-        { pNameSpace =
-               if qNameSpace == namespaces_default
-               then Nothing
-               else HM.lookup qNameSpace namespaces_prefixes
-        , pNameLocal = qNameLocal
-        }
-
--- ** Type 'NCName'
--- | Non-colonized name.
-newtype NCName = NCName { unNCName :: TL.Text }
- deriving (Eq, Ord, Hashable)
-instance Show NCName where
-       showsPrec _p = showString . TL.unpack . unNCName
-instance IsString NCName where
-       fromString s =
-               fromMaybe (error $ "Invalid XML NCName: "<>show s) $
-               ncName (TL.pack s)
-
-ncName :: TL.Text -> Maybe NCName
-ncName t =
-       case TL.uncons t of
-        Just (c, cs)
-         | XC.isXmlNCNameStartChar c
-         , TL.all XC.isXmlNCNameChar cs
-         -> Just (NCName t)
-        _ -> Nothing
-
-poolNCNames :: [NCName]
-poolNCNames =
-       [ NCName $ TL.pack ("ns"<>show i)
-       | i <- [1 :: Int ..]
-       ]
-
-freshNCName :: HS.HashSet NCName -> NCName
-freshNCName ps = List.head $ poolNCNames List.\\ HS.toList ps
-
-freshifyNCName :: HS.HashSet NCName -> NCName -> NCName
-freshifyNCName ns (NCName n) =
-       let ints = [1..] :: [Int] in
-       List.head
-        [ fresh
-        | suffix <- mempty : (show <$> ints)
-        , fresh <- [ NCName $ n <> TL.pack suffix]
-        , not $ fresh `HS.member` ns
-        ]
-
--- ** Type 'PName'
--- | Prefixed name.
-data PName = PName
- { pNameSpace :: (Maybe NCName) -- ^ eg. Just "xml"
- , pNameLocal :: NCName         -- ^ eg. "stylesheet"
- } deriving (Eq, Ord, Generic)
-instance Show PName where
-       showsPrec p PName{pNameSpace=Nothing, ..} =
-               showsPrec p pNameLocal
-       showsPrec _p PName{pNameSpace=Just p, ..} =
-               showsPrec 10 p .
-               showChar ':' .
-               showsPrec 10 pNameLocal
-instance IsString PName where
-       fromString "" = PName Nothing "" -- NOTE: NCName's fromString will raise an error.
-       fromString s =
-               case List.break (== ':') s of
-                (_, "")    -> PName Nothing $ fromString s
-                (p, local) -> PName (Just $ fromString p) (fromString $ List.drop 1 local)
-instance Hashable PName
-
-pName :: NCName -> PName
-pName = PName Nothing
-{-# INLINE pName #-}
-
--- ** Type 'QName'
--- | Qualified name.
-data QName = QName
- { qNameSpace :: Namespace -- ^ eg. "http://www.w3.org/1999/XSL/Transform"
- , qNameLocal :: NCName    -- ^ eg. "stylesheet"
- } deriving (Eq, Ord, Generic)
-instance Show QName where
-       showsPrec _p QName{..} =
-               (if TL.null $ unNamespace qNameSpace then id
-               else showChar '{' . showString (TL.unpack $ unNamespace qNameSpace) . showChar '}'
-               ) . showsPrec 10 qNameLocal
-instance IsString QName where
-       fromString "" = QName "" "" -- NOTE: NCName's fromString will raise an error.
-       fromString full@('{':rest) =
-               case List.break (== '}') rest of
-                (_, "")     -> error $ "Invalid XML Clark notation: "<>show full
-                (ns, local) -> QName (fromString ns) $ fromString $ List.drop 1 local
-       fromString local = QName "" $ fromString local
-instance Hashable QName
-
-qName :: NCName -> QName
-qName = QName (Namespace "")
-{-# INLINE qName #-}
-
--- * Type 'Sourced'
-data Sourced src a
- =   Sourced
- {   source  :: src
- , unSourced :: a
- } deriving (Eq, Ord, Functor)
-instance (Show src, Show a) => Show (Sourced src a) where
-       showsPrec p Sourced{..} =
-               showParen (p > 10) $
-               showsPrec 11 unSourced .
-               showString " @" . showsPrec 10 source
-instance Semigroup a => Semigroup (Sourced (FileSource Offset) a) where
-       (<>)
-        (Sourced rx@(FileRange xf xb xe :|  xs) x)
-        (Sourced    (FileRange yf yb ye :| _ys) y)
-        | xf == yf && xe == yb = Sourced (FileRange xf xb ye :| xs) $ x<>y
-        | otherwise = Sourced rx (x<>y)
-{-
-instance (FromPad a, Semigroup a) => Semigroup (Sourced (FileSource LineCol) a) where
-       (<>)
-        (Sourced rx@(FileRange xf xb xe :|  xs) x)
-        (Sourced    (FileRange yf yb ye :| _ys) y)
-        | xf == yf  = Sourced (FileRange xf xb ye :| xs) $ x<>fromPad (LineColumn l c)<>y
-        | otherwise = Sourced rx (x<>y)
-       where
-       l = lineNum yb - lineNum xe
-       c = colNum  yb - colNum (if l <= 0 then xe else xb)
-
--- ** Class 'FromPad'
-class FromPad a where
-       fromPad :: LineColumn -> a
-instance FromPad T.Text where
-       fromPad LineColumn{..} =
-               T.replicate lineNum   "\n" <>
-               T.replicate colNum " "
-instance FromPad TL.Text where
-       fromPad LineColumn{..} =
-               TL.replicate (fromIntegral lineNum)   "\n" <>
-               TL.replicate (fromIntegral colNum) " "
-instance FromPad EscapedText where
-       fromPad = EscapedText . pure . fromPad
-instance FromPad Escaped where
-       fromPad = EscapedPlain . fromPad
--}
-
--- ** Class 'NoSource'
-class NoSource src where
-       noSource :: src
-instance Default pos => NoSource (FileSource pos) where
-       noSource = noSource :| []
-instance Default pos => NoSource (FileRange pos) where
-       noSource = FileRange "" def def
-instance NoSource Offset where
-       noSource = Offset def
-{-
-instance (FromPad a, Semigroup a, Monoid a) => Monoid (Sourced a) where
-       mempty  = sourced0 mempty
-       mappend = (<>)
--}
-
-notSourced :: NoSource src => a -> Sourced src a
-notSourced = Sourced noSource
-
--- * Type 'FileSource'
-type FileSource pos = NonEmpty (FileRange pos)
-
--- ** Type 'FileSourced'
-type FileSourced = Sourced (FileSource Offset)
-
--- ** Type 'FileRange'
-data FileRange pos
- =   FileRange
- {   fileRange_file  :: FilePath
- ,   fileRange_begin :: pos
- ,   fileRange_end   :: pos
- } deriving (Eq, Ord)
-instance Default (FileRange Offset) where
-       def = FileRange "" def def
-instance Default (FileRange LineColumn) where
-       def = FileRange "" def def
-instance Show (FileRange Offset) where
-       showsPrec _p FileRange{..} =
-               showString fileRange_file .
-               showChar '@' . showsPrec 10 fileRange_begin .
-               showChar '-' . showsPrec 10 fileRange_end
-instance Show (FileRange LineColumn) where
-       showsPrec _p FileRange{..} =
-               showString fileRange_file .
-               showChar '#' . showsPrec 10 fileRange_begin .
-               showChar '-' . showsPrec 10 fileRange_end
-
--- *** Type 'Offset'
-newtype Offset = Offset Int
- deriving (Eq, Ord)
-instance Show Offset where
-       showsPrec p (Offset o) = showsPrec p o
-instance Default Offset where
-       def = Offset 0
-instance Semigroup Offset where
-       Offset x <> Offset y = Offset (x+y)
-instance Monoid Offset where
-       mempty  = def
-       mappend = (<>)
-
--- *** Type 'LineColumn'
--- | Absolute text file position.
-data LineColumn = LineColumn
- { lineNum :: {-# UNPACK #-} Offset
- , colNum  :: {-# UNPACK #-} Offset
- } deriving (Eq, Ord)
-instance Default LineColumn where
-       def = LineColumn def def
-instance Show LineColumn where
-       showsPrec _p LineColumn{..} =
-               showsPrec 11 lineNum .
-               showChar ':' .
-               showsPrec 11 colNum
-
-filePos1 :: LineColumn
-filePos1 = def
diff --git a/Symantic/XML/HLint.hs b/Symantic/XML/HLint.hs
deleted file mode 120000 (symlink)
index ab18269..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../HLint.hs
\ No newline at end of file
diff --git a/Symantic/XML/Read.hs b/Symantic/XML/Read.hs
deleted file mode 100644 (file)
index 130983b..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE Rank2Types #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Symantic.XML.Read
- ( module Symantic.XML.Read.Parser
- , module Symantic.XML.Read
- ) where
-
-import Control.Arrow (left)
-import Control.Applicative (Applicative(..), Alternative(..))
-import Control.Monad (Monad(..), void, unless, forM, join)
-import Data.Bool
-import Data.Char (Char)
-import Data.Default.Class (Default(..))
-import Data.Either (Either(..))
-import Data.Eq (Eq(..))
-import Data.Foldable (Foldable(..))
-import Data.Function (($), (.), const)
-import Data.Functor ((<$>), (<$))
-import Data.Maybe (Maybe(..), maybe)
-import Data.Monoid (Monoid(..))
-import Data.Ord (Ord(..))
-import Data.Semigroup (Semigroup(..))
-import Data.String (String)
-import Data.TreeSeq.Strict (Tree(..))
-import Data.Tuple (snd)
-import Prelude (Num(..), Enum(..), Bounded(..), Integer, toInteger)
-import System.IO (FilePath, IO)
-import Text.Megaparsec ((<?>))
-import Text.Show (Show(..))
-import qualified Control.Exception as Exn
-import qualified Control.Monad.Trans.Reader as R
-import qualified Data.ByteString.Lazy as BSL
-import qualified Data.Char as Char
-import qualified Data.Char.Properties.XMLCharProps as XC
-import qualified Data.HashMap.Strict as HM
-import qualified Data.List as List
-import qualified Data.Sequence as Seq
-import qualified Data.Text.Encoding.Error as TL
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Lazy.Encoding as TL
-import qualified Data.TreeSeq.Strict as TS
-import qualified System.IO.Error as IO
-import qualified Text.Megaparsec as P
-import qualified Text.Megaparsec.Char as P
-
-import Symantic.XML.Document hiding (XML, XMLs)
-import Symantic.XML.Read.Parser
-
-readXML :: FilePath -> TL.Text -> Either (P.ParseErrorBundle TL.Text Error) XMLs
-readXML filePath stateInput =
-       snd $
-       P.runParser'
-        (R.runReaderT p_document def)
-        P.State
-        { P.stateInput
-        , P.stateOffset = 0
-        , P.statePosState = P.PosState
-                { P.pstateInput      = stateInput
-                , P.pstateOffset     = 0
-                , P.pstateSourcePos  = P.initialPos filePath
-                , P.pstateTabWidth   = P.pos1
-                , P.pstateLinePrefix = ""
-                }
-        }
-
-readFile :: FilePath -> IO (Either ErrorRead TL.Text)
-readFile fp =
-       (left ErrorRead_Unicode . TL.decodeUtf8' <$> BSL.readFile fp)
-       `Exn.catch` \e ->
-               if IO.isAlreadyInUseError e
-               || IO.isDoesNotExistError e
-               || IO.isPermissionError   e
-               then return $ Left $ ErrorRead_IO e
-               else IO.ioError e
-
--- * Type 'ErrorRead'
-data ErrorRead
- =   ErrorRead_IO IO.IOError
- |   ErrorRead_Unicode TL.UnicodeException
- deriving (Show)
-
--- * Document
-p_document :: P.Tokens s ~ TL.Text => Parser Error s XMLs
-p_document = do
-       ps <- p_prolog
-       e  <- p_Element
-       ms <- P.many p_Misc
-       P.eof
-       return (ps <> pure e <> join (Seq.fromList ms))
-
--- ** Prolog
-p_prolog :: P.Tokens s ~ TL.Text => Parser Error s XMLs
-p_prolog = do
-       xmlDecl <- P.option Seq.empty $ pure <$> p_XMLDecl
-       ms <- P.many p_Misc
-       return (xmlDecl <> join (Seq.fromList ms))
-
--- ** Misc
-p_Misc :: P.Tokens s ~ TL.Text => Parser Error s XMLs
-p_Misc =
-       P.try (pure <$> p_Comment)
-        <|> P.try (pure <$> p_PI)
-        <|> pure <$> p_S
-
--- ** XMLDecl
-p_XMLDecl :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_XMLDecl = P.label "XMLDecl" $ do
-       Sourced src as <- p_Sourced $ P.between (P.string "<?xml") (P.string "?>") $ do
-               vi <- pure <$> p_VersionInfo
-               ed <- P.option Seq.empty $ pure <$> p_EncodingDecl
-               sd <- P.option Seq.empty $ pure <$> p_SDDecl
-               p_Spaces
-               return $ vi <> ed <> sd
-       return $ Tree (Sourced src $ NodePI "xml" "") as
-
-p_VersionInfo :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_VersionInfo = P.label "VersionInfo" $ do
-       Sourced c v <- p_Sourced $ do
-               P.try (() <$ p_Spaces1 <* P.string "version")
-               p_Eq
-               p_quoted $ const $ p_Sourced $
-                       (<>)
-                        <$> P.string "1."
-                        <*> P.takeWhile1P Nothing Char.isDigit
-       return $ Tree (Sourced c $ NodeAttr "version") $ pure $
-               TS.tree0 $ NodeText . EscapedText . pure . EscapedPlain <$> v
-
-p_EncodingDecl :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_EncodingDecl = P.label "EncodingDecl" $ do
-       Sourced c v <- p_Sourced $ do
-               P.try (() <$ p_Spaces1 <* P.string "encoding")
-               p_Eq
-               p_quoted $ const $ p_Sourced p_EncName
-       return $ Tree (Sourced c $ NodeAttr "encoding") $ pure $
-               TS.tree0 $ NodeText . EscapedText . pure . EscapedPlain <$> v
-
-p_EncName :: P.Tokens s ~ TL.Text => Parser Error s TL.Text
-p_EncName = P.label "EncName" $ do
-       P.notFollowedBy (P.satisfy $ not . isAlpha)
-       P.takeWhile1P Nothing $ \c ->
-               isAlpha c || Char.isDigit c ||
-               c=='.' || c=='_' || c=='-'
-       where isAlpha c = Char.isAsciiLower c || Char.isAsciiUpper c
-
--- *** SDDecl
-p_SDDecl :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_SDDecl = P.label "SDDecl" $ do
-       p_SourcedBegin $ do
-               Sourced ca () <- P.try (p_Sourced $ () <$ p_Spaces1 <* P.string "standalone")
-               p_Eq
-               v <- p_quoted $ const $ p_Sourced $ P.string "yes" <|> P.string "no"
-               return $ Tree (Sourced ca $ NodeAttr "standalone") $ pure $
-                       TS.tree0 $ NodeText . EscapedText . pure . EscapedPlain <$> v
-
--- ** CharData
-p_CharData :: P.Tokens s ~ TL.Text => Parser e s EscapedText
-p_CharData =
-       escapeText
-        <$> p_until1 (\c -> XC.isXmlChar c && c/='<' && c/='&') (']',"]>")
-
--- ** Comment
-p_Comment :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_Comment = p_SourcedBegin $ P.string "<!--" *> p_Comment__
-p_Comment_ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_Comment_ = P.string "--" *> p_Comment__
-p_Comment__:: P.Tokens s ~ TL.Text => Parser Error s XML
-p_Comment__ = P.label "Comment" $ do
-       c <- p_until XC.isXmlChar ('-', "-")
-       void $ P.string "-->"
-       cell <- p_SourcedEnd
-       return $ TS.tree0 (cell $ NodeComment c)
-
--- ** CDATA
-p_CDSect :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_CDSect = p_SourcedBegin $ P.string "<![CDATA[" *> p_CDSect__
-p_CDSect_ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_CDSect_ = P.string "[CDATA[" *> p_CDSect__
-p_CDSect__ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_CDSect__ = P.label "CDSect" $ do
-       c <- p_until XC.isXmlChar (']', "]>")
-       void $ P.string "]]>"
-       cell <- p_SourcedEnd
-       return $ TS.tree0 $ cell $ NodeCDATA c
-
--- ** PI
-p_PI :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_PI = p_SourcedBegin $ P.string "<?" *> p_PI__
-p_PI_ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_PI_ = P.char '?' *> p_PI__
-p_PI__ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_PI__ = P.label "PI" $ do
-       n <- p_PITarget
-       v <- P.option "" $ P.try $ p_Spaces1 *> p_until XC.isXmlChar ('?', ">")
-       void $ P.string "?>"
-       cell <- p_SourcedEnd
-       return $ TS.tree0 $ cell $ NodePI n v
-p_PITarget :: P.Tokens s ~ TL.Text => Parser Error s PName
-p_PITarget = do
-       n <- p_PName
-       case n of
-        PName{pNameSpace=Nothing, pNameLocal=NCName l}
-         | "xml" == TL.toLower l -> p_error $ Error_PI_reserved n
-        _ -> return n
-
--- ** Element
-p_Element :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_Element = p_SourcedBegin $ (P.char '<' *> p_Element_)
-p_Element_ :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_Element_ = P.label "Element" p_STag
-
--- *** STag
-p_STag :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_STag = do
-       n  <- p_PName
-       as <- P.many $ P.try $ p_Spaces1 *> p_Attribute
-       p_Spaces
-       ro <- R.ask
-       elemNS :: HM.HashMap NCName Namespace <-
-               (HM.fromList . List.concat <$>) $ forM as $ \case
-                Sourced _ (PName{..}, Sourced _ av)
-                 | ns <- Namespace $ unescapeText av
-                 , Nothing        <- pNameSpace
-                 , NCName "xmlns" <- pNameLocal ->
-                       -- NOTE: default namespace declaration.
-                       case ns of
-                        _ |  ns == xmlns_xml   -- DOC: it MUST NOT be declared as the default namespace
-                          || ns == xmlns_xmlns -- DOC: it MUST NOT be declared as the default namespace
-                          -> p_error $ Error_Namespace_reserved ns
-                        _ -> return [(NCName "" , ns)]
-                 | ns <- Namespace $ unescapeText av
-                 , Just (NCName "xmlns") <- pNameSpace ->
-                       -- NOTE: namespace prefix declaration.
-                       case unNCName pNameLocal of
-                        "xml" -- DOC: It MAY, but need not, be declared,
-                              -- and MUST NOT be bound to any other namespace name.
-                              | ns == xmlns_xml -> return []
-                              | otherwise -> p_error $ Error_Namespace_reserved_prefix pNameLocal
-                        "xmlns" -- DOC: It MUST NOT be declared
-                                -> p_error $ Error_Namespace_reserved_prefix pNameLocal
-                        local | "xml" <- TL.toLower $ TL.take 3 local -> return []
-                              -- DOC: All other prefixes beginning with the three-letter
-                              -- sequence x, m, l, in any case combination, are reserved.
-                              -- This means that: processors MUST NOT treat them as fatal errors.
-                        _ |  ns == xmlns_xml   -- DOC: Other prefixes MUST NOT be bound to this namespace name.
-                          || ns == xmlns_xmlns -- DOC: Other prefixes MUST NOT be bound to this namespace name.
-                          -> p_error $ Error_Namespace_reserved ns
-                        _ -> return [(pNameLocal, ns)]
-                 | otherwise -> return []
-       let scopeNS = elemNS <> reader_ns_scope ro
-       let defaultNS = HM.lookupDefault (reader_ns_default ro) (NCName "") scopeNS
-       let lookupNamePrefix prefix =
-               maybe (p_error $ Error_Namespace_prefix_unknown prefix) return $
-               HM.lookup prefix scopeNS
-       elemName :: QName <-
-               -- NOTE: expand element's QName.
-               case pNameSpace n of
-                Nothing -> return QName{qNameSpace=defaultNS, qNameLocal=pNameLocal n}
-                 -- DOC: If there is a default namespace declaration in scope,
-                 -- the expanded name corresponding to an unprefixed element name
-                 -- has the URI of the default namespace as its namespace name.
-                Just prefix
-                 | NCName "xmlns" <- prefix ->
-                       -- DOC: Element names MUST NOT have the prefix xmlns.
-                       p_error $ Error_Namespace_reserved_prefix prefix
-                 | otherwise -> do
-                       ns <- lookupNamePrefix prefix
-                       return QName{qNameSpace=ns, qNameLocal=pNameLocal n}
-       elemAttrs :: [FileSourced (QName, FileSourced EscapedText)] <-
-               -- NOTE: expand attributes' PName into QName.
-               forM as $ \s@Sourced{unSourced=(an, av)} -> do
-                       ns <- maybe (return "") lookupNamePrefix $ pNameSpace an
-                       let qn = QName{qNameSpace=ns, qNameLocal=pNameLocal an}
-                       return s{unSourced=(qn, av)}
-       -- NOTE: check for attribute collision.
-       let attrsByQName :: HM.HashMap QName [FileSourced (QName, FileSourced EscapedText)] =
-               HM.fromListWith (<>) $ (<$> elemAttrs) $ \a@(Sourced _c (an, _av)) -> (an, [a])
-       case HM.toList $ HM.filter (\x -> length x > 1) attrsByQName of
-        (an, _):_ -> p_error $ Error_Attribute_collision an
-        _ -> return ()
-       elemAttrsXML :: XMLs <- (Seq.fromList <$>) $
-               forM elemAttrs $ \(Sourced sa (an, av)) -> do
-                       return $ TS.Tree (Sourced sa $ NodeAttr an) $
-                               pure $ TS.tree0 $ NodeText <$> av
-       content :: XMLs <-
-               elemAttrsXML <$ P.string "/>" <|>
-               R.local
-                (const ro
-                        { reader_ns_scope   = scopeNS
-                        , reader_ns_default = defaultNS
-                        })
-                ((elemAttrsXML <>) <$ P.char '>' <*> p_content <* p_ETag elemName)
-       cell <- p_SourcedEnd
-       return $ Tree (cell $ NodeElem elemName) content
-
--- *** Attribute
-p_Attribute :: P.Tokens s ~ TL.Text => Parser Error s (FileSourced (PName, FileSourced EscapedText))
-p_Attribute = p_Sourced $ (,) <$> p_PName <* p_Eq <*> p_AttValue
-
-p_AttValue :: P.Tokens s ~ TL.Text => Parser Error s (FileSourced EscapedText)
-p_AttValue = P.label "AttValue" $ p_quoted p_AttValueText
-
-p_AttValueText :: P.Tokens s ~ TL.Text => Char -> Parser Error s (FileSourced EscapedText)
-p_AttValueText q = p_Sourced $
-       EscapedText . Seq.fromList <$> P.many
-        ( p_Reference
-        <|> EscapedPlain <$> P.takeWhile1P Nothing (\c ->
-               XC.isXmlChar c &&
-               c `List.notElem` (q:"<&'\">"))
-        <|> EscapedEntityRef entityRef_gt <$ P.char '>'
-        <|> (if q == '\''
-               then EscapedEntityRef entityRef_quot <$ P.char '"'
-               else EscapedEntityRef entityRef_apos <$ P.char '\'')
-        )
-
--- * content
-p_content :: P.Tokens s ~ TL.Text => Parser Error s XMLs
-p_content =
-       (Seq.fromList <$>) $ P.many $
-               (p_SourcedBegin $ do
-                       P.try $ P.char '<' *> P.notFollowedBy (P.char '/')
-                       p_Element_ <|> p_PI_ <|> (P.char '!' *> (p_Comment_ <|> p_CDSect_))
-               )
-               <|> ((tree0 <$>) $ p_Sourced $ NodeText . mconcat
-                        <$> P.some (p_CharData <|> EscapedText . pure <$> p_Reference))
-
--- *** ETag
-p_ETag :: P.Tokens s ~ TL.Text => QName -> Parser Error s ()
-p_ETag expected = do
-       got <- P.string "</" *> p_QName <* p_Spaces <* P.char '>'
-       unless (got == expected) $
-               p_error $ Error_Closing_tag_unexpected got expected
-
--- * Name
-p_Name :: P.Tokens s ~ TL.Text => Parser Error s Name
-p_Name = P.label "Name" $
-       Name
-        <$  P.notFollowedBy (P.satisfy $ not . XC.isXmlNameStartChar)
-        <*> P.takeWhile1P Nothing XC.isXmlNameChar
-
--- * PName
-p_PName :: P.Tokens s ~ TL.Text => Parser e s PName
-p_PName = P.label "PName" $ do
-       n <- p_NCName
-       s <- P.optional $ P.try $ P.char ':' *> p_NCName
-       return $ case s of
-        Nothing -> PName{pNameSpace=Nothing, pNameLocal=n}
-        Just l  -> PName{pNameSpace=Just n , pNameLocal=l}
-
--- * QName
-p_QName :: P.Tokens s ~ TL.Text => Parser Error s QName
-p_QName = P.label "QName" $ do
-       n <- p_NCName
-       s <- P.optional $ P.try $ P.char ':' *> p_NCName
-       Reader{..} <- R.ask
-       case s of
-        Nothing -> return QName{qNameSpace=reader_ns_default, qNameLocal=n}
-        Just l ->
-               case HM.lookup n reader_ns_scope of
-                Nothing -> p_error $ Error_Namespace_prefix_unknown n
-                Just ns -> return QName{qNameSpace=ns, qNameLocal=l}
-
--- ** NCName
-p_NCName :: P.Tokens s ~ TL.Text => Parser e s NCName
-p_NCName = P.label "NCName" $
-       NCName
-        <$  P.notFollowedBy (P.satisfy $ not . XC.isXmlNCNameStartChar)
-        <*> P.takeWhile1P Nothing XC.isXmlNCNameChar
-
--- * Reference
-p_Reference :: P.Tokens s ~ TL.Text => Parser Error s Escaped
-p_Reference =
-       EscapedCharRef <$> p_CharRef <|>
-       EscapedEntityRef <$> p_EntityRef
-
--- ** EntityRef
-p_EntityRef :: P.Tokens s ~ TL.Text => Parser Error s EntityRef
-p_EntityRef = P.label "EntityRef" $ do
-       ref <- P.char '&' *> p_NCName <* P.char ';'
-       EntityRef ref <$> lookupEntityRef ref
-       where
-       lookupEntityRef (NCName "lt"  ) = pure "<"
-       lookupEntityRef (NCName "gt"  ) = pure ">"
-       lookupEntityRef (NCName "amp" ) = pure "&"
-       lookupEntityRef (NCName "apos") = pure "'"
-       lookupEntityRef (NCName "quot") = pure "\""
-       lookupEntityRef n = p_error $ Error_EntityRef_unknown n
-
--- ** CharRef
-p_CharRef :: P.Tokens s ~ TL.Text => Parser Error s CharRef
-p_CharRef = P.label "CharRef" $
-       do
-               ref <- readHexadecimal
-                <$  P.string "&#x"
-                <*> P.some P.hexDigitChar
-                <*  P.char ';'
-               check ref
-       <|> do
-               ref <- readDecimal
-                <$  P.string "&#"
-                <*> P.some P.digitChar
-                <*  P.char ';'
-               check ref
-       where
-       check i =
-               let c = toEnum (fromInteger i) in
-               if i <= toInteger (fromEnum (maxBound::Char))
-               && XC.isXmlChar c
-               then pure $ CharRef c
-               else p_error $ Error_CharRef_invalid i
-
-readInt :: Integer -> String -> Integer
-readInt base digits =
-       sign * List.foldl' acc 0 (List.concatMap digToInt digits1)
-       where
-       acc q r = q*base + r
-       (sign, digits1) =
-               case digits of
-                [] -> (1, digits)
-                c:ds | c == '-'  -> (-1, ds)
-                     | c == '+'  -> ( 1, ds)
-                     | otherwise -> ( 1, digits)
-       ord = toInteger . Char.ord
-       digToInt c
-        | Char.isDigit c      = [ord c - ord '0']
-        | Char.isAsciiLower c = [ord c - ord 'a' + 10]
-        | Char.isAsciiUpper c = [ord c - ord 'A' + 10]
-        | otherwise           = []
-
-readDecimal :: String -> Integer
-readDecimal = readInt 10
-
-readHexadecimal :: String -> Integer
-readHexadecimal = readInt 16
-
--- * Char
-p_Char :: P.Tokens s ~ TL.Text => Parser e s Char
-p_Char = P.label "Char" $ P.satisfy XC.isXmlCharCR <|> p_CRLF
-{-# INLINE p_Char #-}
-
--- ** Space
--- | Map '\r' and '\r\n' to '\n'.
-p_CRLF :: P.Tokens s ~ TL.Text => Parser e s Char
-p_CRLF = P.label "CRLF" $
-       P.char '\r' *> P.option '\n' (P.char '\n')
-
-p_Space :: P.Tokens s ~ TL.Text => Parser e s Char
-p_Space = P.label "Space" $
-       P.satisfy XC.isXmlSpaceCharCR <|> p_CRLF
-{-# INLINE p_Space #-}
-
-p_Spaces :: P.Tokens s ~ TL.Text => Parser e s ()
-p_Spaces = P.label "Spaces" $
-       void $ P.takeWhileP Nothing XC.isXmlSpaceChar
-{-# INLINE p_Spaces #-}
-
-p_S :: P.Tokens s ~ TL.Text => Parser Error s XML
-p_S = P.label "Spaces" $
-       (\ts -> TS.tree0 (NodeText . EscapedText . pure . EscapedPlain . TL.concat <$> ts))
-        <$> p_Sourced (P.some $
-               P.takeWhile1P Nothing XC.isXmlSpaceCharCR <|>
-               TL.singleton <$> p_CRLF)
-
-p_Spaces1 :: P.Tokens s ~ TL.Text => Parser e s ()
-p_Spaces1 = P.label "Spaces1" $
-       void $ P.takeWhile1P Nothing XC.isXmlSpaceChar
-{-# INLINE p_Spaces1 #-}
-
--- * Eq
-p_separator :: P.Tokens s ~ TL.Text => Char -> Parser e s ()
-p_separator c = P.try (() <$ p_Spaces <* P.char c) <* p_Spaces <?> [c]
-
-p_Eq :: P.Tokens s ~ TL.Text => Parser e s ()
-p_Eq = p_separator '=' <?> "Eq"
diff --git a/Symantic/XML/Read/HLint.hs b/Symantic/XML/Read/HLint.hs
deleted file mode 120000 (symlink)
index ab18269..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../HLint.hs
\ No newline at end of file
diff --git a/Symantic/XML/Read/Parser.hs b/Symantic/XML/Read/Parser.hs
deleted file mode 100644 (file)
index 524004b..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE Rank2Types #-}
-{-# LANGUAGE StrictData #-}
-{-# LANGUAGE TypeFamilies #-}
-module Symantic.XML.Read.Parser where
-
-import Control.Applicative (Applicative(..), Alternative(..))
-import Control.Monad (Monad(..))
-import Data.Bool
-import Data.Char (Char)
-import Data.Default.Class (Default(..))
-import Data.Eq (Eq(..))
-import Data.Function (($), (.))
-import Data.Functor ((<$>))
-import Data.List.NonEmpty (NonEmpty(..))
-import Data.Maybe (Maybe(..))
-import Data.Ord (Ord(..))
-import Data.String (IsString)
-import Prelude (Integer)
-import Text.Show (Show(..))
-import qualified Control.Monad.Trans.Reader as R
-import qualified Data.HashMap.Strict as HM
-import qualified Data.Set as Set
-import qualified Data.Text.Lazy as TL
-import qualified Text.Megaparsec as P
-import qualified Text.Megaparsec.Char as P
-
-import Symantic.XML.Document hiding (XML, XMLs)
-import qualified Symantic.XML.Document as XML
-
--- | Specify |XML.XML|'s 'src' type parameter for parsing.
-type XML = XML.XML (FileSource Offset)
--- | Specify |XML.XMLs|'s 'src' type parameter for parsing.
-type XMLs = XML.XMLs (FileSource Offset)
-
--- * Type 'Parser'
--- | Convenient alias.
-type Parser   e s a =
-     Parsable e s a =>
-     R.ReaderT Reader (P.Parsec e s) a
-
--- ** Type 'Parsable'
-type Parsable e s a =
- ( P.Stream s
- , P.Token s ~ Char
- , Ord e
- , IsString (P.Tokens s)
- , P.ShowErrorComponent e
- )
-
--- ** Type 'Reader'
-data Reader = Reader
- { reader_source     :: FileSource Offset
- , reader_ns_scope   :: HM.HashMap NCName Namespace
- , reader_ns_default :: Namespace
- } deriving (Show)
-instance Default Reader where
-       def = Reader
-        { reader_source     = pure def
-        , reader_ns_scope   = HM.fromList
-                [ ("xml"  , xmlns_xml)
-                , ("xmlns", xmlns_xmlns)
-                ]
-        , reader_ns_default = ""
-        }
-
-p_Offset :: Parser e s Offset
-p_Offset = Offset <$> P.getOffset
-{-# INLINE p_Offset #-}
-
-p_Sourced :: Parser e s a -> Parser e s (Sourced (FileSource Offset) a)
-p_Sourced pa = do
-       Reader{reader_source} <- R.ask
-       b <- P.getParserState
-       let fileRange_file = P.sourceName $ P.pstateSourcePos $ P.statePosState b
-       let fileRange_begin = Offset $ P.stateOffset b
-       a <- pa
-       e <- P.getParserState
-       let fileRange_end = Offset $ P.stateOffset e
-       return $ Sourced (setSource FileRange{..} reader_source) a
-
-setSource :: FileRange pos -> FileSource pos -> FileSource pos
-setSource fileRange (_curr:|next) = fileRange :| next
-
--- | Like 'p_Sourced' but uncoupled (through the use of 'p_SourcedEnd') for more flexibility.
-p_SourcedBegin :: Parser e s a -> Parser e s a
-p_SourcedBegin pa = do
-       b <- P.getParserState
-       let fileRange_file  = P.sourceName $ P.pstateSourcePos $ P.statePosState b
-       let fileRange_begin = Offset $ P.stateOffset b
-       let fileRange_end   = fileRange_begin
-       (`R.local` pa) $ \ro@Reader{..} ->
-               ro{ reader_source = setSource FileRange{..} reader_source }
-
--- | WARNING: Only to be used within a 'p_SourcedBegin'.
-p_SourcedEnd :: Parser e s (a -> Sourced (FileSource Offset) a)
-p_SourcedEnd = do
-       Reader{..} <- R.ask
-       e <- P.getParserState
-       let fileRange_end = Offset $ P.stateOffset e
-       return $ Sourced $
-                (\(curr:|path) -> curr{fileRange_end}:|path)
-                reader_source
-
-{-
--- ** Type 'StreamSourced'
--- | Wrap 'TL.Text' to have a 'P.Stream' instance
--- whose 'P.advance1' method abuses the tab width state
--- to instead pass the line indent.
--- This in order to report correct 'P.SourcePos'
--- when parsing a 'Sourced' containing newlines.
-newtype StreamSourced = StreamSourced { unStreamSourced :: TL.Text }
- deriving (IsString,Eq,Ord)
-instance P.Stream StreamSourced where
-       type Token  StreamSourced = Char
-       type Tokens StreamSourced = TL.Text
-       take1_       (StreamSourced t) = (StreamSourced <$>) <$> P.take1_ t
-       takeN_     n (StreamSourced t) = (StreamSourced <$>) <$> P.takeN_ n t
-       takeWhile_ f (StreamSourced t) = StreamSourced <$> P.takeWhile_ f t
-       tokensToChunk _s = P.tokensToChunk (Proxy::Proxy TL.Text)
-       chunkToTokens _s = P.chunkToTokens (Proxy::Proxy TL.Text)
-       chunkLength   _s = P.chunkLength   (Proxy::Proxy TL.Text)
-       {-
-       advance1 _s indent (P.SourcePos n line col) c =
-               case c of
-                '\n' -> P.SourcePos n (line <> P.pos1) indent
-                _    -> P.SourcePos n line (col <> P.pos1)
-       advanceN s indent = TL.foldl' (P.advance1 s indent)
-       -}
-
--- | Wrapper around |P.runParser'|
--- to use given 'Sourced' as starting position.
-runParserOnSourced ::
- Parsable e StreamSourced a =>
- Parser e StreamSourced a ->
- Sourced FileSource TL.Text ->
- Either (P.ParseError (P.Token StreamSourced) e) a
-runParserOnSourced p (Sourced (FileRange inp bp _ep :| path) s) =
-       snd $
-       P.runParser' (R.runReaderT p ro <* P.eof)
-        P.State
-        { P.stateInput    = StreamSourced s
-        , P.statePos      = pure $ P.SourcePos inp (P.mkPos $ filePos_line bp) indent
-        , P.stateTabWidth = indent
-        , P.stateTokensProcessed = 0
-        }
-       where
-       indent = P.mkPos $ filePos_column bp
-       ro     = def{ reader_source = fromMaybe (pure def) $ nonEmpty path }
--}
-
--- * Type 'Error'
-data Error
- =   Error_CharRef_invalid Integer
-     -- ^ Well-formedness constraint: Legal Character.
-     --
-     -- Characters referred to using character references MUST match the production for Char.
- |   Error_EntityRef_unknown NCName
-     -- ^ Well-formedness constraint: Entity Declared
-     --
-     -- In a document without any DTD, a document with only an internal DTD
-     -- subset which contains no parameter entity references, or a document
-     -- with " standalone='yes' ", for an entity reference that does not occur
-     -- within the external subset or a parameter entity, the Name given in the
-     -- entity reference MUST match that in an entity declaration that does not
-     -- occur within the external subset or a parameter entity, except that
-     -- well-formed documents need not declare any of the following entities:
-     -- amp, lt, gt, apos, quot. The declaration of a general entity MUST
-     -- precede any reference to it which appears in a default value in an
-     -- attribute-list declaration.
-     --
-     -- Note that non-validating processors are not obligated to read and
-     -- process entity declarations occurring in parameter entities or in the
-     -- external subset; for such documents, the rule that an entity must be
-     -- declared is a well-formedness constraint only if standalone='yes'.
- |   Error_Closing_tag_unexpected QName QName
-     -- ^ Well-formedness constraint: Element Type Match.
-     --
-     -- The Name in an element's end-tag MUST match the element type in the start-tag.
- |   Error_Attribute_collision QName
-     -- ^ Well-formedness constraint: Unique Att Spec.
-     --
-     -- An attribute name MUST NOT appear more than once in the same start-tag or empty-element tag.
- |   Error_PI_reserved PName
-     -- ^ The target names " XML ", " xml ", and so on are reserved for standardization.
- |   Error_Namespace_prefix_unknown NCName
-     -- ^ Namespace constraint: Prefix Declared
-     --
-     -- The namespace prefix, unless it is xml or xmlns, MUST have been declared in a namespace declaration attribute in either the start-tag of the element where the prefix is used or in an ancestor element (i.e., an element in whose content the prefixed markup occurs). 
- |   Error_Namespace_empty NCName
-     -- ^ Namespace constraint: No Prefix Undeclaring
-     --
-     -- In a namespace declaration for a prefix (i.e., where the NSAttName is a PrefixedAttName), the attribute value MUST NOT be empty.
- |   Error_Namespace_reserved Namespace
- |   Error_Namespace_reserved_prefix NCName
-     -- ^ Namespace constraint: Reserved Prefixes and Namespace Names
-     --
-     -- The prefix xml is by definition bound to the namespace name
-     -- http://www.w3.org/XML/1998/namespace. It MAY, but need not, be
-     -- declared, and MUST NOT be bound to any other namespace name. Other
-     -- prefixes MUST NOT be bound to this namespace name, and it MUST NOT be
-     -- declared as the default namespace.
-     --
-     -- The prefix xmlns is used only to declare namespace bindings and is by
-     -- definition bound to the namespace name http://www.w3.org/2000/xmlns/.
-     -- It MUST NOT be declared . Other prefixes MUST NOT be bound to this
-     -- namespace name, and it MUST NOT be declared as the default namespace.
-     -- Element names MUST NOT have the prefix xmlns.
-     --
-     -- All other prefixes beginning with the three-letter sequence x, m, l, in
-     -- any case combination, are reserved. This means that:
-     --
-     -- - users SHOULD NOT use them except as defined by later specifications
-     -- - processors MUST NOT treat them as fatal errors.
- deriving (Eq,Ord,Show)
-instance P.ShowErrorComponent Error where
-       showErrorComponent = show
-
--- * Helpers
-p_error :: e -> Parser e s a
-p_error = P.fancyFailure . Set.singleton . P.ErrorCustom
-
-p_quoted :: P.Tokens s ~ TL.Text => (Char -> Parser e s a) -> Parser e s a
-p_quoted p =
-       P.between (P.char '"') (P.char '"') (p '"') <|>
-       P.between (P.char '\'') (P.char '\'') (p '\'')
-
-p_until :: P.Tokens s ~ TL.Text => (Char -> Bool) -> (Char, TL.Text) -> Parser e s TL.Text
-p_until content (end, end_) =
-       (TL.concat <$>) $ P.many $
-               P.takeWhile1P Nothing (\c -> content c && c /= end) <|>
-               P.try (TL.singleton <$> P.char end <* P.notFollowedBy (P.string end_))
-
-p_until1 :: P.Tokens s ~ TL.Text => (Char -> Bool) -> (Char, TL.Text) -> Parser e s TL.Text
-p_until1 content (end, end_) =
-       (TL.concat <$>) $ P.some $
-               P.takeWhile1P Nothing (\c -> content c && c /= end) <|>
-               P.try (TL.singleton <$> P.char end <* P.notFollowedBy (P.string end_))
diff --git a/Symantic/XML/Write.hs b/Symantic/XML/Write.hs
deleted file mode 100644 (file)
index 0b04545..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE StrictData #-}
-module Symantic.XML.Write where
-
-import Control.Applicative (Applicative(..), liftA2)
-import Control.Monad (Monad(..))
-import Data.Bool
-import Data.Default.Class (Default(..))
-import Data.Eq (Eq(..))
-import Data.Foldable (Foldable(..), all)
-import Data.Function (($), (.), const)
-import Data.Maybe (Maybe(..))
-import Data.Monoid (Monoid(..))
-import Data.Semigroup (Semigroup(..))
-import Data.String (String, IsString(..))
-import Data.Traversable (Traversable(..))
-import System.IO (IO, FilePath)
-import Text.Show (Show(..))
-import qualified Control.Monad.Trans.Reader as R
-import qualified Control.Monad.Trans.State as S
-import qualified Data.ByteString.Lazy as BSL
-import qualified Data.Char as Char
-import qualified Data.HashMap.Strict as HM
-import qualified Data.HashSet as HS
-import qualified Data.Sequence as Seq
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Lazy.Builder as TLB
-import qualified Data.Text.Lazy.Encoding as TL
-
-import Symantic.XML.Document as XML
-
-writeXML :: NoSource src => XMLs src -> TL.Text
-writeXML xs = TLB.toLazyText $ write xs `R.runReader` def
-
-writeXMLIndented :: NoSource src => TL.Text -> XMLs src -> TL.Text
-writeXMLIndented ind xs =
-       TLB.toLazyText $
-       write xs `R.runReader` def
-        { reader_indent       = if TL.null ind then mempty else "\n"
-        , reader_indent_delta = ind
-        }
-
-writeFile :: FilePath -> TL.Text -> IO ()
-writeFile fp t = BSL.writeFile fp $ TL.encodeUtf8 t
-
--- * Type 'Write'
-type Write = R.Reader Reader TLB.Builder
-instance Semigroup Write where
-       (<>) = liftA2 (<>)
-instance Monoid Write where
-       mempty = return ""
-       mappend = (<>)
-instance IsString Write where
-       fromString = return . fromString
-
--- ** Type 'Reader'
-data Reader = Reader
- { reader_ns_scope     :: Namespaces NCName
- , reader_indent       :: TLB.Builder
- , reader_indent_delta :: TL.Text
- , reader_no_text      :: Bool
- }
-instance Default Reader where
-       def = Reader
-        { reader_ns_scope     = def
-        , reader_indent       = ""
-        , reader_indent_delta = ""
-        , reader_no_text      = False
-        }
-
--- * Class 'Buildable'
-class Buildable a where
-       build :: a -> TLB.Builder
-instance Buildable Char.Char where
-       build = TLB.singleton
-instance Buildable String where
-       build = TLB.fromString
-instance Buildable TL.Text where
-       build = TLB.fromLazyText
-instance Buildable NCName where
-       build = build . unNCName
-instance Buildable Name where
-       build = build . unName
-instance Buildable PName where
-       build PName{..} =
-               case pNameSpace of
-                Nothing -> build pNameLocal
-                Just p -> build p<>":"<> build pNameLocal
-instance Buildable Namespace where
-       build = build . unNamespace
-instance Buildable EntityRef where
-       build EntityRef{..} = "&"<>build entityRef_name<>";"
-instance Buildable CharRef where
-       build (CharRef c) = "&#"<>build (show (Char.ord c))<>";"
-instance Buildable EscapedText where
-       build (EscapedText et) = (`foldMap` et) $ \case
-        EscapedPlain     t -> build t
-        EscapedEntityRef r -> build r
-        EscapedCharRef   r -> build r
-
--- * Class 'Writable'
-class Writeable a where
-       write :: a -> Write
-instance Writeable NCName where
-       write = return . TLB.fromLazyText . unNCName
-instance NoSource src => Writeable (XMLs src) where
-       write xs = do
-               ro <- R.ask
-               if TL.null (reader_indent_delta ro)
-                then foldMap write xs
-                else
-                       R.local (const ro{reader_no_text}) $
-                               foldMap write xs
-                       where reader_no_text =
-                               (`all` xs) $ \case
-                                Tree (Sourced _ (NodeText (EscapedText et))) _ts ->
-                                       all (\case
-                                        EscapedPlain t -> TL.all Char.isSpace t
-                                        _ -> False) et
-                                _ -> True
-instance NoSource src => Writeable (XML src) where
-       write (Tree (Sourced _src nod) xs) = do
-               ro <- R.ask
-               case nod of
-                       NodeAttr an
-                        | [Tree (Sourced _ (NodeText av)) _] <- toList xs -> do
-                               return $ " "<>buildAttr (prefixifyQName (reader_ns_scope ro) an) av
-                        | otherwise -> mempty
-                       NodeCDATA t ->
-                               return $
-                                       reader_indent ro <>
-                                       "<[CDATA[["<>build t<>"]]>"
-                       NodeComment t ->
-                               return $
-                                       reader_indent ro <>
-                                       "<!--"<>build t<>"-->"
-                       NodeElem elemQName -> do
-                               let (elemAttrs, elemChilds) =
-                                       (`Seq.spanl` xs) $ \case
-                                                Tree (Sourced _ NodeAttr{}) _ -> True
-                                                _ -> False
-                               let (usedNS, declNS) ::
-                                       ( HS.HashSet Namespace
-                                       , Namespaces NCName
-                                       ) =
-                                       foldl' go (initUsedNS, initDeclNS) elemAttrs
-                                       where
-                                       initUsedNS
-                                        | qNameSpace elemQName == xmlns_empty = mempty
-                                        | otherwise                           = HS.singleton $ qNameSpace elemQName
-                                       initDeclNS = def{namespaces_default = namespaces_default $ reader_ns_scope ro}
-                                       go (!uNS, !dNS) = \case
-                                               Tree (Sourced _ (NodeAttr QName{..})) vs
-                                                -- xmlns:prefix="namespace"
-                                                | qNameSpace == xmlns_xmlns
-                                                , [Tree (Sourced _ (NodeText t)) _] <- toList vs ->
-                                                       let n = unescapeText t in
-                                                       (uNS,) dNS
-                                                        { namespaces_prefixes =
-                                                               (if TL.null n
-                                                               then HM.delete
-                                                               -- NOTE: empty namespace means removal of the prefix from scope.
-                                                               else (`HM.insert` qNameLocal))
-                                                                (Namespace n)
-                                                                (namespaces_prefixes dNS)
-                                                        }
-                                                -- xmlns="namespace"
-                                                | qNameSpace == xmlns_empty
-                                                , qNameLocal == NCName "xmlns"
-                                                , [Tree (Sourced _ (NodeText t)) _] <- toList vs ->
-                                                       (uNS,)
-                                                       dNS{namespaces_default = Namespace $ unescapeText t}
-                                                -- name="value"
-                                                | qNameSpace == xmlns_empty -> (uNS, dNS)
-                                                -- {namespace}name="value"
-                                                | otherwise -> (HS.insert qNameSpace uNS, dNS)
-                                               _ -> (uNS, dNS)
-                               let inhNS =
-                                       -- NOTE: the inherited namespaces,
-                                       -- including those declared at this element.
-                                       HM.union
-                                        (namespaces_prefixes declNS)
-                                        (namespaces_prefixes (reader_ns_scope ro))
-                               let autoNS =
-                                       -- NOTE: the namespaces used but not declared nor default,
-                                       -- with fresh prefixes.
-                                       HM.delete (namespaces_default declNS) $
-                                       (`S.evalState` HS.empty) $
-                                       traverse
-                                        (\() -> S.gets freshNCName)
-                                        (HS.toMap usedNS `HM.difference` inhNS)
-                               let autoAttrs =
-                                       -- NOTE: XMLify autoNS
-                                       HM.foldlWithKey'
-                                        (\acc (Namespace v) p ->
-                                               (acc Seq.|>) $
-                                                       Tree (notSourced $ NodeAttr QName{qNameSpace=xmlns_xmlns, qNameLocal=p}) $
-                                                               pure $ tree0 $ notSourced $ NodeText $ EscapedText $ pure $ EscapedPlain v
-                                        ) mempty autoNS
-                               let scopeNS = declNS { namespaces_prefixes = autoNS <> inhNS }
-                               return $
-                                       let build_elemPName = build $ prefixifyQName scopeNS elemQName in
-                                       let build_elemAttrs =
-                                               (`foldMap` (autoAttrs <> elemAttrs)) $ \case
-                                                Tree (Sourced _ (NodeAttr an)) vs
-                                                 | [Tree (Sourced _ (NodeText av)) _] <- toList vs ->
-                                                       " "<>buildAttr (prefixifyQName scopeNS{namespaces_default=""} an) av
-                                                _ -> mempty in
-                                       reader_indent ro
-                                        <> "<"<>build_elemPName
-                                        <> build_elemAttrs <>
-                                       let build_elemChilds = write elemChilds
-                                               `R.runReader` ro
-                                                { reader_ns_scope = scopeNS
-                                                , reader_indent   = reader_indent ro <> build (reader_indent_delta ro)
-                                                } in
-                                       if null elemChilds
-                                       then "/>"
-                                       else ">"
-                                                <> build_elemChilds
-                                                <> (
-                                                       if TL.null (reader_indent_delta ro)
-                                                       || noIndent elemChilds
-                                                       then mempty
-                                                       else reader_indent ro
-                                                )
-                                                <> "</"<>build_elemPName<>">"
-                                       where
-                                       noIndent =
-                                               all $ \case
-                                                Tree (Sourced _ (NodeText _txt)) _ts -> True
-                                                _ -> False
-                       NodePI pn pv
-                        | pn == "xml" -> do
-                               write_xs <- write xs
-                               return $
-                                       "<?"<>build pn<>s<>write_xs<>"?>"
-                        | otherwise ->
-                               return $
-                                       reader_indent ro <>
-                                       "<?"<>build pn<>s<>build pv<>"?>"
-                               where s | TL.null pv = ""
-                                       | otherwise  = " "
-                       NodeText t -> do
-                               return $
-                                       if reader_no_text ro
-                                        then mempty
-                                        else build t
-
-buildAttr :: PName -> EscapedText -> TLB.Builder
-buildAttr n v = build n<>"=\""<>buildAttrValue v<>"\""
-
-buildAttrValue :: EscapedText -> TLB.Builder
-buildAttrValue (EscapedText et) = (`foldMap` et) $ \case
- EscapedPlain p -> build p
- EscapedEntityRef EntityRef{..} ->
-       build $ TL.replace "\"" "&quot;" entityRef_value
- EscapedCharRef (CharRef c)
-       | c == '\"' -> "&quot;"
-       | otherwise -> build c
-
-removeSpaces :: XMLs src -> XMLs src
-removeSpaces xs =
-       if (`all` xs) $ \case
-        Tree (Sourced _ (NodeText (EscapedText et))) _ts ->
-               all (\case
-                EscapedPlain t -> TL.all Char.isSpace t
-                _ -> False) et
-        _ -> True
-       then (`Seq.filter` xs) $ \case
-                Tree (Sourced _ NodeText{}) _ts -> False
-                _ -> True
-       else xs
diff --git a/hie.yaml b/hie.yaml
new file mode 100644 (file)
index 0000000..b02bb35
--- /dev/null
+++ b/hie.yaml
@@ -0,0 +1,6 @@
+cradle:
+  stack:
+    - path: "./"
+      component: "symantic-xml:lib"
+    - path: "./test"
+      component: "symantic-xml:test:symantic-xml-test"
diff --git a/src/Symantic/XML.hs b/src/Symantic/XML.hs
new file mode 100644 (file)
index 0000000..eafd2e2
--- /dev/null
@@ -0,0 +1,11 @@
+module Symantic.XML
+ ( module Symantic.XML.Language
+ , module Symantic.XML.Read
+ , module Symantic.XML.Tree
+ , module Symantic.XML.Write
+ ) where
+
+import Symantic.XML.Language
+import Symantic.XML.Read
+import Symantic.XML.Tree
+import Symantic.XML.Write
diff --git a/src/Symantic/XML/Language.hs b/src/Symantic/XML/Language.hs
new file mode 100644 (file)
index 0000000..af245e4
--- /dev/null
@@ -0,0 +1,76 @@
+{-# LANGUAGE UndecidableInstances #-}
+module Symantic.XML.Language
+ ( module Symantic.XML.Language
+ , module Symantic.XML.Namespace
+ , module Symantic.XML.Text
+ , module Symantic.Base.Composable
+ , module Symantic.Base.Algebrable
+ , module Symantic.Base.Permutable
+ ) where
+
+import Data.Function ((.))
+import Data.Maybe (Maybe)
+import Data.Kind (Constraint)
+import qualified Data.Text.Lazy as TL
+
+import Symantic.XML.Namespace
+import Symantic.XML.Text
+import Symantic.Base.Algebrable
+import Symantic.Base.Composable
+import Symantic.Base.Permutable
+
+-- * Class 'XML'
+class
+ ( Composable repr
+ , Tupable repr
+ , Eitherable repr
+ , Textable repr
+ ) => XML repr where
+  --xmlPI ::  -> repr a k
+  -- | @('namespace' p ns)@ declares a namespace prefix @(p)@
+  -- to be used for the 'Namespace' @(ns)@.
+  -- Or make @(ns)@ the default namespace if @(p)@ is 'Nothing'.
+  namespace :: Maybe NCName -> Namespace -> repr k k
+  default namespace ::
+   Transformable repr => XML (UnTrans repr) =>
+   Maybe NCName -> Namespace -> repr k k
+  namespace n ns = noTrans (namespace n ns)
+  
+  default element :: Transformable repr => XML (UnTrans repr) =>
+             QName -> repr a k -> repr a k
+  element :: QName -> repr a k -> repr a k
+  element n x = noTrans (element n (unTrans x))
+  
+  default attribute :: Transformable repr => XML (UnTrans repr) =>
+               QName -> repr a k -> repr a k
+  attribute :: QName -> repr a k -> repr a k
+  attribute n x = noTrans (attribute n (unTrans x))
+  
+  default pi :: Transformable repr => XML (UnTrans repr) =>
+        PName -> repr (TL.Text -> k) k
+  pi :: PName -> repr (TL.Text -> k) k
+  pi n = noTrans (pi n)
+  
+  default literal :: Transformable repr => XML (UnTrans repr) =>
+             TL.Text -> repr k k
+  literal :: TL.Text -> repr k k
+  literal = noTrans . literal
+  
+  default comment :: Transformable repr => XML (UnTrans repr) =>
+             repr (TL.Text -> k) k
+  comment :: repr (TL.Text -> k) k
+  comment = noTrans comment
+  
+  default cdata :: Transformable repr => XML (UnTrans repr) =>
+           repr (TL.Text -> k) k
+  cdata :: repr (TL.Text -> k) k
+  cdata = noTrans cdata
+
+-- ** Class 'Textable'
+class Textable repr where
+  type TextConstraint repr a :: Constraint
+  type TextConstraint repr a = TextConstraint (UnTrans repr) a
+  default text :: Transformable repr => XML (UnTrans repr) =>
+          TextConstraint (UnTrans repr) a => repr (a -> k) k
+  text :: TextConstraint repr a => repr (a -> k) k
+  text = noTrans text
diff --git a/src/Symantic/XML/Namespace.hs b/src/Symantic/XML/Namespace.hs
new file mode 100644 (file)
index 0000000..15866bb
--- /dev/null
@@ -0,0 +1,180 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE StrictData #-}
+{-# LANGUAGE TypeFamilyDependencies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Symantic.XML.Namespace where
+
+import Control.Applicative (Alternative(..))
+import Data.Bool
+import Data.Eq (Eq(..))
+import Data.Foldable (all)
+import Data.Function (($), (.), id)
+import Data.Functor (Functor(..), (<$>))
+import Data.Hashable (Hashable(..))
+import Data.Int (Int)
+import Data.Maybe (Maybe(..), fromMaybe)
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (String, IsString(..))
+import GHC.Generics (Generic)
+import Prelude (error)
+import Text.Show (Show(..), showsPrec, showChar, showString)
+import qualified Data.Char.Properties.XMLCharProps as XC
+import qualified Data.HashMap.Strict as HM
+import qualified Data.HashSet as HS
+import qualified Data.List as List
+import qualified Data.Text.Lazy as TL
+
+-- * Type 'QName'
+-- | Qualified name.
+data QName
+ =   QName
+ {   qNameSpace :: Namespace -- ^ eg. "http://www.w3.org/1999/XSL/Transform"
+ ,   qNameLocal :: NCName    -- ^ eg. "stylesheet"
+ } deriving (Eq, Ord, Generic)
+instance Show QName where
+  showsPrec _p QName{..} =
+    (if TL.null $ unNamespace qNameSpace then id
+    else showChar '{' . showString (TL.unpack $ unNamespace qNameSpace) . showChar '}'
+    ) . showsPrec 10 qNameLocal
+instance IsString QName where
+  -- NCName's fromString will raise an error.
+  fromString "" = QName "" ""
+  fromString full@('{':rest) =
+    case List.break (== '}') rest of
+     (_, "")     -> error $ "Invalid XML Clark notation: "<>show full
+     (ns, local) -> QName (fromString ns) $ fromString $ List.drop 1 local
+  fromString local = QName "" $ fromString local
+instance Hashable QName
+
+qName :: NCName -> QName
+qName = QName (Namespace "")
+{-# INLINE qName #-}
+
+-- ** Type 'Namespace'
+newtype Namespace = Namespace { unNamespace :: TL.Text }
+ deriving (Eq, Ord, Show, Hashable)
+instance IsString Namespace where
+  fromString s =
+    if all (\c -> XC.isXmlChar c && c `List.notElem` ("'\"<&"::String)) s
+    then Namespace (fromString s)
+    else error $ "Invalid XML Namespace: "<>show s
+
+xmlns_xml, xmlns_xmlns, xmlns_xsd, xmlns_empty :: Namespace
+xmlns_xml   = Namespace "http://www.w3.org/XML/1998/namespace"
+xmlns_xmlns = Namespace "http://www.w3.org/2000/xmlns/"
+xmlns_xsd   = Namespace "http://www/w3/org/2001/XMLSchema-datatypes"
+xmlns_empty = Namespace ""
+
+-- *** Type 'Namespaces'
+data Namespaces prefix
+ =   Namespaces
+ {   namespaces_prefixes :: HM.HashMap Namespace prefix
+ ,   namespaces_default  :: Namespace
+ } deriving (Show)
+instance Functor Namespaces where
+  fmap f (Namespaces ps d) = Namespaces (fmap f ps) d
+instance Semigroup (Namespaces NCName) where
+  x <> y = Namespaces
+   { namespaces_prefixes = namespaces_prefixes x <> namespaces_prefixes y
+   , namespaces_default  = namespaces_default x
+   }
+instance Semigroup (Namespaces (Maybe NCName)) where
+  x <> y = Namespaces
+   { namespaces_prefixes = HM.unionWith (<|>) (namespaces_prefixes x) (namespaces_prefixes y)
+   , namespaces_default  = namespaces_default x
+   }
+instance Monoid (Namespaces NCName) where
+  mempty  = Namespaces HM.empty xmlns_empty
+  mappend = (<>)
+instance Monoid (Namespaces (Maybe NCName)) where
+  mempty  = Namespaces HM.empty xmlns_empty
+  mappend = (<>)
+
+defaultNamespaces :: IsString prefix => Namespaces prefix
+defaultNamespaces = Namespaces
+ { namespaces_prefixes = HM.fromList
+   [ (xmlns_xml  , "xml")
+   , (xmlns_xmlns, "xmlns")
+   ]
+ , namespaces_default = xmlns_empty
+ }
+
+prefixifyQName :: Namespaces NCName -> QName -> PName
+prefixifyQName Namespaces{..} QName{..} = PName
+ { pNameSpace =
+  if qNameSpace == namespaces_default
+  then Nothing
+  else HM.lookup qNameSpace namespaces_prefixes
+ , pNameLocal = qNameLocal
+ }
+
+-- ** Type 'PName'
+-- | Prefixed 'NCName'
+data PName
+ =   PName
+ {   pNameSpace :: Maybe NCName -- ^ eg. Just "xml"
+ ,   pNameLocal :: NCName       -- ^ eg. "stylesheet"
+ } deriving (Eq, Ord, Generic)
+instance Show PName where
+  showsPrec p PName{pNameSpace=Nothing, ..} =
+    showsPrec p pNameLocal
+  showsPrec _p PName{pNameSpace=Just p, ..} =
+    showsPrec 10 p .
+    showChar ':' .
+    showsPrec 10 pNameLocal
+instance IsString PName where
+  fromString "" = PName Nothing "" -- NCName's fromString will raise an error.
+  fromString s =
+    case List.break (== ':') s of
+     (_, "")    -> PName Nothing $ fromString s
+     (p, local) -> PName (Just $ fromString p) (fromString $ List.drop 1 local)
+
+pName :: NCName -> PName
+pName = PName Nothing
+{-# INLINE pName #-}
+
+-- ** Type 'NCName'
+-- | Non-colonized name.
+newtype NCName = NCName { unNCName :: TL.Text }
+ deriving (Eq, Ord, Hashable)
+instance Show NCName where
+  showsPrec _p = showString . TL.unpack . unNCName
+instance IsString NCName where
+  fromString s =
+    fromMaybe (error $ "Invalid XML NCName: "<>show s) $
+    ncName (TL.pack s)
+
+ncName :: TL.Text -> Maybe NCName
+ncName t =
+  case TL.uncons t of
+   Just (c, cs)
+    | XC.isXmlNCNameStartChar c
+    , TL.all XC.isXmlNCNameChar cs
+    -> Just (NCName t)
+   _ -> Nothing
+
+poolNCNames :: [NCName]
+poolNCNames =
+  [ NCName $ TL.pack ("ns"<>show i)
+  | i <- [1 :: Int ..]
+  ]
+
+freshNCName :: HS.HashSet NCName -> NCName
+freshNCName ps = List.head $ poolNCNames List.\\ HS.toList ps
+
+freshifyNCName :: HS.HashSet NCName -> NCName -> NCName
+freshifyNCName ns (NCName n) =
+  let ints = [1..] :: [Int] in
+  List.head
+   [ fresh
+   | suffix <- mempty : (show <$> ints)
+   , fresh <- [ NCName $ n <> TL.pack suffix]
+   , not $ fresh `HS.member` ns
+   ]
diff --git a/src/Symantic/XML/Read.hs b/src/Symantic/XML/Read.hs
new file mode 100644 (file)
index 0000000..c654253
--- /dev/null
@@ -0,0 +1,640 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Symantic.XML.Read where
+
+import Control.Applicative as Alternative (Applicative(..), Alternative(..), optional)
+import Control.Monad (Monad(..))
+import Control.Monad.Trans.Class (MonadTrans(..))
+import Data.Bool
+import Data.Either (Either(..))
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..), all)
+import Data.Function (($), (.), const, id, flip)
+import Data.Functor (Functor(..), (<$>))
+import Data.List.NonEmpty (NonEmpty(..))
+import Data.Maybe (Maybe(..), maybe, isNothing, maybeToList)
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Proxy (Proxy(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (String, IsString(..))
+import Data.Tuple (fst)
+import Data.Void (Void)
+import Numeric.Natural (Natural)
+import Prelude ((+), Integer, undefined)
+import System.IO (IO, FilePath)
+import Text.Show (Show(..))
+import qualified Data.Char as Char
+import qualified Data.HashMap.Strict as HM
+import qualified Data.List as List
+import qualified Data.List.NonEmpty as NonEmpty
+import qualified Data.Sequence as Seq
+import qualified Data.Set as Set
+import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TLB
+import qualified Data.TreeSeq.Strict as TS
+import qualified Text.Megaparsec as P
+import qualified Text.Megaparsec.Char as P
+import qualified Text.Megaparsec.Char.Lexer as P
+import qualified Text.Megaparsec.Internal as P
+
+import Symantic.Base
+import Symantic.XML.Language
+import Symantic.XML.RelaxNG.Language
+import Symantic.XML.Tree
+
+-- | Main reading function.
+read ::
+ Read FileSourced Void (x->x) a ->
+ FilePath ->
+ IO (Either String a)
+read rng path =
+  readTree path >>= \case
+   Left  err -> return $ Left err
+   Right xml -> return $ runRead rng xml
+
+-- | Like 'readWithRelaxNG' but on a 'FileSourcedTrees'.
+runRead ::
+ Read FileSourced Void (x->x) a ->
+ FileSourcedTrees ->
+ Either String a
+runRead rng xml =
+  case P.runParser (unRead rng) "" (mempty, xml) of
+   Left err -> Left $ foldMap parseErrorTextPretty $ P.bundleErrors err
+   Right a -> Right $ a id
+
+-- * Type 'ReadStream'
+type ReadStream src =
+ ( HM.HashMap QName (src EscapedAttr)
+ , Trees src
+ )
+
+-- | Take one 'Node' from the 'ReadStream',
+-- or fallback to an attribute, or 'Nothing'.
+-- 
+-- Use 'pTokenAttr' to take only attributes.
+take1_ ::
+ UnSource src =>
+ (Node (src EscapedAttr) -> Bool) ->
+ ReadStream src ->
+ Maybe ( P.Token (ReadStream src)
+       , ReadStream src )
+take1_ isIgnoredNode s@(attrs, trees) =
+  go trees
+  where
+  go trs =
+    case Seq.viewl trs of
+     Seq.EmptyL
+      | null attrs -> Nothing
+      | otherwise -> Just (Left attrs, s)
+     t Seq.:< ts ->
+      case unSource (TS.unTree t) of
+       n | isIgnoredNode n -> go ts
+         | otherwise -> Just (Right t, (attrs, ts))
+        -- Note that having an ignored node
+        -- can split a text into two 'NodeText's.
+        -- Not sure if it would be better to unify them.
+
+-- ** Type 'ReadConstraints'
+-- | Convenient alias to be less verbose.
+type ReadConstraints src =
+ ( Ord (src (Node (src EscapedAttr)))
+ , Ord (src EscapedAttr)
+ , UnSource src
+ , NoSource src
+ , SourceOf src
+ , Show (Source src)
+ , Show (src String)
+ , Functor src
+ )
+
+instance ReadConstraints src => P.Stream (ReadStream src) where
+  type Token (ReadStream src) = Either
+   (HM.HashMap QName (src EscapedAttr))
+   (Tree src)
+  type Tokens (ReadStream src) = ReadStream src
+  take1_ = take1_ isIgnoredNode
+    where
+    isIgnoredNode = \case
+     NodeComment{} -> True
+     NodePI{}      -> True
+     _ -> False
+  showTokens _s toks =
+    orList $
+    mconcat $
+    toList $ showTree <$> toks
+    where
+    showSource :: src String -> String
+    showSource sa =
+      let src = sourceOf sa in
+      if nullSource @src src
+      then unSource sa
+      else unSource sa<>" at "<>show src
+    showTree = \case
+     Left as ->
+      (\(an, av) -> showSource $ ("(attribute "<>show an<>")") <$ av)
+       <$> List.sortOn fst (HM.toList as)
+     Right (TS.Tree nod ts) ->
+      pure $
+      showSource . (<$ nod) $
+      case unSource nod of
+       NodeElem n _as -> "(element "<>show n<>")"
+       NodeText{} ->
+        case Seq.viewl ts of
+         TS.Tree tn _ Seq.:< _
+          | NodeText lit <- unSource tn ->
+          -- Abuse the encoding to detect expected 'literal'
+          -- using nested 'NodeText'
+          "\""<>TL.unpack (unescapeText lit)<>"\""
+         _ -> "text"
+       NodeComment _c -> "comment"
+       NodePI n _t    -> "(processing-instruction "<>show n<>")"
+       NodeCDATA _t   -> "cdata"
+  -- Useless methods for validating an XML AST
+  takeN_ = undefined
+  tokensToChunk = undefined
+  chunkToTokens = undefined
+  chunkLength = undefined
+  takeWhile_ = undefined
+  reachOffset = undefined
+  reachOffsetNoLine = undefined
+
+-- * Type 'Read'
+newtype Read src e f k
+ =      Read
+ {    unRead :: P.Parsec e (ReadStream src) (f->k) }
+
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Emptyable (Read src err) where
+  empty = Read $ id <$ P.eof
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Unitable (Read src err) where
+  unit = Read $ return ($ ())
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Voidable (Read src err) where
+  void _a (Read x) = Read $
+    (\a2b2k b -> a2b2k (\_a -> b)) <$> x
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Constant (Read src err) where
+  constant a = Read $ return ($ a)
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Permutable (Read src err) where
+  type Permutation (Read src err) =
+    ReadPerm src err
+  permutable (ReadPerm ma p) = Read $ do
+    r <- Alternative.optional p
+    unRead $
+      case r of
+       Just perms -> permutable perms
+       Nothing ->
+        Read $ maybe
+         -- Not 'empty' here so that 'P.TrivialError'
+         -- has the unexpected token.
+         (P.token (const Nothing) Set.empty)
+         return ma
+  noPerm = ReadPerm Nothing Alternative.empty
+  perm (Read x) =
+    ReadPerm Nothing $ (<$> x) $ \a ->
+      ReadPerm (Just a) Alternative.empty
+  permWithDefault d (Read x) =
+    ReadPerm (Just ($ d)) $ (<$> x) $ \a ->
+      ReadPerm (Just a) Alternative.empty
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Composable (Read src err) where
+  Read x <.> Read y = Read $
+    x >>= \a2b -> (. a2b) <$> y
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Tupable (Read src err) where
+  Read x <:> Read y = Read $
+    consCont (,) <$> x <*> y
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Eitherable (Read src err) where
+  Read x <+> Read y = Read $
+    mapCont Left <$> P.try x <|>
+    mapCont Right <$> y
+{-
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Routable (Read src err) where
+  Read x <!> Read y = Read $
+    (\a2k (a:!:_b) -> a2k a) <$> P.try x <|>
+    (\b2k (_a:!:b) -> b2k b) <$> y
+-}
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Optionable (Read src err) where
+  option (Read x) = Read $
+    P.try x <|> return id
+  optional (Read x) = Read $
+    mapCont Just <$> P.try x <|>
+    return ($ Nothing)
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Repeatable (Read src err) where
+  many0 (Read x) = Read $ concatCont <$> many x
+  many1 (Read x) = Read $ concatCont <$> some x
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Dimapable (Read src err) where
+  dimap a2b _b2a (Read r) =
+    Read $ (\k b2k -> k (b2k . a2b)) <$> r
+instance
+ ( Ord err
+ , ReadConstraints src
+ ) => Dicurryable (Read src err) where
+  dicurry (_::proxy args) constr _destr (Read x) = Read $ do
+    f <- x
+    return $ \r2k ->
+      f (mapresultN @args r2k constr)
+instance
+ ( Ord err
+ , ReadConstraints src
+ , Textable (Read src err)
+ ) => XML (Read src err) where
+  namespace _nm _ns = Read (return id)
+  element n p = Read $ do
+    s <- P.token check $ Set.singleton $
+      P.Tokens $ pure expected
+    unRead $ readNested p s
+    where
+    expected = Right $ TS.tree0 $ noSource $ NodeElem n mempty
+    check = \case
+     Right (TS.Tree nod ts)
+      | NodeElem e as <- unSource nod
+      , e == n
+      -> Just (removeXMLNS as, removeSpaces ts)
+     _ -> Nothing
+  attribute n p = Read $ do
+    v <- pTokenAttr n $ Set.singleton $
+      P.Tokens $ pure expected
+    unRead $ readNested p
+     (mempty, pure (TS.tree0 (NodeText . EscapedText . unEscapedAttr <$> v)))
+    -- Cast 'EscapedAttr' into 'EscapedText'
+    -- because it will be read, not written,
+    -- hence only given to 'unescapeText'
+    -- which is the same than 'unescapeAttr'.
+    where
+    expected = Left $ HM.singleton n $ noSource ""
+  literal lit = Read $ do
+    P.token check $ Set.singleton $ P.Tokens $ pure expected
+    where
+    expected = Right $
+      TS.Tree (noSource $ NodeText "")
+       (pure $ TS.tree0 (noSource $ NodeText $ escapeText lit))
+    check = \case
+     Right (Tree0 nod)
+      | NodeText t <- unSource nod
+      , unescapeText t == lit
+      -> Just id
+     _ -> Nothing
+  pi n = Read $ do
+    v <- pTokenPI n $ Set.singleton $
+      P.Tokens $ pure expected
+    return ($ v)
+    where
+    expected = Right $ TS.tree0 $ noSource $ NodePI n mempty
+  cdata = Read $
+    P.token check $ Set.singleton $
+      P.Tokens $ pure expected
+    where
+    expected = Right $ TS.tree0 $ noSource $ NodeCDATA mempty
+    check = \case
+     Right (Tree0 nod)
+      | NodeCDATA v <- unSource nod
+      -> Just ($ v)
+     _ -> Nothing
+  comment = Read $
+    P.token check $ Set.singleton $
+      P.Tokens $ pure expected
+    where
+    expected = Right $ TS.tree0 $ noSource $ NodeComment mempty
+    check = \case
+     Right (Tree0 nod)
+      | NodeComment v <- unSource nod
+      -> Just ($ v)
+     _ -> Nothing
+instance Ord err => Textable (Read FileSourced err) where
+  type TextConstraint (Read FileSourced err) a =
+    DecodeText a
+  text :: forall a k repr.
+   repr ~ Read FileSourced err =>
+   TextConstraint repr a => repr (a->k) k
+  text = Read $ do
+    Sourced (FileSource (src :| _)) txt <-
+      P.token check $ Set.singleton $ P.Tokens $ pure expected
+    case P.runParser @Void (decodeText @a <* P.eof) "" (unescapeText txt) of
+     Right a -> return ($ a)
+     Left errs -> P.fancyFailure $ Set.singleton $ P.ErrorFail $
+      (`foldMap` P.bundleErrors errs) $ \err ->
+        fileRange_path src <> ":" <>
+        show (fileRange_begin src <> Offset (P.errorOffset err)) <> "\n" <>
+        P.parseErrorTextPretty err
+    where
+    expected = Right $ TS.tree0 $ noSource $ NodeText $ EscapedText mempty
+    check = \case
+     Right (Tree0 nod)
+      | NodeText t <- unSource nod
+      -> Just (t <$ nod)
+     _ -> Nothing
+instance
+ ( Ord err
+ , ReadConstraints src
+ , Textable (Read src err)
+ , Definable (Read src err)
+ ) => RelaxNG (Read src err) where
+  elementMatch nc p = Read $ do
+    (n,s) <- P.token check $ Set.singleton $
+      P.Tokens $ pure expected
+    ((\a2k n2a -> a2k (n2a n)) <$>) $
+      unRead (readNested p s)
+    where
+    expected = Right $ TS.tree0 $ noSource $
+      NodeElem (qName (NCName (TLB.toLazyText
+       (textify (mempty::Namespaces NCName,(infixN0,SideL),nc)))))
+       mempty
+    check = \case
+     Right (TS.Tree nod ts)
+      | NodeElem n as <- unSource nod
+      , matchNameClass nc n
+      -> Just (n, (removeXMLNS as, removeSpaces ts))
+     _ -> Nothing
+  attributeMatch nc p = Read $ do
+    (an,av) <- pTokenAttrNameClass nc $ Set.singleton $
+      P.Tokens $ pure expected
+    ((\a2k n2a -> a2k (n2a an)) <$>) $
+      unRead $ readNested p
+       (mempty, pure (TS.tree0 (NodeText . EscapedText . unEscapedAttr <$> av)))
+    -- See comment in 'attribute' about the cast to 'EscapedText' here.
+    where
+    expected = Left $ HM.singleton (qName (NCName n)) $ noSource ""
+      where n = TLB.toLazyText $ textify (mempty::Namespaces NCName,(infixN0,SideL),nc)
+instance Ord err => Definable (Read FileSourced err) where
+  define n = Read . P.label n . unRead
+
+-- ** Type 'ReadPerm'
+data ReadPerm (src :: * -> *) err a k
+ =   ReadPerm
+ {   readPerm_result :: !(Maybe (a->k))
+ ,   readPerm_parser :: P.Parsec err (ReadStream src) (ReadPerm src err a k)
+ }
+
+instance
+ (Ord err, ReadConstraints src) =>
+ Dimapable (ReadPerm src err) where
+  dimap a2b b2a (ReadPerm a ma) =
+    ReadPerm (merge <$> a)
+    (dimap a2b b2a `fmap` ma)
+    where merge = \a2k2k b2k -> a2k2k $ b2k . a2b
+instance
+ (Ord err, ReadConstraints src) =>
+ Dicurryable (ReadPerm src err) where
+  dicurry ::
+   forall args r k proxy.
+   CurryN args =>
+   proxy args ->
+   (args-..->r) -> -- construction
+   (r->Tuples args) -> -- destruction
+   ReadPerm src err (args-..->k) k ->
+   ReadPerm src err (r->k) k
+  dicurry px constr destr (ReadPerm a ma) =
+    ReadPerm (merge <$> a)
+     (dicurry px constr destr `fmap` ma)
+    where
+    merge args2k2k = \r2k ->
+      args2k2k $ mapresultN @args r2k constr
+instance
+ (Ord err, ReadConstraints src) =>
+ Composable (ReadPerm src err) where
+  lhs@(ReadPerm da pa) <.> rhs@(ReadPerm db pb) =
+    ReadPerm a $
+      lhsAlt <|> rhsAlt
+    where
+    lhsAlt = (<.> rhs) <$> pa
+    rhsAlt = (lhs <.>) <$> pb
+    a = flip (.) <$> da <*> db
+instance
+ (Ord err, ReadConstraints src) =>
+ Tupable (ReadPerm src err) where
+  lhs@(ReadPerm da pa) <:> rhs@(ReadPerm db pb) =
+    ReadPerm a (lhsAlt <|> rhsAlt)
+    where
+    lhsAlt = (<:> rhs) <$> pa
+    rhsAlt = (lhs <:>) <$> pb
+    a = consCont (,) <$> da <*> db
+instance Definable (ReadPerm src err) where
+  define _n = id
+
+-- * Utils
+
+concatCont :: [(a->k)->k] -> ([a]->k)->k
+concatCont = List.foldr (consCont (:)) ($ [])
+{-# INLINE concatCont #-}
+
+consCont :: (a->b->c) -> ((a->k)->k) -> ((b->k)->k) -> (c->k)->k
+consCont ab2c a2k2k b2k2k = \c2k -> a2k2k $ \a -> b2k2k $ \b -> c2k (ab2c a b)
+{-# INLINE consCont #-}
+
+mapCont :: (a->b) -> ((a->k)->k) -> ((b->k)->k)
+mapCont a2b a2k2k = \b2k -> a2k2k (b2k . a2b)
+{-# INLINE mapCont #-}
+
+-- | An adaptation of megaparsec's 'pToken',
+-- to handle 'attribute' properly.
+pTokenAttr ::
+ forall e m src.
+ ReadConstraints src =>
+ QName ->
+ Set.Set (P.ErrorItem (P.Token (ReadStream src))) ->
+ P.ParsecT e (ReadStream src) m (src EscapedAttr)
+pTokenAttr an ps = P.ParsecT $ \st@(P.State s@(attrs,trees) o pst de) cok _ _ eerr ->
+  case HM.lookup an attrs of
+   Just av -> cok av (P.State (HM.delete an attrs, trees) (o+1) pst de) mempty
+   Nothing -> eerr (P.TrivialError o us ps) st
+    where
+    us = case P.take1_ s of
+     Nothing -> pure P.EndOfInput
+     Just (t,_ts) -> (Just . P.Tokens . pure) t
+{-# INLINE pTokenAttr #-}
+
+-- | An adaptation of megaparsec's 'pToken',
+-- to handle 'attributeMatch' properly.
+pTokenAttrNameClass ::
+ forall e m src.
+ ReadConstraints src =>
+ NameClass ->
+ Set.Set (P.ErrorItem (P.Token (ReadStream src))) ->
+ P.ParsecT e (ReadStream src) m (QName, src EscapedAttr)
+pTokenAttrNameClass nc ps = P.ParsecT $ \st@(P.State s@(attrs,trees) o pst de) cok _ _ eerr ->
+  case HM.toList attrs of
+   a@(an,_av):_ | matchNameClass nc an -> cok a (P.State (HM.delete an attrs, trees) (o+1) pst de) mempty
+   _ -> eerr (P.TrivialError o us ps) st
+    where
+    us = case P.take1_ s of
+     Nothing -> pure P.EndOfInput
+     Just (t,_ts) -> (Just . P.Tokens . pure) t
+{-# INLINE pTokenAttrNameClass #-}
+
+-- | An adaptation of megaparsec's 'pToken',
+-- to handle 'pi' since 'NodePI' is ignored by 'P.take1_'.
+pTokenPI ::
+ forall e m src.
+ UnSource src =>
+ PName ->
+ Set.Set (P.ErrorItem (P.Token (ReadStream src))) ->
+ P.ParsecT e (ReadStream src) m TL.Text
+pTokenPI n ps = P.ParsecT $ \st@(P.State s o pst de) cok _ _ eerr ->
+  case take1 s of
+   Nothing -> eerr (P.TrivialError o us ps) st
+    where us = pure P.EndOfInput
+   Just (c, cs)
+    | Right (TS.Tree nod _) <- c
+    , NodePI pn pv <- unSource nod
+    , pn == n -> cok pv (P.State cs (o+1) pst de) mempty
+    | otherwise -> eerr (P.TrivialError o us ps) st
+      where
+      us = case take1 s of
+       Nothing -> pure P.EndOfInput
+       Just (t,_ts) -> (Just . P.Tokens . pure) t
+  where
+  take1 = take1_ isIgnoredNode
+    where
+    isIgnoredNode = \case
+     NodeComment{} -> True
+     _ -> False
+
+removeXMLNS ::
+ HM.HashMap QName (src EscapedAttr) ->
+ HM.HashMap QName (src EscapedAttr)
+removeXMLNS =
+  HM.filterWithKey $ \an _av ->
+    case an of
+     QName "" "xmlns" -> False
+     QName ns _l -> ns /= xmlns_xmlns
+
+removeSpaces :: UnSource src => Trees src -> Trees src
+removeSpaces xs =
+  if (`all` xs) $ \case
+   TS.Tree nod _ts
+    | NodeText (EscapedText et) <- unSource nod ->
+    all (\case
+     EscapedPlain t -> TL.all Char.isSpace t
+     _ -> False) et
+   _ -> True
+  then (`Seq.filter` xs) $ \case
+   TS.Tree nod _ts
+    | NodeText EscapedText{} <- unSource nod -> False
+   _ -> True
+  else xs
+
+-- | @readNested v xs@ returns a 'Read' parsing @xs@ entirely with @v@,
+-- updating 'P.stateOffset' and re-raising any exception.
+readNested ::
+ Ord err =>
+ ReadConstraints src =>
+ Read src err f a ->
+ ReadStream src ->
+ Read src err f a
+readNested (Read p) stateInput = Read $ do
+  st <- P.getParserState
+  (st', res) <- lift $ P.runParserT' (p <* P.eof) st
+   { P.stateInput
+   , P.stateOffset = P.stateOffset st
+   }
+  P.updateParserState (\s -> s{P.stateOffset = P.stateOffset st'})
+  case res of
+   Right a -> return a
+   Left (P.ParseErrorBundle errs _) ->
+    case NonEmpty.head errs of
+     P.TrivialError _o us es -> P.failure us es
+     P.FancyError _o es -> P.fancyFailure es
+
+-- * Class 'DecodeText'
+class DecodeText a where
+  decodeText :: P.Parsec Void TL.Text a
+instance DecodeText String where
+  decodeText = TL.unpack . fst <$>
+    P.match (P.skipMany P.anySingle)
+instance DecodeText Text.Text where
+  decodeText = TL.toStrict . fst <$>
+    P.match (P.skipMany P.anySingle)
+instance DecodeText TL.Text where
+  decodeText = fst <$>
+    P.match (P.skipMany P.anySingle)
+instance DecodeText Bool where
+  decodeText =
+    False <$ (P.string "false" <|> P.string "0") <|>
+    True  <$ (P.string "true"  <|> P.string "1")
+instance DecodeText Integer where
+  decodeText = P.signed (return ()) P.decimal
+instance DecodeText Natural where
+  decodeText = P.optional (P.char '+') *> P.decimal
+
+-- * Megaparsec adaptations
+-- | Rewrite 'P.parseErrorTextPretty' to keep 'Ord' of 'node's.
+parseErrorTextPretty ::
+ P.ShowErrorComponent err =>
+ P.ParseError (ReadStream FileSourced) err -> String
+parseErrorTextPretty (P.TrivialError o us ps) =
+  if isNothing us && Set.null ps
+  then "unknown parse error\n"
+  else
+    (case us of
+     Just P.Tokens{} -> ""
+     _ ->
+      -- FIXME: this is not informative enough,
+      -- but P.EndOfInput can not carry a source location,
+      -- and retraversing the XML tree cannot be done
+      -- exactly as the parser did only knowing the Offset,
+      -- because of attributes being permutable.
+      "node #"<>show o<>"\n"
+    ) <>
+    messageItemsPretty "unexpected "
+     (showErrorItem px <$> maybeToList us) <>
+    messageItemsPretty "expecting "
+     (showErrorItem px <$> Set.toAscList ps)
+  where px = Proxy :: Proxy s
+parseErrorTextPretty err = P.parseErrorTextPretty err
+
+messageItemsPretty :: String -> [String] -> String
+messageItemsPretty prefix ts
+ | null ts = ""
+ | otherwise = prefix <> orList ts <> "\n"
+
+orList :: IsString s => Monoid s => [s] -> s
+orList [] = mempty
+orList [x] = x
+orList [x,y] = x <> " or " <> y
+orList xs = mconcat (List.intersperse ", " (List.init xs)) <> ", or " <> List.last xs
+
+showErrorItem ::
+ (s ~ ReadStream (Sourced (FileSource Offset))) =>
+ Proxy s -> P.ErrorItem (P.Token s) -> String
+showErrorItem px = \case
+ P.Tokens ts   -> P.showTokens px ts
+ P.Label label -> NonEmpty.toList label
+ P.EndOfInput  -> "end-of-node"
diff --git a/src/Symantic/XML/RelaxNG.hs b/src/Symantic/XML/RelaxNG.hs
new file mode 100644 (file)
index 0000000..08c6f22
--- /dev/null
@@ -0,0 +1,7 @@
+module Symantic.XML.RelaxNG
+ ( module Symantic.XML.RelaxNG.Language
+ , module Symantic.XML.RelaxNG.Compact.Write
+ ) where
+
+import Symantic.XML.RelaxNG.Language
+import Symantic.XML.RelaxNG.Compact.Write
diff --git a/src/Symantic/XML/RelaxNG/Compact/Write.hs b/src/Symantic/XML/RelaxNG/Compact/Write.hs
new file mode 100644 (file)
index 0000000..6245eb8
--- /dev/null
@@ -0,0 +1,429 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Symantic.XML.RelaxNG.Compact.Write where
+
+import Control.Applicative (Applicative(..), Alternative(..))
+import Control.Monad (forM)
+import Data.Bool
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
+import Data.Function (($), (.), id, const)
+import Data.Functor ((<$>))
+import Data.Int (Int)
+import Data.Maybe (Maybe(..), maybe, catMaybes, isNothing)
+import Data.Monoid (Monoid(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (IsString(..), String)
+import Numeric.Natural (Natural)
+import Prelude (Integer)
+import qualified Control.Monad.Trans.State.Strict as S
+import qualified Data.HashMap.Strict as HM
+import qualified Data.HashSet as HS
+import qualified Data.List as List
+import qualified Data.Map.Strict as Map
+import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TLB
+
+import Symantic.Base.Fixity
+import Symantic.XML.Language
+import Symantic.XML.RelaxNG.Language
+
+-- | Get textual rendition of given 'RNCWriteSyn'.
+writeRNC :: RNCWriteSyn a k -> TL.Text
+writeRNC = TLB.toLazyText . runRNCWriteSyn
+
+-- | Get textual rendition of given 'RNCWriteSyn'.
+runRNCWriteSyn :: RNCWriteSyn a k -> TLB.Builder
+runRNCWriteSyn RNCWriteSyn{..} =
+  mconcat $
+  List.concat
+   [ [ "default namespace = \""<>textify (namespaces_default rncWriteInh_namespaces)<>"\"\n"
+     | not $ TL.null $ unNamespace (namespaces_default rncWriteInh_namespaces)
+     ]
+   , [ "namespace "<>textify p<>" = \""<>textify n<>"\"\n"
+     | (Namespace n, NCName p) <-
+      HM.toList (namespaces_prefixes rncWriteInh_namespaces)
+     ]
+   , Map.foldrWithKey
+     (\n v -> ((textify n<>" = "<>v<>"\n") :)) []
+     defs
+   ]
+  where
+  RNCWriteState{..} = rncWriteSyn_state $ RNCWriteState mempty mempty
+  defs :: Map.Map DefineName TLB.Builder
+  defs = Map.mapMaybe ($ inh) rncWriteState_defines
+  inh = RNCWriteInh
+   { rncWriteInh_namespaces
+   , rncWriteInh_op = (infixN0, SideL)
+   , rncWriteInh_pair = pairParen
+   }
+  rncWriteInh_namespaces :: Namespaces NCName
+  rncWriteInh_namespaces = rncWriteState_namespaces
+   { namespaces_prefixes =
+    (`S.evalState` HS.empty) $
+      forM prefixByNamespace $ \mp -> do
+        usedPrefixes <- S.get
+        let
+         freshPrefix = maybe
+           (freshNCName usedPrefixes)
+           (freshifyNCName usedPrefixes)
+           mp
+        S.modify' $ HS.insert freshPrefix
+        pure freshPrefix
+   }
+  prefixByNamespace :: HM.HashMap Namespace (Maybe NCName)
+  prefixByNamespace =
+    -- Add default prefixes if their 'Namespace' is used.
+    HM.union
+     (HM.intersectionWith (<|>)
+       (namespaces_prefixes rncWriteState_namespaces)
+       (Just <$> namespaces_prefixes defaultNamespaces)) $
+    namespaces_prefixes rncWriteState_namespaces
+
+-- * Type 'RNCWriteState'
+-- | Chained values.
+data RNCWriteState
+ =   RNCWriteState
+ {   rncWriteState_namespaces :: Namespaces (Maybe NCName)
+     -- ^ The 'Namespaces' used throughout the 'RelaxNG' schema.
+ ,   rncWriteState_defines    :: Map.Map DefineName (RNCWriteInh -> Maybe TLB.Builder)
+     -- ^ Used to avoid infinite recursion,
+     -- by looking up the 'DefineName' of 'define'.
+ }
+
+-- * Type 'RNCWriteSyn'
+-- | Synthetized (bottom-up) values.
+data RNCWriteSyn a k
+ =   RNCWriteSyn
+ {   rncWriteSyn_state  :: Chained RNCWriteState
+ ,   rncWriteSyn_schema :: RNCWriteInh -> Maybe TLB.Builder
+ }
+instance IsString (RNCWriteSyn a k) where
+  fromString s = RNCWriteSyn
+   { rncWriteSyn_state = id
+   , rncWriteSyn_schema = const $
+    if List.null s then Nothing
+    else Just (textify s)
+   }
+
+-- | Like the @State st ()@ monad, but without @()@.
+-- The name comme from chained-attribute from Attribute Grammar.
+type Chained a = a -> a
+
+coerceRNCWriteSyn :: RNCWriteSyn a k -> RNCWriteSyn a' k'
+coerceRNCWriteSyn RNCWriteSyn{..} = RNCWriteSyn{..}
+{-# INLINE coerceRNCWriteSyn #-}
+
+pairRNCWriteInh ::
+ Semigroup s => IsString s =>
+ RNCWriteInh -> Infix -> Maybe s -> Maybe s
+pairRNCWriteInh inh op s =
+  if isPairNeeded (rncWriteInh_op inh) op
+  then Just (fromString o<>" ")<>s<>Just (" "<>fromString c)
+  else s
+  where (o,c) = rncWriteInh_pair inh
+
+-- ** Type 'RNCWriteInh'
+-- Inherited (top-down) values.
+data RNCWriteInh
+ =   RNCWriteInh
+ {   rncWriteInh_namespaces :: Namespaces NCName
+ ,   rncWriteInh_op :: (Infix, Side)
+ ,   rncWriteInh_pair :: Pair
+ }
+
+instance Emptyable RNCWriteSyn where
+  empty = "empty"
+instance Unitable RNCWriteSyn where
+  unit = ""
+instance Voidable RNCWriteSyn where
+  void _a = coerceRNCWriteSyn
+instance Constant RNCWriteSyn where
+  constant _a = ""
+instance Composable RNCWriteSyn where
+  x <.> y = RNCWriteSyn
+   (rncWriteSyn_state x . rncWriteSyn_state y) $ \inh ->
+    let
+     inh' side = inh
+      { rncWriteInh_op   = (op, side)
+      , rncWriteInh_pair = pairParen
+      } in
+    case rncWriteSyn_schema x (inh' SideL) of
+     Nothing -> rncWriteSyn_schema y (inh' SideR)
+     Just xw ->
+      case rncWriteSyn_schema y (inh' SideR) of
+       Nothing -> Just xw
+       Just yw ->
+        pairRNCWriteInh inh op $
+          Just $ xw <> ", " <> yw
+    where
+    op = infixB SideL 2
+instance Tupable RNCWriteSyn where
+  x <:> y = coerceRNCWriteSyn x <.> coerceRNCWriteSyn y
+instance Eitherable RNCWriteSyn where
+  x <+> y = RNCWriteSyn
+   (rncWriteSyn_state x . rncWriteSyn_state y) $ \inh ->
+    pairRNCWriteInh inh op $
+    rncWriteSyn_schema x inh
+     { rncWriteInh_op   = (op, SideL)
+     , rncWriteInh_pair = pairParen
+     } <>
+    Just " | " <>
+    rncWriteSyn_schema y inh
+     { rncWriteInh_op   = (op, SideR)
+     , rncWriteInh_pair = pairParen
+     }
+    where op = infixB SideL 3
+instance Optionable RNCWriteSyn where
+  option = coerceRNCWriteSyn . optional . coerceRNCWriteSyn
+  optional w = w{ rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh op $
+    rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (op, SideL)
+     , rncWriteInh_pair = pairParen
+     } <> Just "?"
+    }
+    where op = infixN 9
+instance Dimapable RNCWriteSyn where
+  dimap _a2b _b2a = coerceRNCWriteSyn
+instance Dicurryable RNCWriteSyn where
+  dicurry _args _constr _destr = coerceRNCWriteSyn
+instance Repeatable RNCWriteSyn where
+  many0 w = w{ rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh op $
+    rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (op, SideL)
+     , rncWriteInh_pair = pairParen
+     } <> Just "*"
+    }
+    where op = infixN 9
+  many1 w = w{ rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh op $
+    rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (op, SideL)
+     , rncWriteInh_pair = pairParen
+     } <> Just "+"
+    }
+    where op = infixN 9
+instance Textable RNCWriteSyn where
+  type TextConstraint RNCWriteSyn a = RNCText a
+  text :: forall a k. TextConstraint RNCWriteSyn a => RNCWriteSyn (a -> k) k
+  text = RNCWriteSyn
+   { rncWriteSyn_state = \st ->
+    case HM.lookup
+     (qNameSpace (rncText_qname @a))
+     (namespaces_prefixes (rncWriteState_namespaces st)) of
+     Just{} -> st
+     Nothing ->
+      let ns = qNameSpace (rncText_qname @a) in
+      if ns == xmlns_empty then st else st
+       { rncWriteState_namespaces = (rncWriteState_namespaces st)
+        { namespaces_prefixes =
+        HM.insertWith (<|>) ns Nothing $
+        namespaces_prefixes (rncWriteState_namespaces st) } }
+   , rncWriteSyn_schema = \inh ->
+    let n = rncText_qname @a in
+    let t = if TL.null (unNamespace (qNameSpace n))
+            then textify (qNameLocal n)
+            else textify (prefixifyQName (rncWriteInh_namespaces inh) n)
+    in if null (rncText_params @a)
+    then Just t
+    else
+      pairRNCWriteInh inh (infixN 8) $
+      Just $
+      t<>" {"<>Map.foldMapWithKey
+       (\k v -> " "<>textify k<>" = \""<>textify v<>"\"")
+       (rncText_params @a)<>" }"
+   }
+instance XML RNCWriteSyn where
+  namespace mp ns = RNCWriteSyn
+   { rncWriteSyn_state = \st -> st
+    { rncWriteState_namespaces =
+      let nss = rncWriteState_namespaces st in
+      Namespaces
+       { namespaces_prefixes =
+        HM.insertWith (<|>) ns mp (namespaces_prefixes nss)
+       , namespaces_default =
+        if isNothing mp
+        then ns
+        else namespaces_default nss
+       }
+    }
+   , rncWriteSyn_schema = const Nothing
+   }
+  element n w = w
+   { rncWriteSyn_state = \st ->
+    rncWriteSyn_state w $ st
+     { rncWriteState_namespaces = (rncWriteState_namespaces st)
+       { namespaces_prefixes =
+        -- Insert this 'qNameSpace' even if this is the default namespace,
+        -- because the default namespace here may not end up
+        -- being the global default namespace
+        -- if there is a default 'namespace' declaration after this one.
+        -- at worse this will just add a superfluous ns# declaration
+        -- in the schema rendering.
+        HM.insertWith (<|>) (qNameSpace n) Nothing
+         (namespaces_prefixes (rncWriteState_namespaces st)) } }
+   , rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh (infixN 8) $
+    Just ("element "
+     <> textify (prefixifyQName (rncWriteInh_namespaces inh) n)
+     <> " {")
+    <> rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (infixN0, SideR)
+     , rncWriteInh_pair = pairBrace
+     }
+    <> Just "}"
+   }
+  attribute n w = w
+   { rncWriteSyn_state = \st ->
+    rncWriteSyn_state w $
+    if qNameSpace n == xmlns_empty then st else st
+     { rncWriteState_namespaces = (rncWriteState_namespaces st)
+       { namespaces_prefixes =
+        HM.insertWith (<|>) (qNameSpace n) Nothing
+         (namespaces_prefixes (rncWriteState_namespaces st)) } }
+   , rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh (infixN 8) $
+    Just ("attribute "
+     -- The namespace name for an unprefixed attribute name always has no value.
+     <> textify (prefixifyQName (rncWriteInh_namespaces inh){namespaces_default=xmlns_empty} n)
+     <> " {")
+    <> rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (infixN0, SideR)
+     , rncWriteInh_pair = pairBrace
+     }
+    <> Just "}"
+   }
+  literal lit = RNCWriteSyn
+   { rncWriteSyn_state = id
+   , rncWriteSyn_schema = \_inh -> Just ("\""<>textify lit<>"\"")
+   }
+  pi _n   = ""
+  comment = ""
+  cdata   = ""
+instance Definable RNCWriteSyn where
+  define n w = w
+   { rncWriteSyn_state = \st ->
+    let defs = rncWriteState_defines st in
+    case Map.lookup n defs of
+     Nothing ->
+      rncWriteSyn_state w $ st
+       { rncWriteState_defines =
+        Map.insert n (rncWriteSyn_schema w) defs
+       }
+     Just{} -> st
+   , rncWriteSyn_schema = const $ Just $ textify n
+   }
+instance Permutable RNCWriteSyn where
+  type Permutation RNCWriteSyn = RNCWriteSynPerm
+  permutable (RNCWriteSynPerm ps) = RNCWriteSyn
+   { rncWriteSyn_state = List.foldl' (.) id (rncWriteSyn_state <$> ps)
+   , rncWriteSyn_schema = case ps of
+     [] -> const Nothing
+     _ -> \inh ->
+      case
+        List.intersperse " & " $
+        catMaybes $ (<$> ps) $ \w ->
+          rncWriteSyn_schema w inh{rncWriteInh_op=(op, SideL)}
+      of
+       [] -> Nothing
+       [x] -> Just x
+       xs -> pairRNCWriteInh inh op $ Just $ mconcat xs
+   }
+    where op = infixR 3
+  perm = RNCWriteSynPerm . pure
+  noPerm = RNCWriteSynPerm []
+  permWithDefault _def p = RNCWriteSynPerm
+   [coerceRNCWriteSyn (optional p)]
+instance RelaxNG RNCWriteSyn where
+  elementMatch nc w = w
+   { rncWriteSyn_state = \st ->
+    rncWriteSyn_state w $ st
+     { rncWriteState_namespaces = (rncWriteState_namespaces st)
+       { namespaces_prefixes =
+        namespacesNameClass nc <>
+        namespaces_prefixes (rncWriteState_namespaces st)
+       } }
+   , rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh (infixN 8) $
+    Just ("element "
+     <> textify (rncWriteInh_namespaces inh, (infixN0,SideL), nc)
+     <> " ")
+    <> rncWriteSyn_schema w inh
+     { rncWriteInh_op = (infixN 9, SideR)
+     , rncWriteInh_pair = pairBrace
+     }
+   }
+  attributeMatch nc w = w
+   { rncWriteSyn_state = \st ->
+    let nss = HM.delete xmlns_empty $ namespacesNameClass nc in
+    rncWriteSyn_state w $
+    if null nss then st else st
+     { rncWriteState_namespaces = (rncWriteState_namespaces st)
+       { namespaces_prefixes =
+        HM.unionWith (<|>) nss $
+        namespaces_prefixes (rncWriteState_namespaces st)
+       } }
+   , rncWriteSyn_schema = \inh ->
+    pairRNCWriteInh inh (infixN 8) $
+    Just ("attribute "
+     <> textify ( (rncWriteInh_namespaces inh){namespaces_default=xmlns_empty}
+              , (infixN0,SideL)
+              , nc )
+     <> " ")
+    <> rncWriteSyn_schema w inh
+     { rncWriteInh_op   = (infixN 9, SideR)
+     , rncWriteInh_pair = pairBrace
+     }
+   }
+
+-- ** Type 'RNCWriteSynPerm'
+newtype RNCWriteSynPerm a k
+ =      RNCWriteSynPerm
+ {      rncWriteSynPerm_alternatives :: [RNCWriteSyn a k]
+        -- ^ Collect alternatives for rendering
+        -- them all at once in 'runPermutation'.
+ }
+instance Composable RNCWriteSynPerm where
+  RNCWriteSynPerm x <.> RNCWriteSynPerm y =
+    RNCWriteSynPerm $
+      (coerceRNCWriteSyn <$> x) <>
+      (coerceRNCWriteSyn <$> y)
+instance Dimapable RNCWriteSynPerm where
+  dimap _a2b _b2a (RNCWriteSynPerm x) =
+    RNCWriteSynPerm (coerceRNCWriteSyn <$> x)
+instance Tupable RNCWriteSynPerm where
+  RNCWriteSynPerm x <:> RNCWriteSynPerm y =
+    RNCWriteSynPerm $
+      (coerceRNCWriteSyn <$> x) <>
+      (coerceRNCWriteSyn <$> y)
+instance Definable RNCWriteSynPerm where
+  define n (RNCWriteSynPerm ps) =
+    RNCWriteSynPerm $ pure $
+      coerceRNCWriteSyn $ define n $
+        permutable $ RNCWriteSynPerm $
+          coerceRNCWriteSyn <$> ps
+
+-- * Class 'RNCText'
+class RNCText a where
+  rncText_qname  :: QName
+  rncText_params :: Map.Map TL.Text TL.Text
+  rncText_params = mempty
+instance RNCText String where
+  rncText_qname = QName (Namespace "") "text"
+instance RNCText Text.Text where
+  rncText_qname = QName (Namespace "") "text"
+instance RNCText TL.Text where
+  rncText_qname = QName (Namespace "") "text"
+instance RNCText Bool where
+  rncText_qname = QName xmlns_xsd "boolean"
+instance RNCText Int where
+  rncText_qname = QName xmlns_xsd "int"
+instance RNCText Integer where
+  rncText_qname = QName xmlns_xsd "integer"
+instance RNCText Natural where
+  rncText_qname = QName xmlns_xsd "nonNegativeInteger"
diff --git a/src/Symantic/XML/RelaxNG/Language.hs b/src/Symantic/XML/RelaxNG/Language.hs
new file mode 100644 (file)
index 0000000..b511d84
--- /dev/null
@@ -0,0 +1,119 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Symantic.XML.RelaxNG.Language where
+
+import Data.Bool
+import Data.Eq (Eq(..))
+import Data.Function (($), (.))
+import Data.Maybe (Maybe(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (String, IsString(..))
+import Prelude (error)
+import Text.Show (Show(..))
+import qualified Data.List as List
+import qualified Data.HashMap.Strict as HM
+
+import Symantic.Base.Fixity
+import Symantic.XML.Language
+
+-- * Class 'RelaxNG'
+class
+ ( XML repr
+ , Permutable repr
+ , Definable repr
+ ) => RelaxNG repr where
+  default elementMatch ::
+                  Transformable repr =>
+                  RelaxNG (UnTrans repr) =>
+                  NameClass -> repr a k -> repr (QName -> a) k
+  -- | Like 'element' but with a matching pattern
+  -- instead of a specific 'QName'.
+  elementMatch :: NameClass -> repr a k -> repr (QName -> a) k
+  elementMatch nc = noTrans . elementMatch nc . unTrans
+  default attributeMatch ::
+                  Transformable repr =>
+                  RelaxNG (UnTrans repr) =>
+                  NameClass -> repr a k -> repr (QName -> a) k
+  -- | Like 'attribute' but with a matching pattern
+  -- instead of a specific 'QName'.
+  attributeMatch :: NameClass -> repr a k -> repr (QName -> a) k
+  attributeMatch nc = noTrans . attributeMatch nc . unTrans
+
+-- * Type 'Definable'
+class Definable repr where
+  -- | @(define name expr)@ declares a rule named @(name)@
+  -- and matching the 'RelaxNG' schema @(expr)@.
+  --
+  -- Useful for rendering the 'RelaxNG' schema,
+  -- and necessary to avoid infinite recursion when
+  -- printing a 'RelaxNG' schema calling itself recursively.
+  --
+  -- WARNING: 'DefineName's must be unique inside
+  -- a whole 'RelaxNG' schema.
+  define :: DefineName -> repr a k -> repr a k
+  default define ::
+   Transformable repr => RelaxNG (UnTrans repr) =>
+   DefineName -> repr f k -> repr f k
+  define n = noTrans . define n . unTrans
+
+-- ** Type 'DefineName'
+type DefineName = String
+
+-- * Type 'NameClass'
+data NameClass
+ =   NameClass_Any
+ |   (:::) Namespace NCName
+ |   (:*) Namespace
+ |   (:-:) NameClass NameClass
+ |   (:|:) NameClass NameClass
+
+infix 9 :::
+infixr 2 :|:
+infixl 6 :-:
+
+(*:*) :: NameClass
+(*:*) = NameClass_Any
+
+-- | @('matchNameClass' nc q)@ returns 'True' iif. the 'NameClass' @(nc)@ matches the 'QName' @(q)@.
+matchNameClass :: NameClass -> QName -> Bool
+matchNameClass NameClass_Any _q = True
+matchNameClass (ns:::nl) q = qNameSpace q == ns && qNameLocal q == nl
+matchNameClass ((:*) ns) q = qNameSpace q == ns
+matchNameClass (x:|:y) q = matchNameClass x q || matchNameClass y q
+matchNameClass (x:-:y) q = matchNameClass x q && not (matchNameClass y q)
+
+-- | Return the namespaces used by the given 'NameClass'
+namespacesNameClass :: NameClass -> HM.HashMap Namespace (Maybe NCName)
+namespacesNameClass = \case
+ NameClass_Any -> HM.empty
+ ns ::: _ -> HM.singleton ns Nothing
+ (:*) ns -> HM.singleton ns Nothing
+ x :|: y -> namespacesNameClass x <> namespacesNameClass y
+ x :-: y -> namespacesNameClass x <> namespacesNameClass y
+
+-- | Only parses "*", "{some-namespace}*", or "{some-namespace}some-localname".
+instance IsString NameClass where
+  fromString = \case
+   "*" -> NameClass_Any
+   full@('{':rest) ->
+    case List.break (== '}') rest of
+     (_, "") -> error $ "Invalid XML Clark notation: "<>show full
+     (ns, "*") -> (:*) (fromString ns)
+     (ns, local) -> fromString ns ::: fromString (List.drop 1 local)
+   s -> let QName ns nl = fromString s in ns:::nl
+instance Textify (Namespaces NCName, (Infix,Side), NameClass) where
+  textify (nss,po,nc) = case nc of
+   NameClass_Any -> textify '*'
+   ns:::nl ->
+    textify (prefixifyQName nss (QName ns nl))
+   (:*) ns ->
+    case HM.lookup ns (namespaces_prefixes nss) of
+     Nothing -> "{"<>textify ns<>"}*"
+     Just p -> textify p <> ":*"
+   x :|: y -> pairIfNeeded pairParen po op $
+    textify (nss,(op,SideL),x) <> " | " <> textify (nss,(op,SideR),y)
+    where op = infixR 2
+   x :-: y ->
+    pairIfNeeded pairParen po op $
+    textify (nss,(op,SideL),x) <> " - " <> textify (nss,(op,SideR),y)
+    where op = infixL 6
diff --git a/src/Symantic/XML/Text.hs b/src/Symantic/XML/Text.hs
new file mode 100644 (file)
index 0000000..b5101b1
--- /dev/null
@@ -0,0 +1,164 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE StrictData #-}
+module Symantic.XML.Text where
+
+import Data.Bool
+import Data.Char (Char)
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
+import Data.Function (($), (.))
+import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Semigroup (Semigroup(..))
+import Data.Sequence (Seq)
+import Data.String (IsString(..), String)
+import Text.Show (Show(..))
+import qualified Data.Char as Char
+import qualified Data.List as List
+import qualified Data.Sequence as Seq
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TLB
+
+import Symantic.XML.Namespace
+
+-- * Type 'Escaped'
+-- | 'EscapedText' lexemes.
+data Escaped
+ =   EscapedPlain     TL.Text
+ |   EscapedEntityRef EntityRef
+ |   EscapedCharRef   CharRef
+ deriving (Eq, Ord, Show)
+
+-- ** Type 'EntityRef'
+data EntityRef
+ =   EntityRef
+ {   entityRef_name  :: NCName
+ ,   entityRef_value :: TL.Text
+ } deriving (Eq, Ord, Show)
+
+entityRef_lt,
+ entityRef_gt,
+ entityRef_amp,
+ entityRef_quot,
+ entityRef_apos :: EntityRef
+entityRef_lt   = EntityRef (NCName "lt") "<"
+entityRef_gt   = EntityRef (NCName "gt") ">"
+entityRef_amp  = EntityRef (NCName "amp") "&"
+entityRef_quot = EntityRef (NCName "quot") "\""
+entityRef_apos = EntityRef (NCName "apos") "'"
+
+-- ** Type 'CharRef'
+newtype CharRef = CharRef Char
+ deriving (Eq, Ord, Show)
+
+-- * Type 'EscapedText'
+newtype EscapedText = EscapedText (Seq Escaped)
+ deriving (Eq, Ord, Show)
+
+instance IsString EscapedText where
+  fromString = escapeText . fromString
+
+unEscapedText :: EscapedText -> Seq Escaped
+unEscapedText (EscapedText et) = et
+{-# INLINE unEscapedText #-}
+
+escapeText :: TL.Text -> EscapedText
+escapeText s =
+  EscapedText $
+  -- Add '>' to escape "]]>" without adding a 'TL.replace'.
+  case TL.span (`List.notElem` ("<&>"::String)) s of
+   (t, r) | TL.null t -> escape r
+          | otherwise -> EscapedPlain t Seq.<| escape r
+  where
+  escape t = case TL.uncons t of
+   Nothing -> mempty
+   Just (c, cs) -> escapeTextChar c Seq.<| et
+     where EscapedText et = escapeText cs
+
+escapeTextChar :: Char -> Escaped
+escapeTextChar = \case
+ '<'  -> EscapedEntityRef entityRef_lt
+ '&'  -> EscapedEntityRef entityRef_amp
+  -- Add '>' to escape "]]>".
+ '>'  -> EscapedEntityRef entityRef_gt
+ c    -> EscapedPlain $ TL.singleton c
+
+unescapeText :: EscapedText -> TL.Text
+unescapeText (EscapedText et) = (`foldMap` et) $ \case
+ EscapedPlain t -> t
+ EscapedEntityRef EntityRef{..} -> entityRef_value
+ EscapedCharRef (CharRef c) -> TL.singleton c
+
+-- * Type 'EscapedAttr'
+newtype EscapedAttr = EscapedAttr (Seq Escaped)
+ deriving (Eq, Ord, Show)
+
+instance IsString EscapedAttr where
+  fromString = escapeAttr . fromString
+
+unEscapedAttr :: EscapedAttr -> Seq Escaped
+unEscapedAttr (EscapedAttr et) = et
+{-# INLINE unEscapedAttr #-}
+
+escapeAttr :: TL.Text -> EscapedAttr
+escapeAttr s =
+  EscapedAttr $
+  case TL.span (`List.notElem` ("<&\""::String)) s of
+   (t, r) | TL.null t -> escape r
+          | otherwise -> EscapedPlain t Seq.<| escape r
+  where
+  escape t = case TL.uncons t of
+   Nothing -> mempty
+   Just (c, cs) -> escapeAttrChar c Seq.<| et
+     where EscapedAttr et = escapeAttr cs
+
+escapeAttrChar :: Char -> Escaped
+escapeAttrChar = \case
+ '<'  -> EscapedEntityRef entityRef_lt
+ '&'  -> EscapedEntityRef entityRef_amp
+ -- Remove '\'' because 'textifyAttr' uses '"' for quoting.
+ -- '\'' -> EscapedEntityRef entityRef_apos
+ '"'  -> EscapedEntityRef entityRef_quot
+ c    -> EscapedPlain $ TL.singleton c
+
+unescapeAttr :: EscapedAttr -> TL.Text
+unescapeAttr (EscapedAttr et) = unescapeText (EscapedText et)
+
+-- * Class 'Textify'
+class Textify a where
+  textify :: a -> TLB.Builder
+instance Textify Char.Char where
+  textify = TLB.singleton
+instance Textify String where
+  textify = TLB.fromString
+instance Textify TL.Text where
+  textify = TLB.fromLazyText
+instance Textify NCName where
+  textify = textify . unNCName
+instance Textify PName where
+  textify PName{..} =
+    case pNameSpace of
+     Nothing -> textify pNameLocal
+     Just p -> textify p<>":"<> textify pNameLocal
+instance Textify Namespace where
+  textify = textify . unNamespace
+instance Textify EntityRef where
+  textify EntityRef{..} = "&"<>textify entityRef_name<>";"
+instance Textify CharRef where
+  textify (CharRef c) = "&#"<>textify (show (Char.ord c))<>";"
+instance Textify EscapedText where
+  textify (EscapedText et) = (`foldMap` et) $ \case
+   EscapedPlain     t -> textify t
+   EscapedEntityRef r -> textify r
+   EscapedCharRef   r -> textify r
+instance Textify EscapedAttr where
+  textify (EscapedAttr et) = "\""<>txt<>"\""
+    where
+    txt = (`foldMap` et) $ \case
+     EscapedPlain     t -> textify t
+     EscapedEntityRef r -> textify r
+     EscapedCharRef   r -> textify r
+
+textifyAttr :: PName -> EscapedAttr -> TLB.Builder
+textifyAttr n v = " "<>textify n<>"="<>textify v
diff --git a/src/Symantic/XML/Tree.hs b/src/Symantic/XML/Tree.hs
new file mode 100644 (file)
index 0000000..3f73b6d
--- /dev/null
@@ -0,0 +1,11 @@
+module Symantic.XML.Tree
+ ( module Symantic.XML.Tree.Source
+ , module Symantic.XML.Tree.Data
+ , module Symantic.XML.Tree.Read
+ , module Symantic.XML.Tree.Write
+ ) where
+
+import Symantic.XML.Tree.Source
+import Symantic.XML.Tree.Data
+import Symantic.XML.Tree.Read
+import Symantic.XML.Tree.Write
diff --git a/src/Symantic/XML/Tree/Data.hs b/src/Symantic/XML/Tree/Data.hs
new file mode 100644 (file)
index 0000000..e40f5ac
--- /dev/null
@@ -0,0 +1,197 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE StrictData #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Symantic.XML.Tree.Data
+ ( module Symantic.XML.Tree.Data
+ , TS.unTree
+ , TS.subTrees
+ ) where
+
+import Control.Applicative (Applicative(..))
+import Data.Bool
+import Data.Either (Either(..))
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
+import Data.Function (($), id)
+import Data.Functor ((<$>))
+import Data.Functor.Identity (Identity(..))
+import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Semigroup (Semigroup(..))
+import Prelude (error)
+import Text.Show (Show(..))
+import qualified Data.HashMap.Strict as HM
+import qualified Data.Sequence as Seq
+import qualified Data.Text.Lazy as TL
+import qualified Data.TreeSeq.Strict as TS
+
+import Symantic.Base
+import Symantic.XML.Language
+import Symantic.XML.RelaxNG.Language
+import Symantic.XML.Write
+import Symantic.XML.Tree.Source
+
+-- * Type 'Tree'
+type Tree src = TS.Tree (src (Node (src EscapedAttr)))
+
+-- ** Type 'Trees'
+type Trees src = TS.Trees (src (Node (src EscapedAttr)))
+
+pattern Tree0 :: a -> TS.Tree a
+pattern Tree0 a <- TS.Tree a (null -> True)
+  where Tree0 a = TS.Tree a Seq.empty
+
+-- ** Type 'Node'
+data Node attr
+   = NodeElem    QName (HM.HashMap QName attr) -- ^ Node.
+   | NodePI      PName TL.Text -- ^ Leaf (except for @<?xml?>@ which has 'NodePI' children.
+   | NodeText    EscapedText   -- ^ Leaf.
+   | NodeComment TL.Text       -- ^ Leaf.
+   | NodeCDATA   TL.Text       -- ^ Leaf.
+   deriving (Eq, Ord, Show)
+
+-- * Type 'TreeData'
+newtype TreeData params k
+ =      TreeData
+ {    unTreeData :: ( HM.HashMap QName (Identity EscapedAttr) ->
+                      TL.Text ->
+                      Trees Identity -> k
+                    ) -> params }
+
+tree :: TreeData callers (Trees Identity) -> callers
+tree (TreeData callers) = callers (\_as _txt ts -> ts)
+
+type SourcedTree  src = Tree  (Sourced src)
+type SourcedTrees src = Trees (Sourced src)
+type FileSourcedTree  = SourcedTree  (FileSource Offset)
+type FileSourcedTrees = SourcedTrees (FileSource Offset)
+
+-- | Unify two 'Trees', merging border 'NodeText's if any.
+union ::
+ Semigroup (Sourced src EscapedText) =>
+ SourcedTrees src -> SourcedTrees src -> SourcedTrees src
+union x y =
+  case (Seq.viewr x, Seq.viewl y) of
+   (xs Seq.:> x0, y0 Seq.:< ys) ->
+    case (x0,y0) of
+     (  Tree0 (Sourced sx (NodeText tx))
+      , Tree0 (Sourced sy (NodeText ty)) ) ->
+      xs `union`
+      Seq.singleton (Tree0 $ (NodeText <$>) $
+        Sourced sx tx <> Sourced sy ty) `union`
+      ys
+     _ -> x <> y
+   (Seq.EmptyR, _) -> y
+   (_, Seq.EmptyL) -> x
+
+unions ::
+ Semigroup (Sourced src EscapedText) =>
+ Foldable f => f (SourcedTrees src) -> SourcedTrees src
+unions = foldl' union mempty
+
+instance Emptyable TreeData where
+  empty = TreeData (\k -> k mempty mempty mempty)
+instance Unitable TreeData where
+  unit = TreeData (\k () -> k mempty mempty mempty)
+instance Voidable TreeData where
+  void a (TreeData x) = TreeData (`x` a)
+instance Dimapable TreeData where
+  dimap _a2b b2a (TreeData x) = TreeData $ \k b ->
+    x k (b2a b)
+instance Dicurryable TreeData where
+  dicurry (_::proxy args) _construct destruct (TreeData x) = TreeData $ \k r ->
+    uncurryN @args (x k) (destruct r)
+instance Composable TreeData where
+  TreeData x <.> TreeData y = TreeData $ \k ->
+    x (\ax vx tx -> y (\ay vy ty -> k (ax<>ay) (vx<>vy) (tx<>ty)))
+instance Tupable TreeData where
+  TreeData x <:> TreeData y = TreeData $ \k (a,b) ->
+    x (\ax vx tx -> y (\ay vy ty -> k (ax<>ay) (vx<>vy) (tx<>ty)) b) a
+instance Eitherable TreeData where
+  TreeData x <+> TreeData y = TreeData $ \k -> \case
+   Left  a -> x k a
+   Right b -> y k b
+instance Constant TreeData where
+  constant _a = TreeData $ \k _a -> k mempty mempty mempty
+instance Optionable TreeData where
+  option = id
+  optional (TreeData x) = TreeData $ \k ->
+    \case
+     Nothing -> k mempty mempty mempty
+     Just a -> x k a
+{-
+instance Routable TreeData where
+  TreeData x <!> TreeData y = TreeData $ \k ->
+    x k :!: y k
+-}
+instance Repeatable TreeData where
+  many0 (TreeData x) = TreeData $ \k -> \case
+   [] -> k mempty mempty mempty
+   a:as -> x (\ax vx tx ->
+    unTreeData (many0 (TreeData x))
+     (\aas vas tas -> k (ax<>aas) (vx<>vas) (tx<>tas)) as) a
+  many1 (TreeData x) = TreeData $ \k -> \case
+   [] -> k mempty mempty mempty
+   a:as -> x (\ax vx tx ->
+    unTreeData (many1 (TreeData x))
+     (\aas vas tas -> k (ax<>aas) (vx<>vas) (tx<>tas)) as) a
+instance Textable TreeData where
+  type TextConstraint TreeData a = EncodeText a
+  text = TreeData $ \k v ->
+    let t = encodeText v in
+    k mempty t $ pure $
+      TS.Tree (Identity (NodeText (escapeText t))) mempty
+instance XML TreeData where
+  namespace _nm _ns = empty
+  element n (TreeData x) = TreeData $ \k ->
+    x $ \as _txt ts ->
+      k mempty mempty $ pure $
+        TS.Tree (Identity (NodeElem n as)) ts
+  attribute n (TreeData x) = TreeData $ \k ->
+    x $ \as txt _ts ->
+      k (HM.insert n (Identity (escapeAttr txt)) as) mempty mempty
+  literal lit = TreeData $ \k ->
+    k mempty lit $ pure $
+      TS.Tree (Identity (NodeText (escapeText lit))) mempty
+  pi n = TreeData $ \k v ->
+    k mempty mempty $ pure $
+      TS.Tree (Identity (NodePI n v)) mempty
+  comment = TreeData $ \k v ->
+    k mempty mempty $ pure $
+      TS.Tree (Identity (NodeComment v)) mempty
+  cdata = TreeData $ \k v ->
+    k mempty mempty $ pure $
+      TS.Tree (Identity (NodeCDATA v)) mempty
+instance Permutable TreeData where
+  type Permutation TreeData = TreeDataPerm TreeData
+  permutable = unTreeDataPerm
+  perm = TreeDataPerm
+  noPerm = TreeDataPerm empty
+  permWithDefault _a = TreeDataPerm
+instance Definable TreeData where
+  define _n = id
+instance RelaxNG TreeData where
+  elementMatch nc x = TreeData $ \k n ->
+    if matchNameClass nc n
+    then error "elementMatch: given QName does not match expected NameClass"
+    else unTreeData (element n x) k
+  attributeMatch nc x = TreeData $ \k n ->
+    if matchNameClass nc n
+    then error "attributeMatch: given QName does not match expected NameClass"
+    else unTreeData (attribute n x) k
+
+-- ** Type 'TreeDataPerm'
+newtype TreeDataPerm repr xml k
+ =      TreeDataPerm
+ {    unTreeDataPerm :: repr xml k }
+instance Transformable (TreeDataPerm repr) where
+  type UnTrans (TreeDataPerm repr) = repr
+  noTrans = TreeDataPerm
+  unTrans = unTreeDataPerm
+instance Dimapable (TreeDataPerm TreeData)
+instance Composable (TreeDataPerm TreeData)
+instance Tupable (TreeDataPerm TreeData)
diff --git a/src/Symantic/XML/Tree/Read.hs b/src/Symantic/XML/Tree/Read.hs
new file mode 100644 (file)
index 0000000..b1976f8
--- /dev/null
@@ -0,0 +1,628 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Symantic.XML.Tree.Read where
+
+import Control.Arrow (left)
+import Control.Applicative (Applicative(..), Alternative(..))
+import Control.Monad (Monad(..), void, unless, forM)
+import Data.Bool
+import Data.Char (Char)
+import Data.Either (Either(..))
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
+import Data.Function (($), (.), const)
+import Data.Functor ((<$>), (<$))
+import Data.Maybe (Maybe(..), maybe, catMaybes)
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Semigroup (Semigroup(..))
+import Data.List.NonEmpty (NonEmpty(..))
+import Data.String (String, IsString(..))
+import Prelude (Num(..), Enum(..), Bounded(..), Integer, toInteger)
+import System.IO (FilePath, IO)
+import Text.Show (Show(..))
+import qualified Control.Exception as Exn
+import qualified Control.Monad.Trans.Reader as R
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Char as Char
+import qualified Data.Char.Properties.XMLCharProps as XC
+import qualified Data.HashMap.Strict as HM
+import qualified Data.List as List
+import qualified Data.Set as Set
+import qualified Data.Sequence as Seq
+import qualified Data.Text.Encoding.Error as TL
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
+import qualified Data.TreeSeq.Strict as TS
+import qualified System.IO.Error as IO
+import qualified Text.Megaparsec as P
+import qualified Text.Megaparsec.Char as P
+
+import Symantic.Base ()
+import Symantic.XML.Language hiding (void)
+import Symantic.XML.Tree.Source
+import Symantic.XML.Tree.Data
+
+readTree :: FilePath -> IO (Either String FileSourcedTrees)
+readTree path =
+  readUtf8 path >>= \case
+   Left err -> return $ Left $ show err
+   Right txt -> return $
+    case runReadTree path txt of
+     Right a -> Right a
+     Left err -> Left $ P.errorBundlePretty err
+
+runReadTree ::
+ FilePath -> TL.Text ->
+ Either (P.ParseErrorBundle TL.Text Error)
+        FileSourcedTrees
+runReadTree = P.runParser $ R.runReaderT p_document defaultReadTreeInh
+
+-- * Type 'ErrorRead'
+data ErrorRead
+ =   ErrorRead_IO IO.IOError
+ |   ErrorRead_Unicode TL.UnicodeException
+ deriving (Show)
+readUtf8 :: FilePath -> IO (Either ErrorRead TL.Text)
+readUtf8 path =
+  (left ErrorRead_Unicode . TL.decodeUtf8' <$> BSL.readFile path)
+  `Exn.catch` \e ->
+    if IO.isAlreadyInUseError e
+    || IO.isDoesNotExistError e
+    || IO.isPermissionError   e
+    then return $ Left $ ErrorRead_IO e
+    else IO.ioError e
+
+-- * Type 'ReadTree'
+-- | Convenient alias.
+type ReadTree e s a =
+ ReadTreeConstraints e s a =>
+ R.ReaderT ReadTreeInh (P.Parsec e s) a
+
+-- ** Type 'ReadTreeConstraints'
+type ReadTreeConstraints e s a =
+ ( P.Stream s
+ , P.Token s ~ Char
+ , Ord e
+ , IsString (P.Tokens s)
+ , P.ShowErrorComponent e
+ )
+
+-- ** Type 'ReadTreeInh'
+data ReadTreeInh
+ =   ReadTreeInh
+ {   readTreeInh_source     :: FileSource Offset
+ ,   readTreeInh_ns_scope   :: HM.HashMap NCName Namespace
+ ,   readTreeInh_ns_default :: Namespace
+ } deriving (Show)
+
+defaultReadTreeInh :: ReadTreeInh
+defaultReadTreeInh = ReadTreeInh
+ { readTreeInh_source = FileSource $ pure $
+  FileRange mempty mempty mempty
+ , readTreeInh_ns_scope = HM.fromList
+   [ ("xml"  , xmlns_xml)
+   , ("xmlns", xmlns_xmlns)
+   ]
+ , readTreeInh_ns_default = ""
+ }
+
+p_Offset :: ReadTree e s Offset
+p_Offset = Offset <$> P.getOffset
+{-# INLINE p_Offset #-}
+
+p_Sourced :: ReadTree e s a -> ReadTree e s (Sourced (FileSource Offset) a)
+p_Sourced pa = do
+  ReadTreeInh{readTreeInh_source} <- R.ask
+  b <- P.getParserState
+  let fileRange_path = P.sourceName $ P.pstateSourcePos $ P.statePosState b
+  let fileRange_begin = Offset $ P.stateOffset b
+  a <- pa
+  e <- P.getParserState
+  let fileRange_end = Offset $ P.stateOffset e
+  return $ Sourced (setSource FileRange{..} readTreeInh_source) a
+
+setSource :: FileRange pos -> FileSource pos -> FileSource pos
+setSource fileRange (FileSource (_curr:|next)) = FileSource (fileRange:|next)
+
+-- | Like 'p_Sourced' but uncoupled (through the use of 'p_SourcedEnd') for more flexibility.
+p_SourcedBegin :: ReadTree e s a -> ReadTree e s a
+p_SourcedBegin pa = do
+  b <- P.getParserState
+  let fileRange_path  = P.sourceName $ P.pstateSourcePos $ P.statePosState b
+  let fileRange_begin = Offset $ P.stateOffset b
+  let fileRange_end   = fileRange_begin
+  (`R.local` pa) $ \inh@ReadTreeInh{..} ->
+    inh{ readTreeInh_source = setSource FileRange{..} readTreeInh_source }
+
+-- | WARNING: only to be used within a 'p_SourcedBegin'.
+p_SourcedEnd :: ReadTree e s (a -> Sourced (FileSource Offset) a)
+p_SourcedEnd = do
+  ReadTreeInh{..} <- R.ask
+  e <- P.getParserState
+  let fileRange_end = Offset $ P.stateOffset e
+  return $ Sourced $
+     (\(FileSource (curr:|path)) -> FileSource (curr{fileRange_end}:|path))
+     readTreeInh_source
+
+-- * Type 'Error'
+data Error
+ =   Error_CharRef_invalid Integer
+     -- ^ Well-formedness constraint: Legal Character.
+     --
+     -- Characters referred to using character references MUST match the production for Char.
+ |   Error_EntityRef_unknown NCName
+     -- ^ Well-formedness constraint: Entity Declared
+     --
+     -- In a document without any DTD, a document with only an internal DTD
+     -- subset which contains no parameter entity references, or a document
+     -- with " standalone='yes' ", for an entity reference that does not occur
+     -- within the external subset or a parameter entity, the Name given in the
+     -- entity reference MUST match that in an entity declaration that does not
+     -- occur within the external subset or a parameter entity, except that
+     -- well-formed documents need not declare any of the following entities:
+     -- amp, lt, gt, apos, quot. The declaration of a general entity MUST
+     -- precede any reference to it which appears in a default value in an
+     -- attribute-list declaration.
+     --
+     -- Note that non-validating processors are not obligated to read and
+     -- process entity declarations occurring in parameter entities or in the
+     -- external subset; for such documents, the define that an entity must be
+     -- declared is a well-formedness constraint only if standalone='yes'.
+ |   Error_Closing_tag_unexpected QName QName
+     -- ^ Well-formedness constraint: Element Type Match.
+     --
+     -- The Name in an element's end-tag MUST match the element type in the start-tag.
+ |   Error_Attribute_collision QName
+     -- ^ Well-formedness constraint: Unique Att Spec.
+     --
+     -- An attribute name MUST NOT appear more than once in the same start-tag or empty-element tag.
+ |   Error_PI_reserved PName
+     -- ^ The target names " XML ", " xml ", and so on are reserved for standardization.
+ |   Error_Namespace_prefix_unknown NCName
+     -- ^ Namespace constraint: Prefix Declared
+     --
+     -- The namespace prefix, unless it is xml or xmlns, MUST have been declared in a namespace declaration attribute in either the start-tag of the element where the prefix is used or in an ancestor element (i.e., an element in whose content the prefixed markup occurs). 
+ |   Error_Namespace_empty NCName
+     -- ^ Namespace constraint: No Prefix Undeclaring
+     --
+     -- In a namespace declaration for a prefix (i.e., where the NSAttName is a PrefixedAttName), the attribute value MUST NOT be empty.
+ |   Error_Namespace_reserved Namespace
+ |   Error_Namespace_reserved_prefix NCName
+     -- ^ Namespace constraint: Reserved Prefixes and Namespace Names
+     --
+     -- The prefix xml is by definition bound to the namespace name
+     -- http://www.w3.org/XML/1998/namespace. It MAY, but need not, be
+     -- declared, and MUST NOT be bound to any other namespace name. Other
+     -- prefixes MUST NOT be bound to this namespace name, and it MUST NOT be
+     -- declared as the default namespace.
+     --
+     -- The prefix xmlns is used only to declare namespace bindings and is by
+     -- definition bound to the namespace name http://www.w3.org/2000/xmlns/.
+     -- It MUST NOT be declared . Other prefixes MUST NOT be bound to this
+     -- namespace name, and it MUST NOT be declared as the default namespace.
+     -- Element names MUST NOT have the prefix xmlns.
+     --
+     -- All other prefixes beginning with the three-letter sequence x, m, l, in
+     -- any case combination, are reserved. This means that:
+     --
+     -- - users SHOULD NOT use them except as defined by later specifications
+     -- - processors MUST NOT treat them as fatal errors.
+ deriving (Eq,Ord,Show)
+instance P.ShowErrorComponent Error where
+  showErrorComponent = show
+
+-- * Helpers
+p_error :: e -> ReadTree e s a
+p_error = P.fancyFailure . Set.singleton . P.ErrorCustom
+
+p_quoted :: P.Tokens s ~ TL.Text => (Char -> ReadTree e s a) -> ReadTree e s a
+p_quoted p =
+  P.between (P.char '"') (P.char '"') (p '"') <|>
+  P.between (P.char '\'') (P.char '\'') (p '\'')
+
+p_until ::
+ P.Tokens s ~ TL.Text =>
+ (Char -> Bool) -> (Char, TL.Text) -> ReadTree e s TL.Text
+p_until content (end, end_) =
+  (TL.concat <$>) $ P.many $
+    P.takeWhile1P Nothing (\c -> content c && c /= end) <|>
+    P.try (TL.singleton <$> P.char end <* P.notFollowedBy (P.string end_))
+
+p_until1 ::
+ P.Tokens s ~ TL.Text =>
+ (Char -> Bool) -> (Char, TL.Text) -> ReadTree e s TL.Text
+p_until1 content (end, end_) =
+  (TL.concat <$>) $ P.some $
+    P.takeWhile1P Nothing (\c -> content c && c /= end) <|>
+    P.try (TL.singleton <$> P.char end <* P.notFollowedBy (P.string end_))
+
+-- * Document
+p_document :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTrees
+p_document = do
+  ps <- p_prolog
+  e  <- p_Element
+  m  <- p_Miscs
+  P.eof
+  return (ps <> pure e <> m)
+
+-- ** Prolog
+p_prolog :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTrees
+p_prolog = (<>)
+ <$> P.option Seq.empty (pure <$> p_XMLDecl)
+ <*> p_Miscs
+
+-- ** Misc
+p_Miscs :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTrees
+p_Miscs = (Seq.fromList . catMaybes <$>) $ P.many $
+  Just <$> p_Comment <|>
+  Just <$> p_PI <|>
+  Nothing <$ p_Spaces1
+
+-- ** XMLDecl
+p_XMLDecl :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_XMLDecl = do
+  Sourced src as <- p_Sourced $ P.between (P.string "<?xml") (P.string "?>") $ do
+    vi <- pure <$> p_VersionInfo
+    ed <- P.option Seq.empty $ pure <$> p_EncodingDecl
+    sd <- P.option Seq.empty $ pure <$> p_SDDecl
+    p_Spaces
+    return $ vi <> ed <> sd
+  return $ TS.Tree (Sourced src $ NodePI "xml" "") as
+
+p_VersionInfo :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_VersionInfo = do
+  Sourced src v <- p_Sourced $ do
+    P.try $ p_Spaces1 <* P.string "version"
+    p_Eq
+    p_quoted $ const $
+      (<>)
+       <$> P.string "1."
+       <*> P.takeWhile1P Nothing Char.isDigit
+  return $ TS.tree0 $ Sourced src $ NodePI "version" v
+
+p_EncodingDecl :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_EncodingDecl = do
+  Sourced src v <- p_Sourced $ do
+    P.try $ p_Spaces1 <* P.string "encoding"
+    p_Eq
+    p_quoted $ const p_EncName
+  return $ TS.tree0 $ Sourced src $ NodePI "encoding" v
+
+p_EncName :: P.Tokens s ~ TL.Text => ReadTree Error s TL.Text
+p_EncName = P.label "EncName" $ do
+  P.notFollowedBy (P.satisfy $ not . isAlpha)
+  P.takeWhile1P Nothing $ \c ->
+    isAlpha c || Char.isDigit c ||
+    c=='.' || c=='_' || c=='-'
+  where isAlpha c = Char.isAsciiLower c || Char.isAsciiUpper c
+
+-- *** SDDecl
+p_SDDecl :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_SDDecl = do
+  Sourced src v <- p_Sourced $ do
+    P.try $ p_Spaces1 <* P.string "standalone"
+    p_Eq
+    p_quoted $ const $ P.string "yes" <|> P.string "no"
+  return $ TS.tree0 $ Sourced src $ NodePI "standalone" v
+
+-- ** CharData
+p_CharData :: P.Tokens s ~ TL.Text => ReadTree e s EscapedText
+p_CharData = P.label "[^<&]" $ escapeText <$>
+  p_until1 (\c -> XC.isXmlChar c && c/='<' && c/='&') (']',"]>")
+
+-- ** Comment
+p_Comment :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_Comment = p_SourcedBegin $ P.string "<!--" *> p_Comment__
+p_Comment_ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_Comment_ = P.string "--" *> p_Comment__
+p_Comment__:: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_Comment__ = do
+  c <- p_until XC.isXmlChar ('-', "-")
+  void $ P.string "-->"
+  src <- p_SourcedEnd
+  return $ TS.tree0 $ src $ NodeComment c
+
+-- ** CDATA
+p_CDSect :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_CDSect = p_SourcedBegin $ P.string "<![CDATA[" *> p_CDSect__
+p_CDSect_ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_CDSect_ = P.string "[CDATA[" *> p_CDSect__
+p_CDSect__ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_CDSect__ = do
+  c <- p_until XC.isXmlChar (']', "]>")
+  void $ P.string "]]>"
+  src <- p_SourcedEnd
+  return $ TS.tree0 $ src $ NodeCDATA c
+
+-- ** PI
+p_PI :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_PI = p_SourcedBegin $ P.string "<?" *> p_PI__
+p_PI_ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_PI_ = P.char '?' *> p_PI__
+p_PI__ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_PI__ = do
+  n <- p_PITarget
+  v <- P.option "" $ p_Spaces1 *> p_until XC.isXmlChar ('?', ">")
+  void $ P.string "?>"
+  src <- p_SourcedEnd
+  return $ TS.tree0 $ src $ NodePI n v
+p_PITarget :: P.Tokens s ~ TL.Text => ReadTree Error s PName
+p_PITarget = do
+  n <- p_PName
+  case n of
+   PName{pNameSpace=Nothing, pNameLocal=NCName l}
+    | "xml" == TL.toLower l -> p_error $ Error_PI_reserved n
+   _ -> return n
+
+-- ** Element
+p_Element :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_Element = p_SourcedBegin $ (P.char '<' *> p_Element_)
+p_Element_ :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_Element_ = p_STag
+
+-- *** STag
+p_STag :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTree
+p_STag = do
+  n  <- p_PName
+  attrs <- P.many $ p_Attribute
+  p_Spaces
+  ro <- R.ask
+  elemNS :: HM.HashMap NCName Namespace <-
+    (HM.fromList . List.concat <$>) $ forM attrs $ \case
+     (PName{..}, Sourced _ av)
+      | ns <- Namespace $ unescapeAttr av
+      , Nothing        <- pNameSpace
+      , NCName "xmlns" <- pNameLocal ->
+      -- Default namespace declaration
+      case ns of
+       _ |  ns == xmlns_xml   -- DOC: it MUST NOT be declared as the default namespace
+         || ns == xmlns_xmlns -- DOC: it MUST NOT be declared as the default namespace
+         -> p_error $ Error_Namespace_reserved ns
+       _ -> return [(NCName "" , ns)]
+      | ns <- Namespace $ unescapeAttr av
+      , Just (NCName "xmlns") <- pNameSpace ->
+      -- Namespace prefix declaration
+      case unNCName pNameLocal of
+       "xml" -- DOC: It MAY, but need not, be declared,
+             -- and MUST NOT be bound to any other namespace name.
+             | ns == xmlns_xml -> return []
+             | otherwise -> p_error $ Error_Namespace_reserved_prefix pNameLocal
+       "xmlns" -- DOC: It MUST NOT be declared
+               -> p_error $ Error_Namespace_reserved_prefix pNameLocal
+       local | "xml" <- TL.toLower $ TL.take 3 local -> return []
+             -- DOC: All other prefixes beginning with the three-letter
+             -- sequence x, m, l, in any case combination, are reserved.
+             -- This means that: processors MUST NOT treat them as fatal errors.
+       _ |  ns == xmlns_xml   -- DOC: Other prefixes MUST NOT be bound to this namespace name.
+         || ns == xmlns_xmlns -- DOC: Other prefixes MUST NOT be bound to this namespace name.
+         -> p_error $ Error_Namespace_reserved ns
+       _ -> return [(pNameLocal, ns)]
+      | otherwise -> return []
+  let scopeNS = elemNS <> readTreeInh_ns_scope ro
+  let defaultNS = HM.lookupDefault (readTreeInh_ns_default ro) (NCName "") scopeNS
+  let
+   lookupNamePrefix prefix =
+    maybe (p_error $ Error_Namespace_prefix_unknown prefix) return $
+    HM.lookup prefix scopeNS
+  elemName :: QName <-
+    -- Expand element's QName
+    case pNameSpace n of
+     Nothing -> return QName{qNameSpace=defaultNS, qNameLocal=pNameLocal n}
+      -- DOC: If there is a default namespace declaration in scope,
+      -- the expanded name corresponding to an unprefixed element name
+      -- has the URI of the default namespace as its namespace name.
+     Just prefix
+      | NCName "xmlns" <- prefix ->
+      -- DOC: Element names MUST NOT have the prefix xmlns.
+      p_error $ Error_Namespace_reserved_prefix prefix
+      | otherwise -> do
+      ns <- lookupNamePrefix prefix
+      return QName{qNameSpace=ns, qNameLocal=pNameLocal n}
+  elemAttrs :: [(QName, FileSourced EscapedAttr)] <-
+    -- Expand attributes' PName into QName
+    forM attrs $ \(an, av) -> do
+      ns <- maybe (return "") lookupNamePrefix $ pNameSpace an
+      let qn = QName{qNameSpace=ns, qNameLocal=pNameLocal an}
+      return (qn, av)
+  -- Check for attribute collision
+  let
+   attrsByQName :: HM.HashMap QName [FileSourced EscapedAttr] =
+    HM.fromListWith (<>) $ (<$> elemAttrs) $
+     \(an, av) -> (an, [av])
+  case HM.toList $ HM.filter (\x -> length x > 1) attrsByQName of
+   (an, _):_ -> p_error $ Error_Attribute_collision an
+   _ -> return ()
+  content :: FileSourcedTrees <-
+    mempty <$ P.string "/>" <|>
+    R.local
+     (const ro
+       { readTreeInh_ns_scope   = scopeNS
+       , readTreeInh_ns_default = defaultNS
+       })
+     (P.char '>' *> p_content <* p_ETag elemName)
+  src <- p_SourcedEnd
+  return $ TS.Tree (src $ NodeElem elemName (List.head <$> attrsByQName)) content
+
+-- *** Attribute
+-- | Note: despite the type, the returned 'FileSource'
+-- encompasses also the attribute 'PName'.
+-- It is pushed in the attribute value to fit the insertion
+-- of the attribute into a 'HM.HashMap'.
+p_Attribute :: P.Tokens s ~ TL.Text => ReadTree Error s (PName, FileSourced EscapedAttr)
+p_Attribute =
+  p_SourcedBegin $ do
+    an <- P.try $ p_Spaces1 *> p_PName
+    void p_Eq
+    av <- p_AttrValue
+    src <- p_SourcedEnd
+    return (an, src av)
+
+p_AttrValue :: P.Tokens s ~ TL.Text => ReadTree Error s EscapedAttr
+p_AttrValue = p_quoted p_AttrValueText
+
+p_AttrValueText :: P.Tokens s ~ TL.Text => Char -> ReadTree Error s EscapedAttr
+p_AttrValueText q =
+  EscapedAttr . Seq.fromList <$> P.many (
+    p_Reference <|>
+    -- Supplementary alternative to always escape the quote
+    -- as expected by 'EscapedAttr'.
+    (if q /= '\"' then EscapedEntityRef entityRef_quot <$ P.char '"' else P.empty) <|>
+    EscapedPlain <$> P.label ("[^<&"<>[q]<>"]")
+      (P.takeWhile1P Nothing $ \c ->
+        XC.isXmlChar c &&
+        c `List.notElem` (q:"<&")
+      )
+  )
+
+-- * content
+p_content :: P.Tokens s ~ TL.Text => ReadTree Error s FileSourcedTrees
+p_content =
+  (Seq.fromList <$>) $ P.many $
+    (p_SourcedBegin $ do
+      P.try $ P.char '<' *> P.notFollowedBy (P.char '/')
+      p_Element_ <|> p_PI_ <|> (P.char '!' *> (p_Comment_ <|> p_CDSect_))
+    )
+    <|> (
+    (TS.tree0 <$>) $
+      p_Sourced $ NodeText . EscapedText . foldMap unEscapedText
+       <$> P.some (
+        p_CharData <|>
+        EscapedText . pure <$> p_Reference
+      )
+    )
+
+-- *** ETag
+p_ETag :: P.Tokens s ~ TL.Text => QName -> ReadTree Error s ()
+p_ETag expected = do
+  got <- P.string "</" *> p_QName <* p_Spaces <* P.char '>'
+  unless (got == expected) $
+    p_error $ Error_Closing_tag_unexpected got expected
+
+-- * PName
+p_PName :: P.Tokens s ~ TL.Text => ReadTree e s PName
+p_PName = do
+  n <- p_NCName
+  s <- P.optional $ P.try $ P.char ':' *> p_NCName
+  return $ case s of
+   Nothing -> PName{pNameSpace=Nothing, pNameLocal=n}
+   Just l  -> PName{pNameSpace=Just n , pNameLocal=l}
+
+-- * QName
+p_QName :: P.Tokens s ~ TL.Text => ReadTree Error s QName
+p_QName = do
+  n <- p_NCName
+  s <- P.optional $ P.try $ P.char ':' *> p_NCName
+  ReadTreeInh{..} <- R.ask
+  case s of
+   Nothing -> return QName{qNameSpace=readTreeInh_ns_default, qNameLocal=n}
+   Just l ->
+    case HM.lookup n readTreeInh_ns_scope of
+     Nothing -> p_error $ Error_Namespace_prefix_unknown n
+     Just ns -> return QName{qNameSpace=ns, qNameLocal=l}
+
+-- ** NCName
+p_NCName :: P.Tokens s ~ TL.Text => ReadTree e s NCName
+p_NCName = P.label "NCName" $ NCName
+ <$  P.notFollowedBy (P.satisfy (not . XC.isXmlNCNameStartChar))
+ <*> P.takeWhile1P Nothing XC.isXmlNCNameChar
+
+-- * Reference
+p_Reference :: P.Tokens s ~ TL.Text => ReadTree Error s Escaped
+p_Reference =
+  EscapedCharRef   <$> p_CharRef <|>
+  EscapedEntityRef <$> p_EntityRef
+
+-- ** EntityRef
+p_EntityRef :: P.Tokens s ~ TL.Text => ReadTree Error s EntityRef
+p_EntityRef = do
+  ref <- P.char '&' *> p_NCName <* P.char ';'
+  EntityRef ref <$> lookupEntityRef ref
+  where
+  -- Because entities are declared in the (unimplemented) DTD,
+  -- only builtins entities are supported for now.
+  lookupEntityRef (NCName "lt"  ) = pure "<"
+  lookupEntityRef (NCName "gt"  ) = pure ">"
+  lookupEntityRef (NCName "amp" ) = pure "&"
+  lookupEntityRef (NCName "apos") = pure "'"
+  lookupEntityRef (NCName "quot") = pure "\""
+  lookupEntityRef n = p_error $ Error_EntityRef_unknown n
+
+-- ** CharRef
+p_CharRef :: P.Tokens s ~ TL.Text => ReadTree Error s CharRef
+p_CharRef =
+  do
+    ref <- readHexadecimal
+     <$  P.string "&#x"
+     <*> P.some P.hexDigitChar
+     <*  P.char ';'
+    check ref
+  <|> do
+    ref <- readDecimal
+     <$  P.string "&#"
+     <*> P.some P.digitChar
+     <*  P.char ';'
+    check ref
+  where
+  check i =
+    let c = toEnum (fromInteger i) in
+    if i <= toInteger (fromEnum (maxBound::Char))
+    && XC.isXmlChar c
+    then pure $ CharRef c
+    else p_error $ Error_CharRef_invalid i
+
+readInt :: Integer -> String -> Integer
+readInt base digits =
+  sign * List.foldl' acc 0 (List.concatMap digToInt digits1)
+  where
+  acc q r = q*base + r
+  (sign, digits1) =
+    case digits of
+     [] -> (1, digits)
+     c:ds | c == '-'  -> (-1, ds)
+          | c == '+'  -> ( 1, ds)
+          | otherwise -> ( 1, digits)
+  ord = toInteger . Char.ord
+  digToInt c
+   | Char.isDigit c      = [ord c - ord '0']
+   | Char.isAsciiLower c = [ord c - ord 'a' + 10]
+   | Char.isAsciiUpper c = [ord c - ord 'A' + 10]
+   | otherwise           = []
+
+readDecimal :: String -> Integer
+readDecimal = readInt 10
+
+readHexadecimal :: String -> Integer
+readHexadecimal = readInt 16
+
+-- * Char
+p_Char :: P.Tokens s ~ TL.Text => ReadTree e s Char
+p_Char = P.label "XmlChar" $ P.satisfy XC.isXmlCharCR <|> p_CRLF
+{-# INLINE p_Char #-}
+
+-- ** Space
+-- | Map '\r' and '\r\n' to '\n'.
+-- See: https://www.w3.org/TR/xml/#sec-line-ends
+p_CRLF :: P.Tokens s ~ TL.Text => ReadTree e s Char
+p_CRLF = P.char '\r' *> P.option '\n' (P.char '\n')
+
+p_Space :: P.Tokens s ~ TL.Text => ReadTree e s Char
+p_Space = P.label "space" $ P.satisfy XC.isXmlSpaceCharCR <|> p_CRLF
+{-# INLINE p_Space #-}
+
+p_Spaces :: P.Tokens s ~ TL.Text => ReadTree e s ()
+p_Spaces = P.label "spaces" $ void $ P.takeWhileP Nothing XC.isXmlSpaceChar
+{-# INLINE p_Spaces #-}
+
+p_Spaces1 :: P.Tokens s ~ TL.Text => ReadTree e s ()
+p_Spaces1 = P.label "spaces" $ void $ P.takeWhile1P Nothing XC.isXmlSpaceChar
+{-# INLINE p_Spaces1 #-}
+
+-- * Eq
+p_separator :: P.Tokens s ~ TL.Text => Char -> ReadTree e s ()
+p_separator c = P.try (() <$ p_Spaces <* P.char c) <* p_Spaces
+
+p_Eq :: P.Tokens s ~ TL.Text => ReadTree e s ()
+p_Eq = p_separator '='
diff --git a/src/Symantic/XML/Tree/Source.hs b/src/Symantic/XML/Tree/Source.hs
new file mode 100644 (file)
index 0000000..74b22e0
--- /dev/null
@@ -0,0 +1,142 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE StrictData #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Symantic.XML.Tree.Source where
+
+import Control.Applicative (Applicative(..))
+import Data.Bool
+import Data.Eq (Eq(..))
+import Data.Function (($), (.), const)
+import Data.Functor (Functor)
+import Data.Functor.Identity (Identity(..))
+import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
+import Data.Semigroup (Semigroup(..))
+import Data.List.NonEmpty (NonEmpty(..))
+import Prelude (Num(..), Int)
+import System.IO (FilePath)
+import Text.Show (Show(..), shows, showChar, showParen, showString)
+
+-- * Type family 'Source'
+type family Source (src :: * -> *) :: *
+type instance Source (Sourced src) = src
+type instance Source Identity = ()
+
+-- * Class 'NoSource'
+class NoSource src where
+  noSource :: a -> src a
+  nullSource :: Source src -> Bool
+  default nullSource ::
+   Eq (Source src) =>
+   SourceOf src =>
+   Source src -> Bool
+  nullSource = (==) (sourceOf @src (noSource @src ()))
+instance NoSource Identity where
+  noSource = Identity
+  nullSource = const True
+
+-- * Class 'UnSource'
+class UnSource src where
+  unSource :: src a -> a
+instance UnSource Identity where
+  unSource = runIdentity
+
+-- * Class 'SourceOf'
+class SourceOf src where
+  sourceOf :: src a -> Source src
+instance SourceOf Identity where
+  sourceOf _ = ()
+
+-- * Type 'FileSource'
+newtype FileSource pos
+ =      FileSource (NonEmpty (FileRange pos))
+ deriving (Eq)
+instance Show (FileRange pos) => Show (FileSource pos) where
+  showsPrec _p (FileSource (s:|[])) = shows s
+  showsPrec _p (FileSource (s:|s1:ss)) =
+    shows s . showString "\n in " .
+    shows (FileSource (s1:|ss))
+
+-- ** Type 'FileSourced'
+type FileSourced = Sourced (FileSource Offset)
+
+-- ** Type 'FileRange'
+data FileRange pos
+ =   FileRange
+ {   fileRange_path  :: FilePath
+ ,   fileRange_begin :: pos
+ ,   fileRange_end   :: pos
+ } deriving (Eq, Ord)
+instance Show (FileRange Offset) where
+  showsPrec _p FileRange{..} =
+    showString fileRange_path . showString " at char position " .
+    showsPrec 10 fileRange_begin . showString " to " .
+    showsPrec 10 fileRange_end
+instance Show (FileRange LineColumn) where
+  showsPrec _p FileRange{..} =
+    showString fileRange_path . showString " at line:column position " .
+    showsPrec 10 fileRange_begin . showString " to " .
+    showsPrec 10 fileRange_end
+
+-- *** Type 'Offset'
+newtype Offset = Offset Int
+ deriving (Eq, Ord)
+instance Show Offset where
+  showsPrec p (Offset o) = showsPrec p o
+instance Semigroup Offset where
+  Offset x <> Offset y = Offset (x+y)
+instance Monoid Offset where
+  mempty  = Offset 0
+  mappend = (<>)
+
+-- *** Type 'LineColumn'
+-- | Absolute text file position.
+data LineColumn = LineColumn
+ { lineNum :: {-# UNPACK #-} Offset
+ , colNum  :: {-# UNPACK #-} Offset
+ } deriving (Eq, Ord)
+instance Show LineColumn where
+  showsPrec _p LineColumn{..} =
+    showsPrec 11 lineNum .
+    showChar ':' .
+    showsPrec 11 colNum
+
+-- * Type 'Sourced'
+data Sourced src a
+ =   Sourced
+ {   source  :: src
+ , unSourced :: a
+ } deriving (Functor)
+instance UnSource (Sourced src) where
+  unSource = unSourced
+instance NoSource (Sourced (FileSource Offset)) where
+  noSource = Sourced $ FileSource $ pure $ FileRange mempty mempty mempty
+instance SourceOf (Sourced src) where
+  sourceOf (Sourced src _a) = src
+-- | Ignore 'src'
+instance Eq a => Eq (Sourced src a) where
+  x == y = unSourced x == unSourced y
+-- | Ignore 'src'
+instance Ord a => Ord (Sourced src a) where
+  x `compare` y = unSourced x `compare` unSourced y
+instance
+ (Show src, Show a, NoSource (Sourced src)) =>
+ Show (Sourced src a) where
+  showsPrec p (Sourced src a)
+   | nullSource @(Sourced src) src = showsPrec p a
+   | otherwise =
+    showParen (p > 10) $
+    showsPrec 10 a .
+    showString " in " . showsPrec 10 src
+instance Semigroup a => Semigroup (Sourced (FileSource Offset) a) where
+  (<>)
+   (Sourced rx@(FileSource (FileRange xf xb xe :|  xs)) x)
+   (Sourced    (FileSource (FileRange yf yb ye :| _ys)) y)
+   | xf == yf && xe == yb =
+    Sourced (FileSource (FileRange xf xb ye :| xs)) $ x<>y
+   | otherwise = Sourced rx (x<>y)
diff --git a/src/Symantic/XML/Tree/Write.hs b/src/Symantic/XML/Tree/Write.hs
new file mode 100644 (file)
index 0000000..e75863f
--- /dev/null
@@ -0,0 +1,199 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE StrictData #-}
+module Symantic.XML.Tree.Write where
+
+import Data.Bool
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..), all)
+import Data.Function (($), (.), const)
+import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (IsString(..))
+import Data.Traversable (Traversable(..))
+import Data.Tuple (fst)
+import System.IO (IO, FilePath)
+import qualified Control.Monad.Trans.State as S
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Char as Char
+import qualified Data.HashMap.Strict as HM
+import qualified Data.HashSet as HS
+import qualified Data.List as List
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TLB
+import qualified Data.Text.Lazy.Encoding as TL
+import qualified Data.TreeSeq.Strict as TS
+
+import Symantic.XML.Language
+import Symantic.XML.Tree.Source
+import Symantic.XML.Tree.Data
+import Symantic.XML.Write
+
+writeTree :: UnSource src => Trees src -> TL.Text
+writeTree ts = TLB.toLazyText $ unTreeWrite (write_Trees ts) defaultWriteInh
+
+writeTreeIndented :: UnSource src => TL.Text -> Trees src -> TL.Text
+writeTreeIndented ind xs =
+  TLB.toLazyText $
+  unTreeWrite (write_Trees xs) defaultWriteInh
+   { writeInh_indent_delta = ind }
+
+writeFile :: FilePath -> TL.Text -> IO ()
+writeFile fp = BSL.writeFile fp . TL.encodeUtf8
+
+-- * Type 'TreeWrite'
+newtype TreeWrite
+ =      TreeWrite
+ {    unTreeWrite :: WriteInh -> TLB.Builder
+ }
+instance Semigroup TreeWrite where
+  TreeWrite x <> TreeWrite y = TreeWrite (x <> y)
+instance Monoid TreeWrite where
+  mempty = TreeWrite (const "")
+  mappend = (<>)
+instance IsString TreeWrite where
+  fromString = TreeWrite . const . fromString
+
+write_Trees :: UnSource src => Trees src -> TreeWrite
+write_Trees = foldMap write_Tree
+
+write_Tree :: UnSource src => Tree src -> TreeWrite
+write_Tree (TS.Tree node elemChilds) = TreeWrite $ \inh ->
+ case unSource node of
+  NodeText et@(EscapedText t)
+   -- Remove spaces when indenting
+   | not $ TL.null (writeInh_indent_delta inh)
+   , all (\case
+     EscapedPlain p -> TL.all Char.isSpace p
+     _ -> False
+    ) t -> mempty
+   | otherwise -> textify et
+  NodePI pn pv ->
+    writeInh_indent inh <>
+    "<?"<>textify pn<>
+    (case pn of
+     -- Special case: the value of the "xml" PI is parsed
+     -- as children NodePI
+     "xml" -> foldMap (\case
+       TS.Tree nod _ ->
+        case unSource nod of
+         NodePI n v -> " "<>textify n<>"=\""<>textify v<>"\""
+         _ -> mempty
+      ) elemChilds
+     _ -> s<>textify pv
+    ) <> "?>" <> nl inh
+    where s | TL.null pv = ""
+            | otherwise  = " "
+  NodeCDATA t ->
+    writeInh_indent inh <>
+    "<[CDATA[["<>textify (TL.replace "]]>" "]]&gt;" t)<>"]]>"<>nl inh
+  NodeComment t ->
+    writeInh_indent inh <>
+    "<!--"<>textify (TL.replace "-->" "--&gt;" t)<>"-->"<>nl inh
+  NodeElem elemQName elemAttrs ->
+    writeInh_indent inh
+     <> "<"
+     <> write_elemPName
+     <> write_xmlnsAttrs
+     <> write_elemAttrs
+     <> if noChild
+    then "/>" <> nl inh
+    else ">"
+     <> (if hasIndenting then nl inh else mempty)
+     <> write_elemChilds
+     <> (if hasIndenting then writeInh_indent inh else mempty)
+     <> "</"<>write_elemPName<>">"
+     <> nl inh
+    where
+    -- Empty NodeText do not count as a child
+    noChild =
+      all (\case
+       TS.Tree n _ts
+        | NodeText (EscapedText t) <- unSource n ->
+          all (\case
+           EscapedPlain p -> TL.null p
+           _ -> False
+          ) t
+        | otherwise -> False
+      ) elemChilds
+    -- Follow xmllint --format rules to detect indenting:
+    -- if there is any NodeText it should only contain whites
+    hasIndenting =
+      (`all` elemChilds) $ \case
+       TS.Tree n _ts
+        | NodeText (EscapedText t) <- unSource n ->
+          all (\case
+           EscapedPlain p -> TL.all Char.isSpace p
+           _ -> False
+          ) t
+        | otherwise -> True
+    (usedNS, declNS) =
+      HM.foldlWithKey' go (initUsedNS, initDeclNS) elemAttrs
+      where
+      initUsedNS = HS.singleton $ qNameSpace elemQName
+      initDeclNS = (writeInh_namespaces inh){namespaces_prefixes=mempty}
+      go acc@(uNS, dNS) an sav =
+        case unSource sav of
+         av
+         -- xmlns:prefix="namespace"
+          | qNameSpace an == xmlns_xmlns ->
+          let ns = unescapeAttr av in
+          (uNS, dNS
+           { namespaces_prefixes =
+            (if TL.null ns
+            then HM.delete
+            -- Empty namespace means removal
+            -- of the prefix from scope.
+            else (`HM.insert` qNameLocal an))
+             (Namespace ns)
+             (namespaces_prefixes dNS)
+           })
+         -- xmlns="namespace"
+          | qNameSpace an == xmlns_empty
+          , qNameLocal an == NCName "xmlns" ->
+          (uNS, dNS{namespaces_default = Namespace (unescapeAttr av)})
+         -- name="value"
+          | qNameSpace an == xmlns_empty -> acc
+         -- {namespace}name="value"
+          | otherwise -> (HS.insert (qNameSpace an) uNS, dNS)
+    -- The inherited namespaces,
+    -- including those declared at this element.
+    inhNS =
+      HM.union
+       (namespaces_prefixes declNS)
+       (namespaces_prefixes (writeInh_namespaces inh))
+    -- The namespaces used but not declared nor default,
+    -- with fresh prefixes.
+    autoNS =
+      HM.delete (namespaces_default declNS) $
+      (`S.evalState` HS.empty) $
+      traverse
+       (\() -> S.gets freshNCName)
+       (HS.toMap usedNS `HM.difference` inhNS)
+    write_xmlnsAttrs =
+      foldMap (\(Namespace ns, qNameLocal) ->
+        textifyAttr (PName (Just "xmlns") qNameLocal) (escapeAttr ns)) $
+      List.sortOn fst $
+      HM.toList autoNS
+    scopeNS = declNS{ namespaces_prefixes = autoNS <> inhNS }
+    write_elemPName = textify $ prefixifyQName scopeNS elemQName
+    write_elemAttrs =
+      foldMap (\(an, av) -> textifyAttr
+       (prefixifyQName scopeNS{namespaces_default=xmlns_empty} an)
+       (unSource av)) $
+      List.sortOn fst $ -- This makes the rendition more predictible, but this is useless.
+      HM.toList elemAttrs
+    write_elemChilds = unTreeWrite (write_Trees elemChilds) inh
+     { writeInh_namespaces = scopeNS
+     -- Disable indenting unless hasIndenting.
+     , writeInh_indent =
+      if hasIndenting
+      then
+        writeInh_indent inh <>
+        textify (writeInh_indent_delta inh)
+      else mempty
+     , writeInh_indent_delta =
+      if hasIndenting
+      then writeInh_indent_delta inh
+      else mempty
+     }
diff --git a/src/Symantic/XML/Write.hs b/src/Symantic/XML/Write.hs
new file mode 100644 (file)
index 0000000..8ddb2e2
--- /dev/null
@@ -0,0 +1,334 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE StrictData #-}
+{-# LANGUAGE UndecidableInstances #-}
+module Symantic.XML.Write where
+
+import Control.Applicative (Applicative(..), Alternative((<|>)))
+import Data.Bool
+import Data.Either (Either(..))
+import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
+import Data.Function (($), (.), id)
+import Data.Functor ((<$>), (<$))
+import Data.Int (Int)
+import Data.Maybe (Maybe(..), fromMaybe)
+import Data.Monoid (Monoid(..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (String)
+import Data.Traversable (Traversable(..))
+import Data.Tuple (fst)
+import Numeric.Natural (Natural)
+import Prelude (Integer, error)
+import System.IO (IO, FilePath)
+import Text.Show (Show(..))
+import qualified Control.Exception as Exn
+import qualified Control.Monad.Trans.State as S
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.HashMap.Strict as HM
+import qualified Data.HashSet as HS
+import qualified Data.List as List
+import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TLB
+import qualified Data.Text.Lazy.Encoding as TL
+import qualified System.IO.Error as IO
+
+import Symantic.Base.CurryN
+import Symantic.XML.Language
+import Symantic.XML.RelaxNG.Language
+
+-- * Type 'Write'
+newtype Write params k
+ =      Write
+ {    unWrite :: (WriteSyn -> k) -> params
+ }
+
+write :: Write params BSL.ByteString -> params
+write = runWrite defaultWriteInh
+
+runWrite :: WriteInh -> Write params BSL.ByteString -> params
+runWrite def (Write params) = params $ \syn ->
+  TL.encodeUtf8 $ TLB.toLazyText $
+  fromMaybe mempty $ writeSyn_result syn def
+
+writeUtf8 :: FilePath -> Write params (IO (Maybe ErrorWrite)) -> params
+writeUtf8 path (Write params) = params $ \syn ->
+  let txt =
+       TL.encodeUtf8 $ TLB.toLazyText $
+       fromMaybe mempty $
+       writeSyn_result syn defaultWriteInh in
+  (Nothing <$ BSL.writeFile path txt)
+  `Exn.catch` \e ->
+    if IO.isAlreadyInUseError e
+    || IO.isPermissionError   e
+    then pure $ Just e
+    else IO.ioError e
+
+-- ** Type 'Write'
+type ErrorWrite = IO.IOError
+
+-- ** Type 'WriteInh'
+-- | Top-down inheritage.
+data WriteInh
+ =   WriteInh
+ {   writeInh_namespaces   :: Namespaces NCName
+     -- ^ 'Namespaces' from the parent element.
+ ,   writeInh_indent       :: TLB.Builder
+ ,   writeInh_indent_delta :: TL.Text
+ }
+
+defaultWriteInh :: WriteInh
+defaultWriteInh = WriteInh
+ { writeInh_namespaces   = defaultNamespaces
+ , writeInh_indent       = mempty
+ , writeInh_indent_delta = "  "
+ }
+
+-- ** Type 'WriteSyn'
+-- | Bottom-up synthesis to build 'element' or 'attribute'.
+data WriteSyn
+ =   WriteSyn
+ {   writeSyn_attrs :: HM.HashMap QName TL.Text
+ ,   writeSyn_attr :: TL.Text
+ ,   writeSyn_namespaces_default :: Maybe Namespace
+ ,   writeSyn_namespaces_prefixes :: HM.HashMap Namespace NCName
+ ,   writeSyn_result :: WriteInh -> Maybe TLB.Builder
+ }
+
+instance Semigroup WriteSyn where
+  x <> y = WriteSyn
+   { writeSyn_attrs = writeSyn_attrs x <> writeSyn_attrs y
+   , writeSyn_attr = writeSyn_attr x <> writeSyn_attr y
+   , writeSyn_namespaces_default = writeSyn_namespaces_default x <|> writeSyn_namespaces_default y
+   , writeSyn_namespaces_prefixes = writeSyn_namespaces_prefixes x <> writeSyn_namespaces_prefixes y
+   , writeSyn_result = writeSyn_result x <> writeSyn_result y
+   }
+instance Monoid WriteSyn where
+  mempty = WriteSyn
+   { writeSyn_attrs = mempty
+   , writeSyn_attr = mempty
+   , writeSyn_namespaces_default = Nothing
+   , writeSyn_namespaces_prefixes = mempty
+   , writeSyn_result = mempty
+   }
+
+instance Emptyable Write where
+  empty = Write (\k -> k mempty)
+instance Unitable Write where
+  unit = Write (\k () -> k mempty)
+instance Voidable Write where
+  void a (Write x) = Write (\k -> x k a)
+instance Dimapable Write where
+  dimap _a2b b2a (Write x) = Write $ \k b ->
+    x k (b2a b)
+instance Dicurryable Write where
+  dicurry (_::proxy args) _construct destruct (Write x) =
+    Write $ \k r ->
+      uncurryN @args (x k) (destruct r)
+instance Composable Write where
+  Write x <.> Write y = Write $ \k ->
+    x (\mx -> y $ \my -> k (mx<>my))
+instance Tupable Write where
+  Write x <:> Write y = Write $ \k (a,b) ->
+    x (\mx -> y (\my -> k (mx<>my)) b) a
+instance Eitherable Write where
+  Write x <+> Write y = Write $ \k -> \case
+   Left  a -> x k a
+   Right b -> y k b
+instance Constant Write where
+  constant _a = Write $ \k _a -> k mempty
+instance Optionable Write where
+  option = id
+  optional (Write x) = Write $ \k ->
+    \case
+     Nothing -> k mempty
+     Just a -> x k a
+{-
+instance Routable Write where
+  Write x <!> Write y = Write $ \k ->
+    x k :!: y k
+-}
+instance Repeatable Write where
+  many0 (Write x) = Write $ \k -> \case
+   [] -> k mempty
+   a:as -> x (\ma ->
+    unWrite (many0 (Write x))
+     (\mas -> k (ma<>mas)) as) a
+  many1 (Write x) = Write $ \k -> \case
+   [] -> k mempty
+   a:as -> x (\ma ->
+    unWrite (many0 (Write x))
+     (\mas -> k (ma<>mas)) as) a
+instance Textable Write where
+  type TextConstraint Write a = EncodeText a
+  text = Write $ \k v ->
+    let t = encodeText v in
+    k mempty
+     { writeSyn_attr = t
+     , writeSyn_result = \_inh -> Just $ textify $ escapeText t
+     }
+instance XML Write where
+  namespace nm ns = Write $ \k ->
+    k $ case nm of
+     Nothing -> mempty{writeSyn_namespaces_default=Just ns}
+     Just p  -> mempty{writeSyn_namespaces_prefixes=HM.singleton ns p}
+  element elemQName (Write x) = Write $ \k ->
+    x $ \syn ->
+      k mempty{ writeSyn_result = \inh ->
+      let
+        hasIndenting = not $ TL.null $ writeInh_indent_delta inh
+        defNS = fromMaybe
+         (namespaces_default (writeInh_namespaces inh))
+         (writeSyn_namespaces_default syn)
+        usedNS =
+          HS.singleton (qNameSpace elemQName) <>
+          HS.delete xmlns_empty (HS.fromList (qNameSpace <$> HM.keys (writeSyn_attrs syn)))
+        -- The inherited namespaces,
+        -- including those declared at this element.
+        inhNS =
+          HM.union
+           (writeSyn_namespaces_prefixes syn)
+           (namespaces_prefixes (writeInh_namespaces inh))
+        -- The namespaces used but not declared nor default,
+        -- with fresh prefixes.
+        autoNS =
+          -- HM.delete defNS $
+          (`S.evalState` HS.empty) $
+          traverse
+           (\() -> S.gets freshNCName)
+           (HS.toMap usedNS `HM.difference` inhNS)
+        write_xmlnsAttrs =
+          (if defNS == namespaces_default (writeInh_namespaces inh)
+          then mempty
+          else textifyAttr (PName Nothing "xmlns") (escapeAttr (unNamespace defNS))) <>
+          HM.foldrWithKey (\(Namespace ns) qNameLocal acc ->
+            textifyAttr (PName (Just "xmlns") qNameLocal) (escapeAttr ns) <> acc
+           ) mempty
+           (autoNS <> writeSyn_namespaces_prefixes syn)
+        scopeNS = Namespaces
+         { namespaces_prefixes = autoNS <> inhNS
+         , namespaces_default = defNS
+         }
+        write_elemPName = textify $ prefixifyQName scopeNS elemQName
+        write_elemAttrs =
+          foldMap (\(an, av) -> textifyAttr
+           (prefixifyQName scopeNS{namespaces_default=xmlns_empty} an)
+           (escapeAttr av)) $
+          List.sortOn fst $ -- This makes the rendition more predictible, but this is useless.
+          HM.toList (writeSyn_attrs syn)
+        write_elemChilds = writeSyn_result syn inh
+         { writeInh_namespaces = scopeNS
+         -- Disable indenting unless hasIndenting.
+         , writeInh_indent =
+          if hasIndenting
+          then
+            writeInh_indent inh <>
+            textify (writeInh_indent_delta inh)
+          else mempty
+         , writeInh_indent_delta =
+          if hasIndenting
+          then writeInh_indent_delta inh
+          else mempty
+         }
+      in Just $
+      writeInh_indent inh
+       <> "<"
+       <> write_elemPName
+       <> write_xmlnsAttrs
+       <> write_elemAttrs
+       <> case write_elemChilds of
+       Nothing -> "/>" <> nl inh
+       Just w -> ">"
+         <> nl inh
+         <> w
+         <> (if hasIndenting then writeInh_indent inh else mempty)
+         <> "</"<>write_elemPName<>">"
+         <> nl inh
+      }
+  attribute n@(QName ans aln) (Write x) = Write $ \k ->
+    x $ \syn ->
+      if ans == xmlns_xmlns
+      then unWrite (namespace (Just aln) (Namespace (writeSyn_attr syn))) k
+      else if ans == xmlns_empty && aln == NCName "xmlns"
+      then unWrite (namespace Nothing (Namespace (writeSyn_attr syn))) k
+      else k mempty{writeSyn_attrs = HM.insert n (writeSyn_attr syn) (writeSyn_attrs syn)}
+  literal lit = Write $ \k ->
+    k mempty
+     { writeSyn_attr = lit
+     , writeSyn_result = \_inh ->
+      Just $ textify $ escapeText lit
+     }
+  pi n = Write $ \k v ->
+    k mempty{ writeSyn_result = \inh ->
+      let s | TL.null v = ""
+            | otherwise  = " " in
+      Just $
+      writeInh_indent inh <>
+      "<?"<>textify n<>s <>
+      textify (TL.replace "?>" "?&gt;" v) <>
+      "?>"<>nl inh
+    }
+  comment = Write $ \k v ->
+    k mempty{ writeSyn_result = \inh ->
+      Just $
+      writeInh_indent inh <>
+      "<!--"<>textify (TL.replace "-->" "--&gt;" v)<>"-->"<>nl inh
+    }
+  cdata = Write $ \k v ->
+    k mempty{ writeSyn_result = \inh ->
+      Just $
+      writeInh_indent inh <>
+      "<[CDATA[["<>textify (TL.replace "]]>" "]]&gt;" v)<>"]]>"<>nl inh
+    }
+instance Permutable Write where
+  type Permutation Write = WritePerm Write
+  permutable = unWritePerm
+  perm = WritePerm
+  noPerm = WritePerm empty
+  permWithDefault _a = WritePerm
+instance Definable Write where
+  define _n = id
+instance RelaxNG Write where
+  elementMatch nc x = Write $ \k n ->
+    if matchNameClass nc n
+    then error "elementMatch: given QName does not match expected NameClass"
+    else unWrite (element n x) k
+  attributeMatch nc x = Write $ \k n ->
+    if matchNameClass nc n
+    then error "attributeMatch: given QName does not match expected NameClass"
+    else unWrite (attribute n x) k
+
+-- ** Type 'WritePerm'
+newtype WritePerm repr xml k
+ =      WritePerm
+ {    unWritePerm :: repr xml k }
+instance Transformable (WritePerm repr) where
+  type UnTrans (WritePerm repr) = repr
+  noTrans = WritePerm
+  unTrans = unWritePerm
+instance Dimapable (WritePerm Write)
+instance Composable (WritePerm Write)
+instance Tupable (WritePerm Write)
+
+nl :: WriteInh -> TLB.Builder
+nl inh | TL.null (writeInh_indent_delta inh) = mempty
+       | otherwise = "\n"
+
+-- * Class 'EncodeText'
+class EncodeText a where
+  encodeText :: a -> TL.Text
+  default encodeText :: Show a => a -> TL.Text
+  encodeText = TL.pack . show
+instance EncodeText String where
+  encodeText = TL.pack
+instance EncodeText Text.Text where
+  encodeText = TL.fromStrict
+instance EncodeText TL.Text where
+  encodeText = id
+instance EncodeText Bool where
+  encodeText = \case
+   False -> "0"
+   True  -> "1"
+instance EncodeText Int
+instance EncodeText Integer
+instance EncodeText Natural
index 8dab1a0db3f29788707d3b0e59235c9b2a080c5c..693692f2bd7dc508452e8f0ebae7059134a95ffb 100644 (file)
@@ -1,9 +1,4 @@
-resolver: lts-13.19
-packages:
-- '.'
-- location: '../treeseq'
-  extra-dep: true
-- location: '../symantic/symantic-grammar'
-  extra-dep: true
+resolver: lts-15.4
 extra-deps:
 extra-deps:
-- megaparsec-7.0.4@sha256:a7397151601cbe6b8f831f8bdad1a10118dcd6d9a7ee50d6bbdcfbd1181b4ba2
+- ../treeseq
+- ../symantic-base
diff --git a/stack.yaml.lock b/stack.yaml.lock
new file mode 100644 (file)
index 0000000..ab34d2b
--- /dev/null
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+#   https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+    size: 491163
+    url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/15/4.yaml
+    sha256: bc60043a06b58902b533baa80fb566c0ec495c41e428bc0f8c1e8c15b2a4c468
+  original: lts-15.4
index c57212304b15c046949f47382fc4499235947231..5f528ae2166380d1b017afe666ce32788e618d72 100644 (file)
@@ -2,62 +2,65 @@ name: symantic-xml
 -- PVP:  +-+------- breaking API changes
 --       | | +----- non-breaking API additions
 --       | | | +--- code changes with no API change
 -- PVP:  +-+------- breaking API changes
 --       | | +----- non-breaking API additions
 --       | | | +--- code changes with no API change
-version: 1.0.0.20190223
-category: Data Structures
-synopsis: Library for reading, validating and writing a subset of the XML format.
-description: Symantics for an approximative implementation
            of XML (eXtensible Markup Language) and RNC (RelaxNG Compact).
+version: 2.0.0.20200523
+category: Text, XML
+synopsis: Library for reading, validating and writing XML.
+description: Symantics for XML (eXtensible Markup Language)
+ and RNC (RelaxNG Compact).
  .
  .
- Motivation: Other Haskell libraries do not fit my needs or are too heavy/complex.
- I like the principle to parse XML using some symantics,
- which can both generate a Megaparsec parser to validate the XML tree,
- and a RNC rendition of the schema it validates.
+ DISCLAIMER: This is an experimental library, use at your own risks.
  .
  .
- DISCLAMER: My life being's too short, I'm NOT burning my brain
- on seriously conforming to the too complex XML and RNC formats.
- Still I try to respect a vague subset of those,
- unless it makes the code more complex than I am comfortable with.
+ Motivation: Writing a schema using Haskell combinators
+ and deriving automatically a reader, a writer
+ and a documentation from it.
  .
  .
- WARNING: It's currently using an old symantic approach,
not the one developped in <https://hackage.haskell.org/package/symantic-http symantic-http>.
- This may change when I'll get to it.
+ Example:
+ .
+ * <symantic-atom https://hackage.haskell.org/package/symantic-atom>
 extra-doc-files:
 license: GPL-3
 license-file: COPYING
 stability: experimental
 extra-doc-files:
 license: GPL-3
 license-file: COPYING
 stability: experimental
-author:      Julien Moutinho <julm+symantic-xml@autogeree.net>
-maintainer:  Julien Moutinho <julm+symantic-xml@autogeree.net>
-bug-reports: Julien Moutinho <julm+symantic-xml@autogeree.net>
+author:      Julien Moutinho <julm+symantic-xml@sourcephile.fr>
+maintainer:  Julien Moutinho <julm+symantic-xml@sourcephile.fr>
+bug-reports: Julien Moutinho <julm+symantic-xml@sourcephile.fr>
 -- homepage:
 
 build-type: Simple
 cabal-version: 1.24
 -- homepage:
 
 build-type: Simple
 cabal-version: 1.24
-tested-with: GHC==8.6.4
+tested-with: GHC==8.8.3
 extra-source-files:
   stack.yaml
 extra-source-files:
   stack.yaml
+  stack.yaml.lock
 extra-tmp-files:
 
 Source-Repository head
 extra-tmp-files:
 
 Source-Repository head
-  location: git://git.autogeree.net/symantic-xml
+  location: git://git.sourcephile.fr/haskell/symantic-xml
   type:     git
 
 Library
   type:     git
 
 Library
+  hs-source-dirs: src
   exposed-modules:
   exposed-modules:
-    Symantic.RNC
-    Symantic.RNC.Sym
-    Symantic.RNC.Validate
-    Symantic.RNC.Write
-    Symantic.RNC.Write.Fixity
-    Symantic.RNC.Write.Namespaces
     Symantic.XML
     Symantic.XML
-    Symantic.XML.Document
+    Symantic.XML.Language
+    Symantic.XML.Namespace
     Symantic.XML.Read
     Symantic.XML.Read
-    Symantic.XML.Read.Parser
+    Symantic.XML.RelaxNG
+    Symantic.XML.RelaxNG.Compact.Write
+    Symantic.XML.RelaxNG.Language
+    Symantic.XML.Text
+    Symantic.XML.Tree
+    Symantic.XML.Tree.Data
+    Symantic.XML.Tree.Read
+    Symantic.XML.Tree.Source
+    Symantic.XML.Tree.Write
     Symantic.XML.Write
   default-language: Haskell2010
   default-extensions:
     Symantic.XML.Write
   default-language: Haskell2010
   default-extensions:
+    DefaultSignatures
     FlexibleContexts
     FlexibleInstances
     FlexibleContexts
     FlexibleInstances
+    GeneralizedNewtypeDeriving
     LambdaCase
     MultiParamTypeClasses
     NamedFieldPuns
     LambdaCase
     MultiParamTypeClasses
     NamedFieldPuns
@@ -65,24 +68,22 @@ Library
     RecordWildCards
     ScopedTypeVariables
     TupleSections
     RecordWildCards
     ScopedTypeVariables
     TupleSections
-    -- TypeFamilies
+    TypeApplications
+    TypeFamilies
+    TypeOperators
   ghc-options:
     -Wall
     -Wincomplete-uni-patterns
     -Wincomplete-record-updates
   ghc-options:
     -Wall
     -Wincomplete-uni-patterns
     -Wincomplete-record-updates
-    -fno-warn-tabs
     -- -fhide-source-paths
   build-depends:
       base                 >= 4.10 && < 5
     , bytestring           >= 0.10
     , containers           >= 0.5
     -- -fhide-source-paths
   build-depends:
       base                 >= 4.10 && < 5
     , bytestring           >= 0.10
     , containers           >= 0.5
-    , data-default-class   >= 0.1
-    , filepath             >= 1.4
     , hashable             >= 1.2.6
     , hxt-charproperties   >= 9.2
     , hashable             >= 1.2.6
     , hxt-charproperties   >= 9.2
-    , megaparsec           >= 7.0.4
-    -- , parser-combinators   >= 1.0
-    , safe                 >= 0.3
+    , megaparsec           >= 8.0
+    , symantic-base        >= 0.0
     , text                 >= 1.2
     , transformers         >= 0.5
     , treeseq              >= 1.0
     , text                 >= 1.2
     , transformers         >= 0.5
     , treeseq              >= 1.0
@@ -93,8 +94,8 @@ Test-Suite symantic-xml-test
   hs-source-dirs: test
   main-is: Main.hs
   other-modules:
   hs-source-dirs: test
   main-is: Main.hs
   other-modules:
-    RNC.Parser
-    RNC.Commoning
+    RelaxNG.Commoning
+    RelaxNG.Whatever
     Golden
     -- HUnit
     -- QuickCheck
     Golden
     -- HUnit
     -- QuickCheck
@@ -104,28 +105,28 @@ Test-Suite symantic-xml-test
     NamedFieldPuns
     NoImplicitPrelude
     RecordWildCards
     NamedFieldPuns
     NoImplicitPrelude
     RecordWildCards
+    TypeFamilies
     ViewPatterns
   ghc-options:
     -Wall
     -Wincomplete-uni-patterns
     -Wincomplete-record-updates
     ViewPatterns
   ghc-options:
     -Wall
     -Wincomplete-uni-patterns
     -Wincomplete-record-updates
-    -fno-warn-tabs
     -fhide-source-paths
   build-depends:
     symantic-xml
     -fhide-source-paths
   build-depends:
     symantic-xml
+    , symantic-base >= 0.0
     , base >= 4.10 && < 5
     , bytestring >= 0.10
     , containers >= 0.5
     , base >= 4.10 && < 5
     , bytestring >= 0.10
     , containers >= 0.5
-    , data-default-class   >= 0.1
     , deepseq >= 1.4
     , deepseq >= 1.4
-    , filepath >= 1.4
     , hashable >= 1.2.6
     , megaparsec >= 7.0.4
     , tasty >= 0.11
     , tasty-golden >= 2.3
     , hashable >= 1.2.6
     , megaparsec >= 7.0.4
     , tasty >= 0.11
     , tasty-golden >= 2.3
+    -- , tasty-hunit
     , text >= 1.2
     , text >= 1.2
+    -- , time >= 1.9
     , transformers >= 0.4
     , treeseq >= 1.0
     -- , QuickCheck >= 2.0
     , transformers >= 0.4
     , treeseq >= 1.0
     -- , QuickCheck >= 2.0
-    -- , tasty-hunit
     -- , tasty-quickcheck
     -- , tasty-quickcheck
index 2a152186a0c9de426750aaf21880497d2ea8f0a3..bc87e994749733b4a5031021c7e69b6f9f8ff288 100644 (file)
-{-# LANGUAGE FlexibleInstances #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 module Golden where
 
 module Golden where
 
-import Control.Arrow (left)
 import Control.Monad (Monad(..), sequence)
 import Data.Bool
 import Data.Either (Either(..))
 import Control.Monad (Monad(..), sequence)
 import Data.Bool
 import Data.Either (Either(..))
-import Data.Foldable (Foldable(..))
 import Data.Function (($), (.))
 import Data.Functor ((<$>))
 import Data.Function (($), (.))
 import Data.Functor ((<$>))
+import Data.Monoid (Monoid(..))
 import Data.Semigroup (Semigroup(..))
 import Data.String (String)
 import Data.Semigroup (Semigroup(..))
 import Data.String (String)
-import Data.Void (Void)
-import System.FilePath (FilePath)
-import System.IO (IO)
+import System.IO (IO, FilePath)
 import Text.Show (Show(..))
 import qualified Data.ByteString.Lazy as BSL
 import qualified Data.List as List
 import qualified Data.Text.Lazy          as TL
 import qualified Data.Text.Lazy.Encoding as TL
 import Text.Show (Show(..))
 import qualified Data.ByteString.Lazy as BSL
 import qualified Data.List as List
 import qualified Data.Text.Lazy          as TL
 import qualified Data.Text.Lazy.Encoding as TL
-import qualified Text.Megaparsec as P
 import qualified Data.TreeSeq.Strict as TS
 
 import Test.Tasty
 import Test.Tasty.Golden
 
 import qualified Data.TreeSeq.Strict as TS
 
 import Test.Tasty
 import Test.Tasty.Golden
 
-import Symantic.XML.Read.Parser (XMLs)
 import qualified Symantic.XML as XML
 import qualified Symantic.XML as XML
-import qualified Symantic.RNC as RNC
-import RNC.Parser ()
-import qualified RNC.Commoning
+import qualified Symantic.XML.RelaxNG as RelaxNG
+import qualified RelaxNG.Commoning
+import qualified RelaxNG.Whatever
+
+goldensIO :: IO TestTree
+goldensIO =
+  testGroup "Golden" <$>
+  sequence
+   [ goldensXML
+   , goldensRelaxNG
+   ]
+
+goldensXML :: IO TestTree
+goldensXML = do
+  inputFiles <- List.sort <$> findByExtension [".xml"] "test/Golden/XML"
+  return $ testGroup "XML"
+   [ testGroup "Read"
+     [ testGolden inputFile ".read" $
+      XML.readTree inputFile >>= \ast ->
+        return $ TL.encodeUtf8 . TL.pack . TS.prettyTrees <$> ast
+     | inputFile <- inputFiles
+     ]
+   , testGroup "Write" $ List.concat
+     [
+       [ testGolden inputFile ".write" $
+        XML.readTree inputFile >>= \ast ->
+          return $ TL.encodeUtf8 . XML.writeTree <$> ast
+       , testGolden inputFile ".write.indented" $
+        XML.readTree inputFile >>= \ast ->
+          return $ TL.encodeUtf8 . XML.writeTreeIndented (TL.pack "  ") <$> ast
+       ]
+     | inputFile <- inputFiles
+     , not $ List.isInfixOf "/Error/" inputFile
+     ]
+   ]
+
+goldensRelaxNG :: IO TestTree
+goldensRelaxNG = do
+  inputFiles <- List.sort <$> findByExtension [".xml"] "test/Golden/RelaxNG"
+  return $ testGroup "RelaxNG"
+   [ testGroup "Validate"
+     [ testGroup "Commoning" $ mconcat
+       [
+        let xml = XML.read RelaxNG.Commoning.schema inputFile in
+        [ testGolden inputFile ".read" $
+          ((TL.encodeUtf8 . TL.pack . show) <$>) <$> xml
+        , testGolden inputFile ".write" $
+          ((XML.write RelaxNG.Commoning.schema) <$>) <$> xml
+        ]
+       | inputFile <- inputFiles
+       , "/Commoning/" `List.isInfixOf` inputFile
+       ]
+     , testGroup "Whatever" $ mconcat
+       [
+        let xml = XML.read RelaxNG.Whatever.schema inputFile in
+        [ testGolden inputFile ".read" $
+          ((TL.encodeUtf8 . TL.pack . show) <$>) <$> xml
+        , testGolden inputFile ".write" $
+          ((XML.write RelaxNG.Whatever.schema) <$>) <$> xml
+        ]
+       | inputFile <- inputFiles
+       , "/Whatever/" `List.isInfixOf` inputFile
+       ]
+     ]
+   , testGroup "Compact"
+     [ testGroup "Write"
+       [ testGolden "test/Golden/RelaxNG/Commoning" ".rnc" $
+          return $ Right $ TL.encodeUtf8 $
+            RelaxNG.writeRNC RelaxNG.Commoning.schema
+       , testGolden "test/Golden/RelaxNG/Whatever" ".rnc" $
+          return $ Right $ TL.encodeUtf8 $
+            RelaxNG.writeRNC RelaxNG.Whatever.schema
+       ]
+     ]
+   ]
 
 -- * Golden testing utilities
 testGolden :: TestName -> TestName -> IO (Either String BSL.ByteString) -> TestTree
 
 -- * Golden testing utilities
 testGolden :: TestName -> TestName -> IO (Either String BSL.ByteString) -> TestTree
-testGolden inputFile expectedExt =
-       goldenVsStringDiff inputFile diffGolden (inputFile <> expectedExt)
-        . (>>= unLeft)
+testGolden testName expectedExt =
+  goldenVsStringDiff testName diffGolden (testName <> expectedExt)
+   . (>>= unLeft)
 
 diffGolden :: FilePath -> FilePath -> [String]
 diffGolden ref new = ["diff", "-u", ref, new]
 
 diffGolden :: FilePath -> FilePath -> [String]
 diffGolden ref new = ["diff", "-u", ref, new]
@@ -44,67 +109,3 @@ unLeft :: Either String BSL.ByteString -> IO BSL.ByteString
 unLeft = \case
  Left err -> return $ TL.encodeUtf8 $ TL.pack err
  Right a  -> return a
 unLeft = \case
  Left err -> return $ TL.encodeUtf8 $ TL.pack err
  Right a  -> return a
-
-goldensIO :: IO TestTree
-goldensIO =
-       testGroup "Golden" <$>
-       sequence
-        [ goldensXML
-        , goldensRNC
-        ]
-
-goldensXML :: IO TestTree
-goldensXML = do
-       inputFiles <- List.sort <$> findByExtension [".xml"] "test/Golden/XML"
-       return $ testGroup "XML"
-        [ testGroup "Read"
-                [ testGolden inputFile ".read" $
-                       readXML inputFile >>= \ast ->
-                               return $ TL.encodeUtf8 . TL.pack . TS.prettyTrees <$> ast
-                | inputFile <- inputFiles
-                ]
-        , testGroup "Write" $ List.concat
-                [
-                        [ testGolden inputFile ".write" $
-                               readXML inputFile >>= \ast ->
-                                       return $ TL.encodeUtf8 . XML.writeXML <$> ast
-                        , testGolden inputFile ".write.indented" $
-                               readXML inputFile >>= \ast ->
-                                       return $ TL.encodeUtf8 . XML.writeXMLIndented (TL.pack "  ") <$> ast
-                        ]
-                | inputFile <- inputFiles
-                , not $ List.isInfixOf "/Error/" inputFile
-                ]
-        ]
-
-readXML :: FilePath -> IO (Either String XMLs)
-readXML inputFile =
-       XML.readFile inputFile >>= \case
-        Left err -> return $ Left $ show err
-        Right input ->
-               return $ left P.errorBundlePretty $
-                       XML.readXML inputFile input
-
-goldensRNC :: IO TestTree
-goldensRNC = do
-       inputFiles <- List.sort <$> findByExtension [".xml"] "test/Golden/RNC"
-       return $ testGroup "RNC"
-        [ testGroup "Validate"
-                [ testGolden inputFile ".read" $
-                       validateXML inputFile RNC.Commoning.commoning >>= \a ->
-                               return $ TL.encodeUtf8 . TL.pack . show <$> a
-                | inputFile <- inputFiles
-                , List.isInfixOf "/Commoning/" inputFile
-                ]
-        ]
-
-validateXML :: FilePath -> P.Parsec Void XMLs a -> IO (Either String a)
-validateXML inputFile rnc =
-       (<$> readXML inputFile) $ \case
-        Left err -> Left err
-        Right xml -> do
-               case RNC.validateXML rnc xml of
-                Right a -> Right a
-                Left err ->
-                       Left $ List.unlines $ toList $
-                               P.parseErrorTextPretty <$> P.bundleErrors err
diff --git a/test/Golden/RelaxNG/Commoning.rnc b/test/Golden/RelaxNG/Commoning.rnc
new file mode 100644 (file)
index 0000000..0bed633
--- /dev/null
@@ -0,0 +1,22 @@
+default namespace = "2018/commoning.rnc"
+namespace xsd = "http://www/w3/org/2001/XMLSchema-datatypes"
+namespace ns1 = "2018/commoning.rnc"
+commoning = element commoning {persons & opinions & groups & operations & resources}
+field = element field {attribute name {text}, text}
+fields = element fields {attribute name {text}, ( field | fields )*}
+grade = element grade {attribute name {text}, ( attribute abbrev {text} )?, ( attribute color {text} )?}
+gradeRange = attribute grade {text} | attribute gradeMin {text} | attribute gradeMax {text} | ( attribute gradeMin {text}, attribute gradeMax {text} )
+grades = element grades {attribute id {xsd:id}, ( attribute name {text} )?, grade*}
+group = element group {attribute id {xsd:id}, ( attribute name {text} )?, fields*, members, group*}
+groups = element groups {group*}
+member = element member {attribute person {xsd:id}}
+members = member*
+operation = element operation {attribute id {xsd:id}, operation*}
+operations = element operations {operation*}
+opinions = element opinions {grades*}
+person = element person {attribute id {xsd:id}, fields*}
+persons = element persons {person*}
+policy = element policy {attribute operation {text}, attribute by {xsd:id}, ( attribute toward {xsd:id} )?, rule*}
+resource = element resource {attribute name {text}, policy*, resource*}
+resources = element resources {resource*}
+rule = element rule {attribute grades {xsd:id}, gradeRange}
similarity index 68%
rename from test/Golden/RNC/Commoning/0000.xml
rename to test/Golden/RelaxNG/Commoning/0000.xml
index b5a2a991fc8abee84ff3f1e5439987d6e0608209..252d38742411a5705b5bf1f0d52c552d053d8997 100644 (file)
@@ -1,4 +1,4 @@
-<commoning xmlns="http://commonsoft.org/xml/2018/commoning.rnc">
+<commoning xmlns="2018/commoning.rnc">
        <persons>
         </persons>
        <groups>
        <persons>
         </persons>
        <groups>
diff --git a/test/Golden/RelaxNG/Commoning/0000.xml.write b/test/Golden/RelaxNG/Commoning/0000.xml.write
new file mode 100644 (file)
index 0000000..cb0a5fd
--- /dev/null
@@ -0,0 +1,7 @@
+<ns1:commoning xmlns:ns1="2018/commoning.rnc">
+  <ns1:persons/>
+  <ns1:opinions/>
+  <ns1:groups/>
+  <ns1:operations/>
+  <ns1:resources/>
+</ns1:commoning>
similarity index 94%
rename from test/Golden/RNC/Commoning/0001.xml
rename to test/Golden/RelaxNG/Commoning/0001.xml
index eb7a28370f8391015c9624c949dc0c7e80618744..2171d2bbf01cb7e14d2766e1db9db86deb0fc4ea 100644 (file)
@@ -1,4 +1,4 @@
-<commoning xmlns="http://commonsoft.org/xml/2018/commoning.rnc">
+<commoning xmlns="2018/commoning.rnc">
        <persons>
                <person id="julm"/>
         </persons>
        <persons>
                <person id="julm"/>
         </persons>
diff --git a/test/Golden/RelaxNG/Commoning/0001.xml.write b/test/Golden/RelaxNG/Commoning/0001.xml.write
new file mode 100644 (file)
index 0000000..308349a
--- /dev/null
@@ -0,0 +1,36 @@
+<ns1:commoning xmlns:ns1="2018/commoning.rnc">
+  <ns1:persons>
+    <ns1:person id="julm"/>
+  </ns1:persons>
+  <ns1:opinions>
+    <ns1:grades id="Règlementation">
+      <ns1:grade abbrev="NE-PEUT-PAS" color="black" name="Ne peut pas"/>
+      <ns1:grade abbrev="NE-DOIT-PAS" color="red" name="Ne doit pas"/>
+      <ns1:grade abbrev="NE-DEVRAIT-PAS" color="orange" name="Ne devrait pas"/>
+      <ns1:grade abbrev="NON-RÈGLEMENTÉ" color="#888" name="Non-règlementé"/>
+      <ns1:grade abbrev="PEUT" color="#FFD700" name="Peut"/>
+      <ns1:grade abbrev="DEVRAIT" color="green" name="Devrait"/>
+      <ns1:grade abbrev="DOIT" color="blue" name="Doit"/>
+    </ns1:grades>
+  </ns1:opinions>
+  <ns1:groups>
+    <ns1:group id="Public"/>
+  </ns1:groups>
+  <ns1:operations>
+    <ns1:operation id="Écrire">
+      <ns1:operation id="Lire"/>
+    </ns1:operation>
+  </ns1:operations>
+  <ns1:resources>
+    <ns1:resource name="Financières">
+      <ns1:resource name="Compte courant">
+        <ns1:policy by="Finances" operation="Lire">
+          <ns1:rule grade="DOIT" grades="Règlementation"/>
+        </ns1:policy>
+        <ns1:policy by="Administration" operation="Lire">
+          <ns1:rule gradeMin="PEUT" grades="Règlementation"/>
+        </ns1:policy>
+      </ns1:resource>
+    </ns1:resource>
+  </ns1:resources>
+</ns1:commoning>
similarity index 95%
rename from test/Golden/RNC/Commoning/0002.xml
rename to test/Golden/RelaxNG/Commoning/0002.xml
index aae8cf7f0e243abddced5f9119adcbce6ccad276..5ba58be4b411462ac24414592484963cba19debc 100644 (file)
@@ -1,4 +1,4 @@
-<commoning xmlns="http://commonsoft.org/xml/2018/commoning.rnc">
+<commoning xmlns="2018/commoning.rnc">
        <persons>
                <person id="julm"/>
                <person id="john"/>
        <persons>
                <person id="julm"/>
                <person id="john"/>
                        <grade abbrev="B"  name="Bon"            color="green"/>
                        <grade abbrev="TB" name="Très Bon"       color="blue"/>
                 </grades>
                        <grade abbrev="B"  name="Bon"            color="green"/>
                        <grade abbrev="TB" name="Très Bon"       color="blue"/>
                 </grades>
-               <grades id="R�glementation">
+               <grades id="R�glementation">
                        <grade abbrev="NE-PEUT-PAS"    name="Ne peut pas"    color="black"/>
                        <grade abbrev="NE-DOIT-PAS"    name="Ne doit pas"    color="red"/>
                        <grade abbrev="NE-DEVRAIT-PAS" name="Ne devrait pas" color="orange"/>
                        <grade abbrev="NE-PEUT-PAS"    name="Ne peut pas"    color="black"/>
                        <grade abbrev="NE-DOIT-PAS"    name="Ne doit pas"    color="red"/>
                        <grade abbrev="NE-DEVRAIT-PAS" name="Ne devrait pas" color="orange"/>
-                       <grade abbrev="NON-R��GLEMENTÉ" name="Non-règlementé" color="#888"/>
+                       <grade abbrev="NON-R��GLEMENTÉ" name="Non-réglementé" color="#888"/>
                        <grade abbrev="PEUT"           name="Peut"           color="#FFD700"/>
                        <grade abbrev="DEVRAIT"        name="Devrait"        color="green"/>
                        <grade abbrev="DOIT"           name="Doit"           color="blue"/>
                        <grade abbrev="PEUT"           name="Peut"           color="#FFD700"/>
                        <grade abbrev="DEVRAIT"        name="Devrait"        color="green"/>
                        <grade abbrev="DOIT"           name="Doit"           color="blue"/>
similarity index 96%
rename from test/Golden/RNC/Commoning/0002.xml.read
rename to test/Golden/RelaxNG/Commoning/0002.xml.read
index a893ce0075b9fdbcd9fecceeae2fc70072e521d0..17aeeb1856cad5a4b4b566e2973ff7eb14d4be27 100644 (file)
@@ -1 +1 @@
-Commoning {commoning_persons = [Person {person_id = Ident "julm", person_fields = fromList []},Person {person_id = Ident "john", person_fields = fromList []}], commoning_opinions = [Grades {grades_id = Ident "Adh\233sion", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Fortement Contre", grade_abbrev = Just (Name "FC"), grade_color = Just "black"},Grade {grade_name = Name "Contre", grade_abbrev = Just (Name "C"), grade_color = Just "red"},Grade {grade_name = Name "Plut\244t Contre", grade_abbrev = Just (Name "PC"), grade_color = Just "orange"},Grade {grade_name = Name "Partag\233\183e", grade_abbrev = Just (Name "p"), grade_color = Just "#888"},Grade {grade_name = Name "Plut\244t Pour", grade_abbrev = Just (Name "PP"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Pour", grade_abbrev = Just (Name "P"), grade_color = Just "green"},Grade {grade_name = Name "Fortement Pour", grade_abbrev = Just (Name "FP"), grade_color = Just "blue"}]},Grades {grades_id = Ident "Qualit\233", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Tr\232s Mauvais", grade_abbrev = Just (Name "TM"), grade_color = Just "black"},Grade {grade_name = Name "Mauvais", grade_abbrev = Just (Name "M"), grade_color = Just "red"},Grade {grade_name = Name "Plut\244t Mauvais", grade_abbrev = Just (Name "PM"), grade_color = Just "orange"},Grade {grade_name = Name "Moyen", grade_abbrev = Just (Name "m"), grade_color = Just "#888"},Grade {grade_name = Name "Plut\244t Bon", grade_abbrev = Just (Name "PB"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Bon", grade_abbrev = Just (Name "B"), grade_color = Just "green"},Grade {grade_name = Name "Tr\232s Bon", grade_abbrev = Just (Name "TB"), grade_color = Just "blue"}]},Grades {grades_id = Ident "R\232glementation", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Ne peut pas", grade_abbrev = Just (Name "NE-PEUT-PAS"), grade_color = Just "black"},Grade {grade_name = Name "Ne doit pas", grade_abbrev = Just (Name "NE-DOIT-PAS"), grade_color = Just "red"},Grade {grade_name = Name "Ne devrait pas", grade_abbrev = Just (Name "NE-DEVRAIT-PAS"), grade_color = Just "orange"},Grade {grade_name = Name "Non-r\232glement\233", grade_abbrev = Just (Name "NON-R\200GLEMENT\201"), grade_color = Just "#888"},Grade {grade_name = Name "Peut", grade_abbrev = Just (Name "PEUT"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Devrait", grade_abbrev = Just (Name "DEVRAIT"), grade_color = Just "green"},Grade {grade_name = Name "Doit", grade_abbrev = Just (Name "DOIT"), grade_color = Just "blue"}]}], commoning_groups = fromList [Tree {unTree = NodeGroup {group_id = Ident "Public", group_name = Nothing, group_fields = fromList [], group_members = []}, subTrees = fromList []},Tree {unTree = NodeGroup {group_id = Ident "Assembl\233e", group_name = Just (Name "Assembl\233e G\233n\233rale"), group_fields = fromList [], group_members = []}, subTrees = fromList [Tree {unTree = NodeGroup {group_id = Ident "Infra", group_name = Just (Name "Infrastructure"), group_fields = fromList [], group_members = []}, subTrees = fromList []},Tree {unTree = NodeGroup {group_id = Ident "Modo", group_name = Just (Name "Mod\233ration"), group_fields = fromList [], group_members = []}, subTrees = fromList []}]}], commoning_operations = fromList [Tree {unTree = NodeOperation {operation_id = Ident "\201crire"}, subTrees = fromList [Tree {unTree = NodeOperation {operation_id = Ident "Lire"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Commenter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Proposer"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Ajouter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Modifier"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Supprimer"}, subTrees = fromList []}]},Tree {unTree = NodeOperation {operation_id = Ident "Ex\233cuter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Support"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Mod\233rer"}, subTrees = fromList []}], commoning_resources = fromList [Tree {unTree = NodeResource {resource_name = Name "Financi\232res", resource_policies = []}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "Compte courant", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Finances", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]},Policy {policy_operation = Name "Lire", policy_by = Ident "Administration", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Min (Name "PEUT")}]}]}, subTrees = fromList []}]},Tree {unTree = NodeResource {resource_name = Name "Informatique", resource_policies = [Policy {policy_operation = Name "Support", policy_by = Ident "Infra", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "Ordinateurs", resource_policies = []}, subTrees = fromList []},Tree {unTree = NodeResource {resource_name = Name "Service", resource_policies = [Policy {policy_operation = Name "AdminSys", policy_by = Ident "Infra", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]},Policy {policy_operation = Name "Mod\233rer", policy_by = Ident "Modo", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "DNS", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "example.coop", resource_policies = []}, subTrees = fromList []}]}]},Tree {unTree = NodeResource {resource_name = Name "Logiciels", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]},Policy {policy_operation = Name "Commenter", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]}]}, subTrees = fromList []}]}]}
\ No newline at end of file
+Commoning {commoning_persons = [Person {person_id = Ident "julm", person_fields = fromList []},Person {person_id = Ident "john", person_fields = fromList []}], commoning_opinions = [Grades {grades_id = Ident "Adh\233sion", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Fortement Contre", grade_abbrev = Just (Name "FC"), grade_color = Just "black"},Grade {grade_name = Name "Contre", grade_abbrev = Just (Name "C"), grade_color = Just "red"},Grade {grade_name = Name "Plut\244t Contre", grade_abbrev = Just (Name "PC"), grade_color = Just "orange"},Grade {grade_name = Name "Partag\233\183e", grade_abbrev = Just (Name "p"), grade_color = Just "#888"},Grade {grade_name = Name "Plut\244t Pour", grade_abbrev = Just (Name "PP"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Pour", grade_abbrev = Just (Name "P"), grade_color = Just "green"},Grade {grade_name = Name "Fortement Pour", grade_abbrev = Just (Name "FP"), grade_color = Just "blue"}]},Grades {grades_id = Ident "Qualit\233", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Tr\232s Mauvais", grade_abbrev = Just (Name "TM"), grade_color = Just "black"},Grade {grade_name = Name "Mauvais", grade_abbrev = Just (Name "M"), grade_color = Just "red"},Grade {grade_name = Name "Plut\244t Mauvais", grade_abbrev = Just (Name "PM"), grade_color = Just "orange"},Grade {grade_name = Name "Moyen", grade_abbrev = Just (Name "m"), grade_color = Just "#888"},Grade {grade_name = Name "Plut\244t Bon", grade_abbrev = Just (Name "PB"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Bon", grade_abbrev = Just (Name "B"), grade_color = Just "green"},Grade {grade_name = Name "Tr\232s Bon", grade_abbrev = Just (Name "TB"), grade_color = Just "blue"}]},Grades {grades_id = Ident "R\233glementation", grades_name = Nothing, grades_list = [Grade {grade_name = Name "Ne peut pas", grade_abbrev = Just (Name "NE-PEUT-PAS"), grade_color = Just "black"},Grade {grade_name = Name "Ne doit pas", grade_abbrev = Just (Name "NE-DOIT-PAS"), grade_color = Just "red"},Grade {grade_name = Name "Ne devrait pas", grade_abbrev = Just (Name "NE-DEVRAIT-PAS"), grade_color = Just "orange"},Grade {grade_name = Name "Non-r\233glement\233", grade_abbrev = Just (Name "NON-R\201GLEMENT\201"), grade_color = Just "#888"},Grade {grade_name = Name "Peut", grade_abbrev = Just (Name "PEUT"), grade_color = Just "#FFD700"},Grade {grade_name = Name "Devrait", grade_abbrev = Just (Name "DEVRAIT"), grade_color = Just "green"},Grade {grade_name = Name "Doit", grade_abbrev = Just (Name "DOIT"), grade_color = Just "blue"}]}], commoning_groups = fromList [Tree {unTree = NodeGroup {group_id = Ident "Public", group_name = Nothing, group_fields = fromList [], group_members = []}, subTrees = fromList []},Tree {unTree = NodeGroup {group_id = Ident "Assembl\233e", group_name = Just (Name "Assembl\233e G\233n\233rale"), group_fields = fromList [], group_members = []}, subTrees = fromList [Tree {unTree = NodeGroup {group_id = Ident "Infra", group_name = Just (Name "Infrastructure"), group_fields = fromList [], group_members = []}, subTrees = fromList []},Tree {unTree = NodeGroup {group_id = Ident "Modo", group_name = Just (Name "Mod\233ration"), group_fields = fromList [], group_members = []}, subTrees = fromList []}]}], commoning_operations = fromList [Tree {unTree = NodeOperation {operation_id = Ident "\201crire"}, subTrees = fromList [Tree {unTree = NodeOperation {operation_id = Ident "Lire"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Commenter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Proposer"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Ajouter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Modifier"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Supprimer"}, subTrees = fromList []}]},Tree {unTree = NodeOperation {operation_id = Ident "Ex\233cuter"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Support"}, subTrees = fromList []},Tree {unTree = NodeOperation {operation_id = Ident "Mod\233rer"}, subTrees = fromList []}], commoning_resources = fromList [Tree {unTree = NodeResource {resource_name = Name "Financi\232res", resource_policies = []}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "Compte courant", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Finances", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]},Policy {policy_operation = Name "Lire", policy_by = Ident "Administration", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Min (Name "PEUT")}]}]}, subTrees = fromList []}]},Tree {unTree = NodeResource {resource_name = Name "Informatique", resource_policies = [Policy {policy_operation = Name "Support", policy_by = Ident "Infra", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "Ordinateurs", resource_policies = []}, subTrees = fromList []},Tree {unTree = NodeResource {resource_name = Name "Service", resource_policies = [Policy {policy_operation = Name "AdminSys", policy_by = Ident "Infra", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]},Policy {policy_operation = Name "Mod\233rer", policy_by = Ident "Modo", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "DOIT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "DNS", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]}]}, subTrees = fromList [Tree {unTree = NodeResource {resource_name = Name "example.coop", resource_policies = []}, subTrees = fromList []}]}]},Tree {unTree = NodeResource {resource_name = Name "Logiciels", resource_policies = [Policy {policy_operation = Name "Lire", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]},Policy {policy_operation = Name "Commenter", policy_by = Ident "Public", policy_toward = Nothing, policy_rules = [Rule {rule_grades = Ident "R\232glementation", rule_gradeRange = GradeRange_Single (Name "PEUT")}]}]}, subTrees = fromList []}]}]}
\ No newline at end of file
diff --git a/test/Golden/RelaxNG/Commoning/0002.xml.write b/test/Golden/RelaxNG/Commoning/0002.xml.write
new file mode 100644 (file)
index 0000000..a013058
--- /dev/null
@@ -0,0 +1,95 @@
+<ns1:commoning xmlns:ns1="2018/commoning.rnc">
+  <ns1:persons>
+    <ns1:person id="julm"/>
+    <ns1:person id="john"/>
+  </ns1:persons>
+  <ns1:opinions>
+    <ns1:grades id="Adhésion">
+      <ns1:grade abbrev="FC" color="black" name="Fortement Contre"/>
+      <ns1:grade abbrev="C" color="red" name="Contre"/>
+      <ns1:grade abbrev="PC" color="orange" name="Plutôt Contre"/>
+      <ns1:grade abbrev="p" color="#888" name="Partagé·e"/>
+      <ns1:grade abbrev="PP" color="#FFD700" name="Plutôt Pour"/>
+      <ns1:grade abbrev="P" color="green" name="Pour"/>
+      <ns1:grade abbrev="FP" color="blue" name="Fortement Pour"/>
+    </ns1:grades>
+    <ns1:grades id="Qualité">
+      <ns1:grade abbrev="TM" color="black" name="Très Mauvais"/>
+      <ns1:grade abbrev="M" color="red" name="Mauvais"/>
+      <ns1:grade abbrev="PM" color="orange" name="Plutôt Mauvais"/>
+      <ns1:grade abbrev="m" color="#888" name="Moyen"/>
+      <ns1:grade abbrev="PB" color="#FFD700" name="Plutôt Bon"/>
+      <ns1:grade abbrev="B" color="green" name="Bon"/>
+      <ns1:grade abbrev="TB" color="blue" name="Très Bon"/>
+    </ns1:grades>
+    <ns1:grades id="Réglementation">
+      <ns1:grade abbrev="NE-PEUT-PAS" color="black" name="Ne peut pas"/>
+      <ns1:grade abbrev="NE-DOIT-PAS" color="red" name="Ne doit pas"/>
+      <ns1:grade abbrev="NE-DEVRAIT-PAS" color="orange" name="Ne devrait pas"/>
+      <ns1:grade abbrev="NON-RÉGLEMENTÉ" color="#888" name="Non-réglementé"/>
+      <ns1:grade abbrev="PEUT" color="#FFD700" name="Peut"/>
+      <ns1:grade abbrev="DEVRAIT" color="green" name="Devrait"/>
+      <ns1:grade abbrev="DOIT" color="blue" name="Doit"/>
+    </ns1:grades>
+  </ns1:opinions>
+  <ns1:groups>
+    <ns1:group id="Public"/>
+    <ns1:group id="Assemblée" name="Assemblée Générale">
+      <ns1:group id="Infra" name="Infrastructure"/>
+      <ns1:group id="Modo" name="Modération"/>
+    </ns1:group>
+  </ns1:groups>
+  <ns1:operations>
+    <ns1:operation id="Écrire">
+      <ns1:operation id="Lire"/>
+      <ns1:operation id="Commenter"/>
+      <ns1:operation id="Proposer"/>
+      <ns1:operation id="Ajouter"/>
+      <ns1:operation id="Modifier"/>
+      <ns1:operation id="Supprimer"/>
+    </ns1:operation>
+    <ns1:operation id="Exécuter"/>
+    <ns1:operation id="Support"/>
+    <ns1:operation id="Modérer"/>
+  </ns1:operations>
+  <ns1:resources>
+    <ns1:resource name="Financières">
+      <ns1:resource name="Compte courant">
+        <ns1:policy by="Finances" operation="Lire">
+          <ns1:rule grade="DOIT" grades="Règlementation"/>
+        </ns1:policy>
+        <ns1:policy by="Administration" operation="Lire">
+          <ns1:rule gradeMin="PEUT" grades="Règlementation"/>
+        </ns1:policy>
+      </ns1:resource>
+    </ns1:resource>
+    <ns1:resource name="Informatique">
+      <ns1:policy by="Infra" operation="Support">
+        <ns1:rule grade="DOIT" grades="Règlementation"/>
+      </ns1:policy>
+      <ns1:resource name="Ordinateurs"/>
+      <ns1:resource name="Service">
+        <ns1:policy by="Infra" operation="AdminSys">
+          <ns1:rule grade="DOIT" grades="Règlementation"/>
+        </ns1:policy>
+        <ns1:policy by="Modo" operation="Modérer">
+          <ns1:rule grade="DOIT" grades="Règlementation"/>
+        </ns1:policy>
+        <ns1:resource name="DNS">
+          <ns1:policy by="Public" operation="Lire">
+            <ns1:rule grade="PEUT" grades="Règlementation"/>
+          </ns1:policy>
+          <ns1:resource name="example.coop"/>
+        </ns1:resource>
+      </ns1:resource>
+      <ns1:resource name="Logiciels">
+        <ns1:policy by="Public" operation="Lire">
+          <ns1:rule grade="PEUT" grades="Règlementation"/>
+        </ns1:policy>
+        <ns1:policy by="Public" operation="Commenter">
+          <ns1:rule grade="PEUT" grades="Règlementation"/>
+        </ns1:policy>
+      </ns1:resource>
+    </ns1:resource>
+  </ns1:resources>
+</ns1:commoning>
diff --git a/test/Golden/RelaxNG/Whatever.rnc b/test/Golden/RelaxNG/Whatever.rnc
new file mode 100644 (file)
index 0000000..bd2895b
--- /dev/null
@@ -0,0 +1,5 @@
+default namespace = "2020/whatever.rnc"
+namespace ns1 = ""
+namespace whatever = "2020/whatever.rnc"
+namespace xsd = "http://www/w3/org/2001/XMLSchema-datatypes"
+root = element root {attribute a {text}, element child {element sub-child {empty}}}
diff --git a/test/Golden/RelaxNG/Whatever/00.xml b/test/Golden/RelaxNG/Whatever/00.xml
new file mode 100644 (file)
index 0000000..3031a56
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<root xmlns="2020/whatever.rnc" a="&lt;A&amp;&gt;&apos;&quot;">
+  <child>
+    <sub-child/>
+  </child>
+</root>
diff --git a/test/Golden/RelaxNG/Whatever/00.xml.read b/test/Golden/RelaxNG/Whatever/00.xml.read
new file mode 100644 (file)
index 0000000..62efdae
--- /dev/null
@@ -0,0 +1 @@
+Whatever {whatever_a = "<A&>'\""}
\ No newline at end of file
diff --git a/test/Golden/RelaxNG/Whatever/00.xml.write b/test/Golden/RelaxNG/Whatever/00.xml.write
new file mode 100644 (file)
index 0000000..64262ee
--- /dev/null
@@ -0,0 +1,5 @@
+<root xmlns="2020/whatever.rnc" xmlns:whatever="2020/whatever.rnc" a="&lt;A&amp;>'&quot;">
+  <child xmlns:what="2020/whatever.rnc">
+    <what:sub-child xmlns=""/>
+  </child>
+</root>
diff --git a/test/Golden/XML/0001.xml.ast b/test/Golden/XML/0001.xml.ast
deleted file mode 100644 (file)
index c685baa..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-(NodeElem root) @(test/Golden/XML/0001.xml#1:1-1:8 :| [])
-
index 075d257ab32597dec3cfc705dcd33a39a2052946..6ea3a1d7b644cf689bfe8d9f70fb7f794f625be5 100644 (file)
@@ -1,4 +1,2 @@
-(NodeElem root) @(test/Golden/XML/0001.xml@0-7 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0001.xml@7-8 :| [])
+NodeElem root (fromList []) in test/Golden/XML/0001.xml at char position 0 to 7
 
 
index d46192c39bbc452be4cfdad15e893f9b106473d6..f3f286eafc9c7138f37da2bc8ec3efd25d385e6b 100644 (file)
@@ -1,2 +1 @@
-
-<root/>
\ No newline at end of file
+<root/>
diff --git a/test/Golden/XML/0002.xml.ast b/test/Golden/XML/0002.xml.ast
deleted file mode 100644 (file)
index 6c8fe41..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-(NodeElem root) @(test/Golden/XML/0002.xml#1:1-1:14 :| [])
-
index 01c5adbe59c84f18772fffce0ec69655789c981f..418dc556fb17750c0dfc3eb3428715658a7ae04b 100644 (file)
@@ -1,4 +1,2 @@
-(NodeElem root) @(test/Golden/XML/0002.xml@0-13 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0002.xml@13-14 :| [])
+NodeElem root (fromList []) in test/Golden/XML/0002.xml at char position 0 to 13
 
 
index d46192c39bbc452be4cfdad15e893f9b106473d6..f3f286eafc9c7138f37da2bc8ec3efd25d385e6b 100644 (file)
@@ -1,2 +1 @@
-
-<root/>
\ No newline at end of file
+<root/>
diff --git a/test/Golden/XML/0003.xml.ast b/test/Golden/XML/0003.xml.ast
deleted file mode 100644 (file)
index e194ff6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-(NodeElem root) @(test/Golden/XML/0003.xml#1:1-1:15 :| [])
-|
-`- (NodeAttr n) @(test/Golden/XML/0003.xml#1:7-1:12 :| [])
-   |
-   `- (NodeText "v") @(test/Golden/XML/0003.xml#1:10-1:11 :| [])
-
index e946d40d7aa854cde453ab6240dee60307667b6b..4fd711d95ed6ec4bee72f248f8edf624fc576f8e 100644 (file)
@@ -1,8 +1,2 @@
-(NodeElem root) @(test/Golden/XML/0003.xml@0-14 :| [])
-|
-`- (NodeAttr n) @(test/Golden/XML/0003.xml@6-11 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "v"]))) @(test/Golden/XML/0003.xml@9-10 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0003.xml@14-15 :| [])
+NodeElem root (fromList [(n,EscapedAttr (fromList [EscapedPlain "v"]) in test/Golden/XML/0003.xml at char position 5 to 11)]) in test/Golden/XML/0003.xml at char position 0 to 14
 
 
index 44a5632ebaf6d03547150434f4ac431ed08d399b..1832db34229a61677203831bd92c2b83e228771c 100644 (file)
@@ -1,2 +1 @@
-
-<root n="v"/>
\ No newline at end of file
+<root n="v"/>
index e8303023a6d8a0e60148431c86df4c8a6163ae47..15ae567d710adf3c7c7a3fd517e6a5341b0077fc 100644 (file)
@@ -1,12 +1,12 @@
-(NodeElem doc) @(test/Golden/XML/0004.xml@0-33 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0004.xml at char position 0 to 33
 |
 |
-+- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0004.xml@5-7 :| [])
++- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0004.xml at char position 5 to 7
 |
 |
-+- (NodeElem a) @(test/Golden/XML/0004.xml@7-25 :| [])
++- NodeElem a (fromList []) in test/Golden/XML/0004.xml at char position 7 to 25
 |  |
 |  |
-|  `- (NodeElem b) @(test/Golden/XML/0004.xml@10-21 :| [])
+|  `- NodeElem b (fromList []) in test/Golden/XML/0004.xml at char position 10 to 21
 |     |
 |     |
-|     `- (NodeElem c) @(test/Golden/XML/0004.xml@13-17 :| [])
+|     `- NodeElem c (fromList []) in test/Golden/XML/0004.xml at char position 13 to 17
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0004.xml@25-27 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0004.xml at char position 25 to 27
 
 
index 961dfb3de0cc7358820b08e6caef3b42e62182a3..8247eb72851511e653332f1417e616022a2ce70d 100644 (file)
@@ -1,3 +1,7 @@
-<doc>\r
-<a><b><c/></b></a>\r
-</doc>
\ No newline at end of file
+<doc>
+  <a>
+    <b>
+      <c/>
+    </b>
+  </a>
+</doc>
index ce2ece7a936d04a41705ddbf05084ea1068dfaad..8247eb72851511e653332f1417e616022a2ce70d 100644 (file)
@@ -1,8 +1,7 @@
-
 <doc>
   <a>
     <b>
       <c/>
     </b>
   </a>
 <doc>
   <a>
     <b>
       <c/>
     </b>
   </a>
-</doc>
\ No newline at end of file
+</doc>
index 822b1e8bae98e221c05ea177664bd7639ec25e5c..958332bbc0597f11a5912fec0fef73d21546b58d 100644 (file)
@@ -1,38 +1,24 @@
-(NodeElem doc) @(test/Golden/XML/0005.xml@0-33 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0005.xml at char position 0 to 33
 |
 |
-+- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0005.xml@5-7 :| [])
++- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0005.xml at char position 5 to 7
 |
 |
-+- (NodeElem a) @(test/Golden/XML/0005.xml@7-25 :| [])
++- NodeElem a (fromList []) in test/Golden/XML/0005.xml at char position 7 to 25
 |  |
 |  |
-|  `- (NodeElem b) @(test/Golden/XML/0005.xml@10-21 :| [])
+|  `- NodeElem b (fromList []) in test/Golden/XML/0005.xml at char position 10 to 21
 |     |
 |     |
-|     `- (NodeElem c) @(test/Golden/XML/0005.xml@13-17 :| [])
+|     `- NodeElem c (fromList []) in test/Golden/XML/0005.xml at char position 13 to 17
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0005.xml@25-27 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0005.xml at char position 25 to 27
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@33-35 :| [])
+NodeComment " comment after document element" in test/Golden/XML/0005.xml at char position 35 to 73
 
 
-(NodeComment " comment after document element") @(test/Golden/XML/0005.xml@35-73 :| [])
+NodePI PI "after document element" in test/Golden/XML/0005.xml at char position 75 to 104
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@73-75 :| [])
+NodeComment " comment after document element" in test/Golden/XML/0005.xml at char position 106 to 144
 
 
-(NodePI PI "after document element") @(test/Golden/XML/0005.xml@75-104 :| [])
+NodePI PI "after document element" in test/Golden/XML/0005.xml at char position 146 to 175
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@104-106 :| [])
+NodeComment " comment after document element" in test/Golden/XML/0005.xml at char position 177 to 215
 
 
-(NodeComment " comment after document element") @(test/Golden/XML/0005.xml@106-144 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@144-146 :| [])
-
-(NodePI PI "after document element") @(test/Golden/XML/0005.xml@146-175 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@175-177 :| [])
-
-(NodeComment " comment after document element") @(test/Golden/XML/0005.xml@177-215 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@215-217 :| [])
-
-(NodePI PI "after document element") @(test/Golden/XML/0005.xml@217-246 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0005.xml@246-248 :| [])
+NodePI PI "after document element" in test/Golden/XML/0005.xml at char position 217 to 246
 
 
index cce3df5cd056f9a7b2ba2f55925c8e1c3d070a22..c4e01ee3403dabab9fee2d5453770afa20331709 100644 (file)
@@ -1,5 +1,9 @@
-<doc>\r
-<a><b><c/></b></a>\r
+<doc>
+  <a>
+    <b>
+      <c/>
+    </b>
+  </a>
 </doc>
 <!-- comment after document element-->
 <?PI after document element?>
 </doc>
 <!-- comment after document element-->
 <?PI after document element?>
index a54b0a826cc0d862c689d38ff93e3690312e33ac..c4e01ee3403dabab9fee2d5453770afa20331709 100644 (file)
@@ -1,4 +1,3 @@
-
 <doc>
   <a>
     <b>
 <doc>
   <a>
     <b>
@@ -11,4 +10,4 @@
 <!-- comment after document element-->
 <?PI after document element?>
 <!-- comment after document element-->
 <!-- comment after document element-->
 <?PI after document element?>
 <!-- comment after document element-->
-<?PI after document element?>
\ No newline at end of file
+<?PI after document element?>
index a99a3f9c5f3fd52e845879df277dfcdb718613c2..13312d623073b8c807104b7c39ee419ff342b677 100644 (file)
@@ -1,4 +1,2 @@
-(NodeText (EscapedText (fromList [EscapedPlain "\t\n "]))) @(test/Golden/XML/0006.xml@0-4 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0006.xml@4-10 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0006.xml at char position 4 to 10
 
 
index 339a4e34f5486ef2fcb4c5e3f4a2176c6036f919..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-       
- <doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index af2189848e4414eded4aeef60bbbfc7551590f98..0a6e955e5c2c24c188ffb5958b637af922a53dce 100644 (file)
@@ -1,20 +1,12 @@
-(NodeElem doc) @(test/Golden/XML/0007.xml@0-72 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0007.xml at char position 0 to 72
 |
 |
-+- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0007.xml@5-7 :| [])
++- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0007.xml at char position 5 to 7
 |
 |
-+- (NodeElem A) @(test/Golden/XML/0007.xml@7-40 :| [])
-|  |
-|  `- (NodeAttr a) @(test/Golden/XML/0007.xml@10-38 :| [])
-|     |
-|     `- (NodeText (EscapedText (fromList [EscapedPlain "asdf",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedEntityRef (EntityRef {entityRef_name = apos, entityRef_value = "'"}),EscapedCharRef (CharRef '"'),EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedPlain "\r\nasdf\r\n\t?",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedPlain "%"]))) @(test/Golden/XML/0007.xml@13-37 :| [])
++- NodeElem A (fromList [(a,EscapedAttr (fromList [EscapedPlain "asdf>'",EscapedCharRef (CharRef '"'),EscapedPlain ">\r\nasdf\r\n\t?>%"]) in test/Golden/XML/0007.xml at char position 9 to 38)]) in test/Golden/XML/0007.xml at char position 7 to 40
 |
 |
-+- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0007.xml@40-42 :| [])
++- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0007.xml at char position 40 to 42
 |
 |
-+- (NodeElem A) @(test/Golden/XML/0007.xml@42-64 :| [])
-|  |
-|  `- (NodeAttr a) @(test/Golden/XML/0007.xml@45-62 :| [])
-|     |
-|     `- (NodeText (EscapedText (fromList [EscapedEntityRef (EntityRef {entityRef_name = quot, entityRef_value = "\""}),EscapedEntityRef (EntityRef {entityRef_name = quot, entityRef_value = "\""}),EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedCharRef (CharRef '\''),EscapedCharRef (CharRef '"')]))) @(test/Golden/XML/0007.xml@48-61 :| [])
++- NodeElem A (fromList [(a,EscapedAttr (fromList [EscapedEntityRef (EntityRef {entityRef_name = quot, entityRef_value = "\""}),EscapedEntityRef (EntityRef {entityRef_name = quot, entityRef_value = "\""}),EscapedPlain ">",EscapedCharRef (CharRef '\''),EscapedCharRef (CharRef '"')]) in test/Golden/XML/0007.xml at char position 44 to 62)]) in test/Golden/XML/0007.xml at char position 42 to 64
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "\r\n"]))) @(test/Golden/XML/0007.xml@64-66 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "\r\n"])) in test/Golden/XML/0007.xml at char position 64 to 66
 
 
index 71f05e6d2bf576c30ce08abe3eefdb3083283739..29626e39672b6b780d483359b4cace043480f6f8 100644 (file)
@@ -1,6 +1,6 @@
-<doc>\r
-<A a="asdf>'&quot;>\r
+<doc>
+  <A a="asdf>'&#34;>\r
 asdf\r
 asdf\r
-       ?>%"/>\r
-<A a="&quot;&quot;>'&quot;"/>\r
-</doc>
\ No newline at end of file
+       ?>%"/>
+  <A a="&quot;&quot;>&#39;&#34;"/>
+</doc>
index 568b6a1f7ea5588d292a51366e0d2889a2e78990..29626e39672b6b780d483359b4cace043480f6f8 100644 (file)
@@ -1,7 +1,6 @@
-
 <doc>
 <doc>
-  <A a="asdf>'&quot;>\r
+  <A a="asdf>'&#34;>\r
 asdf\r
        ?>%"/>
 asdf\r
        ?>%"/>
-  <A a="&quot;&quot;>'&quot;"/>
-</doc>
\ No newline at end of file
+  <A a="&quot;&quot;>&#39;&#34;"/>
+</doc>
index bdae20ebbdceb477723b0d7ef6b08de8baff5c32..292aa31e6c592784e3379a927fdd760bfd3ba116 100644 (file)
@@ -1,6 +1,4 @@
-(NodeElem doc) @(test/Golden/XML/0008.xml@0-45 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0008.xml at char position 0 to 45
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "a%b%",EscapedEntityRef (EntityRef {entityRef_name = lt, entityRef_value = "<"}),EscapedPlain "/doc",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedCharRef (CharRef '<'),EscapedPlain "/doc",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedPlain "]]",EscapedEntityRef (EntityRef {entityRef_name = lt, entityRef_value = "<"}),EscapedEntityRef (EntityRef {entityRef_name = amp, entityRef_value = "&"})]))) @(test/Golden/XML/0008.xml@5-39 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0008.xml@45-47 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "a%b%",EscapedEntityRef (EntityRef {entityRef_name = lt, entityRef_value = "<"}),EscapedPlain "/doc",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedCharRef (CharRef '<'),EscapedPlain "/doc",EscapedEntityRef (EntityRef {entityRef_name = gt, entityRef_value = ">"}),EscapedPlain "]]",EscapedEntityRef (EntityRef {entityRef_name = lt, entityRef_value = "<"}),EscapedEntityRef (EntityRef {entityRef_name = amp, entityRef_value = "&"})])) in test/Golden/XML/0008.xml at char position 5 to 39
 
 
index bb89861a4eba53c2a54ca0f037be7ba3c0c36ecd..6f1c6b3df6a942d746d35d73cdc31759a2303c4b 100644 (file)
@@ -1,2 +1 @@
-
-<doc>a%b%&lt;/doc&gt;&#60;/doc&gt;]]&lt;&amp;</doc>
\ No newline at end of file
+<doc>a%b%&lt;/doc&gt;&#60;/doc&gt;]]&lt;&amp;</doc>
index fcb15a59de704683a5965b59bb4a77dddc7a1714..e16a80c2b6b48fbd0596b14b743305ae4163d012 100644 (file)
@@ -1,6 +1,4 @@
-(NodePI pitarget "'") @(test/Golden/XML/0009.xml@0-14 :| [])
+NodePI pitarget "'" in test/Golden/XML/0009.xml at char position 0 to 14
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0009.xml@14-16 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0009.xml@16-22 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0009.xml at char position 16 to 22
 
 
index db85499b91c1b1f3c6e178dc015e288efc60d5ac..497f69dc2e8c2cf766a86b7a8ac4d3f932813e52 100644 (file)
@@ -1,2 +1,2 @@
 <?pitarget '?>
 <?pitarget '?>
-<doc/>
\ No newline at end of file
+<doc/>
index d43736ac465ffd8284efad2db10af558b1acc6fe..497f69dc2e8c2cf766a86b7a8ac4d3f932813e52 100644 (file)
@@ -1,3 +1,2 @@
-
 <?pitarget '?>
 <?pitarget '?>
-<doc/>
\ No newline at end of file
+<doc/>
index 4817789b7d5c419cc37e910e3d81f653493b2b02..5cc071e5e27b5691c17aacd234b9c641ba142d9a 100644 (file)
@@ -1,6 +1,4 @@
-(NodePI pitarget "\"") @(test/Golden/XML/0010.xml@0-14 :| [])
+NodePI pitarget "\"" in test/Golden/XML/0010.xml at char position 0 to 14
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0010.xml@14-16 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0010.xml@16-22 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0010.xml at char position 16 to 22
 
 
index 4805e637eeaba2fe177c48f0c5081527227a0e44..41e6a7496a37e9dbe2a9a4cce2894f5d4050d788 100644 (file)
@@ -1,2 +1,2 @@
 <?pitarget "?>
 <?pitarget "?>
-<doc/>
\ No newline at end of file
+<doc/>
index 5292c0b3fbb2483322b393bfa1c3fb18f1b4c57d..41e6a7496a37e9dbe2a9a4cce2894f5d4050d788 100644 (file)
@@ -1,3 +1,2 @@
-
 <?pitarget "?>
 <?pitarget "?>
-<doc/>
\ No newline at end of file
+<doc/>
index 7a6da1b248a2fd41a87f2bcc8187c1fb2a4627a2..2a9395949f45c7738e179ec0a40c172ca395b416 100644 (file)
@@ -1,4 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0011.xml@0-6 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0011.xml@6-8 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0011.xml at char position 0 to 6
 
 
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index d8f291026c55d441efc00c5a262f7345b2eb87f1..892d5589951447505724a66a3a10776eca58467a 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0012.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0012.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0012.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0012.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0012.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0012.xml@21-23 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0012.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0012.xml@29-31 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0012.xml at char position 23 to 29
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 1ceaa05148eeae70b979ea8b6e0c376919374efb..55b4d5a169951a132ecb03e5becd9e055cf1c9ff 100644 (file)
@@ -1,20 +1,10 @@
-(NodePI xml "") @(test/Golden/XML/0013.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0013.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0013.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0013.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0013.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0013.xml@21-23 :| [])
+NodeComment "comment" in test/Golden/XML/0013.xml at char position 23 to 37
 
 
-(NodeComment "comment") @(test/Golden/XML/0013.xml@23-37 :| [])
+NodePI pi "" in test/Golden/XML/0013.xml at char position 38 to 44
 
 
-(NodeText (EscapedText (fromList [EscapedPlain " "]))) @(test/Golden/XML/0013.xml@37-38 :| [])
-
-(NodePI pi "") @(test/Golden/XML/0013.xml@38-44 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0013.xml@44-46 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0013.xml@46-52 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0013.xml@52-54 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0013.xml at char position 46 to 52
 
 
index f5da05de6cd7d0f2298bd39722cca6b145726cfe..f1fd73fa7c57818e29f5e2357f1f2ad28205f8dc 100644 (file)
@@ -1,3 +1,4 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<!--comment--> <?pi?>
+<!--comment-->
+<?pi?>
 <doc/>
 <doc/>
index beec8a7e86fb1741a08ab173a005c6d19924c21d..f1fd73fa7c57818e29f5e2357f1f2ad28205f8dc 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0"?>
 <!--comment-->
 <?pi?>
 <?xml version="1.0"?>
 <!--comment-->
 <?pi?>
-<doc/>
\ No newline at end of file
+<doc/>
index 0e6768b6ad297b0968bc5107b41a5db6d3b65a90..9a4c63e2d61529a2bbd6e084a0caf16f5521a908 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0014.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0014.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0014.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0014.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0014.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0014.xml@21-23 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0014.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0014.xml@29-31 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0014.xml at char position 23 to 29
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 6ee7fc2f5e6ce082cb5f261e93d97b1b2b92e517..a437e32691ce728c9d83c3e1b336c52aa380cc24 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0015.xml@0-38 :| [])
+NodePI xml "" in test/Golden/XML/0015.xml at char position 0 to 38
 |
 |
-+- (NodeAttr version) @(test/Golden/XML/0015.xml@5-19 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0015.xml@15-18 :| [])
++- NodePI version "1.0" in test/Golden/XML/0015.xml at char position 5 to 19
 |
 |
-`- (NodeAttr encoding) @(test/Golden/XML/0015.xml@19-36 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "UTF-8"]))) @(test/Golden/XML/0015.xml@30-35 :| [])
+`- NodePI encoding "UTF-8" in test/Golden/XML/0015.xml at char position 19 to 36
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0015.xml@38-40 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0015.xml@40-46 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0015.xml@46-48 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0015.xml at char position 40 to 46
 
 
index aa33d841ab5938f17b6b9286eadb92da35168982..354e12a7e2e140d679b0d6f2211494aa583f3dd8 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 56b1cf72b49fc643d105c022cde0b0f0b639ab79..3f94445c2918a248ee9dea44c4f136b80ff25b37 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0016.xml@0-38 :| [])
+NodePI xml "" in test/Golden/XML/0016.xml at char position 0 to 38
 |
 |
-+- (NodeAttr version) @(test/Golden/XML/0016.xml@5-19 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0016.xml@15-18 :| [])
++- NodePI version "1.0" in test/Golden/XML/0016.xml at char position 5 to 19
 |
 |
-`- (NodeAttr standalone) @(test/Golden/XML/0016.xml@19-30 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "yes"]))) @(test/Golden/XML/0016.xml@32-35 :| [])
+`- NodePI standalone "yes" in test/Golden/XML/0016.xml at char position 19 to 36
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0016.xml@38-40 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0016.xml@40-46 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0016.xml@46-48 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0016.xml at char position 40 to 46
 
 
index bd686ff8b10ffadbbb9ee8dc5d2251ba006162fe..ced689946e1ee08b65c0d1c1eff7cf3182f535f8 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0" standalone="yes"?>
 <?xml version="1.0" standalone="yes"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 5834c55f6eb3500afc93bb9f2944f259e216ed59..a1a0e2105422f08c6b41ce588d02936369c88c51 100644 (file)
@@ -1,20 +1,10 @@
-(NodePI xml "") @(test/Golden/XML/0017.xml@0-55 :| [])
+NodePI xml "" in test/Golden/XML/0017.xml at char position 0 to 55
 |
 |
-+- (NodeAttr version) @(test/Golden/XML/0017.xml@5-19 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0017.xml@15-18 :| [])
++- NodePI version "1.0" in test/Golden/XML/0017.xml at char position 5 to 19
 |
 |
-+- (NodeAttr encoding) @(test/Golden/XML/0017.xml@19-36 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "UTF-8"]))) @(test/Golden/XML/0017.xml@30-35 :| [])
++- NodePI encoding "UTF-8" in test/Golden/XML/0017.xml at char position 19 to 36
 |
 |
-`- (NodeAttr standalone) @(test/Golden/XML/0017.xml@36-47 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "yes"]))) @(test/Golden/XML/0017.xml@49-52 :| [])
+`- NodePI standalone "yes" in test/Golden/XML/0017.xml at char position 36 to 53
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0017.xml@55-57 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0017.xml@57-63 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0017.xml@63-65 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0017.xml at char position 57 to 63
 
 
index bfd7c91eac07a0650ccdc449e18396f4cd01215f..0a992900c91eae6093a74b493148b63966050bd4 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 526fd51b01a86d0a7d59be122ac406053adf2bca..20bddd29bc533ac12610074810cac4655ca3279e 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0018.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0018.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0018.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0018.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0018.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0018.xml@21-23 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0018.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0018.xml@29-31 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0018.xml at char position 23 to 29
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index ce1f73940433996adf5895400d77d3ba247c4797..e550f9e9955cf8f5b8ab1ca35e78af606a36181d 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0019.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0019.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0019.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0019.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0019.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0019.xml@21-23 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0019.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0019.xml@29-31 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0019.xml at char position 23 to 29
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 7f60babaa9af0207c77acac1b0f6f908352ab031..7199d5799060c2c1a681178ba9d3fc6bc730c2f5 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0020.xml@0-32 :| [])
+NodePI xml "" in test/Golden/XML/0020.xml at char position 0 to 32
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0020.xml@5-28 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0020.xml@24-27 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0020.xml at char position 5 to 28
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0020.xml@32-34 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0020.xml@34-40 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0020.xml@40-42 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0020.xml at char position 34 to 40
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index cb4e152ffdeb1dfbce47666832e1ead29765de7a..33f66cc33cbf17acb49d1998f90bb6256eaeb967 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0021.xml@0-23 :| [])
+NodePI xml "" in test/Golden/XML/0021.xml at char position 0 to 23
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0021.xml@5-21 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0021.xml@17-20 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0021.xml at char position 5 to 21
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0021.xml@23-25 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0021.xml@25-31 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0021.xml@31-33 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0021.xml at char position 25 to 31
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 77383e059c542e5df136d1fd095618642b323b9e..18c3fea230a073c1583b6b3bdc6a5f38be25a35a 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0022.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0022.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0022.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0022.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0022.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0022.xml@21-23 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0022.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0022.xml@29-31 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0022.xml at char position 23 to 29
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index a1dcb323121c24749d66cce5d0b35b90e39184af..f8acbea1329953834f6e85bdc21f723d77046ba7 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0023.xml@0-37 :| [])
+NodePI xml "" in test/Golden/XML/0023.xml at char position 0 to 37
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0023.xml@5-35 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0023.xml@31-34 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0023.xml at char position 5 to 35
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0023.xml@37-39 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0023.xml@39-45 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0023.xml@45-47 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0023.xml at char position 39 to 45
 
 
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index ce13f288e1a4cf485d8d227ef77f06c29e293129..adbb73687ae8ef15c060282b96f29e2f645cd869 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0024.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0024.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0024.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0024.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0024.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0024.xml@21-23 :| [])
+NodeComment "because we are testing conformace to XML 1.0, there can be no\r\n    exhaustive tests of the VersionNum production.  The only\r\n    VersionNum a 1.0-compliant processor is required to pass\r\n    is \"1.0\" " in test/Golden/XML/0024.xml at char position 23 to 230
 
 
-(NodeComment "because we are testing conformace to XML 1.0, there can be no\r\n    exhaustive tests of the VersionNum production.  The only\r\n    VersionNum a 1.0-compliant processor is required to pass\r\n    is \"1.0\" ") @(test/Golden/XML/0024.xml@23-230 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0024.xml@230-232 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0024.xml@232-238 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0024.xml@238-240 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0024.xml at char position 232 to 238
 
 
index 85b175a99c2c51236cbed6111e5af006c70237bd..dff4d92d39b3c7d7510da57a25609b3583016a33 100644 (file)
@@ -3,4 +3,4 @@
     exhaustive tests of the VersionNum production.  The only\r
     VersionNum a 1.0-compliant processor is required to pass\r
     is "1.0" -->
     exhaustive tests of the VersionNum production.  The only\r
     VersionNum a 1.0-compliant processor is required to pass\r
     is "1.0" -->
-<doc/>
\ No newline at end of file
+<doc/>
index 8fd5f766a608c2d4a4b85c0f92c3816725bc8cd0..893edf2dc4f8add1fde0d2e12db026f0a0ffb8b3 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0025.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0025.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0025.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0025.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0025.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0025.xml@21-23 :| [])
+NodeComment "Non-terminal Misc only appears as Misc*, so we cannot test the fact\r\n    that Misc must match exactly one comment, PI, or S" in test/Golden/XML/0025.xml at char position 23 to 153
 
 
-(NodeComment "Non-terminal Misc only appears as Misc*, so we cannot test the fact\r\n    that Misc must match exactly one comment, PI, or S") @(test/Golden/XML/0025.xml@23-153 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0025.xml@153-155 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0025.xml@155-161 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0025.xml@161-163 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0025.xml at char position 155 to 161
 
 
index 1eca3ea4fad31a8b2d0f313dca312724867a5839..7c37e55ec4a882c137ab2f42931b5980ea65da21 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0"?>
 <!--Non-terminal Misc only appears as Misc*, so we cannot test the fact\r
     that Misc must match exactly one comment, PI, or S-->
 <?xml version="1.0"?>
 <!--Non-terminal Misc only appears as Misc*, so we cannot test the fact\r
     that Misc must match exactly one comment, PI, or S-->
-<doc/>
\ No newline at end of file
+<doc/>
index 21a383b6551ebd07d9d2f7cd8cc5b4654c52f66b..2138228432f22ccdceee0f010c0c3f904f3b97f7 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0026.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0026.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0026.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0026.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0026.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0026.xml@21-23 :| [])
+NodePI pi "" in test/Golden/XML/0026.xml at char position 23 to 29
 
 
-(NodePI pi "") @(test/Golden/XML/0026.xml@23-29 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0026.xml@29-31 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0026.xml@31-37 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0026.xml@37-39 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0026.xml at char position 31 to 37
 
 
index a306461b8c3c1eb6c3dec7759fa31a283773f14d..5673efd54638e66fe94406ee7d5df36b0ce42b8e 100644 (file)
@@ -1,3 +1,3 @@
 <?xml version="1.0"?>
 <?pi?>
 <?xml version="1.0"?>
 <?pi?>
-<doc/>
\ No newline at end of file
+<doc/>
index 36546304a10dbb07e4a1c943ea272f5409091152..cb825be285d602d5215717d1b40e8cd86202c1ae 100644 (file)
@@ -1,12 +1,6 @@
-(NodePI xml "") @(test/Golden/XML/0027.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0027.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0027.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0027.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0027.xml at char position 5 to 19
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n\n \t\n\n"]))) @(test/Golden/XML/0027.xml@21-31 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0027.xml@31-37 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0027.xml@37-39 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0027.xml at char position 31 to 37
 
 
index 912c601400fa436be6ae589eb1f4cf1ed0c5f94b..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,5 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-
-       
-
 <doc/>
 <doc/>
index 7b4f7436d9b7207605f5c9d13e7015289a22ad5f..8e39ecbe54549bfeaa70f9dbd47f6e6a5a712de5 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0"?>
 <?xml version="1.0"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 19a4d7ea1a89024ed5560bc991452e050aef448d..3a9568c777179107eb8c40dcf5c574cf2780ebf2 100644 (file)
@@ -1,28 +1,16 @@
-(NodePI xml "") @(test/Golden/XML/0028.xml@0-21 :| [])
+NodePI xml "" in test/Golden/XML/0028.xml at char position 0 to 21
 |
 |
-`- (NodeAttr version) @(test/Golden/XML/0028.xml@5-19 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0028.xml@15-18 :| [])
+`- NodePI version "1.0" in test/Golden/XML/0028.xml at char position 5 to 19
 
 
-(NodePI pi "") @(test/Golden/XML/0028.xml@21-27 :| [])
+NodePI pi "" in test/Golden/XML/0028.xml at char position 21 to 27
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n\n \t\n\n"]))) @(test/Golden/XML/0028.xml@27-37 :| [])
+NodeComment "comment" in test/Golden/XML/0028.xml at char position 37 to 51
 
 
-(NodeComment "comment") @(test/Golden/XML/0028.xml@37-51 :| [])
+NodePI pi "" in test/Golden/XML/0028.xml at char position 53 to 59
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0028.xml@51-53 :| [])
+NodeComment "comment" in test/Golden/XML/0028.xml at char position 69 to 83
 
 
-(NodePI pi "") @(test/Golden/XML/0028.xml@53-59 :| [])
+NodePI pi "" in test/Golden/XML/0028.xml at char position 85 to 91
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n\n \t\n\n"]))) @(test/Golden/XML/0028.xml@59-69 :| [])
-
-(NodeComment "comment") @(test/Golden/XML/0028.xml@69-83 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0028.xml@83-85 :| [])
-
-(NodePI pi "") @(test/Golden/XML/0028.xml@85-91 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0028.xml@91-97 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0028.xml@97-99 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0028.xml at char position 91 to 97
 
 
index aa4da668500ecac68cc647f6ba4e8d16fcdeef46..dd1cc5f870d7207131627de881824b48bc79d6a9 100644 (file)
@@ -1,11 +1,7 @@
-<?xml version="1.0"?><?pi?>
-
-       
-
+<?xml version="1.0"?>
+<?pi?>
 <!--comment-->
 <?pi?>
 <!--comment-->
 <?pi?>
-
-       
-
 <!--comment-->
 <!--comment-->
-<?pi?><doc/>
+<?pi?>
+<doc/>
index f27efc09104d2b4871576074042f61de20afba74..dd1cc5f870d7207131627de881824b48bc79d6a9 100644 (file)
@@ -4,4 +4,4 @@
 <?pi?>
 <!--comment-->
 <?pi?>
 <?pi?>
 <!--comment-->
 <?pi?>
-<doc/>
\ No newline at end of file
+<doc/>
index b304310fda30153c21fe703115f22a15c33626db..4cdb16ac8b0912f0f776a5c6de6f60afafcada69 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0029.xml@0-38 :| [])
+NodePI xml "" in test/Golden/XML/0029.xml at char position 0 to 38
 |
 |
-+- (NodeAttr version) @(test/Golden/XML/0029.xml@5-19 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0029.xml@15-18 :| [])
++- NodePI version "1.0" in test/Golden/XML/0029.xml at char position 5 to 19
 |
 |
-`- (NodeAttr standalone) @(test/Golden/XML/0029.xml@19-30 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "yes"]))) @(test/Golden/XML/0029.xml@32-35 :| [])
+`- NodePI standalone "yes" in test/Golden/XML/0029.xml at char position 19 to 36
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0029.xml@38-40 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0029.xml@40-46 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0029.xml@46-48 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0029.xml at char position 40 to 46
 
 
index bd686ff8b10ffadbbb9ee8dc5d2251ba006162fe..ced689946e1ee08b65c0d1c1eff7cf3182f535f8 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0" standalone="yes"?>
 <?xml version="1.0" standalone="yes"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 1849afdc293e799c9438197c5a8a97c94d34ce37..b559c13e43c764dcee11b0cd500f0bd5d99932b3 100644 (file)
@@ -1,16 +1,8 @@
-(NodePI xml "") @(test/Golden/XML/0030.xml@0-37 :| [])
+NodePI xml "" in test/Golden/XML/0030.xml at char position 0 to 37
 |
 |
-+- (NodeAttr version) @(test/Golden/XML/0030.xml@5-19 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "1.0"]))) @(test/Golden/XML/0030.xml@15-18 :| [])
++- NodePI version "1.0" in test/Golden/XML/0030.xml at char position 5 to 19
 |
 |
-`- (NodeAttr standalone) @(test/Golden/XML/0030.xml@19-30 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "no"]))) @(test/Golden/XML/0030.xml@32-34 :| [])
+`- NodePI standalone "no" in test/Golden/XML/0030.xml at char position 19 to 35
 
 
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0030.xml@37-39 :| [])
-
-(NodeElem doc) @(test/Golden/XML/0030.xml@39-45 :| [])
-
-(NodeText (EscapedText (fromList [EscapedPlain "\n"]))) @(test/Golden/XML/0030.xml@45-47 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0030.xml at char position 39 to 45
 
 
index b93cc8ffd21ac5897f1581b9f50b311ed6f612ef..aebf579c18a1a1a8e2f69300906e9fae238dc9fb 100644 (file)
@@ -1,2 +1,2 @@
 <?xml version="1.0" standalone="no"?>
 <?xml version="1.0" standalone="no"?>
-<doc/>
\ No newline at end of file
+<doc/>
index 15b46dabc4f1d7dea6fc14df24e8d210ac2dacfc..fee10f80d2f8a3890401bc04fff07df14b109c13 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0031.xml@0-6 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0031.xml at char position 0 to 6
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index 30e6cc1166ce9d9b9c3915da54b7b1e04cc38803..024794b5481f05debcd345413f6bd24044bb17d2 100644 (file)
@@ -1,4 +1,4 @@
-(NodeElem doc) @(test/Golden/XML/0032.xml@0-18 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0032.xml at char position 0 to 18
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "content"]))) @(test/Golden/XML/0032.xml@5-12 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "content"])) in test/Golden/XML/0032.xml at char position 5 to 12
 
 
index 5b47e63d1aad77fdb822e96d6c8e108866d88a78..a225647d1b0a3bd55363d1cd6f900dc069f5a346 100644 (file)
@@ -1 +1 @@
-<doc>content</doc>
\ No newline at end of file
+<doc>content</doc>
index ea4c0ca8131123fcd8a54ce172c939dbdd09f547..a225647d1b0a3bd55363d1cd6f900dc069f5a346 100644 (file)
@@ -1,2 +1 @@
-
-<doc>content</doc>
\ No newline at end of file
+<doc>content</doc>
index 739a4f9cb4bc989cddab00987ef9cbe500fba4b9..23ef168d996693b43483b8cc6fd0518aea8d6681 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0033.xml@0-11 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0033.xml at char position 0 to 11
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index 9130de15c9f4a87d6cc4a9bd5f74782220fc914f..8c161e3505bed2ce97e8d723ee3172be65c1c931 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0034.xml@0-16 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0034.xml at char position 0 to 16
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index 64c22731533a6514ed2a13861aa8318544124641..b825ab5178b8696a78d785d2e96b4696e45e9548 100644 (file)
@@ -1,6 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0035.xml@0-21 :| [])
-|
-`- (NodeAttr att) @(test/Golden/XML/0035.xml@5-14 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0035.xml@10-13 :| [])
+NodeElem doc (fromList [(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0035.xml at char position 4 to 14)]) in test/Golden/XML/0035.xml at char position 0 to 21
 
 
index 1ea50d325c3074d86c10d8c7bd22b20b48e748e4..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1 +1 @@
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 45edd509e52468ae159f99e8bb3f87ccbb2aa6c9..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index f2bdbed5258b9dccdd5e3f132bbca252f6c32e3d..42303b6f1dccb216c86485044ccd2de369f081ce 100644 (file)
@@ -1,14 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0036.xml@0-48 :| [])
-|
-+- (NodeAttr att) @(test/Golden/XML/0036.xml@5-14 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0036.xml@10-13 :| [])
-|
-+- (NodeAttr att2) @(test/Golden/XML/0036.xml@15-26 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "val2"]))) @(test/Golden/XML/0036.xml@21-25 :| [])
-|
-`- (NodeAttr att3) @(test/Golden/XML/0036.xml@28-39 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val3"]))) @(test/Golden/XML/0036.xml@34-38 :| [])
+NodeElem doc (fromList [(att3,EscapedAttr (fromList [EscapedPlain "val3"]) in test/Golden/XML/0036.xml at char position 26 to 39),(att2,EscapedAttr (fromList [EscapedPlain "val2"]) in test/Golden/XML/0036.xml at char position 14 to 26),(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0036.xml at char position 4 to 14)]) in test/Golden/XML/0036.xml at char position 0 to 48
 
 
index e015116537d349805f4214da6d7b03c22d4f4c9b..1098e3f4b9070bac02edf413bbab9aff619cdf4f 100644 (file)
@@ -1 +1 @@
-<doc att="val" att2="val2" att3="val3"/>
\ No newline at end of file
+<doc att="val" att2="val2" att3="val3"/>
index 99deda77a64c8f2f1f74445cd9e9c840d0b3bce8..1098e3f4b9070bac02edf413bbab9aff619cdf4f 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val" att2="val2" att3="val3"/>
\ No newline at end of file
+<doc att="val" att2="val2" att3="val3"/>
index 006d6f3794531300d04103f542e7a562693fd47c..76d3a33fccc579127ca79f0279daea9948b660de 100644 (file)
@@ -1,6 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0037.xml@0-21 :| [])
-|
-`- (NodeAttr att) @(test/Golden/XML/0037.xml@5-14 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0037.xml@10-13 :| [])
+NodeElem doc (fromList [(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0037.xml at char position 4 to 14)]) in test/Golden/XML/0037.xml at char position 0 to 21
 
 
index 1ea50d325c3074d86c10d8c7bd22b20b48e748e4..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1 +1 @@
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 45edd509e52468ae159f99e8bb3f87ccbb2aa6c9..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 93cb626231286379ea6ffb409b3512f230b57763..756a3b4ae367919dc0886e144a3bfc6516619908 100644 (file)
@@ -1,6 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0038.xml@0-28 :| [])
-|
-`- (NodeAttr att) @(test/Golden/XML/0038.xml@5-21 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0038.xml@17-20 :| [])
+NodeElem doc (fromList [(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0038.xml at char position 4 to 21)]) in test/Golden/XML/0038.xml at char position 0 to 28
 
 
index 1ea50d325c3074d86c10d8c7bd22b20b48e748e4..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1 +1 @@
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 45edd509e52468ae159f99e8bb3f87ccbb2aa6c9..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index e4c75688f10d3535aab4424605564f62ba3a0ee3..6b93bb8eb77e48a7f0e47a600623a349c2300a32 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0039.xml@0-11 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0039.xml at char position 0 to 11
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index 882b70c28b45527cd779d40a8687c23abea81812..1901870b12e4e608358c7b32cf516316f3abc39c 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0040.xml@0-15 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0040.xml at char position 0 to 15
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index d6d464031e3fa56af755135e7650f75990e9b677..c2c20f58ab26392ba08a65e859acc299ffcf1c1c 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0041.xml@0-6 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0041.xml at char position 0 to 6
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index c9df3d34189f0fdbc10998ea2c9043a52bb830ed..905ddb443985bf36f692cf55ec39906bc9a413ff 100644 (file)
@@ -1,6 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0042.xml@0-16 :| [])
-|
-`- (NodeAttr att) @(test/Golden/XML/0042.xml@5-14 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0042.xml@10-13 :| [])
+NodeElem doc (fromList [(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0042.xml at char position 4 to 14)]) in test/Golden/XML/0042.xml at char position 0 to 16
 
 
index 1ea50d325c3074d86c10d8c7bd22b20b48e748e4..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1 +1 @@
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 45edd509e52468ae159f99e8bb3f87ccbb2aa6c9..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index e0f1cfb8120480e431addc71af84582cb19cee8d..41071b433d565040bb4b4ba6c541d8c4f105df1e 100644 (file)
@@ -1,6 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0043.xml@0-22 :| [])
-|
-`- (NodeAttr att) @(test/Golden/XML/0043.xml@5-14 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0043.xml@10-13 :| [])
+NodeElem doc (fromList [(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0043.xml at char position 4 to 14)]) in test/Golden/XML/0043.xml at char position 0 to 22
 
 
index 1ea50d325c3074d86c10d8c7bd22b20b48e748e4..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1 +1 @@
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index 45edd509e52468ae159f99e8bb3f87ccbb2aa6c9..9288e1ea87fed81873484b8d42591b5dfa60311c 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val"/>
\ No newline at end of file
+<doc att="val"/>
index e12c76d95aed917f7878b738ad3a268a1b9fe593..c4e17b2f73b5e83c3875b3188c5cf6bfcf9219a3 100644 (file)
@@ -1,2 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0044.xml@0-12 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0044.xml at char position 0 to 12
 
 
index ff29a91370f76c53086929f3cbc7686369dde8a8..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1 +1 @@
-<doc/>
\ No newline at end of file
+<doc/>
index b91a1a01be8b44a1fe6c3bcf67a8d875506ee794..69d62f2c9aef314c16555933c4938b1b430a52ab 100644 (file)
@@ -1,2 +1 @@
-
-<doc/>
\ No newline at end of file
+<doc/>
index b0311a2497bd7d63ad44c7bbedac60eaee33bc16..d0a2b134bc91e787851017917146e6c488fd851a 100644 (file)
@@ -1,14 +1,2 @@
-(NodeElem doc) @(test/Golden/XML/0045.xml@0-41 :| [])
-|
-+- (NodeAttr att) @(test/Golden/XML/0045.xml@5-14 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "val"]))) @(test/Golden/XML/0045.xml@10-13 :| [])
-|
-+- (NodeAttr att2) @(test/Golden/XML/0045.xml@16-27 :| [])
-|  |
-|  `- (NodeText (EscapedText (fromList [EscapedPlain "val2"]))) @(test/Golden/XML/0045.xml@22-26 :| [])
-|
-`- (NodeAttr att3) @(test/Golden/XML/0045.xml@28-39 :| [])
-   |
-   `- (NodeText (EscapedText (fromList [EscapedPlain "val3"]))) @(test/Golden/XML/0045.xml@34-38 :| [])
+NodeElem doc (fromList [(att3,EscapedAttr (fromList [EscapedPlain "val3"]) in test/Golden/XML/0045.xml at char position 27 to 39),(att2,EscapedAttr (fromList [EscapedPlain "val2"]) in test/Golden/XML/0045.xml at char position 14 to 27),(att,EscapedAttr (fromList [EscapedPlain "val"]) in test/Golden/XML/0045.xml at char position 4 to 14)]) in test/Golden/XML/0045.xml at char position 0 to 41
 
 
index e015116537d349805f4214da6d7b03c22d4f4c9b..1098e3f4b9070bac02edf413bbab9aff619cdf4f 100644 (file)
@@ -1 +1 @@
-<doc att="val" att2="val2" att3="val3"/>
\ No newline at end of file
+<doc att="val" att2="val2" att3="val3"/>
index 99deda77a64c8f2f1f74445cd9e9c840d0b3bce8..1098e3f4b9070bac02edf413bbab9aff619cdf4f 100644 (file)
@@ -1,2 +1 @@
-
-<doc att="val" att2="val2" att3="val3"/>
\ No newline at end of file
+<doc att="val" att2="val2" att3="val3"/>
index 290bdb02cb7c4b85973938e4012eb038c23278ca..ec48a2b6cd682707d8ab197cc4cb33f74a7afd2b 100644 (file)
@@ -1,4 +1,4 @@
-(NodeElem doc) @(test/Golden/XML/0046.xml@0-81 :| [])
+NodeElem doc (fromList []) in test/Golden/XML/0046.xml at char position 0 to 81
 |
 |
-`- (NodeText (EscapedText (fromList [EscapedPlain "\r\n",EscapedCharRef (CharRef 'A'),EscapedCharRef (CharRef '\t'),EscapedCharRef (CharRef 'A'),EscapedCharRef (CharRef 'O'),EscapedCharRef (CharRef 'O'),EscapedCharRef (CharRef '\t'),EscapedPlain "\r\n",EscapedCharRef (CharRef '\1110764'),EscapedCharRef (CharRef '\n'),EscapedPlain "\r\n"]))) @(test/Golden/XML/0046.xml@5-75 :| [])
+`- NodeText (EscapedText (fromList [EscapedPlain "\r\n",EscapedCharRef (CharRef 'A'),EscapedCharRef (CharRef '\t'),EscapedCharRef (CharRef 'A'),EscapedCharRef (CharRef 'O'),EscapedCharRef (CharRef 'O'),EscapedCharRef (CharRef '\t'),EscapedPlain "\r\n",EscapedCharRef (CharRef '\1110764'),EscapedCharRef (CharRef '\n'),EscapedPlain "\r\n"])) in test/Golden/XML/0046.xml at char position 5 to 75
 
 
index c4988b55d352f0222190f2b32b4b3b8d50025a08..2692561cb6d7fbaa09793ae7401dec2693b3cf52 100644 (file)
@@ -1,4 +1,4 @@
 <doc>\r
 &#65;&#9;&#65;&#79;&#79;&#9;\r
 &#1110764;&#10;\r
 <doc>\r
 &#65;&#9;&#65;&#79;&#79;&#9;\r
 &#1110764;&#10;\r
-</doc>
\ No newline at end of file
+</doc>
index afe74ce59c7cf0f4b986b0044e33a6eaea2c2177..2692561cb6d7fbaa09793ae7401dec2693b3cf52 100644 (file)
@@ -1,5 +1,4 @@
-
 <doc>\r
 &#65;&#9;&#65;&#79;&#79;&#9;\r
 &#1110764;&#10;\r
 <doc>\r
 &#65;&#9;&#65;&#79;&#79;&#9;\r
 &#1110764;&#10;\r
-</doc>
\ No newline at end of file
+</doc>
diff --git a/test/Golden/XML/0047.xml b/test/Golden/XML/0047.xml
new file mode 100644 (file)
index 0000000..a86a7d0
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+<dict>
+    <!-- these aren't the droids you're looking for -->
+    <!---><!-->
+    <key>platform-application</key>
+    <true/>
+    <key>com.apple.private.security.no-container</key>
+    <true/>
+    <key>task_for_pid-allow</key>
+    <true/>
+    <!-- -->
+</dict>
+</plist>
diff --git a/test/Golden/XML/0047.xml.read b/test/Golden/XML/0047.xml.read
new file mode 100644 (file)
index 0000000..c5d995f
--- /dev/null
@@ -0,0 +1,58 @@
+NodePI xml "" in test/Golden/XML/0047.xml at char position 0 to 38
+|
++- NodePI version "1.0" in test/Golden/XML/0047.xml at char position 5 to 19
+|
+`- NodePI encoding "UTF-8" in test/Golden/XML/0047.xml at char position 19 to 36
+
+NodeElem plist (fromList [(version,EscapedAttr (fromList [EscapedPlain "1.0"]) in test/Golden/XML/0047.xml at char position 45 to 59)]) in test/Golden/XML/0047.xml at char position 39 to 330
+|
++- NodeText (EscapedText (fromList [EscapedPlain "\n"])) in test/Golden/XML/0047.xml at char position 60 to 61
+|
++- NodeElem dict (fromList []) in test/Golden/XML/0047.xml at char position 61 to 321
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 67 to 72
+|  |
+|  +- NodeComment " these aren't the droids you're looking for " in test/Golden/XML/0047.xml at char position 72 to 123
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 123 to 128
+|  |
+|  +- NodeComment "-><!" in test/Golden/XML/0047.xml at char position 128 to 139
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 139 to 144
+|  |
+|  +- NodeElem key (fromList []) in test/Golden/XML/0047.xml at char position 144 to 175
+|  |  |
+|  |  `- NodeText (EscapedText (fromList [EscapedPlain "platform-application"])) in test/Golden/XML/0047.xml at char position 149 to 169
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 175 to 180
+|  |
+|  +- NodeElem true (fromList []) in test/Golden/XML/0047.xml at char position 180 to 187
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 187 to 192
+|  |
+|  +- NodeElem key (fromList []) in test/Golden/XML/0047.xml at char position 192 to 242
+|  |  |
+|  |  `- NodeText (EscapedText (fromList [EscapedPlain "com.apple.private.security.no-container"])) in test/Golden/XML/0047.xml at char position 197 to 236
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 242 to 247
+|  |
+|  +- NodeElem true (fromList []) in test/Golden/XML/0047.xml at char position 247 to 254
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 254 to 259
+|  |
+|  +- NodeElem key (fromList []) in test/Golden/XML/0047.xml at char position 259 to 288
+|  |  |
+|  |  `- NodeText (EscapedText (fromList [EscapedPlain "task_for_pid-allow"])) in test/Golden/XML/0047.xml at char position 264 to 282
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 288 to 293
+|  |
+|  +- NodeElem true (fromList []) in test/Golden/XML/0047.xml at char position 293 to 300
+|  |
+|  +- NodeText (EscapedText (fromList [EscapedPlain "\n    "])) in test/Golden/XML/0047.xml at char position 300 to 305
+|  |
+|  +- NodeComment " " in test/Golden/XML/0047.xml at char position 305 to 313
+|  |
+|  `- NodeText (EscapedText (fromList [EscapedPlain "\n"])) in test/Golden/XML/0047.xml at char position 313 to 314
+|
+`- NodeText (EscapedText (fromList [EscapedPlain "\n"])) in test/Golden/XML/0047.xml at char position 321 to 322
+
diff --git a/test/Golden/XML/0047.xml.write b/test/Golden/XML/0047.xml.write
new file mode 100644 (file)
index 0000000..c2ccfe4
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+  <dict>
+    <!-- these aren't the droids you're looking for -->
+    <!---><!-->
+    <key>platform-application</key>
+    <true/>
+    <key>com.apple.private.security.no-container</key>
+    <true/>
+    <key>task_for_pid-allow</key>
+    <true/>
+    <!-- -->
+  </dict>
+</plist>
diff --git a/test/Golden/XML/0047.xml.write.indented b/test/Golden/XML/0047.xml.write.indented
new file mode 100644 (file)
index 0000000..c2ccfe4
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+  <dict>
+    <!-- these aren't the droids you're looking for -->
+    <!---><!-->
+    <key>platform-application</key>
+    <true/>
+    <key>com.apple.private.security.no-container</key>
+    <true/>
+    <key>task_for_pid-allow</key>
+    <true/>
+    <!-- -->
+  </dict>
+</plist>
index 01064301efac7456fbec2084deb9826846404b74..e45136c4d52b57e832fd8f9f2169780707632620 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0009.xml:2:2:
 2 | <.doc></.doc>\r
   |  ^
 unexpected '.'
 2 | <.doc></.doc>\r
   |  ^
 unexpected '.'
-expecting '!', '?', or Element
+expecting '!', '?', or NCName
index 9654b25b9ee4aed481096ddac9baa239acc9bfba..08043c81d9c4d6e55a30a800ccad2973755a6b1b 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0010.xml:1:8:
 1 | <doc><? ?></doc>\r
   |        ^
 unexpected space
 1 | <doc><? ?></doc>\r
   |        ^
 unexpected space
-expecting PI
+expecting NCName
index a3b662f4ad1c0aef881ce2b0b051633c831f6a75..488b85b658e2c374e5a32a87fe6e972f96323d81 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0018.xml:1:6:
+test/Golden/XML/Error/0018.xml:1:8:
   |
 1 | <doc a1></doc>\r
   |
 1 | <doc a1></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |        ^
+unexpected '>'
+expecting ':' or '='
index 434cbce9149af1d86a664e215cd0eef10bdc2c56..598a9324772290d5766c90bf013aa93c7532d9ec 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0019.xml:1:6:
+test/Golden/XML/Error/0019.xml:1:9:
   |
 1 | <doc a1=v1></doc>\r
   |
 1 | <doc a1=v1></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |         ^
+unexpected 'v'
+expecting '"' or '''
index 1cb433f48b3a2735d5f1a418e743623e7e037a8c..0b5868e1562cb6e217d457211b03f8e210c9146e 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0020.xml:1:6:
+test/Golden/XML/Error/0020.xml:1:14:
   |
 1 | <doc a1="v1'></doc>\r
   |
 1 | <doc a1="v1'></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |              ^
+unexpected '<'
+expecting "&#", "&#x", '"', '&', or [^<&"]
index ef2aa97da5f9aff318096132a570044c72998bd8..a703c481e991b17bec043d6b5e74b6b57b3bcb09 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0021.xml:1:6:
+test/Golden/XML/Error/0021.xml:1:10:
   |
 1 | <doc a1="<foo>"></doc>\r
   |
 1 | <doc a1="<foo>"></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |          ^
+unexpected '<'
+expecting "&#", "&#x", '"', '&', or [^<&"]
index 8430ac2f2ff0a25ca62d7a32060c403983572464..0ddad811033013565a62bcfd15d23b69d869a258 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0022.xml:1:6:
+test/Golden/XML/Error/0022.xml:1:9:
   |
 1 | <doc a1=></doc>\r
   |
 1 | <doc a1=></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |         ^
+unexpected '>'
+expecting '"' or '''
index fe68e11678251f975411e45e10ec2bb2ffcb3a99..c04d006d6ecdb894e8fae1968ba333f3c4a7529d 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0026.xml:1:8:
 1 | <doc></>\r
   |        ^
 unexpected '>'
 1 | <doc></>\r
   |        ^
 unexpected '>'
-expecting QName
+expecting NCName
index 50150e0044d3ba3ba3656de3cf35f0c100a0f035..2b1b5c8d3a5b506b46faee86bb6e245fe42f8593 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0027.xml:1:6:
+test/Golden/XML/Error/0027.xml:1:13:
   |
 1 | <doc a1="A & B"></doc>\r
   |
 1 | <doc a1="A & B"></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |             ^
+unexpected space
+expecting NCName
index 9341783a44e98fd58e5ed84aa5ce53665437454f..c2bde7171e568158ce161f425b0407bf4038309a 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0028.xml:1:6:
+test/Golden/XML/Error/0028.xml:1:13:
   |
 1 | <doc a1="a&b"></doc>\r
   |
 1 | <doc a1="a&b"></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |             ^
+unexpected '"'
+expecting ';'
index 42fe15e73b7a7dc3d07b5057e8d2ad47eaa5314b..dd0d73c5b967130d64ae4d67da52f48e3452dbae 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0029.xml:1:6:
+test/Golden/XML/Error/0029.xml:1:15:
   |
 1 | <doc a1="&#123:"></doc>\r
   |
 1 | <doc a1="&#123:"></doc>\r
-  |      ^^
-unexpected "a1"
-expecting "/>" or '>'
+  |               ^
+unexpected ':'
+expecting ';' or digit
index 819447fac5810e340dd990d65635eb73a82c3d73..873e5fbf836a17d9d1f58dbe9442dbed56ef9fa2 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0031.xml:2:2:
 2 | <123></123>\r
   |  ^
 unexpected '1'
 2 | <123></123>\r
   |  ^
 unexpected '1'
-expecting '!', '?', or Element
+expecting '!', '?', or NCName
index a7b8826b18c166f561b32e859b7b060ea4e39dca..f0b1e0ce57246b80cd2668fe92009b2f8add6d86 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0037.xml:1:19:
 1 | <doc>A form feed (\f) is not legal in data</doc>\r
   |                   ^^
 unexpected "<form feed>)"
 1 | <doc>A form feed (\f) is not legal in data</doc>\r
   |                   ^^
 unexpected "<form feed>)"
-expecting "</", '<', ']', CharRef, or EntityRef
+expecting "&#", "&#x", "</", '&', '<', ']', or [^<&]
index 5fb9e9ef56465935beb0173751b07f93aeec121b..5b348c4413bf1632f7c52406c631b4b9dc5d9ae9 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0040.xml:1:9:
 1 | <doc>abc\edef</doc>\r
   |         ^^
 unexpected "<escape>d"
 1 | <doc>abc\edef</doc>\r
   |         ^^
 unexpected "<escape>d"
-expecting "</", '<', ']', CharRef, or EntityRef
+expecting "&#", "&#x", "</", '&', '<', ']', or [^<&]
index 9adc85f692de340efd498fe6a80d0a6a0dee44ad..8aade0d6e29ad10785d20734691711338959ef67 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0041.xml:1:5:
 1 | <doc\f>A form-feed is not white space or a name character</doc\f>\r
   |     ^^
 unexpected "<form feed>>"
 1 | <doc\f>A form-feed is not white space or a name character</doc\f>\r
   |     ^^
 unexpected "<form feed>>"
-expecting "/>", ':', '>', or Spaces1
+expecting "/>", ':', '>', or spaces
index da1bd057d49de3f2ea0a641d732d4a0aad978e77..c806edd1cc5ab7ce0c03206fdee9251d93797829 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0042.xml:1:9:
 1 | <doc>1 < 2 but not in XML</doc>\r
   |         ^
 unexpected space
 1 | <doc>1 < 2 but not in XML</doc>\r
   |         ^
 unexpected space
-expecting '!', '?', or Element
+expecting '!', '?', or NCName
index d6190c31e435dda4d278ae28fb14791476882918..27e30bf750726b6543c5a43bb9ce185a3056066b 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0043.xml:2:1:
 2 | Illegal data\r
   | ^
 unexpected 'I'
 2 | Illegal data\r
   | ^
 unexpected 'I'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index c226bc1c2e565ff2bf6da0265fcc5c0a1ec25ca0..361ff0f70c976aa1ae4dfb3eb6610ce2755bc778 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0044.xml:2:1:
 2 | &#32;\r
   | ^
 unexpected '&'
 2 | &#32;\r
   | ^
 unexpected '&'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index 5ad131f7ce66eab89d19ad5046f1432a9a317f3c..0a2d7c6c0b03669b65765ded94b4d1838da36765 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0047.xml:2:1:
 2 | <doc></doc>\r
   | ^
 unexpected '<'
 2 | <doc></doc>\r
   | ^
 unexpected '<'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index a253e0cdcf2a15ef83946e4edd837d4fab17b83b..301e2f10e6c5331934f469619bd283ff003f2c82 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0048.xml:2:1:
 2 | <doc></doc>\r
   | ^
 unexpected '<'
 2 | <doc></doc>\r
   | ^
 unexpected '<'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index 7e2d8836117cb3b7f96a6a0a6a4e40867418bec1..d7964370ea8908730d2648fdf4ba041edd5b7935 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0049.xml:1:7:
 1 | <doc/></doc/>\r
   |       ^
 unexpected '<'
 1 | <doc/></doc/>\r
   |       ^
 unexpected '<'
-expecting "<!--", "<?", Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index bbde64a7bf355c69e4aaef97b08754607f0e9547..f63d7571f0ae2ffd6d24869fb943bddd2b9ff99b 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0050.xml:2:1:
 2 | Illegal data\r
   | ^
 unexpected 'I'
 2 | Illegal data\r
   | ^
 unexpected 'I'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index 8f977c7824e52f89beaf2bd5b927da3c1c5c0358..7b694bc8c03ab7ade279ba99ad31161f852aea17 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0051.xml:1:7:
 1 | <doc/><doc/>\r
   |       ^
 unexpected '<'
 1 | <doc/><doc/>\r
   |       ^
 unexpected '<'
-expecting "<!--", "<?", Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index b15c5f5d14b7249f70725998464addb3501e2c1c..902597d725fe05618a9da207adb1c454737f4f7d 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0052.xml:2:3:
 2 | <a/\r
   |   ^^
 unexpected "/<carriage return>"
 2 | <a/\r
   |   ^^
 unexpected "/<carriage return>"
-expecting "/>", ':', '>', or Spaces1
+expecting "/>", ':', '>', or spaces
index 28509b42fb65d06daf9dac6ee677619019046807..c2e69dc748a2835abc7e02d01e8e9b8240d04019 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0053.xml:2:3:
 2 | <a/</a>\r
   |   ^^
 unexpected "/<"
 2 | <a/</a>\r
   |   ^^
 unexpected "/<"
-expecting "/>", ':', '>', or Spaces1
+expecting "/>", ':', '>', or spaces
index a9931d280975a4b0123fb584cb4246486cfb7376..1b3dfadf2bb6397730f393edcec1ce379204fcbc 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0055.xml:3:1:
 3 | <![CDATA[]]>\r
   | ^
 unexpected '<'
 3 | <![CDATA[]]>\r
   | ^
 unexpected '<'
-expecting "<!--", "<?", CRLF, Spaces, or end of input
+expecting "<!--", "<?", end of input, or spaces
index d6d66a1c324358b09f04cf59858ab7d91afa7ee3..6421a68a5d875ef1d506bf9d475bfd76accc2586 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0057.xml:1:1:
 1 | <empty line>
   | ^
 unexpected end of input
 1 | <empty line>
   | ^
 unexpected end of input
-expecting "<!--", "<?", '<', Spaces, or XMLDecl
+expecting "<!--", "<?", "<?xml", '<', or spaces
index 4f8689257ecf503dd727f7ac911bb77e8750c261..a9983142033f15fba7597b6a1511a3a5dc08f294 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0058.xml:2:2:
 2 | <![CDATA[]]>\r
   |  ^
 unexpected '!'
 2 | <![CDATA[]]>\r
   |  ^
 unexpected '!'
-expecting Element
+expecting NCName
index 445cfb7227feabc5a8ccf022fd99e59aeb07a911..c0d0a144bfaff7ef6653a76326a407829d621a21 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0059.xml:2:1:
 2 | &#32;\r
   | ^
 unexpected '&'
 2 | &#32;\r
   | ^
 unexpected '&'
-expecting "<!--", "<?", '<', CRLF, or Spaces
+expecting "<!--", "<?", '<', or spaces
index ba6d5a569541bf039857796f9bceba56791cae0b..183b13c8e80a7a399d2658df7d225b10d2e1e809 100644 (file)
@@ -1,6 +1,6 @@
-test/Golden/XML/Error/0061.xml:1:2:
+test/Golden/XML/Error/0061.xml:1:41:
   |
 1 | <!-- a comment ending with three dashes --->\r
   |
 1 | <!-- a comment ending with three dashes --->\r
-  |  ^
-unexpected '!'
-expecting Element
+  |                                         ^^^
+unexpected "---"
+expecting "-->"
index 6f6c3199a1cf1cfc14cad070dd8701d5140e4987..758d59e3c62abb1f7458a2240bd9a7b1df4a2352 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0063.xml:1:6:
+test/Golden/XML/Error/0063.xml:1:14:
   |
 1 | <doc a="&foo;"></doc>\r
   |
 1 | <doc a="&foo;"></doc>\r
-  |      ^^
-unexpected "a="
-expecting "/>" or '>'
+  |              ^
+Error_EntityRef_unknown foo
index de714088fdbc04dbff057b8c5eb1c68805d4438f..7c993b4e0a496e6d48286a01a326af04399a2b60 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0065.xml:1:7:
 1 | <?xml VERSION="1.0"?>\r
   |       ^^^^^^^
 unexpected "VERSION"
 1 | <?xml VERSION="1.0"?>\r
   |       ^^^^^^^
 unexpected "VERSION"
-expecting VersionInfo
+expecting "version"
index 3551ebfdd823b30792c41182e61699cdd41b4c8c..af8350ceffebf638572e25e473ca03fc0a986d7d 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0066.xml:1:7:
 1 | <?xml encoding="UTF-8" version="1.0"?>\r
   |       ^^^^^^^
 unexpected "encodin"
 1 | <?xml encoding="UTF-8" version="1.0"?>\r
   |       ^^^^^^^
 unexpected "encodin"
-expecting VersionInfo
+expecting "version"
index 6edfd253fadeaf885597e9eb6a8417a3f026d915..28562655773b7813448994b445821673adeb9c01 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0067.xml:1:20:
 1 | <?xml version="1.0"encoding="UTF-8" ?>\r
   |                    ^^
 unexpected "en"
 1 | <?xml version="1.0"encoding="UTF-8" ?>\r
   |                    ^^
 unexpected "en"
-expecting "?>", EncodingDecl, or SDDecl
+expecting "?>" or spaces
index 506c719aef11b2ab2f07cc0737a648a884933ba4..14b2033954f9afcb6229453188dd9950a44535f0 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0074.xml:2:2:
 2 | <![CDATA[]]>\r
   |  ^
 unexpected '!'
 2 | <![CDATA[]]>\r
   |  ^
 unexpected '!'
-expecting Element
+expecting NCName
index 35d016acba050ba49822e5a00b8b6bf845535517..f916ce75fd91156947ef2a354e4a676fbb4bb78a 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0075.xml:2:1:
 2 | &#32;<doc></doc>\r
   | ^
 unexpected '&'
 2 | &#32;<doc></doc>\r
   | ^
 unexpected '&'
-expecting "<!--", "<?", '<', CRLF, or Spaces
+expecting "<!--", "<?", '<', or spaces
index 9752c890f154538cc30b2e074224cd7a310b16c0..8a0b3645af5db0e85069815f9851e1e170697770 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0078.xml:2:2:
+test/Golden/XML/Error/0078.xml:2:6:
   |
 2 | <?xml version="1.0"?>\r
   |
 2 | <?xml version="1.0"?>\r
-  |  ^
-unexpected '?'
-expecting Element
+  |      ^
+Error_PI_reserved xml
index d2ee580d021825a219b71a3bdeb6b1b68c015300..d98955e51ebca8111f28d614d85f81a4c350d892 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0079.xml:2:2:
+test/Golden/XML/Error/0079.xml:2:6:
   |
 2 | <?xml version="1.0"?>\r
   |
 2 | <?xml version="1.0"?>\r
-  |  ^
-unexpected '?'
-expecting Element
+  |      ^
+Error_PI_reserved xml
index fc79c5cd634904972ca3be40988b7f1e0607a9b2..3cce79afe0f1205d36ffeeeadb2fd13b099b610c 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0081.xml:3:1:
+test/Golden/XML/Error/0081.xml:3:6:
   |
 3 | <?xml version="1.0"?>\r
   |
 3 | <?xml version="1.0"?>\r
-  | ^
-unexpected '<'
-expecting CRLF or end of input
+  |      ^
+Error_PI_reserved xml
index 381d43a19260c034ee14795eaab351a611d4908f..d29ebd7eb9a6ea87633c125d82b265a7c0875640 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0082.xml:1:7:
 1 | <?xml encoding="UTF-8"?>\r
   |       ^^^^^^^
 unexpected "encodin"
 1 | <?xml encoding="UTF-8"?>\r
   |       ^^^^^^^
 unexpected "encodin"
-expecting VersionInfo
+expecting "version"
index 3d7f745fdc2884ed0f42260cdb111b783b191732..7f6c7ce65ad0b60379b575be6afeb751f8364877 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0083.xml:1:2:
+test/Golden/XML/Error/0083.xml:1:6:
   |
 1 | <?XML version="1.0"?>\r
   |
 1 | <?XML version="1.0"?>\r
-  |  ^
-unexpected '?'
-expecting Element
+  |      ^
+Error_PI_reserved XML
index 8a377b70c6ccc82a79f284fd48206db9f8929261..29415e5d410cd7843e1d0b5676b0ca9ff1a47925 100644 (file)
@@ -1,6 +1,5 @@
-test/Golden/XML/Error/0084.xml:1:2:
+test/Golden/XML/Error/0084.xml:1:6:
   |
 1 | <?xmL version="1.0"?>\r
   |
 1 | <?xmL version="1.0"?>\r
-  |  ^
-unexpected '?'
-expecting Element
+  |      ^
+Error_PI_reserved xmL
index 879ea69cba0a80aa151223c0506d9ef9bc5c3fe4..1c3483bba4256f6f51c339cd7706be9a8ca228a7 100644 (file)
@@ -3,4 +3,4 @@ test/Golden/XML/Error/0087.xml:1:6:
Content-type: text/html ]> Git — Sourcephile - haskell/symantic-xml.git/commitdiff


500 - Internal Server Error

"\x{ffff}" does not map to UTF-8 at /nix/store/xki0wimgnkmimkvwyy73rpwafyh7m0b2-gitweb-2.42.0/gitweb.cgi line 1320, <$fd> line 8796.