Backtrack (try) the grammar only when necessary to get better error messages.
authorJulien Moutinho <julm+symantic@autogeree.net>
Mon, 6 Mar 2017 22:30:09 +0000 (23:30 +0100)
committerJulien Moutinho <julm+symantic@autogeree.net>
Fri, 10 Mar 2017 00:28:05 +0000 (01:28 +0100)
symantic-grammar/Language/Symantic/Grammar/ContextFree.hs
symantic-grammar/Language/Symantic/Grammar/EBNF.hs
symantic-grammar/Language/Symantic/Grammar/Operators.hs
symantic-grammar/Language/Symantic/Grammar/Regular.hs
symantic-grammar/Language/Symantic/Grammar/Test.hs
symantic-lib/Language/Symantic/Parsing/Test.hs
symantic/Language/Symantic/Compiling/Term/Grammar.hs
symantic/Language/Symantic/Typing/Type.hs

index 0153405ca6fc57f45f578aa3a573236ec058afc8..ae739315b60dbbc7bd68859bbd3db943d4d66fb0 100644 (file)
@@ -16,8 +16,9 @@ import Language.Symantic.Grammar.Regular
 -- | Context-free grammar.
 newtype CF g a = CF { unCF :: g a }
  deriving (IsString, Functor, Gram_Terminal, Applicative, App)
-deriving instance Alter g => Alter (CF g)
-deriving instance Alt g => Alt (CF g)
+deriving instance Alter     g => Alter     (CF g)
+deriving instance Alt       g => Alt       (CF g)
+deriving instance Try       g => Try       (CF g)
 deriving instance Gram_Rule g => Gram_Rule (CF g)
 deriving instance Gram_RegL g => Gram_RegL (CF g)
 deriving instance Gram_RegR g => Gram_RegR (CF g)
index 44e08c35884e457635f698644bb86592656100d2..22f552be1771d1f6a3bbfc9e01472b2490180f7c 100644 (file)
@@ -62,6 +62,7 @@ data RuleMode
 newtype RuleDef a = RuleDef { unRuleDef :: EBNF a }
  deriving (Functor, Applicative)
 deriving instance Gram_RuleDef RuleDef
+deriving instance Try RuleDef
 instance Gram_Rule RuleDef where
        rule  n           = rule_def (ebnf_const n)
        rule1 n g a       = rule_def (ebnf_const n `ebnf_arg` unRuleDef a) (g a)
@@ -182,3 +183,9 @@ data LR
  = L -- ^ Left
  | R -- ^ Right
  deriving (Eq, Show)
+
+-- * Type 'Try'
+class Try g where
+       try :: g a -> g a
+instance Try EBNF where
+       try = id
index e19cc83f846b5056e6f2d0d98cf753c0ce518ecf..8a6bf8c54bac2ba9d8fd1cd3d9e20d71cf50ffd4 100644 (file)
@@ -15,6 +15,7 @@ class
  ( Alt g
  , Alter g
  , App g
+ , Try g
  , Gram_CF g
  , Gram_Rule g
  , Gram_Terminal g
@@ -44,10 +45,10 @@ class
                                in \case
                                 Just (in_, b) -> insert_infix nod_a in_ b
                                 Nothing -> Right nod_a)
-                        <$> many preG
+                        <$> many (try preG)
                         <*> aG
-                        <*> many postG
-                        <*> option Nothing (curry Just <$> inG <*> go aG preG inG postG)
+                        <*> many (try postG)
+                        <*> option Nothing (curry Just <$> try inG <*> go aG preG inG postG)
                
                insert_unifix :: (Unifix, a -> a) -> OpTree a -> OpTree a
                insert_unifix a@(uni_a@(Prefix prece_a), op_a) nod_b =
@@ -121,7 +122,7 @@ class
                 Just (op, b) -> a `op` b
                 Nothing -> a)
                 <$> g
-                <*> option Nothing (curry Just <$> opG <*> infixrG g opG)
+                <*> option Nothing (try $ curry Just <$> opG <*> infixrG g opG)
        infixlG :: CF g a -> CF g (a -> a -> a) -> CF g a
        infixlG = rule2 "infixl" $ \g opG ->
                -- NOTE: infixl uses the same grammar than infixr,
@@ -135,7 +136,7 @@ class
                         Just (op, kb) -> \k -> kb (k a `op`)
                         Nothing -> ($ a))
                         <$> g
-                        <*> option Nothing (curry Just <$> opG <*> go g opG)
+                        <*> option Nothing (try $ curry Just <$> opG <*> go g opG)
 deriving instance Gram_Op g => Gram_Op (CF g)
 instance Gram_Op RuleDef
 instance Gram_Op EBNF
index 0d580d4a2b50f22796175362c201570a7c4fb10c..e6e379d2dfa16c684db578fbac17c63c84ff4f18 100644 (file)
@@ -14,6 +14,7 @@ import Language.Symantic.Grammar.Terminal
 newtype Reg (lr::LR) g a = Reg { unReg :: g a }
  deriving (IsString, Functor, Gram_Terminal)
 deriving instance Alter g => Alter (Reg lr g)
