import qualified Data.ByteString as B
import qualified Data.List as L
import qualified Data.Map as M
+import Data.Monoid
import qualified Text.Trifecta as T
import Text.PrettyPrint.Free
import Dyna.Analysis.ANF
+import qualified Dyna.ParserHS.OneshotDriver as PD
import qualified Dyna.ParserHS.Parser as P
import Dyna.ParserHS.Selftest
import Dyna.Term.Normalized
+import Dyna.Term.SurfaceSyntax
import Dyna.Term.TTerm
import Dyna.XXX.TrifectaTest
testNormRule :: B.ByteString -> (Rule, ANFWarns)
-testNormRule = normRule . unsafeParse P.rawDRule
+testNormRule s = normRule ( 0
+ , disposTab_dyna mempty
+ , unsafeParse (T.spanned (P.testRule defDLC)) s)
{-
e1 = testNormRule "f(X)."
UpdateEvalMap {-, QueryEvalMap -})
import Dyna.Term.TTerm (DFunctAr)
import System.IO (Handle)
+import qualified Text.PrettyPrint.Free as PP
-- XXX The notion of be_constants is not quite right, I think? It is used
-- only in Dyna.Analysis.RuleMode.planEachEval to avoid generating some
-- plans, but that's not really how we should be doing it. The right
-- answer, of course, is to use update mode information, once we have it.
-type BackendDriver bs = AggMap -- ^ Aggregation
- -> UpdateEvalMap bs -- ^ Rule update
- -- -> QueryEvalMap bs -- ^ Rule query
+type BackendDriver bs = AggMap -- ^ Aggregation
+ -> UpdateEvalMap bs -- ^ Rule update
+ -- -> QueryEvalMap bs -- ^ Rule query
-> [(Rule,Cost,Actions bs)] -- ^ Initializers
- -> Handle -- ^ Output
+ -> (forall e . PP.Doc e) -- ^ Parser persistence
+ -> Handle -- ^ Output
-> IO ()
data Backend = forall bs . Backend
, be_driver = driver
}
-driver am um {-_-} is fh = hPutStrLn fh "No backend selected; stopping."
+driver _ _ {-_-} _ _ fh = hPutStrLn fh "No backend selected; stopping."
------------------------------------------------------------------------}}}
-- Primitive operations {{{
-- Driver {{{
driver :: BackendDriver PyDopeBS
-driver am um {-qm-} is fh = do
+driver am um {-qm-} is pp fh = do
-- Aggregation mapping
forM_ (M.toList am) $ \((f,a),v) -> do
hPutStrLn fh $ show $ "agg_decl"
maybeWarnANF xs = Just $ vcat $ map (uncurry renderSpannedWarn) xs
go out = do
- P.PDP rs _ <- parse
+ P.PDP rs pp <- parse
- dump DumpParsed (vcat $ map (\(i,_,r) -> text $ show (i,r)) rs)
+ dump DumpParsed $
+ (vcat $ map (\(i,_,r) -> text $ show (i,r)) rs)
+ <> line <> pp
let (frs, anfWarns) = unzip $ map normRule rs
dump DumpDopUpd (renderDopUpds be_ddi uPlans')
-- Invoke the backend code generator
- be_d aggm uPlans' {- qPlans -} initializers' out
+ be_d aggm uPlans' {- qPlans -} initializers' pp out
parse = do
pr <- T.parseFromFileEx (P.oneshotDynaParser <* T.eof) fileName
--
-- XXX add arity to key?
, _pcs_operspec :: OperSpec
- , _pcs_opertab :: EOT
+ , _pcs_ot_cache :: EOT
-- ^ Cache the operator table so we are not rebuilding it
-- before every parse operation
, _pcs_ruleix :: RuleIx
}
$(makeLenses ''PCS)
-_pcs_dlc pcs = DLC (_pcs_opertab pcs)
+_pcs_dlc pcs = DLC (_pcs_ot_cache pcs)
update_pcs_dt = pcs_dt_cache <<~
liftA2 ($) (uses pcs_dt_mk dtmk) (use pcs_dt_over)
+update_pcs_ot = pcs_ot_cache <<~ flip mkEOT True <$> (use pcs_operspec)
+
dtmk "dyna" = disposTab_dyna
dtmk "prologish" = disposTab_dyna
dtmk n = dynacPanic $ "Unknown default disposition table:"
, _pcs_modemap = mempty -- XXX
, _pcs_operspec = defOperSpec
- , _pcs_opertab = mkEOT (defPCS ^. pcs_operspec) True
+ , _pcs_ot_cache = mkEOT (defPCS ^. pcs_operspec) True
, _pcs_ruleix = 0
}
PP.<//> prettySpanLoc s
-- XXX
-pragmasFromPCS pcs = empty
+pragmasFromPCS (PCS dt_mk dt_over _
+ im mm
+ om _
+ rix) =
+ PP.vcat $ map renderPragma $
+ (map (\((k,_),(s,as)) -> PDispos s k as)
+ $ M.toList dt_over)
+ ++ [PDisposDefl dt_mk]
+ ++ (map (\(n,(as,pi,_)) -> PInst (PNWA n as) pi) $ M.toList im)
+ ++ (map (\(n,(as,pmf,pmt,_)) -> PMode (PNWA n as) pmf pmt) $ M.toList mm)
+ ++ [PRuleIx rix]
nextRule :: (DeltaParsing m, LookAheadParsing m, MonadState PCS m)
=> m (Spanned Rule)
=> m ParsedDynaProgram
oneshotDynaParser = (postProcess =<<)
$ flip runStateT defPCS
- $ many $ do
+ $ many (try $ do
r <- nextRule
rix <- pcs_ruleix <<%= (+1)
dt <- use pcs_dt_cache
- return $ (rix, dt, r)
- <* whiteSpace
+ return $ (rix, dt, r))
+ <* optional (dynaWhiteSpace (someSpace))
where
postProcess (rs,pcs) = return $ PDP rs (pragmasFromPCS pcs)
-- * Parser output types
NameWithArgs(..),
-- ** Surface langauge
- Term(..), Rule(..),
+ Term(..), Rule(..), dynaWhiteSpace,
-- ** Pragmas
ParsedInst(..), ParsedModeInst, Pragma(..), renderPragma,
-- ** Line
-- XXX Add support for Haskell-style `foo`. This requires augmenting
-- the PFIn branch of interpret below to check for the ` framing and
-- change the symbol returned (but not the symbol matched!)
+--
+-- XXX On parser failure, we get a huge mass of cruft for "expected: ...",
+-- since it blats out the entire operator table. Can we fix that?
mkEOT :: OperSpec
-> Bool -- ^ add some measure of fail-safety using generic
-- parsers
lift = DL . lift
instance (TokenParsing m, MonadPlus m) => TokenParsing (DynaLanguage m) where
- someSpace = buildSomeSpaceParser (lift someSpace) dynaCommentStyle
+ someSpace = dynaWhiteSpace (lift someSpace)
semi = lift semi
highlight h (DL m) = DL (highlight h m)
, _commentNesting = True
}
+dynaWhiteSpace :: (TokenParsing m) => m () -> m ()
+dynaWhiteSpace m = buildSomeSpaceParser m dynaCommentStyle
+
------------------------------------------------------------------------}}}
-- Identifier Syles {{{
rule :: (DeltaParsing m, LookAheadParsing m, MonadReader DLCfg m)
=> m Rule
rule = do
- _ <- optional whiteSpace
+ _ <- whiteSpace
h@(_ :~ hs) <- term
choice [ do
_ <- try (char '.' <* lookAhead whiteSpace)
------------------------------------------------------------------------}}}
-- Aggregators {{{
+test_aggregators :: [TF.Test]
test_aggregators = hUnitTestToTests $ TestList
[ TestLabel "valid" $ TestList $
map (\x -> (BU.toString x) ~: x ~=? unsafeParse testAggr x)
["+=", "*=", ".=", "min=", "max=", "?=", ":-", "max+=" ]
, TestLabel "invalid" $ TestList $
map (\x -> TestLabel (BU.toString x) $ TestCase $ checkParseFail_ testAggr x)
- [".", ". ", "+=3", "+=a" ]
+ [".", ". ", "+=3", "+3=", "+=a", "+a=" ]
]
------------------------------------------------------------------------}}}
arbAtom = elements [ "f", "+" ]
+prop_pragma_roundtrip :: Property
prop_pragma_roundtrip =
forAll arbPragma (\p -> p == unsafeParse (testPragma defDLC)
(BU.fromString
main = $(defaultMainGenerator)
------------------------------------------------------------------------}}}
--- Experimental debris (XXX) {{{
-
-{-
-runParser :: (Show a) => (forall r . Language (Parser r String) a) -> B.ByteString -> Result TermDoc a
-runParser p = parseByteString (dynafy p <* eof) M.mempty
-
-testParser :: (Show a) => (forall r . Language (Parser r String) a) -> String -> IO ()
-testParser p = parseTest (dynafy p <* eof)
-
-testDyna :: (Show a) => (forall r . Language (Parser r String) a) -> String -> Result TermDoc a
-testDyna p i = runParser p (BU.fromString i)
-
-cs r e = case r of
- Success w s | S.null w -> assertEqual "XXX" e s
- _ -> assertBool "XXX" False
--}
-
-------------------------------------------------------------------------}}}