1 {-# LANGUAGE ConstraintKinds #-}
2 {-# LANGUAGE DeriveFunctor #-}
3 {-# LANGUAGE ExistentialQuantification #-}
4 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
5 {-# LANGUAGE PolyKinds #-}
6 {-# LANGUAGE UndecidableInstances #-}
7 module Language.Symantic.Compiling.Grammar where
9 import Control.Arrow (left)
10 import Control.Monad (void)
11 import Data.Map.Strict (Map)
12 import Data.Proxy (Proxy(..))
13 import Data.Semigroup (Semigroup(..))
14 import Data.String (IsString(..))
15 import Data.Text (Text)
16 import Prelude hiding (mod, not, any)
17 import qualified Data.Char as Char
18 import qualified Data.Function as Fun
19 import qualified Data.Map.Strict as Map
20 import qualified Data.Text as Text
22 import Language.Symantic.Grammar
23 import Language.Symantic.Typing
24 import Language.Symantic.Compiling.Term
27 data Mod a = Mod PathMod a
28 deriving (Eq, Functor, Ord, Show)
31 type PathMod = [NameMod]
34 newtype NameMod = NameMod Text
35 deriving (Eq, Ord, Show)
38 newtype NameTe = NameTe Text
39 deriving (Eq, Ord, Show)
40 instance IsString NameTe where
41 fromString = NameTe . fromString
46 { modules_prefix :: Map PathMod (Map NameTe (Tokenizer Unifix src ss))
47 , modules_infix :: Map PathMod (Map NameTe (Tokenizer Infix src ss))
48 , modules_postfix :: Map PathMod (Map NameTe (Tokenizer Unifix src ss))
52 ( Show (Tokenizer Unifix src ss)
53 , Show (Tokenizer Infix src ss)
54 ) => Show (Modules src ss)
55 instance Semigroup (Modules src ss) where
71 instance Monoid (Modules src ss) where
72 mempty = Modules Map.empty Map.empty Map.empty
75 -- ** Type 'Tokenizer'
76 data Tokenizer fixy src ss
78 { token_fixity :: fixy
79 , token_term :: src -> Token_Term src ss
82 -- ** Type 'Token_Term'
83 data Token_Term src ss
84 = Token_Term (TermVT_CF src ss)
85 | Token_Term_Abst src NameTe (AST_Type src) (AST_Term src ss)
86 | Token_Term_Var src NameTe
87 | Token_Term_Let src NameTe (AST_Term src ss) (AST_Term src ss)
92 -- | /Abstract Syntax Tree/ of 'Token_Term'.
93 type AST_Term src ss = BinTree (Token_Term src ss)
95 -- * Class 'Inj_Modules'
96 type Inj_Modules src ss
97 = Inj_ModulesR src ss ss
99 inj_modules :: forall src ss. Inj_Modules src ss => Modules src ss
100 inj_modules = inj_modulesR (Proxy @ss)
102 -- ** Class 'Inj_ModulesR'
103 class Inj_ModulesR src (ss::[*]) (rs::[*]) where
104 inj_modulesR :: Proxy rs -> Modules src ss
105 instance Inj_ModulesR src ss '[] where
106 inj_modulesR _rs = mempty
109 , Inj_ModulesR src ss rs
110 ) => Inj_ModulesR src ss (Proxy s ': rs) where
111 inj_modulesR _ = inj_modulesR (Proxy @rs) <> module_ (Proxy @s)
113 -- | Lookup the given 'Mod' 'NameTe' into the given 'Modules',
114 -- returning for prefix, infix and postfix positions, when there is a match.
119 ( Maybe (Tokenizer Unifix src ss)
120 , Maybe (Tokenizer Infix src ss)
121 , Maybe (Tokenizer Unifix src ss)
123 modulesLookup mn@(mod `Mod` n) (Modules pres ins posts) = do
124 let pre = Map.lookup mod pres >>= Map.lookup n
125 let post = Map.lookup mod posts >>= Map.lookup n
130 { token_term = Token_Term_App @src @ss
131 , token_fixity = Infix (Just AssocL) 9
133 _ -> Map.lookup mod ins >>= Map.lookup n
137 class Module src ss s where
138 module_ :: Proxy s -> Modules src ss
144 PathMod -> [DefTerm src ss] -> Modules src ss
145 moduleWhere mod lst =
147 { modules_infix = mk $ \(n `WithFixity` fixy := t) ->
149 Fixity2 inf -> [(n, Tokenizer inf $ Token_Term . setSource (TermVT_CF t))]
151 , modules_prefix = mk $ \(n `WithFixity` fixy := t) ->
153 Fixity1 pre@Prefix{} -> [(n, Tokenizer pre $ Token_Term . setSource (TermVT_CF t))]
155 , modules_postfix = mk $ \(n `WithFixity` fixy := t) ->
157 Fixity1 post@Postfix{} -> [(n, Tokenizer post $ Token_Term . setSource (TermVT_CF t))]
162 (DefTerm src ss -> [(NameTe, Tokenizer fixy src ss)]) ->
163 Map PathMod (Map NameTe (Tokenizer fixy src ss))
164 mk = Map.singleton mod . Map.fromList . (`foldMap` lst)
169 (:=) (WithFixity NameTe)
170 (forall es. Term src ss es vs t)
172 -- ** Type 'WithFixity'
174 = WithFixity a Fixity
176 instance IsString (WithFixity NameTe) where
177 fromString a = WithFixity (fromString a) (Fixity2 infixN5)
179 withInfix :: a -> Infix -> WithFixity a
180 withInfix a inf = a `WithFixity` Fixity2 inf
181 withInfixR :: a -> Precedence -> WithFixity a
182 withInfixR a p = a `WithFixity` Fixity2 (infixR p)
183 withInfixL :: a -> Precedence -> WithFixity a
184 withInfixL a p = a `WithFixity` Fixity2 (infixL p)
185 withInfixN :: a -> Precedence -> WithFixity a
186 withInfixN a p = a `WithFixity` Fixity2 (infixN p)
187 withInfixB :: a -> (Side, Precedence) -> WithFixity a
188 withInfixB a (lr, p) = a `WithFixity` Fixity2 (infixB lr p)
189 withPrefix :: a -> Precedence -> WithFixity a
190 withPrefix a p = a `WithFixity` Fixity1 (Prefix p)
191 withPostfix :: a -> Precedence -> WithFixity a
192 withPostfix a p = a `WithFixity` Fixity1 (Postfix p)
194 -- * Class 'Gram_Name'
206 ) => Gram_Name g where
207 g_mod_path :: CF g PathMod
208 g_mod_path = rule "mod_path" $
210 (pure <$> g_mod_name)
213 g_mod_name :: CF g NameMod
214 g_mod_name = rule "mod_name" $
215 (NameMod . Text.pack <$>) $
219 <*. (any `but` g_term_idname_tail)
221 identG = (:) <$> headG <*> many (cf_of_Terminal g_term_idname_tail)
222 headG = unicat $ Unicat Char.UppercaseLetter
224 g_term_mod_name :: CF g (Mod NameTe)
225 g_term_mod_name = rule "term_mod_name" $
227 g_term_mod_idname <+>
228 parens g_term_mod_opname
229 g_term_name :: CF g NameTe
230 g_term_name = rule "term_name" $
235 g_term_mod_idname :: CF g (Mod NameTe)
236 g_term_mod_idname = rule "term_mod_idname" $
238 <$> option [] (try $ g_mod_path <* char '.')
240 g_term_idname :: CF g NameTe
241 g_term_idname = rule "term_idname" $
242 (NameTe . Text.pack <$>) $
246 <*. (any `but` g_term_idname_tail)
248 identG = (:) <$> headG <*> many (cf_of_Terminal g_term_idname_tail)
249 headG = unicat $ Unicat_Letter
250 g_term_idname_tail :: Terminal g Char
251 g_term_idname_tail = rule "term_idname_tail" $
252 unicat Unicat_Letter <+>
254 g_term_keywords :: Reg rl g String
255 g_term_keywords = rule "term_keywords" $
256 choice $ string <$> ["in", "let"]
258 g_term_mod_opname :: CF g (Mod NameTe)
259 g_term_mod_opname = rule "term_mod_opname" $
261 <$> option [] (try $ g_mod_path <* char '.')
263 g_term_opname :: CF g NameTe
264 g_term_opname = rule "term_opname" $
265 (NameTe . Text.pack <$>) $
269 <*. (any `but` g_term_opname_ok)
271 symG = some $ cf_of_Terminal g_term_opname_ok
272 g_term_opname_ok :: Terminal g Char
273 g_term_opname_ok = rule "term_opname_ok" $
280 koG = choice (char <$> ['(', ')', '`', '\'', ',', '[', ']'])
281 g_term_keysyms :: Reg rl g String
282 g_term_keysyms = rule "term_keysyms" $
283 choice $ string <$> ["\\", "->", "=", "@"]
285 deriving instance Gram_Name g => Gram_Name (CF g)
286 instance Gram_Name EBNF
287 instance Gram_Name RuleEBNF
289 -- * Class 'Gram_Term_Type'
301 ) => Gram_Term_Type src g where
303 :: CF g (NameTe, AST_Type src)
304 g_term_abst_decl = rule "term_abst_decl" $
307 <* (symbol "::" <+> symbol ":")
308 -- NOTE: "::" is Haskell compatibility and ":" is another common notation.
311 deriving instance Gram_Term_Type src g => Gram_Term_Type src (CF g)
312 instance Inj_Source (Text_of_Source src) src => Gram_Term_Type src EBNF
313 instance Inj_Source (Text_of_Source src) src => Gram_Term_Type src RuleEBNF
315 -- ** Type 'Error_Term_Gram'
317 = Error_Term_Gram_Fixity Error_Fixity
318 | Error_Term_Gram_Fixity_Need FixityPos
319 | Error_Term_Gram_Term_incomplete
320 | Error_Term_Gram_Type_applied_to_nothing
321 | Error_Term_Gram_not_applicable
322 | Error_Term_Gram_application
323 | Error_Term_Gram_application_mismatch
326 -- *** Type 'FixityPos'
333 -- * Class 'Gram_Term'
336 , Gram_Error Error_Term_Gram g
346 , Gram_Term_Type src g
347 , Gram_Term_Atoms src ss g
349 ) => Gram_Term src ss g where
350 modules_get :: CF g (Modules src ss -> a) -> CF g a
351 modules_put :: CF g (Modules src ss, a) -> CF g a
352 g_term :: CF g (AST_Term src ss)
353 g_term = rule "term" $
359 g_term_operators :: CF g (AST_Term src ss)
360 g_term_operators = rule "term_operators" $
362 left Error_Term_Gram_Fixity <$>
365 g_ops :: CF g (Either Error_Fixity (AST_Term src ss))
366 g_ops = operators g_term_atom g_prefix g_infix g_postfix
367 g_prefix :: CF g (Unifix, AST_Term src ss -> AST_Term src ss)
368 g_infix :: CF g (Infix, AST_Term src ss -> AST_Term src ss -> AST_Term src ss)
369 g_postfix :: CF g (Unifix, AST_Term src ss -> AST_Term src ss)
370 g_prefix = catch $ withMeta $ modules_get $ op_prefix <$> g_prefix_op
371 g_infix = catch $ withMeta $ modules_get $ op_infix <$> g_infix_op
372 g_postfix = catch $ withMeta $ modules_get $ op_postfix <$> g_postfix_op
377 -> Either Error_Term_Gram
378 (Infix, AST_Term src ss -> AST_Term src ss -> AST_Term src ss)
379 op_infix name toks src = do
380 let (_pre, in_, _post) = modulesLookup name toks
382 Nothing -> Left $ Error_Term_Gram_Fixity_Need FixityPos_Infix
384 Right $ (token_fixity p,) $ \a b ->
385 (BinTree0 (token_term p src) `BinTree2` a) `BinTree2` b
386 op_prefix, op_postfix
390 -> Either Error_Term_Gram
392 , AST_Term src ss -> AST_Term src ss )
393 op_prefix name toks src = do
394 let (pre, _in_, _post) = modulesLookup name toks
396 Nothing -> Left $ Error_Term_Gram_Fixity_Need FixityPos_Prefix
398 Right $ (token_fixity p,) $ \a ->
399 BinTree0 (token_term p src) `BinTree2` a
400 op_postfix name toks src = do
401 let (_pre, _in_, post) = modulesLookup name toks
403 Nothing -> Left $ Error_Term_Gram_Fixity_Need FixityPos_Postfix
405 Right $ (token_fixity p,) $ \a ->
406 BinTree0 (token_term p src) `BinTree2` a
407 g_postfix_op :: CF g (Mod NameTe)
408 g_postfix_op = rule "term_op_postfix" $
410 g_backquote *> g_term_mod_idname <+> -- <* (cf_of_Terminal $ Gram.Term (pure ' ') `but` g_backquote)
412 g_infix_op :: CF g (Mod NameTe)
413 g_infix_op = rule "term_op_infix" $
415 between g_backquote g_backquote g_term_mod_idname <+>
416 try (Fun.const <$> g_term_mod_opname <*> (string " " <+> string "\n")) <+>
418 g_prefix_op :: CF g (Mod NameTe)
419 g_prefix_op = rule "term_op_prefix" $
421 g_term_mod_idname <* g_backquote <+>
423 g_backquote :: Gram_Terminal g' => g' Char
424 g_backquote = char '`'
426 g_term_atom :: CF g (AST_Term src ss)
427 g_term_atom = rule "term_atom" $
431 (\typ src -> BinTree0 $ inj_EToken src $ Token_Term_Type typ)
432 <$ char '@' <*> g_type) :) $
434 (try <$> g_term_atomsR (Proxy @ss)) <>
436 catch $ withMeta $ modules_get $
438 let (_, in_, _) = modulesLookup mn toks
440 Just p -> Right $ BinTree0 $ token_term p src
443 [] `Mod` n -> Right $ BinTree0 $ Token_Term_Var src n
444 _ -> Left $ Error_Term_Gram_Fixity_Need FixityPos_Infix
445 ) <$> g_term_mod_name
448 g_term_group :: CF g (AST_Term src ss)
449 g_term_group = rule "term_group" $ parens g_term
450 g_term_abst :: CF g (AST_Term src ss)
451 g_term_abst = rule "term_abst" $
455 BinTree0 . Token_Term_Abst src x ty_x) te xs) <$>) $
456 g_term_abst_args_body
457 (symbol "\\" *> some g_term_abst_decl <* symbol "->")
459 g_term_abst_args_body
460 :: CF g [(NameTe, AST_Type src)]
461 -> CF g (AST_Term src ss)
462 -> CF g ([(NameTe, AST_Type src)], AST_Term src ss)
463 -- g_term_abst_args_body args body = (,) <$> args <*> body
464 g_term_abst_args_body cf_args cf_body =
465 modules_put $ modules_get $
466 (\a b (toks::Modules src ss) -> (toks, (a, b)))
467 <$> (modules_put $ modules_get $
468 (\args (toks::Modules src ss) -> (,args)
470 { modules_prefix = del (modules_prefix toks) args
471 , modules_infix = ins (modules_infix toks) args
472 , modules_postfix = del (modules_postfix toks) args
476 del = foldr $ \(n, _) -> Map.adjust (Map.delete n) []
477 ins = foldr $ \(n, _) ->
478 Map.insertWith (<>) [] $
481 { token_term = \src -> Token_Term_Var src n
482 , token_fixity = infixN5
484 g_term_let :: CF g (AST_Term src ss)
485 g_term_let = rule "term_let" $
487 (\name args bound body src ->
489 Token_Term_Let src name
490 (foldr (\(x, ty_x) ->
491 BinTree0 . Token_Term_Abst src x ty_x) bound args) body)
494 <*> many g_term_abst_decl
502 , Gram_Term_Atoms src ss (CF g)
504 ) => Gram_Term src ss (CF g)
506 ( Gram_Term_Atoms src ss EBNF
507 , Inj_Source (Text_of_Source src) src
509 ) => Gram_Term src ss EBNF where
510 modules_get (CF (EBNF g)) = CF $ EBNF g
511 modules_put (CF (EBNF g)) = CF $ EBNF g
513 ( Gram_Term_Atoms src ss RuleEBNF
514 , Inj_Source (Text_of_Source src) src
516 ) => Gram_Term src ss RuleEBNF where
517 modules_get (CF (RuleEBNF (EBNF g))) = CF $ RuleEBNF $ EBNF g
518 modules_put (CF (RuleEBNF (EBNF g))) = CF $ RuleEBNF $ EBNF g
520 -- ** Class 'Gram_Term_Atoms'
521 type Gram_Term_Atoms src ss g = Gram_Term_AtomsR src ss ss g
523 -- *** Class 'Gram_Term_AtomsR'
524 class Gram_Term_AtomsR src (ss::[*]) (rs::[*]) g where
525 g_term_atomsR :: Proxy rs -> [CF g (AST_Term src ss)]
526 instance Gram_Term_AtomsR src ss '[] g where
527 g_term_atomsR _rs = []
529 ( Gram_Term_AtomsFor src ss g t
530 , Gram_Term_AtomsR src ss rs g
531 ) => Gram_Term_AtomsR src ss (Proxy t ': rs) g where
533 g_term_atomsFor (Proxy @t) <>
534 g_term_atomsR (Proxy @rs)
536 -- *** Class 'Gram_Term_AtomsFor'
537 class Gram_Term_AtomsFor src ss g t where
538 g_term_atomsFor :: Proxy t -> [CF g (AST_Term src ss)]
539 g_term_atomsFor _t = []
543 ( Gram_Term () '[Proxy (->), Proxy Integer] g
547 , voiD g_term_operators
551 , void (g_term_abst_decl::CF g (NameTe, AST_Type ()))
553 , void g_term_mod_name
556 , void $ cf_of_Terminal g_term_idname_tail
557 , void $ cf_of_Reg g_term_keywords
558 , void g_term_mod_opname
560 , void $ cf_of_Terminal g_term_opname_ok
561 , void $ cf_of_Reg g_term_keysyms
563 voiD :: CF g (AST_Term () '[Proxy (->), Proxy Integer]) -> CF g ()