+deriving instance Try g => Try (Reg lr g)
 deriving instance Gram_Rule g => Gram_Rule (Reg lr g)
 deriving instance (Functor g, Alter g, Gram_RegL g) => Gram_RegL (RegL g)
 deriving instance (Functor g, Alter g, Gram_RegR g) => Gram_RegR (RegR g)
index a620e1905537a79fc6d817aae6a86dadbb244147..d337887ee88f4473a57404af7f5eefc3241170a3 100644 (file)
@@ -10,7 +10,6 @@ import qualified Control.Applicative as Alt
 import Control.Monad
 import qualified Data.Char as Char
 import Data.Functor.Identity
-import qualified Data.List as List
 import Data.Monoid ((<>))
 import Data.String (IsString(..))
 import qualified Data.Text as Text
@@ -30,13 +29,16 @@ instance ParsecC e s => Gram_Terminal (P.ParsecT e s m) where
        eoi          = P.eof
        char         = P.char
        string       = P.string
-       unicat cat   = P.satisfy $ (`List.elem` cats) . Char.generalCategory
+       unicat cat   = P.satisfy $ (`elem` cats) . Char.generalCategory
                where cats = unicode_categories cat
        range (l, h) = P.satisfy $ \c -> l <= c && c <= h
        but (Terminal f) (Terminal p) = Terminal $ P.notFollowedBy (P.try p) *> f
 instance ParsecC e s => Alter (P.ParsecT e s m) where
-       empty = Alt.empty
-       x <+> y = P.try x Alt.<|> y
+       empty  = Alt.empty
+       (<+>)  = (Alt.<|>)
+       choice = P.choice
+instance ParsecC e s => Try (P.ParsecT e s m) where
+       try = P.try
 instance ParsecC e s => Gram_RegR (P.ParsecT e s m) where
        Terminal f .*> Reg x = Reg $ f <*> x
 instance ParsecC e s => Gram_RegL (P.ParsecT e s m) where
index 7dc668380c553d2affa6a9aa1565cacf4ccc2da2..f2af4f68bd32271527dc2a3a6ce62adb69d07651 100644 (file)
@@ -31,14 +31,23 @@ instance ParsecC e s => Gram_Terminal (P.ParsecT e s m) where
        range (l, h) = P.satisfy $ \c -> l <= c && c <= h
        but (Terminal f) (Terminal p) = Terminal $ P.notFollowedBy (P.try p) *> f
 instance ParsecC e s => Alter (P.ParsecT e s m) where
-       empty = Alt.empty
-       x <+> y = P.try x Alt.<|> y
+       empty  = Alt.empty
+       (<+>)  = (Alt.<|>)
+       choice = P.choice
+instance ParsecC e s => Try (P.ParsecT e s m) where
+       try = P.try
 instance ParsecC e s => Gram_RegR (P.ParsecT e s m) where
        Terminal f .*> Reg x = Reg $ f <*> x
 instance ParsecC e s => Gram_RegL (P.ParsecT e s m) where
        Reg f <*. Terminal x = Reg $ f <*> x
-instance ParsecC e s => App (P.ParsecT e s m)
-instance ParsecC e s => Alt (P.ParsecT e s m)
+instance ParsecC e s => App (P.ParsecT e s m) where
+       between = P.between
+instance ParsecC e s => Alt (P.ParsecT e s m) where
+       option   = P.option
+       optional = P.optional
+       many     = P.many
+       some     = P.some
+       skipMany = P.skipMany
 instance ParsecC e s => Gram_CF (P.ParsecT e s m) where
        CF f <& Reg p        = CF $ P.lookAhead f <*> p
        Reg f &> CF p        = CF $ P.lookAhead f <*> p
index c5a124f7be3bf3dd6d82d1e8cc411eace54fbc61..fd2fe2263d40c7f085bfb5a5f497962b7fdcdcb8 100644 (file)
@@ -225,6 +225,7 @@ class
  , Alter g
  , Alter g
  , App g
+ , Try g
  , Gram_CF g
  , Gram_Op g
  , Gram_Lexer g
@@ -263,7 +264,7 @@ class
        term_mod_idname :: CF g (Mod Term_Name)
        term_mod_idname = rule "term_mod_idname" $
                Mod
-                <$> option [] (mod_path <* char '.')
+                <$> option [] (try $ mod_path <* char '.')
                 <*> term_idname
        term_idname :: CF g Term_Name
        term_idname = rule "term_idname" $
@@ -286,7 +287,7 @@ class
        term_mod_opname :: CF g (Mod Term_Name)
        term_mod_opname = rule "term_mod_opname" $
                Mod
-                <$> option [] (mod_path <* char '.')
+                <$> option [] (try $ mod_path <* char '.')
                 <*> term_opname
        term_opname :: CF g Term_Name
        term_opname = rule "term_opname" $
@@ -386,10 +387,10 @@ class
         :: Inj_Tokens meta ts '[Proxy (->)]
         => CF g (EToken meta ts)
        termG = rule "term" $
-               choice $
-                [ term_abst
-                , term_let
+               choice
+                [ try term_abst
                 , term_operators
+                , term_let
                 ]
        term_operators
         :: Inj_Tokens meta ts '[Proxy (->)]
@@ -449,7 +450,7 @@ class
                term_unError $
                (\a as -> unProTok =<< protok_app a as)
                 <$> term_atom_proto
-                <*> many term_atom
+                <*> many (try term_atom)
        term_atom
         :: Inj_Tokens meta ts '[Proxy (->)]
         => CF g (Either (EToken meta '[Proxy Token_Type])
@@ -462,8 +463,11 @@ class
         => CF g (ProTok meta ts)
        term_atom_proto =
                choice $
-                term_atomsR (Proxy @ts) <>
-                [ metaG $ ((\(_, in_, _) -> term_protok in_) <$>) $ term_unError $ term_tokenizers $
+                try <$> term_atomsR (Proxy @ts) <>
+                [ try $
+                       metaG $ ((\(_, in_, _) -> term_protok in_) <$>) $
+                       term_unError $
+                       term_tokenizers $
                        protok <$> term_mod_name
                 , ProTok <$> term_group
                 ]
index 276c6a11cf4a5c2507962cce06f964cca7a2d075..6d23074e6636b8eb3f934f85a024559ccbdbde2d 100644 (file)
@@ -320,33 +320,34 @@ instance
 -- * Class 'Gram_Type'
 type TokType meta = EToken meta '[Proxy Token_Type]
 class
- ( Alt p
- , Alter p
- , App p
- , Gram_CF p
- , Gram_Rule p
- , Gram_Terminal p
- , Gram_Lexer p
- , Gram_Op p
- , Gram_Meta meta p
- ) => Gram_Type meta p where
-       typeG :: CF p (TokType meta)
+ ( Alt g
+ , Alter g
+ , App g
+ , Try g
+ , Gram_CF g
+ , Gram_Rule g
+ , Gram_Terminal g
+ , Gram_Lexer g
+ , Gram_Op g
+ , Gram_Meta meta g
+ ) => Gram_Type meta g where
+       typeG :: CF g (TokType meta)
        typeG = rule "type" $ type_fun
-       type_fun :: CF p (TokType meta)
+       type_fun :: CF g (TokType meta)
        type_fun = rule "type_fun" $
                infixrG type_list (metaG $ op <$ symbol "->")
                where op meta a b = inj_EToken meta $ Token_Type (TyName "(->)") [a, b]
-       type_list :: CF p (TokType meta)
+       type_list :: CF g (TokType meta)
        type_list = rule "type_list" $
                metaG $ inside f
                 (symbol "[") (option [] (pure <$> typeG)) (symbol "]")
                 (const <$> type_tuple2)
                where f a meta = inj_EToken meta $ Token_Type (TyName "[]") a
-       type_tuple2 :: CF p (TokType meta)
+       type_tuple2 :: CF g (TokType meta)
        type_tuple2 = rule "type_tuple2" $
-               parens (infixrG typeG (metaG $ op <$ symbol ",")) <+> type_app
+               try (parens (infixrG typeG (metaG $ op <$ symbol ","))) <+> type_app
                where op meta a b = inj_EToken meta $ Token_Type (TyName "(,)") [a, b]
-       type_app :: CF p (TokType meta)
+       type_app :: CF g (TokType meta)
        type_app = rule "type_app" $
                f <$> some type_atom
                where
@@ -354,18 +355,18 @@ class
                f (EToken (TokenZ meta (Token_Type a as)):as') =
                        EToken $ TokenZ meta $ Token_Type a $ as <> as'
                f _ = error "Oops, the impossible happened"
-       type_atom :: CF p (TokType meta)
+       type_atom :: CF g (TokType meta)
        type_atom = rule "type_atom" $
-               parens typeG <+>
+               try (parens typeG) <+>
                type_name <+>
                type_symbol
-       type_name :: CF p (TokType meta)
+       type_name :: CF g (TokType meta)
        type_name = rule "type_name" $
                metaG $ lexeme $
                (\c cs meta -> EToken $ TokenZ meta $ Token_Type (TyName $ Text.pack $ c:cs) [])
                 <$> unicat (Unicat Char.UppercaseLetter)
                 <*> many (choice $ unicat <$> [Unicat_Letter, Unicat_Number])
-       type_symbol :: CF p (TokType meta)
+       type_symbol :: CF g (TokType meta)
        type_symbol = rule "type_symbol" $
                metaG $ (f <$>) $
                parens $ many $ cf_of_Terminal $ choice okG `but` choice koG
@@ -379,12 +380,12 @@ class
                 ]
                koG = char <$> ['(', ')', '`']
 
-deriving instance Gram_Type meta p => Gram_Type meta (CF p)
+deriving instance Gram_Type meta g => Gram_Type meta (CF g)
 instance Gram_Type meta EBNF
 instance Gram_Type meta RuleDef
 
 -- | List of the rules of 'Gram_Type'.
-gram_type :: Gram_Type meta p => [CF p (TokType meta)]
+gram_type :: Gram_Type meta g => [CF g (TokType meta)]
 gram_type =
  [ typeG
  , type_fun