From 585130cfacceab83b64944826e4904972d84844a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 14 Dec 2023 14:27:16 -0700 Subject: [PATCH 001/192] update readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e393772..99d6323 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,8 @@ $ cabal test --test-show-details=direct ### Use ```sh -# Compile and evaluate t.hs -$ rlpc t.hs -# Compile and evaluate t.hs, with evaluation info dumped to stderr -$ rlpc -ddump-eval t.hs +# Compile and evaluate examples/factorial.hs, with evaluation info dumped to stderr +$ rlpc -ddump-eval examples/factorial.hs # Compile and evaluate t.hs, with evaluation info dumped to t.log $ rlpc -ddump-eval -l t.log t.hs # Print the raw structure describing the compiler options and die -- 2.52.0 From 136e3687b079d6374e97cdaea92f042be4e9b4f1 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 15:36:17 -0700 Subject: [PATCH 002/192] Literal -> Lit, LitE -> Lit --- src/Core/Parse.y | 2 +- src/Core/Syntax.hs | 8 ++++---- src/Core/Utils.hs | 2 +- src/Core2Core.hs | 4 ++-- src/GM.hs | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 94d0dcc..4dab15a 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -123,7 +123,7 @@ Alter :: { Alter Name } Alter : litint ParList '->' Expr { Alter (AltData $1) $2 $4 } Expr1 :: { Expr Name } -Expr1 : litint { LitE $ IntL $1 } +Expr1 : litint { Lit $ IntL $1 } | Id { Var $1 } | PackCon { $1 } | ExprPragma { $1 } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 676cf3b..2fc88f0 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -7,7 +7,7 @@ Description : Core ASTs and the like module Core.Syntax ( Expr(..) , Type(..) - , Literal(..) + , Lit(..) , pattern (:$) , Binding(..) , AltCon(..) @@ -47,7 +47,7 @@ data Expr b = Var Name | Lam [b] (Expr b) | Let Rec [Binding b] (Expr b) | App (Expr b) (Expr b) - | LitE Literal + | Lit Lit | Type Type deriving (Show, Read, Lift) @@ -87,11 +87,11 @@ data Rec = Rec deriving (Show, Read, Eq, Lift) data AltCon = AltData Tag - | AltLiteral Literal + | AltLit Lit | Default deriving (Show, Read, Eq, Lift) -data Literal = IntL Int +data Lit = IntL Int deriving (Show, Read, Eq, Lift) type Name = String diff --git a/src/Core/Utils.hs b/src/Core/Utils.hs index dd9c6ed..892a7e3 100644 --- a/src/Core/Utils.hs +++ b/src/Core/Utils.hs @@ -32,7 +32,7 @@ rhssOf = fromList . fmap f isAtomic :: Expr b -> Bool isAtomic (Var _) = True -isAtomic (LitE _) = True +isAtomic (Lit _) = True isAtomic _ = False ---------------------------------------------------------------------------------- diff --git a/src/Core2Core.hs b/src/Core2Core.hs index ed885bc..7aa9dc6 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -55,7 +55,7 @@ floatNonStrictCases g = goE where goE :: Expr' -> Floater Expr' goE (Var k) = pure (Var k) - goE (LitE l) = pure (LitE l) + goE (Lit l) = pure (Lit l) goE (Case e as) = pure (Case e as) goE (Let Rec bs e) = Let Rec <$> bs' <*> goE e where bs' = travBs goE bs @@ -77,7 +77,7 @@ floatNonStrictCases g = goE goC (f :$ x) = (:$) <$> goC f <*> goC x goC (Let r bs e) = Let r <$> bs' <*> goE e where bs' = travBs goC bs - goC (LitE l) = pure (LitE l) + goC (Lit l) = pure (Lit l) goC (Var k) = pure (Var k) goC (Con t as) = pure (Con t as) diff --git a/src/GM.hs b/src/GM.hs index a29e158..00f125f 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -617,7 +617,7 @@ buildInitialHeap (Program ss) = mapAccumL allocateSc mempty compiledScs f (NameKey n, _) = Just n f _ = Nothing - compileC _ (LitE l) = compileCL l + compileC _ (Lit l) = compileCL l -- >> [ref/compileC] compileC g (App f x) = compileC g x @@ -661,16 +661,16 @@ buildInitialHeap (Program ss) = mapAccumL allocateSc mempty compiledScs compileC _ _ = error "yet to be implemented!" - compileCL :: Literal -> Code + compileCL :: Lit -> Code compileCL (IntL n) = [PushInt n] - compileEL :: Literal -> Code + compileEL :: Lit -> Code compileEL (IntL n) = [PushInt n] -- compile an expression in a strict context such that a pointer to the -- expression is left on top of the stack in WHNF compileE :: Env -> Expr' -> Code - compileE _ (LitE l) = compileEL l + compileE _ (Lit l) = compileEL l compileE g (Let NonRec bs e) = -- we use compileE instead of compileC mconcat binders <> compileE g' e <> [Slide d] -- 2.52.0 From 20c936f317599b9c917ae7c19d39723a5a5be745 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 14 Dec 2023 16:12:20 -0700 Subject: [PATCH 003/192] commentary --- doc/src/commentary/gm.rst | 30 +++++++++++++++++++++--------- doc/src/commentary/ti.rst | 6 ------ doc/src/conf.py | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) delete mode 100644 doc/src/commentary/ti.rst diff --git a/doc/src/commentary/gm.rst b/doc/src/commentary/gm.rst index 1682a58..4cf3d6a 100644 --- a/doc/src/commentary/gm.rst +++ b/doc/src/commentary/gm.rst @@ -1,16 +1,24 @@ The *G-Machine* =============== +The G-Machine (graph machine) is the current heart of rlpc, until we potentially +move onto a STG (spineless tagless graph machine) or a TIM (three-instruction +machine). rl' source code is desugared into Core; a dumbed-down subset of rl', +and then compiled to G-Machine code, which is then finally translated to the +desired target. + ********** Motivation ********** -Our initial model, the *Template Instantiator* (TI) was a very -straightforward solution to compilation, but its core design has a major -Achilles' heel, being that Compilation is interleaved with evaluation -- The -heap nodes for supercombinators hold uninstantiated expressions, i.e. raw ASTs -straight from the parser. When a supercombinator is found on the stack during -evaluation, the template expression is instantiated (compiled) on the spot. +Our initial model, the *Template Instantiator* (TI) was a very straightforward +solution to compilation, but its core design has a major Achilles' heel, being +that compilation is interleaved with evaluation -- The heap nodes for +supercombinators hold uninstantiated expressions, i.e. raw ASTs straight from +the parser. When a supercombinator is found on the stack during evaluation, the +template expression is instantiated (compiled) on the spot. This makes +translation to an assembly difficult, undermining the point of an intermediate +language. .. math:: \transrule @@ -31,7 +39,7 @@ evaluation, the template expression is instantiated (compiled) on the spot. \text{where } h' = \mathtt{instantiateU} \; e \; a_n \; h \; g } -The process of instantiating a supercombinator goes something like this +The process of instantiating a supercombinator goes something like this: 1. Augment the environment with bindings to the arguments. @@ -52,13 +60,17 @@ The process of instantiating a supercombinator goes something like this Instantiating the supercombinator's body in this way is the root of our Achilles' heel. Traversing a tree structure is a very non-linear task unfit for an assembly target. The goal of our new G-Machine is to compile a *linear -sequence of instructions* which instantiate the expression at execution. +sequence of instructions* which, **when executed**, build up a graph +representing the code. ************************** Trees and Vines, in Theory ************************** -WIP. +Rather than instantiating an expression at runtime -- traversing the AST and +building a graph -- we want to compile all expressions at compile-time, +generating a linear sequence of instructions which may be executed to build the +graph. ************************** Evaluation: Slurping Vines diff --git a/doc/src/commentary/ti.rst b/doc/src/commentary/ti.rst deleted file mode 100644 index 4e167d0..0000000 --- a/doc/src/commentary/ti.rst +++ /dev/null @@ -1,6 +0,0 @@ -The *Template Instantiator* -==================================== - -WIP. This will hopefully be expanded into a thorough walkthrough of the state -machine. - diff --git a/doc/src/conf.py b/doc/src/conf.py index 1cd64cc..d344334 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -13,7 +13,7 @@ author = 'madeleine sydney slaga' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = ['sphinx.ext.imgmath'] +extensions = ['sphinx.ext.imgmath', 'sphinx.ext.graphviz'] # templates_path = ['_templates'] exclude_patterns = [] -- 2.52.0 From 78f88e085f1b7d44d6e5a7851d96d9bd5983542c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 17 Dec 2023 15:23:09 -0700 Subject: [PATCH 004/192] infer --- rlp.cabal | 7 ++- src/Core/HindleyMilner.hs | 90 +++++++++++++++++++++++++++++++++++ src/Core/Syntax.hs | 14 +++++- tst/Core/HindleyMilnerSpec.hs | 19 ++++++++ 4 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/Core/HindleyMilner.hs create mode 100644 tst/Core/HindleyMilnerSpec.hs diff --git a/rlp.cabal b/rlp.cabal index 33c4d95..f5b26ab 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -26,13 +26,14 @@ library , Core.Examples , Core.Utils , Core.TH + , Core.HindleyMilner other-modules: Data.Heap , Data.Pretty , Core.Parse , Core.Lex - , Control.Monad.Errorful , Core2Core + , Control.Monad.Errorful , RLP.Syntax build-tool-depends: happy:happy, alex:alex @@ -41,6 +42,7 @@ library build-depends: base ^>=4.18.0.0 , containers , microlens + , microlens-mtl , microlens-th , mtl , template-haskell @@ -50,6 +52,8 @@ library , unordered-containers , hashable , pretty + -- TODO: either learn recursion-schemes, or stop depending + -- on it. , recursion-schemes , megaparsec , text @@ -86,5 +90,6 @@ test-suite rlp-test , hspec ==2.* other-modules: Arith , GMSpec + , Core.HindleyMilnerSpec build-tool-depends: hspec-discover:hspec-discover diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs new file mode 100644 index 0000000..f437ad0 --- /dev/null +++ b/src/Core/HindleyMilner.hs @@ -0,0 +1,90 @@ +{-# LANGUAGE LambdaCase #-} +module Core.HindleyMilner + ( infer + , Context' + ) + where +---------------------------------------------------------------------------------- +import Lens.Micro +import Lens.Micro.Mtl +import Data.Set qualified as S +import Data.Set (Set) +import Data.Maybe (fromMaybe) +import Control.Monad.State +import Core.Syntax +---------------------------------------------------------------------------------- + +type Context b = [(b, Type)] + +type Context' = Context Name + +infer :: Context' -> Expr' -> Maybe Type +infer g e = foldr (uncurry subst) t <$> unify cs where + (t,cs) = gather g e + +type Constraint = (Type, Type) + +gather :: Context' -> Expr' -> (Type, [Constraint]) +gather = \g e -> let (t,(cs,_)) = runState (go g e) ([],0) in (t,cs) where + go :: Context' -> Expr' -> State ([Constraint], Int) Type + go g = \case + LitE (IntL _) -> pure TyInt + Var k -> maybe e pure $ lookup k g + where e = error $ "variable `" <> k <> "' untyped in Γ" + App f x -> do + tf <- go g f + tx <- go g x + tfx <- uniqueVar + addConstraint tf (tx :-> tfx) + pure tfx + +uniqueVar :: State ([Constraint], Int) Type +uniqueVar = do + n <- use _2 + _2 %= succ + pure (TyVar $ '$' : 'a' : show n) + +addConstraint :: Type -> Type -> State ([Constraint], Int) () +addConstraint t u = _1 %= ((t, u):) + +unify :: [Constraint] -> Maybe Context' +unify = go mempty where + go :: Context' -> [Constraint] -> Maybe Context' + + -- nothing left! return accumulator + go g [] = Just g + + go g (c:cs) = case c of + -- primitives may of course unify with themselves + (TyInt, TyInt) -> go g cs + + -- `x` unifies with `x` + (TyVar t, TyVar u) | t == u -> go g cs + + -- a type variable `x` unifies with an arbitrary type `t` if `t` does + -- not reference `x` + (TyVar x, t) -> unifyTV g x t cs + (t, TyVar x) -> unifyTV g x t cs + + -- two functions may be unified if their domain and codomain unify + (a :-> b, x :-> y) -> go g $ (a,x) : (b,y) : cs + + _ -> Nothing + + unifyTV :: Context' -> Name -> Type -> [Constraint] -> Maybe Context' + unifyTV g x t cs | occurs t = Nothing + | otherwise = go g' substed + where + g' = (x,t) : g + substed = cs & each . both %~ subst x t + + occurs (a :-> b) = occurs a || occurs b + occurs (TyVar y) + | x == y = True + occurs _ = False + +subst :: String -> Type -> Type -> Type +subst x t (TyVar y) | x == y = t +subst x t (a :-> b) = subst x t a :-> subst x t b +subst _ _ e = e + diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 2fc88f0..9025613 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -9,6 +9,8 @@ module Core.Syntax , Type(..) , Lit(..) , pattern (:$) + , pattern (:@) + , pattern (:->) , Binding(..) , AltCon(..) , pattern (:=) @@ -57,15 +59,23 @@ data Type = TyInt | TyFun | TyVar Name | TyApp Type Type - | TyConApp TyCon [Type] + -- | TyConApp TyCon [Type] deriving (Show, Read, Lift, Eq) type TyCon = Name infixl 2 :$ -pattern (:$) :: Expr b -> Expr b -> Expr b +pattern (:$) :: Expr b -> Expr b -> Expr b pattern f :$ x = App f x +infixl 2 :@ +pattern (:@) :: Type -> Type -> Type +pattern f :@ x = TyApp f x + +infixr 1 :-> +pattern (:->) :: Type -> Type -> Type +pattern a :-> b = TyApp (TyApp TyFun a) b + {-# COMPLETE Binding :: Binding #-} {-# COMPLETE (:=) :: Binding #-} data Binding b = Binding b (Expr b) diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs new file mode 100644 index 0000000..5beabb2 --- /dev/null +++ b/tst/Core/HindleyMilnerSpec.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE QuasiQuotes #-} +module Core.HindleyMilnerSpec + ( spec + ) + where +---------------------------------------------------------------------------------- +import Core.Syntax +import Core.TH (coreExpr) +import Core.HindleyMilner (infer) +import Test.Hspec +---------------------------------------------------------------------------------- + +-- TODO: more tests. preferrably property-based. lol. +spec :: Spec +spec = do + it "should infer `id 3` :: Int" $ + let g = [ ("id", TyVar "a" :-> TyVar "a") ] + in infer g [coreExpr|id 3|] `shouldBe` Just TyInt + -- 2.52.0 From f7e850c61a07c686fb89ebef620106f7336d80c8 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 10:05:34 -0700 Subject: [PATCH 005/192] hindley milner inference :D --- src/Core/HindleyMilner.hs | 23 +++++++++++++++-------- src/Core/Syntax.hs | 2 -- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index f437ad0..c5b9e99 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -2,6 +2,7 @@ module Core.HindleyMilner ( infer , Context' + , TypeError(..) ) where ---------------------------------------------------------------------------------- @@ -18,7 +19,12 @@ type Context b = [(b, Type)] type Context' = Context Name -infer :: Context' -> Expr' -> Maybe Type +-- TODO: Errorful monad? +data TypeError = TyErrCouldNotUnify Type Type + | TyErrRecursiveType Name Type + deriving Show + +infer :: Context' -> Expr' -> Either TypeError Type infer g e = foldr (uncurry subst) t <$> unify cs where (t,cs) = gather g e @@ -47,12 +53,12 @@ uniqueVar = do addConstraint :: Type -> Type -> State ([Constraint], Int) () addConstraint t u = _1 %= ((t, u):) -unify :: [Constraint] -> Maybe Context' +unify :: [Constraint] -> Either TypeError Context' unify = go mempty where - go :: Context' -> [Constraint] -> Maybe Context' + go :: Context' -> [Constraint] -> Either TypeError Context' - -- nothing left! return accumulator - go g [] = Just g + -- nothing left! return accumulated context + go g [] = Right g go g (c:cs) = case c of -- primitives may of course unify with themselves @@ -69,10 +75,11 @@ unify = go mempty where -- two functions may be unified if their domain and codomain unify (a :-> b, x :-> y) -> go g $ (a,x) : (b,y) : cs - _ -> Nothing + -- anything else is a failure :( + (t,u) -> Left $ TyErrCouldNotUnify t u - unifyTV :: Context' -> Name -> Type -> [Constraint] -> Maybe Context' - unifyTV g x t cs | occurs t = Nothing + unifyTV :: Context' -> Name -> Type -> [Constraint] -> Either TypeError Context' + unifyTV g x t cs | occurs t = Left $ TyErrRecursiveType x t | otherwise = go g' substed where g' = (x,t) : g diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 9025613..c6fbb5c 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -50,7 +50,6 @@ data Expr b = Var Name | Let Rec [Binding b] (Expr b) | App (Expr b) (Expr b) | Lit Lit - | Type Type deriving (Show, Read, Lift) deriving instance (Eq b) => Eq (Expr b) @@ -59,7 +58,6 @@ data Type = TyInt | TyFun | TyVar Name | TyApp Type Type - -- | TyConApp TyCon [Type] deriving (Show, Read, Lift, Eq) type TyCon = Name -- 2.52.0 From 047091298337ae4b299d7b294459e57215d720cf Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 11:11:22 -0700 Subject: [PATCH 006/192] comments and better type errors --- src/Core/HindleyMilner.hs | 79 ++++++++++++++++++++++++++++------- src/Core/Syntax.hs | 2 +- tst/Core/HindleyMilnerSpec.hs | 2 +- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index c5b9e99..514fa0b 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -1,3 +1,7 @@ +{-| +Module : Core.HindleyMilner +Description : Hindley-Milner inference +-} {-# LANGUAGE LambdaCase #-} module Core.HindleyMilner ( infer @@ -15,28 +19,65 @@ import Control.Monad.State import Core.Syntax ---------------------------------------------------------------------------------- +-- | Annotated typing context -- I have a feeling we're going to want this in the +-- future. type Context b = [(b, Type)] +-- | Unannotated typing context, AKA our beloved Γ. type Context' = Context Name -- TODO: Errorful monad? -data TypeError = TyErrCouldNotUnify Type Type - | TyErrRecursiveType Name Type - deriving Show + +-- | Type error enum. +data TypeError + -- | Two types could not be unified + = TyErrCouldNotUnify Type Type + -- | @x@ could not be unified with @t@ because @x@ occurs in @t@ + | TyErrRecursiveType Name Type + -- | Untyped, potentially undefined variable + | TyErrUntypedVariable Name + deriving (Show, Eq) + +-- | Synonym for @Either TypeError@ +type HMError = Either TypeError + +-- | Infer the type of an expression under some context. +-- +-- >>> let g1 = [("id", TyVar "a" :-> TyVar "a")] +-- >>> let g2 = [("id", (TyVar "a" :-> TyVar "a") :-> TyVar "a" :-> TyVar "a")] +-- >>> infer g1 [coreExpr|id 3|] +-- Right TyInt +-- >>> infer g2 [coreExpr|id 3|] +-- Left (TyErrCouldNotUnify (TyVar "a" :-> TyVar "a") TyInt) infer :: Context' -> Expr' -> Either TypeError Type -infer g e = foldr (uncurry subst) t <$> unify cs where - (t,cs) = gather g e +infer g e = do + (t,cs) <- gather g e + foldr (uncurry subst) t <$> unify cs +-- | A @Constraint@ between two types describes the requirement that the pair +-- must unify type Constraint = (Type, Type) -gather :: Context' -> Expr' -> (Type, [Constraint]) -gather = \g e -> let (t,(cs,_)) = runState (go g e) ([],0) in (t,cs) where - go :: Context' -> Expr' -> State ([Constraint], Int) Type +-- | Type of an expression under some context, and gather the constraints +-- necessary to unify. Note that this is not the same as @infer@, as the +-- expression will likely be given a fresh type variable along with a +-- constraint, rather than the solved type. +-- +-- For example, if the context says "@id@ has type a -> a," in an application of +-- @id 3@, the whole application is assigned type @$a0@ and the constraint that +-- @id@ must unify with type @Int -> $a0@ is generated. +-- +-- >>> gather [("id", TyVar "a" :-> TyVar "a")] [coreExpr|id 3|] +-- (TyVar "$a0",[(TyVar "a" :-> TyVar "a",TyInt :-> TyVar "$a0")]) + +gather :: Context' -> Expr' -> HMError (Type, [Constraint]) +gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where + go :: Context' -> Expr' -> StateT ([Constraint], Int) HMError Type go g = \case LitE (IntL _) -> pure TyInt - Var k -> maybe e pure $ lookup k g - where e = error $ "variable `" <> k <> "' untyped in Γ" + Var k -> lift $ maybe e Right $ lookup k g + where e = Left (TyErrUntypedVariable k) App f x -> do tf <- go g f tx <- go g x @@ -44,18 +85,23 @@ gather = \g e -> let (t,(cs,_)) = runState (go g e) ([],0) in (t,cs) where addConstraint tf (tx :-> tfx) pure tfx -uniqueVar :: State ([Constraint], Int) Type +uniqueVar :: StateT ([Constraint], Int) HMError Type uniqueVar = do n <- use _2 _2 %= succ pure (TyVar $ '$' : 'a' : show n) -addConstraint :: Type -> Type -> State ([Constraint], Int) () +addConstraint :: Type -> Type -> StateT ([Constraint], Int) HMError () addConstraint t u = _1 %= ((t, u):) -unify :: [Constraint] -> Either TypeError Context' +-- | Unify a list of constraints, meaning that pairs between types are turned +-- into pairs of type variables and types. A useful thought model is to think of +-- it like solving an equation such that the unknown variable is the left-hand +-- side. + +unify :: [Constraint] -> HMError Context' unify = go mempty where - go :: Context' -> [Constraint] -> Either TypeError Context' + go :: Context' -> [Constraint] -> HMError Context' -- nothing left! return accumulated context go g [] = Right g @@ -90,7 +136,10 @@ unify = go mempty where | x == y = True occurs _ = False -subst :: String -> Type -> Type -> Type +-- | The expression @subst x t e@ substitutes all occurences of @x@ in @e@ with +-- @t@ + +subst :: Name -> Type -> Type -> Type subst x t (TyVar y) | x == y = t subst x t (a :-> b) = subst x t a :-> subst x t b subst _ _ e = e diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index c6fbb5c..1681a26 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -44,7 +44,7 @@ import Lens.Micro ---------------------------------------------------------------------------------- data Expr b = Var Name - | Con Tag Int -- Con Tag Arity + | Con Tag Int -- ^ Con Tag Arity | Case (Expr b) [Alter b] | Lam [b] (Expr b) | Let Rec [Binding b] (Expr b) diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 5beabb2..008510a 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -15,5 +15,5 @@ spec :: Spec spec = do it "should infer `id 3` :: Int" $ let g = [ ("id", TyVar "a" :-> TyVar "a") ] - in infer g [coreExpr|id 3|] `shouldBe` Just TyInt + in infer g [coreExpr|id 3|] `shouldBe` Right TyInt -- 2.52.0 From e9e1c075db3c5b6df9e8010ba12aa736c0389c9f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 11:22:40 -0700 Subject: [PATCH 007/192] type IsString + test unification error --- src/Core/HindleyMilner.hs | 3 ++- src/Core/Syntax.hs | 3 +++ tst/Core/HindleyMilnerSpec.hs | 14 +++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 514fa0b..b59b7a5 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -7,6 +7,7 @@ module Core.HindleyMilner ( infer , Context' , TypeError(..) + , HMError ) where ---------------------------------------------------------------------------------- @@ -50,7 +51,7 @@ type HMError = Either TypeError -- >>> infer g2 [coreExpr|id 3|] -- Left (TyErrCouldNotUnify (TyVar "a" :-> TyVar "a") TyInt) -infer :: Context' -> Expr' -> Either TypeError Type +infer :: Context' -> Expr' -> HMError Type infer g e = do (t,cs) <- gather g e foldr (uncurry subst) t <$> unify cs diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 1681a26..fab3170 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -126,6 +126,9 @@ type Binding' = Binding Name instance IsString (Expr b) where fromString = Var +instance IsString Type where + fromString = TyVar + instance Semigroup (Program b) where (<>) = coerce $ (<>) @[ScDef b] diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 008510a..c50be15 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE QuasiQuotes, OverloadedStrings #-} module Core.HindleyMilnerSpec ( spec ) @@ -6,7 +6,7 @@ module Core.HindleyMilnerSpec ---------------------------------------------------------------------------------- import Core.Syntax import Core.TH (coreExpr) -import Core.HindleyMilner (infer) +import Core.HindleyMilner (infer, TypeError(..), HMError) import Test.Hspec ---------------------------------------------------------------------------------- @@ -14,6 +14,14 @@ import Test.Hspec spec :: Spec spec = do it "should infer `id 3` :: Int" $ - let g = [ ("id", TyVar "a" :-> TyVar "a") ] + let g = [ ("id", "a" :-> "a") ] in infer g [coreExpr|id 3|] `shouldBe` Right TyInt + it "should not infer `id 3` when `id` is specialised to `a -> a`" $ + let g = [ ("id", ("a" :-> "a") :-> "a" :-> "a") ] + in infer g [coreExpr|id 3|] `shouldSatisfy` isUntypedVariableErr + +isUntypedVariableErr :: HMError a -> Bool +isUntypedVariableErr (Left (TyErrCouldNotUnify _ _)) = True +isUntypedVariableErr _ = False + -- 2.52.0 From e222dae6ac4598b5a464a69fe886e550f82d7f19 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 12:21:53 -0700 Subject: [PATCH 008/192] infer nonrec let binds infer nonrec let binds --- rlp.cabal | 1 + src/Control/Monad/Utils.hs | 21 +++++++++++++++++++++ src/Core/HindleyMilner.hs | 15 +++++++++++++-- tst/Core/HindleyMilnerSpec.hs | 11 +++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/Control/Monad/Utils.hs diff --git a/rlp.cabal b/rlp.cabal index f5b26ab..4803362 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -34,6 +34,7 @@ library , Core.Lex , Core2Core , Control.Monad.Errorful + , Control.Monad.Utils , RLP.Syntax build-tool-depends: happy:happy, alex:alex diff --git a/src/Control/Monad/Utils.hs b/src/Control/Monad/Utils.hs new file mode 100644 index 0000000..6cc5521 --- /dev/null +++ b/src/Control/Monad/Utils.hs @@ -0,0 +1,21 @@ +module Control.Monad.Utils + ( mapAccumLM + ) + where +---------------------------------------------------------------------------------- +import Data.Tuple (swap) +import Control.Monad.State +---------------------------------------------------------------------------------- + +-- | Monadic variant of @mapAccumL@ + +mapAccumLM :: forall m t s a b. (Monad m, Traversable t) + => (s -> a -> m (s, b)) + -> s + -> t a + -> m (s, t b) +mapAccumLM k s t = swap <$> runStateT (traverse k' t) s + where + k' :: a -> StateT s m b + k' a = StateT $ fmap swap <$> flip k a + diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index b59b7a5..0897ece 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -13,10 +13,10 @@ module Core.HindleyMilner ---------------------------------------------------------------------------------- import Lens.Micro import Lens.Micro.Mtl -import Data.Set qualified as S -import Data.Set (Set) import Data.Maybe (fromMaybe) +import Control.Monad (foldM) import Control.Monad.State +import Control.Monad.Utils (mapAccumLM) import Core.Syntax ---------------------------------------------------------------------------------- @@ -85,6 +85,17 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where tfx <- uniqueVar addConstraint tf (tx :-> tfx) pure tfx + Let NonRec bs e -> do + g' <- buildLetContext g bs + go g' e + + buildLetContext :: Context' -> [Binding'] + -> StateT ([Constraint], Int) HMError Context' + buildLetContext = foldM k where + k :: Context' -> Binding' -> StateT ([Constraint], Int) HMError Context' + k g (x := y) = do + ty <- go g y + pure ((x,ty) : g) uniqueVar :: StateT ([Constraint], Int) HMError Type uniqueVar = do diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index c50be15..74a2468 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -21,6 +21,17 @@ spec = do let g = [ ("id", ("a" :-> "a") :-> "a" :-> "a") ] in infer g [coreExpr|id 3|] `shouldSatisfy` isUntypedVariableErr + -- TODO: property-based tests for let + it "should infer `let x = 3 in id x` :: Int" $ + let g = [ ("id", "a" :-> "a") ] + e = [coreExpr|let {x = 3} in id x|] + in infer g e `shouldBe` Right TyInt + + it "should infer `let x = 3; y = 2 in (+#) x y` :: Int" $ + let g = [ ("+#", TyInt :-> TyInt :-> TyInt) ] + e = [coreExpr|let {x=3;y=2} in (+#) x y|] + in infer g e `shouldBe` Right TyInt + isUntypedVariableErr :: HMError a -> Bool isUntypedVariableErr (Left (TyErrCouldNotUnify _ _)) = True isUntypedVariableErr _ = False -- 2.52.0 From ac6f826141b384d95bdedbf6e563a76c5f312534 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 15:30:39 -0700 Subject: [PATCH 009/192] small --- src/Core/HindleyMilner.hs | 2 +- src/Core/Syntax.hs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 0897ece..e159d8d 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -108,7 +108,7 @@ addConstraint t u = _1 %= ((t, u):) -- | Unify a list of constraints, meaning that pairs between types are turned -- into pairs of type variables and types. A useful thought model is to think of --- it like solving an equation such that the unknown variable is the left-hand +-- it as solving an equation such that the unknown variable is the left-hand -- side. unify :: [Constraint] -> HMError Context' diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index fab3170..1e99723 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -58,6 +58,7 @@ data Type = TyInt | TyFun | TyVar Name | TyApp Type Type + | TyCon Name deriving (Show, Read, Lift, Eq) type TyCon = Name -- 2.52.0 From 52b7723ea058a30f7a4d5f351f408e6d324856d4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 15:38:26 -0700 Subject: [PATCH 010/192] LitE -> Lit --- src/Core/HindleyMilner.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index e159d8d..9c4ac73 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -76,7 +76,7 @@ gather :: Context' -> Expr' -> HMError (Type, [Constraint]) gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where go :: Context' -> Expr' -> StateT ([Constraint], Int) HMError Type go g = \case - LitE (IntL _) -> pure TyInt + Lit (IntL _) -> pure TyInt Var k -> lift $ maybe e Right $ lookup k g where e = Left (TyErrUntypedVariable k) App f x -> do -- 2.52.0 From d9547346601c052bfe91bdec68970f49396d82fb Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 18 Dec 2023 15:42:41 -0700 Subject: [PATCH 011/192] LitE -> Lit --- tst/Arith.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/Arith.hs b/tst/Arith.hs index ea91311..700849b 100644 --- a/tst/Arith.hs +++ b/tst/Arith.hs @@ -76,7 +76,7 @@ toCore expr = Program ] where go :: ArithExpr -> Expr' - go (IntA n) = LitE (IntL n) + go (IntA n) = Lit (IntL n) go (NegateA e) = "negate#" :$ go e go (IdA e) = "id" :$ go e go (a :+ b) = f "+#" a b -- 2.52.0 From 6f522d34ff2191461c48b84b9045ecd7875bcc71 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 14:12:45 -0700 Subject: [PATCH 012/192] TyInt -> TyCon "Int#" --- src/Core/Syntax.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 1e99723..24d13b9 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -7,6 +7,7 @@ Description : Core ASTs and the like module Core.Syntax ( Expr(..) , Type(..) + , pattern TyInt , Lit(..) , pattern (:$) , pattern (:@) @@ -54,14 +55,14 @@ data Expr b = Var Name deriving instance (Eq b) => Eq (Expr b) -data Type = TyInt - | TyFun +data Type = TyFun | TyVar Name | TyApp Type Type | TyCon Name deriving (Show, Read, Lift, Eq) -type TyCon = Name +pattern TyInt :: Type +pattern TyInt = TyCon "Int#" infixl 2 :$ pattern (:$) :: Expr b -> Expr b -> Expr b -- 2.52.0 From 414312cf98c34c703e95448f6664f96d8be0fc7c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 13:41:43 -0700 Subject: [PATCH 013/192] parse type sigs; program type sigs --- src/Core/Examples.hs | 63 +++++++++++++++++++++++++------------------- src/Core/Lex.x | 2 ++ src/Core/Parse.y | 24 ++++++++++++++++- src/Core/Syntax.hs | 21 +++++++++++---- src/Core/Utils.hs | 7 ++--- src/Core2Core.hs | 2 +- src/GM.hs | 10 ++++--- 7 files changed, 88 insertions(+), 41 deletions(-) diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index 430a94f..cb1823e 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -15,7 +15,14 @@ import Core.Syntax import Core.TH ---------------------------------------------------------------------------------- --- TODO: my shitty lexer isn't inserting semicolons +-- +fac3 = undefined +sumList = undefined +constDivZero = undefined +idCase = undefined +--} + +{-- letrecExample :: Program' letrecExample = [coreProg| @@ -191,30 +198,32 @@ idCase = [coreProg| }) |] -corePrelude :: Module Name -corePrelude = Module (Just ("Prelude", [])) $ - -- non-primitive defs - [coreProg| - id x = x; - k x y = x; - k1 x y = y; - s f g x = f x (g x); - compose f g x = f (g x); - twice f x = f (f x); - fst p = casePair# p k; - snd p = casePair# p k1; - head l = caseList# l abort# k; - tail l = caseList# l abort# k1; - _length_cc x xs = (+#) 1 (length xs); - length l = caseList# l 0 length_cc; - |] - <> - -- primitive constructors need some specialised wiring: - Program - [ ScDef "False" [] $ Con 0 0 - , ScDef "True" [] $ Con 1 0 - , ScDef "MkPair" [] $ Con 0 2 - , ScDef "Nil" [] $ Con 1 0 - , ScDef "Cons" [] $ Con 2 2 - ] +-- corePrelude :: Module Name +-- corePrelude = Module (Just ("Prelude", [])) $ +-- -- non-primitive defs +-- [coreProg| +-- id x = x; +-- k x y = x; +-- k1 x y = y; +-- s f g x = f x (g x); +-- compose f g x = f (g x); +-- twice f x = f (f x); +-- fst p = casePair# p k; +-- snd p = casePair# p k1; +-- head l = caseList# l abort# k; +-- tail l = caseList# l abort# k1; +-- _length_cc x xs = (+#) 1 (length xs); +-- length l = caseList# l 0 length_cc; +-- |] +-- <> +-- -- primitive constructors need some specialised wiring: +-- Program +-- [ ScDef "False" [] $ Con 0 0 +-- , ScDef "True" [] $ Con 1 0 +-- , ScDef "MkPair" [] $ Con 0 2 +-- , ScDef "Nil" [] $ Con 1 0 +-- , ScDef "Cons" [] $ Con 2 2 +-- ] + +--} diff --git a/src/Core/Lex.x b/src/Core/Lex.x index b666d69..55946e8 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -68,6 +68,7 @@ rlp :- "{" { constTok TokenLBrace } "}" { constTok TokenRBrace } ";" { constTok TokenSemicolon } + "::" { constTok TokenHasType } "@" { constTok TokenTypeApp } "{-#" { constTok TokenLPragma `andBegin` pragma } @@ -134,6 +135,7 @@ data CoreToken = TokenLet | TokenLBrace | TokenRBrace | TokenSemicolon + | TokenHasType | TokenTypeApp | TokenLPragma | TokenRPragma diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 4dab15a..a2f8496 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -19,7 +19,10 @@ import Data.Foldable (foldl') import Core.Syntax import Core.Lex import Compiler.RLPC +import Lens.Micro import Data.Default.Class (def) +import Data.Hashable (Hashable) +import Data.HashMap.Strict qualified as H } %name parseCore Module @@ -55,6 +58,7 @@ import Data.Default.Class (def) '{-#' { Located _ _ _ TokenLPragma } '#-}' { Located _ _ _ TokenRPragma } ';' { Located _ _ _ TokenSemicolon } + '::' { Located _ _ _ TokenHasType } eof { Located _ _ _ TokenEOF } %% @@ -71,7 +75,15 @@ StandaloneProgram :: { Program Name } StandaloneProgram : Program eof { $1 } Program :: { Program Name } -Program : ScDefs { Program $1 } +Program : ScTypeSig ';' Program { insTypeSig $1 $3 } + | ScTypeSig OptSemi { singletonTypeSig $1 } + +OptSemi :: { () } +OptSemi : ';' { () } + | {- epsilon -} { () } + +ScTypeSig :: { (Name, Type) } +ScTypeSig : Var '::' Type { ($1,$3) } ScDefs :: { [ScDef Name] } ScDefs : ScDef ';' ScDefs { $1 : $3 } @@ -82,6 +94,9 @@ ScDefs : ScDef ';' ScDefs { $1 : $3 } ScDef :: { ScDef Name } ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 } +Type :: { Type } +Type : Var { TyInt } + ParList :: { [Name] } ParList : Var ParList { $1 : $2 } | {- epsilon -} { [] } @@ -190,5 +205,12 @@ exprPragma _ = addFatal err astPragma :: [String] -> RLPC SrcError (Expr Name) astPragma = pure . read . unwords +insTypeSig :: (Hashable b) => (b, Type) -> Program b -> Program b +insTypeSig ts = programTypeSigs %~ uncurry H.insert ts + +singletonTypeSig :: (Hashable b) => (b, Type) -> Program b +singletonTypeSig ts = mempty + & programTypeSigs .~ uncurry H.singleton ts + } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 24d13b9..8f20599 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -4,6 +4,7 @@ Description : Core ASTs and the like -} {-# LANGUAGE PatternSynonyms, OverloadedStrings #-} {-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE TemplateHaskell #-} module Core.Syntax ( Expr(..) , Type(..) @@ -24,6 +25,7 @@ module Core.Syntax , Program(..) , Program' , programScDefs + , programTypeSigs , Expr' , ScDef' , Alter' @@ -39,8 +41,11 @@ import GHC.Generics import Data.List (intersperse) import Data.Function ((&)) import Data.String +import Data.HashMap.Strict qualified as H +import Data.Hashable -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) +import Lens.Micro.TH (makeLenses) import Lens.Micro ---------------------------------------------------------------------------------- @@ -113,11 +118,14 @@ data ScDef b = ScDef b [b] (Expr b) data Module b = Module (Maybe (Name, [Name])) (Program b) deriving (Show, Lift) -newtype Program b = Program [ScDef b] +data Program b = Program + { _programScDefs :: [ScDef b] + , _programTypeSigs :: H.HashMap b Type + } deriving (Show, Lift) -programScDefs :: Lens' (Program b) [ScDef b] -programScDefs = lens coerce (const coerce) +makeLenses ''Program +pure [] type Program' = Program Name type Expr' = Expr Name @@ -134,8 +142,11 @@ instance IsString Type where instance Semigroup (Program b) where (<>) = coerce $ (<>) @[ScDef b] -instance Monoid (Program b) where - mempty = Program [] +instance (Hashable b) => Semigroup (Program b) where + (<>) = undefined + +instance (Hashable b) => Monoid (Program b) where + mempty = Program mempty mempty ---------------------------------------------------------------------------------- diff --git a/src/Core/Utils.hs b/src/Core/Utils.hs index 892a7e3..1a47785 100644 --- a/src/Core/Utils.hs +++ b/src/Core/Utils.hs @@ -7,7 +7,7 @@ module Core.Utils ( bindersOf , rhssOf , isAtomic - , insertModule + -- , insertModule , extractProgram , freeVariables , ExprF(..) @@ -19,6 +19,7 @@ import Data.Functor.Foldable import Data.Set (Set) import Data.Set qualified as S import Core.Syntax +import Lens.Micro import GHC.Exts (IsList(..)) ---------------------------------------------------------------------------------- @@ -38,8 +39,8 @@ isAtomic _ = False ---------------------------------------------------------------------------------- -- TODO: export list awareness -insertModule :: Module b -> Program b -> Program b -insertModule (Module _ m) p = p <> m +-- insertModule :: Module b -> Program b -> Program b +-- insertModule (Module _ p) = programScDefs %~ (<>m) extractProgram :: Module b -> Program b extractProgram (Module _ p) = p diff --git a/src/Core2Core.hs b/src/Core2Core.hs index 7aa9dc6..aca3552 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -27,7 +27,7 @@ core2core :: Program' -> Program' core2core p = undefined gmPrep :: Program' -> Program' -gmPrep p = p' <> Program caseScs +gmPrep p = p' & programScDefs %~ (<>caseScs) where rhss :: Applicative f => (Expr z -> f (Expr z)) -> Program z -> f (Program z) rhss = programScDefs . each . _rhs diff --git a/src/GM.hs b/src/GM.hs index 00f125f..7efd0cd 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -22,6 +22,7 @@ import Data.Maybe (fromMaybe, mapMaybe) import Data.Monoid (Endo(..)) import Data.Tuple (swap) import Lens.Micro +import Lens.Micro.Extras (view) import Lens.Micro.TH import Text.Printf import Text.PrettyPrint hiding ((<>)) @@ -582,7 +583,7 @@ compiledPrims = binop k i = (k, 2, [Push 1, Eval, Push 1, Eval, i, Update 2, Pop 2, Unwind]) buildInitialHeap :: Program' -> (GmHeap, Env) -buildInitialHeap (Program ss) = mapAccumL allocateSc mempty compiledScs +buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compiledScs where compiledScs = fmap compileSc ss <> compiledPrims @@ -975,7 +976,8 @@ resultOf p = do h = st ^. gmHeap resultOfExpr :: Expr' -> Maybe Node -resultOfExpr e = resultOf $ Program - [ ScDef "main" [] e - ] +resultOfExpr e = resultOf $ + mempty & programScDefs .~ + [ ScDef "main" [] e + ] -- 2.52.0 From fe90c9afb0c017e7636ace00d111deac04d2ed4e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 14:10:33 -0700 Subject: [PATCH 014/192] parse types --- src/Core/Parse.y | 9 ++++++++- src/Core/Syntax.hs | 3 --- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index a2f8496..129fb77 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -95,7 +95,14 @@ ScDef :: { ScDef Name } ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 } Type :: { Type } -Type : Var { TyInt } +Type : Type1 { $1 } + +Type1 :: { Type } +Type1 : '(' Type ')' { $2 } + | Type1 '->' Type { $1 :-> $3 } + -- do we want to use Var instead, permitting symbolic type vars? + | varname { TyVar $1 } + | conname { TyCon $1 } ParList :: { [Name] } ParList : Var ParList { $1 : $2 } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 8f20599..46179ca 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -139,9 +139,6 @@ instance IsString (Expr b) where instance IsString Type where fromString = TyVar -instance Semigroup (Program b) where - (<>) = coerce $ (<>) @[ScDef b] - instance (Hashable b) => Semigroup (Program b) where (<>) = undefined -- 2.52.0 From 5c9bf40e40f3912a9ba4fe752268d66bc46e9a72 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 14:42:35 -0700 Subject: [PATCH 015/192] parse programs (with types :D) --- src/Core/Examples.hs | 11 ----------- src/Core/Parse.y | 11 +++++++++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index cb1823e..efe953d 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -15,15 +15,6 @@ import Core.Syntax import Core.TH ---------------------------------------------------------------------------------- --- -fac3 = undefined -sumList = undefined -constDivZero = undefined -idCase = undefined ---} - -{-- - letrecExample :: Program' letrecExample = [coreProg| pair x y f = f x y; @@ -225,5 +216,3 @@ idCase = [coreProg| -- , ScDef "Cons" [] $ Con 2 2 -- ] ---} - diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 129fb77..111fe59 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -77,6 +77,8 @@ StandaloneProgram : Program eof { $1 } Program :: { Program Name } Program : ScTypeSig ';' Program { insTypeSig $1 $3 } | ScTypeSig OptSemi { singletonTypeSig $1 } + | ScDef ';' Program { insScDef $1 $3 } + | ScDef OptSemi { singletonScDef $1 } OptSemi :: { () } OptSemi : ';' { () } @@ -216,8 +218,13 @@ insTypeSig :: (Hashable b) => (b, Type) -> Program b -> Program b insTypeSig ts = programTypeSigs %~ uncurry H.insert ts singletonTypeSig :: (Hashable b) => (b, Type) -> Program b -singletonTypeSig ts = mempty - & programTypeSigs .~ uncurry H.singleton ts +singletonTypeSig ts = insTypeSig ts mempty + +insScDef :: (Hashable b) => ScDef b -> Program b -> Program b +insScDef sc = programScDefs %~ (sc:) + +singletonScDef :: (Hashable b) => ScDef b -> Program b +singletonScDef sc = insScDef sc mempty } -- 2.52.0 From 07be32c618682853d3cb37a0233e1301f0260be4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 14:49:40 -0700 Subject: [PATCH 016/192] parse programs (with type sigs :D) --- src/Core/Parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 111fe59..da8878b 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -102,7 +102,7 @@ Type : Type1 { $1 } Type1 :: { Type } Type1 : '(' Type ')' { $2 } | Type1 '->' Type { $1 :-> $3 } - -- do we want to use Var instead, permitting symbolic type vars? + -- do we want to allow symbolic names for tyvars and tycons? | varname { TyVar $1 } | conname { TyCon $1 } -- 2.52.0 From c2960e4acc6f7c3874f13c6d5e5e344071d23b8f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 15:37:01 -0700 Subject: [PATCH 017/192] Name = Text Name = Text --- app/Main.hs | 11 +++++++---- rlp.cabal | 2 ++ src/Core/HindleyMilner.hs | 3 ++- src/Core/Lex.x | 18 +++++++++++------- src/Core/Parse.y | 9 ++++++--- src/Core/Syntax.hs | 7 ++++--- src/Core/TH.hs | 9 +++++---- src/Core2Core.hs | 3 ++- src/GM.hs | 20 +++++++++++++------- 9 files changed, 52 insertions(+), 30 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index 7b0b18d..f48824b 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -7,6 +7,9 @@ import Options.Applicative hiding (ParseError) import Control.Monad import Control.Monad.Reader import Data.HashSet qualified as S +import Data.Text (Text) +import Data.Text qualified as T +import Data.Text.IO qualified as TIO import System.IO import System.Exit (exitSuccess) import Core @@ -102,7 +105,7 @@ dshowFlags = whenFlag flagDDumpOpts do ddumpAST :: RLPCIO CompilerError () ddumpAST = whenFlag flagDDumpAST $ forFiles_ \o f -> do liftIO $ withFile f ReadMode $ \h -> do - s <- hGetContents h + s <- TIO.hGetContents h case parseProg o s of Right (a,_) -> hPutStrLn stderr $ show a Left e -> error "todo errors lol" @@ -110,10 +113,10 @@ ddumpAST = whenFlag flagDDumpAST $ forFiles_ \o f -> do ddumpEval :: RLPCIO CompilerError () ddumpEval = whenFlag flagDDumpEval do fs <- view rlpcInputFiles - forM_ fs $ \f -> liftIO (readFile f) >>= doProg + forM_ fs $ \f -> liftIO (TIO.readFile f) >>= doProg where - doProg :: String -> RLPCIO CompilerError () + doProg :: Text -> RLPCIO CompilerError () doProg s = ask >>= \o -> case parseProg o s of -- TODO: error handling Left e -> addFatal . CompilerError $ show e @@ -133,7 +136,7 @@ ddumpEval = whenFlag flagDDumpEval do where v f p h = f p h *> pure () parseProg :: RLPCOptions - -> String + -> Text -> Either SrcError (Program', [SrcError]) parseProg o = evalRLPC o . (lexCore >=> parseCoreProg) diff --git a/rlp.cabal b/rlp.cabal index 4803362..990386f 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -45,6 +45,7 @@ library , microlens , microlens-mtl , microlens-th + , microlens-platform , mtl , template-haskell -- required for happy @@ -74,6 +75,7 @@ executable rlpc , microlens-mtl , mtl , unordered-containers + , text hs-source-dirs: app default-language: GHC2021 diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 9c4ac73..18bd346 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -14,6 +14,7 @@ module Core.HindleyMilner import Lens.Micro import Lens.Micro.Mtl import Data.Maybe (fromMaybe) +import Data.Text qualified as T import Control.Monad (foldM) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) @@ -101,7 +102,7 @@ uniqueVar :: StateT ([Constraint], Int) HMError Type uniqueVar = do n <- use _2 _2 %= succ - pure (TyVar $ '$' : 'a' : show n) + pure (TyVar . T.pack $ '$' : 'a' : show n) addConstraint :: Type -> Type -> StateT ([Constraint], Int) HMError () addConstraint t u = _1 %= ((t, u):) diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 55946e8..0cf9795 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -3,6 +3,7 @@ Module : Core.Lex Description : Lexical analysis for the core language -} +{-# LANGUAGE OverloadedStrings #-} module Core.Lex ( lexCore , lexCore' @@ -15,13 +16,16 @@ module Core.Lex where import Data.Char (chr) import Debug.Trace +import Data.Text (Text) +import Data.Text qualified as T +import Data.String (IsString(..)) import Core.Syntax import Compiler.RLPC import Lens.Micro import Lens.Micro.TH } -%wrapper "monad" +%wrapper "monad-strict-text" $whitechar = [ \t\n\r\f\v] $special = [\(\)\,\;\[\]\{\}] @@ -91,7 +95,7 @@ rlp :- @varsym { lexWith TokenVarSym } @consym { lexWith TokenConSym } - @decimal { lexWith (TokenLitInt . read @Int) } + @decimal { lexWith (TokenLitInt . read @Int . T.unpack) } $white { skip } \n { skip } @@ -139,7 +143,7 @@ data CoreToken = TokenLet | TokenTypeApp | TokenLPragma | TokenRPragma - | TokenWord String + | TokenWord Text | TokenEOF deriving Show @@ -157,11 +161,11 @@ data SrcErrorType = SrcErrLexical String type Lexer = AlexInput -> Int -> Alex (Located CoreToken) -lexWith :: (String -> CoreToken) -> Lexer -lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ take l s) +lexWith :: (Text -> CoreToken) -> Lexer +lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s) -- | The main lexer driver. -lexCore :: String -> RLPC SrcError [Located CoreToken] +lexCore :: Text -> RLPC SrcError [Located CoreToken] lexCore s = case m of Left e -> addFatal err where err = SrcError @@ -175,7 +179,7 @@ lexCore s = case m of -- | @lexCore@, but the tokens are stripped of location info. Useful for -- debugging -lexCore' :: String -> RLPC SrcError [CoreToken] +lexCore' :: Text -> RLPC SrcError [CoreToken] lexCore' s = fmap f <$> lexCore s where f (Located _ _ _ t) = t diff --git a/src/Core/Parse.y b/src/Core/Parse.y index da8878b..0133d15 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -3,6 +3,7 @@ Module : Core.Parse Description : Parser for the Core language -} +{-# LANGUAGE OverloadedStrings #-} module Core.Parse ( parseCore , parseCoreExpr @@ -22,6 +23,8 @@ import Compiler.RLPC import Lens.Micro import Data.Default.Class (def) import Data.Hashable (Hashable) +import Data.Text.IO qualified as TIO +import Data.Text qualified as T import Data.HashMap.Strict qualified as H } @@ -157,8 +160,8 @@ ExprPragma :: { Expr Name } ExprPragma : '{-#' Words '#-}' {% exprPragma $2 } Words :: { [String] } -Words : word Words { $1 : $2 } - | word { [$1] } +Words : word Words { T.unpack $1 : $2 } + | word { [T.unpack $1] } PackCon :: { Expr Name } PackCon : pack '{' litint litint '}' { Con $3 $4 } @@ -195,7 +198,7 @@ parseError (Located y x l _ : _) = addFatal err parseTmp :: IO (Module Name) parseTmp = do - s <- readFile "/tmp/t.hs" + s <- TIO.readFile "/tmp/t.hs" case parse s of Left e -> error (show e) Right (ts,_) -> pure ts diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 46179ca..ddc3b66 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -43,6 +43,7 @@ import Data.Function ((&)) import Data.String import Data.HashMap.Strict qualified as H import Data.Hashable +import Data.Text qualified as T -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) import Lens.Micro.TH (makeLenses) @@ -109,7 +110,7 @@ data AltCon = AltData Tag data Lit = IntL Int deriving (Show, Read, Eq, Lift) -type Name = String +type Name = T.Text type Tag = Int data ScDef b = ScDef b [b] (Expr b) @@ -134,10 +135,10 @@ type Alter' = Alter Name type Binding' = Binding Name instance IsString (Expr b) where - fromString = Var + fromString = Var . fromString instance IsString Type where - fromString = TyVar + fromString = TyVar . fromString instance (Hashable b) => Semigroup (Program b) where (<>) = undefined diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 5239239..72ec901 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -10,11 +10,12 @@ module Core.TH where ---------------------------------------------------------------------------------- import Language.Haskell.TH -import Language.Haskell.TH.Syntax hiding (Module) +import Language.Haskell.TH.Syntax hiding (Module) import Language.Haskell.TH.Quote import Control.Monad ((>=>)) import Compiler.RLPC import Data.Default.Class (def) +import Data.Text qualified as T import Core.Parse import Core.Lex ---------------------------------------------------------------------------------- @@ -44,21 +45,21 @@ coreExpr = QuasiQuoter } qCore :: String -> Q Exp -qCore s = case parse s of +qCore s = case parse (T.pack s) of Left e -> error (show e) Right (m,ts) -> lift m where parse = evalRLPC def . (lexCore >=> parseCore) qCoreExpr :: String -> Q Exp -qCoreExpr s = case parseExpr s of +qCoreExpr s = case parseExpr (T.pack s) of Left e -> error (show e) Right (m,ts) -> lift m where parseExpr = evalRLPC def . (lexCore >=> parseCoreExpr) qCoreProg :: String -> Q Exp -qCoreProg s = case parseProg s of +qCoreProg s = case parseProg (T.pack s) of Left e -> error (show e) Right (m,ts) -> lift m where diff --git a/src/Core2Core.hs b/src/Core2Core.hs index aca3552..5088dab 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -17,6 +17,7 @@ import Data.List import Control.Monad.Writer import Control.Monad.State import Control.Arrow ((>>>)) +import Data.Text qualified as T import Numeric (showHex) import Lens.Micro import Core.Syntax @@ -46,7 +47,7 @@ type Floater = StateT [Name] (Writer [ScDef']) runFloater :: Floater a -> (a, [ScDef']) runFloater = flip evalStateT ns >>> runWriter where - ns = [ "$nonstrict_case_" ++ showHex n "" | n <- [0..] ] + ns = [ T.pack $ "$nonstrict_case_" ++ showHex n "" | n <- [0..] ] -- TODO: formally define a "strict context" and reference that here -- the returned ScDefs are guaranteed to be free of non-strict cases. diff --git a/src/GM.hs b/src/GM.hs index 7efd0cd..8b91393 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -24,6 +24,8 @@ import Data.Tuple (swap) import Lens.Micro import Lens.Micro.Extras (view) import Lens.Micro.TH +import Lens.Micro.Platform (packed, unpacked) +import Lens.Micro.Platform.Internal (IsText(..)) import Text.Printf import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint.HughesPJ (maybeParens) @@ -282,7 +284,7 @@ step st = case head (st ^. gmCode) of m = st ^. gmEnv s = st ^. gmStack h = st ^. gmHeap - n' = show n + n' = show n ^. packed -- Core Rule 2. (no sharing) -- pushIntI :: Int -> GmState @@ -613,7 +615,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil | k `elem` domain = [Push n] | otherwise = [PushGlobal k] where - n = fromMaybe (error $ "undeclared var: " <> k) $ lookupN k g + n = fromMaybe err $ lookupN k g + err = error $ "undeclared var: " <> (k ^. unpacked) domain = f `mapMaybe` g f (NameKey n, _) = Just n f _ = Nothing @@ -739,8 +742,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil argOffset :: Int -> Env -> Env argOffset n = each . _2 %~ (+n) -idPack :: Tag -> Int -> String -idPack t n = printf "Pack{%d %d}" t n +showCon :: (IsText a) => Tag -> Int -> a +showCon t n = printf "Pack{%d %d}" t n ^. packed ---------------------------------------------------------------------------------- @@ -856,12 +859,12 @@ showNodeAt = showNodeAtP 0 showNodeAtP :: Int -> GmState -> Addr -> Doc showNodeAtP p st a = case hLookup a h of Just (NNum n) -> int n <> "#" - Just (NGlobal _ _) -> text name + Just (NGlobal _ _) -> textt name where g = st ^. gmEnv name = case lookup a (swap <$> g) of Just (NameKey n) -> n - Just (ConstrKey t n) -> idPack t n + Just (ConstrKey t n) -> showCon t n _ -> errTxtInvalidAddress -- TODO: left-associativity Just (NAp f x) -> pprec $ showNodeAtP (p+1) st f @@ -878,7 +881,7 @@ showNodeAtP p st a = case hLookup a h of pprec = maybeParens (p > 0) showSc :: GmState -> (Name, Addr) -> Doc -showSc st (k,a) = "Supercomb " <> qquotes (text k) <> colon +showSc st (k,a) = "Supercomb " <> qquotes (textt k) <> colon $$ code where code = case hLookup a (st ^. gmHeap) of @@ -901,6 +904,9 @@ showInstr (CaseJump alts) = "CaseJump" $$ nest pprTabstop alternatives alternatives = foldr (\a acc -> showAlt a $$ acc) mempty alts showInstr i = text $ show i +textt :: (IsText a) => a -> Doc +textt t = t ^. unpacked & text + ---------------------------------------------------------------------------------- lookupN :: Name -> Env -> Maybe Addr -- 2.52.0 From 526bf0734eee6254fa9606626aa4caeb6650a09f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 28 Dec 2023 15:55:24 -0700 Subject: [PATCH 018/192] RlpcError --- rlp.cabal | 1 + src/Compiler/RLPC.hs | 19 ++++++++++++++++--- src/Compiler/RlpcError.hs | 15 +++++++++++++++ src/Control/Monad/Errorful.hs | 8 ++++++++ src/Core/Lex.x | 13 +++++++++++++ src/Core/Parse.y | 4 ++++ src/Core/TH.hs | 2 +- 7 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 src/Compiler/RlpcError.hs diff --git a/rlp.cabal b/rlp.cabal index 990386f..34a5c00 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -22,6 +22,7 @@ library , TI , GM , Compiler.RLPC + , Compiler.RlpcError , Core.Syntax , Core.Examples , Core.Utils diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 9cd1454..e1e6778 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -16,6 +16,7 @@ module Compiler.RLPC , RLPCT , RLPCIO , RLPCOptions(RLPCOptions) + , RlpcError(..) , addFatal , addWound , MonadErrorful @@ -24,6 +25,9 @@ module Compiler.RLPC , evalRLPCT , evalRLPCIO , evalRLPC + , addRlpcWound + , addRlpcFatal + , liftRlpcErrs , rlpcLogFile , rlpcDebugOpts , rlpcEvaluator @@ -42,6 +46,7 @@ import Control.Exception import Control.Monad.Reader import Control.Monad.State (MonadState(state)) import Control.Monad.Errorful +import Compiler.RlpcError import Data.Functor.Identity import Data.Default.Class import GHC.Generics (Generic) @@ -115,13 +120,21 @@ data Severity = Error -- temporary until we have a new doc building system type ErrorDoc = String -class Diagnostic e where - errorDoc :: e -> ErrorDoc - instance (Monad m) => MonadErrorful e (RLPCT e m) where addWound = RLPCT . lift . addWound addFatal = RLPCT . lift . addFatal +liftRlpcErrs :: (IsRlpcError e, Monad m) + => RLPCT e m a -> RLPCT RlpcError m a +liftRlpcErrs m = RLPCT . ReaderT $ \r -> + mapErrors liftRlpcErr $ runRLPCT >>> (`runReaderT` r) $ m + +addRlpcWound :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m () +addRlpcWound = addWound . liftRlpcErr + +addRlpcFatal :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m () +addRlpcFatal = addWound . liftRlpcErr + ---------------------------------------------------------------------------------- instance Default RLPCOptions where diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs new file mode 100644 index 0000000..581d301 --- /dev/null +++ b/src/Compiler/RlpcError.hs @@ -0,0 +1,15 @@ +module Compiler.RlpcError + ( RlpcError(..) + , IsRlpcError(..) + ) + where +---------------------------------------------------------------------------------- +import Control.Monad.Errorful +---------------------------------------------------------------------------------- + +data RlpcError = RlpcErr String -- temp + deriving Show + +class IsRlpcError a where + liftRlpcErr :: a -> RlpcError + diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index bcfd4a3..789a4ad 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -6,6 +6,7 @@ module Control.Monad.Errorful , runErrorfulT , Errorful , runErrorful + , mapErrors , MonadErrorful(..) ) where @@ -63,3 +64,10 @@ instance (Monad m) => Monad (ErrorfulT e m) where Right (a,es) -> runErrorfulT (k a) Left e -> pure (Left e) +mapErrors :: (Monad m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a +mapErrors f m = ErrorfulT $ do + x <- runErrorfulT m + case x of + Left e -> pure . Left $ f e + Right (a,es) -> pure . Right $ (a, f <$> es) + diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 0cf9795..341b51b 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -6,6 +6,7 @@ Description : Lexical analysis for the core language {-# LANGUAGE OverloadedStrings #-} module Core.Lex ( lexCore + , lexCoreR , lexCore' , CoreToken(..) , SrcError(..) @@ -21,6 +22,7 @@ import Data.Text qualified as T import Data.String (IsString(..)) import Core.Syntax import Compiler.RLPC +import Compiler.RlpcError import Lens.Micro import Lens.Micro.TH } @@ -177,6 +179,9 @@ lexCore s = case m of where m = runAlex s lexStream +lexCoreR :: Text -> RLPC RlpcError [Located CoreToken] +lexCoreR = liftRlpcErrs . lexCore + -- | @lexCore@, but the tokens are stripped of location info. Useful for -- debugging lexCore' :: Text -> RLPC SrcError [CoreToken] @@ -194,6 +199,14 @@ data ParseError = ParErrLexical String | ParErrParse deriving Show +-- TODO: +instance IsRlpcError SrcError where + liftRlpcErr = RlpcErr . show + +-- TODO: +instance IsRlpcError ParseError where + liftRlpcErr = RlpcErr . show + alexEOF :: Alex (Located CoreToken) alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> Right (st, Located y x 0 TokenEOF) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 0133d15..11e91be 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -8,6 +8,7 @@ module Core.Parse ( parseCore , parseCoreExpr , parseCoreProg + , parseCoreProgR , module Core.Lex -- temp convenience , parseTmp , SrcError @@ -229,5 +230,8 @@ insScDef sc = programScDefs %~ (sc:) singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty +parseCoreProgR :: [Located CoreToken] -> RLPC RlpcError Program' +parseCoreProgR = liftRlpcErrs . parseCoreProg + } diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 72ec901..063d4fe 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -63,5 +63,5 @@ qCoreProg s = case parseProg (T.pack s) of Left e -> error (show e) Right (m,ts) -> lift m where - parseProg = evalRLPC def . (lexCore >=> parseCoreProg) + parseProg = evalRLPC def . (lexCoreR >=> parseCoreProgR) -- 2.52.0 From b6945a64eb2c1be27d7d02a50a9ae298970742e7 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 20 Dec 2023 23:44:57 -0700 Subject: [PATCH 019/192] i'm on an airplane rn, my eyelids grow heavy, and i forgot my medication. should this be my final commit (of the week): gootbye --- rlp.cabal | 1 + src/Core/HindleyMilner.hs | 39 ++++++++++++++++++++++++++++++++--- src/Core/Lex.x | 1 + src/Core/Syntax.hs | 12 +++++++++-- tst/Arith.hs | 3 ++- tst/Core/HindleyMilnerSpec.hs | 13 ++++++------ 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 34a5c00..5880571 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -92,6 +92,7 @@ test-suite rlp-test , rlp , QuickCheck , hspec ==2.* + , microlens other-modules: Arith , GMSpec , Core.HindleyMilnerSpec diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 18bd346..4aa6c77 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -4,8 +4,9 @@ Description : Hindley-Milner inference -} {-# LANGUAGE LambdaCase #-} module Core.HindleyMilner - ( infer - , Context' + ( Context' + , infer + , check , TypeError(..) , HMError ) @@ -15,7 +16,8 @@ import Lens.Micro import Lens.Micro.Mtl import Data.Maybe (fromMaybe) import Data.Text qualified as T -import Control.Monad (foldM) +import Data.HashMap.Strict qualified as H +import Control.Monad (foldM, void) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) import Core.Syntax @@ -43,6 +45,26 @@ data TypeError -- | Synonym for @Either TypeError@ type HMError = Either TypeError +-- | Assert that an expression unifies with a given type +-- +-- >>> let e = [coreProg|3|] +-- >>> check [] (TyCon "Bool") e +-- Left (TyErrCouldNotUnify (TyCon "Bool") (TyCon "Int#")) +-- >>> check [] (TyCon "Int#") e +-- Right () + +check :: Context' -> Type -> Expr' -> HMError () +check g t1 e = do + t2 <- infer g e + unify [(t1,t2)] + pure () + +checkProg :: Program' -> HMError () +checkProg p = p ^. programScDefs + & traversalOf k + where + k sc = undefined + -- | Infer the type of an expression under some context. -- -- >>> let g1 = [("id", TyVar "a" :-> TyVar "a")] @@ -55,6 +77,7 @@ type HMError = Either TypeError infer :: Context' -> Expr' -> HMError Type infer g e = do (t,cs) <- gather g e + -- apply all unified constraints foldr (uncurry subst) t <$> unify cs -- | A @Constraint@ between two types describes the requirement that the pair @@ -89,6 +112,7 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where Let NonRec bs e -> do g' <- buildLetContext g bs go g' e + -- TODO letrec, lambda, case buildLetContext :: Context' -> [Binding'] -> StateT ([Constraint], Int) HMError Context' @@ -149,8 +173,17 @@ unify = go mempty where | x == y = True occurs _ = False +buildInitialContext :: Program b -> Context b +buildInitialContext p = p ^. programTypeSigs + & H.toList + -- | The expression @subst x t e@ substitutes all occurences of @x@ in @e@ with -- @t@ +-- +-- >>> subst "a" (TyCon "Int") (TyVar "a") +-- TyCon "Int" +-- >>> subst "a" (TyCon "Int") (TyVar "a" :-> TyVar "a") +-- TyCon "Int" :-> TyCon "Int" subst :: Name -> Type -> Type -> Type subst x t (TyVar y) | x == y = t diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 341b51b..9fb9d31 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -87,6 +87,7 @@ rlp :- "where" { constTok TokenWhere } "Pack" { constTok TokenPack } -- temp + -- TODO: this should be "\" "\\" { constTok TokenLambda } "λ" { constTok TokenLambda } "=" { constTok TokenEquals } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index ddc3b66..fb9b720 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -24,6 +24,7 @@ module Core.Syntax , Module(..) , Program(..) , Program' + , unliftScDef , programScDefs , programTypeSigs , Expr' @@ -37,13 +38,13 @@ module Core.Syntax ---------------------------------------------------------------------------------- import Data.Coerce import Data.Pretty -import GHC.Generics import Data.List (intersperse) import Data.Function ((&)) import Data.String import Data.HashMap.Strict qualified as H import Data.Hashable import Data.Text qualified as T +import Data.Char -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) import Lens.Micro.TH (makeLenses) @@ -116,6 +117,9 @@ type Tag = Int data ScDef b = ScDef b [b] (Expr b) deriving (Show, Lift) +unliftScDef :: ScDef b -> Expr b +unliftScDef (ScDef _ as e) = Lam as e + data Module b = Module (Maybe (Name, [Name])) (Program b) deriving (Show, Lift) @@ -138,7 +142,11 @@ instance IsString (Expr b) where fromString = Var . fromString instance IsString Type where - fromString = TyVar . fromString + fromString "" = error "IsString Type string may not be empty" + fromString s + | isUpper c = TyCon . fromString $ s + | otherwise = TyVar . fromString $ s + where (c:_) = s instance (Hashable b) => Semigroup (Program b) where (<>) = undefined diff --git a/tst/Arith.hs b/tst/Arith.hs index 700849b..2c168c4 100644 --- a/tst/Arith.hs +++ b/tst/Arith.hs @@ -6,6 +6,7 @@ module Arith ) where ---------------------------------------------------------------------------------- import Data.Functor.Classes (eq1) +import Lens.Micro import Core.Syntax import GM import Test.QuickCheck @@ -70,7 +71,7 @@ instance Arbitrary ArithExpr where -- coreResult = evalCore (toCore e) toCore :: ArithExpr -> Program' -toCore expr = Program +toCore expr = mempty & programScDefs .~ [ ScDef "id" ["x"] $ Var "x" , ScDef "main" [] $ go expr ] diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 74a2468..07940e6 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -6,7 +6,8 @@ module Core.HindleyMilnerSpec ---------------------------------------------------------------------------------- import Core.Syntax import Core.TH (coreExpr) -import Core.HindleyMilner (infer, TypeError(..), HMError) +import Core.HindleyMilner (infer, check, TypeError(..), HMError) +import Data.Either (isLeft) import Test.Hspec ---------------------------------------------------------------------------------- @@ -19,7 +20,7 @@ spec = do it "should not infer `id 3` when `id` is specialised to `a -> a`" $ let g = [ ("id", ("a" :-> "a") :-> "a" :-> "a") ] - in infer g [coreExpr|id 3|] `shouldSatisfy` isUntypedVariableErr + in infer g [coreExpr|id 3|] `shouldSatisfy` isLeft -- TODO: property-based tests for let it "should infer `let x = 3 in id x` :: Int" $ @@ -31,8 +32,8 @@ spec = do let g = [ ("+#", TyInt :-> TyInt :-> TyInt) ] e = [coreExpr|let {x=3;y=2} in (+#) x y|] in infer g e `shouldBe` Right TyInt - -isUntypedVariableErr :: HMError a -> Bool -isUntypedVariableErr (Left (TyErrCouldNotUnify _ _)) = True -isUntypedVariableErr _ = False + + it "should find `3 :: Bool` contradictory" $ + let e = [coreExpr|3|] + in check [] (TyCon "Bool") e `shouldSatisfy` isLeft -- 2.52.0 From 1164b13a1efc2117bbfc76f15b8fa0375bcdc813 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 22 Dec 2023 16:12:58 -0700 Subject: [PATCH 020/192] kinda sorta typechecking --- src/Core/HindleyMilner.hs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 4aa6c77..c0d64f8 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -17,6 +17,7 @@ import Lens.Micro.Mtl import Data.Maybe (fromMaybe) import Data.Text qualified as T import Data.HashMap.Strict qualified as H +import Data.Foldable (traverse_) import Control.Monad (foldM, void) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) @@ -56,14 +57,20 @@ type HMError = Either TypeError check :: Context' -> Type -> Expr' -> HMError () check g t1 e = do t2 <- infer g e - unify [(t1,t2)] - pure () + void $ unify [(t1,t2)] +-- | Typecheck program. I plan to allow for *some* inference in the future, but +-- in the mean time all top-level binders must have a type annotation. checkProg :: Program' -> HMError () -checkProg p = p ^. programScDefs - & traversalOf k +checkProg p = scDefs + & traverse_ k where - k sc = undefined + scDefs = p ^. programScDefs + g = gatherTypeSigs p + + k :: ScDef' -> HMError () + k sc | Just t <- lookup (sc ^. _lhs._1) g + = check g t (sc ^. _rhs) -- | Infer the type of an expression under some context. -- @@ -173,9 +180,9 @@ unify = go mempty where | x == y = True occurs _ = False -buildInitialContext :: Program b -> Context b -buildInitialContext p = p ^. programTypeSigs - & H.toList +gatherTypeSigs :: Program b -> Context b +gatherTypeSigs p = p ^. programTypeSigs + & H.toList -- | The expression @subst x t e@ substitutes all occurences of @x@ in @e@ with -- @t@ -- 2.52.0 From cb5692248f65c9e28182d84774eeff73c2d5dbad Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 28 Dec 2023 14:46:10 -0700 Subject: [PATCH 021/192] back and medicated! --- src/Core/HindleyMilner.hs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index c0d64f8..eb11ce7 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -1,6 +1,6 @@ {-| Module : Core.HindleyMilner -Description : Hindley-Milner inference +Description : Hindley-Milner type system -} {-# LANGUAGE LambdaCase #-} module Core.HindleyMilner @@ -18,6 +18,7 @@ import Data.Maybe (fromMaybe) import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Foldable (traverse_) +import Compiler.RLPC import Control.Monad (foldM, void) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) @@ -41,11 +42,15 @@ data TypeError | TyErrRecursiveType Name Type -- | Untyped, potentially undefined variable | TyErrUntypedVariable Name + | TyErrMissingTypeSig Name deriving (Show, Eq) -- | Synonym for @Either TypeError@ type HMError = Either TypeError +-- TODO: better errors. Errorful-esque, with cummulative errors instead of +-- instantly dying. + -- | Assert that an expression unifies with a given type -- -- >>> let e = [coreProg|3|] @@ -69,8 +74,13 @@ checkProg p = scDefs g = gatherTypeSigs p k :: ScDef' -> HMError () - k sc | Just t <- lookup (sc ^. _lhs._1) g - = check g t (sc ^. _rhs) + k sc = case lookup scname g of + Just t -> check g t (sc ^. _rhs) + Nothing -> Left (TyErrMissingTypeSig $ scname) + where scname = sc ^. _lhs._1 + +checkRlpcProg :: Program' -> RLPC TypeError () +checkRlpcProg = undefined -- | Infer the type of an expression under some context. -- -- 2.52.0 From e80acbcd2883466389029508541c50ca904499c0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 28 Dec 2023 15:06:15 -0700 Subject: [PATCH 022/192] errorful (it's not good) --- src/Core/HindleyMilner.hs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index eb11ce7..15b8ab9 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -7,6 +7,7 @@ module Core.HindleyMilner ( Context' , infer , check + , checkProg , TypeError(..) , HMError ) @@ -20,6 +21,7 @@ import Data.HashMap.Strict qualified as H import Data.Foldable (traverse_) import Compiler.RLPC import Control.Monad (foldM, void) +import Control.Monad.Errorful (Errorful, addFatal) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) import Core.Syntax @@ -45,8 +47,9 @@ data TypeError | TyErrMissingTypeSig Name deriving (Show, Eq) --- | Synonym for @Either TypeError@ -type HMError = Either TypeError +-- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may +-- throw any number of fatal or nonfatal errors. Run with @runErrorful@. +type HMError = Errorful TypeError -- TODO: better errors. Errorful-esque, with cummulative errors instead of -- instantly dying. @@ -76,7 +79,7 @@ checkProg p = scDefs k :: ScDef' -> HMError () k sc = case lookup scname g of Just t -> check g t (sc ^. _rhs) - Nothing -> Left (TyErrMissingTypeSig $ scname) + Nothing -> addFatal $ TyErrMissingTypeSig scname where scname = sc ^. _lhs._1 checkRlpcProg :: Program' -> RLPC TypeError () @@ -118,8 +121,8 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where go :: Context' -> Expr' -> StateT ([Constraint], Int) HMError Type go g = \case Lit (IntL _) -> pure TyInt - Var k -> lift $ maybe e Right $ lookup k g - where e = Left (TyErrUntypedVariable k) + Var k -> lift $ maybe e pure $ lookup k g + where e = addFatal $ TyErrUntypedVariable k App f x -> do tf <- go g f tx <- go g x @@ -158,7 +161,7 @@ unify = go mempty where go :: Context' -> [Constraint] -> HMError Context' -- nothing left! return accumulated context - go g [] = Right g + go g [] = pure g go g (c:cs) = case c of -- primitives may of course unify with themselves @@ -176,10 +179,10 @@ unify = go mempty where (a :-> b, x :-> y) -> go g $ (a,x) : (b,y) : cs -- anything else is a failure :( - (t,u) -> Left $ TyErrCouldNotUnify t u + (t,u) -> addFatal $ TyErrCouldNotUnify t u - unifyTV :: Context' -> Name -> Type -> [Constraint] -> Either TypeError Context' - unifyTV g x t cs | occurs t = Left $ TyErrRecursiveType x t + unifyTV :: Context' -> Name -> Type -> [Constraint] -> HMError Context' + unifyTV g x t cs | occurs t = addFatal $ TyErrRecursiveType x t | otherwise = go g' substed where g' = (x,t) : g -- 2.52.0 From 35446533d7be5c929f60ea7fd3134ce7bff4f18a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 29 Dec 2023 13:47:42 -0700 Subject: [PATCH 023/192] type-checked quasiquoters --- src/Compiler/RLPC.hs | 7 ++++++- src/Core/HindleyMilner.hs | 18 +++++++++++++----- src/Core/TH.hs | 24 ++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index e1e6778..5e69e16 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -13,10 +13,12 @@ errors and the family of RLPC monads. {-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-} module Compiler.RLPC ( RLPC - , RLPCT + , RLPCT(..) , RLPCIO , RLPCOptions(RLPCOptions) , RlpcError(..) + , IsRlpcError(..) + , rlpc , addFatal , addWound , MonadErrorful @@ -135,6 +137,9 @@ addRlpcWound = addWound . liftRlpcErr addRlpcFatal :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m () addRlpcFatal = addWound . liftRlpcErr +rlpc :: (Monad m) => ErrorfulT e m a -> RLPCT e m a +rlpc = RLPCT . ReaderT . const + ---------------------------------------------------------------------------------- instance Default RLPCOptions where diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 15b8ab9..d7277c4 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -7,7 +7,8 @@ module Core.HindleyMilner ( Context' , infer , check - , checkProg + , checkCoreProg + , checkCoreProgR , TypeError(..) , HMError ) @@ -47,6 +48,10 @@ data TypeError | TyErrMissingTypeSig Name deriving (Show, Eq) +-- TODO: +instance IsRlpcError TypeError where + liftRlpcErr = RlpcErr . show + -- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may -- throw any number of fatal or nonfatal errors. Run with @runErrorful@. type HMError = Errorful TypeError @@ -69,8 +74,8 @@ check g t1 e = do -- | Typecheck program. I plan to allow for *some* inference in the future, but -- in the mean time all top-level binders must have a type annotation. -checkProg :: Program' -> HMError () -checkProg p = scDefs +checkCoreProg :: Program' -> HMError () +checkCoreProg p = scDefs & traverse_ k where scDefs = p ^. programScDefs @@ -82,8 +87,11 @@ checkProg p = scDefs Nothing -> addFatal $ TyErrMissingTypeSig scname where scname = sc ^. _lhs._1 -checkRlpcProg :: Program' -> RLPC TypeError () -checkRlpcProg = undefined +-- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. +checkCoreProgR :: Program' -> RLPC RlpcError Program' +checkCoreProgR p = do + liftRlpcErrs . rlpc . checkCoreProg $ p + pure p -- | Infer the type of an expression under some context. -- diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 063d4fe..7d85bf5 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -5,6 +5,7 @@ Description : Core quasiquoters module Core.TH ( coreExpr , coreProg + , coreProgT , core ) where @@ -18,8 +19,11 @@ import Data.Default.Class (def) import Data.Text qualified as T import Core.Parse import Core.Lex +import Core.HindleyMilner (checkCoreProgR) ---------------------------------------------------------------------------------- +-- TODO: write in terms of a String -> QuasiQuoter + core :: QuasiQuoter core = QuasiQuoter { quoteExp = qCore @@ -44,6 +48,15 @@ coreExpr = QuasiQuoter , quoteDec = error "core quasiquotes may only be used in expressions" } +-- | Type-checked @coreProg@ +coreProgT :: QuasiQuoter +coreProgT = QuasiQuoter + { quoteExp = qCoreProgT + , quotePat = error "core quasiquotes may only be used in expressions" + , quoteType = error "core quasiquotes may only be used in expressions" + , quoteDec = error "core quasiquotes may only be used in expressions" + } + qCore :: String -> Q Exp qCore s = case parse (T.pack s) of Left e -> error (show e) @@ -59,9 +72,16 @@ qCoreExpr s = case parseExpr (T.pack s) of parseExpr = evalRLPC def . (lexCore >=> parseCoreExpr) qCoreProg :: String -> Q Exp -qCoreProg s = case parseProg (T.pack s) of +qCoreProg s = case parse (T.pack s) of Left e -> error (show e) Right (m,ts) -> lift m where - parseProg = evalRLPC def . (lexCoreR >=> parseCoreProgR) + parse = evalRLPC def . (lexCoreR >=> parseCoreProgR) + +qCoreProgT :: String -> Q Exp +qCoreProgT s = case parse (T.pack s) of + Left e -> error (show e) + Right (m,_) -> lift m + where + parse = evalRLPC def . (lexCoreR >=> parseCoreProgR >=> checkCoreProgR) -- 2.52.0 From b941347f8265db29d51995d2f184db0aa46b3ec6 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 29 Dec 2023 13:54:09 -0700 Subject: [PATCH 024/192] fix hm tests --- rlp.cabal | 2 +- tst/Core/HindleyMilnerSpec.hs | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 5880571..c1bedaa 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -28,13 +28,13 @@ library , Core.Utils , Core.TH , Core.HindleyMilner + , Control.Monad.Errorful other-modules: Data.Heap , Data.Pretty , Core.Parse , Core.Lex , Core2Core - , Control.Monad.Errorful , Control.Monad.Utils , RLP.Syntax diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 07940e6..8f498a9 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -6,7 +6,8 @@ module Core.HindleyMilnerSpec ---------------------------------------------------------------------------------- import Core.Syntax import Core.TH (coreExpr) -import Core.HindleyMilner (infer, check, TypeError(..), HMError) +import Core.HindleyMilner +import Control.Monad.Errorful import Data.Either (isLeft) import Test.Hspec ---------------------------------------------------------------------------------- @@ -16,24 +17,30 @@ spec :: Spec spec = do it "should infer `id 3` :: Int" $ let g = [ ("id", "a" :-> "a") ] - in infer g [coreExpr|id 3|] `shouldBe` Right TyInt + in infer' g [coreExpr|id 3|] `shouldBe` Right TyInt it "should not infer `id 3` when `id` is specialised to `a -> a`" $ let g = [ ("id", ("a" :-> "a") :-> "a" :-> "a") ] - in infer g [coreExpr|id 3|] `shouldSatisfy` isLeft + in infer' g [coreExpr|id 3|] `shouldSatisfy` isLeft -- TODO: property-based tests for let it "should infer `let x = 3 in id x` :: Int" $ let g = [ ("id", "a" :-> "a") ] e = [coreExpr|let {x = 3} in id x|] - in infer g e `shouldBe` Right TyInt + in infer' g e `shouldBe` Right TyInt it "should infer `let x = 3; y = 2 in (+#) x y` :: Int" $ let g = [ ("+#", TyInt :-> TyInt :-> TyInt) ] e = [coreExpr|let {x=3;y=2} in (+#) x y|] - in infer g e `shouldBe` Right TyInt + in infer' g e `shouldBe` Right TyInt it "should find `3 :: Bool` contradictory" $ let e = [coreExpr|3|] - in check [] (TyCon "Bool") e `shouldSatisfy` isLeft + in check' [] (TyCon "Bool") e `shouldSatisfy` isLeft + +infer' :: Context' -> Expr' -> Either TypeError Type +infer' g e = fmap fst . runErrorful $ infer g e + +check' :: Context' -> Type -> Expr' -> Either TypeError () +check' g t e = fmap fst . runErrorful $ check g t e -- 2.52.0 From 1dc695f6404a50def341f20aa298699da3f74a54 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 29 Dec 2023 14:20:53 -0700 Subject: [PATCH 025/192] Compiler.JustRun --- rlp.cabal | 1 + src/Compiler/JustRun.hs | 46 +++++++++++++++++++++++++++++++++++++++++ src/Compiler/RLPC.hs | 1 - 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/Compiler/JustRun.hs diff --git a/rlp.cabal b/rlp.cabal index c1bedaa..660a3d8 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -23,6 +23,7 @@ library , GM , Compiler.RLPC , Compiler.RlpcError + , Compiler.JustRun , Core.Syntax , Core.Examples , Core.Utils diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs new file mode 100644 index 0000000..df28db5 --- /dev/null +++ b/src/Compiler/JustRun.hs @@ -0,0 +1,46 @@ +{-| +Module : Compiler.JustRun +Description : No-BS, high-level wrappers for major pipeline pieces. + +A collection of wrapper functions to demo processes such as lexing, parsing, +type-checking, and evaluation. This module intends to export "no-BS" functions +that use Prelude types such as @Either@ and @String@ rather than more complex +types such as @RLPC@ or @Text@. +-} +module Compiler.JustRun + ( justLexSrc + , justParseSrc + , justTypeCheckSrc + ) + where +---------------------------------------------------------------------------------- +import Core.Lex +import Core.Parse +import Core.HindleyMilner +import Core.Syntax (Program') +import Compiler.RLPC +import Control.Arrow ((>>>)) +import Control.Monad ((>=>)) +import Data.Text qualified as T +import Data.Function ((&)) +import GM +---------------------------------------------------------------------------------- + +justLexSrc :: String -> Either RlpcError [CoreToken] +justLexSrc s = lexCoreR (T.pack s) + & fmap (map $ \ (Located _ _ _ t) -> t) + & rlpcToEither + +justParseSrc :: String -> Either RlpcError Program' +justParseSrc s = parse (T.pack s) + & rlpcToEither + where parse = lexCoreR >=> parseCoreProgR + +justTypeCheckSrc :: String -> Either RlpcError Program' +justTypeCheckSrc s = typechk (T.pack s) + & rlpcToEither + where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR + +rlpcToEither :: RLPC e a -> Either e a +rlpcToEither = evalRLPC def >>> fmap fst + diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 5e69e16..266e06a 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -100,7 +100,6 @@ evalRLPCIO o m = do -- TODO: errors Left e -> throwIO e Right a -> pure a - data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath -- 2.52.0 From 832767575c48d31b9a676a610d3c982bfb454a38 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 29 Dec 2023 18:43:09 -0700 Subject: [PATCH 026/192] lex \ instead of \\ --- src/Core/Lex.x | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 9fb9d31..d5cdc1e 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -87,8 +87,7 @@ rlp :- "where" { constTok TokenWhere } "Pack" { constTok TokenPack } -- temp - -- TODO: this should be "\" - "\\" { constTok TokenLambda } + "\" { constTok TokenLambda } "λ" { constTok TokenLambda } "=" { constTok TokenEquals } "->" { constTok TokenArrow } -- 2.52.0 From 7ed565fc240230961ef3a165ca4c8d0817763a03 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 02:33:31 -0700 Subject: [PATCH 027/192] grammar reference --- doc/src/conf.py | 1 + doc/src/references/rlp-grammar.rst | 67 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 doc/src/references/rlp-grammar.rst diff --git a/doc/src/conf.py b/doc/src/conf.py index d344334..533296a 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -32,6 +32,7 @@ html_theme = 'alabaster' imgmath_latex_preamble = r''' \usepackage{amsmath} \usepackage{tabularray} +\usepackage{syntax} \newcommand{\transrule}[2] {\begin{tblr}{|rrrlc|} diff --git a/doc/src/references/rlp-grammar.rst b/doc/src/references/rlp-grammar.rst new file mode 100644 index 0000000..c81fea7 --- /dev/null +++ b/doc/src/references/rlp-grammar.rst @@ -0,0 +1,67 @@ +The Complete Syntax of rl' +========================== + +WIP. + +Provided is the complete syntax of rl' in (pseudo) EBNF. {A} represents zero or +more A's, [A] means optional A, and terminals are wrapped in 'single-quotes'. + +.. math + :nowrap: + + \setlength{\grammarparsep}{20pt plus 1pt minus 1pt} + \setlength{\grammarindent}{12em} + \begin{grammar} + ::= + \alt + \alt + \alt + + ::= `litint' + ::= `infix' + \alt `infixl' + \alt `infixr' + + ::= `data' `conname' {} + + \end{grammar} + +.. code-block:: bnf + + Decl ::= InfixDecl + | DataDecl + | TypeSig + | FunDef + + InfixDecl ::= InfixWord 'litint' Operator + InfixWord ::= 'infix' + | 'infixl' + | 'infixr' + + DataDecl ::= 'data' 'conname' {'name'} '=' Data + DataCons ::= 'conname' {Type1} ['|' DataCons] + + TypeSig ::= Var '::' Type + FunDef ::= Var {Pat1} '=' Expr + + Type ::= Type1 {Type1} + -- note that (->) is right-associative, + -- and extends as far as possible + | Type '->' Type + Type1 ::= '(' Type ')' + | 'conname' + + Pat ::= 'conname' Pat1 {Pat1} + | Pat 'consym' Pat + + Pat1 ::= Literal + | 'conname' + | '(' Pat ')' + + Literal ::= 'litint' + + Var ::= 'varname' + | '(' 'varsym' ')' + Con ::= 'conname' + | '(' 'consym' ')' + -- 2.52.0 From bf4abeb8b4a2f80e8aed42a6cf7cb64ecba1d4da Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 05:34:11 -0700 Subject: [PATCH 028/192] 4:00 AM psychopath code --- rlp.cabal | 3 +- src/RLP/ParseDecls.hs | 139 ++++++++++++++++++++++++++++++++++++++++++ src/RLP/Syntax.hs | 65 +++++++++++++++++--- 3 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 src/RLP/ParseDecls.hs diff --git a/rlp.cabal b/rlp.cabal index 660a3d8..b960ec6 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -30,6 +30,8 @@ library , Core.TH , Core.HindleyMilner , Control.Monad.Errorful + , Rlp.Syntax + , Rlp.ParseDecls other-modules: Data.Heap , Data.Pretty @@ -37,7 +39,6 @@ library , Core.Lex , Core2Core , Control.Monad.Utils - , RLP.Syntax build-tool-depends: happy:happy, alex:alex diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs new file mode 100644 index 0000000..4d18e22 --- /dev/null +++ b/src/RLP/ParseDecls.hs @@ -0,0 +1,139 @@ +-- Show Y +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE OverloadedStrings #-} +module Rlp.ParseDecls + ( + ) + where +---------------------------------------------------------------------------------- +import Rlp.Syntax +import Text.Megaparsec hiding (State) +import Text.Megaparsec.Char +import Text.Megaparsec.Char.Lexer qualified as L +import Data.Functor.Const +import Data.Text (Text) +import Data.Text qualified as T +import Data.Void +import Data.Char +import Data.Functor +import Data.HashMap.Strict qualified as H +import Control.Monad +import Core.Syntax +import Control.Monad.State +---------------------------------------------------------------------------------- + +type Parser = ParsecT Void Text (State ParserState) + +data ParserState = ParserState + { _psPrecTable :: PrecTable + } + deriving Show + +type PrecTable = H.HashMap Name (Assoc, Int) + +---------------------------------------------------------------------------------- + +parseTest' :: (Show a) => Parser a -> Text -> IO () +parseTest' p s = case runState (runParserT p "test" s) init of + (Left e, _) -> putStr (errorBundlePretty e) + (Right x, st) -> print st *> print x + where + init = ParserState mempty + +lexeme :: Parser a -> Parser a +lexeme = L.lexeme sc + +symbol :: Text -> Parser Text +symbol = L.symbol sc + +sc :: Parser () +sc = L.space space1 (void lineComment) (void blockComment) + +-- TODO: return comment text +-- TODO: '---' should not start a comment +lineComment :: Parser Text +lineComment = L.skipLineComment "--" $> "" + +-- TODO: return comment text +blockComment :: Parser Text +blockComment = L.skipBlockCommentNested "{-" "-}" $> "" + +decl :: Parser PartialDecl' +decl = choice + [ funD + , tySigD + , dataD + , infixD + ] + +funD :: Parser PartialDecl' +funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) + +partialExpr :: Parser PartialExpr' +partialExpr = choice + [ fmap Y $ U <$> varid' <*> lexeme infixOp <*> varid' + ] + where varid' = E . VarEF <$> varid + + +infixOp :: Parser Name +infixOp = symvar <|> symcon + +symvar :: Parser Name +symvar = T.pack <$> + liftA2 (:) (satisfy isVarSym) (many $ satisfy isSym) + +symcon :: Parser Name +symcon = T.pack <$> + liftA2 (:) (char ':') (many $ satisfy isSym) + +-- partialExpr :: Parser (Const Text a) +-- partialExpr = fmap Const $ L.lineFold w $ \w' -> +-- try w' <> w +-- where +-- w = L.space eat (void lineComment) (void blockComment) +-- eat = void . some $ satisfy (not . isSpace) + +pat1 :: Parser Pat' +pat1 = VarP <$> varid + +varid :: Parser VarId +varid = NameVar <$> lexeme namevar + <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') + "variable identifier" + where + namevar = T.pack <$> + liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) + + isNameTail c = isAlphaNum c + || c == '\'' + || c == '_' + +isVarSym :: Char -> Bool +isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") + +isSym :: Char -> Bool +isSym c = c == ':' || isVarSym c + +infixD = undefined + +tySigD = undefined +dataD = undefined + +---------------------------------------------------------------------------------- + +-- absolute psycho shit + +type PartialDecl' = Decl (Const PartialExpr') Name + +newtype Y f = Y (f (Y f)) + +instance (Show (f (Y f))) => Show (Y f) where + showsPrec p (Y f) = showsPrec p f + +data Partial a = E (RlpExprF Name a) + | U (Partial a) Name (Partial a) + deriving Show + +type PartialExpr' = Y Partial + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 6efdc4e..9e5c53b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -1,23 +1,52 @@ +-- recursion-schemes +{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} +-- recursion-schemes +{-# LANGUAGE TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} -module RLP.Syntax - ( RlpExpr +module Rlp.Syntax + ( RlpExpr(..) + , RlpExprF(..) + , RlpExprF' + , Decl(..) + , Assoc(..) + , VarId(..) + , Pat(..) + , Pat' ) where ---------------------------------------------------------------------------------- +import Data.Functor.Const import Data.Text (Text) +import Data.Text qualified as T +import Data.String (IsString(..)) +import Data.Functor.Foldable.TH (makeBaseFunctor) import Lens.Micro +import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- -newtype RlpProgram b = RlpProgram [Decl b] +newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -data Decl b = InfixD InfixAssoc Int VarId - | FunD VarId [Pat b] (RlpExpr b) - | DataD ConId [ConId] [ConAlt] +-- | The @e@ parameter is used for partial results. When parsing an input, we +-- first parse all top-level declarations in order to extract infix[lr] +-- declarations. This process yields a @[Decl (Const Text) Name]@, where @Const +-- Text@ stores the remaining unparsed function bodies. Once infixities are +-- accounted for, we may complete the parsing task and get a proper @[Decl +-- RlpExpr Name]@. + +data Decl e b = FunD VarId [Pat b] (e b) + | TySigD [VarId] Type + | DataD ConId [ConId] [ConAlt] + | InfixD Assoc Int Name + deriving Show + +data Assoc = InfixL + | InfixR + | Infix + deriving Show data ConAlt = ConAlt ConId [ConId] - -data InfixAssoc = Assoc | AssocL | AssocR + deriving Show data RlpExpr b = LetE [Bind b] (RlpExpr b) | VarE VarId @@ -27,26 +56,39 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) | IfE (RlpExpr b) (RlpExpr b) (RlpExpr b) | AppE (RlpExpr b) (RlpExpr b) | LitE (Lit b) + deriving Show -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) + deriving Show data Bind b = PatB (Pat b) (RlpExpr b) | FunB VarId [Pat b] (RlpExpr b) + deriving Show data VarId = NameVar Text | SymVar Text + deriving Show + +instance IsString VarId where + -- TODO: use symvar if it's an operator + fromString = NameVar . T.pack data ConId = NameCon Text | SymCon Text + deriving Show data Pat b = VarP VarId | LitP (Lit b) | ConP ConId [Pat b] + deriving Show + +type Pat' = Pat Name data Lit b = IntL Int | CharL Char | ListL [RlpExpr b] + deriving Show -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens @@ -57,3 +99,10 @@ data Lit b = IntL Int -- _rhs = lens -- (\ (AltA _ e) -> e) -- (\ (AltA p _) e' -> AltA p e') + +makeBaseFunctor ''RlpExpr + +deriving instance (Show b, Show a) => Show (RlpExprF b a) + +type RlpExprF' = RlpExprF Name + -- 2.52.0 From 060d48f9e18ac077bf3a5e50d02c26b59c6e9b82 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 06:26:48 -0700 Subject: [PATCH 029/192] oh boy am i going to hate this code in 12 hours --- src/RLP/ParseDecls.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 4d18e22..376ef37 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -71,7 +71,8 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ fmap Y $ U <$> varid' <*> lexeme infixOp <*> varid' + [ try $ fmap Y $ U <$> varid' <*> lexeme infixOp <*> fmap unY partialExpr + , fmap Y $ varid' ] where varid' = E . VarEF <$> varid @@ -128,6 +129,9 @@ type PartialDecl' = Decl (Const PartialExpr') Name newtype Y f = Y (f (Y f)) +unY :: Y f -> f (Y f) +unY (Y f) = f + instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f -- 2.52.0 From 9a357a99b71b193ea060b069fadf30c948e590cf Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 07:03:45 -0700 Subject: [PATCH 030/192] application and lits appl --- src/RLP/ParseDecls.hs | 37 ++++++++++++++++++++++++++----------- src/RLP/Syntax.hs | 5 +++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 376ef37..1789c83 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -13,12 +13,12 @@ import Text.Megaparsec.Char.Lexer qualified as L import Data.Functor.Const import Data.Text (Text) import Data.Text qualified as T +import Data.List (foldl1') import Data.Void import Data.Char import Data.Functor import Data.HashMap.Strict qualified as H import Control.Monad -import Core.Syntax import Control.Monad.State ---------------------------------------------------------------------------------- @@ -71,11 +71,25 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Y $ U <$> varid' <*> lexeme infixOp <*> fmap unY partialExpr - , fmap Y $ varid' + [ try $ fmap Y $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + , foldl1' papp <$> some partialExpr1 ] - where varid' = E . VarEF <$> varid + where + partialExpr1' = unY <$> partialExpr1 + partialExpr' = unY <$> partialExpr + papp :: PartialExpr' -> PartialExpr' -> PartialExpr' + papp f x = Y . E $ f `AppEF` x + +partialExpr1 :: Parser PartialExpr' +partialExpr1 = choice + [ try $ char '(' *> partialExpr <* char ')' + , fmap Y $ varid' + , fmap Y $ lit' + ] + where + varid' = E . VarEF <$> varid + lit' = E . LitEF <$> lit infixOp :: Parser Name infixOp = symvar <|> symcon @@ -88,13 +102,6 @@ symcon :: Parser Name symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) --- partialExpr :: Parser (Const Text a) --- partialExpr = fmap Const $ L.lineFold w $ \w' -> --- try w' <> w --- where --- w = L.space eat (void lineComment) (void blockComment) --- eat = void . some $ satisfy (not . isSpace) - pat1 :: Parser Pat' pat1 = VarP <$> varid @@ -121,6 +128,11 @@ infixD = undefined tySigD = undefined dataD = undefined +lit :: Parser Lit' +lit = int + where + int = IntL <$> L.decimal + ---------------------------------------------------------------------------------- -- absolute psycho shit @@ -132,6 +144,9 @@ newtype Y f = Y (f (Y f)) unY :: Y f -> f (Y f) unY (Y f) = f +ymap :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g +ymap m (Y f) = Y $ m (ymap m <$> f) + instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 9e5c53b..8a93059 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -12,6 +12,9 @@ module Rlp.Syntax , VarId(..) , Pat(..) , Pat' + , Lit(..) + , Lit' + , Name ) where ---------------------------------------------------------------------------------- @@ -90,6 +93,8 @@ data Lit b = IntL Int | ListL [RlpExpr b] deriving Show +type Lit' = Lit Name + -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens -- (\ (AltA p _) -> p) -- 2.52.0 From 8aa9bb843f3e2ab9d682566462fca5bfd0d19b20 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 08:04:49 -0700 Subject: [PATCH 031/192] something --- src/RLP/ParseDecls.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 1789c83..9472063 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -47,7 +47,7 @@ symbol :: Text -> Parser Text symbol = L.symbol sc sc :: Parser () -sc = L.space space1 (void lineComment) (void blockComment) +sc = L.space hspace1 (void lineComment) (void blockComment) -- TODO: return comment text -- TODO: '---' should not start a comment @@ -156,3 +156,7 @@ data Partial a = E (RlpExprF Name a) type PartialExpr' = Y Partial +---------------------------------------------------------------------------------- + + + -- 2.52.0 From f31726b43d94e9a8620c9a1fe4e990b5715a9f73 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 08:43:34 -0700 Subject: [PATCH 032/192] goofy --- src/RLP/ParseDecls.hs | 14 +++++++++----- src/RLP/Syntax.hs | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 9472063..83db884 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -1,5 +1,6 @@ -- Show Y {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.ParseDecls ( @@ -17,6 +18,7 @@ import Data.List (foldl1') import Data.Void import Data.Char import Data.Functor +import Data.Functor.Foldable import Data.HashMap.Strict qualified as H import Control.Monad import Control.Monad.State @@ -83,7 +85,7 @@ partialExpr = choice partialExpr1 :: Parser PartialExpr' partialExpr1 = choice - [ try $ char '(' *> partialExpr <* char ')' + [ try $ char '(' *> (hoistY P <$> partialExpr) <* char ')' , fmap Y $ varid' , fmap Y $ lit' ] @@ -144,19 +146,21 @@ newtype Y f = Y (f (Y f)) unY :: Y f -> f (Y f) unY (Y f) = f -ymap :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g -ymap m (Y f) = Y $ m (ymap m <$> f) +hoistY :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g +hoistY m (Y f) = Y $ m (hoistY m <$> f) instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f data Partial a = E (RlpExprF Name a) | U (Partial a) Name (Partial a) - deriving Show + | P (Partial a) + deriving (Show, Functor) type PartialExpr' = Y Partial ---------------------------------------------------------------------------------- - +mkOp :: RlpExpr b -> RlpExpr b -> RlpExpr b -> RlpExpr b +mkOp f a b = (f `AppE` a) `AppE` b diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 8a93059..eaf6b12 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -5,6 +5,7 @@ {-# LANGUAGE OverloadedStrings #-} module Rlp.Syntax ( RlpExpr(..) + , RlpExpr' , RlpExprF(..) , RlpExprF' , Decl(..) @@ -61,6 +62,8 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) | LitE (Lit b) deriving Show +type RlpExpr' = RlpExpr Name + -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) deriving Show -- 2.52.0 From d1e64eb12d8da0f7fcb845560782f4b37a31568c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 3 Jan 2024 10:04:42 -0700 Subject: [PATCH 033/192] Show1 instances --- rlp.cabal | 3 +++ src/RLP/ParseDecls.hs | 45 ++++++++++++++++++++++++------------------- src/RLP/Syntax.hs | 30 ++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index b960ec6..172e047 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -43,6 +43,8 @@ library build-tool-depends: happy:happy, alex:alex -- other-extensions: + + -- TODO: version bounds build-depends: base ^>=4.18.0.0 , containers , microlens @@ -62,6 +64,7 @@ library , recursion-schemes , megaparsec , text + , data-fix hs-source-dirs: src default-language: GHC2021 diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 83db884..7a36248 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -1,7 +1,8 @@ --- Show Y +-- Show Fix {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} module Rlp.ParseDecls ( ) @@ -12,6 +13,7 @@ import Text.Megaparsec hiding (State) import Text.Megaparsec.Char import Text.Megaparsec.Char.Lexer qualified as L import Data.Functor.Const +import Data.Functor.Classes import Data.Text (Text) import Data.Text qualified as T import Data.List (foldl1') @@ -19,6 +21,7 @@ import Data.Void import Data.Char import Data.Functor import Data.Functor.Foldable +import Data.Fix import Data.HashMap.Strict qualified as H import Control.Monad import Control.Monad.State @@ -73,21 +76,21 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Y $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + [ try $ fmap Fix $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] where - partialExpr1' = unY <$> partialExpr1 - partialExpr' = unY <$> partialExpr + partialExpr1' = unFix <$> partialExpr1 + partialExpr' = unFix <$> partialExpr papp :: PartialExpr' -> PartialExpr' -> PartialExpr' - papp f x = Y . E $ f `AppEF` x + papp f x = Fix . E $ f `AppEF` x partialExpr1 :: Parser PartialExpr' partialExpr1 = choice - [ try $ char '(' *> (hoistY P <$> partialExpr) <* char ')' - , fmap Y $ varid' - , fmap Y $ lit' + [ try $ char '(' *> (hoistFix P <$> partialExpr) <* char ')' + , fmap Fix $ varid' + , fmap Fix $ lit' ] where varid' = E . VarEF <$> varid @@ -141,23 +144,25 @@ lit = int type PartialDecl' = Decl (Const PartialExpr') Name -newtype Y f = Y (f (Y f)) - -unY :: Y f -> f (Y f) -unY (Y f) = f - -hoistY :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g -hoistY m (Y f) = Y $ m (hoistY m <$> f) - -instance (Show (f (Y f))) => Show (Y f) where - showsPrec p (Y f) = showsPrec p f - data Partial a = E (RlpExprF Name a) | U (Partial a) Name (Partial a) | P (Partial a) deriving (Show, Functor) -type PartialExpr' = Y Partial +instance Show1 Partial where + liftShowsPrec :: forall a. (Int -> a -> ShowS) + -> ([a] -> ShowS) + -> Int -> Partial a -> ShowS + + liftShowsPrec sp sl p m = case m of + (E e) -> showsUnaryWith lshow "E" p e + (U a f b) -> showsTernaryWith lshow showsPrec lshow "U" p a f b + (P e) -> showsUnaryWith lshow "P" p e + where + lshow :: forall f. (Show1 f) => Int -> f a -> ShowS + lshow = liftShowsPrec sp sl + +type PartialExpr' = Fix Partial ---------------------------------------------------------------------------------- diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index eaf6b12..4a47b7a 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -16,6 +16,9 @@ module Rlp.Syntax , Lit(..) , Lit' , Name + + -- TODO: ugh move this somewhere else later + , showsTernaryWith ) where ---------------------------------------------------------------------------------- @@ -24,11 +27,12 @@ import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) +import Data.Functor.Classes import Lens.Micro import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- - + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we @@ -114,3 +118,27 @@ deriving instance (Show b, Show a) => Show (RlpExprF b a) type RlpExprF' = RlpExprF Name +-- society if derivable Show1 +instance (Show b) => Show1 (RlpExprF b) where + liftShowsPrec sp _ p m = case m of + (LetEF bs e) -> showsBinaryWith showsPrec sp "LetEF" p bs e + (VarEF n) -> showsUnaryWith showsPrec "VarEF" p n + (ConEF n) -> showsUnaryWith showsPrec "ConEF" p n + (LamEF bs e) -> showsBinaryWith showsPrec sp "LamEF" p bs e + (CaseEF e as) -> showsBinaryWith sp showsPrec "CaseEF" p e as + (IfEF a b c) -> showsTernaryWith sp sp sp "IfEF" p a b c + (AppEF f x) -> showsBinaryWith sp sp "AppEF" p f x + (LitEF l) -> showsUnaryWith showsPrec "LitEF" p l + +showsTernaryWith :: (Int -> x -> ShowS) + -> (Int -> y -> ShowS) + -> (Int -> z -> ShowS) + -> String -> Int + -> x -> y -> z + -> ShowS +showsTernaryWith sa sb sc name p a b c = showParen (p > 10) + $ showString name + . showChar ' ' . sa 11 a + . showChar ' ' . sb 11 b + . showChar ' ' . sc 11 c + -- 2.52.0 From a71c099fe0c0ea93235cfaa96e95fda4bc6e061a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 13:39:12 -0700 Subject: [PATCH 034/192] fixation fufilled - back to work! --- rlp.cabal | 3 +- src/RLP/{ParseDecls.hs => Parse/Decls.hs} | 88 +++++++++++------------ src/RLP/Parse/Types.hs | 65 +++++++++++++++++ src/RLP/Syntax.hs | 6 +- 4 files changed, 115 insertions(+), 47 deletions(-) rename src/RLP/{ParseDecls.hs => Parse/Decls.hs} (69%) create mode 100644 src/RLP/Parse/Types.hs diff --git a/rlp.cabal b/rlp.cabal index 172e047..88ab65c 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -31,7 +31,8 @@ library , Core.HindleyMilner , Control.Monad.Errorful , Rlp.Syntax - , Rlp.ParseDecls + , Rlp.Parse.Decls + , Rlp.Parse.Types other-modules: Data.Heap , Data.Pretty diff --git a/src/RLP/ParseDecls.hs b/src/RLP/Parse/Decls.hs similarity index 69% rename from src/RLP/ParseDecls.hs rename to src/RLP/Parse/Decls.hs index 7a36248..18e85aa 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/Parse/Decls.hs @@ -1,41 +1,30 @@ --- Show Fix -{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ImplicitParams #-} +{-# LANGUAGE LambdaCase, BlockArguments #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -module Rlp.ParseDecls +module Rlp.Parse.Decls ( ) where ---------------------------------------------------------------------------------- -import Rlp.Syntax +import Control.Monad +import Control.Monad.State import Text.Megaparsec hiding (State) import Text.Megaparsec.Char import Text.Megaparsec.Char.Lexer qualified as L -import Data.Functor.Const import Data.Functor.Classes +import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T import Data.List (foldl1') -import Data.Void import Data.Char import Data.Functor -import Data.Functor.Foldable -import Data.Fix -import Data.HashMap.Strict qualified as H -import Control.Monad -import Control.Monad.State ----------------------------------------------------------------------------------- - -type Parser = ParsecT Void Text (State ParserState) - -data ParserState = ParserState - { _psPrecTable :: PrecTable - } - deriving Show - -type PrecTable = H.HashMap Name (Assoc, Int) - +import Data.Functor.Const +import Data.Fix hiding (cata) +import Lens.Micro +import Rlp.Parse.Types +import Rlp.Syntax ---------------------------------------------------------------------------------- parseTest' :: (Show a) => Parser a -> Text -> IO () @@ -76,10 +65,11 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Fix $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] where + mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr @@ -140,32 +130,42 @@ lit = int ---------------------------------------------------------------------------------- --- absolute psycho shit +type PartialE = Partial RlpExpr' -type PartialDecl' = Decl (Const PartialExpr') Name +-- complete :: OpTable -> Fix Partial -> RlpExpr' +complete :: OpTable -> PartialExpr' -> RlpExpr' +complete pt = let ?pt = pt in cata completePartial -data Partial a = E (RlpExprF Name a) - | U (Partial a) Name (Partial a) - | P (Partial a) - deriving (Show, Functor) +completePartial :: PartialE -> RlpExpr' +completePartial (E e) = completeRlpExpr e +completePartial p@(B o l r) = completeB (build p) +completePartial (P e) = completePartial e -instance Show1 Partial where - liftShowsPrec :: forall a. (Int -> a -> ShowS) - -> ([a] -> ShowS) - -> Int -> Partial a -> ShowS +completeRlpExpr :: RlpExprF' RlpExpr' -> RlpExpr' +completeRlpExpr = embed - liftShowsPrec sp sl p m = case m of - (E e) -> showsUnaryWith lshow "E" p e - (U a f b) -> showsTernaryWith lshow showsPrec lshow "U" p a f b - (P e) -> showsUnaryWith lshow "P" p e - where - lshow :: forall f. (Show1 f) => Int -> f a -> ShowS - lshow = liftShowsPrec sp sl +completeB :: PartialE -> RlpExpr' +completeB = build -type PartialExpr' = Fix Partial +build :: PartialE -> PartialE +build e = go id e (rightmost e) where + rightmost :: Partial -> Partial + rightmost (B _ _ _) = rightmost r + rightmost (E n) = undefined ----------------------------------------------------------------------------------- + go :: (?pt :: OpTable) + => (PartialE -> PartialE) + -> PartialE -> PartialE -> PartialE + go f p@(WithPrec o _ r) = case r of + E _ -> mkHole o (f . f') + P _ -> undefined + B _ _ _ -> go (mkHole o (f . f')) r + where f' r' = p & pR .~ r' -mkOp :: RlpExpr b -> RlpExpr b -> RlpExpr b -> RlpExpr b -mkOp f a b = (f `AppE` a) `AppE` b +mkHole :: (?pt :: OpTable) + => OpInfo + -> (PartialE -> PartialE) + -> PartialE + -> PartialE +mkHole = undefined diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs new file mode 100644 index 0000000..cb1d6bf --- /dev/null +++ b/src/RLP/Parse/Types.hs @@ -0,0 +1,65 @@ +module Rlp.Parse.Types + ( + -- * Partial ASTs + Partial(..) + , PartialExpr' + , PartialDecl' + + -- * Parser types + , Parser + , ParserState(..) + , OpTable + , OpInfo + ) + where +---------------------------------------------------------------------------------- +import Control.Monad.State +import Data.HashMap.Strict qualified as H +import Data.Fix +import Data.Functor.Foldable +import Data.Functor.Const +import Data.Functor.Classes +import Data.Void +import Text.Megaparsec hiding (State) +import Rlp.Syntax +---------------------------------------------------------------------------------- + +-- parser types + +type Parser = ParsecT Void Text (State ParserState) + +data ParserState = ParserState + { _psOpTable :: OpTable + } + deriving Show + +type OpTable = H.HashMap Name OpInfo +type OpInfo = (Assoc, Int) + +---------------------------------------------------------------------------------- + +-- absolute psycho shit (partial ASTs) + +type PartialDecl' = Decl (Const PartialExpr') Name + +data Partial a = E (RlpExprF Name a) + | B Name (Partial a) (Partial a) + | P (Partial a) + deriving (Show, Functor) + +-- required to satisfy constraint on Fix's show instance +instance Show1 Partial where + liftShowsPrec :: forall a. (Int -> a -> ShowS) + -> ([a] -> ShowS) + -> Int -> Partial a -> ShowS + + liftShowsPrec sp sl p m = case m of + (E e) -> showsUnaryWith lshow "E" p e + (B f a b) -> showsTernaryWith showsPrec lshow lshow "B" p f a b + (P e) -> showsUnaryWith lshow "P" p e + where + lshow :: forall f. (Show1 f) => Int -> f a -> ShowS + lshow = liftShowsPrec sp sl + +type PartialExpr' = Fix Partial + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 4a47b7a..b314d7b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -19,10 +19,12 @@ module Rlp.Syntax -- TODO: ugh move this somewhere else later , showsTernaryWith + + -- * Convenience re-exports + , Text ) where ---------------------------------------------------------------------------------- -import Data.Functor.Const import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) @@ -32,7 +34,7 @@ import Lens.Micro import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- - + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we -- 2.52.0 From 2f783d96e88a354b298b463460759e3cb7ed85b7 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 18:56:14 -0700 Subject: [PATCH 035/192] works --- src/RLP/Parse/Decls.hs | 70 +++++++++++++++++++++++++++++++++--------- src/RLP/Parse/Types.hs | 27 ++++++++++++++++ 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 18e85aa..965a4c5 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -17,6 +17,7 @@ import Data.Functor.Classes import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T +import Data.HashMap.Strict qualified as H import Data.List (foldl1') import Data.Char import Data.Functor @@ -130,42 +131,81 @@ lit = int ---------------------------------------------------------------------------------- -type PartialE = Partial RlpExpr' - -- complete :: OpTable -> Fix Partial -> RlpExpr' -complete :: OpTable -> PartialExpr' -> RlpExpr' -complete pt = let ?pt = pt in cata completePartial +complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' +complete = cata completePartial -completePartial :: PartialE -> RlpExpr' +completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' completePartial (E e) = completeRlpExpr e completePartial p@(B o l r) = completeB (build p) completePartial (P e) = completePartial e -completeRlpExpr :: RlpExprF' RlpExpr' -> RlpExpr' +completeRlpExpr :: (?pt :: OpTable) => RlpExprF' RlpExpr' -> RlpExpr' completeRlpExpr = embed -completeB :: PartialE -> RlpExpr' -completeB = build +completeB :: (?pt :: OpTable) => PartialE -> RlpExpr' +completeB p = case build p of + B o l r -> (o' `AppE` l') `AppE` r' + where + -- TODO: how do we know it's symbolic? + o' = VarE (SymVar o) + l' = completeB l + r' = completeB r + P e -> completeB e + E e -> completeRlpExpr e -build :: PartialE -> PartialE +build :: (?pt :: OpTable) => PartialE -> PartialE build e = go id e (rightmost e) where - rightmost :: Partial -> Partial - rightmost (B _ _ _) = rightmost r - rightmost (E n) = undefined + rightmost :: PartialE -> PartialE + rightmost (B _ _ r) = rightmost r + rightmost p@(E _) = p + rightmost p@(P _) = p go :: (?pt :: OpTable) => (PartialE -> PartialE) -> PartialE -> PartialE -> PartialE - go f p@(WithPrec o _ r) = case r of + go f p@(WithInfo o _ r) = case r of E _ -> mkHole o (f . f') - P _ -> undefined + P _ -> mkHole o (f . f') B _ _ _ -> go (mkHole o (f . f')) r where f' r' = p & pR .~ r' + go f _ = id mkHole :: (?pt :: OpTable) => OpInfo -> (PartialE -> PartialE) -> PartialE -> PartialE -mkHole = undefined +mkHole _ hole p@(P _) = hole p +mkHole _ hole p@(E _) = hole p +mkHole (a,d) hole p@(WithInfo (a',d') _ _) + | d' < d = above + | d' > d = below + | d == d' = case (a,a') of + -- left-associative operators of equal precedence are + -- associated left + (InfixL,InfixL) -> above + -- right-associative operators are handled similarly + (InfixR,InfixR) -> below + -- non-associative operators of equal precedence, or equal + -- precedence operators of different associativities are + -- invalid + (_, _) -> error "invalid expression" + where + above = p & pL %~ hole + below = hole p + +examplePrecTable :: OpTable +examplePrecTable = H.fromList + [ ("+", (InfixL,6)) + , ("*", (InfixL,7)) + , ("^", (InfixR,8)) + , (".", (InfixR,7)) + , ("~", (Infix, 9)) + , ("=", (Infix, 4)) + , ("&&", (Infix, 3)) + , ("||", (Infix, 2)) + , ("$", (InfixR,0)) + , ("&", (InfixL,0)) + ] diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index cb1d6bf..d3e7bd1 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -1,9 +1,17 @@ +{-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} +{- +Description : Supporting types for the parser +-} module Rlp.Parse.Types ( -- * Partial ASTs Partial(..) + , PartialE , PartialExpr' , PartialDecl' + , pattern WithInfo + , pR + , pL -- * Parser types , Parser @@ -20,7 +28,9 @@ import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes import Data.Void +import Data.Maybe import Text.Megaparsec hiding (State) +import Lens.Micro import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -47,6 +57,23 @@ data Partial a = E (RlpExprF Name a) | P (Partial a) deriving (Show, Functor) +pL :: Traversal' (Partial a) (Partial a) +pL k (B o l r) = (\l' -> B o l' r) <$> k l +pL _ x = pure x + +pR :: Traversal' (Partial a) (Partial a) +pR k (B o l r) = (\r' -> B o l r') <$> k r +pR _ x = pure x + +type PartialE = Partial RlpExpr' + +-- i love you haskell +pattern WithInfo :: (?pt :: OpTable) => OpInfo -> PartialE -> PartialE -> PartialE +pattern WithInfo p l r <- B (opInfoOrDef -> p) l r + +opInfoOrDef :: (?pt :: OpTable) => Name -> OpInfo +opInfoOrDef c = fromMaybe (InfixL,9) $ H.lookup c ?pt + -- required to satisfy constraint on Fix's show instance instance Show1 Partial where liftShowsPrec :: forall a. (Int -> a -> ShowS) -- 2.52.0 From cb7cdf7ed7422d1e144a371234d8654a59fc8e36 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 20:14:18 -0700 Subject: [PATCH 036/192] labels --- src/RLP/Parse/Decls.hs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 965a4c5..c8a0a33 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -64,11 +64,18 @@ decl = choice funD :: Parser PartialDecl' funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) +standalonePartialExpr :: Parser PartialExpr' +standalonePartialExpr = standaloneOf partialExpr + +standaloneOf :: Parser a -> Parser a +standaloneOf = (<* eof) + partialExpr :: Parser PartialExpr' partialExpr = choice [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] + "expression" where mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 @@ -83,12 +90,13 @@ partialExpr1 = choice , fmap Fix $ varid' , fmap Fix $ lit' ] + "expression" where varid' = E . VarEF <$> varid lit' = E . LitEF <$> lit infixOp :: Parser Name -infixOp = symvar <|> symcon +infixOp = symvar <|> symcon "infix operator" symvar :: Parser Name symvar = T.pack <$> @@ -100,6 +108,7 @@ symcon = T.pack <$> pat1 :: Parser Pat' pat1 = VarP <$> varid + "pattern" varid :: Parser VarId varid = NameVar <$> lexeme namevar @@ -126,6 +135,7 @@ dataD = undefined lit :: Parser Lit' lit = int + "literal" where int = IntL <$> L.decimal -- 2.52.0 From 37d9e6f219523f4b1584cf62e9ffb09286683ca5 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 11:39:26 -0700 Subject: [PATCH 037/192] infix decl --- rlp.cabal | 2 +- src/RLP/Parse/Decls.hs | 36 +++++++++++++++++++++++++++++++++++- src/RLP/Parse/Types.hs | 36 +++++++++++++++++++++++++++++++++++- src/RLP/Syntax.hs | 3 +++ 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 88ab65c..f4a93e2 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -63,7 +63,7 @@ library -- TODO: either learn recursion-schemes, or stop depending -- on it. , recursion-schemes - , megaparsec + , megaparsec ^>=9.6.0 , text , data-fix diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index c8a0a33..3c28017 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -24,6 +24,7 @@ import Data.Functor import Data.Functor.Const import Data.Fix hiding (cata) import Lens.Micro +import Lens.Micro.Platform import Rlp.Parse.Types import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -128,7 +129,40 @@ isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") isSym :: Char -> Bool isSym c = c == ':' || isVarSym c -infixD = undefined +infixD :: Parser (Decl' e) +infixD = do + o <- getOffset + a <- infixWord + p <- prec + op <- infixOp + region (setErrorOffset o) $ updateOpTable a p op + pure $ InfixD a p op + where + infixWord :: Parser Assoc + infixWord = choice $ lexeme <$> + [ "infixr" $> InfixR + , "infixl" $> InfixL + , "infix" $> Infix + ] + + prec :: Parser Int + prec = do + o <- getOffset + n <- lexeme L.decimal + if 0 <= n && n <= 9 then + pure n + else + region (setErrorOffset o) $ + registerCustomFailure (RlpParErrOutOfBoundsPrecedence n) + $> 9 + + updateOpTable :: Assoc -> Int -> Name -> Parser () + updateOpTable a p op = do + t <- use psOpTable + psOpTable <~ H.alterF f op t + where + f Nothing = pure (Just (a,p)) + f (Just _) = customFailure RlpParErrDuplicateInfixD tySigD = undefined dataD = undefined diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index d3e7bd1..16a0ed9 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} {- Description : Supporting types for the parser @@ -16,8 +18,13 @@ module Rlp.Parse.Types -- * Parser types , Parser , ParserState(..) + , psOpTable + , RlpParseError(..) , OpTable , OpInfo + + -- * Extras + , registerCustomFailure ) where ---------------------------------------------------------------------------------- @@ -29,14 +36,17 @@ import Data.Functor.Const import Data.Functor.Classes import Data.Void import Data.Maybe +import Data.Set qualified as S import Text.Megaparsec hiding (State) +import Text.Printf import Lens.Micro +import Lens.Micro.TH import Rlp.Syntax ---------------------------------------------------------------------------------- -- parser types -type Parser = ParsecT Void Text (State ParserState) +type Parser = ParsecT RlpParseError Text (State ParserState) data ParserState = ParserState { _psOpTable :: OpTable @@ -46,6 +56,23 @@ data ParserState = ParserState type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) +-- data WithLocation a = WithLocation [String] a + +data RlpParseError = RlpParErrOutOfBoundsPrecedence Int + | RlpParErrDuplicateInfixD + deriving (Eq, Ord, Show) + +instance ShowErrorComponent RlpParseError where + showErrorComponent = \case + -- TODO: wrap text to 80 characters + RlpParErrOutOfBoundsPrecedence n -> + printf "%d is an invalid precedence level! rl' currently only\ + \allows custom precedences between 0 and 9 (inclusive).\ + \ This is an arbitrary limit put in place for legibility\ + \ concerns, and may change in the future." n + RlpParErrDuplicateInfixD -> + "duplicate infix decl" + ---------------------------------------------------------------------------------- -- absolute psycho shit (partial ASTs) @@ -90,3 +117,10 @@ instance Show1 Partial where type PartialExpr' = Fix Partial +---------------------------------------------------------------------------------- + +makeLenses ''ParserState + +registerCustomFailure :: MonadParsec e s m => e -> m () +registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index b314d7b..4a43cb9 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -9,6 +9,7 @@ module Rlp.Syntax , RlpExprF(..) , RlpExprF' , Decl(..) + , Decl' , Assoc(..) , VarId(..) , Pat(..) @@ -50,6 +51,8 @@ data Decl e b = FunD VarId [Pat b] (e b) | InfixD Assoc Int Name deriving Show +type Decl' e = Decl e Name + data Assoc = InfixL | InfixR | Infix -- 2.52.0 From 074350768c259f4ac65aac530368ce9edec7578a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 12:26:53 -0700 Subject: [PATCH 038/192] expr fixups --- src/RLP/Parse/Decls.hs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 3c28017..87668aa 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -45,6 +45,9 @@ symbol = L.symbol sc sc :: Parser () sc = L.space hspace1 (void lineComment) (void blockComment) +scn :: Parser () +scn = L.space space1 (void lineComment) (void blockComment) + -- TODO: return comment text -- TODO: '---' should not start a comment lineComment :: Parser Text @@ -72,27 +75,35 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = choice - [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' - , foldl1' papp <$> some partialExpr1 +partialExpr = (choice . fmap foldedLexeme) + [ try application + , Fix <$> infixExpr ] "expression" where + application = foldl1' mkApp <$> some partialExpr1 + infixExpr = mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' + mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr + infixOp' = foldedLexeme infixOp - papp :: PartialExpr' -> PartialExpr' -> PartialExpr' - papp f x = Fix . E $ f `AppEF` x + mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' + mkApp f x = Fix . E $ f `AppEF` x + +foldedLexeme :: Parser a -> Parser a +foldedLexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p partialExpr1 :: Parser PartialExpr' -partialExpr1 = choice - [ try $ char '(' *> (hoistFix P <$> partialExpr) <* char ')' - , fmap Fix $ varid' - , fmap Fix $ lit' +partialExpr1 = (choice . fmap foldedLexeme) + [ foldedLexeme "(" *> partialExpr' <* foldedLexeme ")" + , Fix <$> varid' + , Fix <$> lit' ] "expression" where + partialExpr' = wrapFix . P . unwrapFix <$> partialExpr varid' = E . VarEF <$> varid lit' = E . LitEF <$> lit -- 2.52.0 From 90a9594e8f8a55c2cf071b7e6c4aebc74a079341 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 14:24:51 -0700 Subject: [PATCH 039/192] where --- src/RLP/Parse/Decls.hs | 93 ++++++++++++++++++++++++++++++++---------- src/RLP/Parse/Types.hs | 7 ---- src/RLP/Parse/Utils.hs | 30 ++++++++++++++ src/RLP/Syntax.hs | 24 +++++++---- 4 files changed, 119 insertions(+), 35 deletions(-) create mode 100644 src/RLP/Parse/Utils.hs diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 87668aa..8a95f41 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -18,6 +18,7 @@ import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H +import Data.Maybe (maybeToList) import Data.List (foldl1') import Data.Char import Data.Functor @@ -26,6 +27,7 @@ import Data.Fix hiding (cata) import Lens.Micro import Lens.Micro.Platform import Rlp.Parse.Types +import Rlp.Parse.Utils import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -39,6 +41,9 @@ parseTest' p s = case runState (runParserT p "test" s) init of lexeme :: Parser a -> Parser a lexeme = L.lexeme sc +flexeme :: Parser a -> Parser a +flexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p + symbol :: Text -> Parser Text symbol = L.symbol sc @@ -66,7 +71,16 @@ decl = choice ] funD :: Parser PartialDecl' -funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) +funD = FunD <$> flexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause + where + params = many pat1 + body = fmap Const partialExpr + +whereClause :: Parser Where' +whereClause = optionalList $ + flexeme "where" *> pure + [ FunB "fixme" [] (VarE "fixme") + ] standalonePartialExpr :: Parser PartialExpr' standalonePartialExpr = standaloneOf partialExpr @@ -75,7 +89,7 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = (choice . fmap foldedLexeme) +partialExpr = (choice . fmap flexeme) [ try application , Fix <$> infixExpr ] @@ -87,17 +101,14 @@ partialExpr = (choice . fmap foldedLexeme) mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr - infixOp' = foldedLexeme infixOp + infixOp' = flexeme infixOp mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x -foldedLexeme :: Parser a -> Parser a -foldedLexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p - partialExpr1 :: Parser PartialExpr' -partialExpr1 = (choice . fmap foldedLexeme) - [ foldedLexeme "(" *> partialExpr' <* foldedLexeme ")" +partialExpr1 = (choice . fmap flexeme) + [ try $ flexeme "(" *> partialExpr' <* flexeme ")" , Fix <$> varid' , Fix <$> lit' ] @@ -108,7 +119,7 @@ partialExpr1 = (choice . fmap foldedLexeme) lit' = E . LitEF <$> lit infixOp :: Parser Name -infixOp = symvar <|> symcon "infix operator" +infixOp = symvar <|> symcon "operator" symvar :: Parser Name symvar = T.pack <$> @@ -119,20 +130,34 @@ symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) pat1 :: Parser Pat' -pat1 = VarP <$> varid +pat1 = VarP <$> flexeme varid "pattern" +conid :: Parser ConId +conid = NameCon <$> lexeme namecon + <|> SymCon <$> lexeme (char '(' *> symcon <* char ')') + "constructor identifier" + +namecon :: Parser Name +namecon = T.pack <$> + liftA2 (:) (satisfy isUpper) + (many $ satisfy isNameTail) + varid :: Parser VarId -varid = NameVar <$> lexeme namevar +varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" - where - namevar = T.pack <$> + +namevar :: Parser Name +namevar = try word + & withPredicate (`notElem` ["where"]) empty + where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) - isNameTail c = isAlphaNum c - || c == '\'' - || c == '_' +isNameTail :: Char -> Bool +isNameTail c = isAlphaNum c + || c == '\'' + || c == '_' isVarSym :: Char -> Bool isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") @@ -159,7 +184,7 @@ infixD = do prec :: Parser Int prec = do o <- getOffset - n <- lexeme L.decimal + n <- lexeme L.decimal "precedence level (an integer)" if 0 <= n && n <= 9 then pure n else @@ -173,10 +198,36 @@ infixD = do psOpTable <~ H.alterF f op t where f Nothing = pure (Just (a,p)) - f (Just _) = customFailure RlpParErrDuplicateInfixD + f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD + $> Just x tySigD = undefined -dataD = undefined + +dataD :: Parser (Decl' e) +dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram + <*> optionalList (symbol "=" *> conalts) + where + typaram :: Parser Name + typaram = flexeme namevar + + conalts :: Parser [ConAlt] + conalts = (:) <$> conalt <*> optionalList (symbol "|" *> conalts) + + conalt :: Parser ConAlt + conalt = ConAlt <$> conid <*> many type1 + +type1 :: Parser Type +type1 = (choice . fmap flexeme) + [ flexeme "(" *> type_ <* flexeme ")" + , TyVar <$> namevar + , TyCon <$> namecon + ] + +type_ :: Parser Type +type_ = (choice . fmap flexeme) + [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) + , type1 + ] lit :: Parser Lit' lit = int @@ -184,9 +235,9 @@ lit = int where int = IntL <$> L.decimal ----------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- completing partial expressions --- complete :: OpTable -> Fix Partial -> RlpExpr' complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' complete = cata completePartial diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index 16a0ed9..e961d2d 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -22,9 +22,6 @@ module Rlp.Parse.Types , RlpParseError(..) , OpTable , OpInfo - - -- * Extras - , registerCustomFailure ) where ---------------------------------------------------------------------------------- @@ -36,7 +33,6 @@ import Data.Functor.Const import Data.Functor.Classes import Data.Void import Data.Maybe -import Data.Set qualified as S import Text.Megaparsec hiding (State) import Text.Printf import Lens.Micro @@ -121,6 +117,3 @@ type PartialExpr' = Fix Partial makeLenses ''ParserState -registerCustomFailure :: MonadParsec e s m => e -> m () -registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom - diff --git a/src/RLP/Parse/Utils.hs b/src/RLP/Parse/Utils.hs new file mode 100644 index 0000000..cf5fb8c --- /dev/null +++ b/src/RLP/Parse/Utils.hs @@ -0,0 +1,30 @@ +module Rlp.Parse.Utils + ( withPredicate + , registerCustomFailure + , optionalList + ) + where +-------------------------------------------------------------------------------- +import Text.Megaparsec +import Rlp.Parse.Types +import Data.Set qualified as S +import Data.Maybe +import Control.Monad +-------------------------------------------------------------------------------- + +-- TODO: generalise type sig +withPredicate :: (a -> Bool) + -> Parser a -- ^ action to run should the predicate fail + -> Parser a + -> Parser a +withPredicate f r p = do + o <- getOffset + a <- p + if f a then pure a else setOffset o *> r + +registerCustomFailure :: MonadParsec e s m => e -> m () +registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom + +optionalList :: Parser [a] -> Parser [a] +optionalList = fmap (join . maybeToList) . optional + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 4a43cb9..09acb8b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -2,7 +2,7 @@ {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} -- recursion-schemes {-# LANGUAGE TemplateHaskell, TypeFamilies #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings, PatternSynonyms #-} module Rlp.Syntax ( RlpExpr(..) , RlpExpr' @@ -10,8 +10,15 @@ module Rlp.Syntax , RlpExprF' , Decl(..) , Decl' + , Bind(..) + , Where + , Where' + , ConAlt(..) + , Type(..) + , pattern (:->) , Assoc(..) , VarId(..) + , ConId(..) , Pat(..) , Pat' , Lit(..) @@ -45,9 +52,9 @@ newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- accounted for, we may complete the parsing task and get a proper @[Decl -- RlpExpr Name]@. -data Decl e b = FunD VarId [Pat b] (e b) +data Decl e b = FunD VarId [Pat b] (e b) (Where b) | TySigD [VarId] Type - | DataD ConId [ConId] [ConAlt] + | DataD ConId [Name] [ConAlt] | InfixD Assoc Int Name deriving Show @@ -58,14 +65,14 @@ data Assoc = InfixL | Infix deriving Show -data ConAlt = ConAlt ConId [ConId] - deriving Show +data ConAlt = ConAlt ConId [Type] + deriving Show data RlpExpr b = LetE [Bind b] (RlpExpr b) | VarE VarId | ConE ConId | LamE [Pat b] (RlpExpr b) - | CaseE (RlpExpr b) [Alt b] + | CaseE (RlpExpr b) [(Alt b, Where b)] | IfE (RlpExpr b) (RlpExpr b) (RlpExpr b) | AppE (RlpExpr b) (RlpExpr b) | LitE (Lit b) @@ -73,9 +80,12 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) type RlpExpr' = RlpExpr Name +type Where b = [Bind b] +type Where' = [Bind Name] + -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) - deriving Show + deriving Show data Bind b = PatB (Pat b) (RlpExpr b) | FunB VarId [Pat b] (RlpExpr b) -- 2.52.0 From 4b44f57066d8fdb82c5030f81d41254021f79806 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 22:57:14 -0700 Subject: [PATCH 040/192] cool --- src/RLP/Parse/Decls.hs | 44 ++++++++++++++++++++++++++++-------------- src/RLP/Syntax.hs | 15 +++++++++++++- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 8a95f41..9d4a911 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE RecursiveDo #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase, BlockArguments #-} @@ -71,14 +72,14 @@ decl = choice ] funD :: Parser PartialDecl' -funD = FunD <$> flexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause +funD = FunD <$> lexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause where params = many pat1 body = fmap Const partialExpr whereClause :: Parser Where' whereClause = optionalList $ - flexeme "where" *> pure + lexeme "where" *> pure [ FunB "fixme" [] (VarE "fixme") ] @@ -89,7 +90,7 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = (choice . fmap flexeme) +partialExpr = choice [ try application , Fix <$> infixExpr ] @@ -101,14 +102,14 @@ partialExpr = (choice . fmap flexeme) mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr - infixOp' = flexeme infixOp + infixOp' = lexeme infixOp mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x partialExpr1 :: Parser PartialExpr' -partialExpr1 = (choice . fmap flexeme) - [ try $ flexeme "(" *> partialExpr' <* flexeme ")" +partialExpr1 = choice + [ try $ lexeme "(" *> partialExpr' <* lexeme ")" , Fix <$> varid' , Fix <$> lit' ] @@ -130,7 +131,7 @@ symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) pat1 :: Parser Pat' -pat1 = VarP <$> flexeme varid +pat1 = VarP <$> lexeme varid "pattern" conid :: Parser ConId @@ -148,8 +149,23 @@ varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" +decls :: Parser [PartialDecl'] +decls = L.indentBlock scn p where + p = do + a <- "wtf" + pure (L.IndentSome (Just pos1) pure decl) + +t :: Parser [PartialDecl'] +t = do + space + i <- L.indentLevel + let indentGuard = L.indentGuard scn EQ i + -- indentGuard *> decl *> eol *> indentGuard *> decl + rec ds <- indentGuard *> decl <|> eof + many $ indentGuard *> decl <* (eol <|> eof) + namevar :: Parser Name -namevar = try word +namevar = word & withPredicate (`notElem` ["where"]) empty where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) @@ -204,11 +220,11 @@ infixD = do tySigD = undefined dataD :: Parser (Decl' e) -dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram +dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram <*> optionalList (symbol "=" *> conalts) where typaram :: Parser Name - typaram = flexeme namevar + typaram = lexeme namevar conalts :: Parser [ConAlt] conalts = (:) <$> conalt <*> optionalList (symbol "|" *> conalts) @@ -217,15 +233,15 @@ dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram conalt = ConAlt <$> conid <*> many type1 type1 :: Parser Type -type1 = (choice . fmap flexeme) - [ flexeme "(" *> type_ <* flexeme ")" +type1 = choice + [ lexeme "(" *> type_ <* lexeme ")" , TyVar <$> namevar , TyCon <$> namecon ] type_ :: Parser Type -type_ = (choice . fmap flexeme) - [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) +type_ = choice + [ try $ (:->) <$> type1 <*> (lexeme "->" *> type_) , type1 ] diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 09acb8b..58843b5 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -4,7 +4,10 @@ {-# LANGUAGE TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings, PatternSynonyms #-} module Rlp.Syntax - ( RlpExpr(..) + ( RlpModule(..) + , rlpmodName + , rlpmodProgram + , RlpExpr(..) , RlpExpr' , RlpExprF(..) , RlpExprF' @@ -39,10 +42,16 @@ import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes import Lens.Micro +import Lens.Micro.TH import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- +data RlpModule b = RlpModule + { _rlpmodName :: Text + , _rlpmodProgram :: RlpProgram b + } + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we @@ -157,3 +166,7 @@ showsTernaryWith sa sb sc name p a b c = showParen (p > 10) . showChar ' ' . sb 11 b . showChar ' ' . sc 11 c +-------------------------------------------------------------------------------- + +makeLenses ''RlpModule + -- 2.52.0 From 1d43c1d3049fe759cbbc91232c3bff948811f2c5 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 10:46:53 -0700 Subject: [PATCH 041/192] aaaaa --- src/RLP/Parse/Decls.hs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 9d4a911..201316b 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -65,10 +65,12 @@ blockComment = L.skipBlockCommentNested "{-" "-}" $> "" decl :: Parser PartialDecl' decl = choice - [ funD - , tySigD + -- declarations that begin with a keyword before those beginning with an + -- arbitrary name + [ infixD , dataD - , infixD + , funD + , tySigD ] funD :: Parser PartialDecl' @@ -150,26 +152,28 @@ varid = NameVar <$> try (lexeme namevar) "variable identifier" decls :: Parser [PartialDecl'] -decls = L.indentBlock scn p where - p = do - a <- "wtf" - pure (L.IndentSome (Just pos1) pure decl) - -t :: Parser [PartialDecl'] -t = do +decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i -- indentGuard *> decl *> eol *> indentGuard *> decl - rec ds <- indentGuard *> decl <|> eof - many $ indentGuard *> decl <* (eol <|> eof) + many $ indentGuard *> decl + -- many $ indentGuard *> decl <* (eol <|> eof) namevar :: Parser Name namevar = word - & withPredicate (`notElem` ["where"]) empty + & withPredicate (`notElem` keywords) empty where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) +keywords :: (IsString a) => [a] +keywords = + [ "where" + , "infix" + , "infixr" + , "infixl" + ] + isNameTail :: Char -> Bool isNameTail c = isAlphaNum c || c == '\'' @@ -217,7 +221,8 @@ infixD = do f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD $> Just x -tySigD = undefined +tySigD :: Parser (Decl' e) +tySigD = undefined -- TySigD <$> (flexeme) dataD :: Parser (Decl' e) dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram -- 2.52.0 From 86cd1075ca93f2072d4521849d09ae9a9139859e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:03:06 -0700 Subject: [PATCH 042/192] decls fix --- src/RLP/Parse/Decls.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 201316b..07c8263 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -22,9 +22,11 @@ import Data.HashMap.Strict qualified as H import Data.Maybe (maybeToList) import Data.List (foldl1') import Data.Char +import Data.Function (fix) import Data.Functor import Data.Functor.Const import Data.Fix hiding (cata) +import GHC.Exts (IsString) import Lens.Micro import Lens.Micro.Platform import Rlp.Parse.Types @@ -156,9 +158,8 @@ decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i - -- indentGuard *> decl *> eol *> indentGuard *> decl - many $ indentGuard *> decl - -- many $ indentGuard *> decl <* (eol <|> eof) + fix \ds -> (:) <$> (indentGuard *> decl) + <*> (try ds <|> eof *> pure []) namevar :: Parser Name namevar = word -- 2.52.0 From 981c5d8a831b6d266fec499984166dbbfcb2bd57 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:26:17 -0700 Subject: [PATCH 043/192] finally in a decent state --- src/RLP/Parse/Decls.hs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 07c8263..480bea3 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -44,9 +44,6 @@ parseTest' p s = case runState (runParserT p "test" s) init of lexeme :: Parser a -> Parser a lexeme = L.lexeme sc -flexeme :: Parser a -> Parser a -flexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p - symbol :: Text -> Parser Text symbol = L.symbol sc @@ -56,6 +53,8 @@ sc = L.space hspace1 (void lineComment) (void blockComment) scn :: Parser () scn = L.space space1 (void lineComment) (void blockComment) +type OnFold = (?foldGuard :: Parser ()) + -- TODO: return comment text -- TODO: '---' should not start a comment lineComment :: Parser Text @@ -65,7 +64,7 @@ lineComment = L.skipLineComment "--" $> "" blockComment :: Parser Text blockComment = L.skipBlockCommentNested "{-" "-}" $> "" -decl :: Parser PartialDecl' +decl :: (OnFold) => Parser PartialDecl' decl = choice -- declarations that begin with a keyword before those beginning with an -- arbitrary name @@ -75,12 +74,18 @@ decl = choice , tySigD ] -funD :: Parser PartialDecl' -funD = FunD <$> lexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause +funD :: (OnFold) => Parser PartialDecl' +funD = FunD <$> lexeme varid <*> params <*> (fsymbol "=" *> body) <*> whereClause where params = many pat1 body = fmap Const partialExpr +fsymbol :: (OnFold) => Text -> Parser Text +fsymbol p = scn *> ?foldGuard *> symbol p + +flexeme :: (OnFold) => Parser a -> Parser a +flexeme p = scn *> ?foldGuard *> lexeme p + whereClause :: Parser Where' whereClause = optionalList $ lexeme "where" *> pure @@ -134,8 +139,8 @@ symcon :: Parser Name symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) -pat1 :: Parser Pat' -pat1 = VarP <$> lexeme varid +pat1 :: (OnFold) => Parser Pat' +pat1 = VarP <$> flexeme varid "pattern" conid :: Parser ConId @@ -158,6 +163,7 @@ decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i + let ?foldGuard = void $ L.indentGuard scn GT i fix \ds -> (:) <$> (indentGuard *> decl) <*> (try ds <|> eof *> pure []) -- 2.52.0 From 05226373eed319d056780b6fd4ec8ee48230e998 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:33:27 -0700 Subject: [PATCH 044/192] replace uses of many+satisfy with takeWhileP --- src/RLP/Parse/Decls.hs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 480bea3..3e86529 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -132,12 +132,10 @@ infixOp :: Parser Name infixOp = symvar <|> symcon "operator" symvar :: Parser Name -symvar = T.pack <$> - liftA2 (:) (satisfy isVarSym) (many $ satisfy isSym) +symvar = T.cons <$> satisfy isVarSym <*> takeWhileP Nothing isSym symcon :: Parser Name -symcon = T.pack <$> - liftA2 (:) (char ':') (many $ satisfy isSym) +symcon = T.cons <$> char ':' <*> takeWhileP Nothing isSym pat1 :: (OnFold) => Parser Pat' pat1 = VarP <$> flexeme varid @@ -149,9 +147,7 @@ conid = NameCon <$> lexeme namecon "constructor identifier" namecon :: Parser Name -namecon = T.pack <$> - liftA2 (:) (satisfy isUpper) - (many $ satisfy isNameTail) +namecon = T.cons <$> satisfy isUpper <*> takeWhileP Nothing isNameTail varid :: Parser VarId varid = NameVar <$> try (lexeme namevar) @@ -170,8 +166,8 @@ decls = do namevar :: Parser Name namevar = word & withPredicate (`notElem` keywords) empty - where word = T.pack <$> - liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) + where + word = T.cons <$> satisfy isLower <*> takeWhileP Nothing isNameTail keywords :: (IsString a) => [a] keywords = -- 2.52.0 From 55dbc9de70528429b258b4d5e5729d5f71697944 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 14:10:46 -0700 Subject: [PATCH 045/192] layout layouts oh my layouts --- src/RLP/Parse/Decls.hs | 55 +++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 3e86529..5199b92 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -64,6 +64,31 @@ lineComment = L.skipLineComment "--" $> "" blockComment :: Parser Text blockComment = L.skipBlockCommentNested "{-" "-}" $> "" +layout :: forall a. ((OnFold) => Parser a) -> Parser [a] +layout item = scn *> (explicit <|> implicit) where + explicit :: Parser [a] + explicit = let ?foldGuard = scn -- line folds just go to the semicolon + in sym "{" *> fix \items -> choice + [ sym "}" $> [] + , (:) <$> item + <*> (sym ";" *> items <|> sym "}" $> []) + ] + where + sym = L.symbol scn + + implicit :: Parser [a] + implicit = do + i <- L.indentLevel + -- items must be aligned + let indentGuard = L.indentGuard scn EQ i + -- override foldGuard in order with new indentation + let ?foldGuard = void $ L.indentGuard scn GT i + fix \ds -> (:) <$> (indentGuard *> item) + <*> (ds <|> pure []) + +t :: (?foldGuard :: Parser ()) => Parser [Text] +t = (:) <$> lexeme "soge" <*> many (flexeme "doge") + decl :: (OnFold) => Parser PartialDecl' decl = choice -- declarations that begin with a keyword before those beginning with an @@ -80,11 +105,13 @@ funD = FunD <$> lexeme varid <*> params <*> (fsymbol "=" *> body) <*> whereClaus params = many pat1 body = fmap Const partialExpr +-- we may not need to call scn here fsymbol :: (OnFold) => Text -> Parser Text -fsymbol p = scn *> ?foldGuard *> symbol p +fsymbol p = try ?foldGuard *> symbol p +-- we may not need to call scn here flexeme :: (OnFold) => Parser a -> Parser a -flexeme p = scn *> ?foldGuard *> lexeme p +flexeme p = try ?foldGuard *> lexeme p whereClause :: Parser Where' whereClause = optionalList $ @@ -94,18 +121,19 @@ whereClause = optionalList $ standalonePartialExpr :: Parser PartialExpr' standalonePartialExpr = standaloneOf partialExpr + where ?foldGuard = undefined standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) -partialExpr :: Parser PartialExpr' +partialExpr :: (OnFold) => Parser PartialExpr' partialExpr = choice [ try application , Fix <$> infixExpr ] "expression" where - application = foldl1' mkApp <$> some partialExpr1 + application = foldl1' mkApp <$> some (flexeme partialExpr1) infixExpr = mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' mkB a f b = B f a b @@ -116,7 +144,7 @@ partialExpr = choice mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x -partialExpr1 :: Parser PartialExpr' +partialExpr1 :: (OnFold) => Parser PartialExpr' partialExpr1 = choice [ try $ lexeme "(" *> partialExpr' <* lexeme ")" , Fix <$> varid' @@ -155,13 +183,16 @@ varid = NameVar <$> try (lexeme namevar) "variable identifier" decls :: Parser [PartialDecl'] -decls = do - space - i <- L.indentLevel - let indentGuard = L.indentGuard scn EQ i - let ?foldGuard = void $ L.indentGuard scn GT i - fix \ds -> (:) <$> (indentGuard *> decl) - <*> (try ds <|> eof *> pure []) +decls = layout decl <* eof + +-- decls :: Parser [PartialDecl'] +-- decls = do +-- space +-- i <- L.indentLevel +-- let indentGuard = L.indentGuard scn EQ i +-- let ?foldGuard = void $ L.indentGuard scn GT i +-- fix \ds -> (:) <$> (indentGuard *> decl) +-- <*> (try ds <|> eof *> pure []) namevar :: Parser Name namevar = word -- 2.52.0 From 8ad967fac0207b5c6a1c14b335de14e8e7563209 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 14:33:03 -0700 Subject: [PATCH 046/192] i did not realise my fs is case insensitive --- src/{RLP => Rlp}/Parse/Decls.hs | 4 ++-- src/{RLP => Rlp}/Parse/Types.hs | 0 src/{RLP => Rlp}/Parse/Utils.hs | 0 src/{RLP => Rlp}/Syntax.hs | 0 tst/Rlp/Parse/DeclsSpec.hs | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename src/{RLP => Rlp}/Parse/Decls.hs (99%) rename src/{RLP => Rlp}/Parse/Types.hs (100%) rename src/{RLP => Rlp}/Parse/Utils.hs (100%) rename src/{RLP => Rlp}/Syntax.hs (100%) create mode 100644 tst/Rlp/Parse/DeclsSpec.hs diff --git a/src/RLP/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs similarity index 99% rename from src/RLP/Parse/Decls.hs rename to src/Rlp/Parse/Decls.hs index 5199b92..d8af6ca 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/Rlp/Parse/Decls.hs @@ -128,8 +128,8 @@ standaloneOf = (<* eof) partialExpr :: (OnFold) => Parser PartialExpr' partialExpr = choice - [ try application - , Fix <$> infixExpr + [ try $ Fix <$> infixExpr + , application ] "expression" where diff --git a/src/RLP/Parse/Types.hs b/src/Rlp/Parse/Types.hs similarity index 100% rename from src/RLP/Parse/Types.hs rename to src/Rlp/Parse/Types.hs diff --git a/src/RLP/Parse/Utils.hs b/src/Rlp/Parse/Utils.hs similarity index 100% rename from src/RLP/Parse/Utils.hs rename to src/Rlp/Parse/Utils.hs diff --git a/src/RLP/Syntax.hs b/src/Rlp/Syntax.hs similarity index 100% rename from src/RLP/Syntax.hs rename to src/Rlp/Syntax.hs diff --git a/tst/Rlp/Parse/DeclsSpec.hs b/tst/Rlp/Parse/DeclsSpec.hs new file mode 100644 index 0000000..e69de29 -- 2.52.0 From cb9ec43c14e69373e8cafffbd8f18e85ab9956b3 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 15:11:26 -0700 Subject: [PATCH 047/192] tysigs --- src/Rlp/Parse/Decls.hs | 43 +++++++++++++++++++++--------------------- src/Rlp/Parse/Types.hs | 3 +++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Rlp/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs index d8af6ca..d61c0d4 100644 --- a/src/Rlp/Parse/Decls.hs +++ b/src/Rlp/Parse/Decls.hs @@ -83,7 +83,7 @@ layout item = scn *> (explicit <|> implicit) where let indentGuard = L.indentGuard scn EQ i -- override foldGuard in order with new indentation let ?foldGuard = void $ L.indentGuard scn GT i - fix \ds -> (:) <$> (indentGuard *> item) + fix \ds -> (:) <$> (indentGuard *> item <* scn) <*> (ds <|> pure []) t :: (?foldGuard :: Parser ()) => Parser [Text] @@ -95,7 +95,7 @@ decl = choice -- arbitrary name [ infixD , dataD - , funD + , try funD , tySigD ] @@ -182,17 +182,11 @@ varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" -decls :: Parser [PartialDecl'] -decls = layout decl <* eof - --- decls :: Parser [PartialDecl'] --- decls = do --- space --- i <- L.indentLevel --- let indentGuard = L.indentGuard scn EQ i --- let ?foldGuard = void $ L.indentGuard scn GT i --- fix \ds -> (:) <$> (indentGuard *> decl) --- <*> (try ds <|> eof *> pure []) +program :: Parser [Decl' RlpExpr] +program = do + ds <- layout decl <* eof + pt <- use psOpTable + pure $ complete pt <$> ds namevar :: Parser Name namevar = word @@ -255,10 +249,10 @@ infixD = do f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD $> Just x -tySigD :: Parser (Decl' e) -tySigD = undefined -- TySigD <$> (flexeme) +tySigD :: (OnFold) => Parser (Decl' e) +tySigD = TySigD <$> (pure <$> varid) <*> (flexeme "::" *> flexeme type_) -dataD :: Parser (Decl' e) +dataD :: (OnFold) => Parser (Decl' e) dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram <*> optionalList (symbol "=" *> conalts) where @@ -271,16 +265,16 @@ dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram conalt :: Parser ConAlt conalt = ConAlt <$> conid <*> many type1 -type1 :: Parser Type +type1 :: (OnFold) => Parser Type type1 = choice [ lexeme "(" *> type_ <* lexeme ")" , TyVar <$> namevar , TyCon <$> namecon ] -type_ :: Parser Type +type_ :: (OnFold) => Parser Type type_ = choice - [ try $ (:->) <$> type1 <*> (lexeme "->" *> type_) + [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) , type1 ] @@ -293,8 +287,15 @@ lit = int -------------------------------------------------------------------------------- -- completing partial expressions -complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' -complete = cata completePartial +complete :: OpTable -> PartialDecl' -> Decl' RlpExpr +complete pt (FunD n as b w) = FunD n as b' w + where b' = let ?pt = pt in completeExpr (getConst b) +complete pt (TySigD ns t) = TySigD ns t +complete pt (DataD n as cs) = DataD n as cs +complete pt (InfixD a p n) = InfixD a p n + +completeExpr :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' +completeExpr = cata completePartial completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' completePartial (E e) = completeRlpExpr e diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index e961d2d..41e67f8 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -42,6 +42,9 @@ import Rlp.Syntax -- parser types +-- TODO: the State is only used for building an operator table from infix[lr] +-- declarations. we should switch to a normal Parsec monad in the future + type Parser = ParsecT RlpParseError Text (State ParserState) data ParserState = ParserState -- 2.52.0 From 245b12a96e7f120b9e8afa663daaf5f5f9f9eb39 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 07:43:59 -0700 Subject: [PATCH 048/192] add version bounds --- rlp.cabal | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 660a3d8..74aad24 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -43,24 +43,22 @@ library -- other-extensions: build-depends: base ^>=4.18.0.0 - , containers - , microlens - , microlens-mtl - , microlens-th - , microlens-platform - , mtl - , template-haskell -- required for happy - , array - , data-default-class - , unordered-containers - , hashable - , pretty - -- TODO: either learn recursion-schemes, or stop depending - -- on it. - , recursion-schemes - , megaparsec - , text + , array >= 0.5.5 && < 0.6 + , containers >= 0.6.7 && < 0.7 + , template-haskell >= 2.20.0 && < 2.21 + , pretty >= 1.1.3 && < 1.2 + , data-default-class >= 0.1.2 && < 0.2 + , hashable >= 1.4.3 && < 1.5 + , mtl >= 2.3.1 && < 2.4 + , text >= 2.0.2 && < 2.1 + , megaparsec >= 9.6.1 && < 9.7 + , microlens >= 0.4.13 && < 0.5 + , microlens-mtl >= 0.2.0 && < 0.3 + , microlens-platform >= 0.4.3 && < 0.5 + , microlens-th >= 0.4.3 && < 0.5 + , unordered-containers >= 0.2.20 && < 0.3 + , recursion-schemes >= 5.2.2 && < 5.3 hs-source-dirs: src default-language: GHC2021 @@ -72,12 +70,12 @@ executable rlpc -- other-extensions: build-depends: base ^>=4.18.0.0 , rlp - , optparse-applicative - , microlens - , microlens-mtl - , mtl - , unordered-containers - , text + , optparse-applicative >= 0.18.1 && < 0.19 + , microlens >= 0.4.13 && < 0.5 + , microlens-mtl >= 0.2.0 && < 0.3 + , mtl >= 2.3.1 && < 2.4 + , unordered-containers >= 0.2.20 && < 0.3 + , text >= 2.0.2 && < 2.1 hs-source-dirs: app default-language: GHC2021 -- 2.52.0 From bb6aca094c1ff7f6922d7d6ba44c5cd3701e3f90 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 02:33:31 -0700 Subject: [PATCH 049/192] grammar reference --- doc/src/conf.py | 1 + doc/src/references/rlp-grammar.rst | 67 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 doc/src/references/rlp-grammar.rst diff --git a/doc/src/conf.py b/doc/src/conf.py index d344334..533296a 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -32,6 +32,7 @@ html_theme = 'alabaster' imgmath_latex_preamble = r''' \usepackage{amsmath} \usepackage{tabularray} +\usepackage{syntax} \newcommand{\transrule}[2] {\begin{tblr}{|rrrlc|} diff --git a/doc/src/references/rlp-grammar.rst b/doc/src/references/rlp-grammar.rst new file mode 100644 index 0000000..c81fea7 --- /dev/null +++ b/doc/src/references/rlp-grammar.rst @@ -0,0 +1,67 @@ +The Complete Syntax of rl' +========================== + +WIP. + +Provided is the complete syntax of rl' in (pseudo) EBNF. {A} represents zero or +more A's, [A] means optional A, and terminals are wrapped in 'single-quotes'. + +.. math + :nowrap: + + \setlength{\grammarparsep}{20pt plus 1pt minus 1pt} + \setlength{\grammarindent}{12em} + \begin{grammar} + ::= + \alt + \alt + \alt + + ::= `litint' + ::= `infix' + \alt `infixl' + \alt `infixr' + + ::= `data' `conname' {} + + \end{grammar} + +.. code-block:: bnf + + Decl ::= InfixDecl + | DataDecl + | TypeSig + | FunDef + + InfixDecl ::= InfixWord 'litint' Operator + InfixWord ::= 'infix' + | 'infixl' + | 'infixr' + + DataDecl ::= 'data' 'conname' {'name'} '=' Data + DataCons ::= 'conname' {Type1} ['|' DataCons] + + TypeSig ::= Var '::' Type + FunDef ::= Var {Pat1} '=' Expr + + Type ::= Type1 {Type1} + -- note that (->) is right-associative, + -- and extends as far as possible + | Type '->' Type + Type1 ::= '(' Type ')' + | 'conname' + + Pat ::= 'conname' Pat1 {Pat1} + | Pat 'consym' Pat + + Pat1 ::= Literal + | 'conname' + | '(' Pat ')' + + Literal ::= 'litint' + + Var ::= 'varname' + | '(' 'varsym' ')' + Con ::= 'conname' + | '(' 'consym' ')' + -- 2.52.0 From c15f9b65469e97e97dc58ed29dc066b94f599dbe Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 05:34:11 -0700 Subject: [PATCH 050/192] 4:00 AM psychopath code --- rlp.cabal | 3 +- src/RLP/ParseDecls.hs | 139 ++++++++++++++++++++++++++++++++++++++++++ src/RLP/Syntax.hs | 65 +++++++++++++++++--- 3 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 src/RLP/ParseDecls.hs diff --git a/rlp.cabal b/rlp.cabal index 74aad24..9e2e7b8 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -30,6 +30,8 @@ library , Core.TH , Core.HindleyMilner , Control.Monad.Errorful + , Rlp.Syntax + , Rlp.ParseDecls other-modules: Data.Heap , Data.Pretty @@ -37,7 +39,6 @@ library , Core.Lex , Core2Core , Control.Monad.Utils - , RLP.Syntax build-tool-depends: happy:happy, alex:alex diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs new file mode 100644 index 0000000..4d18e22 --- /dev/null +++ b/src/RLP/ParseDecls.hs @@ -0,0 +1,139 @@ +-- Show Y +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE OverloadedStrings #-} +module Rlp.ParseDecls + ( + ) + where +---------------------------------------------------------------------------------- +import Rlp.Syntax +import Text.Megaparsec hiding (State) +import Text.Megaparsec.Char +import Text.Megaparsec.Char.Lexer qualified as L +import Data.Functor.Const +import Data.Text (Text) +import Data.Text qualified as T +import Data.Void +import Data.Char +import Data.Functor +import Data.HashMap.Strict qualified as H +import Control.Monad +import Core.Syntax +import Control.Monad.State +---------------------------------------------------------------------------------- + +type Parser = ParsecT Void Text (State ParserState) + +data ParserState = ParserState + { _psPrecTable :: PrecTable + } + deriving Show + +type PrecTable = H.HashMap Name (Assoc, Int) + +---------------------------------------------------------------------------------- + +parseTest' :: (Show a) => Parser a -> Text -> IO () +parseTest' p s = case runState (runParserT p "test" s) init of + (Left e, _) -> putStr (errorBundlePretty e) + (Right x, st) -> print st *> print x + where + init = ParserState mempty + +lexeme :: Parser a -> Parser a +lexeme = L.lexeme sc + +symbol :: Text -> Parser Text +symbol = L.symbol sc + +sc :: Parser () +sc = L.space space1 (void lineComment) (void blockComment) + +-- TODO: return comment text +-- TODO: '---' should not start a comment +lineComment :: Parser Text +lineComment = L.skipLineComment "--" $> "" + +-- TODO: return comment text +blockComment :: Parser Text +blockComment = L.skipBlockCommentNested "{-" "-}" $> "" + +decl :: Parser PartialDecl' +decl = choice + [ funD + , tySigD + , dataD + , infixD + ] + +funD :: Parser PartialDecl' +funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) + +partialExpr :: Parser PartialExpr' +partialExpr = choice + [ fmap Y $ U <$> varid' <*> lexeme infixOp <*> varid' + ] + where varid' = E . VarEF <$> varid + + +infixOp :: Parser Name +infixOp = symvar <|> symcon + +symvar :: Parser Name +symvar = T.pack <$> + liftA2 (:) (satisfy isVarSym) (many $ satisfy isSym) + +symcon :: Parser Name +symcon = T.pack <$> + liftA2 (:) (char ':') (many $ satisfy isSym) + +-- partialExpr :: Parser (Const Text a) +-- partialExpr = fmap Const $ L.lineFold w $ \w' -> +-- try w' <> w +-- where +-- w = L.space eat (void lineComment) (void blockComment) +-- eat = void . some $ satisfy (not . isSpace) + +pat1 :: Parser Pat' +pat1 = VarP <$> varid + +varid :: Parser VarId +varid = NameVar <$> lexeme namevar + <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') + "variable identifier" + where + namevar = T.pack <$> + liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) + + isNameTail c = isAlphaNum c + || c == '\'' + || c == '_' + +isVarSym :: Char -> Bool +isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") + +isSym :: Char -> Bool +isSym c = c == ':' || isVarSym c + +infixD = undefined + +tySigD = undefined +dataD = undefined + +---------------------------------------------------------------------------------- + +-- absolute psycho shit + +type PartialDecl' = Decl (Const PartialExpr') Name + +newtype Y f = Y (f (Y f)) + +instance (Show (f (Y f))) => Show (Y f) where + showsPrec p (Y f) = showsPrec p f + +data Partial a = E (RlpExprF Name a) + | U (Partial a) Name (Partial a) + deriving Show + +type PartialExpr' = Y Partial + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 6efdc4e..9e5c53b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -1,23 +1,52 @@ +-- recursion-schemes +{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} +-- recursion-schemes +{-# LANGUAGE TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} -module RLP.Syntax - ( RlpExpr +module Rlp.Syntax + ( RlpExpr(..) + , RlpExprF(..) + , RlpExprF' + , Decl(..) + , Assoc(..) + , VarId(..) + , Pat(..) + , Pat' ) where ---------------------------------------------------------------------------------- +import Data.Functor.Const import Data.Text (Text) +import Data.Text qualified as T +import Data.String (IsString(..)) +import Data.Functor.Foldable.TH (makeBaseFunctor) import Lens.Micro +import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- -newtype RlpProgram b = RlpProgram [Decl b] +newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -data Decl b = InfixD InfixAssoc Int VarId - | FunD VarId [Pat b] (RlpExpr b) - | DataD ConId [ConId] [ConAlt] +-- | The @e@ parameter is used for partial results. When parsing an input, we +-- first parse all top-level declarations in order to extract infix[lr] +-- declarations. This process yields a @[Decl (Const Text) Name]@, where @Const +-- Text@ stores the remaining unparsed function bodies. Once infixities are +-- accounted for, we may complete the parsing task and get a proper @[Decl +-- RlpExpr Name]@. + +data Decl e b = FunD VarId [Pat b] (e b) + | TySigD [VarId] Type + | DataD ConId [ConId] [ConAlt] + | InfixD Assoc Int Name + deriving Show + +data Assoc = InfixL + | InfixR + | Infix + deriving Show data ConAlt = ConAlt ConId [ConId] - -data InfixAssoc = Assoc | AssocL | AssocR + deriving Show data RlpExpr b = LetE [Bind b] (RlpExpr b) | VarE VarId @@ -27,26 +56,39 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) | IfE (RlpExpr b) (RlpExpr b) (RlpExpr b) | AppE (RlpExpr b) (RlpExpr b) | LitE (Lit b) + deriving Show -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) + deriving Show data Bind b = PatB (Pat b) (RlpExpr b) | FunB VarId [Pat b] (RlpExpr b) + deriving Show data VarId = NameVar Text | SymVar Text + deriving Show + +instance IsString VarId where + -- TODO: use symvar if it's an operator + fromString = NameVar . T.pack data ConId = NameCon Text | SymCon Text + deriving Show data Pat b = VarP VarId | LitP (Lit b) | ConP ConId [Pat b] + deriving Show + +type Pat' = Pat Name data Lit b = IntL Int | CharL Char | ListL [RlpExpr b] + deriving Show -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens @@ -57,3 +99,10 @@ data Lit b = IntL Int -- _rhs = lens -- (\ (AltA _ e) -> e) -- (\ (AltA p _) e' -> AltA p e') + +makeBaseFunctor ''RlpExpr + +deriving instance (Show b, Show a) => Show (RlpExprF b a) + +type RlpExprF' = RlpExprF Name + -- 2.52.0 From 6130a916682c23a4199ab53f91aca820408dc95a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 06:26:48 -0700 Subject: [PATCH 051/192] oh boy am i going to hate this code in 12 hours --- src/RLP/ParseDecls.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 4d18e22..376ef37 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -71,7 +71,8 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ fmap Y $ U <$> varid' <*> lexeme infixOp <*> varid' + [ try $ fmap Y $ U <$> varid' <*> lexeme infixOp <*> fmap unY partialExpr + , fmap Y $ varid' ] where varid' = E . VarEF <$> varid @@ -128,6 +129,9 @@ type PartialDecl' = Decl (Const PartialExpr') Name newtype Y f = Y (f (Y f)) +unY :: Y f -> f (Y f) +unY (Y f) = f + instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f -- 2.52.0 From 0f04e2decf98c6d0b37933eefd7b53247cd338af Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 07:03:45 -0700 Subject: [PATCH 052/192] application and lits appl --- src/RLP/ParseDecls.hs | 37 ++++++++++++++++++++++++++----------- src/RLP/Syntax.hs | 5 +++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 376ef37..1789c83 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -13,12 +13,12 @@ import Text.Megaparsec.Char.Lexer qualified as L import Data.Functor.Const import Data.Text (Text) import Data.Text qualified as T +import Data.List (foldl1') import Data.Void import Data.Char import Data.Functor import Data.HashMap.Strict qualified as H import Control.Monad -import Core.Syntax import Control.Monad.State ---------------------------------------------------------------------------------- @@ -71,11 +71,25 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Y $ U <$> varid' <*> lexeme infixOp <*> fmap unY partialExpr - , fmap Y $ varid' + [ try $ fmap Y $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + , foldl1' papp <$> some partialExpr1 ] - where varid' = E . VarEF <$> varid + where + partialExpr1' = unY <$> partialExpr1 + partialExpr' = unY <$> partialExpr + papp :: PartialExpr' -> PartialExpr' -> PartialExpr' + papp f x = Y . E $ f `AppEF` x + +partialExpr1 :: Parser PartialExpr' +partialExpr1 = choice + [ try $ char '(' *> partialExpr <* char ')' + , fmap Y $ varid' + , fmap Y $ lit' + ] + where + varid' = E . VarEF <$> varid + lit' = E . LitEF <$> lit infixOp :: Parser Name infixOp = symvar <|> symcon @@ -88,13 +102,6 @@ symcon :: Parser Name symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) --- partialExpr :: Parser (Const Text a) --- partialExpr = fmap Const $ L.lineFold w $ \w' -> --- try w' <> w --- where --- w = L.space eat (void lineComment) (void blockComment) --- eat = void . some $ satisfy (not . isSpace) - pat1 :: Parser Pat' pat1 = VarP <$> varid @@ -121,6 +128,11 @@ infixD = undefined tySigD = undefined dataD = undefined +lit :: Parser Lit' +lit = int + where + int = IntL <$> L.decimal + ---------------------------------------------------------------------------------- -- absolute psycho shit @@ -132,6 +144,9 @@ newtype Y f = Y (f (Y f)) unY :: Y f -> f (Y f) unY (Y f) = f +ymap :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g +ymap m (Y f) = Y $ m (ymap m <$> f) + instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 9e5c53b..8a93059 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -12,6 +12,9 @@ module Rlp.Syntax , VarId(..) , Pat(..) , Pat' + , Lit(..) + , Lit' + , Name ) where ---------------------------------------------------------------------------------- @@ -90,6 +93,8 @@ data Lit b = IntL Int | ListL [RlpExpr b] deriving Show +type Lit' = Lit Name + -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens -- (\ (AltA p _) -> p) -- 2.52.0 From c5c06fa6cb3d9b1919e0013feb7bb5cb2ff2f5f4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 08:04:49 -0700 Subject: [PATCH 053/192] something --- src/RLP/ParseDecls.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 1789c83..9472063 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -47,7 +47,7 @@ symbol :: Text -> Parser Text symbol = L.symbol sc sc :: Parser () -sc = L.space space1 (void lineComment) (void blockComment) +sc = L.space hspace1 (void lineComment) (void blockComment) -- TODO: return comment text -- TODO: '---' should not start a comment @@ -156,3 +156,7 @@ data Partial a = E (RlpExprF Name a) type PartialExpr' = Y Partial +---------------------------------------------------------------------------------- + + + -- 2.52.0 From cbe4276061c042b1773300661ee82108c99ed9fc Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 2 Jan 2024 08:43:34 -0700 Subject: [PATCH 054/192] goofy --- src/RLP/ParseDecls.hs | 14 +++++++++----- src/RLP/Syntax.hs | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 9472063..83db884 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -1,5 +1,6 @@ -- Show Y {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.ParseDecls ( @@ -17,6 +18,7 @@ import Data.List (foldl1') import Data.Void import Data.Char import Data.Functor +import Data.Functor.Foldable import Data.HashMap.Strict qualified as H import Control.Monad import Control.Monad.State @@ -83,7 +85,7 @@ partialExpr = choice partialExpr1 :: Parser PartialExpr' partialExpr1 = choice - [ try $ char '(' *> partialExpr <* char ')' + [ try $ char '(' *> (hoistY P <$> partialExpr) <* char ')' , fmap Y $ varid' , fmap Y $ lit' ] @@ -144,19 +146,21 @@ newtype Y f = Y (f (Y f)) unY :: Y f -> f (Y f) unY (Y f) = f -ymap :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g -ymap m (Y f) = Y $ m (ymap m <$> f) +hoistY :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g +hoistY m (Y f) = Y $ m (hoistY m <$> f) instance (Show (f (Y f))) => Show (Y f) where showsPrec p (Y f) = showsPrec p f data Partial a = E (RlpExprF Name a) | U (Partial a) Name (Partial a) - deriving Show + | P (Partial a) + deriving (Show, Functor) type PartialExpr' = Y Partial ---------------------------------------------------------------------------------- - +mkOp :: RlpExpr b -> RlpExpr b -> RlpExpr b -> RlpExpr b +mkOp f a b = (f `AppE` a) `AppE` b diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 8a93059..eaf6b12 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -5,6 +5,7 @@ {-# LANGUAGE OverloadedStrings #-} module Rlp.Syntax ( RlpExpr(..) + , RlpExpr' , RlpExprF(..) , RlpExprF' , Decl(..) @@ -61,6 +62,8 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) | LitE (Lit b) deriving Show +type RlpExpr' = RlpExpr Name + -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) deriving Show -- 2.52.0 From 4ee9785239929538aa7093bf991157e10eea9745 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 3 Jan 2024 10:04:42 -0700 Subject: [PATCH 055/192] Show1 instances --- src/RLP/ParseDecls.hs | 45 ++++++++++++++++++++++++------------------- src/RLP/Syntax.hs | 30 ++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/RLP/ParseDecls.hs b/src/RLP/ParseDecls.hs index 83db884..7a36248 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/ParseDecls.hs @@ -1,7 +1,8 @@ --- Show Y +-- Show Fix {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} module Rlp.ParseDecls ( ) @@ -12,6 +13,7 @@ import Text.Megaparsec hiding (State) import Text.Megaparsec.Char import Text.Megaparsec.Char.Lexer qualified as L import Data.Functor.Const +import Data.Functor.Classes import Data.Text (Text) import Data.Text qualified as T import Data.List (foldl1') @@ -19,6 +21,7 @@ import Data.Void import Data.Char import Data.Functor import Data.Functor.Foldable +import Data.Fix import Data.HashMap.Strict qualified as H import Control.Monad import Control.Monad.State @@ -73,21 +76,21 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Y $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + [ try $ fmap Fix $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] where - partialExpr1' = unY <$> partialExpr1 - partialExpr' = unY <$> partialExpr + partialExpr1' = unFix <$> partialExpr1 + partialExpr' = unFix <$> partialExpr papp :: PartialExpr' -> PartialExpr' -> PartialExpr' - papp f x = Y . E $ f `AppEF` x + papp f x = Fix . E $ f `AppEF` x partialExpr1 :: Parser PartialExpr' partialExpr1 = choice - [ try $ char '(' *> (hoistY P <$> partialExpr) <* char ')' - , fmap Y $ varid' - , fmap Y $ lit' + [ try $ char '(' *> (hoistFix P <$> partialExpr) <* char ')' + , fmap Fix $ varid' + , fmap Fix $ lit' ] where varid' = E . VarEF <$> varid @@ -141,23 +144,25 @@ lit = int type PartialDecl' = Decl (Const PartialExpr') Name -newtype Y f = Y (f (Y f)) - -unY :: Y f -> f (Y f) -unY (Y f) = f - -hoistY :: (Functor f) => (forall a. f a -> g a) -> Y f -> Y g -hoistY m (Y f) = Y $ m (hoistY m <$> f) - -instance (Show (f (Y f))) => Show (Y f) where - showsPrec p (Y f) = showsPrec p f - data Partial a = E (RlpExprF Name a) | U (Partial a) Name (Partial a) | P (Partial a) deriving (Show, Functor) -type PartialExpr' = Y Partial +instance Show1 Partial where + liftShowsPrec :: forall a. (Int -> a -> ShowS) + -> ([a] -> ShowS) + -> Int -> Partial a -> ShowS + + liftShowsPrec sp sl p m = case m of + (E e) -> showsUnaryWith lshow "E" p e + (U a f b) -> showsTernaryWith lshow showsPrec lshow "U" p a f b + (P e) -> showsUnaryWith lshow "P" p e + where + lshow :: forall f. (Show1 f) => Int -> f a -> ShowS + lshow = liftShowsPrec sp sl + +type PartialExpr' = Fix Partial ---------------------------------------------------------------------------------- diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index eaf6b12..4a47b7a 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -16,6 +16,9 @@ module Rlp.Syntax , Lit(..) , Lit' , Name + + -- TODO: ugh move this somewhere else later + , showsTernaryWith ) where ---------------------------------------------------------------------------------- @@ -24,11 +27,12 @@ import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) +import Data.Functor.Classes import Lens.Micro import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- - + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we @@ -114,3 +118,27 @@ deriving instance (Show b, Show a) => Show (RlpExprF b a) type RlpExprF' = RlpExprF Name +-- society if derivable Show1 +instance (Show b) => Show1 (RlpExprF b) where + liftShowsPrec sp _ p m = case m of + (LetEF bs e) -> showsBinaryWith showsPrec sp "LetEF" p bs e + (VarEF n) -> showsUnaryWith showsPrec "VarEF" p n + (ConEF n) -> showsUnaryWith showsPrec "ConEF" p n + (LamEF bs e) -> showsBinaryWith showsPrec sp "LamEF" p bs e + (CaseEF e as) -> showsBinaryWith sp showsPrec "CaseEF" p e as + (IfEF a b c) -> showsTernaryWith sp sp sp "IfEF" p a b c + (AppEF f x) -> showsBinaryWith sp sp "AppEF" p f x + (LitEF l) -> showsUnaryWith showsPrec "LitEF" p l + +showsTernaryWith :: (Int -> x -> ShowS) + -> (Int -> y -> ShowS) + -> (Int -> z -> ShowS) + -> String -> Int + -> x -> y -> z + -> ShowS +showsTernaryWith sa sb sc name p a b c = showParen (p > 10) + $ showString name + . showChar ' ' . sa 11 a + . showChar ' ' . sb 11 b + . showChar ' ' . sc 11 c + -- 2.52.0 From 2a159232c75ece11c8e7ad240ee21aef87c899af Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 13:39:12 -0700 Subject: [PATCH 056/192] fixation fufilled - back to work! --- rlp.cabal | 3 +- src/RLP/{ParseDecls.hs => Parse/Decls.hs} | 88 +++++++++++------------ src/RLP/Parse/Types.hs | 65 +++++++++++++++++ src/RLP/Syntax.hs | 6 +- 4 files changed, 115 insertions(+), 47 deletions(-) rename src/RLP/{ParseDecls.hs => Parse/Decls.hs} (69%) create mode 100644 src/RLP/Parse/Types.hs diff --git a/rlp.cabal b/rlp.cabal index 9e2e7b8..dbdb12c 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -31,7 +31,8 @@ library , Core.HindleyMilner , Control.Monad.Errorful , Rlp.Syntax - , Rlp.ParseDecls + , Rlp.Parse.Decls + , Rlp.Parse.Types other-modules: Data.Heap , Data.Pretty diff --git a/src/RLP/ParseDecls.hs b/src/RLP/Parse/Decls.hs similarity index 69% rename from src/RLP/ParseDecls.hs rename to src/RLP/Parse/Decls.hs index 7a36248..18e85aa 100644 --- a/src/RLP/ParseDecls.hs +++ b/src/RLP/Parse/Decls.hs @@ -1,41 +1,30 @@ --- Show Fix -{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ImplicitParams #-} +{-# LANGUAGE LambdaCase, BlockArguments #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -module Rlp.ParseDecls +module Rlp.Parse.Decls ( ) where ---------------------------------------------------------------------------------- -import Rlp.Syntax +import Control.Monad +import Control.Monad.State import Text.Megaparsec hiding (State) import Text.Megaparsec.Char import Text.Megaparsec.Char.Lexer qualified as L -import Data.Functor.Const import Data.Functor.Classes +import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T import Data.List (foldl1') -import Data.Void import Data.Char import Data.Functor -import Data.Functor.Foldable -import Data.Fix -import Data.HashMap.Strict qualified as H -import Control.Monad -import Control.Monad.State ----------------------------------------------------------------------------------- - -type Parser = ParsecT Void Text (State ParserState) - -data ParserState = ParserState - { _psPrecTable :: PrecTable - } - deriving Show - -type PrecTable = H.HashMap Name (Assoc, Int) - +import Data.Functor.Const +import Data.Fix hiding (cata) +import Lens.Micro +import Rlp.Parse.Types +import Rlp.Syntax ---------------------------------------------------------------------------------- parseTest' :: (Show a) => Parser a -> Text -> IO () @@ -76,10 +65,11 @@ funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) partialExpr :: Parser PartialExpr' partialExpr = choice - [ try $ fmap Fix $ U <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' + [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] where + mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr @@ -140,32 +130,42 @@ lit = int ---------------------------------------------------------------------------------- --- absolute psycho shit +type PartialE = Partial RlpExpr' -type PartialDecl' = Decl (Const PartialExpr') Name +-- complete :: OpTable -> Fix Partial -> RlpExpr' +complete :: OpTable -> PartialExpr' -> RlpExpr' +complete pt = let ?pt = pt in cata completePartial -data Partial a = E (RlpExprF Name a) - | U (Partial a) Name (Partial a) - | P (Partial a) - deriving (Show, Functor) +completePartial :: PartialE -> RlpExpr' +completePartial (E e) = completeRlpExpr e +completePartial p@(B o l r) = completeB (build p) +completePartial (P e) = completePartial e -instance Show1 Partial where - liftShowsPrec :: forall a. (Int -> a -> ShowS) - -> ([a] -> ShowS) - -> Int -> Partial a -> ShowS +completeRlpExpr :: RlpExprF' RlpExpr' -> RlpExpr' +completeRlpExpr = embed - liftShowsPrec sp sl p m = case m of - (E e) -> showsUnaryWith lshow "E" p e - (U a f b) -> showsTernaryWith lshow showsPrec lshow "U" p a f b - (P e) -> showsUnaryWith lshow "P" p e - where - lshow :: forall f. (Show1 f) => Int -> f a -> ShowS - lshow = liftShowsPrec sp sl +completeB :: PartialE -> RlpExpr' +completeB = build -type PartialExpr' = Fix Partial +build :: PartialE -> PartialE +build e = go id e (rightmost e) where + rightmost :: Partial -> Partial + rightmost (B _ _ _) = rightmost r + rightmost (E n) = undefined ----------------------------------------------------------------------------------- + go :: (?pt :: OpTable) + => (PartialE -> PartialE) + -> PartialE -> PartialE -> PartialE + go f p@(WithPrec o _ r) = case r of + E _ -> mkHole o (f . f') + P _ -> undefined + B _ _ _ -> go (mkHole o (f . f')) r + where f' r' = p & pR .~ r' -mkOp :: RlpExpr b -> RlpExpr b -> RlpExpr b -> RlpExpr b -mkOp f a b = (f `AppE` a) `AppE` b +mkHole :: (?pt :: OpTable) + => OpInfo + -> (PartialE -> PartialE) + -> PartialE + -> PartialE +mkHole = undefined diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs new file mode 100644 index 0000000..cb1d6bf --- /dev/null +++ b/src/RLP/Parse/Types.hs @@ -0,0 +1,65 @@ +module Rlp.Parse.Types + ( + -- * Partial ASTs + Partial(..) + , PartialExpr' + , PartialDecl' + + -- * Parser types + , Parser + , ParserState(..) + , OpTable + , OpInfo + ) + where +---------------------------------------------------------------------------------- +import Control.Monad.State +import Data.HashMap.Strict qualified as H +import Data.Fix +import Data.Functor.Foldable +import Data.Functor.Const +import Data.Functor.Classes +import Data.Void +import Text.Megaparsec hiding (State) +import Rlp.Syntax +---------------------------------------------------------------------------------- + +-- parser types + +type Parser = ParsecT Void Text (State ParserState) + +data ParserState = ParserState + { _psOpTable :: OpTable + } + deriving Show + +type OpTable = H.HashMap Name OpInfo +type OpInfo = (Assoc, Int) + +---------------------------------------------------------------------------------- + +-- absolute psycho shit (partial ASTs) + +type PartialDecl' = Decl (Const PartialExpr') Name + +data Partial a = E (RlpExprF Name a) + | B Name (Partial a) (Partial a) + | P (Partial a) + deriving (Show, Functor) + +-- required to satisfy constraint on Fix's show instance +instance Show1 Partial where + liftShowsPrec :: forall a. (Int -> a -> ShowS) + -> ([a] -> ShowS) + -> Int -> Partial a -> ShowS + + liftShowsPrec sp sl p m = case m of + (E e) -> showsUnaryWith lshow "E" p e + (B f a b) -> showsTernaryWith showsPrec lshow lshow "B" p f a b + (P e) -> showsUnaryWith lshow "P" p e + where + lshow :: forall f. (Show1 f) => Int -> f a -> ShowS + lshow = liftShowsPrec sp sl + +type PartialExpr' = Fix Partial + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 4a47b7a..b314d7b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -19,10 +19,12 @@ module Rlp.Syntax -- TODO: ugh move this somewhere else later , showsTernaryWith + + -- * Convenience re-exports + , Text ) where ---------------------------------------------------------------------------------- -import Data.Functor.Const import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) @@ -32,7 +34,7 @@ import Lens.Micro import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- - + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we -- 2.52.0 From 936f24148f1268eb21a5c9190272679e82b4ac75 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 18:56:14 -0700 Subject: [PATCH 057/192] works --- src/RLP/Parse/Decls.hs | 70 +++++++++++++++++++++++++++++++++--------- src/RLP/Parse/Types.hs | 27 ++++++++++++++++ 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 18e85aa..965a4c5 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -17,6 +17,7 @@ import Data.Functor.Classes import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T +import Data.HashMap.Strict qualified as H import Data.List (foldl1') import Data.Char import Data.Functor @@ -130,42 +131,81 @@ lit = int ---------------------------------------------------------------------------------- -type PartialE = Partial RlpExpr' - -- complete :: OpTable -> Fix Partial -> RlpExpr' -complete :: OpTable -> PartialExpr' -> RlpExpr' -complete pt = let ?pt = pt in cata completePartial +complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' +complete = cata completePartial -completePartial :: PartialE -> RlpExpr' +completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' completePartial (E e) = completeRlpExpr e completePartial p@(B o l r) = completeB (build p) completePartial (P e) = completePartial e -completeRlpExpr :: RlpExprF' RlpExpr' -> RlpExpr' +completeRlpExpr :: (?pt :: OpTable) => RlpExprF' RlpExpr' -> RlpExpr' completeRlpExpr = embed -completeB :: PartialE -> RlpExpr' -completeB = build +completeB :: (?pt :: OpTable) => PartialE -> RlpExpr' +completeB p = case build p of + B o l r -> (o' `AppE` l') `AppE` r' + where + -- TODO: how do we know it's symbolic? + o' = VarE (SymVar o) + l' = completeB l + r' = completeB r + P e -> completeB e + E e -> completeRlpExpr e -build :: PartialE -> PartialE +build :: (?pt :: OpTable) => PartialE -> PartialE build e = go id e (rightmost e) where - rightmost :: Partial -> Partial - rightmost (B _ _ _) = rightmost r - rightmost (E n) = undefined + rightmost :: PartialE -> PartialE + rightmost (B _ _ r) = rightmost r + rightmost p@(E _) = p + rightmost p@(P _) = p go :: (?pt :: OpTable) => (PartialE -> PartialE) -> PartialE -> PartialE -> PartialE - go f p@(WithPrec o _ r) = case r of + go f p@(WithInfo o _ r) = case r of E _ -> mkHole o (f . f') - P _ -> undefined + P _ -> mkHole o (f . f') B _ _ _ -> go (mkHole o (f . f')) r where f' r' = p & pR .~ r' + go f _ = id mkHole :: (?pt :: OpTable) => OpInfo -> (PartialE -> PartialE) -> PartialE -> PartialE -mkHole = undefined +mkHole _ hole p@(P _) = hole p +mkHole _ hole p@(E _) = hole p +mkHole (a,d) hole p@(WithInfo (a',d') _ _) + | d' < d = above + | d' > d = below + | d == d' = case (a,a') of + -- left-associative operators of equal precedence are + -- associated left + (InfixL,InfixL) -> above + -- right-associative operators are handled similarly + (InfixR,InfixR) -> below + -- non-associative operators of equal precedence, or equal + -- precedence operators of different associativities are + -- invalid + (_, _) -> error "invalid expression" + where + above = p & pL %~ hole + below = hole p + +examplePrecTable :: OpTable +examplePrecTable = H.fromList + [ ("+", (InfixL,6)) + , ("*", (InfixL,7)) + , ("^", (InfixR,8)) + , (".", (InfixR,7)) + , ("~", (Infix, 9)) + , ("=", (Infix, 4)) + , ("&&", (Infix, 3)) + , ("||", (Infix, 2)) + , ("$", (InfixR,0)) + , ("&", (InfixL,0)) + ] diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index cb1d6bf..d3e7bd1 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -1,9 +1,17 @@ +{-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} +{- +Description : Supporting types for the parser +-} module Rlp.Parse.Types ( -- * Partial ASTs Partial(..) + , PartialE , PartialExpr' , PartialDecl' + , pattern WithInfo + , pR + , pL -- * Parser types , Parser @@ -20,7 +28,9 @@ import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes import Data.Void +import Data.Maybe import Text.Megaparsec hiding (State) +import Lens.Micro import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -47,6 +57,23 @@ data Partial a = E (RlpExprF Name a) | P (Partial a) deriving (Show, Functor) +pL :: Traversal' (Partial a) (Partial a) +pL k (B o l r) = (\l' -> B o l' r) <$> k l +pL _ x = pure x + +pR :: Traversal' (Partial a) (Partial a) +pR k (B o l r) = (\r' -> B o l r') <$> k r +pR _ x = pure x + +type PartialE = Partial RlpExpr' + +-- i love you haskell +pattern WithInfo :: (?pt :: OpTable) => OpInfo -> PartialE -> PartialE -> PartialE +pattern WithInfo p l r <- B (opInfoOrDef -> p) l r + +opInfoOrDef :: (?pt :: OpTable) => Name -> OpInfo +opInfoOrDef c = fromMaybe (InfixL,9) $ H.lookup c ?pt + -- required to satisfy constraint on Fix's show instance instance Show1 Partial where liftShowsPrec :: forall a. (Int -> a -> ShowS) -- 2.52.0 From 97ce9b48ae82a817116c2e3f85c36412a54be670 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 8 Jan 2024 20:14:18 -0700 Subject: [PATCH 058/192] labels --- src/RLP/Parse/Decls.hs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 965a4c5..c8a0a33 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -64,11 +64,18 @@ decl = choice funD :: Parser PartialDecl' funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) +standalonePartialExpr :: Parser PartialExpr' +standalonePartialExpr = standaloneOf partialExpr + +standaloneOf :: Parser a -> Parser a +standaloneOf = (<* eof) + partialExpr :: Parser PartialExpr' partialExpr = choice [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' , foldl1' papp <$> some partialExpr1 ] + "expression" where mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 @@ -83,12 +90,13 @@ partialExpr1 = choice , fmap Fix $ varid' , fmap Fix $ lit' ] + "expression" where varid' = E . VarEF <$> varid lit' = E . LitEF <$> lit infixOp :: Parser Name -infixOp = symvar <|> symcon +infixOp = symvar <|> symcon "infix operator" symvar :: Parser Name symvar = T.pack <$> @@ -100,6 +108,7 @@ symcon = T.pack <$> pat1 :: Parser Pat' pat1 = VarP <$> varid + "pattern" varid :: Parser VarId varid = NameVar <$> lexeme namevar @@ -126,6 +135,7 @@ dataD = undefined lit :: Parser Lit' lit = int + "literal" where int = IntL <$> L.decimal -- 2.52.0 From 84c11229959d4593d0585ec62933ebb29e9a56c4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 11:39:26 -0700 Subject: [PATCH 059/192] infix decl --- rlp.cabal | 26 +++++++++++--------------- src/RLP/Parse/Decls.hs | 36 +++++++++++++++++++++++++++++++++++- src/RLP/Parse/Types.hs | 36 +++++++++++++++++++++++++++++++++++- src/RLP/Syntax.hs | 3 +++ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index dbdb12c..dc83431 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -46,21 +46,17 @@ library -- other-extensions: build-depends: base ^>=4.18.0.0 -- required for happy - , array >= 0.5.5 && < 0.6 - , containers >= 0.6.7 && < 0.7 - , template-haskell >= 2.20.0 && < 2.21 - , pretty >= 1.1.3 && < 1.2 - , data-default-class >= 0.1.2 && < 0.2 - , hashable >= 1.4.3 && < 1.5 - , mtl >= 2.3.1 && < 2.4 - , text >= 2.0.2 && < 2.1 - , megaparsec >= 9.6.1 && < 9.7 - , microlens >= 0.4.13 && < 0.5 - , microlens-mtl >= 0.2.0 && < 0.3 - , microlens-platform >= 0.4.3 && < 0.5 - , microlens-th >= 0.4.3 && < 0.5 - , unordered-containers >= 0.2.20 && < 0.3 - , recursion-schemes >= 5.2.2 && < 5.3 + , array + , data-default-class + , unordered-containers + , hashable + , pretty + -- TODO: either learn recursion-schemes, or stop depending + -- on it. + , recursion-schemes + , megaparsec ^>=9.6.0 + , text + , data-fix hs-source-dirs: src default-language: GHC2021 diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index c8a0a33..3c28017 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -24,6 +24,7 @@ import Data.Functor import Data.Functor.Const import Data.Fix hiding (cata) import Lens.Micro +import Lens.Micro.Platform import Rlp.Parse.Types import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -128,7 +129,40 @@ isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") isSym :: Char -> Bool isSym c = c == ':' || isVarSym c -infixD = undefined +infixD :: Parser (Decl' e) +infixD = do + o <- getOffset + a <- infixWord + p <- prec + op <- infixOp + region (setErrorOffset o) $ updateOpTable a p op + pure $ InfixD a p op + where + infixWord :: Parser Assoc + infixWord = choice $ lexeme <$> + [ "infixr" $> InfixR + , "infixl" $> InfixL + , "infix" $> Infix + ] + + prec :: Parser Int + prec = do + o <- getOffset + n <- lexeme L.decimal + if 0 <= n && n <= 9 then + pure n + else + region (setErrorOffset o) $ + registerCustomFailure (RlpParErrOutOfBoundsPrecedence n) + $> 9 + + updateOpTable :: Assoc -> Int -> Name -> Parser () + updateOpTable a p op = do + t <- use psOpTable + psOpTable <~ H.alterF f op t + where + f Nothing = pure (Just (a,p)) + f (Just _) = customFailure RlpParErrDuplicateInfixD tySigD = undefined dataD = undefined diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index d3e7bd1..16a0ed9 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} {- Description : Supporting types for the parser @@ -16,8 +18,13 @@ module Rlp.Parse.Types -- * Parser types , Parser , ParserState(..) + , psOpTable + , RlpParseError(..) , OpTable , OpInfo + + -- * Extras + , registerCustomFailure ) where ---------------------------------------------------------------------------------- @@ -29,14 +36,17 @@ import Data.Functor.Const import Data.Functor.Classes import Data.Void import Data.Maybe +import Data.Set qualified as S import Text.Megaparsec hiding (State) +import Text.Printf import Lens.Micro +import Lens.Micro.TH import Rlp.Syntax ---------------------------------------------------------------------------------- -- parser types -type Parser = ParsecT Void Text (State ParserState) +type Parser = ParsecT RlpParseError Text (State ParserState) data ParserState = ParserState { _psOpTable :: OpTable @@ -46,6 +56,23 @@ data ParserState = ParserState type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) +-- data WithLocation a = WithLocation [String] a + +data RlpParseError = RlpParErrOutOfBoundsPrecedence Int + | RlpParErrDuplicateInfixD + deriving (Eq, Ord, Show) + +instance ShowErrorComponent RlpParseError where + showErrorComponent = \case + -- TODO: wrap text to 80 characters + RlpParErrOutOfBoundsPrecedence n -> + printf "%d is an invalid precedence level! rl' currently only\ + \allows custom precedences between 0 and 9 (inclusive).\ + \ This is an arbitrary limit put in place for legibility\ + \ concerns, and may change in the future." n + RlpParErrDuplicateInfixD -> + "duplicate infix decl" + ---------------------------------------------------------------------------------- -- absolute psycho shit (partial ASTs) @@ -90,3 +117,10 @@ instance Show1 Partial where type PartialExpr' = Fix Partial +---------------------------------------------------------------------------------- + +makeLenses ''ParserState + +registerCustomFailure :: MonadParsec e s m => e -> m () +registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index b314d7b..4a43cb9 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -9,6 +9,7 @@ module Rlp.Syntax , RlpExprF(..) , RlpExprF' , Decl(..) + , Decl' , Assoc(..) , VarId(..) , Pat(..) @@ -50,6 +51,8 @@ data Decl e b = FunD VarId [Pat b] (e b) | InfixD Assoc Int Name deriving Show +type Decl' e = Decl e Name + data Assoc = InfixL | InfixR | Infix -- 2.52.0 From 3292998c421cf5b3b526af984d9908be961e8867 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 12:26:53 -0700 Subject: [PATCH 060/192] expr fixups --- src/RLP/Parse/Decls.hs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 3c28017..87668aa 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -45,6 +45,9 @@ symbol = L.symbol sc sc :: Parser () sc = L.space hspace1 (void lineComment) (void blockComment) +scn :: Parser () +scn = L.space space1 (void lineComment) (void blockComment) + -- TODO: return comment text -- TODO: '---' should not start a comment lineComment :: Parser Text @@ -72,27 +75,35 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = choice - [ try $ fmap Fix $ mkB <$> partialExpr1' <*> lexeme infixOp <*> partialExpr' - , foldl1' papp <$> some partialExpr1 +partialExpr = (choice . fmap foldedLexeme) + [ try application + , Fix <$> infixExpr ] "expression" where + application = foldl1' mkApp <$> some partialExpr1 + infixExpr = mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' + mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr + infixOp' = foldedLexeme infixOp - papp :: PartialExpr' -> PartialExpr' -> PartialExpr' - papp f x = Fix . E $ f `AppEF` x + mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' + mkApp f x = Fix . E $ f `AppEF` x + +foldedLexeme :: Parser a -> Parser a +foldedLexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p partialExpr1 :: Parser PartialExpr' -partialExpr1 = choice - [ try $ char '(' *> (hoistFix P <$> partialExpr) <* char ')' - , fmap Fix $ varid' - , fmap Fix $ lit' +partialExpr1 = (choice . fmap foldedLexeme) + [ foldedLexeme "(" *> partialExpr' <* foldedLexeme ")" + , Fix <$> varid' + , Fix <$> lit' ] "expression" where + partialExpr' = wrapFix . P . unwrapFix <$> partialExpr varid' = E . VarEF <$> varid lit' = E . LitEF <$> lit -- 2.52.0 From cae0939f0cf6d15115a772bc60fef2a70cba414d Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 14:24:51 -0700 Subject: [PATCH 061/192] where --- src/RLP/Parse/Decls.hs | 93 ++++++++++++++++++++++++++++++++---------- src/RLP/Parse/Types.hs | 7 ---- src/RLP/Parse/Utils.hs | 30 ++++++++++++++ src/RLP/Syntax.hs | 24 +++++++---- 4 files changed, 119 insertions(+), 35 deletions(-) create mode 100644 src/RLP/Parse/Utils.hs diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 87668aa..8a95f41 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -18,6 +18,7 @@ import Data.Functor.Foldable import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H +import Data.Maybe (maybeToList) import Data.List (foldl1') import Data.Char import Data.Functor @@ -26,6 +27,7 @@ import Data.Fix hiding (cata) import Lens.Micro import Lens.Micro.Platform import Rlp.Parse.Types +import Rlp.Parse.Utils import Rlp.Syntax ---------------------------------------------------------------------------------- @@ -39,6 +41,9 @@ parseTest' p s = case runState (runParserT p "test" s) init of lexeme :: Parser a -> Parser a lexeme = L.lexeme sc +flexeme :: Parser a -> Parser a +flexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p + symbol :: Text -> Parser Text symbol = L.symbol sc @@ -66,7 +71,16 @@ decl = choice ] funD :: Parser PartialDecl' -funD = FunD <$> varid <*> many pat1 <*> (symbol "=" *> fmap Const partialExpr) +funD = FunD <$> flexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause + where + params = many pat1 + body = fmap Const partialExpr + +whereClause :: Parser Where' +whereClause = optionalList $ + flexeme "where" *> pure + [ FunB "fixme" [] (VarE "fixme") + ] standalonePartialExpr :: Parser PartialExpr' standalonePartialExpr = standaloneOf partialExpr @@ -75,7 +89,7 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = (choice . fmap foldedLexeme) +partialExpr = (choice . fmap flexeme) [ try application , Fix <$> infixExpr ] @@ -87,17 +101,14 @@ partialExpr = (choice . fmap foldedLexeme) mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr - infixOp' = foldedLexeme infixOp + infixOp' = flexeme infixOp mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x -foldedLexeme :: Parser a -> Parser a -foldedLexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p - partialExpr1 :: Parser PartialExpr' -partialExpr1 = (choice . fmap foldedLexeme) - [ foldedLexeme "(" *> partialExpr' <* foldedLexeme ")" +partialExpr1 = (choice . fmap flexeme) + [ try $ flexeme "(" *> partialExpr' <* flexeme ")" , Fix <$> varid' , Fix <$> lit' ] @@ -108,7 +119,7 @@ partialExpr1 = (choice . fmap foldedLexeme) lit' = E . LitEF <$> lit infixOp :: Parser Name -infixOp = symvar <|> symcon "infix operator" +infixOp = symvar <|> symcon "operator" symvar :: Parser Name symvar = T.pack <$> @@ -119,20 +130,34 @@ symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) pat1 :: Parser Pat' -pat1 = VarP <$> varid +pat1 = VarP <$> flexeme varid "pattern" +conid :: Parser ConId +conid = NameCon <$> lexeme namecon + <|> SymCon <$> lexeme (char '(' *> symcon <* char ')') + "constructor identifier" + +namecon :: Parser Name +namecon = T.pack <$> + liftA2 (:) (satisfy isUpper) + (many $ satisfy isNameTail) + varid :: Parser VarId -varid = NameVar <$> lexeme namevar +varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" - where - namevar = T.pack <$> + +namevar :: Parser Name +namevar = try word + & withPredicate (`notElem` ["where"]) empty + where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) - isNameTail c = isAlphaNum c - || c == '\'' - || c == '_' +isNameTail :: Char -> Bool +isNameTail c = isAlphaNum c + || c == '\'' + || c == '_' isVarSym :: Char -> Bool isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") @@ -159,7 +184,7 @@ infixD = do prec :: Parser Int prec = do o <- getOffset - n <- lexeme L.decimal + n <- lexeme L.decimal "precedence level (an integer)" if 0 <= n && n <= 9 then pure n else @@ -173,10 +198,36 @@ infixD = do psOpTable <~ H.alterF f op t where f Nothing = pure (Just (a,p)) - f (Just _) = customFailure RlpParErrDuplicateInfixD + f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD + $> Just x tySigD = undefined -dataD = undefined + +dataD :: Parser (Decl' e) +dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram + <*> optionalList (symbol "=" *> conalts) + where + typaram :: Parser Name + typaram = flexeme namevar + + conalts :: Parser [ConAlt] + conalts = (:) <$> conalt <*> optionalList (symbol "|" *> conalts) + + conalt :: Parser ConAlt + conalt = ConAlt <$> conid <*> many type1 + +type1 :: Parser Type +type1 = (choice . fmap flexeme) + [ flexeme "(" *> type_ <* flexeme ")" + , TyVar <$> namevar + , TyCon <$> namecon + ] + +type_ :: Parser Type +type_ = (choice . fmap flexeme) + [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) + , type1 + ] lit :: Parser Lit' lit = int @@ -184,9 +235,9 @@ lit = int where int = IntL <$> L.decimal ----------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- completing partial expressions --- complete :: OpTable -> Fix Partial -> RlpExpr' complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' complete = cata completePartial diff --git a/src/RLP/Parse/Types.hs b/src/RLP/Parse/Types.hs index 16a0ed9..e961d2d 100644 --- a/src/RLP/Parse/Types.hs +++ b/src/RLP/Parse/Types.hs @@ -22,9 +22,6 @@ module Rlp.Parse.Types , RlpParseError(..) , OpTable , OpInfo - - -- * Extras - , registerCustomFailure ) where ---------------------------------------------------------------------------------- @@ -36,7 +33,6 @@ import Data.Functor.Const import Data.Functor.Classes import Data.Void import Data.Maybe -import Data.Set qualified as S import Text.Megaparsec hiding (State) import Text.Printf import Lens.Micro @@ -121,6 +117,3 @@ type PartialExpr' = Fix Partial makeLenses ''ParserState -registerCustomFailure :: MonadParsec e s m => e -> m () -registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom - diff --git a/src/RLP/Parse/Utils.hs b/src/RLP/Parse/Utils.hs new file mode 100644 index 0000000..cf5fb8c --- /dev/null +++ b/src/RLP/Parse/Utils.hs @@ -0,0 +1,30 @@ +module Rlp.Parse.Utils + ( withPredicate + , registerCustomFailure + , optionalList + ) + where +-------------------------------------------------------------------------------- +import Text.Megaparsec +import Rlp.Parse.Types +import Data.Set qualified as S +import Data.Maybe +import Control.Monad +-------------------------------------------------------------------------------- + +-- TODO: generalise type sig +withPredicate :: (a -> Bool) + -> Parser a -- ^ action to run should the predicate fail + -> Parser a + -> Parser a +withPredicate f r p = do + o <- getOffset + a <- p + if f a then pure a else setOffset o *> r + +registerCustomFailure :: MonadParsec e s m => e -> m () +registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom + +optionalList :: Parser [a] -> Parser [a] +optionalList = fmap (join . maybeToList) . optional + diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 4a43cb9..09acb8b 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -2,7 +2,7 @@ {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} -- recursion-schemes {-# LANGUAGE TemplateHaskell, TypeFamilies #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings, PatternSynonyms #-} module Rlp.Syntax ( RlpExpr(..) , RlpExpr' @@ -10,8 +10,15 @@ module Rlp.Syntax , RlpExprF' , Decl(..) , Decl' + , Bind(..) + , Where + , Where' + , ConAlt(..) + , Type(..) + , pattern (:->) , Assoc(..) , VarId(..) + , ConId(..) , Pat(..) , Pat' , Lit(..) @@ -45,9 +52,9 @@ newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- accounted for, we may complete the parsing task and get a proper @[Decl -- RlpExpr Name]@. -data Decl e b = FunD VarId [Pat b] (e b) +data Decl e b = FunD VarId [Pat b] (e b) (Where b) | TySigD [VarId] Type - | DataD ConId [ConId] [ConAlt] + | DataD ConId [Name] [ConAlt] | InfixD Assoc Int Name deriving Show @@ -58,14 +65,14 @@ data Assoc = InfixL | Infix deriving Show -data ConAlt = ConAlt ConId [ConId] - deriving Show +data ConAlt = ConAlt ConId [Type] + deriving Show data RlpExpr b = LetE [Bind b] (RlpExpr b) | VarE VarId | ConE ConId | LamE [Pat b] (RlpExpr b) - | CaseE (RlpExpr b) [Alt b] + | CaseE (RlpExpr b) [(Alt b, Where b)] | IfE (RlpExpr b) (RlpExpr b) (RlpExpr b) | AppE (RlpExpr b) (RlpExpr b) | LitE (Lit b) @@ -73,9 +80,12 @@ data RlpExpr b = LetE [Bind b] (RlpExpr b) type RlpExpr' = RlpExpr Name +type Where b = [Bind b] +type Where' = [Bind Name] + -- do we want guards? data Alt b = AltA (Pat b) (RlpExpr b) - deriving Show + deriving Show data Bind b = PatB (Pat b) (RlpExpr b) | FunB VarId [Pat b] (RlpExpr b) -- 2.52.0 From d0dbdbbd9b67175093cdb45a12f7cb9456c264fc Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 9 Jan 2024 22:57:14 -0700 Subject: [PATCH 062/192] cool --- src/RLP/Parse/Decls.hs | 44 ++++++++++++++++++++++++++++-------------- src/RLP/Syntax.hs | 15 +++++++++++++- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 8a95f41..9d4a911 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE RecursiveDo #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase, BlockArguments #-} @@ -71,14 +72,14 @@ decl = choice ] funD :: Parser PartialDecl' -funD = FunD <$> flexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause +funD = FunD <$> lexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause where params = many pat1 body = fmap Const partialExpr whereClause :: Parser Where' whereClause = optionalList $ - flexeme "where" *> pure + lexeme "where" *> pure [ FunB "fixme" [] (VarE "fixme") ] @@ -89,7 +90,7 @@ standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) partialExpr :: Parser PartialExpr' -partialExpr = (choice . fmap flexeme) +partialExpr = choice [ try application , Fix <$> infixExpr ] @@ -101,14 +102,14 @@ partialExpr = (choice . fmap flexeme) mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr - infixOp' = flexeme infixOp + infixOp' = lexeme infixOp mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x partialExpr1 :: Parser PartialExpr' -partialExpr1 = (choice . fmap flexeme) - [ try $ flexeme "(" *> partialExpr' <* flexeme ")" +partialExpr1 = choice + [ try $ lexeme "(" *> partialExpr' <* lexeme ")" , Fix <$> varid' , Fix <$> lit' ] @@ -130,7 +131,7 @@ symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) pat1 :: Parser Pat' -pat1 = VarP <$> flexeme varid +pat1 = VarP <$> lexeme varid "pattern" conid :: Parser ConId @@ -148,8 +149,23 @@ varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" +decls :: Parser [PartialDecl'] +decls = L.indentBlock scn p where + p = do + a <- "wtf" + pure (L.IndentSome (Just pos1) pure decl) + +t :: Parser [PartialDecl'] +t = do + space + i <- L.indentLevel + let indentGuard = L.indentGuard scn EQ i + -- indentGuard *> decl *> eol *> indentGuard *> decl + rec ds <- indentGuard *> decl <|> eof + many $ indentGuard *> decl <* (eol <|> eof) + namevar :: Parser Name -namevar = try word +namevar = word & withPredicate (`notElem` ["where"]) empty where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) @@ -204,11 +220,11 @@ infixD = do tySigD = undefined dataD :: Parser (Decl' e) -dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram +dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram <*> optionalList (symbol "=" *> conalts) where typaram :: Parser Name - typaram = flexeme namevar + typaram = lexeme namevar conalts :: Parser [ConAlt] conalts = (:) <$> conalt <*> optionalList (symbol "|" *> conalts) @@ -217,15 +233,15 @@ dataD = DataD <$> (flexeme "data" *> conid) <*> many typaram conalt = ConAlt <$> conid <*> many type1 type1 :: Parser Type -type1 = (choice . fmap flexeme) - [ flexeme "(" *> type_ <* flexeme ")" +type1 = choice + [ lexeme "(" *> type_ <* lexeme ")" , TyVar <$> namevar , TyCon <$> namecon ] type_ :: Parser Type -type_ = (choice . fmap flexeme) - [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) +type_ = choice + [ try $ (:->) <$> type1 <*> (lexeme "->" *> type_) , type1 ] diff --git a/src/RLP/Syntax.hs b/src/RLP/Syntax.hs index 09acb8b..58843b5 100644 --- a/src/RLP/Syntax.hs +++ b/src/RLP/Syntax.hs @@ -4,7 +4,10 @@ {-# LANGUAGE TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings, PatternSynonyms #-} module Rlp.Syntax - ( RlpExpr(..) + ( RlpModule(..) + , rlpmodName + , rlpmodProgram + , RlpExpr(..) , RlpExpr' , RlpExprF(..) , RlpExprF' @@ -39,10 +42,16 @@ import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes import Lens.Micro +import Lens.Micro.TH import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- +data RlpModule b = RlpModule + { _rlpmodName :: Text + , _rlpmodProgram :: RlpProgram b + } + newtype RlpProgram b = RlpProgram [Decl RlpExpr b] -- | The @e@ parameter is used for partial results. When parsing an input, we @@ -157,3 +166,7 @@ showsTernaryWith sa sb sc name p a b c = showParen (p > 10) . showChar ' ' . sb 11 b . showChar ' ' . sc 11 c +-------------------------------------------------------------------------------- + +makeLenses ''RlpModule + -- 2.52.0 From ed60ec8b3225dc3c36a7fb8791916120be5402e9 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 10:46:53 -0700 Subject: [PATCH 063/192] aaaaa --- src/RLP/Parse/Decls.hs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 9d4a911..201316b 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -65,10 +65,12 @@ blockComment = L.skipBlockCommentNested "{-" "-}" $> "" decl :: Parser PartialDecl' decl = choice - [ funD - , tySigD + -- declarations that begin with a keyword before those beginning with an + -- arbitrary name + [ infixD , dataD - , infixD + , funD + , tySigD ] funD :: Parser PartialDecl' @@ -150,26 +152,28 @@ varid = NameVar <$> try (lexeme namevar) "variable identifier" decls :: Parser [PartialDecl'] -decls = L.indentBlock scn p where - p = do - a <- "wtf" - pure (L.IndentSome (Just pos1) pure decl) - -t :: Parser [PartialDecl'] -t = do +decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i -- indentGuard *> decl *> eol *> indentGuard *> decl - rec ds <- indentGuard *> decl <|> eof - many $ indentGuard *> decl <* (eol <|> eof) + many $ indentGuard *> decl + -- many $ indentGuard *> decl <* (eol <|> eof) namevar :: Parser Name namevar = word - & withPredicate (`notElem` ["where"]) empty + & withPredicate (`notElem` keywords) empty where word = T.pack <$> liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) +keywords :: (IsString a) => [a] +keywords = + [ "where" + , "infix" + , "infixr" + , "infixl" + ] + isNameTail :: Char -> Bool isNameTail c = isAlphaNum c || c == '\'' @@ -217,7 +221,8 @@ infixD = do f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD $> Just x -tySigD = undefined +tySigD :: Parser (Decl' e) +tySigD = undefined -- TySigD <$> (flexeme) dataD :: Parser (Decl' e) dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram -- 2.52.0 From 65b967689c6eda1ecbd34a1ecb7d678f5ee42b9a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:03:06 -0700 Subject: [PATCH 064/192] decls fix --- src/RLP/Parse/Decls.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 201316b..07c8263 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -22,9 +22,11 @@ import Data.HashMap.Strict qualified as H import Data.Maybe (maybeToList) import Data.List (foldl1') import Data.Char +import Data.Function (fix) import Data.Functor import Data.Functor.Const import Data.Fix hiding (cata) +import GHC.Exts (IsString) import Lens.Micro import Lens.Micro.Platform import Rlp.Parse.Types @@ -156,9 +158,8 @@ decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i - -- indentGuard *> decl *> eol *> indentGuard *> decl - many $ indentGuard *> decl - -- many $ indentGuard *> decl <* (eol <|> eof) + fix \ds -> (:) <$> (indentGuard *> decl) + <*> (try ds <|> eof *> pure []) namevar :: Parser Name namevar = word -- 2.52.0 From 4b9a570c7221dc24b704c3f9e271d11ff94e0d9f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:26:17 -0700 Subject: [PATCH 065/192] finally in a decent state --- src/RLP/Parse/Decls.hs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 07c8263..480bea3 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -44,9 +44,6 @@ parseTest' p s = case runState (runParserT p "test" s) init of lexeme :: Parser a -> Parser a lexeme = L.lexeme sc -flexeme :: Parser a -> Parser a -flexeme p = L.lineFold scn $ \sc' -> L.lexeme sc' p - symbol :: Text -> Parser Text symbol = L.symbol sc @@ -56,6 +53,8 @@ sc = L.space hspace1 (void lineComment) (void blockComment) scn :: Parser () scn = L.space space1 (void lineComment) (void blockComment) +type OnFold = (?foldGuard :: Parser ()) + -- TODO: return comment text -- TODO: '---' should not start a comment lineComment :: Parser Text @@ -65,7 +64,7 @@ lineComment = L.skipLineComment "--" $> "" blockComment :: Parser Text blockComment = L.skipBlockCommentNested "{-" "-}" $> "" -decl :: Parser PartialDecl' +decl :: (OnFold) => Parser PartialDecl' decl = choice -- declarations that begin with a keyword before those beginning with an -- arbitrary name @@ -75,12 +74,18 @@ decl = choice , tySigD ] -funD :: Parser PartialDecl' -funD = FunD <$> lexeme varid <*> params <*> (symbol "=" *> body) <*> whereClause +funD :: (OnFold) => Parser PartialDecl' +funD = FunD <$> lexeme varid <*> params <*> (fsymbol "=" *> body) <*> whereClause where params = many pat1 body = fmap Const partialExpr +fsymbol :: (OnFold) => Text -> Parser Text +fsymbol p = scn *> ?foldGuard *> symbol p + +flexeme :: (OnFold) => Parser a -> Parser a +flexeme p = scn *> ?foldGuard *> lexeme p + whereClause :: Parser Where' whereClause = optionalList $ lexeme "where" *> pure @@ -134,8 +139,8 @@ symcon :: Parser Name symcon = T.pack <$> liftA2 (:) (char ':') (many $ satisfy isSym) -pat1 :: Parser Pat' -pat1 = VarP <$> lexeme varid +pat1 :: (OnFold) => Parser Pat' +pat1 = VarP <$> flexeme varid "pattern" conid :: Parser ConId @@ -158,6 +163,7 @@ decls = do space i <- L.indentLevel let indentGuard = L.indentGuard scn EQ i + let ?foldGuard = void $ L.indentGuard scn GT i fix \ds -> (:) <$> (indentGuard *> decl) <*> (try ds <|> eof *> pure []) -- 2.52.0 From 1fc45b70b40a81933b443443dbd420c77e783baf Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 11:33:27 -0700 Subject: [PATCH 066/192] replace uses of many+satisfy with takeWhileP --- src/RLP/Parse/Decls.hs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 480bea3..3e86529 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -132,12 +132,10 @@ infixOp :: Parser Name infixOp = symvar <|> symcon "operator" symvar :: Parser Name -symvar = T.pack <$> - liftA2 (:) (satisfy isVarSym) (many $ satisfy isSym) +symvar = T.cons <$> satisfy isVarSym <*> takeWhileP Nothing isSym symcon :: Parser Name -symcon = T.pack <$> - liftA2 (:) (char ':') (many $ satisfy isSym) +symcon = T.cons <$> char ':' <*> takeWhileP Nothing isSym pat1 :: (OnFold) => Parser Pat' pat1 = VarP <$> flexeme varid @@ -149,9 +147,7 @@ conid = NameCon <$> lexeme namecon "constructor identifier" namecon :: Parser Name -namecon = T.pack <$> - liftA2 (:) (satisfy isUpper) - (many $ satisfy isNameTail) +namecon = T.cons <$> satisfy isUpper <*> takeWhileP Nothing isNameTail varid :: Parser VarId varid = NameVar <$> try (lexeme namevar) @@ -170,8 +166,8 @@ decls = do namevar :: Parser Name namevar = word & withPredicate (`notElem` keywords) empty - where word = T.pack <$> - liftA2 (:) (satisfy isLower) (many $ satisfy isNameTail) + where + word = T.cons <$> satisfy isLower <*> takeWhileP Nothing isNameTail keywords :: (IsString a) => [a] keywords = -- 2.52.0 From ec4902b2d49f2e9d087d80651dea26cfe71203c6 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 14:10:46 -0700 Subject: [PATCH 067/192] layout layouts oh my layouts --- src/RLP/Parse/Decls.hs | 55 +++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/RLP/Parse/Decls.hs b/src/RLP/Parse/Decls.hs index 3e86529..5199b92 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/RLP/Parse/Decls.hs @@ -64,6 +64,31 @@ lineComment = L.skipLineComment "--" $> "" blockComment :: Parser Text blockComment = L.skipBlockCommentNested "{-" "-}" $> "" +layout :: forall a. ((OnFold) => Parser a) -> Parser [a] +layout item = scn *> (explicit <|> implicit) where + explicit :: Parser [a] + explicit = let ?foldGuard = scn -- line folds just go to the semicolon + in sym "{" *> fix \items -> choice + [ sym "}" $> [] + , (:) <$> item + <*> (sym ";" *> items <|> sym "}" $> []) + ] + where + sym = L.symbol scn + + implicit :: Parser [a] + implicit = do + i <- L.indentLevel + -- items must be aligned + let indentGuard = L.indentGuard scn EQ i + -- override foldGuard in order with new indentation + let ?foldGuard = void $ L.indentGuard scn GT i + fix \ds -> (:) <$> (indentGuard *> item) + <*> (ds <|> pure []) + +t :: (?foldGuard :: Parser ()) => Parser [Text] +t = (:) <$> lexeme "soge" <*> many (flexeme "doge") + decl :: (OnFold) => Parser PartialDecl' decl = choice -- declarations that begin with a keyword before those beginning with an @@ -80,11 +105,13 @@ funD = FunD <$> lexeme varid <*> params <*> (fsymbol "=" *> body) <*> whereClaus params = many pat1 body = fmap Const partialExpr +-- we may not need to call scn here fsymbol :: (OnFold) => Text -> Parser Text -fsymbol p = scn *> ?foldGuard *> symbol p +fsymbol p = try ?foldGuard *> symbol p +-- we may not need to call scn here flexeme :: (OnFold) => Parser a -> Parser a -flexeme p = scn *> ?foldGuard *> lexeme p +flexeme p = try ?foldGuard *> lexeme p whereClause :: Parser Where' whereClause = optionalList $ @@ -94,18 +121,19 @@ whereClause = optionalList $ standalonePartialExpr :: Parser PartialExpr' standalonePartialExpr = standaloneOf partialExpr + where ?foldGuard = undefined standaloneOf :: Parser a -> Parser a standaloneOf = (<* eof) -partialExpr :: Parser PartialExpr' +partialExpr :: (OnFold) => Parser PartialExpr' partialExpr = choice [ try application , Fix <$> infixExpr ] "expression" where - application = foldl1' mkApp <$> some partialExpr1 + application = foldl1' mkApp <$> some (flexeme partialExpr1) infixExpr = mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' mkB a f b = B f a b @@ -116,7 +144,7 @@ partialExpr = choice mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x -partialExpr1 :: Parser PartialExpr' +partialExpr1 :: (OnFold) => Parser PartialExpr' partialExpr1 = choice [ try $ lexeme "(" *> partialExpr' <* lexeme ")" , Fix <$> varid' @@ -155,13 +183,16 @@ varid = NameVar <$> try (lexeme namevar) "variable identifier" decls :: Parser [PartialDecl'] -decls = do - space - i <- L.indentLevel - let indentGuard = L.indentGuard scn EQ i - let ?foldGuard = void $ L.indentGuard scn GT i - fix \ds -> (:) <$> (indentGuard *> decl) - <*> (try ds <|> eof *> pure []) +decls = layout decl <* eof + +-- decls :: Parser [PartialDecl'] +-- decls = do +-- space +-- i <- L.indentLevel +-- let indentGuard = L.indentGuard scn EQ i +-- let ?foldGuard = void $ L.indentGuard scn GT i +-- fix \ds -> (:) <$> (indentGuard *> decl) +-- <*> (try ds <|> eof *> pure []) namevar :: Parser Name namevar = word -- 2.52.0 From ab2cb595263d649fd77d440bd6535d5545a8de9b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 14:33:03 -0700 Subject: [PATCH 068/192] i did not realise my fs is case insensitive --- src/{RLP => Rlp}/Parse/Decls.hs | 4 ++-- src/{RLP => Rlp}/Parse/Types.hs | 0 src/{RLP => Rlp}/Parse/Utils.hs | 0 src/{RLP => Rlp}/Syntax.hs | 0 tst/Rlp/Parse/DeclsSpec.hs | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename src/{RLP => Rlp}/Parse/Decls.hs (99%) rename src/{RLP => Rlp}/Parse/Types.hs (100%) rename src/{RLP => Rlp}/Parse/Utils.hs (100%) rename src/{RLP => Rlp}/Syntax.hs (100%) create mode 100644 tst/Rlp/Parse/DeclsSpec.hs diff --git a/src/RLP/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs similarity index 99% rename from src/RLP/Parse/Decls.hs rename to src/Rlp/Parse/Decls.hs index 5199b92..d8af6ca 100644 --- a/src/RLP/Parse/Decls.hs +++ b/src/Rlp/Parse/Decls.hs @@ -128,8 +128,8 @@ standaloneOf = (<* eof) partialExpr :: (OnFold) => Parser PartialExpr' partialExpr = choice - [ try application - , Fix <$> infixExpr + [ try $ Fix <$> infixExpr + , application ] "expression" where diff --git a/src/RLP/Parse/Types.hs b/src/Rlp/Parse/Types.hs similarity index 100% rename from src/RLP/Parse/Types.hs rename to src/Rlp/Parse/Types.hs diff --git a/src/RLP/Parse/Utils.hs b/src/Rlp/Parse/Utils.hs similarity index 100% rename from src/RLP/Parse/Utils.hs rename to src/Rlp/Parse/Utils.hs diff --git a/src/RLP/Syntax.hs b/src/Rlp/Syntax.hs similarity index 100% rename from src/RLP/Syntax.hs rename to src/Rlp/Syntax.hs diff --git a/tst/Rlp/Parse/DeclsSpec.hs b/tst/Rlp/Parse/DeclsSpec.hs new file mode 100644 index 0000000..e69de29 -- 2.52.0 From ea2fb4dcaa30067c8cb235d7b514986f5257df1b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 15:11:26 -0700 Subject: [PATCH 069/192] tysigs --- src/Rlp/Parse/Decls.hs | 43 +++++++++++++++++++++--------------------- src/Rlp/Parse/Types.hs | 3 +++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Rlp/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs index d8af6ca..d61c0d4 100644 --- a/src/Rlp/Parse/Decls.hs +++ b/src/Rlp/Parse/Decls.hs @@ -83,7 +83,7 @@ layout item = scn *> (explicit <|> implicit) where let indentGuard = L.indentGuard scn EQ i -- override foldGuard in order with new indentation let ?foldGuard = void $ L.indentGuard scn GT i - fix \ds -> (:) <$> (indentGuard *> item) + fix \ds -> (:) <$> (indentGuard *> item <* scn) <*> (ds <|> pure []) t :: (?foldGuard :: Parser ()) => Parser [Text] @@ -95,7 +95,7 @@ decl = choice -- arbitrary name [ infixD , dataD - , funD + , try funD , tySigD ] @@ -182,17 +182,11 @@ varid = NameVar <$> try (lexeme namevar) <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') "variable identifier" -decls :: Parser [PartialDecl'] -decls = layout decl <* eof - --- decls :: Parser [PartialDecl'] --- decls = do --- space --- i <- L.indentLevel --- let indentGuard = L.indentGuard scn EQ i --- let ?foldGuard = void $ L.indentGuard scn GT i --- fix \ds -> (:) <$> (indentGuard *> decl) --- <*> (try ds <|> eof *> pure []) +program :: Parser [Decl' RlpExpr] +program = do + ds <- layout decl <* eof + pt <- use psOpTable + pure $ complete pt <$> ds namevar :: Parser Name namevar = word @@ -255,10 +249,10 @@ infixD = do f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD $> Just x -tySigD :: Parser (Decl' e) -tySigD = undefined -- TySigD <$> (flexeme) +tySigD :: (OnFold) => Parser (Decl' e) +tySigD = TySigD <$> (pure <$> varid) <*> (flexeme "::" *> flexeme type_) -dataD :: Parser (Decl' e) +dataD :: (OnFold) => Parser (Decl' e) dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram <*> optionalList (symbol "=" *> conalts) where @@ -271,16 +265,16 @@ dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram conalt :: Parser ConAlt conalt = ConAlt <$> conid <*> many type1 -type1 :: Parser Type +type1 :: (OnFold) => Parser Type type1 = choice [ lexeme "(" *> type_ <* lexeme ")" , TyVar <$> namevar , TyCon <$> namecon ] -type_ :: Parser Type +type_ :: (OnFold) => Parser Type type_ = choice - [ try $ (:->) <$> type1 <*> (lexeme "->" *> type_) + [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) , type1 ] @@ -293,8 +287,15 @@ lit = int -------------------------------------------------------------------------------- -- completing partial expressions -complete :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' -complete = cata completePartial +complete :: OpTable -> PartialDecl' -> Decl' RlpExpr +complete pt (FunD n as b w) = FunD n as b' w + where b' = let ?pt = pt in completeExpr (getConst b) +complete pt (TySigD ns t) = TySigD ns t +complete pt (DataD n as cs) = DataD n as cs +complete pt (InfixD a p n) = InfixD a p n + +completeExpr :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' +completeExpr = cata completePartial completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' completePartial (E e) = completeRlpExpr e diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index e961d2d..41e67f8 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -42,6 +42,9 @@ import Rlp.Syntax -- parser types +-- TODO: the State is only used for building an operator table from infix[lr] +-- declarations. we should switch to a normal Parsec monad in the future + type Parser = ParsecT RlpParseError Text (State ParserState) data ParserState = ParserState -- 2.52.0 From eaa04c4a592c6faff5fc3d1e7adf35219b115dd7 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 10 Jan 2024 16:12:35 -0700 Subject: [PATCH 070/192] its fine --- src/Rlp/Parse/Decls.hs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Rlp/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs index d61c0d4..fb6d875 100644 --- a/src/Rlp/Parse/Decls.hs +++ b/src/Rlp/Parse/Decls.hs @@ -128,18 +128,26 @@ standaloneOf = (<* eof) partialExpr :: (OnFold) => Parser PartialExpr' partialExpr = choice - [ try $ Fix <$> infixExpr + [ ifExpr + , try $ infixExpr , application ] "expression" where application = foldl1' mkApp <$> some (flexeme partialExpr1) - infixExpr = mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' + infixExpr = fmap Fix $ + mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' + + ifExpr :: Parser PartialExpr' + ifExpr = fmap (Fix . E) $ + IfEF <$> (flexeme "if" *> partialExpr) + <*> (flexeme "then" *> partialExpr) + <*> (flexeme "else" *> partialExpr) mkB a f b = B f a b partialExpr1' = unFix <$> partialExpr1 partialExpr' = unFix <$> partialExpr - infixOp' = lexeme infixOp + infixOp' = flexeme infixOp mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' mkApp f x = Fix . E $ f `AppEF` x -- 2.52.0 From bec376b7c7c443a0606d66f2cfcee4db39496e6f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 11 Jan 2024 08:36:44 -0700 Subject: [PATCH 071/192] threaded lexer --- rlp.cabal | 4 +++- src/Rlp/Lex.x | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Rlp/Parse.y | 28 ++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/Rlp/Lex.x create mode 100644 src/Rlp/Parse.y diff --git a/rlp.cabal b/rlp.cabal index dc83431..e6b81a9 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -31,7 +31,9 @@ library , Core.HindleyMilner , Control.Monad.Errorful , Rlp.Syntax - , Rlp.Parse.Decls + -- , Rlp.Parse.Decls + , Rlp.Parse + , Rlp.Lex , Rlp.Parse.Types other-modules: Data.Heap diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x new file mode 100644 index 0000000..893a487 --- /dev/null +++ b/src/Rlp/Lex.x @@ -0,0 +1,64 @@ +{ +{-# LANGUAGE GeneralisedNewtypeDeriving #-} +{-# LANGUAGE OverloadedStrings #-} +module Rlp.Lex + ( P(..) + , RlpToken(..) + , Located(..) + , AlexPosn + , lexer + ) + where +import Data.Functor.Identity +import Core.Syntax (Name) +import Data.Text (Text) +import Data.Text qualified as T +import Lens.Micro +} + +%wrapper "monad-strict-text" + +rlp :- +<0> +{ + "a" { const $ const $ pure $ Located (AlexPn 0 0 0) (TokenVarName "a") } + "" { undefined } +} + +{ + +alexEOF :: Alex a +alexEOF = undefined + +data RlpToken = TokenEquals + | TokenLitInt Int + | TokenVarName Name + | TokenConName Name + | TokenVarSym Name + | TokenConSym Name + | TokenData + | TokenPipe + | TokenEOF + deriving (Show) + +newtype P a = P { runP :: Text -> Either String a } + deriving (Functor) + +instance Applicative P where + pure = P . const . Right + + liftA2 f p q = P $ \s -> undefined + +instance Monad P where + m >>= k = P $ \s -> case runP m s of + Right a -> runP (k a) s + Left e -> Left e + +data Located a = Located AlexPosn a + deriving (Show) + +lexer :: (Located RlpToken -> P a) -> P a +lexer f = P $ \s -> case runAlex s ((,) <$> alexMonadScan <*> alexGetInput) of + Right (a,s') -> runP (f a) (s' ^. _4) + +} diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y new file mode 100644 index 0000000..efc5d22 --- /dev/null +++ b/src/Rlp/Parse.y @@ -0,0 +1,28 @@ +{ +module Rlp.Parse + ( + ) + where +import Rlp.Lex +} + +%name rlp +%monad { P } +%lexer { lexer } { Located _ TokenEOF } +%error { parseError } +%tokentype { Located RlpToken } + +%token + t { Located _ _ } + +%% + +P :: { () } +P : { error "aa" } + +{ + +parseError :: Located RlpToken -> P a +parseError = error "aaaaah" + +} -- 2.52.0 From aff1c6b4c698682a883c3b76816f9a030670861e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 11 Jan 2024 11:49:46 -0700 Subject: [PATCH 072/192] decent starting point --- .ghci | 2 ++ src/Rlp/Lex.x | 58 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 .ghci diff --git a/.ghci b/.ghci new file mode 100644 index 0000000..83c65a0 --- /dev/null +++ b/.ghci @@ -0,0 +1,2 @@ +:set -XOverloadedStrings + diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 893a487..34dd85f 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -9,6 +9,7 @@ module Rlp.Lex , lexer ) where +import Control.Monad import Data.Functor.Identity import Core.Syntax (Name) import Data.Text (Text) @@ -18,17 +19,32 @@ import Lens.Micro %wrapper "monad-strict-text" +$whitechar = [ \t\n\r\f\v] + rlp :- + + -- skip whitespace + $white+ ; + -- TODO: don't treat operators like (-->) as comments + "--".* ; + ";" { constToken TokenSemicolon } + "{" { constToken TokenLBrace } + "}" { constToken TokenRBrace } + <0> { "a" { const $ const $ pure $ Located (AlexPn 0 0 0) (TokenVarName "a") } - "" { undefined } } { -alexEOF :: Alex a -alexEOF = undefined +constToken :: RlpToken -> AlexAction (Located RlpToken) +constToken t inp _ = pure $ Located (inp ^. _1) t + +alexEOF :: Alex (Located RlpToken) +alexEOF = do + inp <- alexGetInput + pure (Located (inp ^. _1) TokenEOF) data RlpToken = TokenEquals | TokenLitInt Int @@ -38,27 +54,47 @@ data RlpToken = TokenEquals | TokenConSym Name | TokenData | TokenPipe + -- syntax control + | TokenSemicolon + | TokenLBrace + | TokenRBrace | TokenEOF deriving (Show) -newtype P a = P { runP :: Text -> Either String a } +newtype P a = P { runP :: PState -> Text -> Either String a } deriving (Functor) -instance Applicative P where - pure = P . const . Right +data PState = PState + { psLayoutStack :: [Layout] + } - liftA2 f p q = P $ \s -> undefined +data Layout = ExplicitLayout + | ImplicitLayout Int + deriving (Show) + +instance Applicative P where + pure = P . const . const . Right + + liftA2 = liftM2 instance Monad P where - m >>= k = P $ \s -> case runP m s of - Right a -> runP (k a) s + m >>= k = P $ \st s -> case runP m st s of + Right a -> runP (k a) st s Left e -> Left e data Located a = Located AlexPosn a deriving (Show) lexer :: (Located RlpToken -> P a) -> P a -lexer f = P $ \s -> case runAlex s ((,) <$> alexMonadScan <*> alexGetInput) of - Right (a,s') -> runP (f a) (s' ^. _4) +lexer f = P $ \st s -> case m s of + Right (a,s') -> runP (f a) st (s' ^. _4) + Left e -> error (show e) + where + m s = runAlex s ((,) <$> alexMonadScan <*> alexGetInput) + +lexStream :: P [RlpToken] +lexStream = lexer go where + go (Located _ TokenEOF) = pure [TokenEOF] + go (Located _ t) = (t:) <$> lexStream } -- 2.52.0 From 681a39431266551294a6f490c16c944acbd2c694 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 11 Jan 2024 16:26:34 -0700 Subject: [PATCH 073/192] man this sucks --- src/Rlp/Lex.x | 135 +++++++++++++++++++++++++++++++++++++----------- src/Rlp/Parse.y | 16 ++++-- 2 files changed, 118 insertions(+), 33 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 34dd85f..33489c2 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,5 +1,6 @@ { {-# LANGUAGE GeneralisedNewtypeDeriving #-} +{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex ( P(..) @@ -12,19 +13,34 @@ module Rlp.Lex import Control.Monad import Data.Functor.Identity import Core.Syntax (Name) +import Data.Monoid (First) import Data.Text (Text) import Data.Text qualified as T +import Lens.Micro.Mtl import Lens.Micro +import Lens.Micro.TH } -%wrapper "monad-strict-text" +%wrapper "monadUserState-strict-text" -$whitechar = [ \t\n\r\f\v] +$whitechar = [ \t\n\r\f\v] + +$lower = [a-z \_] +$upper = [A-Z] +$alpha = [$lower $upper] +$digit = 0-9 + +$nl = [\n\r] +$white_no_nl = $white # $nl + +$namechar = [$alpha $digit \' \#] + +@varname = $lower $namechar* rlp :- -- skip whitespace - $white+ ; + $white_no_nl+ ; -- TODO: don't treat operators like (-->) as comments "--".* ; ";" { constToken TokenSemicolon } @@ -33,7 +49,15 @@ rlp :- <0> { - "a" { const $ const $ pure $ Located (AlexPn 0 0 0) (TokenVarName "a") } + @varname { tokenWith TokenVarName } + "=" { constToken TokenEquals } +} + + +{ + $whitechar ; + \n ; + () { doBol } } { @@ -41,53 +65,71 @@ rlp :- constToken :: RlpToken -> AlexAction (Located RlpToken) constToken t inp _ = pure $ Located (inp ^. _1) t +tokenWith :: (Text -> RlpToken) -> AlexAction (Located RlpToken) +tokenWith tf (p,_,_,s) l = pure $ Located p (tf $ T.take l s) + alexEOF :: Alex (Located RlpToken) alexEOF = do inp <- alexGetInput pure (Located (inp ^. _1) TokenEOF) -data RlpToken = TokenEquals - | TokenLitInt Int - | TokenVarName Name - | TokenConName Name - | TokenVarSym Name - | TokenConSym Name - | TokenData - | TokenPipe - -- syntax control - | TokenSemicolon - | TokenLBrace - | TokenRBrace - | TokenEOF - deriving (Show) +data RlpToken + -- literals + = TokenLitInt Int + -- identifiers + | TokenVarName Name + | TokenConName Name + | TokenVarSym Name + | TokenConSym Name + -- keywords + | TokenData + | TokenPipe + | TokenLet + | TokenIn + -- control symbols + | TokenEquals + | TokenSemicolon + | TokenLBrace + | TokenRBrace + | TokenEOF + deriving (Show) -newtype P a = P { runP :: PState -> Text -> Either String a } +newtype P a = P { runP :: Text -> Either String a } deriving (Functor) -data PState = PState - { psLayoutStack :: [Layout] +data AlexUserState = AlexUserState + { _ausLayoutStack :: [Layout] } -data Layout = ExplicitLayout - | ImplicitLayout Int - deriving (Show) +alexInitUserState :: AlexUserState +alexInitUserState = AlexUserState + { _ausLayoutStack = [] + } + +data Layout = Explicit + | Implicit Int + deriving (Show, Eq) instance Applicative P where - pure = P . const . const . Right + pure = P . const . Right liftA2 = liftM2 instance Monad P where - m >>= k = P $ \st s -> case runP m st s of - Right a -> runP (k a) st s + m >>= k = P $ \s -> case runP m s of + Right a -> runP (k a) s Left e -> Left e data Located a = Located AlexPosn a deriving (Show) +ausLayoutStack :: Lens' AlexUserState [Layout] +ausLayoutStack = lens _ausLayoutStack + (\ s l -> s { _ausLayoutStack = l }) + lexer :: (Located RlpToken -> P a) -> P a -lexer f = P $ \st s -> case m s of - Right (a,s') -> runP (f a) st (s' ^. _4) +lexer f = P $ \s -> case m s of + Right (a,s') -> runP (f a) (s' ^. _4) Left e -> error (show e) where m s = runAlex s ((,) <$> alexMonadScan <*> alexGetInput) @@ -95,6 +137,39 @@ lexer f = P $ \st s -> case m s of lexStream :: P [RlpToken] lexStream = lexer go where go (Located _ TokenEOF) = pure [TokenEOF] - go (Located _ t) = (t:) <$> lexStream + go (Located _ t) = (t:) <$!> lexStream + +getsAus :: (AlexUserState -> b) -> Alex b +getsAus k = alexGetUserState <&> k + +useAus :: Getting a AlexUserState a -> Alex a +useAus l = do + aus <- alexGetUserState + pure (aus ^. l) + +preuseAus :: Getting (First a) AlexUserState a -> Alex (Maybe a) +preuseAus l = do + aus <- alexGetUserState + pure (aus ^? l) + +indentLevel :: Alex Int +indentLevel = do + inp <- alexGetInput + let col = inp ^. _1 + & \ (AlexPn _ _ c) -> c + pure col + +cmpLayout :: Alex Ordering +cmpLayout = do + i <- indentLevel + ctx <- preuseAus (ausLayoutStack . _head) + case ctx ^. non (Implicit 0) of + Implicit n -> pure (n `compare` i) + Explicit -> pure GT + +doBol :: AlexAction (Located RlpToken) +doBol _ _ = do + undefined } + diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index efc5d22..d136507 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -4,6 +4,8 @@ module Rlp.Parse ) where import Rlp.Lex +import Rlp.Syntax +import Rlp.Parse.Types } %name rlp @@ -13,12 +15,20 @@ import Rlp.Lex %tokentype { Located RlpToken } %token - t { Located _ _ } + varname { Located _ (TokenVarName $$) } + '=' { Located _ TokenEquals } + eof { Located _ TokenEOF } %% -P :: { () } -P : { error "aa" } +Decl :: { PartialDecl' } +Decl : FunDecl { undefined } + +FunDecl :: { PartialDecl' } +FunDecl : varname '=' Expr { undefined } + +Expr :: { RlpExpr' } +Expr : { undefined } { -- 2.52.0 From 2496589346deae800b5a0190c5bb05852bdb615c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 12 Jan 2024 17:53:53 -0700 Subject: [PATCH 074/192] aagh --- .ghci | 16 ++++++ Makefile_happysrcs | 19 +++++++ src/.DS_Store | Bin 0 -> 6148 bytes src/Rlp/Lex.x | 125 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 Makefile_happysrcs create mode 100644 src/.DS_Store diff --git a/.ghci b/.ghci index 83c65a0..4d96080 100644 --- a/.ghci +++ b/.ghci @@ -1,2 +1,18 @@ :set -XOverloadedStrings +:set -package process + +:{ +import System.Exit qualified +import System.Process qualified + +_reload_and_make _ = do + p <- System.Process.spawnCommand "make -f Makefile_happysrcs" + r <- System.Process.waitForProcess p + case r of + System.Exit.ExitSuccess -> pure ":reload" + _ -> pure "" +:} + +:def! r _reload_and_make + diff --git a/Makefile_happysrcs b/Makefile_happysrcs new file mode 100644 index 0000000..2baa703 --- /dev/null +++ b/Makefile_happysrcs @@ -0,0 +1,19 @@ +HAPPY = happy +HAPPY_OPTS = +ALEX = alex +ALEX_OPTS = + +SRC = src +CABAL_BUILD = dist-newstyle/build/x86_64-osx/ghc-9.6.2/rlp-0.1.0.0/build + +all: parsers lexers + +parsers: $(CABAL_BUILD)/Rlp/Parse.hs +lexers: $(CABAL_BUILD)/Rlp/Lex.hs + +$(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y + $(HAPPY) $(HAPPY_OPTS) $< -o $@ + +$(CABAL_BUILD)/Rlp/Lex.hs: $(SRC)/Rlp/Lex.x + $(ALEX) $(ALEX_OPTS) $< -o $@ + diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2f1be0865f62a73b132a62e86953f60eef47401f GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8z45|#6fRTZLfrY`DA)ld$A+;>HC@&{JFCCbS3Ltr!nhHD5gvbY4hIDsln96kiqxd~7? z5F1n#GlJ@9h#qiN3~K~1K?W2hpvpnjJ-8}nWPsG) as comments "--".* ; ";" { constToken TokenSemicolon } - "{" { constToken TokenLBrace } - "}" { constToken TokenRBrace } + "{" { explicitLBrace } + "}" { explicitRBrace } <0> { + $whitechar+ ; + \n ; + "{" { expectLBrace } +} + + +{ + \n { begin bol } @varname { tokenWith TokenVarName } "=" { constToken TokenEquals } } +-- consume all whitespace leaving us at the beginning of the next non-empty +-- line. we then compare the indentation of that line to the enclosing layout +-- context and proceed accordingly { $whitechar ; @@ -91,15 +105,27 @@ data RlpToken | TokenSemicolon | TokenLBrace | TokenRBrace + -- 'virtual' control symbols, implicitly inserted by the lexer + | TokenSemicolonV + | TokenLBraceV + | TokenRBraceV | TokenEOF deriving (Show) -newtype P a = P { runP :: Text -> Either String a } +newtype P a = P { + runP :: AlexUserState -> Text -> Either String (AlexUserState, a) + } deriving (Functor) +runPInit :: P a -> Text -> Either String (AlexUserState, a) +runPInit p = runP p alexInitUserState + data AlexUserState = AlexUserState - { _ausLayoutStack :: [Layout] + -- the layout context, along with a start code to return to when the layout + -- ends + { _ausLayoutStack :: [(Layout, Int)] } + deriving Show alexInitUserState :: AlexUserState alexInitUserState = AlexUserState @@ -111,34 +137,40 @@ data Layout = Explicit deriving (Show, Eq) instance Applicative P where - pure = P . const . Right + pure a = P $ \st _ -> Right (st,a) liftA2 = liftM2 instance Monad P where - m >>= k = P $ \s -> case runP m s of - Right a -> runP (k a) s - Left e -> Left e + m >>= k = P $ \st s -> case runP m st s of + Right (st',a) -> runP (k a) st' s + Left e -> Left e data Located a = Located AlexPosn a deriving (Show) -ausLayoutStack :: Lens' AlexUserState [Layout] +ausLayoutStack :: Lens' AlexUserState [(Layout, Int)] ausLayoutStack = lens _ausLayoutStack (\ s l -> s { _ausLayoutStack = l }) lexer :: (Located RlpToken -> P a) -> P a -lexer f = P $ \s -> case m s of - Right (a,s') -> runP (f a) (s' ^. _4) - Left e -> error (show e) +lexer f = P $ \st s -> case m st s of + Right (a,st',s') -> runP (f a) st' (s' ^. _4) + Left e -> error (show e) where - m s = runAlex s ((,) <$> alexMonadScan <*> alexGetInput) + m st s = runAlex s + ((,,) <$> (alexSetUserState st *> alexMonadScan) + <*> alexGetUserState + <*> alexGetInput) lexStream :: P [RlpToken] lexStream = lexer go where go (Located _ TokenEOF) = pure [TokenEOF] go (Located _ t) = (t:) <$!> lexStream +lexToken :: Alex (Located RlpToken) +lexToken = alexMonadScan + getsAus :: (AlexUserState -> b) -> Alex b getsAus k = alexGetUserState <&> k @@ -152,6 +184,11 @@ preuseAus l = do aus <- alexGetUserState pure (aus ^? l) +modifyingAus :: ASetter' AlexUserState a -> (a -> a) -> Alex () +modifyingAus l f = do + aus <- alexGetUserState + alexSetUserState (aus & l %~ f) + indentLevel :: Alex Int indentLevel = do inp <- alexGetInput @@ -163,13 +200,67 @@ cmpLayout :: Alex Ordering cmpLayout = do i <- indentLevel ctx <- preuseAus (ausLayoutStack . _head) - case ctx ^. non (Implicit 0) of - Implicit n -> pure (n `compare` i) + case (ctx <&> fst) ^. non (Implicit 1) of + Implicit n -> pure (i `compare` n) Explicit -> pure GT +insertToken :: RlpToken -> Alex (Located RlpToken) +insertToken t = do + inp <- alexGetInput + pure (Located (inp ^. _1) t) + +insertSemicolon, insertLBrace, insertRBrace :: Alex (Located RlpToken) +insertSemicolon = insertToken TokenSemicolonV +insertLBrace = insertToken TokenLBraceV +insertRBrace = insertToken TokenRBraceV + +-- pop the layout stack and jump to the popped return code +popLayout :: Alex () +popLayout = do + ctx <- preuseAus (ausLayoutStack . _head) + modifyingAus ausLayoutStack (drop 1) + case ctx of + Just (l,c) -> alexSetStartCode c + Nothing -> pure () + +pushLayout :: Layout -> Alex () +pushLayout l = do + c <- alexGetStartCode + modifyingAus ausLayoutStack ((l,c):) + doBol :: AlexAction (Located RlpToken) -doBol _ _ = do - undefined +doBol inp len = do + off <- cmpLayout + case off of + -- the line is aligned with the previous. it therefore belongs to the + -- same list + EQ -> insertSemicolon + -- the line is indented further than the previous, so we assume it is a + -- line continuation. ignore it and move on! + GT -> undefined -- alexSetStartCode one >> lexToken + -- the line is indented less than the previous, pop the layout stack and + -- insert a closing brace. + LT -> popLayout >> insertRBrace >> alexSetStartCode 0 >> lexToken + +explicitLBrace, explicitRBrace :: AlexAction (Located RlpToken) + +explicitLBrace _ _ = do + pushLayout Explicit + insertToken TokenLBrace + +explicitRBrace _ _ = do + popLayout + insertToken TokenRBrace + +doLayout :: AlexAction (Located RlpToken) +doLayout _ _ = do + i <- indentLevel + pushLayout (Implicit i) + insertLBrace + +expectLBrace :: AlexAction (Located RlpToken) +expectLBrace _ _ = do + off <- cmpLayout } -- 2.52.0 From e597ecbfc643f9137e8892965f8e898b7a881f75 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 14 Jan 2024 14:20:08 -0700 Subject: [PATCH 075/192] okay layouts kinda --- Makefile_happysrcs | 2 +- rlp.cabal | 1 + src/.DS_Store | Bin 6148 -> 6148 bytes src/Rlp/Lex.x | 98 +++++++++++++++++++++++++-------------------- src/Rlp/Parse.y | 2 +- 5 files changed, 58 insertions(+), 45 deletions(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index 2baa703..35c2ca8 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -1,7 +1,7 @@ HAPPY = happy HAPPY_OPTS = ALEX = alex -ALEX_OPTS = +ALEX_OPTS = -d SRC = src CABAL_BUILD = dist-newstyle/build/x86_64-osx/ghc-9.6.2/rlp-0.1.0.0/build diff --git a/rlp.cabal b/rlp.cabal index e6b81a9..411434b 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -50,6 +50,7 @@ library -- required for happy , array , data-default-class + , data-default , unordered-containers , hashable , pretty diff --git a/src/.DS_Store b/src/.DS_Store index 2f1be0865f62a73b132a62e86953f60eef47401f..4390780d02bbee1b3430a6fac093424b3e29cf90 100644 GIT binary patch delta 306 zcmZoMXfc=|#>B`mu~3YagMop8V`8C*EE59+fM`Yr1_6eo^5TM|octsP28Qhu3zye} zBv=@n8S)v57*dfXlL~S&i%Sd)t}!w(v#_$UbFg!8bHoN`r7fQWN`UP)qRUTP6YNpNOLYEoiROn7EqN`ARheraAxF<5VKW*}IG zgOh_ZUO>FM+RVgQN5RmjR!5=Q%*a$n!Q9lSww9AaR9W9TC_XzUH!r^v;vYsv2+hC? yrD0UpL>=jk>4I#N4MbQrb8~QWFfnp$Ed0(qnO{Va735ik$%Z1rn>|GKFarRGc1u10 delta 82 zcmZoMXfc=|#>AjHu~3+iaq?|OX+b6i2w-GjU|?im5MbE+oKb;ovj9^+<7RdaehwxE e)y<4d-) as comments "--".* ; ";" { constToken TokenSemicolon } - "{" { explicitLBrace } - "}" { explicitRBrace } + -- "{" { explicitLBrace } + -- "}" { explicitRBrace } <0> { - $whitechar+ ; \n ; - "{" { expectLBrace } + "{" { explicitLBrace `thenBegin` one } + () { doLayout `thenBegin` one } } { - \n { begin bol } @varname { tokenWith TokenVarName } "=" { constToken TokenEquals } + \n { begin bol } } -- consume all whitespace leaving us at the beginning of the next non-empty @@ -71,11 +73,19 @@ rlp :- { $whitechar ; \n ; - () { doBol } + () { doBol `andBegin` one } } { +-- | @andBegin@, with the subtle difference that the start code is set +-- /after/ the action +thenBegin :: AlexAction a -> Int -> AlexAction a +thenBegin act c inp l = do + a <- act inp l + alexSetStartCode c + pure a + constToken :: RlpToken -> AlexAction (Located RlpToken) constToken t inp _ = pure $ Located (inp ^. _1) t @@ -105,20 +115,33 @@ data RlpToken | TokenSemicolon | TokenLBrace | TokenRBrace - -- 'virtual' control symbols, implicitly inserted by the lexer + -- 'virtual' control symbols, inserted by the lexer without any correlation + -- to a specific symbol | TokenSemicolonV | TokenLBraceV | TokenRBraceV | TokenEOF deriving (Show) -newtype P a = P { - runP :: AlexUserState -> Text -> Either String (AlexUserState, a) - } +newtype P a = P { runP :: ParseState -> Alex (ParseState, a) } deriving (Functor) -runPInit :: P a -> Text -> Either String (AlexUserState, a) -runPInit p = runP p alexInitUserState +execP :: P a -> ParseState -> Text -> Either String a +execP p st s = snd <$> runAlex s (runP p st) + +data ParseState = ParseState { } + +instance Default ParseState where + def = ParseState { } + +instance Applicative P where + pure a = P $ \st -> pure (st,a) + liftA2 = liftM2 + +instance Monad P where + p >>= k = P $ \st -> do + (st',a) <- runP p st + runP (k a) st' data AlexUserState = AlexUserState -- the layout context, along with a start code to return to when the layout @@ -136,16 +159,6 @@ data Layout = Explicit | Implicit Int deriving (Show, Eq) -instance Applicative P where - pure a = P $ \st _ -> Right (st,a) - - liftA2 = liftM2 - -instance Monad P where - m >>= k = P $ \st s -> case runP m st s of - Right (st',a) -> runP (k a) st' s - Left e -> Left e - data Located a = Located AlexPosn a deriving (Show) @@ -153,20 +166,21 @@ ausLayoutStack :: Lens' AlexUserState [(Layout, Int)] ausLayoutStack = lens _ausLayoutStack (\ s l -> s { _ausLayoutStack = l }) -lexer :: (Located RlpToken -> P a) -> P a -lexer f = P $ \st s -> case m st s of - Right (a,st',s') -> runP (f a) st' (s' ^. _4) - Left e -> error (show e) - where - m st s = runAlex s - ((,,) <$> (alexSetUserState st *> alexMonadScan) - <*> alexGetUserState - <*> alexGetInput) +lexer :: P (Located RlpToken) +lexer = P $ \st -> (st,) <$> lexToken -lexStream :: P [RlpToken] -lexStream = lexer go where - go (Located _ TokenEOF) = pure [TokenEOF] - go (Located _ t) = (t:) <$!> lexStream +lexerCont :: (Located RlpToken -> P a) -> P a +lexerCont = (lexer >>=) + +lexStream :: Alex [RlpToken] +lexStream = do + t <- lexToken + case t of + Located _ TokenEOF -> pure [TokenEOF] + Located _ a -> (a:) <$> lexStream + +lexTest :: Text -> Either String [RlpToken] +lexTest = flip runAlex lexStream lexToken :: Alex (Located RlpToken) lexToken = alexMonadScan @@ -210,13 +224,14 @@ insertToken t = do pure (Located (inp ^. _1) t) insertSemicolon, insertLBrace, insertRBrace :: Alex (Located RlpToken) -insertSemicolon = insertToken TokenSemicolonV -insertLBrace = insertToken TokenLBraceV -insertRBrace = insertToken TokenRBraceV +insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV +insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV +insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV -- pop the layout stack and jump to the popped return code popLayout :: Alex () popLayout = do + traceM "pop layout" ctx <- preuseAus (ausLayoutStack . _head) modifyingAus ausLayoutStack (drop 1) case ctx of @@ -225,6 +240,7 @@ popLayout = do pushLayout :: Layout -> Alex () pushLayout l = do + traceM "push layout" c <- alexGetStartCode modifyingAus ausLayoutStack ((l,c):) @@ -240,7 +256,7 @@ doBol inp len = do GT -> undefined -- alexSetStartCode one >> lexToken -- the line is indented less than the previous, pop the layout stack and -- insert a closing brace. - LT -> popLayout >> insertRBrace >> alexSetStartCode 0 >> lexToken + LT -> insertRBrace >> popLayout >> lexToken explicitLBrace, explicitRBrace :: AlexAction (Located RlpToken) @@ -258,9 +274,5 @@ doLayout _ _ = do pushLayout (Implicit i) insertLBrace -expectLBrace :: AlexAction (Located RlpToken) -expectLBrace _ _ = do - off <- cmpLayout - } diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index d136507..3016594 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -10,7 +10,7 @@ import Rlp.Parse.Types %name rlp %monad { P } -%lexer { lexer } { Located _ TokenEOF } +%lexer { lexerCont } { Located _ TokenEOF } %error { parseError } %tokentype { Located RlpToken } -- 2.52.0 From 17ddf3530cc114871ddea53637bf1e5f8d06bc75 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 14 Jan 2024 18:19:37 -0700 Subject: [PATCH 076/192] kitten i'll be honest mommy's about to kill herself --- src/Rlp/Lex.x | 210 +++++++++++----------------------- src/Rlp/Lex.x.old | 280 ++++++++++++++++++++++++++++++++++++++++++++++ src/Rlp/Parse.y | 44 +++++++- src/Rlp/Syntax.hs | 4 + 4 files changed, 390 insertions(+), 148 deletions(-) create mode 100644 src/Rlp/Lex.x.old diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 324fb19..9d41eb4 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -6,18 +6,19 @@ module Rlp.Lex ( P(..) , RlpToken(..) , Located(..) - , AlexPosn , lexer , lexerCont ) where import Control.Monad import Data.Functor.Identity +import Data.Char (digitToInt) import Core.Syntax (Name) import Data.Monoid (First) import Data.Maybe import Data.Text (Text) import Data.Text qualified as T +import Data.Word import Data.Default import Lens.Micro.Mtl import Lens.Micro @@ -26,8 +27,6 @@ import Lens.Micro.TH import Debug.Trace } -%wrapper "monadUserState-strict-text" - $whitechar = [ \t\n\r\f\v] $lower = [a-z \_] @@ -42,6 +41,8 @@ $namechar = [$alpha $digit \' \#] @varname = $lower $namechar* +@digits = $digit+ + rlp :- -- skip whitespace @@ -54,14 +55,13 @@ rlp :- <0> { - \n ; - "{" { explicitLBrace `thenBegin` one } - () { doLayout `thenBegin` one } + \n { begin bol } } { @varname { tokenWith TokenVarName } + @digits { tokenWith (TokenLitInt . readInt) } "=" { constToken TokenEquals } \n { begin bol } } @@ -73,29 +73,50 @@ rlp :- { $whitechar ; \n ; - () { doBol `andBegin` one } + () { doBol } } { +begin = undefined + +type LexerAction a = AlexInput -> Int -> P a + +type AlexInput = + ( Char -- prev char + , Text -- input + ) + +alexGetByte :: AlexInput -> Maybe (Word8, AlexInput) +alexGetByte (_,s) = undefined + +getInput :: P AlexInput +getInput = undefined + +alexInputPrevChar :: AlexInput -> Char +alexInputPrevChar = (^. _1) + +readInt :: Text -> Int +readInt = T.foldr f 0 where + f c n = digitToInt c + 10*n + -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action -thenBegin :: AlexAction a -> Int -> AlexAction a +thenBegin :: LexerAction a -> Int -> LexerAction a thenBegin act c inp l = do a <- act inp l - alexSetStartCode c - pure a + undefined -constToken :: RlpToken -> AlexAction (Located RlpToken) -constToken t inp _ = pure $ Located (inp ^. _1) t +constToken :: RlpToken -> LexerAction (Located RlpToken) +constToken t inp _ = undefined -tokenWith :: (Text -> RlpToken) -> AlexAction (Located RlpToken) -tokenWith tf (p,_,_,s) l = pure $ Located p (tf $ T.take l s) +tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) +tokenWith tf inp l = undefined -alexEOF :: Alex (Located RlpToken) +alexEOF :: P (Located RlpToken) alexEOF = do - inp <- alexGetInput - pure (Located (inp ^. _1) TokenEOF) + inp <- getInput + pure (Located undefined TokenEOF) data RlpToken -- literals @@ -123,156 +144,59 @@ data RlpToken | TokenEOF deriving (Show) -newtype P a = P { runP :: ParseState -> Alex (ParseState, a) } +newtype P a = P { runP :: ParseState -> (ParseState, Maybe a) } deriving (Functor) -execP :: P a -> ParseState -> Text -> Either String a -execP p st s = snd <$> runAlex s (runP p st) +execP :: P a -> ParseState -> Either String a +execP p st = undefined -data ParseState = ParseState { } +execP' :: P a -> Text -> Either String a +execP' p s = execP p st where + st = initParseState s -instance Default ParseState where - def = ParseState { } +initParseState :: Text -> ParseState +initParseState s = ParseState + { _psLayoutStack = [] + , _psLexState = [bol,0] + , _psInput = (undefined, s) + } + +data ParseState = ParseState + { _psLayoutStack :: [Layout] + , _psLexState :: [Int] + , _psInput :: AlexInput + } instance Applicative P where - pure a = P $ \st -> pure (st,a) + pure a = P $ \st -> (st,Just a) liftA2 = liftM2 instance Monad P where - p >>= k = P $ \st -> do - (st',a) <- runP p st - runP (k a) st' - -data AlexUserState = AlexUserState - -- the layout context, along with a start code to return to when the layout - -- ends - { _ausLayoutStack :: [(Layout, Int)] - } - deriving Show - -alexInitUserState :: AlexUserState -alexInitUserState = AlexUserState - { _ausLayoutStack = [] - } + p >>= k = undefined data Layout = Explicit | Implicit Int deriving (Show, Eq) -data Located a = Located AlexPosn a +data Located a = Located (Int, Int) a deriving (Show) -ausLayoutStack :: Lens' AlexUserState [(Layout, Int)] -ausLayoutStack = lens _ausLayoutStack - (\ s l -> s { _ausLayoutStack = l }) - lexer :: P (Located RlpToken) -lexer = P $ \st -> (st,) <$> lexToken +lexer = undefined lexerCont :: (Located RlpToken -> P a) -> P a -lexerCont = (lexer >>=) +lexerCont = undefined -lexStream :: Alex [RlpToken] -lexStream = do - t <- lexToken - case t of - Located _ TokenEOF -> pure [TokenEOF] - Located _ a -> (a:) <$> lexStream +lexStream :: P [RlpToken] +lexStream = undefined lexTest :: Text -> Either String [RlpToken] -lexTest = flip runAlex lexStream +lexTest = undefined -lexToken :: Alex (Located RlpToken) -lexToken = alexMonadScan +lexToken :: P (Located RlpToken) +lexToken = undefined -getsAus :: (AlexUserState -> b) -> Alex b -getsAus k = alexGetUserState <&> k - -useAus :: Getting a AlexUserState a -> Alex a -useAus l = do - aus <- alexGetUserState - pure (aus ^. l) - -preuseAus :: Getting (First a) AlexUserState a -> Alex (Maybe a) -preuseAus l = do - aus <- alexGetUserState - pure (aus ^? l) - -modifyingAus :: ASetter' AlexUserState a -> (a -> a) -> Alex () -modifyingAus l f = do - aus <- alexGetUserState - alexSetUserState (aus & l %~ f) - -indentLevel :: Alex Int -indentLevel = do - inp <- alexGetInput - let col = inp ^. _1 - & \ (AlexPn _ _ c) -> c - pure col - -cmpLayout :: Alex Ordering -cmpLayout = do - i <- indentLevel - ctx <- preuseAus (ausLayoutStack . _head) - case (ctx <&> fst) ^. non (Implicit 1) of - Implicit n -> pure (i `compare` n) - Explicit -> pure GT - -insertToken :: RlpToken -> Alex (Located RlpToken) -insertToken t = do - inp <- alexGetInput - pure (Located (inp ^. _1) t) - -insertSemicolon, insertLBrace, insertRBrace :: Alex (Located RlpToken) -insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV -insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV -insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV - --- pop the layout stack and jump to the popped return code -popLayout :: Alex () -popLayout = do - traceM "pop layout" - ctx <- preuseAus (ausLayoutStack . _head) - modifyingAus ausLayoutStack (drop 1) - case ctx of - Just (l,c) -> alexSetStartCode c - Nothing -> pure () - -pushLayout :: Layout -> Alex () -pushLayout l = do - traceM "push layout" - c <- alexGetStartCode - modifyingAus ausLayoutStack ((l,c):) - -doBol :: AlexAction (Located RlpToken) -doBol inp len = do - off <- cmpLayout - case off of - -- the line is aligned with the previous. it therefore belongs to the - -- same list - EQ -> insertSemicolon - -- the line is indented further than the previous, so we assume it is a - -- line continuation. ignore it and move on! - GT -> undefined -- alexSetStartCode one >> lexToken - -- the line is indented less than the previous, pop the layout stack and - -- insert a closing brace. - LT -> insertRBrace >> popLayout >> lexToken - -explicitLBrace, explicitRBrace :: AlexAction (Located RlpToken) - -explicitLBrace _ _ = do - pushLayout Explicit - insertToken TokenLBrace - -explicitRBrace _ _ = do - popLayout - insertToken TokenRBrace - -doLayout :: AlexAction (Located RlpToken) -doLayout _ _ = do - i <- indentLevel - pushLayout (Implicit i) - insertLBrace +doBol = undefined } diff --git a/src/Rlp/Lex.x.old b/src/Rlp/Lex.x.old new file mode 100644 index 0000000..533c94c --- /dev/null +++ b/src/Rlp/Lex.x.old @@ -0,0 +1,280 @@ +{ +{-# LANGUAGE GeneralisedNewtypeDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE OverloadedStrings #-} +module Rlp.Lex + ( P(..) + , RlpToken(..) + , Located(..) + , AlexPosn + , lexer + , lexerCont + ) + where +import Control.Monad +import Data.Functor.Identity +import Data.Char (digitToInt) +import Core.Syntax (Name) +import Data.Monoid (First) +import Data.Maybe +import Data.Text (Text) +import Data.Text qualified as T +import Data.Default +import Lens.Micro.Mtl +import Lens.Micro +import Lens.Micro.TH + +import Debug.Trace +} + +$whitechar = [ \t\n\r\f\v] + +$lower = [a-z \_] +$upper = [A-Z] +$alpha = [$lower $upper] +$digit = 0-9 + +$nl = [\n\r] +$white_no_nl = $white # $nl + +$namechar = [$alpha $digit \' \#] + +@varname = $lower $namechar* + +@digits = $digit+ + +rlp :- + + -- skip whitespace + $white_no_nl+ ; + -- TODO: don't treat operators like (-->) as comments + "--".* ; + ";" { constToken TokenSemicolon } + -- "{" { explicitLBrace } + -- "}" { explicitRBrace } + +<0> +{ + \n { begin bol } +} + + +{ + @varname { tokenWith TokenVarName } + @digits { tokenWith (TokenLitInt . readInt) } + "=" { constToken TokenEquals } + \n { begin bol } +} + +-- consume all whitespace leaving us at the beginning of the next non-empty +-- line. we then compare the indentation of that line to the enclosing layout +-- context and proceed accordingly + +{ + $whitechar ; + \n ; + () { doBol `andBegin` one } +} + +{ + +readInt :: Text -> Int +readInt = T.foldr f 0 where + f c n = digitToInt c + 10*n + +-- | @andBegin@, with the subtle difference that the start code is set +-- /after/ the action +thenBegin :: AlexAction a -> Int -> AlexAction a +thenBegin act c inp l = do + a <- act inp l + alexSetStartCode c + pure a + +constToken :: RlpToken -> AlexAction (Located RlpToken) +constToken t inp _ = pure $ Located (inp ^. _1) t + +tokenWith :: (Text -> RlpToken) -> AlexAction (Located RlpToken) +tokenWith tf (p,_,_,s) l = pure $ Located p (tf $ T.take l s) + +alexEOF :: Alex (Located RlpToken) +alexEOF = do + inp <- alexGetInput + pure (Located (inp ^. _1) TokenEOF) + +data RlpToken + -- literals + = TokenLitInt Int + -- identifiers + | TokenVarName Name + | TokenConName Name + | TokenVarSym Name + | TokenConSym Name + -- keywords + | TokenData + | TokenPipe + | TokenLet + | TokenIn + -- control symbols + | TokenEquals + | TokenSemicolon + | TokenLBrace + | TokenRBrace + -- 'virtual' control symbols, inserted by the lexer without any correlation + -- to a specific symbol + | TokenSemicolonV + | TokenLBraceV + | TokenRBraceV + | TokenEOF + deriving (Show) + +newtype P a = P { runP :: ParseState -> Alex (ParseState, Maybe a) } + deriving (Functor) + +execP :: P a -> ParseState -> Text -> Either String a +execP p st s = snd <$> runAlex s (runP p st) + +execP' :: P a -> Text -> Either String a +execP' p = execP p def + +data ParseState = ParseState + { _psLayoutStack :: [Layout] + , _psLexState :: [Int] + } + +instance Default ParseState where + def = ParseState { } + +instance Applicative P where + pure a = P $ \st -> pure (st,a) + liftA2 = liftM2 + +instance Monad P where + p >>= k = P $ \st -> do + (st',a) <- runP p st + runP (k a) st' + +data Layout = Explicit + | Implicit Int + deriving (Show, Eq) + +data Located a = Located AlexPosn a + deriving (Show) + +psLayoutStack :: Lens' AlexUserState [Layout] +psLayoutStack = lens _psLayoutStack + (\ s l -> s { _psLayoutStack = l }) + +lexer :: P (Located RlpToken) +lexer = P $ \st -> (st,) <$> lexToken + +lexerCont :: (Located RlpToken -> P a) -> P a +lexerCont = (lexer >>=) + +lexStream :: Alex [RlpToken] +lexStream = do + t <- lexToken + case t of + Located _ TokenEOF -> pure [TokenEOF] + Located _ a -> (a:) <$> lexStream + +lexTest :: Text -> Either String [RlpToken] +lexTest = flip runAlex lexStream + +lexToken :: Alex (Located RlpToken) +lexToken = alexMonadScan + +getsAus :: (AlexUserState -> b) -> Alex b +getsAus k = alexGetUserState <&> k + +useAus :: Getting a AlexUserState a -> Alex a +useAus l = do + aus <- alexGetUserState + pure (aus ^. l) + +preuseAus :: Getting (First a) AlexUserState a -> Alex (Maybe a) +preuseAus l = do + aus <- alexGetUserState + pure (aus ^? l) + +modifyingAus :: ASetter' AlexUserState a -> (a -> a) -> Alex () +modifyingAus l f = do + aus <- alexGetUserState + alexSetUserState (aus & l %~ f) + +indentLevel :: Alex Int +indentLevel = do + inp <- alexGetInput + let col = inp ^. _1 + & \ (AlexPn _ _ c) -> c + pure col + +cmpLayout :: Alex Ordering +cmpLayout = do + i <- indentLevel + ctx <- preuseAus (ausLayoutStack . _head) + case ctx ^. non (Implicit 1) of + Implicit n -> pure (i `compare` n) + Explicit -> pure GT + +insertToken :: RlpToken -> Alex (Located RlpToken) +insertToken t = do + inp <- alexGetInput + pure (Located (inp ^. _1) t) + +insertSemicolon, insertLBrace, insertRBrace :: Alex (Located RlpToken) +insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV +insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV +insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV + +-- pop the layout stack and jump to the popped return code +popLayout :: Alex Layout +popLayout = do + traceM "pop layout" + ctx <- preuseAus (ausLayoutStack . _head) + modifyingAus ausLayoutStack (drop 1) + case ctx of + Just l -> pure l + Nothing -> error "uhh" + +pushLayout :: Layout -> Alex () +pushLayout l = do + traceM "push layout" + modifyingAus ausLayoutStack (l:) + +pushLexState :: Alex () +pushLexState = do + undefined + +doBol :: AlexAction (Located RlpToken) +doBol inp len = do + off <- cmpLayout + case off of + -- the line is aligned with the previous. it therefore belongs to the + -- same list + EQ -> insertSemicolon + -- the line is indented further than the previous, so we assume it is a + -- line continuation. ignore it and move on! + GT -> undefined -- alexSetStartCode one >> lexToken + -- the line is indented less than the previous, pop the layout stack and + -- insert a closing brace. + LT -> popLayout >> insertRBrace + +explicitLBrace, explicitRBrace :: AlexAction (Located RlpToken) + +explicitLBrace _ _ = do + pushLayout Explicit + insertToken TokenLBrace + +explicitRBrace _ _ = do + popLayout + insertToken TokenRBrace + +doLayout :: AlexAction (Located RlpToken) +doLayout _ _ = do + i <- indentLevel + pushLayout (Implicit i) + traceM $ "layout " <> show i + insertLBrace + +} + diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 3016594..3205988 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -1,6 +1,6 @@ { module Rlp.Parse - ( + ( parseRlpProgram ) where import Rlp.Lex @@ -8,7 +8,8 @@ import Rlp.Syntax import Rlp.Parse.Types } -%name rlp +%name parseRlpProgram StandaloneProgram + %monad { P } %lexer { lexerCont } { Located _ TokenEOF } %error { parseError } @@ -16,23 +17,56 @@ import Rlp.Parse.Types %token varname { Located _ (TokenVarName $$) } + litint { Located _ (TokenLitInt $$) } '=' { Located _ TokenEquals } + ';' { Located _ TokenSemicolon } + ';?' { Located _ TokenSemicolonV } + '{' { Located _ TokenLBrace } + '}' { Located _ TokenRBrace } + '{?' { Located _ TokenLBraceV } + '?}' { Located _ TokenRBraceV } eof { Located _ TokenEOF } %% +StandaloneProgram :: { [PartialDecl'] } +StandaloneProgram : VL Decls VR eof { $2 } + +VL :: { () } +VL : '{?' { () } + +VR :: { () } +VR : '?}' { () } + | error { () } + +Decls :: { [PartialDecl'] } +Decls : Decl Semi Decls { $1 : $3 } + | Decl Semi { [$1] } + | Decl { [$1] } + +Semi :: { Located RlpToken } +Semi : ';' { $1 } + | ';?' { $1 } + Decl :: { PartialDecl' } Decl : FunDecl { undefined } FunDecl :: { PartialDecl' } FunDecl : varname '=' Expr { undefined } -Expr :: { RlpExpr' } -Expr : { undefined } +Expr :: { RlpExpr' } +Expr : Literal { LitE $1 } + | Var { VarE $1 } + +Literal :: { Lit' } +Literal : litint { IntL $1 } + +Var :: { VarId } +Var : varname { NameVar $1 } { parseError :: Located RlpToken -> P a -parseError = error "aaaaah" +parseError = error . show } diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 58843b5..bf35445 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -5,6 +5,8 @@ {-# LANGUAGE OverloadedStrings, PatternSynonyms #-} module Rlp.Syntax ( RlpModule(..) + , RlpProgram(..) + , RlpProgram' , rlpmodName , rlpmodProgram , RlpExpr(..) @@ -54,6 +56,8 @@ data RlpModule b = RlpModule newtype RlpProgram b = RlpProgram [Decl RlpExpr b] +type RlpProgram' = RlpProgram Name + -- | The @e@ parameter is used for partial results. When parsing an input, we -- first parse all top-level declarations in order to extract infix[lr] -- declarations. This process yields a @[Decl (Const Text) Name]@, where @Const -- 2.52.0 From 6390ca80d892674c034a3285450a93648c0fa334 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 14 Jan 2024 22:57:36 -0700 Subject: [PATCH 077/192] see previous commit and scale back the part where i'm joking --- rlp.cabal | 1 + src/Rlp/Lex.x | 177 +++++++++++-------- src/Rlp/Parse/Decls.hs | 381 ----------------------------------------- src/Rlp/Parse/Types.hs | 142 +++++++++------ src/Rlp/Parse/Utils.hs | 30 ---- 5 files changed, 189 insertions(+), 542 deletions(-) delete mode 100644 src/Rlp/Parse/Decls.hs delete mode 100644 src/Rlp/Parse/Utils.hs diff --git a/rlp.cabal b/rlp.cabal index 411434b..5d3fa6a 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -60,6 +60,7 @@ library , megaparsec ^>=9.6.0 , text , data-fix + , utf8-string hs-source-dirs: src default-language: GHC2021 diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 9d41eb4..d81e432 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,19 +1,19 @@ { {-# LANGUAGE GeneralisedNewtypeDeriving #-} -{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex ( P(..) , RlpToken(..) , Located(..) - , lexer + , lexToken , lexerCont ) where +import Codec.Binary.UTF8.String (encodeChar) import Control.Monad +import Core.Syntax (Name) import Data.Functor.Identity import Data.Char (digitToInt) -import Core.Syntax (Name) import Data.Monoid (First) import Data.Maybe import Data.Text (Text) @@ -22,9 +22,9 @@ import Data.Word import Data.Default import Lens.Micro.Mtl import Lens.Micro -import Lens.Micro.TH import Debug.Trace +import Rlp.Parse.Types } $whitechar = [ \t\n\r\f\v] @@ -78,23 +78,31 @@ rlp :- { +begin :: Int -> LexerAction a begin = undefined -type LexerAction a = AlexInput -> Int -> P a - -type AlexInput = - ( Char -- prev char - , Text -- input - ) - alexGetByte :: AlexInput -> Maybe (Word8, AlexInput) -alexGetByte (_,s) = undefined +alexGetByte inp = case inp ^. aiBytes of + [] -> do + (c,t) <- T.uncons (inp ^. aiSource) + let (b:bs) = encodeChar c + inp' = inp & aiSource .~ t + & aiBytes .~ bs + & aiPrevChar .~ c + pure (b, inp') + + _ -> Just (head bs, inp') + where + (bs, inp') = inp & aiBytes <<%~ drop 1 getInput :: P AlexInput -getInput = undefined +getInput = use psInput + +getLexState :: P Int +getLexState = use (psLexState . singular _head) alexInputPrevChar :: AlexInput -> Char -alexInputPrevChar = (^. _1) +alexInputPrevChar = view aiPrevChar readInt :: Text -> Int readInt = T.foldr f 0 where @@ -108,95 +116,116 @@ thenBegin act c inp l = do undefined constToken :: RlpToken -> LexerAction (Located RlpToken) -constToken t inp _ = undefined +constToken t inp l = do + pos <- use (psInput . aiPos) + pure (Located (pos,l) t) tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) -tokenWith tf inp l = undefined +tokenWith tf inp l = do + pos <- getPos + let t = tf (T.take l $ inp ^. aiSource) + pure (Located (pos,l) t) + +getPos :: P Position +getPos = use (psInput . aiPos) alexEOF :: P (Located RlpToken) alexEOF = do inp <- getInput pure (Located undefined TokenEOF) -data RlpToken - -- literals - = TokenLitInt Int - -- identifiers - | TokenVarName Name - | TokenConName Name - | TokenVarSym Name - | TokenConSym Name - -- keywords - | TokenData - | TokenPipe - | TokenLet - | TokenIn - -- control symbols - | TokenEquals - | TokenSemicolon - | TokenLBrace - | TokenRBrace - -- 'virtual' control symbols, inserted by the lexer without any correlation - -- to a specific symbol - | TokenSemicolonV - | TokenLBraceV - | TokenRBraceV - | TokenEOF - deriving (Show) +execP :: P a -> ParseState -> Maybe a +execP p st = runP p st & snd -newtype P a = P { runP :: ParseState -> (ParseState, Maybe a) } - deriving (Functor) - -execP :: P a -> ParseState -> Either String a -execP p st = undefined - -execP' :: P a -> Text -> Either String a +execP' :: P a -> Text -> Maybe a execP' p s = execP p st where st = initParseState s initParseState :: Text -> ParseState initParseState s = ParseState { _psLayoutStack = [] - , _psLexState = [bol,0] - , _psInput = (undefined, s) + , _psLexState = [one,bol,0] + , _psInput = initAlexInput s } -data ParseState = ParseState - { _psLayoutStack :: [Layout] - , _psLexState :: [Int] - , _psInput :: AlexInput +initAlexInput :: Text -> AlexInput +initAlexInput s = AlexInput + { _aiPrevChar = '\0' + , _aiSource = s + , _aiBytes = [] + , _aiPos = (1,1) } -instance Applicative P where - pure a = P $ \st -> (st,Just a) - liftA2 = liftM2 - -instance Monad P where - p >>= k = undefined - -data Layout = Explicit - | Implicit Int - deriving (Show, Eq) - -data Located a = Located (Int, Int) a - deriving (Show) - -lexer :: P (Located RlpToken) -lexer = undefined +lexToken :: P (Located RlpToken) +lexToken = do + inp <- getInput + c <- getLexState + case alexScan inp c of + AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF + AlexToken inp' l act -> do + psInput .= inp' + traceM $ "l: " <> show l + traceShowM inp' + act inp l lexerCont :: (Located RlpToken -> P a) -> P a lexerCont = undefined lexStream :: P [RlpToken] -lexStream = undefined +lexStream = do + t <- lexToken + case t of + Located _ TokenEOF -> pure [TokenEOF] + Located _ t -> (t:) <$> lexStream lexTest :: Text -> Either String [RlpToken] lexTest = undefined -lexToken :: P (Located RlpToken) -lexToken = undefined +indentLevel :: P Int +indentLevel = do + pos <- use (psInput . aiPos) + pure (pos ^. _2) -doBol = undefined +insertToken :: RlpToken -> P (Located RlpToken) +insertToken t = do + pos <- use (psInput . aiPos) + pure (Located (pos, 0) t) + +popLayout :: P Layout +popLayout = do + traceM "pop layout" + ctx <- preuse (psLayoutStack . _head) + modifying psLayoutStack (drop 1) + case ctx of + Just l -> pure l + Nothing -> error "uhh" + +insertSemicolon, insertLBrace, insertRBrace :: P (Located RlpToken) +insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV +insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV +insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV + +cmpLayout :: P Ordering +cmpLayout = do + i <- indentLevel + ctx <- preuse (psLayoutStack . _head) + case ctx ^. non (Implicit 1) of + Implicit n -> pure (i `compare` n) + Explicit -> pure GT + +doBol :: LexerAction (Located RlpToken) +doBol inp l = do + off <- cmpLayout + case off of + -- the line is aligned with the previous. it therefore belongs to the + -- same list + EQ -> insertSemicolon + -- the line is indented further than the previous, so we assume it is a + -- line continuation. ignore it and move on! + GT -> undefined -- alexSetStartCode one >> lexToken + -- the line is indented less than the previous, pop the layout stack and + -- insert a closing brace. + LT -> popLayout >> insertRBrace } diff --git a/src/Rlp/Parse/Decls.hs b/src/Rlp/Parse/Decls.hs deleted file mode 100644 index fb6d875..0000000 --- a/src/Rlp/Parse/Decls.hs +++ /dev/null @@ -1,381 +0,0 @@ -{-# LANGUAGE RecursiveDo #-} -{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE ImplicitParams #-} -{-# LANGUAGE LambdaCase, BlockArguments #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -module Rlp.Parse.Decls - ( - ) - where ----------------------------------------------------------------------------------- -import Control.Monad -import Control.Monad.State -import Text.Megaparsec hiding (State) -import Text.Megaparsec.Char -import Text.Megaparsec.Char.Lexer qualified as L -import Data.Functor.Classes -import Data.Functor.Foldable -import Data.Text (Text) -import Data.Text qualified as T -import Data.HashMap.Strict qualified as H -import Data.Maybe (maybeToList) -import Data.List (foldl1') -import Data.Char -import Data.Function (fix) -import Data.Functor -import Data.Functor.Const -import Data.Fix hiding (cata) -import GHC.Exts (IsString) -import Lens.Micro -import Lens.Micro.Platform -import Rlp.Parse.Types -import Rlp.Parse.Utils -import Rlp.Syntax ----------------------------------------------------------------------------------- - -parseTest' :: (Show a) => Parser a -> Text -> IO () -parseTest' p s = case runState (runParserT p "test" s) init of - (Left e, _) -> putStr (errorBundlePretty e) - (Right x, st) -> print st *> print x - where - init = ParserState mempty - -lexeme :: Parser a -> Parser a -lexeme = L.lexeme sc - -symbol :: Text -> Parser Text -symbol = L.symbol sc - -sc :: Parser () -sc = L.space hspace1 (void lineComment) (void blockComment) - -scn :: Parser () -scn = L.space space1 (void lineComment) (void blockComment) - -type OnFold = (?foldGuard :: Parser ()) - --- TODO: return comment text --- TODO: '---' should not start a comment -lineComment :: Parser Text -lineComment = L.skipLineComment "--" $> "" - --- TODO: return comment text -blockComment :: Parser Text -blockComment = L.skipBlockCommentNested "{-" "-}" $> "" - -layout :: forall a. ((OnFold) => Parser a) -> Parser [a] -layout item = scn *> (explicit <|> implicit) where - explicit :: Parser [a] - explicit = let ?foldGuard = scn -- line folds just go to the semicolon - in sym "{" *> fix \items -> choice - [ sym "}" $> [] - , (:) <$> item - <*> (sym ";" *> items <|> sym "}" $> []) - ] - where - sym = L.symbol scn - - implicit :: Parser [a] - implicit = do - i <- L.indentLevel - -- items must be aligned - let indentGuard = L.indentGuard scn EQ i - -- override foldGuard in order with new indentation - let ?foldGuard = void $ L.indentGuard scn GT i - fix \ds -> (:) <$> (indentGuard *> item <* scn) - <*> (ds <|> pure []) - -t :: (?foldGuard :: Parser ()) => Parser [Text] -t = (:) <$> lexeme "soge" <*> many (flexeme "doge") - -decl :: (OnFold) => Parser PartialDecl' -decl = choice - -- declarations that begin with a keyword before those beginning with an - -- arbitrary name - [ infixD - , dataD - , try funD - , tySigD - ] - -funD :: (OnFold) => Parser PartialDecl' -funD = FunD <$> lexeme varid <*> params <*> (fsymbol "=" *> body) <*> whereClause - where - params = many pat1 - body = fmap Const partialExpr - --- we may not need to call scn here -fsymbol :: (OnFold) => Text -> Parser Text -fsymbol p = try ?foldGuard *> symbol p - --- we may not need to call scn here -flexeme :: (OnFold) => Parser a -> Parser a -flexeme p = try ?foldGuard *> lexeme p - -whereClause :: Parser Where' -whereClause = optionalList $ - lexeme "where" *> pure - [ FunB "fixme" [] (VarE "fixme") - ] - -standalonePartialExpr :: Parser PartialExpr' -standalonePartialExpr = standaloneOf partialExpr - where ?foldGuard = undefined - -standaloneOf :: Parser a -> Parser a -standaloneOf = (<* eof) - -partialExpr :: (OnFold) => Parser PartialExpr' -partialExpr = choice - [ ifExpr - , try $ infixExpr - , application - ] - "expression" - where - application = foldl1' mkApp <$> some (flexeme partialExpr1) - infixExpr = fmap Fix $ - mkB <$> partialExpr1' <*> infixOp' <*> partialExpr' - - ifExpr :: Parser PartialExpr' - ifExpr = fmap (Fix . E) $ - IfEF <$> (flexeme "if" *> partialExpr) - <*> (flexeme "then" *> partialExpr) - <*> (flexeme "else" *> partialExpr) - - mkB a f b = B f a b - partialExpr1' = unFix <$> partialExpr1 - partialExpr' = unFix <$> partialExpr - infixOp' = flexeme infixOp - - mkApp :: PartialExpr' -> PartialExpr' -> PartialExpr' - mkApp f x = Fix . E $ f `AppEF` x - -partialExpr1 :: (OnFold) => Parser PartialExpr' -partialExpr1 = choice - [ try $ lexeme "(" *> partialExpr' <* lexeme ")" - , Fix <$> varid' - , Fix <$> lit' - ] - "expression" - where - partialExpr' = wrapFix . P . unwrapFix <$> partialExpr - varid' = E . VarEF <$> varid - lit' = E . LitEF <$> lit - -infixOp :: Parser Name -infixOp = symvar <|> symcon "operator" - -symvar :: Parser Name -symvar = T.cons <$> satisfy isVarSym <*> takeWhileP Nothing isSym - -symcon :: Parser Name -symcon = T.cons <$> char ':' <*> takeWhileP Nothing isSym - -pat1 :: (OnFold) => Parser Pat' -pat1 = VarP <$> flexeme varid - "pattern" - -conid :: Parser ConId -conid = NameCon <$> lexeme namecon - <|> SymCon <$> lexeme (char '(' *> symcon <* char ')') - "constructor identifier" - -namecon :: Parser Name -namecon = T.cons <$> satisfy isUpper <*> takeWhileP Nothing isNameTail - -varid :: Parser VarId -varid = NameVar <$> try (lexeme namevar) - <|> SymVar <$> lexeme (char '(' *> symvar <* char ')') - "variable identifier" - -program :: Parser [Decl' RlpExpr] -program = do - ds <- layout decl <* eof - pt <- use psOpTable - pure $ complete pt <$> ds - -namevar :: Parser Name -namevar = word - & withPredicate (`notElem` keywords) empty - where - word = T.cons <$> satisfy isLower <*> takeWhileP Nothing isNameTail - -keywords :: (IsString a) => [a] -keywords = - [ "where" - , "infix" - , "infixr" - , "infixl" - ] - -isNameTail :: Char -> Bool -isNameTail c = isAlphaNum c - || c == '\'' - || c == '_' - -isVarSym :: Char -> Bool -isVarSym = (`T.elem` "\\!#$%&*+./<=>?@^|-~") - -isSym :: Char -> Bool -isSym c = c == ':' || isVarSym c - -infixD :: Parser (Decl' e) -infixD = do - o <- getOffset - a <- infixWord - p <- prec - op <- infixOp - region (setErrorOffset o) $ updateOpTable a p op - pure $ InfixD a p op - where - infixWord :: Parser Assoc - infixWord = choice $ lexeme <$> - [ "infixr" $> InfixR - , "infixl" $> InfixL - , "infix" $> Infix - ] - - prec :: Parser Int - prec = do - o <- getOffset - n <- lexeme L.decimal "precedence level (an integer)" - if 0 <= n && n <= 9 then - pure n - else - region (setErrorOffset o) $ - registerCustomFailure (RlpParErrOutOfBoundsPrecedence n) - $> 9 - - updateOpTable :: Assoc -> Int -> Name -> Parser () - updateOpTable a p op = do - t <- use psOpTable - psOpTable <~ H.alterF f op t - where - f Nothing = pure (Just (a,p)) - f (Just x) = registerCustomFailure RlpParErrDuplicateInfixD - $> Just x - -tySigD :: (OnFold) => Parser (Decl' e) -tySigD = TySigD <$> (pure <$> varid) <*> (flexeme "::" *> flexeme type_) - -dataD :: (OnFold) => Parser (Decl' e) -dataD = DataD <$> (lexeme "data" *> conid) <*> many typaram - <*> optionalList (symbol "=" *> conalts) - where - typaram :: Parser Name - typaram = lexeme namevar - - conalts :: Parser [ConAlt] - conalts = (:) <$> conalt <*> optionalList (symbol "|" *> conalts) - - conalt :: Parser ConAlt - conalt = ConAlt <$> conid <*> many type1 - -type1 :: (OnFold) => Parser Type -type1 = choice - [ lexeme "(" *> type_ <* lexeme ")" - , TyVar <$> namevar - , TyCon <$> namecon - ] - -type_ :: (OnFold) => Parser Type -type_ = choice - [ try $ (:->) <$> type1 <*> (flexeme "->" *> type_) - , type1 - ] - -lit :: Parser Lit' -lit = int - "literal" - where - int = IntL <$> L.decimal - --------------------------------------------------------------------------------- --- completing partial expressions - -complete :: OpTable -> PartialDecl' -> Decl' RlpExpr -complete pt (FunD n as b w) = FunD n as b' w - where b' = let ?pt = pt in completeExpr (getConst b) -complete pt (TySigD ns t) = TySigD ns t -complete pt (DataD n as cs) = DataD n as cs -complete pt (InfixD a p n) = InfixD a p n - -completeExpr :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' -completeExpr = cata completePartial - -completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' -completePartial (E e) = completeRlpExpr e -completePartial p@(B o l r) = completeB (build p) -completePartial (P e) = completePartial e - -completeRlpExpr :: (?pt :: OpTable) => RlpExprF' RlpExpr' -> RlpExpr' -completeRlpExpr = embed - -completeB :: (?pt :: OpTable) => PartialE -> RlpExpr' -completeB p = case build p of - B o l r -> (o' `AppE` l') `AppE` r' - where - -- TODO: how do we know it's symbolic? - o' = VarE (SymVar o) - l' = completeB l - r' = completeB r - P e -> completeB e - E e -> completeRlpExpr e - -build :: (?pt :: OpTable) => PartialE -> PartialE -build e = go id e (rightmost e) where - rightmost :: PartialE -> PartialE - rightmost (B _ _ r) = rightmost r - rightmost p@(E _) = p - rightmost p@(P _) = p - - go :: (?pt :: OpTable) - => (PartialE -> PartialE) - -> PartialE -> PartialE -> PartialE - go f p@(WithInfo o _ r) = case r of - E _ -> mkHole o (f . f') - P _ -> mkHole o (f . f') - B _ _ _ -> go (mkHole o (f . f')) r - where f' r' = p & pR .~ r' - go f _ = id - -mkHole :: (?pt :: OpTable) - => OpInfo - -> (PartialE -> PartialE) - -> PartialE - -> PartialE -mkHole _ hole p@(P _) = hole p -mkHole _ hole p@(E _) = hole p -mkHole (a,d) hole p@(WithInfo (a',d') _ _) - | d' < d = above - | d' > d = below - | d == d' = case (a,a') of - -- left-associative operators of equal precedence are - -- associated left - (InfixL,InfixL) -> above - -- right-associative operators are handled similarly - (InfixR,InfixR) -> below - -- non-associative operators of equal precedence, or equal - -- precedence operators of different associativities are - -- invalid - (_, _) -> error "invalid expression" - where - above = p & pL %~ hole - below = hole p - -examplePrecTable :: OpTable -examplePrecTable = H.fromList - [ ("+", (InfixL,6)) - , ("*", (InfixL,7)) - , ("^", (InfixR,8)) - , (".", (InfixR,7)) - , ("~", (Infix, 9)) - , ("=", (Infix, 4)) - , ("&&", (Infix, 3)) - , ("||", (Infix, 2)) - , ("$", (InfixR,0)) - , ("&", (InfixL,0)) - ] - diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 41e67f8..d25c27b 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -1,57 +1,97 @@ {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} -{- -Description : Supporting types for the parser --} -module Rlp.Parse.Types - ( - -- * Partial ASTs - Partial(..) - , PartialE - , PartialExpr' - , PartialDecl' - , pattern WithInfo - , pR - , pL - - -- * Parser types - , Parser - , ParserState(..) - , psOpTable - , RlpParseError(..) - , OpTable - , OpInfo - ) - where ----------------------------------------------------------------------------------- -import Control.Monad.State -import Data.HashMap.Strict qualified as H +{-# LANGUAGE LambdaCase #-} +module Rlp.Parse.Types where +-------------------------------------------------------------------------------- +import Core.Syntax (Name) +import Control.Monad +import Control.Monad.State.Class +import Data.Text (Text) +import Data.Maybe import Data.Fix import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes -import Data.Void -import Data.Maybe -import Text.Megaparsec hiding (State) -import Text.Printf -import Lens.Micro +import Data.HashMap.Strict qualified as H +import Data.Word (Word8) import Lens.Micro.TH +import Lens.Micro import Rlp.Syntax ----------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- --- parser types +type LexerAction a = AlexInput -> Int -> P a --- TODO: the State is only used for building an operator table from infix[lr] --- declarations. we should switch to a normal Parsec monad in the future - -type Parser = ParsecT RlpParseError Text (State ParserState) - -data ParserState = ParserState - { _psOpTable :: OpTable +data AlexInput = AlexInput + { _aiPrevChar :: Char + , _aiSource :: Text + , _aiBytes :: [Word8] + , _aiPos :: Position } deriving Show +type Position = + ( Int -- line + , Int -- column + ) + +data RlpToken + -- literals + = TokenLitInt Int + -- identifiers + | TokenVarName Name + | TokenConName Name + | TokenVarSym Name + | TokenConSym Name + -- keywords + | TokenData + | TokenPipe + | TokenLet + | TokenIn + -- control symbols + | TokenEquals + | TokenSemicolon + | TokenLBrace + | TokenRBrace + -- 'virtual' control symbols, inserted by the lexer without any correlation + -- to a specific symbol + | TokenSemicolonV + | TokenLBraceV + | TokenRBraceV + | TokenEOF + deriving (Show) + +newtype P a = P { runP :: ParseState -> (ParseState, Maybe a) } + deriving (Functor) + +instance Applicative P where + pure a = P $ \st -> (st,Just a) + liftA2 = liftM2 + +instance Monad P where + p >>= k = P $ \st -> + let (st',a) = runP p st + in case a of + Just x -> runP (k x) st' + Nothing -> (st', Nothing) + +instance MonadState ParseState P where + state f = P $ \st -> + let (a,st') = f st + in (st', Just a) + +data ParseState = ParseState + { _psLayoutStack :: [Layout] + , _psLexState :: [Int] + , _psInput :: AlexInput + } + +data Layout = Explicit + | Implicit Int + deriving (Show, Eq) + +data Located a = Located (Position, Int) a + deriving (Show) + type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) @@ -61,17 +101,6 @@ data RlpParseError = RlpParErrOutOfBoundsPrecedence Int | RlpParErrDuplicateInfixD deriving (Eq, Ord, Show) -instance ShowErrorComponent RlpParseError where - showErrorComponent = \case - -- TODO: wrap text to 80 characters - RlpParErrOutOfBoundsPrecedence n -> - printf "%d is an invalid precedence level! rl' currently only\ - \allows custom precedences between 0 and 9 (inclusive).\ - \ This is an arbitrary limit put in place for legibility\ - \ concerns, and may change in the future." n - RlpParErrDuplicateInfixD -> - "duplicate infix decl" - ---------------------------------------------------------------------------------- -- absolute psycho shit (partial ASTs) @@ -80,7 +109,7 @@ type PartialDecl' = Decl (Const PartialExpr') Name data Partial a = E (RlpExprF Name a) | B Name (Partial a) (Partial a) - | P (Partial a) + | Par (Partial a) deriving (Show, Functor) pL :: Traversal' (Partial a) (Partial a) @@ -109,14 +138,13 @@ instance Show1 Partial where liftShowsPrec sp sl p m = case m of (E e) -> showsUnaryWith lshow "E" p e (B f a b) -> showsTernaryWith showsPrec lshow lshow "B" p f a b - (P e) -> showsUnaryWith lshow "P" p e + (Par e) -> showsUnaryWith lshow "Par" p e where lshow :: forall f. (Show1 f) => Int -> f a -> ShowS lshow = liftShowsPrec sp sl type PartialExpr' = Fix Partial ----------------------------------------------------------------------------------- - -makeLenses ''ParserState +makeLenses ''AlexInput +makeLenses ''ParseState diff --git a/src/Rlp/Parse/Utils.hs b/src/Rlp/Parse/Utils.hs deleted file mode 100644 index cf5fb8c..0000000 --- a/src/Rlp/Parse/Utils.hs +++ /dev/null @@ -1,30 +0,0 @@ -module Rlp.Parse.Utils - ( withPredicate - , registerCustomFailure - , optionalList - ) - where --------------------------------------------------------------------------------- -import Text.Megaparsec -import Rlp.Parse.Types -import Data.Set qualified as S -import Data.Maybe -import Control.Monad --------------------------------------------------------------------------------- - --- TODO: generalise type sig -withPredicate :: (a -> Bool) - -> Parser a -- ^ action to run should the predicate fail - -> Parser a - -> Parser a -withPredicate f r p = do - o <- getOffset - a <- p - if f a then pure a else setOffset o *> r - -registerCustomFailure :: MonadParsec e s m => e -> m () -registerCustomFailure = registerFancyFailure . S.singleton . ErrorCustom - -optionalList :: Parser [a] -> Parser [a] -optionalList = fmap (join . maybeToList) . optional - -- 2.52.0 From a38381f6ca5f1d5b2d5df41ac172bf94fdf91603 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 07:53:40 -0700 Subject: [PATCH 078/192] version bounds --- rlp.cabal | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 5d3fa6a..39d6379 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -48,19 +48,24 @@ library -- other-extensions: build-depends: base ^>=4.18.0.0 -- required for happy - , array - , data-default-class - , data-default - , unordered-containers - , hashable - , pretty - -- TODO: either learn recursion-schemes, or stop depending - -- on it. - , recursion-schemes - , megaparsec ^>=9.6.0 - , text - , data-fix - , utf8-string + , array >= 0.5.5 && < 0.6 + , containers >= 0.6.7 && < 0.7 + , template-haskell >= 2.20.0 && < 2.21 + , pretty >= 1.1.3 && < 1.2 + , data-default >= 0.7.1 && < 0.8 + , data-default-class >= 0.1.2 && < 0.2 + , hashable >= 1.4.3 && < 1.5 + , mtl >= 2.3.1 && < 2.4 + , text >= 2.0.2 && < 2.1 + , megaparsec >= 9.6.1 && < 9.7 + , microlens >= 0.4.13 && < 0.5 + , microlens-mtl >= 0.2.0 && < 0.3 + , microlens-platform >= 0.4.3 && < 0.5 + , microlens-th >= 0.4.3 && < 0.5 + , unordered-containers >= 0.2.20 && < 0.3 + , recursion-schemes >= 5.2.2 && < 5.3 + , data-fix >= 0.3.2 && < 0.4 + , utf8-string >= 1.0.2 && < 1.1 hs-source-dirs: src default-language: GHC2021 -- 2.52.0 From c92d8fac65c3dce3421406d6126c7a75d5955f0d Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 09:44:26 -0700 Subject: [PATCH 079/192] we're so back --- src/Rlp/Lex.x | 126 +++++++++++++++++++++++++++++++---------- src/Rlp/Parse/Types.hs | 1 + 2 files changed, 98 insertions(+), 29 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index d81e432..e5a8805 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,4 +1,5 @@ { +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex @@ -49,21 +50,21 @@ rlp :- $white_no_nl+ ; -- TODO: don't treat operators like (-->) as comments "--".* ; - ";" { constToken TokenSemicolon } - -- "{" { explicitLBrace } - -- "}" { explicitRBrace } <0> { - \n { begin bol } -} - - -{ + \n { beginPush bol } @varname { tokenWith TokenVarName } @digits { tokenWith (TokenLitInt . readInt) } "=" { constToken TokenEquals } - \n { begin bol } +} + +-- control characters +<0> +{ + "{" { explicitLBrace } + "}" { explicitRBrace } + ";" { constToken TokenSemicolon } } -- consume all whitespace leaving us at the beginning of the next non-empty @@ -76,19 +77,47 @@ rlp :- () { doBol } } + +{ + \n ; + "{" { explicitLBrace `thenDo` popLexState } + () { doLayout } +} + { -begin :: Int -> LexerAction a -begin = undefined +-- | @andBegin@, with the subtle difference that the start code is set +-- /after/ the action +thenBegin :: LexerAction a -> Int -> LexerAction a +thenBegin act c inp l = do + a <- act inp l + psLexState . _head .= c + pure a + +andBegin :: LexerAction a -> Int -> LexerAction a +andBegin act c inp l = do + psLexState . _head .= c + act inp l + +beginPush :: Int -> LexerAction (Located RlpToken) +beginPush n _ _ = pushLexState n >> lexToken alexGetByte :: AlexInput -> Maybe (Word8, AlexInput) alexGetByte inp = case inp ^. aiBytes of [] -> do (c,t) <- T.uncons (inp ^. aiSource) let (b:bs) = encodeChar c + -- tail the source inp' = inp & aiSource .~ t + -- record the excess bytes for successive calls & aiBytes .~ bs + -- report the previous char & aiPrevChar .~ c + -- update the position + & aiPos %~ \ (ln,col) -> + if (inp ^. aiPrevChar) == '\n' + then (ln+1,1) + else (ln,col+1) pure (b, inp') _ -> Just (head bs, inp') @@ -104,17 +133,13 @@ getLexState = use (psLexState . singular _head) alexInputPrevChar :: AlexInput -> Char alexInputPrevChar = view aiPrevChar +pushLexState :: Int -> P () +pushLexState n = psLexState %= (n:) + readInt :: Text -> Int readInt = T.foldr f 0 where f c n = digitToInt c + 10*n --- | @andBegin@, with the subtle difference that the start code is set --- /after/ the action -thenBegin :: LexerAction a -> Int -> LexerAction a -thenBegin act c inp l = do - a <- act inp l - undefined - constToken :: RlpToken -> LexerAction (Located RlpToken) constToken t inp l = do pos <- use (psInput . aiPos) @@ -144,27 +169,37 @@ execP' p s = execP p st where initParseState :: Text -> ParseState initParseState s = ParseState { _psLayoutStack = [] - , _psLexState = [one,bol,0] + -- IMPORTANT: the initial state is `bol` to begin the top-level layout, + -- which then returns to state 0 which continues the normal lexing process. + , _psLexState = [layout_top,0] , _psInput = initAlexInput s } initAlexInput :: Text -> AlexInput -initAlexInput s = AlexInput +initAlexInput (unconsBytes -> (b,s)) = AlexInput { _aiPrevChar = '\0' , _aiSource = s - , _aiBytes = [] + , _aiBytes = b , _aiPos = (1,1) } +unconsBytes :: Text -> ([Word8], Text) +unconsBytes s = (encodeChar c, t) where + (c,t) = fromJust $ T.uncons s + lexToken :: P (Located RlpToken) lexToken = do inp <- getInput c <- getLexState + st <- use id + traceM $ "st: " <> show st case alexScan inp c of AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF + AlexSkip inp' l -> do + psInput .= inp' + lexToken AlexToken inp' l act -> do psInput .= inp' - traceM $ "l: " <> show l traceShowM inp' act inp l @@ -178,8 +213,8 @@ lexStream = do Located _ TokenEOF -> pure [TokenEOF] Located _ t -> (t:) <$> lexStream -lexTest :: Text -> Either String [RlpToken] -lexTest = undefined +lexTest :: Text -> Maybe [RlpToken] +lexTest s = execP' lexStream s indentLevel :: P Int indentLevel = do @@ -195,11 +230,20 @@ popLayout :: P Layout popLayout = do traceM "pop layout" ctx <- preuse (psLayoutStack . _head) - modifying psLayoutStack (drop 1) + psLayoutStack %= (drop 1) case ctx of Just l -> pure l Nothing -> error "uhh" +pushLayout :: Layout -> P () +pushLayout l = do + traceM "push layout" + psLayoutStack %= (l:) + +popLexState :: P () +popLexState = do + psLexState %= tail + insertSemicolon, insertLBrace, insertRBrace :: P (Located RlpToken) insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV @@ -209,23 +253,47 @@ cmpLayout :: P Ordering cmpLayout = do i <- indentLevel ctx <- preuse (psLayoutStack . _head) - case ctx ^. non (Implicit 1) of - Implicit n -> pure (i `compare` n) - Explicit -> pure GT + case ctx of + Just (Implicit n) -> pure (i `compare` n) + _ -> pure GT doBol :: LexerAction (Located RlpToken) doBol inp l = do off <- cmpLayout + i <- indentLevel + traceM $ "i: " <> show i + -- important that we pop the lex state lest we find our lexer diverging + popLexState case off of -- the line is aligned with the previous. it therefore belongs to the -- same list EQ -> insertSemicolon -- the line is indented further than the previous, so we assume it is a -- line continuation. ignore it and move on! - GT -> undefined -- alexSetStartCode one >> lexToken + GT -> lexToken -- the line is indented less than the previous, pop the layout stack and -- insert a closing brace. LT -> popLayout >> insertRBrace +thenDo :: LexerAction a -> P b -> LexerAction a +thenDo act p inp l = act inp l <* p + +explicitLBrace :: LexerAction (Located RlpToken) +explicitLBrace inp l = do + pushLayout Explicit + constToken TokenLBrace inp l + +explicitRBrace :: LexerAction (Located RlpToken) +explicitRBrace inp l = do + popLayout + constToken TokenRBrace inp l + +doLayout :: LexerAction (Located RlpToken) +doLayout _ _ = do + i <- indentLevel + pushLayout (Implicit i) + popLexState + insertLBrace + } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index d25c27b..90b5524 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -84,6 +84,7 @@ data ParseState = ParseState , _psLexState :: [Int] , _psInput :: AlexInput } + deriving Show data Layout = Explicit | Implicit Int -- 2.52.0 From 3dfadc17ec646d7936a74bc0dbb4d83537388bb6 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 10:33:09 -0700 Subject: [PATCH 080/192] fixy --- src/Rlp/Lex.x | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index e5a8805..848983f 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -176,17 +176,13 @@ initParseState s = ParseState } initAlexInput :: Text -> AlexInput -initAlexInput (unconsBytes -> (b,s)) = AlexInput +initAlexInput s = AlexInput { _aiPrevChar = '\0' , _aiSource = s - , _aiBytes = b + , _aiBytes = [] , _aiPos = (1,1) } -unconsBytes :: Text -> ([Word8], Text) -unconsBytes s = (encodeChar c, t) where - (c,t) = fromJust $ T.uncons s - lexToken :: P (Located RlpToken) lexToken = do inp <- getInput -- 2.52.0 From bdf74ac6c9f8d875a7b3d85798788b96fe2668b5 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 10:35:11 -0700 Subject: [PATCH 081/192] cool --- src/Rlp/Lex.x | 44 ++++++++++++++++++++++++++++++++---------- src/Rlp/Parse/Types.hs | 8 ++++++-- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 848983f..7f5b292 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,5 +1,5 @@ { -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ViewPatterns, LambdaCase #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex @@ -39,10 +39,20 @@ $nl = [\n\r] $white_no_nl = $white # $nl $namechar = [$alpha $digit \' \#] +$reservedsym = [\(\)\,\;\[\]\`\{\}] +$asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] +$namesym = $asciisym # \; -@varname = $lower $namechar* +@reservedop = + "=" | \\ | "->" | "::" | "|" -@digits = $digit+ +@varname = $lower $namechar* +@conname = $upper $namechar* +@varsym = $namesym+ +@consym = \: $namesym* + + +@decimal = $digit+ rlp :- @@ -55,8 +65,8 @@ rlp :- { \n { beginPush bol } @varname { tokenWith TokenVarName } - @digits { tokenWith (TokenLitInt . readInt) } - "=" { constToken TokenEquals } + @decimal { tokenWith (TokenLitInt . readInt) } + @reservedop { tokenWith readReservedOp } } -- control characters @@ -86,6 +96,14 @@ rlp :- { +readReservedOp :: Text -> RlpToken +readReservedOp = \case + "=" -> TokenEquals + "\\" -> TokenLambda + "->" -> TokenArrow + "::" -> TokenHasType + s -> error (show s) + -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action thenBegin :: LexerAction a -> Int -> LexerAction a @@ -127,6 +145,12 @@ alexGetByte inp = case inp ^. aiBytes of getInput :: P AlexInput getInput = use psInput +takeInput :: Int -> AlexInput -> Text +takeInput n inp = T.cons c cs + where + c = inp ^. aiPrevChar + cs = T.take (max 0 (n-1)) $ inp ^. aiSource + getLexState :: P Int getLexState = use (psLexState . singular _head) @@ -148,8 +172,8 @@ constToken t inp l = do tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) tokenWith tf inp l = do pos <- getPos - let t = tf (T.take l $ inp ^. aiSource) - pure (Located (pos,l) t) + let t = takeInput l inp + pure (Located (pos,l) (tf t)) getPos :: P Position getPos = use (psInput . aiPos) @@ -176,10 +200,10 @@ initParseState s = ParseState } initAlexInput :: Text -> AlexInput -initAlexInput s = AlexInput - { _aiPrevChar = '\0' +initAlexInput t = AlexInput + { _aiPrevChar = c , _aiSource = s - , _aiBytes = [] + , _aiBytes = b , _aiPos = (1,1) } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 90b5524..03f24f8 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -44,11 +44,15 @@ data RlpToken | TokenConSym Name -- keywords | TokenData - | TokenPipe | TokenLet | TokenIn - -- control symbols + -- reserved ops + | TokenArrow + | TokenPipe + | TokenHasType + | TokenLambda | TokenEquals + -- control symbols | TokenSemicolon | TokenLBrace | TokenRBrace -- 2.52.0 From 4f66e71b9a729e4738a071b5eef62d00bd73aefc Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 11:05:10 -0700 Subject: [PATCH 082/192] FIX REAL --- src/Rlp/Lex.x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 848983f..18592f8 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -115,7 +115,7 @@ alexGetByte inp = case inp ^. aiBytes of & aiPrevChar .~ c -- update the position & aiPos %~ \ (ln,col) -> - if (inp ^. aiPrevChar) == '\n' + if c == '\n' then (ln+1,1) else (ln,col+1) pure (b, inp') -- 2.52.0 From c0236dc079c9a2e664a7243a08b0c427f0ab6ae0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 11:11:43 -0700 Subject: [PATCH 083/192] oh my god --- src/Rlp/Lex.x | 44 ++---- src/Rlp/Lex.x.orig | 327 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 337 insertions(+), 34 deletions(-) create mode 100644 src/Rlp/Lex.x.orig diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 589d6bb..18592f8 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,5 +1,5 @@ { -{-# LANGUAGE ViewPatterns, LambdaCase #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex @@ -39,20 +39,10 @@ $nl = [\n\r] $white_no_nl = $white # $nl $namechar = [$alpha $digit \' \#] -$reservedsym = [\(\)\,\;\[\]\`\{\}] -$asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] -$namesym = $asciisym # \; -@reservedop = - "=" | \\ | "->" | "::" | "|" +@varname = $lower $namechar* -@varname = $lower $namechar* -@conname = $upper $namechar* -@varsym = $namesym+ -@consym = \: $namesym* - - -@decimal = $digit+ +@digits = $digit+ rlp :- @@ -65,8 +55,8 @@ rlp :- { \n { beginPush bol } @varname { tokenWith TokenVarName } - @decimal { tokenWith (TokenLitInt . readInt) } - @reservedop { tokenWith readReservedOp } + @digits { tokenWith (TokenLitInt . readInt) } + "=" { constToken TokenEquals } } -- control characters @@ -96,14 +86,6 @@ rlp :- { -readReservedOp :: Text -> RlpToken -readReservedOp = \case - "=" -> TokenEquals - "\\" -> TokenLambda - "->" -> TokenArrow - "::" -> TokenHasType - s -> error (show s) - -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action thenBegin :: LexerAction a -> Int -> LexerAction a @@ -145,12 +127,6 @@ alexGetByte inp = case inp ^. aiBytes of getInput :: P AlexInput getInput = use psInput -takeInput :: Int -> AlexInput -> Text -takeInput n inp = T.cons c cs - where - c = inp ^. aiPrevChar - cs = T.take (max 0 (n-1)) $ inp ^. aiSource - getLexState :: P Int getLexState = use (psLexState . singular _head) @@ -172,8 +148,8 @@ constToken t inp l = do tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) tokenWith tf inp l = do pos <- getPos - let t = takeInput l inp - pure (Located (pos,l) (tf t)) + let t = tf (T.take l $ inp ^. aiSource) + pure (Located (pos,l) t) getPos :: P Position getPos = use (psInput . aiPos) @@ -200,10 +176,10 @@ initParseState s = ParseState } initAlexInput :: Text -> AlexInput -initAlexInput t = AlexInput - { _aiPrevChar = c +initAlexInput s = AlexInput + { _aiPrevChar = '\0' , _aiSource = s - , _aiBytes = b + , _aiBytes = [] , _aiPos = (1,1) } diff --git a/src/Rlp/Lex.x.orig b/src/Rlp/Lex.x.orig new file mode 100644 index 0000000..184e2c6 --- /dev/null +++ b/src/Rlp/Lex.x.orig @@ -0,0 +1,327 @@ +{ +{-# LANGUAGE ViewPatterns, LambdaCase #-} +{-# LANGUAGE GeneralisedNewtypeDeriving #-} +{-# LANGUAGE OverloadedStrings #-} +module Rlp.Lex + ( P(..) + , RlpToken(..) + , Located(..) + , lexToken + , lexerCont + ) + where +import Codec.Binary.UTF8.String (encodeChar) +import Control.Monad +import Core.Syntax (Name) +import Data.Functor.Identity +import Data.Char (digitToInt) +import Data.Monoid (First) +import Data.Maybe +import Data.Text (Text) +import Data.Text qualified as T +import Data.Word +import Data.Default +import Lens.Micro.Mtl +import Lens.Micro + +import Debug.Trace +import Rlp.Parse.Types +} + +$whitechar = [ \t\n\r\f\v] + +$lower = [a-z \_] +$upper = [A-Z] +$alpha = [$lower $upper] +$digit = 0-9 + +$nl = [\n\r] +$white_no_nl = $white # $nl + +$namechar = [$alpha $digit \' \#] +$reservedsym = [\(\)\,\;\[\]\`\{\}] +$asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] +$namesym = $asciisym # \; + +@reservedop = + "=" | \\ | "->" | "::" | "|" + +@varname = $lower $namechar* +@conname = $upper $namechar* +@varsym = $namesym+ +@consym = \: $namesym* + + +@decimal = $digit+ + +rlp :- + + -- skip whitespace + $white_no_nl+ ; + -- TODO: don't treat operators like (-->) as comments + "--".* ; + +<0> +{ + \n { beginPush bol } + @varname { tokenWith TokenVarName } + @decimal { tokenWith (TokenLitInt . readInt) } + @reservedop { tokenWith readReservedOp } +} + +-- control characters +<0> +{ + "{" { explicitLBrace } + "}" { explicitRBrace } + ";" { constToken TokenSemicolon } +} + +-- consume all whitespace leaving us at the beginning of the next non-empty +-- line. we then compare the indentation of that line to the enclosing layout +-- context and proceed accordingly + +{ + $whitechar ; + \n ; + () { doBol } +} + + +{ + \n ; + "{" { explicitLBrace `thenDo` popLexState } + () { doLayout } +} + +{ + +readReservedOp :: Text -> RlpToken +readReservedOp = \case + "=" -> TokenEquals + "\\" -> TokenLambda + "->" -> TokenArrow + "::" -> TokenHasType + s -> error (show s) + +-- | @andBegin@, with the subtle difference that the start code is set +-- /after/ the action +thenBegin :: LexerAction a -> Int -> LexerAction a +thenBegin act c inp l = do + a <- act inp l + psLexState . _head .= c + pure a + +andBegin :: LexerAction a -> Int -> LexerAction a +andBegin act c inp l = do + psLexState . _head .= c + act inp l + +beginPush :: Int -> LexerAction (Located RlpToken) +beginPush n _ _ = pushLexState n >> lexToken + +alexGetByte :: AlexInput -> Maybe (Word8, AlexInput) +alexGetByte inp = case inp ^. aiBytes of + [] -> do + (c,t) <- T.uncons (inp ^. aiSource) + let (b:bs) = encodeChar c + -- tail the source + inp' = inp & aiSource .~ t + -- record the excess bytes for successive calls + & aiBytes .~ bs + -- report the previous char + & aiPrevChar .~ c + -- update the position + & aiPos %~ \ (ln,col) -> + if (inp ^. aiPrevChar) == '\n' + then (ln+1,1) + else (ln,col+1) + pure (b, inp') + + _ -> Just (head bs, inp') + where + (bs, inp') = inp & aiBytes <<%~ drop 1 + +getInput :: P AlexInput +getInput = use psInput + +takeInput :: Int -> AlexInput -> Text +takeInput n inp = T.cons c cs + where + c = inp ^. aiPrevChar + cs = T.take (max 0 (n-1)) $ inp ^. aiSource + +getLexState :: P Int +getLexState = use (psLexState . singular _head) + +alexInputPrevChar :: AlexInput -> Char +alexInputPrevChar = view aiPrevChar + +pushLexState :: Int -> P () +pushLexState n = psLexState %= (n:) + +readInt :: Text -> Int +readInt = T.foldr f 0 where + f c n = digitToInt c + 10*n + +constToken :: RlpToken -> LexerAction (Located RlpToken) +constToken t inp l = do + pos <- use (psInput . aiPos) + pure (Located (pos,l) t) + +tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) +tokenWith tf inp l = do + pos <- getPos + let t = takeInput l inp + pure (Located (pos,l) (tf t)) + +getPos :: P Position +getPos = use (psInput . aiPos) + +alexEOF :: P (Located RlpToken) +alexEOF = do + inp <- getInput + pure (Located undefined TokenEOF) + +execP :: P a -> ParseState -> Maybe a +execP p st = runP p st & snd + +execP' :: P a -> Text -> Maybe a +execP' p s = execP p st where + st = initParseState s + +initParseState :: Text -> ParseState +initParseState s = ParseState + { _psLayoutStack = [] + -- IMPORTANT: the initial state is `bol` to begin the top-level layout, + -- which then returns to state 0 which continues the normal lexing process. + , _psLexState = [layout_top,0] + , _psInput = initAlexInput s + } + +initAlexInput :: Text -> AlexInput +<<<<<<< Updated upstream +initAlexInput s = AlexInput + { _aiPrevChar = '\0' +======= +initAlexInput t = AlexInput + { _aiPrevChar = c +>>>>>>> Stashed changes + , _aiSource = s + , _aiBytes = [] + , _aiPos = (1,1) + } + where + (c,s) = fromJust $ T.uncons t + b = encodeChar c + +lexToken :: P (Located RlpToken) +lexToken = do + inp <- getInput + c <- getLexState + st <- use id + traceM $ "st: " <> show st + case alexScan inp c of + AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF + AlexSkip inp' l -> do + psInput .= inp' + lexToken + AlexToken inp' l act -> do + psInput .= inp' + traceShowM inp' + act inp l + +lexerCont :: (Located RlpToken -> P a) -> P a +lexerCont = undefined + +lexStream :: P [RlpToken] +lexStream = do + t <- lexToken + case t of + Located _ TokenEOF -> pure [TokenEOF] + Located _ t -> (t:) <$> lexStream + +lexTest :: Text -> Maybe [RlpToken] +lexTest s = execP' lexStream s + +indentLevel :: P Int +indentLevel = do + pos <- use (psInput . aiPos) + pure (pos ^. _2) + +insertToken :: RlpToken -> P (Located RlpToken) +insertToken t = do + pos <- use (psInput . aiPos) + pure (Located (pos, 0) t) + +popLayout :: P Layout +popLayout = do + traceM "pop layout" + ctx <- preuse (psLayoutStack . _head) + psLayoutStack %= (drop 1) + case ctx of + Just l -> pure l + Nothing -> error "uhh" + +pushLayout :: Layout -> P () +pushLayout l = do + traceM "push layout" + psLayoutStack %= (l:) + +popLexState :: P () +popLexState = do + psLexState %= tail + +insertSemicolon, insertLBrace, insertRBrace :: P (Located RlpToken) +insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV +insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV +insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV + +cmpLayout :: P Ordering +cmpLayout = do + i <- indentLevel + ctx <- preuse (psLayoutStack . _head) + case ctx of + Just (Implicit n) -> pure (i `compare` n) + _ -> pure GT + +doBol :: LexerAction (Located RlpToken) +doBol inp l = do + off <- cmpLayout + i <- indentLevel + traceM $ "i: " <> show i + -- important that we pop the lex state lest we find our lexer diverging + popLexState + case off of + -- the line is aligned with the previous. it therefore belongs to the + -- same list + EQ -> insertSemicolon + -- the line is indented further than the previous, so we assume it is a + -- line continuation. ignore it and move on! + GT -> lexToken + -- the line is indented less than the previous, pop the layout stack and + -- insert a closing brace. + LT -> popLayout >> insertRBrace + +thenDo :: LexerAction a -> P b -> LexerAction a +thenDo act p inp l = act inp l <* p + +explicitLBrace :: LexerAction (Located RlpToken) +explicitLBrace inp l = do + pushLayout Explicit + constToken TokenLBrace inp l + +explicitRBrace :: LexerAction (Located RlpToken) +explicitRBrace inp l = do + popLayout + constToken TokenRBrace inp l + +doLayout :: LexerAction (Located RlpToken) +doLayout _ _ = do + i <- indentLevel + pushLayout (Implicit i) + popLexState + insertLBrace + +} + -- 2.52.0 From 1c035d092a1d838ec90e5385e45929766c54760c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 13:31:15 -0700 Subject: [PATCH 084/192] works --- Makefile_happysrcs | 4 +- src/Rlp/Lex.x | 92 ++++++++++++++++++++++++++++++++---------- src/Rlp/Parse.y | 42 +++++++++++-------- src/Rlp/Parse/Types.hs | 5 ++- src/Rlp/Syntax.hs | 2 +- 5 files changed, 103 insertions(+), 42 deletions(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index 35c2ca8..e0dc43e 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -1,7 +1,7 @@ HAPPY = happy -HAPPY_OPTS = +HAPPY_OPTS = -a -g -c ALEX = alex -ALEX_OPTS = -d +ALEX_OPTS = -g SRC = src CABAL_BUILD = dist-newstyle/build/x86_64-osx/ghc-9.6.2/rlp-0.1.0.0/build diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 18592f8..55b0191 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -1,5 +1,5 @@ { -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ViewPatterns, LambdaCase #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} module Rlp.Lex @@ -7,7 +7,8 @@ module Rlp.Lex , RlpToken(..) , Located(..) , lexToken - , lexerCont + , lexDebug + , lexCont ) where import Codec.Binary.UTF8.String (encodeChar) @@ -30,33 +31,60 @@ import Rlp.Parse.Types $whitechar = [ \t\n\r\f\v] +$nl = [\n\r] +$white_no_nl = $white # $nl + $lower = [a-z \_] $upper = [A-Z] $alpha = [$lower $upper] $digit = 0-9 -$nl = [\n\r] -$white_no_nl = $white # $nl - +$special = [\(\)\,\;\[\]\{\}] $namechar = [$alpha $digit \' \#] +$asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] + +@decimal = $digit+ @varname = $lower $namechar* +@conname = $upper $namechar* +@consym = \: $asciisym* +@varsym = $asciisym+ -@digits = $digit+ +@reservedname = + case|data|do|import|in|let|letrec|module|of|where + +@reservedop = + "=" | \\ | "->" | "|" rlp :- - -- skip whitespace - $white_no_nl+ ; - -- TODO: don't treat operators like (-->) as comments - "--".* ; +-- everywhere: skip whitespace +$white_no_nl+ ; +-- everywhere: skip comments +-- TODO: don't treat operators like (-->) as comments +"--".* ; + +-- we are indentation-sensitive! do not skip NLs!. upon encountering a newline, +-- we check indentation and potentially insert extra tokens. search this file +-- for the definition of `doBol` +<0> \n { beginPush bol } + +-- scan various identifiers and reserved words. order is important here! <0> { - \n { beginPush bol } + @reservedname { tokenWith lexReservedName } + @conname { tokenWith TokenConName } @varname { tokenWith TokenVarName } - @digits { tokenWith (TokenLitInt . readInt) } - "=" { constToken TokenEquals } + @reservedop { tokenWith lexReservedOp } + @consym { tokenWith TokenConSym } + @varsym { tokenWith TokenVarSym } +} + +-- literals -- currently this is just unsigned integer literals +<0> +{ + @decimal { tokenWith (TokenLitInt . readInt) } } -- control characters @@ -86,6 +114,20 @@ rlp :- { +lexReservedName :: Text -> RlpToken +lexReservedName = \case + "data" -> TokenData + "case" -> TokenCase + "of" -> TokenOf + "let" -> TokenLet + "in" -> TokenIn + +lexReservedOp :: Text -> RlpToken +lexReservedOp = \case + "=" -> TokenEquals + "::" -> TokenHasType + "|" -> TokenPipe + -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action thenBegin :: LexerAction a -> Int -> LexerAction a @@ -173,6 +215,7 @@ initParseState s = ParseState -- which then returns to state 0 which continues the normal lexing process. , _psLexState = [layout_top,0] , _psInput = initAlexInput s + , _psOpTable = mempty } initAlexInput :: Text -> AlexInput @@ -188,7 +231,7 @@ lexToken = do inp <- getInput c <- getLexState st <- use id - traceM $ "st: " <> show st + -- traceM $ "st: " <> show st case alexScan inp c of AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF AlexSkip inp' l -> do @@ -196,11 +239,10 @@ lexToken = do lexToken AlexToken inp' l act -> do psInput .= inp' - traceShowM inp' act inp l -lexerCont :: (Located RlpToken -> P a) -> P a -lexerCont = undefined +lexCont :: (Located RlpToken -> P a) -> P a +lexCont = (lexToken >>=) lexStream :: P [RlpToken] lexStream = do @@ -209,6 +251,12 @@ lexStream = do Located _ TokenEOF -> pure [TokenEOF] Located _ t -> (t:) <$> lexStream +lexDebug :: (Located RlpToken -> P a) -> P a +lexDebug k = do + t <- lexToken + traceM $ "token: " <> show t + k t + lexTest :: Text -> Maybe [RlpToken] lexTest s = execP' lexStream s @@ -224,7 +272,7 @@ insertToken t = do popLayout :: P Layout popLayout = do - traceM "pop layout" + -- traceM "pop layout" ctx <- preuse (psLayoutStack . _head) psLayoutStack %= (drop 1) case ctx of @@ -233,7 +281,7 @@ popLayout = do pushLayout :: Layout -> P () pushLayout l = do - traceM "push layout" + -- traceM "push layout" psLayoutStack %= (l:) popLexState :: P () @@ -241,9 +289,9 @@ popLexState = do psLexState %= tail insertSemicolon, insertLBrace, insertRBrace :: P (Located RlpToken) -insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV -insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV -insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV +insertSemicolon = {- traceM "inserting semi" >> -} insertToken TokenSemicolonV +insertLBrace = {- traceM "inserting lbrace" >> -} insertToken TokenLBraceV +insertRBrace = {- traceM "inserting rbrace" >> -} insertToken TokenRBraceV cmpLayout :: P Ordering cmpLayout = do diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 3205988..8152f66 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -1,62 +1,72 @@ { module Rlp.Parse ( parseRlpProgram + , parseTest ) where import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types +import Data.Fix +import Data.Functor.Const } %name parseRlpProgram StandaloneProgram +%name parseTest VL %monad { P } -%lexer { lexerCont } { Located _ TokenEOF } +%lexer { lexDebug } { Located _ TokenEOF } %error { parseError } %tokentype { Located RlpToken } %token varname { Located _ (TokenVarName $$) } + conname { Located _ (TokenConName $$) } + data { Located _ TokenData } litint { Located _ (TokenLitInt $$) } '=' { Located _ TokenEquals } + '|' { Located _ TokenPipe } ';' { Located _ TokenSemicolon } - ';?' { Located _ TokenSemicolonV } + vsemi { Located _ TokenSemicolonV } '{' { Located _ TokenLBrace } '}' { Located _ TokenRBrace } - '{?' { Located _ TokenLBraceV } - '?}' { Located _ TokenRBraceV } - eof { Located _ TokenEOF } + vlbrace { Located _ TokenLBraceV } + vrbrace { Located _ TokenRBraceV } %% StandaloneProgram :: { [PartialDecl'] } -StandaloneProgram : VL Decls VR eof { $2 } +StandaloneProgram : '{' Decls '}' { $2 } + | VL Decls VR { $2 } VL :: { () } -VL : '{?' { () } +VL : vlbrace { () } VR :: { () } -VR : '?}' { () } +VR : vrbrace { () } | error { () } Decls :: { [PartialDecl'] } -Decls : Decl Semi Decls { $1 : $3 } - | Decl Semi { [$1] } +Decls : Decl VS Decls { $1 : $3 } + | Decl VS { [$1] } | Decl { [$1] } Semi :: { Located RlpToken } Semi : ';' { $1 } - | ';?' { $1 } + +VS :: { Located RlpToken } +VS : ';' { $1 } + | vsemi { $1 } Decl :: { PartialDecl' } -Decl : FunDecl { undefined } +Decl : FunDecl { $1 } FunDecl :: { PartialDecl' } -FunDecl : varname '=' Expr { undefined } +FunDecl : Var '=' Expr { FunD $1 [] (Const $3) Nothing } -Expr :: { RlpExpr' } -Expr : Literal { LitE $1 } - | Var { VarE $1 } +Expr :: { PartialExpr' } +Expr : Literal { Fix . E $ LitEF $1 } + | Var { Fix . E $ VarEF $1 } Literal :: { Lit' } Literal : litint { IntL $1 } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 03f24f8..2ec6079 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -42,8 +42,10 @@ data RlpToken | TokenConName Name | TokenVarSym Name | TokenConSym Name - -- keywords + -- reserved words | TokenData + | TokenCase + | TokenOf | TokenLet | TokenIn -- reserved ops @@ -87,6 +89,7 @@ data ParseState = ParseState { _psLayoutStack :: [Layout] , _psLexState :: [Int] , _psInput :: AlexInput + , _psOpTable :: OpTable } deriving Show diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index bf35445..18de5a1 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -65,7 +65,7 @@ type RlpProgram' = RlpProgram Name -- accounted for, we may complete the parsing task and get a proper @[Decl -- RlpExpr Name]@. -data Decl e b = FunD VarId [Pat b] (e b) (Where b) +data Decl e b = FunD VarId [Pat b] (e b) (Maybe (Where b)) | TySigD [VarId] Type | DataD ConId [Name] [ConAlt] | InfixD Assoc Int Name -- 2.52.0 From a1a50bd01381cf59499484e0212e7029e855a01f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 14:58:26 -0700 Subject: [PATCH 085/192] now we're fucking GETTING SOMEWHERE --- rlp.cabal | 2 + src/Rlp/Lex.x.old | 280 ------------------------------- src/Rlp/Lex.x.orig | 327 ------------------------------------- src/Rlp/Parse.y | 78 +++++++-- src/Rlp/Parse/Associate.hs | 99 +++++++++++ src/Rlp/Parse/Types.hs | 2 + src/Rlp/Syntax.hs | 1 + 7 files changed, 169 insertions(+), 620 deletions(-) delete mode 100644 src/Rlp/Lex.x.old delete mode 100644 src/Rlp/Lex.x.orig create mode 100644 src/Rlp/Parse/Associate.hs diff --git a/rlp.cabal b/rlp.cabal index 39d6379..dc47c0d 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -33,6 +33,7 @@ library , Rlp.Syntax -- , Rlp.Parse.Decls , Rlp.Parse + , Rlp.Parse.Associate , Rlp.Lex , Rlp.Parse.Types @@ -66,6 +67,7 @@ library , recursion-schemes >= 5.2.2 && < 5.3 , data-fix >= 0.3.2 && < 0.4 , utf8-string >= 1.0.2 && < 1.1 + , extra >= 1.7.0 && < 2 hs-source-dirs: src default-language: GHC2021 diff --git a/src/Rlp/Lex.x.old b/src/Rlp/Lex.x.old deleted file mode 100644 index 533c94c..0000000 --- a/src/Rlp/Lex.x.old +++ /dev/null @@ -1,280 +0,0 @@ -{ -{-# LANGUAGE GeneralisedNewtypeDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE OverloadedStrings #-} -module Rlp.Lex - ( P(..) - , RlpToken(..) - , Located(..) - , AlexPosn - , lexer - , lexerCont - ) - where -import Control.Monad -import Data.Functor.Identity -import Data.Char (digitToInt) -import Core.Syntax (Name) -import Data.Monoid (First) -import Data.Maybe -import Data.Text (Text) -import Data.Text qualified as T -import Data.Default -import Lens.Micro.Mtl -import Lens.Micro -import Lens.Micro.TH - -import Debug.Trace -} - -$whitechar = [ \t\n\r\f\v] - -$lower = [a-z \_] -$upper = [A-Z] -$alpha = [$lower $upper] -$digit = 0-9 - -$nl = [\n\r] -$white_no_nl = $white # $nl - -$namechar = [$alpha $digit \' \#] - -@varname = $lower $namechar* - -@digits = $digit+ - -rlp :- - - -- skip whitespace - $white_no_nl+ ; - -- TODO: don't treat operators like (-->) as comments - "--".* ; - ";" { constToken TokenSemicolon } - -- "{" { explicitLBrace } - -- "}" { explicitRBrace } - -<0> -{ - \n { begin bol } -} - - -{ - @varname { tokenWith TokenVarName } - @digits { tokenWith (TokenLitInt . readInt) } - "=" { constToken TokenEquals } - \n { begin bol } -} - --- consume all whitespace leaving us at the beginning of the next non-empty --- line. we then compare the indentation of that line to the enclosing layout --- context and proceed accordingly - -{ - $whitechar ; - \n ; - () { doBol `andBegin` one } -} - -{ - -readInt :: Text -> Int -readInt = T.foldr f 0 where - f c n = digitToInt c + 10*n - --- | @andBegin@, with the subtle difference that the start code is set --- /after/ the action -thenBegin :: AlexAction a -> Int -> AlexAction a -thenBegin act c inp l = do - a <- act inp l - alexSetStartCode c - pure a - -constToken :: RlpToken -> AlexAction (Located RlpToken) -constToken t inp _ = pure $ Located (inp ^. _1) t - -tokenWith :: (Text -> RlpToken) -> AlexAction (Located RlpToken) -tokenWith tf (p,_,_,s) l = pure $ Located p (tf $ T.take l s) - -alexEOF :: Alex (Located RlpToken) -alexEOF = do - inp <- alexGetInput - pure (Located (inp ^. _1) TokenEOF) - -data RlpToken - -- literals - = TokenLitInt Int - -- identifiers - | TokenVarName Name - | TokenConName Name - | TokenVarSym Name - | TokenConSym Name - -- keywords - | TokenData - | TokenPipe - | TokenLet - | TokenIn - -- control symbols - | TokenEquals - | TokenSemicolon - | TokenLBrace - | TokenRBrace - -- 'virtual' control symbols, inserted by the lexer without any correlation - -- to a specific symbol - | TokenSemicolonV - | TokenLBraceV - | TokenRBraceV - | TokenEOF - deriving (Show) - -newtype P a = P { runP :: ParseState -> Alex (ParseState, Maybe a) } - deriving (Functor) - -execP :: P a -> ParseState -> Text -> Either String a -execP p st s = snd <$> runAlex s (runP p st) - -execP' :: P a -> Text -> Either String a -execP' p = execP p def - -data ParseState = ParseState - { _psLayoutStack :: [Layout] - , _psLexState :: [Int] - } - -instance Default ParseState where - def = ParseState { } - -instance Applicative P where - pure a = P $ \st -> pure (st,a) - liftA2 = liftM2 - -instance Monad P where - p >>= k = P $ \st -> do - (st',a) <- runP p st - runP (k a) st' - -data Layout = Explicit - | Implicit Int - deriving (Show, Eq) - -data Located a = Located AlexPosn a - deriving (Show) - -psLayoutStack :: Lens' AlexUserState [Layout] -psLayoutStack = lens _psLayoutStack - (\ s l -> s { _psLayoutStack = l }) - -lexer :: P (Located RlpToken) -lexer = P $ \st -> (st,) <$> lexToken - -lexerCont :: (Located RlpToken -> P a) -> P a -lexerCont = (lexer >>=) - -lexStream :: Alex [RlpToken] -lexStream = do - t <- lexToken - case t of - Located _ TokenEOF -> pure [TokenEOF] - Located _ a -> (a:) <$> lexStream - -lexTest :: Text -> Either String [RlpToken] -lexTest = flip runAlex lexStream - -lexToken :: Alex (Located RlpToken) -lexToken = alexMonadScan - -getsAus :: (AlexUserState -> b) -> Alex b -getsAus k = alexGetUserState <&> k - -useAus :: Getting a AlexUserState a -> Alex a -useAus l = do - aus <- alexGetUserState - pure (aus ^. l) - -preuseAus :: Getting (First a) AlexUserState a -> Alex (Maybe a) -preuseAus l = do - aus <- alexGetUserState - pure (aus ^? l) - -modifyingAus :: ASetter' AlexUserState a -> (a -> a) -> Alex () -modifyingAus l f = do - aus <- alexGetUserState - alexSetUserState (aus & l %~ f) - -indentLevel :: Alex Int -indentLevel = do - inp <- alexGetInput - let col = inp ^. _1 - & \ (AlexPn _ _ c) -> c - pure col - -cmpLayout :: Alex Ordering -cmpLayout = do - i <- indentLevel - ctx <- preuseAus (ausLayoutStack . _head) - case ctx ^. non (Implicit 1) of - Implicit n -> pure (i `compare` n) - Explicit -> pure GT - -insertToken :: RlpToken -> Alex (Located RlpToken) -insertToken t = do - inp <- alexGetInput - pure (Located (inp ^. _1) t) - -insertSemicolon, insertLBrace, insertRBrace :: Alex (Located RlpToken) -insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV -insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV -insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV - --- pop the layout stack and jump to the popped return code -popLayout :: Alex Layout -popLayout = do - traceM "pop layout" - ctx <- preuseAus (ausLayoutStack . _head) - modifyingAus ausLayoutStack (drop 1) - case ctx of - Just l -> pure l - Nothing -> error "uhh" - -pushLayout :: Layout -> Alex () -pushLayout l = do - traceM "push layout" - modifyingAus ausLayoutStack (l:) - -pushLexState :: Alex () -pushLexState = do - undefined - -doBol :: AlexAction (Located RlpToken) -doBol inp len = do - off <- cmpLayout - case off of - -- the line is aligned with the previous. it therefore belongs to the - -- same list - EQ -> insertSemicolon - -- the line is indented further than the previous, so we assume it is a - -- line continuation. ignore it and move on! - GT -> undefined -- alexSetStartCode one >> lexToken - -- the line is indented less than the previous, pop the layout stack and - -- insert a closing brace. - LT -> popLayout >> insertRBrace - -explicitLBrace, explicitRBrace :: AlexAction (Located RlpToken) - -explicitLBrace _ _ = do - pushLayout Explicit - insertToken TokenLBrace - -explicitRBrace _ _ = do - popLayout - insertToken TokenRBrace - -doLayout :: AlexAction (Located RlpToken) -doLayout _ _ = do - i <- indentLevel - pushLayout (Implicit i) - traceM $ "layout " <> show i - insertLBrace - -} - diff --git a/src/Rlp/Lex.x.orig b/src/Rlp/Lex.x.orig deleted file mode 100644 index 184e2c6..0000000 --- a/src/Rlp/Lex.x.orig +++ /dev/null @@ -1,327 +0,0 @@ -{ -{-# LANGUAGE ViewPatterns, LambdaCase #-} -{-# LANGUAGE GeneralisedNewtypeDeriving #-} -{-# LANGUAGE OverloadedStrings #-} -module Rlp.Lex - ( P(..) - , RlpToken(..) - , Located(..) - , lexToken - , lexerCont - ) - where -import Codec.Binary.UTF8.String (encodeChar) -import Control.Monad -import Core.Syntax (Name) -import Data.Functor.Identity -import Data.Char (digitToInt) -import Data.Monoid (First) -import Data.Maybe -import Data.Text (Text) -import Data.Text qualified as T -import Data.Word -import Data.Default -import Lens.Micro.Mtl -import Lens.Micro - -import Debug.Trace -import Rlp.Parse.Types -} - -$whitechar = [ \t\n\r\f\v] - -$lower = [a-z \_] -$upper = [A-Z] -$alpha = [$lower $upper] -$digit = 0-9 - -$nl = [\n\r] -$white_no_nl = $white # $nl - -$namechar = [$alpha $digit \' \#] -$reservedsym = [\(\)\,\;\[\]\`\{\}] -$asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] -$namesym = $asciisym # \; - -@reservedop = - "=" | \\ | "->" | "::" | "|" - -@varname = $lower $namechar* -@conname = $upper $namechar* -@varsym = $namesym+ -@consym = \: $namesym* - - -@decimal = $digit+ - -rlp :- - - -- skip whitespace - $white_no_nl+ ; - -- TODO: don't treat operators like (-->) as comments - "--".* ; - -<0> -{ - \n { beginPush bol } - @varname { tokenWith TokenVarName } - @decimal { tokenWith (TokenLitInt . readInt) } - @reservedop { tokenWith readReservedOp } -} - --- control characters -<0> -{ - "{" { explicitLBrace } - "}" { explicitRBrace } - ";" { constToken TokenSemicolon } -} - --- consume all whitespace leaving us at the beginning of the next non-empty --- line. we then compare the indentation of that line to the enclosing layout --- context and proceed accordingly - -{ - $whitechar ; - \n ; - () { doBol } -} - - -{ - \n ; - "{" { explicitLBrace `thenDo` popLexState } - () { doLayout } -} - -{ - -readReservedOp :: Text -> RlpToken -readReservedOp = \case - "=" -> TokenEquals - "\\" -> TokenLambda - "->" -> TokenArrow - "::" -> TokenHasType - s -> error (show s) - --- | @andBegin@, with the subtle difference that the start code is set --- /after/ the action -thenBegin :: LexerAction a -> Int -> LexerAction a -thenBegin act c inp l = do - a <- act inp l - psLexState . _head .= c - pure a - -andBegin :: LexerAction a -> Int -> LexerAction a -andBegin act c inp l = do - psLexState . _head .= c - act inp l - -beginPush :: Int -> LexerAction (Located RlpToken) -beginPush n _ _ = pushLexState n >> lexToken - -alexGetByte :: AlexInput -> Maybe (Word8, AlexInput) -alexGetByte inp = case inp ^. aiBytes of - [] -> do - (c,t) <- T.uncons (inp ^. aiSource) - let (b:bs) = encodeChar c - -- tail the source - inp' = inp & aiSource .~ t - -- record the excess bytes for successive calls - & aiBytes .~ bs - -- report the previous char - & aiPrevChar .~ c - -- update the position - & aiPos %~ \ (ln,col) -> - if (inp ^. aiPrevChar) == '\n' - then (ln+1,1) - else (ln,col+1) - pure (b, inp') - - _ -> Just (head bs, inp') - where - (bs, inp') = inp & aiBytes <<%~ drop 1 - -getInput :: P AlexInput -getInput = use psInput - -takeInput :: Int -> AlexInput -> Text -takeInput n inp = T.cons c cs - where - c = inp ^. aiPrevChar - cs = T.take (max 0 (n-1)) $ inp ^. aiSource - -getLexState :: P Int -getLexState = use (psLexState . singular _head) - -alexInputPrevChar :: AlexInput -> Char -alexInputPrevChar = view aiPrevChar - -pushLexState :: Int -> P () -pushLexState n = psLexState %= (n:) - -readInt :: Text -> Int -readInt = T.foldr f 0 where - f c n = digitToInt c + 10*n - -constToken :: RlpToken -> LexerAction (Located RlpToken) -constToken t inp l = do - pos <- use (psInput . aiPos) - pure (Located (pos,l) t) - -tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) -tokenWith tf inp l = do - pos <- getPos - let t = takeInput l inp - pure (Located (pos,l) (tf t)) - -getPos :: P Position -getPos = use (psInput . aiPos) - -alexEOF :: P (Located RlpToken) -alexEOF = do - inp <- getInput - pure (Located undefined TokenEOF) - -execP :: P a -> ParseState -> Maybe a -execP p st = runP p st & snd - -execP' :: P a -> Text -> Maybe a -execP' p s = execP p st where - st = initParseState s - -initParseState :: Text -> ParseState -initParseState s = ParseState - { _psLayoutStack = [] - -- IMPORTANT: the initial state is `bol` to begin the top-level layout, - -- which then returns to state 0 which continues the normal lexing process. - , _psLexState = [layout_top,0] - , _psInput = initAlexInput s - } - -initAlexInput :: Text -> AlexInput -<<<<<<< Updated upstream -initAlexInput s = AlexInput - { _aiPrevChar = '\0' -======= -initAlexInput t = AlexInput - { _aiPrevChar = c ->>>>>>> Stashed changes - , _aiSource = s - , _aiBytes = [] - , _aiPos = (1,1) - } - where - (c,s) = fromJust $ T.uncons t - b = encodeChar c - -lexToken :: P (Located RlpToken) -lexToken = do - inp <- getInput - c <- getLexState - st <- use id - traceM $ "st: " <> show st - case alexScan inp c of - AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF - AlexSkip inp' l -> do - psInput .= inp' - lexToken - AlexToken inp' l act -> do - psInput .= inp' - traceShowM inp' - act inp l - -lexerCont :: (Located RlpToken -> P a) -> P a -lexerCont = undefined - -lexStream :: P [RlpToken] -lexStream = do - t <- lexToken - case t of - Located _ TokenEOF -> pure [TokenEOF] - Located _ t -> (t:) <$> lexStream - -lexTest :: Text -> Maybe [RlpToken] -lexTest s = execP' lexStream s - -indentLevel :: P Int -indentLevel = do - pos <- use (psInput . aiPos) - pure (pos ^. _2) - -insertToken :: RlpToken -> P (Located RlpToken) -insertToken t = do - pos <- use (psInput . aiPos) - pure (Located (pos, 0) t) - -popLayout :: P Layout -popLayout = do - traceM "pop layout" - ctx <- preuse (psLayoutStack . _head) - psLayoutStack %= (drop 1) - case ctx of - Just l -> pure l - Nothing -> error "uhh" - -pushLayout :: Layout -> P () -pushLayout l = do - traceM "push layout" - psLayoutStack %= (l:) - -popLexState :: P () -popLexState = do - psLexState %= tail - -insertSemicolon, insertLBrace, insertRBrace :: P (Located RlpToken) -insertSemicolon = traceM "inserting semi" >> insertToken TokenSemicolonV -insertLBrace = traceM "inserting lbrace" >> insertToken TokenLBraceV -insertRBrace = traceM "inserting rbrace" >> insertToken TokenRBraceV - -cmpLayout :: P Ordering -cmpLayout = do - i <- indentLevel - ctx <- preuse (psLayoutStack . _head) - case ctx of - Just (Implicit n) -> pure (i `compare` n) - _ -> pure GT - -doBol :: LexerAction (Located RlpToken) -doBol inp l = do - off <- cmpLayout - i <- indentLevel - traceM $ "i: " <> show i - -- important that we pop the lex state lest we find our lexer diverging - popLexState - case off of - -- the line is aligned with the previous. it therefore belongs to the - -- same list - EQ -> insertSemicolon - -- the line is indented further than the previous, so we assume it is a - -- line continuation. ignore it and move on! - GT -> lexToken - -- the line is indented less than the previous, pop the layout stack and - -- insert a closing brace. - LT -> popLayout >> insertRBrace - -thenDo :: LexerAction a -> P b -> LexerAction a -thenDo act p inp l = act inp l <* p - -explicitLBrace :: LexerAction (Located RlpToken) -explicitLBrace inp l = do - pushLayout Explicit - constToken TokenLBrace inp l - -explicitRBrace :: LexerAction (Located RlpToken) -explicitRBrace inp l = do - popLayout - constToken TokenRBrace inp l - -doLayout :: LexerAction (Located RlpToken) -doLayout _ _ = do - i <- indentLevel - pushLayout (Implicit i) - popLexState - insertLBrace - -} - diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 8152f66..cd29a1f 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -1,18 +1,19 @@ { module Rlp.Parse ( parseRlpProgram - , parseTest ) where import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types +import Rlp.Parse.Associate +import Lens.Micro.Mtl +import Data.List.Extra import Data.Fix import Data.Functor.Const } %name parseRlpProgram StandaloneProgram -%name parseTest VL %monad { P } %lexer { lexDebug } { Located _ TokenEOF } @@ -27,17 +28,22 @@ import Data.Functor.Const '=' { Located _ TokenEquals } '|' { Located _ TokenPipe } ';' { Located _ TokenSemicolon } + '(' { Located _ TokenLParen } + ')' { Located _ TokenRParen } + '->' { Located _ TokenArrow } vsemi { Located _ TokenSemicolonV } '{' { Located _ TokenLBrace } '}' { Located _ TokenRBrace } vlbrace { Located _ TokenLBraceV } vrbrace { Located _ TokenRBraceV } +%right '->' + %% -StandaloneProgram :: { [PartialDecl'] } -StandaloneProgram : '{' Decls '}' { $2 } - | VL Decls VR { $2 } +StandaloneProgram :: { RlpProgram' } +StandaloneProgram : '{' Decls '}' {% mkProgram $2 } + | VL DeclsV VR {% mkProgram $2 } VL :: { () } VL : vlbrace { () } @@ -47,12 +53,14 @@ VR : vrbrace { () } | error { () } Decls :: { [PartialDecl'] } -Decls : Decl VS Decls { $1 : $3 } - | Decl VS { [$1] } +Decls : Decl ';' Decls { $1 : $3 } + | Decl ';' { [$1] } | Decl { [$1] } -Semi :: { Located RlpToken } -Semi : ';' { $1 } +DeclsV :: { [PartialDecl'] } +DeclsV : Decl VS Decls { $1 : $3 } + | Decl VS { [$1] } + | Decl { [$1] } VS :: { Located RlpToken } VS : ';' { $1 } @@ -60,22 +68,66 @@ VS : ';' { $1 } Decl :: { PartialDecl' } Decl : FunDecl { $1 } + | DataDecl { $1 } + +DataDecl :: { PartialDecl' } + : data Con TyParams '=' DataCons { DataD $2 $3 $5 } + +TyParams :: { [Name] } + : {- epsilon -} { [] } + | TyParams varname { $1 `snoc` $2 } + +DataCons :: { [ConAlt] } + : DataCons '|' DataCon { $1 `snoc` $3 } + | DataCon { [$1] } + +DataCon :: { ConAlt } + : Con Type1s { ConAlt $1 $2 } + +Type1s :: { [Type] } + : {- epsilon -} { [] } + | Type1s Type1 { $1 `snoc` $2 } + +Type1 :: { Type } + : '(' Type ')' { $2 } + | conname { TyCon $1 } + | varname { TyVar $1 } + +Type :: { Type } + : Type '->' Type { $1 :-> $3 } + | Type1 { $1 } FunDecl :: { PartialDecl' } -FunDecl : Var '=' Expr { FunD $1 [] (Const $3) Nothing } +FunDecl : Var Params '=' Expr { FunD $1 $2 (Const $4) Nothing } + +Params :: { [Pat'] } +Params : {- epsilon -} { [] } + | Params Pat1 { $1 `snoc` $2 } + +Pat1 :: { Pat' } + : Var { VarP $1 } + | Lit { LitP $1 } Expr :: { PartialExpr' } -Expr : Literal { Fix . E $ LitEF $1 } +Expr : Lit { Fix . E $ LitEF $1 } | Var { Fix . E $ VarEF $1 } -Literal :: { Lit' } -Literal : litint { IntL $1 } +Lit :: { Lit' } +Lit : litint { IntL $1 } Var :: { VarId } Var : varname { NameVar $1 } +Con :: { ConId } + : conname { NameCon $1 } + { +mkProgram :: [PartialDecl'] -> P RlpProgram' +mkProgram ds = do + pt <- use psOpTable + pure $ RlpProgram (associate pt <$> ds) + parseError :: Located RlpToken -> P a parseError = error . show diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs new file mode 100644 index 0000000..837a81a --- /dev/null +++ b/src/Rlp/Parse/Associate.hs @@ -0,0 +1,99 @@ +{-# LANGUAGE PatternSynonyms, ViewPatterns, ImplicitParams #-} +module Rlp.Parse.Associate + ( associate + ) + where +-------------------------------------------------------------------------------- +import Data.HashMap.Strict qualified as H +import Data.Functor.Foldable +import Data.Functor.Const +import Lens.Micro +import Rlp.Parse.Types +import Rlp.Syntax +-------------------------------------------------------------------------------- + +associate :: OpTable -> PartialDecl' -> Decl' RlpExpr +associate pt (FunD n as b w) = FunD n as b' w + where b' = let ?pt = pt in completeExpr (getConst b) +associate pt (TySigD ns t) = TySigD ns t +associate pt (DataD n as cs) = DataD n as cs +associate pt (InfixD a p n) = InfixD a p n + +completeExpr :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' +completeExpr = cata completePartial + +completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' +completePartial (E e) = completeRlpExpr e +completePartial p@(B o l r) = completeB (build p) +completePartial (Par e) = completePartial e + +completeRlpExpr :: (?pt :: OpTable) => RlpExprF' RlpExpr' -> RlpExpr' +completeRlpExpr = embed + +completeB :: (?pt :: OpTable) => PartialE -> RlpExpr' +completeB p = case build p of + B o l r -> (o' `AppE` l') `AppE` r' + where + -- TODO: how do we know it's symbolic? + o' = VarE (SymVar o) + l' = completeB l + r' = completeB r + Par e -> completeB e + E e -> completeRlpExpr e + +build :: (?pt :: OpTable) => PartialE -> PartialE +build e = go id e (rightmost e) where + rightmost :: PartialE -> PartialE + rightmost (B _ _ r) = rightmost r + rightmost p@(E _) = p + rightmost p@(Par _) = p + + go :: (?pt :: OpTable) + => (PartialE -> PartialE) + -> PartialE -> PartialE -> PartialE + go f p@(WithInfo o _ r) = case r of + E _ -> mkHole o (f . f') + Par _ -> mkHole o (f . f') + B _ _ _ -> go (mkHole o (f . f')) r + where f' r' = p & pR .~ r' + go f _ = id + +mkHole :: (?pt :: OpTable) + => OpInfo + -> (PartialE -> PartialE) + -> PartialE + -> PartialE +mkHole _ hole p@(Par _) = hole p +mkHole _ hole p@(E _) = hole p +mkHole (a,d) hole p@(WithInfo (a',d') _ _) + | d' < d = above + | d' > d = below + | d == d' = case (a,a') of + -- left-associative operators of equal precedence are + -- associated left + (InfixL,InfixL) -> above + -- right-associative operators are handled similarly + (InfixR,InfixR) -> below + -- non-associative operators of equal precedence, or equal + -- precedence operators of different associativities are + -- invalid + (_, _) -> error "invalid expression" + where + above = p & pL %~ hole + below = hole p + +examplePrecTable :: OpTable +examplePrecTable = H.fromList + [ ("+", (InfixL,6)) + , ("*", (InfixL,7)) + , ("^", (InfixR,8)) + , (".", (InfixR,7)) + , ("~", (Infix, 9)) + , ("=", (Infix, 4)) + , ("&&", (Infix, 3)) + , ("||", (Infix, 2)) + , ("$", (InfixR,0)) + , ("&", (InfixL,0)) + ] + + diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 2ec6079..d53009a 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -58,6 +58,8 @@ data RlpToken | TokenSemicolon | TokenLBrace | TokenRBrace + | TokenLParen + | TokenRParen -- 'virtual' control symbols, inserted by the lexer without any correlation -- to a specific symbol | TokenSemicolonV diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 18de5a1..a79c496 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -55,6 +55,7 @@ data RlpModule b = RlpModule } newtype RlpProgram b = RlpProgram [Decl RlpExpr b] + deriving Show type RlpProgram' = RlpProgram Name -- 2.52.0 From 5ec625e0fd0558f6ef6e17dfc9d06f9bc0919bf0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 15 Jan 2024 15:20:04 -0700 Subject: [PATCH 086/192] i really need to learn git proper --- src/.DS_Store | Bin 6148 -> 0 bytes src/Rlp/Parse/Associate.hs | 1 + 2 files changed, 1 insertion(+) delete mode 100644 src/.DS_Store diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 4390780d02bbee1b3430a6fac093424b3e29cf90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zj35RBCIAV8Fop~hR0Kpbg3L%NFD^*R$xmWnVAu|o z8|)Ow?JNw=4EYR245`TOPb$dCEG{uHxW>rD%)-jX&cV*X%@G@%kzXEMl2}q&?37p( z4dR95=jSBB*ojGDnW^RR0wT`&c_oRNd8tJpCBc~~sY!`NG2xkcDf#72`K5U&#bCWq z2@XyU&UgXw>S{9+V;u!Uqgow>YBM8K9R+h!quN?d4pC)&>!A4ToZP(pPDpq%GD2tu zUMLNtx)>N3;NB?)1ECdl9B}YSGGz3OO2r#m^1iLtaDoq^T1=Y2n`ZNJ5 w532nk)iJ1|Mr{NzK?W2hph`j2JxD8v23N(543L_9v>^Zsp;3A?1n3_E0Pc55)&Kwi diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs index 837a81a..7446589 100644 --- a/src/Rlp/Parse/Associate.hs +++ b/src/Rlp/Parse/Associate.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms, ViewPatterns, ImplicitParams #-} module Rlp.Parse.Associate ( associate -- 2.52.0 From 7e6bee3d4af31be28be3afba9ef062135a54fa69 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 17 Jan 2024 10:08:57 -0700 Subject: [PATCH 087/192] infix exprs --- Makefile_happysrcs | 2 +- rlp.cabal | 1 + src/Rlp/Lex.x | 2 ++ src/Rlp/Parse.y | 52 ++++++++++++++++++++++++++++++++++++++---- src/Rlp/Parse/Types.hs | 3 +++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index e0dc43e..a535179 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -1,5 +1,5 @@ HAPPY = happy -HAPPY_OPTS = -a -g -c +HAPPY_OPTS = -a -g -c -d -i/tmp/happy-info ALEX = alex ALEX_OPTS = -g diff --git a/rlp.cabal b/rlp.cabal index dc47c0d..59867dc 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -12,6 +12,7 @@ category: Language build-type: Simple extra-doc-files: README.md -- extra-source-files: +tested-with: GHC==9.6.2 common warnings -- ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-unused-top-binds diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 55b0191..6fd2428 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -90,6 +90,8 @@ $white_no_nl+ ; -- control characters <0> { + "(" { constToken TokenLParen } + ")" { constToken TokenRParen } "{" { explicitLBrace } "}" { explicitRBrace } ";" { constToken TokenSemicolon } diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index cd29a1f..edc4874 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -1,28 +1,33 @@ { +{-# LANGUAGE LambdaCase #-} module Rlp.Parse - ( parseRlpProgram + ( parseRlpProg ) where import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types import Rlp.Parse.Associate +import Lens.Micro import Lens.Micro.Mtl +import Lens.Micro.Platform () import Data.List.Extra import Data.Fix import Data.Functor.Const } -%name parseRlpProgram StandaloneProgram +%name parseRlpProg StandaloneProgram %monad { P } -%lexer { lexDebug } { Located _ TokenEOF } +%lexer { lexCont } { Located _ TokenEOF } %error { parseError } %tokentype { Located RlpToken } %token varname { Located _ (TokenVarName $$) } conname { Located _ (TokenConName $$) } + consym { Located _ (TokenConSym $$) } + varsym { Located _ (TokenVarSym $$) } data { Located _ TokenData } litint { Located _ (TokenLitInt $$) } '=' { Located _ TokenEquals } @@ -36,6 +41,9 @@ import Data.Functor.Const '}' { Located _ TokenRBrace } vlbrace { Located _ TokenLBraceV } vrbrace { Located _ TokenRBraceV } + infixl { Located _ TokenInfixL } + infixr { Located _ TokenInfixR } + infix { Located _ TokenInfix } %right '->' @@ -67,8 +75,17 @@ VS : ';' { $1 } | vsemi { $1 } Decl :: { PartialDecl' } -Decl : FunDecl { $1 } + : FunDecl { $1 } | DataDecl { $1 } + | InfixDecl { $1 } + +InfixDecl :: { PartialDecl' } + : InfixWord litint InfixOp {% mkInfixD $1 $2 $3 } + +InfixWord :: { Assoc } + : infixl { InfixL } + | infixr { InfixR } + | infix { Infix } DataDecl :: { PartialDecl' } : data Con TyParams '=' DataCons { DataD $2 $3 $5 } @@ -109,9 +126,24 @@ Pat1 :: { Pat' } | Lit { LitP $1 } Expr :: { PartialExpr' } -Expr : Lit { Fix . E $ LitEF $1 } + : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } + | Expr1 { $1 } + +Expr1 :: { PartialExpr' } + : '(' Expr ')' { wrapFix . Par . unwrapFix $ $2 } + | Lit { Fix . E $ LitEF $1 } | Var { Fix . E $ VarEF $1 } +-- TODO: happy prefers left-associativity. doing such would require adjusting +-- the code in Rlp.Parse.Associate to expect left-associative input rather than +-- right. +InfixExpr :: { PartialExpr' } + : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } + +InfixOp :: { Name } + : consym { $1 } + | varsym { $1 } + Lit :: { Lit' } Lit : litint { IntL $1 } @@ -131,4 +163,14 @@ mkProgram ds = do parseError :: Located RlpToken -> P a parseError = error . show +mkInfixD :: Assoc -> Int -> Name -> P PartialDecl' +mkInfixD a p n = do + let opl :: Lens' ParseState (Maybe OpInfo) + opl = psOpTable . at n + opl <~ (use opl >>= \case + -- TODO: non-fatal error + Just o -> pure (Just o) + Nothing -> pure (Just (a,p)) + ) + pure $ InfixD a p n } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index d53009a..718a9e5 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -48,6 +48,9 @@ data RlpToken | TokenOf | TokenLet | TokenIn + | TokenInfixL + | TokenInfixR + | TokenInfix -- reserved ops | TokenArrow | TokenPipe -- 2.52.0 From d5663c1aadf235ef60c94d3671a83ba26d84234e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 17 Jan 2024 10:11:48 -0700 Subject: [PATCH 088/192] remove debug flags --- Makefile_happysrcs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index a535179..e0dc43e 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -1,5 +1,5 @@ HAPPY = happy -HAPPY_OPTS = -a -g -c -d -i/tmp/happy-info +HAPPY_OPTS = -a -g -c ALEX = alex ALEX_OPTS = -g -- 2.52.0 From d6ac991105a6e3ad89858eb1c39367a894b93cb8 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 17 Jan 2024 10:19:16 -0700 Subject: [PATCH 089/192] renamerlp --- src/{RLP => rlp2}/Syntax.hs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{RLP => rlp2}/Syntax.hs (100%) diff --git a/src/RLP/Syntax.hs b/src/rlp2/Syntax.hs similarity index 100% rename from src/RLP/Syntax.hs rename to src/rlp2/Syntax.hs -- 2.52.0 From 4e1c9dd750049fead7bf97fdf3142f274548f13f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 17 Jan 2024 10:19:48 -0700 Subject: [PATCH 090/192] rename rlp --- src/{rlp2 => Rlp}/Syntax.hs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{rlp2 => Rlp}/Syntax.hs (100%) diff --git a/src/rlp2/Syntax.hs b/src/Rlp/Syntax.hs similarity index 100% rename from src/rlp2/Syntax.hs rename to src/Rlp/Syntax.hs -- 2.52.0 From f47f325e34064da0dbe0a18e11576c4e741cce86 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 19 Jan 2024 14:09:26 -0700 Subject: [PATCH 091/192] compiles (kill me) man --- src/Compiler/JustRun.hs | 11 ++--- src/Compiler/RLPC.hs | 78 ++++++----------------------------- src/Compiler/RlpcError.hs | 34 ++++++++++++--- src/Control/Monad/Errorful.hs | 48 +++++++++------------ src/Core/Examples.hs | 8 ++++ src/Core/HindleyMilner.hs | 11 +++-- src/Core/Lex.x | 25 +++++------ src/Core/Parse.y | 52 +++++++++++------------ src/Core/TH.hs | 31 +++++--------- 9 files changed, 126 insertions(+), 172 deletions(-) diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs index df28db5..c3178f3 100644 --- a/src/Compiler/JustRun.hs +++ b/src/Compiler/JustRun.hs @@ -26,21 +26,22 @@ import Data.Function ((&)) import GM ---------------------------------------------------------------------------------- -justLexSrc :: String -> Either RlpcError [CoreToken] +-- justLexSrc :: String -> Either RlpcError [CoreToken] justLexSrc s = lexCoreR (T.pack s) & fmap (map $ \ (Located _ _ _ t) -> t) & rlpcToEither -justParseSrc :: String -> Either RlpcError Program' +-- justParseSrc :: String -> Either RlpcError Program' justParseSrc s = parse (T.pack s) & rlpcToEither where parse = lexCoreR >=> parseCoreProgR -justTypeCheckSrc :: String -> Either RlpcError Program' +-- justTypeCheckSrc :: String -> Either RlpcError Program' justTypeCheckSrc s = typechk (T.pack s) & rlpcToEither where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR -rlpcToEither :: RLPC e a -> Either e a -rlpcToEither = evalRLPC def >>> fmap fst +rlpcToEither = undefined + +{-# WARNING rlpcToEither "unimpl" #-} diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 266e06a..518e9fb 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -17,8 +17,6 @@ module Compiler.RLPC , RLPCIO , RLPCOptions(RLPCOptions) , RlpcError(..) - , IsRlpcError(..) - , rlpc , addFatal , addWound , MonadErrorful @@ -27,9 +25,6 @@ module Compiler.RLPC , evalRLPCT , evalRLPCIO , evalRLPC - , addRlpcWound - , addRlpcFatal - , liftRlpcErrs , rlpcLogFile , rlpcDebugOpts , rlpcEvaluator @@ -60,46 +55,25 @@ import Lens.Micro import Lens.Micro.TH ---------------------------------------------------------------------------------- --- TODO: fancy errors -newtype RLPCT e m a = RLPCT { - runRLPCT :: ReaderT RLPCOptions (ErrorfulT e m) a +newtype RLPCT m a = RLPCT { + runRLPCT :: forall e. (RlpcError e) + => ReaderT RLPCOptions (ErrorfulT e m) a } - -- TODO: incorrect ussage of MonadReader. RLPC should have its own - -- environment access functions - deriving (Functor, Applicative, Monad, MonadReader RLPCOptions) -deriving instance (MonadIO m) => MonadIO (RLPCT e m) +type RLPC = RLPCT Identity -instance MonadTrans (RLPCT e) where - lift = RLPCT . lift . lift +type RLPCIO = RLPCT IO -instance (MonadState s m) => MonadState s (RLPCT e m) where - state = lift . state +instance Functor (RLPCT m) where +instance Applicative (RLPCT m) where +instance Monad (RLPCT m) where -type RLPC e = RLPCT e Identity +evalRLPC = undefined +evalRLPCT = undefined +evalRLPCIO = undefined -type RLPCIO e = RLPCT e IO - -evalRLPCT :: RLPCOptions - -> RLPCT e m a - -> m (Either e (a, [e])) -evalRLPCT o = runRLPCT >>> flip runReaderT o >>> runErrorfulT - -evalRLPC :: RLPCOptions - -> RLPC e a - -> Either e (a, [e]) -evalRLPC o m = coerce $ evalRLPCT o m - -evalRLPCIO :: (Exception e) - => RLPCOptions - -> RLPCIO e a - -> IO (a, [e]) -evalRLPCIO o m = do - m' <- evalRLPCT o m - case m' of - -- TODO: errors - Left e -> throwIO e - Right a -> pure a +liftErrorful :: (RlpcError e) => ErrorfulT e m a -> RLPCT m a +liftErrorful e = undefined data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath @@ -113,32 +87,6 @@ data RLPCOptions = RLPCOptions data Evaluator = EvaluatorGM | EvaluatorTI deriving Show -data Severity = Error - | Warning - | Debug - deriving Show - --- temporary until we have a new doc building system -type ErrorDoc = String - -instance (Monad m) => MonadErrorful e (RLPCT e m) where - addWound = RLPCT . lift . addWound - addFatal = RLPCT . lift . addFatal - -liftRlpcErrs :: (IsRlpcError e, Monad m) - => RLPCT e m a -> RLPCT RlpcError m a -liftRlpcErrs m = RLPCT . ReaderT $ \r -> - mapErrors liftRlpcErr $ runRLPCT >>> (`runReaderT` r) $ m - -addRlpcWound :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m () -addRlpcWound = addWound . liftRlpcErr - -addRlpcFatal :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m () -addRlpcFatal = addWound . liftRlpcErr - -rlpc :: (Monad m) => ErrorfulT e m a -> RLPCT e m a -rlpc = RLPCT . ReaderT . const - ---------------------------------------------------------------------------------- instance Default RLPCOptions where diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 581d301..cd53964 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -1,15 +1,39 @@ +{-# LANGUAGE TemplateHaskell #-} module Compiler.RlpcError ( RlpcError(..) - , IsRlpcError(..) + , MsgEnvelope(..) + , Severity + , RlpcErrorDoc(..) + , SrcSpan(..) + , msgSpan + , msgDiagnostic + , msgSeverity ) where ---------------------------------------------------------------------------------- import Control.Monad.Errorful +import Lens.Micro.TH ---------------------------------------------------------------------------------- -data RlpcError = RlpcErr String -- temp - deriving Show +data MsgEnvelope = MsgEnvelope + { _msgSpan :: SrcSpan + , _msgDiagnostic :: forall e. (RlpcError e) => e + , _msgSeverity :: Severity + } -class IsRlpcError a where - liftRlpcErr :: a -> RlpcError +class RlpcError e where + liftRlpcError :: e -> RlpcErrorDoc + +data RlpcErrorDoc + +data Severity = SevWarning + | SevError + deriving Show + +data SrcSpan = SrcSpan + !Int -- ^ Line + !Int -- ^ Column + !Int -- ^ Length + +makeLenses ''MsgEnvelope diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index 789a4ad..2f75269 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -14,60 +14,52 @@ module Control.Monad.Errorful import Control.Monad.Trans import Data.Functor.Identity import Data.Coerce +import Data.HashSet (HashSet) +import Data.HashSet qualified as H import Lens.Micro ---------------------------------------------------------------------------------- -newtype ErrorfulT e m a = ErrorfulT { runErrorfulT :: m (Either e (a, [e])) } +newtype ErrorfulT e m a = ErrorfulT { runErrorfulT :: m (Maybe a, [e]) } type Errorful e = ErrorfulT e Identity -pattern Errorful :: (Either e (a, [e])) -> Errorful e a +pattern Errorful :: (Maybe a, [e]) -> Errorful e a pattern Errorful a = ErrorfulT (Identity a) -runErrorful :: Errorful e a -> Either e (a, [e]) +runErrorful :: Errorful e a -> (Maybe a, [e]) runErrorful m = coerce (runErrorfulT m) class (Applicative m) => MonadErrorful e m | m -> e where - addWound :: e -> m () - addFatal :: e -> m a - - -- not sure if i want to add this yet... - -- catchWound :: m a -> (e -> m a) -> m a + addWound :: e -> m () + addFatal :: e -> m a instance (Applicative m) => MonadErrorful e (ErrorfulT e m) where - addWound e = ErrorfulT $ pure . Right $ ((), [e]) - addFatal e = ErrorfulT $ pure . Left $ e + addWound e = ErrorfulT $ pure (Just (), [e]) + addFatal e = ErrorfulT $ pure (Nothing, [e]) instance MonadTrans (ErrorfulT e) where - lift m = ErrorfulT (Right . (,[]) <$> m) + lift m = ErrorfulT ((\x -> (Just x,[])) <$> m) instance (MonadIO m) => MonadIO (ErrorfulT e m) where liftIO = lift . liftIO instance (Functor m) => Functor (ErrorfulT e m) where - fmap f (ErrorfulT m) = ErrorfulT $ fmap (_1 %~ f) <$> m + fmap f (ErrorfulT m) = ErrorfulT (m & mapped . _1 . _Just %~ f) instance (Applicative m) => Applicative (ErrorfulT e m) where - pure a = ErrorfulT (pure . Right $ (a, [])) + pure a = ErrorfulT . pure $ (Just a, []) - m <*> a = ErrorfulT (m' `apply` a') - where - m' = runErrorfulT m - a' = runErrorfulT a - -- TODO: strict concatenation - apply = liftA2 $ liftA2 (\ (f,e1) (x,e2) -> (f x, e1 ++ e2)) + ErrorfulT m <*> ErrorfulT n = ErrorfulT $ m `apply` n where + apply :: m (Maybe (a -> b), [e]) -> m (Maybe a, [e]) -> m (Maybe b, [e]) + apply = liftA2 $ \ (mf,e1) (ma,e2) -> (mf <*> ma, e1 <> e2) instance (Monad m) => Monad (ErrorfulT e m) where ErrorfulT m >>= k = ErrorfulT $ do - m' <- m - case m' of - Right (a,es) -> runErrorfulT (k a) - Left e -> pure (Left e) + (a,es) <- m + case a of + Just x -> runErrorfulT (k x) + Nothing -> pure (Nothing, es) mapErrors :: (Monad m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a -mapErrors f m = ErrorfulT $ do - x <- runErrorfulT m - case x of - Left e -> pure . Left $ f e - Right (a,es) -> pure . Right $ (a, f <$> es) +mapErrors f m = undefined diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index efe953d..39680a4 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -15,6 +15,13 @@ import Core.Syntax import Core.TH ---------------------------------------------------------------------------------- +fac3 = undefined +sumList = undefined +constDivZero = undefined +idCase = undefined + +{-- + letrecExample :: Program' letrecExample = [coreProg| pair x y f = f x y; @@ -216,3 +223,4 @@ idCase = [coreProg| -- , ScDef "Cons" [] $ Con 2 2 -- ] +--} diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index d7277c4..ed01359 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -49,8 +49,7 @@ data TypeError deriving (Show, Eq) -- TODO: -instance IsRlpcError TypeError where - liftRlpcErr = RlpcErr . show +instance RlpcError TypeError where -- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may -- throw any number of fatal or nonfatal errors. Run with @runErrorful@. @@ -88,10 +87,10 @@ checkCoreProg p = scDefs where scname = sc ^. _lhs._1 -- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. -checkCoreProgR :: Program' -> RLPC RlpcError Program' -checkCoreProgR p = do - liftRlpcErrs . rlpc . checkCoreProg $ p - pure p +-- checkCoreProgR :: Program' -> RLPC Program' +checkCoreProgR = undefined + +{-# WARNING checkCoreProgR "unimpl" #-} -- | Infer the type of an expression under some context. -- diff --git a/src/Core/Lex.x b/src/Core/Lex.x index d5cdc1e..d076206 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -167,24 +167,23 @@ lexWith :: (Text -> CoreToken) -> Lexer lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s) -- | The main lexer driver. -lexCore :: Text -> RLPC SrcError [Located CoreToken] +lexCore :: Text -> RLPC [Located CoreToken] lexCore s = case m of - Left e -> addFatal err - where err = SrcError - { _errSpan = (0,0,0) -- TODO: location - , _errSeverity = Error - , _errDiagnostic = SrcErrLexical e - } + Left e -> undefined Right ts -> pure ts where m = runAlex s lexStream -lexCoreR :: Text -> RLPC RlpcError [Located CoreToken] -lexCoreR = liftRlpcErrs . lexCore +{-# WARNING lexCore "unimpl" #-} + +lexCoreR :: Text -> RLPC [Located CoreToken] +lexCoreR t = undefined + +{-# WARNING lexCoreR "unimpl" #-} -- | @lexCore@, but the tokens are stripped of location info. Useful for -- debugging -lexCore' :: Text -> RLPC SrcError [CoreToken] +lexCore' :: Text -> RLPC [CoreToken] lexCore' s = fmap f <$> lexCore s where f (Located _ _ _ t) = t @@ -200,12 +199,10 @@ data ParseError = ParErrLexical String deriving Show -- TODO: -instance IsRlpcError SrcError where - liftRlpcErr = RlpcErr . show +instance RlpcError SrcError where -- TODO: -instance IsRlpcError ParseError where - liftRlpcErr = RlpcErr . show +instance RlpcError ParseError where alexEOF :: Alex (Located CoreToken) alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 11e91be..abc6c70 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -10,7 +10,6 @@ module Core.Parse , parseCoreProg , parseCoreProgR , module Core.Lex -- temp convenience - , parseTmp , SrcError , Module ) @@ -34,7 +33,7 @@ import Data.HashMap.Strict qualified as H %name parseCoreProg StandaloneProgram %tokentype { Located CoreToken } %error { parseError } -%monad { RLPC SrcError } +%monad { RLPC } { happyBind } { happyPure } %token let { Located _ _ _ TokenLet } @@ -189,34 +188,21 @@ Con : '(' consym ')' { $2 } { -parseError :: [Located CoreToken] -> RLPC SrcError a -parseError (Located y x l _ : _) = addFatal err - where err = SrcError - { _errSpan = (y,x,l) - , _errSeverity = Error - , _errDiagnostic = SrcErrParse - } +parseError :: [Located CoreToken] -> RLPC a +parseError (Located y x l _ : _) = undefined -parseTmp :: IO (Module Name) -parseTmp = do - s <- TIO.readFile "/tmp/t.hs" - case parse s of - Left e -> error (show e) - Right (ts,_) -> pure ts - where - parse = evalRLPC def . (lexCore >=> parseCore) +{-# WARNING parseError "unimpl" #-} -exprPragma :: [String] -> RLPC SrcError (Expr Name) -exprPragma ("AST" : e) = astPragma e -exprPragma _ = addFatal err - where err = SrcError - { _errSpan = (0,0,0) -- TODO: span - , _errSeverity = Warning - , _errDiagnostic = SrcErrUnknownPragma "" -- TODO: missing pragma - } +exprPragma :: [String] -> RLPC (Expr Name) +exprPragma ("AST" : e) = undefined +exprPragma _ = undefined -astPragma :: [String] -> RLPC SrcError (Expr Name) -astPragma = pure . read . unwords +{-# WARNING exprPragma "unimpl" #-} + +astPragma :: [String] -> RLPC (Expr Name) +astPragma _ = undefined + +{-# WARNING astPragma "unimpl" #-} insTypeSig :: (Hashable b) => (b, Type) -> Program b -> Program b insTypeSig ts = programTypeSigs %~ uncurry H.insert ts @@ -230,8 +216,16 @@ insScDef sc = programScDefs %~ (sc:) singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty -parseCoreProgR :: [Located CoreToken] -> RLPC RlpcError Program' -parseCoreProgR = liftRlpcErrs . parseCoreProg +parseCoreProgR :: [Located CoreToken] -> RLPC Program' +parseCoreProgR a = undefined + +{-# WARNING parseCoreProgR "unimpl" #-} + +happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b +happyBind m k = m >>= k + +happyPure :: a -> RLPC a +happyPure a = pure a } diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 7d85bf5..28bb9c6 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -19,6 +19,7 @@ import Data.Default.Class (def) import Data.Text qualified as T import Core.Parse import Core.Lex +import Core.Syntax (Expr(Var)) import Core.HindleyMilner (checkCoreProgR) ---------------------------------------------------------------------------------- @@ -58,30 +59,20 @@ coreProgT = QuasiQuoter } qCore :: String -> Q Exp -qCore s = case parse (T.pack s) of - Left e -> error (show e) - Right (m,ts) -> lift m - where - parse = evalRLPC def . (lexCore >=> parseCore) +qCore s = undefined + +{-# WARNING qCore "unimpl" #-} qCoreExpr :: String -> Q Exp -qCoreExpr s = case parseExpr (T.pack s) of - Left e -> error (show e) - Right (m,ts) -> lift m - where - parseExpr = evalRLPC def . (lexCore >=> parseCoreExpr) +qCoreExpr s = undefined + +{-# WARNING qCoreExpr "unimpl" #-} qCoreProg :: String -> Q Exp -qCoreProg s = case parse (T.pack s) of - Left e -> error (show e) - Right (m,ts) -> lift m - where - parse = evalRLPC def . (lexCoreR >=> parseCoreProgR) +qCoreProg s = undefined + +{-# WARNING qCoreProg "unimpl" #-} qCoreProgT :: String -> Q Exp -qCoreProgT s = case parse (T.pack s) of - Left e -> error (show e) - Right (m,_) -> lift m - where - parse = evalRLPC def . (lexCoreR >=> parseCoreProgR >=> checkCoreProgR) +qCoreProgT s = undefined -- 2.52.0 From 257d02da876e493c5f6f83449007a3057c381b66 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 21 Jan 2024 11:53:41 -0700 Subject: [PATCH 092/192] RlpcError -> IsRlpcError --- src/Compiler/RLPC.hs | 6 +++--- src/Compiler/RlpcError.hs | 14 +++++++------- src/Core/HindleyMilner.hs | 2 +- src/Core/Lex.x | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 518e9fb..5acedc6 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -16,6 +16,7 @@ module Compiler.RLPC , RLPCT(..) , RLPCIO , RLPCOptions(RLPCOptions) + , IsRlpcError(..) , RlpcError(..) , addFatal , addWound @@ -56,8 +57,7 @@ import Lens.Micro.TH ---------------------------------------------------------------------------------- newtype RLPCT m a = RLPCT { - runRLPCT :: forall e. (RlpcError e) - => ReaderT RLPCOptions (ErrorfulT e m) a + runRLPCT :: ReaderT RLPCOptions (ErrorfulT RlpcError m) a } type RLPC = RLPCT Identity @@ -72,7 +72,7 @@ evalRLPC = undefined evalRLPCT = undefined evalRLPCIO = undefined -liftErrorful :: (RlpcError e) => ErrorfulT e m a -> RLPCT m a +liftErrorful :: ErrorfulT e m a -> RLPCT m a liftErrorful e = undefined data RLPCOptions = RLPCOptions diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index cd53964..755f05d 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -1,9 +1,9 @@ {-# LANGUAGE TemplateHaskell #-} module Compiler.RlpcError - ( RlpcError(..) + ( IsRlpcError(..) , MsgEnvelope(..) , Severity - , RlpcErrorDoc(..) + , RlpcError(..) , SrcSpan(..) , msgSpan , msgDiagnostic @@ -15,16 +15,16 @@ import Control.Monad.Errorful import Lens.Micro.TH ---------------------------------------------------------------------------------- -data MsgEnvelope = MsgEnvelope +data MsgEnvelope e = MsgEnvelope { _msgSpan :: SrcSpan - , _msgDiagnostic :: forall e. (RlpcError e) => e + , _msgDiagnostic :: e , _msgSeverity :: Severity } -class RlpcError e where - liftRlpcError :: e -> RlpcErrorDoc +class IsRlpcError e where + liftRlpcError :: e -> RlpcError -data RlpcErrorDoc +data RlpcError data Severity = SevWarning | SevError diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index ed01359..12c7436 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -49,7 +49,7 @@ data TypeError deriving (Show, Eq) -- TODO: -instance RlpcError TypeError where +instance IsRlpcError TypeError where -- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may -- throw any number of fatal or nonfatal errors. Run with @runErrorful@. diff --git a/src/Core/Lex.x b/src/Core/Lex.x index d076206..1136409 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -199,10 +199,10 @@ data ParseError = ParErrLexical String deriving Show -- TODO: -instance RlpcError SrcError where +instance IsRlpcError SrcError where -- TODO: -instance RlpcError ParseError where +instance IsRlpcError ParseError where alexEOF :: Alex (Located CoreToken) alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> -- 2.52.0 From 1a881399ab64c2caa5b4d760a454c2fd28b1568b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 21 Jan 2024 14:02:28 -0700 Subject: [PATCH 093/192] when the "Test suite rlp-test: PASS" hits i'm like atlas and the world is writing two lines of code --- rlp.cabal | 3 ++ src/Compiler/RLPC.hs | 34 +++++++++++++++----- src/Compiler/RlpcError.hs | 22 +++++++++++-- src/Control/Monad/Errorful.hs | 11 +++++-- src/Core/Examples.hs | 10 +++--- src/Core/HindleyMilner.hs | 23 +++++++++++--- src/Core/Lex.x | 10 +++--- src/Core/Parse.y | 8 ++--- src/Core/TH.hs | 58 +++++++++-------------------------- tst/Core/HindleyMilnerSpec.hs | 12 +++++--- tst/Rlp/Parse/DeclsSpec.hs | 0 11 files changed, 112 insertions(+), 79 deletions(-) delete mode 100644 tst/Rlp/Parse/DeclsSpec.hs diff --git a/rlp.cabal b/rlp.cabal index 59867dc..a48324a 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -73,6 +73,9 @@ library hs-source-dirs: src default-language: GHC2021 + default-extensions: + OverloadedStrings + executable rlpc import: warnings main-is: Main.hs diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 5acedc6..0de0638 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -36,6 +36,7 @@ module Compiler.RLPC , flagDDumpOpts , flagDDumpAST , def + , liftErrorful ) where ---------------------------------------------------------------------------------- @@ -47,6 +48,7 @@ import Control.Monad.Errorful import Compiler.RlpcError import Data.Functor.Identity import Data.Default.Class +import Data.Foldable import GHC.Generics (Generic) import Data.Hashable (Hashable) import Data.HashSet (HashSet) @@ -54,26 +56,44 @@ import Data.HashSet qualified as S import Data.Coerce import Lens.Micro import Lens.Micro.TH +import System.Exit ---------------------------------------------------------------------------------- newtype RLPCT m a = RLPCT { runRLPCT :: ReaderT RLPCOptions (ErrorfulT RlpcError m) a } + deriving (Functor, Applicative, Monad) type RLPC = RLPCT Identity type RLPCIO = RLPCT IO -instance Functor (RLPCT m) where -instance Applicative (RLPCT m) where -instance Monad (RLPCT m) where +evalRLPC :: RLPCOptions + -> RLPC a + -> (Maybe a, [RlpcError]) +evalRLPC opt r = runRLPCT r + & flip runReaderT opt + & runErrorful -evalRLPC = undefined +evalRLPCT :: (Monad m) + => RLPCOptions + -> RLPCT m a + -> m (Maybe a, [RlpcError]) evalRLPCT = undefined -evalRLPCIO = undefined -liftErrorful :: ErrorfulT e m a -> RLPCT m a -liftErrorful e = undefined +evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a +evalRLPCIO opt r = do + (ma,es) <- evalRLPCT opt r + putRlpcErrs es + case ma of + Just x -> pure x + Nothing -> die "Failed, no code compiled." + +putRlpcErrs :: [RlpcError] -> IO () +putRlpcErrs = traverse_ print + +liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT e m a -> RLPCT m a +liftErrorful e = RLPCT $ lift (liftRlpcErrors e) data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 755f05d..cff9375 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -1,4 +1,5 @@ {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE PatternSynonyms, ViewPatterns #-} module Compiler.RlpcError ( IsRlpcError(..) , MsgEnvelope(..) @@ -8,11 +9,16 @@ module Compiler.RlpcError , msgSpan , msgDiagnostic , msgSeverity + , liftRlpcErrors ) where ---------------------------------------------------------------------------------- import Control.Monad.Errorful -import Lens.Micro.TH +import Data.Text (Text) +import Data.Text qualified as T +import GHC.Exts (IsString(..)) +import Lens.Micro.Platform +import Lens.Micro.Platform.Internal ---------------------------------------------------------------------------------- data MsgEnvelope e = MsgEnvelope @@ -21,10 +27,17 @@ data MsgEnvelope e = MsgEnvelope , _msgSeverity :: Severity } +newtype RlpcError = Text [Text] + deriving Show + +instance IsString RlpcError where + fromString = Text . pure . T.pack + class IsRlpcError e where liftRlpcError :: e -> RlpcError -data RlpcError +instance IsRlpcError RlpcError where + liftRlpcError = id data Severity = SevWarning | SevError @@ -37,3 +50,8 @@ data SrcSpan = SrcSpan makeLenses ''MsgEnvelope +liftRlpcErrors :: (Functor m, IsRlpcError e) + => ErrorfulT e m a + -> ErrorfulT RlpcError m a +liftRlpcErrors = mapErrorful liftRlpcError + diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index 2f75269..5967b45 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -6,7 +6,7 @@ module Control.Monad.Errorful , runErrorfulT , Errorful , runErrorful - , mapErrors + , mapErrorful , MonadErrorful(..) ) where @@ -60,6 +60,11 @@ instance (Monad m) => Monad (ErrorfulT e m) where Just x -> runErrorfulT (k x) Nothing -> pure (Nothing, es) -mapErrors :: (Monad m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a -mapErrors f m = undefined +mapErrorful :: (Functor m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a +mapErrorful f (ErrorfulT m) = ErrorfulT $ + m & mapped . _2 . mapped %~ f + +-- when microlens-pro drops we can write this as +-- mapErrorful f = coerced . mapped . _2 . mappd %~ f +-- lol diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index 39680a4..2ca54e3 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -15,12 +15,12 @@ import Core.Syntax import Core.TH ---------------------------------------------------------------------------------- -fac3 = undefined -sumList = undefined -constDivZero = undefined -idCase = undefined +-- fac3 = undefined +-- sumList = undefined +-- constDivZero = undefined +-- idCase = undefined -{-- +--- letrecExample :: Program' letrecExample = [coreProg| diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 12c7436..ba9e987 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -25,6 +25,7 @@ import Control.Monad (foldM, void) import Control.Monad.Errorful (Errorful, addFatal) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) +import Text.Printf import Core.Syntax ---------------------------------------------------------------------------------- @@ -48,8 +49,20 @@ data TypeError | TyErrMissingTypeSig Name deriving (Show, Eq) --- TODO: instance IsRlpcError TypeError where + liftRlpcError = \case + -- todo: use anti-parser instead of show + TyErrCouldNotUnify t u -> Text + [ T.pack $ printf "Could not match type `%s' with `%s'." + (show t) (show u) + , "Expected: " <> tshow t + , "Got: " <> tshow u + ] + TyErrRecursiveType t x -> Text + [ T.pack $ printf "recursive type error lol" + ] + + where tshow = T.pack . show -- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may -- throw any number of fatal or nonfatal errors. Run with @runErrorful@. @@ -87,10 +100,10 @@ checkCoreProg p = scDefs where scname = sc ^. _lhs._1 -- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. --- checkCoreProgR :: Program' -> RLPC Program' -checkCoreProgR = undefined - -{-# WARNING checkCoreProgR "unimpl" #-} +checkCoreProgR :: Program' -> RLPC Program' +checkCoreProgR p = do + liftErrorful (checkCoreProg p) + pure p -- | Infer the type of an expression under some context. -- diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 1136409..f939258 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -169,17 +169,13 @@ lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s) -- | The main lexer driver. lexCore :: Text -> RLPC [Located CoreToken] lexCore s = case m of - Left e -> undefined + Left e -> error "core lex error" Right ts -> pure ts where m = runAlex s lexStream -{-# WARNING lexCore "unimpl" #-} - lexCoreR :: Text -> RLPC [Located CoreToken] -lexCoreR t = undefined - -{-# WARNING lexCoreR "unimpl" #-} +lexCoreR = lexCore -- | @lexCore@, but the tokens are stripped of location info. Useful for -- debugging @@ -200,9 +196,11 @@ data ParseError = ParErrLexical String -- TODO: instance IsRlpcError SrcError where + liftRlpcError = Text . pure . T.pack . show -- TODO: instance IsRlpcError ParseError where + liftRlpcError = Text . pure . T.pack . show alexEOF :: Alex (Located CoreToken) alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> diff --git a/src/Core/Parse.y b/src/Core/Parse.y index abc6c70..a084ebf 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -189,7 +189,9 @@ Con : '(' consym ')' { $2 } { parseError :: [Located CoreToken] -> RLPC a -parseError (Located y x l _ : _) = undefined +parseError (Located y x l t : _) = + error $ show y <> ":" <> show x + <> ": parse error at token `" <> show t <> "'" {-# WARNING parseError "unimpl" #-} @@ -217,9 +219,7 @@ singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty parseCoreProgR :: [Located CoreToken] -> RLPC Program' -parseCoreProgR a = undefined - -{-# WARNING parseCoreProgR "unimpl" #-} +parseCoreProgR = parseCoreProg happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b happyBind m k = m >>= k diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 28bb9c6..8031314 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -6,7 +6,6 @@ module Core.TH ( coreExpr , coreProg , coreProgT - , core ) where ---------------------------------------------------------------------------------- @@ -14,65 +13,38 @@ import Language.Haskell.TH import Language.Haskell.TH.Syntax hiding (Module) import Language.Haskell.TH.Quote import Control.Monad ((>=>)) +import Control.Monad.IO.Class +import Control.Arrow ((>>>)) import Compiler.RLPC import Data.Default.Class (def) +import Data.Text (Text) import Data.Text qualified as T import Core.Parse import Core.Lex -import Core.Syntax (Expr(Var)) +import Core.Syntax import Core.HindleyMilner (checkCoreProgR) ---------------------------------------------------------------------------------- --- TODO: write in terms of a String -> QuasiQuoter - -core :: QuasiQuoter -core = QuasiQuoter - { quoteExp = qCore - , quotePat = error "core quasiquotes may only be used in expressions" - , quoteType = error "core quasiquotes may only be used in expressions" - , quoteDec = error "core quasiquotes may only be used in expressions" - } - coreProg :: QuasiQuoter -coreProg = QuasiQuoter - { quoteExp = qCoreProg - , quotePat = error "core quasiquotes may only be used in expressions" - , quoteType = error "core quasiquotes may only be used in expressions" - , quoteDec = error "core quasiquotes may only be used in expressions" - } +coreProg = mkqq $ lexCoreR >=> parseCoreProgR coreExpr :: QuasiQuoter -coreExpr = QuasiQuoter - { quoteExp = qCoreExpr - , quotePat = error "core quasiquotes may only be used in expressions" - , quoteType = error "core quasiquotes may only be used in expressions" - , quoteDec = error "core quasiquotes may only be used in expressions" - } +coreExpr = mkqq $ lexCoreR >=> parseCoreExpr -- | Type-checked @coreProg@ coreProgT :: QuasiQuoter -coreProgT = QuasiQuoter - { quoteExp = qCoreProgT +coreProgT = mkqq $ lexCoreR >=> parseCoreProgR >=> checkCoreProgR + +mkqq :: (Lift a) => (Text -> RLPC a) -> QuasiQuoter +mkqq p = QuasiQuoter + { quoteExp = mkq p , quotePat = error "core quasiquotes may only be used in expressions" , quoteType = error "core quasiquotes may only be used in expressions" , quoteDec = error "core quasiquotes may only be used in expressions" } -qCore :: String -> Q Exp -qCore s = undefined - -{-# WARNING qCore "unimpl" #-} - -qCoreExpr :: String -> Q Exp -qCoreExpr s = undefined - -{-# WARNING qCoreExpr "unimpl" #-} - -qCoreProg :: String -> Q Exp -qCoreProg s = undefined - -{-# WARNING qCoreProg "unimpl" #-} - -qCoreProgT :: String -> Q Exp -qCoreProgT s = undefined +mkq :: (Lift a) => (Text -> RLPC a) -> String -> Q Exp +mkq parse s = case evalRLPC def (parse $ T.pack s) of + (Just a, _) -> lift a + (Nothing, _) -> error "todo: aaahhbbhjhbdjhabsjh" diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 8f498a9..7dbe178 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -38,9 +38,13 @@ spec = do let e = [coreExpr|3|] in check' [] (TyCon "Bool") e `shouldSatisfy` isLeft -infer' :: Context' -> Expr' -> Either TypeError Type -infer' g e = fmap fst . runErrorful $ infer g e +infer' :: Context' -> Expr' -> Either [TypeError] Type +infer' g e = case runErrorful $ infer g e of + (Just t, _) -> Right t + (Nothing, es) -> Left es -check' :: Context' -> Type -> Expr' -> Either TypeError () -check' g t e = fmap fst . runErrorful $ check g t e +check' :: Context' -> Type -> Expr' -> Either [TypeError] () +check' g t e = case runErrorful $ check g t e of + (Just t, _) -> Right () + (Nothing, es) -> Left es diff --git a/tst/Rlp/Parse/DeclsSpec.hs b/tst/Rlp/Parse/DeclsSpec.hs deleted file mode 100644 index e69de29..0000000 -- 2.52.0 From 5a659d22dd260b7b565073865fda4fbec2749c61 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 22 Jan 2024 09:55:58 -0700 Subject: [PATCH 094/192] errorful parser --- src/Control/Monad/Errorful.hs | 13 ++++++-- src/Rlp/Lex.x | 16 +++++----- src/Rlp/Parse.y | 2 +- src/Rlp/Parse/Types.hs | 60 +++++++++++++++++++++++++++++------ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index 5967b45..627dcf8 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -1,6 +1,7 @@ {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TupleSections, PatternSynonyms #-} +{-# LANGUAGE UndecidableInstances #-} module Control.Monad.Errorful ( ErrorfulT , runErrorfulT @@ -11,11 +12,12 @@ module Control.Monad.Errorful ) where ---------------------------------------------------------------------------------- +import Control.Monad.State.Strict import Control.Monad.Trans import Data.Functor.Identity import Data.Coerce -import Data.HashSet (HashSet) -import Data.HashSet qualified as H +import Data.HashSet (HashSet) +import Data.HashSet qualified as H import Lens.Micro ---------------------------------------------------------------------------------- @@ -68,3 +70,10 @@ mapErrorful f (ErrorfulT m) = ErrorfulT $ -- mapErrorful f = coerced . mapped . _2 . mappd %~ f -- lol +-------------------------------------------------------------------------------- +-- daily dose of n^2 instances + +instance (Monad m, MonadErrorful e m) => MonadErrorful e (StateT s m) where + addWound = undefined + addFatal = undefined + diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 6fd2428..ccbb65e 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -7,12 +7,14 @@ module Rlp.Lex , RlpToken(..) , Located(..) , lexToken + , lexStream , lexDebug , lexCont ) where import Codec.Binary.UTF8.String (encodeChar) import Control.Monad +import Control.Monad.Errorful import Core.Syntax (Name) import Data.Functor.Identity import Data.Char (digitToInt) @@ -203,13 +205,6 @@ alexEOF = do inp <- getInput pure (Located undefined TokenEOF) -execP :: P a -> ParseState -> Maybe a -execP p st = runP p st & snd - -execP' :: P a -> Text -> Maybe a -execP' p s = execP p st where - st = initParseState s - initParseState :: Text -> ParseState initParseState s = ParseState { _psLayoutStack = [] @@ -228,6 +223,10 @@ initAlexInput s = AlexInput , _aiPos = (1,1) } +runP' :: P a -> Text -> (ParseState, [RlpParseError], Maybe a) +runP' p s = runP p st where + st = initParseState s + lexToken :: P (Located RlpToken) lexToken = do inp <- getInput @@ -242,6 +241,7 @@ lexToken = do AlexToken inp' l act -> do psInput .= inp' act inp l + AlexError inp' -> addFatal RlpParErrLexical lexCont :: (Located RlpToken -> P a) -> P a lexCont = (lexToken >>=) @@ -260,7 +260,7 @@ lexDebug k = do k t lexTest :: Text -> Maybe [RlpToken] -lexTest s = execP' lexStream s +lexTest s = runP' lexStream s ^. _3 indentLevel :: P Int indentLevel = do diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index edc4874..3871a4f 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -161,7 +161,7 @@ mkProgram ds = do pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError = error . show +parseError (Located ((l,c),s) t) = addFatal RlpParErrUnknown mkInfixD :: Assoc -> Int -> Name -> P PartialDecl' mkInfixD a p n = do diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 718a9e5..d0f9be2 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -1,11 +1,42 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} {-# LANGUAGE LambdaCase #-} -module Rlp.Parse.Types where +module Rlp.Parse.Types + ( LexerAction + , AlexInput(..) + , Position(..) + , RlpToken(..) + , P(..) + , ParseState(..) + , psLayoutStack + , psLexState + , psInput + , psOpTable + , Layout(..) + , Located(..) + , OpTable + , OpInfo + , RlpParseError(..) + , PartialDecl' + , Partial(..) + , pL, pR + , PartialE + , pattern WithInfo + , opInfoOrDef + , PartialExpr' + , aiPrevChar + , aiSource + , aiBytes + , aiPos + , addFatal + , addWound + ) + where -------------------------------------------------------------------------------- import Core.Syntax (Name) import Control.Monad -import Control.Monad.State.Class +import Control.Monad.State.Strict +import Control.Monad.Errorful import Data.Text (Text) import Data.Maybe import Data.Fix @@ -71,24 +102,31 @@ data RlpToken | TokenEOF deriving (Show) -newtype P a = P { runP :: ParseState -> (ParseState, Maybe a) } +newtype P a = P { runP :: ParseState -> (ParseState, [RlpParseError], Maybe a) } deriving (Functor) instance Applicative P where - pure a = P $ \st -> (st,Just a) + pure a = P $ \st -> (st, [], pure a) liftA2 = liftM2 instance Monad P where p >>= k = P $ \st -> - let (st',a) = runP p st - in case a of - Just x -> runP (k x) st' - Nothing -> (st', Nothing) + let (st',es,ma) = runP p st + in case ma of + Just a -> runP (k a) st' + & _2 %~ (es<>) + Nothing -> (st',es,Nothing) + + {-# INLINE (>>=) #-} instance MonadState ParseState P where state f = P $ \st -> let (a,st') = f st - in (st', Just a) + in (st', [], Just a) + +instance MonadErrorful RlpParseError P where + addWound e = P $ \st -> (st, [e], Just ()) + addFatal e = P $ \st -> (st, [e], Nothing) data ParseState = ParseState { _psLayoutStack :: [Layout] @@ -112,6 +150,8 @@ type OpInfo = (Assoc, Int) data RlpParseError = RlpParErrOutOfBoundsPrecedence Int | RlpParErrDuplicateInfixD + | RlpParErrLexical + | RlpParErrUnknown deriving (Eq, Ord, Show) ---------------------------------------------------------------------------------- @@ -161,3 +201,5 @@ type PartialExpr' = Fix Partial makeLenses ''AlexInput makeLenses ''ParseState +-------------------------------------------------------------------------------- + -- 2.52.0 From c146e1c45091d975473d86889759b2a8fe9eace5 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 22 Jan 2024 09:59:48 -0700 Subject: [PATCH 095/192] errorful parser small --- src/Compiler/RlpcError.hs | 4 ++++ src/Rlp/Parse.y | 2 +- src/Rlp/Parse/Types.hs | 9 +++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index cff9375..168ad17 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -26,6 +26,7 @@ data MsgEnvelope e = MsgEnvelope , _msgDiagnostic :: e , _msgSeverity :: Severity } + deriving Functor newtype RlpcError = Text [Text] deriving Show @@ -55,3 +56,6 @@ liftRlpcErrors :: (Functor m, IsRlpcError e) -> ErrorfulT RlpcError m a liftRlpcErrors = mapErrorful liftRlpcError +instance (IsRlpcError e) => IsRlpcError (MsgEnvelope e) where + liftRlpcError msg = msg ^. msgDiagnostic & liftRlpcError + diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 3871a4f..e96db59 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -161,7 +161,7 @@ mkProgram ds = do pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError (Located ((l,c),s) t) = addFatal RlpParErrUnknown +parseError (Located ((l,c),s) t) = addFatal RlpParErrUnexpectedToken mkInfixD :: Assoc -> Int -> Name -> P PartialDecl' mkInfixD a p n = do diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index d0f9be2..498335f 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -37,6 +37,7 @@ import Core.Syntax (Name) import Control.Monad import Control.Monad.State.Strict import Control.Monad.Errorful +import Compiler.RlpcError import Data.Text (Text) import Data.Maybe import Data.Fix @@ -151,8 +152,10 @@ type OpInfo = (Assoc, Int) data RlpParseError = RlpParErrOutOfBoundsPrecedence Int | RlpParErrDuplicateInfixD | RlpParErrLexical - | RlpParErrUnknown - deriving (Eq, Ord, Show) + | RlpParErrUnexpectedToken + deriving (Eq, Ord, Show) + +instance IsRlpcError RlpParseError where ---------------------------------------------------------------------------------- @@ -201,5 +204,3 @@ type PartialExpr' = Fix Partial makeLenses ''AlexInput makeLenses ''ParseState --------------------------------------------------------------------------------- - -- 2.52.0 From 692d22afb9b93ba5411467def0788fdf4cf04e72 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 22 Jan 2024 10:26:33 -0700 Subject: [PATCH 096/192] msgenvelope --- src/Compiler/RLPC.hs | 12 ++++++------ src/Compiler/RlpcError.hs | 3 ++- src/Core/HindleyMilner.hs | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 0de0638..a4b3556 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -60,7 +60,7 @@ import System.Exit ---------------------------------------------------------------------------------- newtype RLPCT m a = RLPCT { - runRLPCT :: ReaderT RLPCOptions (ErrorfulT RlpcError m) a + runRLPCT :: ReaderT RLPCOptions (ErrorfulT (MsgEnvelope RlpcError) m) a } deriving (Functor, Applicative, Monad) @@ -70,7 +70,7 @@ type RLPCIO = RLPCT IO evalRLPC :: RLPCOptions -> RLPC a - -> (Maybe a, [RlpcError]) + -> (Maybe a, [MsgEnvelope RlpcError]) evalRLPC opt r = runRLPCT r & flip runReaderT opt & runErrorful @@ -78,7 +78,7 @@ evalRLPC opt r = runRLPCT r evalRLPCT :: (Monad m) => RLPCOptions -> RLPCT m a - -> m (Maybe a, [RlpcError]) + -> m (Maybe a, [MsgEnvelope RlpcError]) evalRLPCT = undefined evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a @@ -89,11 +89,11 @@ evalRLPCIO opt r = do Just x -> pure x Nothing -> die "Failed, no code compiled." -putRlpcErrs :: [RlpcError] -> IO () +putRlpcErrs :: [MsgEnvelope RlpcError] -> IO () putRlpcErrs = traverse_ print -liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT e m a -> RLPCT m a -liftErrorful e = RLPCT $ lift (liftRlpcErrors e) +liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a +liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e) data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 168ad17..2d748af 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -26,7 +26,7 @@ data MsgEnvelope e = MsgEnvelope , _msgDiagnostic :: e , _msgSeverity :: Severity } - deriving Functor + deriving (Functor, Show) newtype RlpcError = Text [Text] deriving Show @@ -48,6 +48,7 @@ data SrcSpan = SrcSpan !Int -- ^ Line !Int -- ^ Column !Int -- ^ Length + deriving Show makeLenses ''MsgEnvelope diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index ba9e987..4cffcca 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -101,9 +101,9 @@ checkCoreProg p = scDefs -- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. checkCoreProgR :: Program' -> RLPC Program' -checkCoreProgR p = do - liftErrorful (checkCoreProg p) - pure p +checkCoreProgR p = undefined + +{-# WARNING checkCoreProgR "unimpl" #-} -- | Infer the type of an expression under some context. -- -- 2.52.0 From e3b18c8915ca5a74177efac9ddfe8f59655593cf Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 22 Jan 2024 12:20:05 -0700 Subject: [PATCH 097/192] errors! --- src/Compiler/RLPC.hs | 1 + src/Compiler/RlpcError.hs | 10 ++++++++- src/Rlp/Lex.x | 8 +++++-- src/Rlp/Parse.y | 11 +++++++--- src/Rlp/Parse/Types.hs | 44 +++++++++++++++++++++++++++++++++++---- 5 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index a4b3556..2993c67 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -18,6 +18,7 @@ module Compiler.RLPC , RLPCOptions(RLPCOptions) , IsRlpcError(..) , RlpcError(..) + , MsgEnvelope(..) , addFatal , addWound , MonadErrorful diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 2d748af..ae3751d 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -3,13 +3,14 @@ module Compiler.RlpcError ( IsRlpcError(..) , MsgEnvelope(..) - , Severity + , Severity(..) , RlpcError(..) , SrcSpan(..) , msgSpan , msgDiagnostic , msgSeverity , liftRlpcErrors + , errorMsg ) where ---------------------------------------------------------------------------------- @@ -60,3 +61,10 @@ liftRlpcErrors = mapErrorful liftRlpcError instance (IsRlpcError e) => IsRlpcError (MsgEnvelope e) where liftRlpcError msg = msg ^. msgDiagnostic & liftRlpcError +errorMsg :: SrcSpan -> e -> MsgEnvelope e +errorMsg s e = MsgEnvelope + { _msgSpan = s + , _msgDiagnostic = e + , _msgSeverity = SevError + } + diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index ccbb65e..6942b84 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -54,6 +54,7 @@ $asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] @reservedname = case|data|do|import|in|let|letrec|module|of|where + |infixr|infixl|infix @reservedop = "=" | \\ | "->" | "|" @@ -125,6 +126,9 @@ lexReservedName = \case "of" -> TokenOf "let" -> TokenLet "in" -> TokenIn + "infix" -> TokenInfix + "infixl" -> TokenInfixL + "infixr" -> TokenInfixR lexReservedOp :: Text -> RlpToken lexReservedOp = \case @@ -223,7 +227,7 @@ initAlexInput s = AlexInput , _aiPos = (1,1) } -runP' :: P a -> Text -> (ParseState, [RlpParseError], Maybe a) +runP' :: P a -> Text -> (ParseState, [MsgEnvelope RlpParseError], Maybe a) runP' p s = runP p st where st = initParseState s @@ -241,7 +245,7 @@ lexToken = do AlexToken inp' l act -> do psInput .= inp' act inp l - AlexError inp' -> addFatal RlpParErrLexical + AlexError inp' -> addFatalHere 1 RlpParErrLexical lexCont :: (Located RlpToken -> P a) -> P a lexCont = (lexToken >>=) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index e96db59..444a6d4 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -4,6 +4,7 @@ module Rlp.Parse ( parseRlpProg ) where +import Compiler.RlpcError import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types @@ -14,6 +15,7 @@ import Lens.Micro.Platform () import Data.List.Extra import Data.Fix import Data.Functor.Const +import Data.Text qualified as T } %name parseRlpProg StandaloneProgram @@ -161,16 +163,19 @@ mkProgram ds = do pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError (Located ((l,c),s) t) = addFatal RlpParErrUnexpectedToken +parseError (Located ((l,c),s) t) = addFatal $ + errorMsg (SrcSpan l c s) RlpParErrUnexpectedToken mkInfixD :: Assoc -> Int -> Name -> P PartialDecl' mkInfixD a p n = do let opl :: Lens' ParseState (Maybe OpInfo) opl = psOpTable . at n opl <~ (use opl >>= \case - -- TODO: non-fatal error - Just o -> pure (Just o) + Just o -> addWoundHere l e >> pure (Just o) where + e = RlpParErrDuplicateInfixD n + l = T.length n Nothing -> pure (Just (a,p)) ) pure $ InfixD a p n + } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 498335f..bddf0d9 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -3,6 +3,8 @@ {-# LANGUAGE LambdaCase #-} module Rlp.Parse.Types ( LexerAction + , MsgEnvelope(..) + , RlpcError(..) , AlexInput(..) , Position(..) , RlpToken(..) @@ -30,6 +32,8 @@ module Rlp.Parse.Types , aiPos , addFatal , addWound + , addFatalHere + , addWoundHere ) where -------------------------------------------------------------------------------- @@ -66,6 +70,12 @@ type Position = , Int -- column ) +posLine :: Lens' Position Int +posLine = _1 + +posColumn :: Lens' Position Int +posColumn = _2 + data RlpToken -- literals = TokenLitInt Int @@ -103,7 +113,10 @@ data RlpToken | TokenEOF deriving (Show) -newtype P a = P { runP :: ParseState -> (ParseState, [RlpParseError], Maybe a) } +newtype P a = P { + runP :: ParseState + -> (ParseState, [MsgEnvelope RlpParseError], Maybe a) + } deriving (Functor) instance Applicative P where @@ -125,7 +138,7 @@ instance MonadState ParseState P where let (a,st') = f st in (st', [], Just a) -instance MonadErrorful RlpParseError P where +instance MonadErrorful (MsgEnvelope RlpParseError) P where addWound e = P $ \st -> (st, [e], Just ()) addFatal e = P $ \st -> (st, [e], Nothing) @@ -150,7 +163,7 @@ type OpInfo = (Assoc, Int) -- data WithLocation a = WithLocation [String] a data RlpParseError = RlpParErrOutOfBoundsPrecedence Int - | RlpParErrDuplicateInfixD + | RlpParErrDuplicateInfixD Name | RlpParErrLexical | RlpParErrUnexpectedToken deriving (Eq, Ord, Show) @@ -158,7 +171,6 @@ data RlpParseError = RlpParErrOutOfBoundsPrecedence Int instance IsRlpcError RlpParseError where ---------------------------------------------------------------------------------- - -- absolute psycho shit (partial ASTs) type PartialDecl' = Decl (Const PartialExpr') Name @@ -204,3 +216,27 @@ type PartialExpr' = Fix Partial makeLenses ''AlexInput makeLenses ''ParseState +addWoundHere :: Int -> RlpParseError -> P () +addWoundHere l e = P $ \st -> + let e' = MsgEnvelope + { _msgSpan = let pos = psInput . aiPos + in SrcSpan (st ^. pos . posLine) + (st ^. pos . posColumn) + l + , _msgDiagnostic = e + , _msgSeverity = SevError + } + in (st, [e'], Just ()) + +addFatalHere :: Int -> RlpParseError -> P a +addFatalHere l e = P $ \st -> + let e' = MsgEnvelope + { _msgSpan = let pos = psInput . aiPos + in SrcSpan (st ^. pos . posLine) + (st ^. pos . posColumn) + l + , _msgDiagnostic = e + , _msgSeverity = SevError + } + in (st, [e'], Nothing) + -- 2.52.0 From cefdf6ffae57fc7630ef5be3ec1df778a383a7f2 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 22 Jan 2024 12:45:42 -0700 Subject: [PATCH 098/192] allow uppercase sc names in preperation for Rlp2Core --- Makefile_happysrcs | 10 ++++++++-- src/Compiler/JustRun.hs | 13 +++++++------ src/Core/Parse.y | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index e0dc43e..1d32855 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -8,8 +8,8 @@ CABAL_BUILD = dist-newstyle/build/x86_64-osx/ghc-9.6.2/rlp-0.1.0.0/build all: parsers lexers -parsers: $(CABAL_BUILD)/Rlp/Parse.hs -lexers: $(CABAL_BUILD)/Rlp/Lex.hs +parsers: $(CABAL_BUILD)/Rlp/Parse.hs $(CABAL_BUILD)/Core/Parse.hs +lexers: $(CABAL_BUILD)/Rlp/Lex.hs $(CABAL_BUILD)/Core/Lex.hs $(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y $(HAPPY) $(HAPPY_OPTS) $< -o $@ @@ -17,3 +17,9 @@ $(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y $(CABAL_BUILD)/Rlp/Lex.hs: $(SRC)/Rlp/Lex.x $(ALEX) $(ALEX_OPTS) $< -o $@ +$(CABAL_BUILD)/Core/Parse.hs: $(SRC)/Core/Parse.y + $(HAPPY) $(HAPPY_OPTS) $< -o $@ + +$(CABAL_BUILD)/Core/Lex.hs: $(SRC)/Core/Lex.x + $(ALEX) $(ALEX_OPTS) $< -o $@ + diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs index c3178f3..6a0d4ca 100644 --- a/src/Compiler/JustRun.hs +++ b/src/Compiler/JustRun.hs @@ -26,22 +26,23 @@ import Data.Function ((&)) import GM ---------------------------------------------------------------------------------- --- justLexSrc :: String -> Either RlpcError [CoreToken] +justLexSrc :: String -> Either [MsgEnvelope RlpcError] [CoreToken] justLexSrc s = lexCoreR (T.pack s) & fmap (map $ \ (Located _ _ _ t) -> t) & rlpcToEither --- justParseSrc :: String -> Either RlpcError Program' +justParseSrc :: String -> Either [MsgEnvelope RlpcError] Program' justParseSrc s = parse (T.pack s) & rlpcToEither where parse = lexCoreR >=> parseCoreProgR --- justTypeCheckSrc :: String -> Either RlpcError Program' +justTypeCheckSrc :: String -> Either [MsgEnvelope RlpcError] Program' justTypeCheckSrc s = typechk (T.pack s) & rlpcToEither where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR -rlpcToEither = undefined - -{-# WARNING rlpcToEither "unimpl" #-} +rlpcToEither :: RLPC a -> Either [MsgEnvelope RlpcError] a +rlpcToEither r = case evalRLPC def r of + (Just a, _) -> Right a + (Nothing, es) -> Left es diff --git a/src/Core/Parse.y b/src/Core/Parse.y index a084ebf..b8a0cf3 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -98,6 +98,8 @@ ScDefs : ScDef ';' ScDefs { $1 : $3 } ScDef :: { ScDef Name } ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 } + -- hack to allow constructors to be compiled into scs + | Con ParList '=' Expr { ScDef $1 $2 $4 } Type :: { Type } Type : Type1 { $1 } -- 2.52.0 From 22b5b477956ec884dc3295bc67c580d2f1e4cfed Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 23 Jan 2024 20:19:16 -0700 Subject: [PATCH 099/192] letrec --- src/Core/HindleyMilner.hs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 4cffcca..6d9bfe9 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -3,6 +3,7 @@ Module : Core.HindleyMilner Description : Hindley-Milner type system -} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} module Core.HindleyMilner ( Context' , infer @@ -16,12 +17,13 @@ module Core.HindleyMilner ---------------------------------------------------------------------------------- import Lens.Micro import Lens.Micro.Mtl +import Lens.Micro.Platform import Data.Maybe (fromMaybe) import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Foldable (traverse_) import Compiler.RLPC -import Control.Monad (foldM, void) +import Control.Monad (foldM, void, forM) import Control.Monad.Errorful (Errorful, addFatal) import Control.Monad.State import Control.Monad.Utils (mapAccumLM) @@ -152,8 +154,28 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where Let NonRec bs e -> do g' <- buildLetContext g bs go g' e + Let Rec bs e -> do + g' <- buildLetrecContext g bs + go g' e + -- TODO letrec, lambda, case + buildLetrecContext :: Context' -> [Binding'] + -> StateT ([Constraint], Int) HMError Context' + buildLetrecContext g bs = do + let f ag (k := _) = do + n <- uniqueVar + pure ((k,n) : ag) + rg <- foldM f g bs + let k ag (k := v) = do + t <- go rg v + pure ((k,t) : ag) + foldM k g bs + + -- | augment a context with the inferred types of each binder. the returned + -- context is linearly accumulated, meaning that the context used to infer each binder + -- will include the inferred types of all previous binder + buildLetContext :: Context' -> [Binding'] -> StateT ([Constraint], Int) HMError Context' buildLetContext = foldM k where @@ -230,3 +252,17 @@ subst x t (TyVar y) | x == y = t subst x t (a :-> b) = subst x t a :-> subst x t b subst _ _ e = e +-------------------------------------------------------------------------------- + +demoContext :: Context' +demoContext = + [ ("fix", (TyVar "a" :-> TyVar "a") :-> TyVar "a") + , ("add", TyInt :-> TyInt :-> TyInt) + ] + +pprintType :: Type -> String +pprintType (s :-> t) = "(" <> pprintType s <> " -> " <> pprintType t <> ")" +pprintType TyFun = "(->)" +pprintType (TyVar x) = x ^. unpacked +pprintType (TyCon t) = t ^. unpacked + -- 2.52.0 From 3d45e12676f09c58912ca0389326501b97f13e43 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 23 Jan 2024 21:08:17 -0700 Subject: [PATCH 100/192] infer letrec expressions --- src/Core/HindleyMilner.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 6d9bfe9..3699310 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -158,7 +158,7 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where g' <- buildLetrecContext g bs go g' e - -- TODO letrec, lambda, case + -- TODO lambda, case buildLetrecContext :: Context' -> [Binding'] -> StateT ([Constraint], Int) HMError Context' @@ -258,6 +258,9 @@ demoContext :: Context' demoContext = [ ("fix", (TyVar "a" :-> TyVar "a") :-> TyVar "a") , ("add", TyInt :-> TyInt :-> TyInt) + , ("==", TyInt :-> TyInt :-> TyCon "Bool") + , ("True", TyCon "Bool") + , ("False", TyCon "Bool") ] pprintType :: Type -> String -- 2.52.0 From c8199a9dd16c16a382fe97301f3b027ac7383ace Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 09:31:57 -0700 Subject: [PATCH 101/192] minor docs --- doc/src/commentary/gm.rst | 2 - doc/src/commentary/layout-lexing.rst | 73 ++++++++++------------ doc/src/commentary/type-inference.rst | 5 ++ doc/src/references/rlp-inference-rules.rst | 13 ++++ 4 files changed, 50 insertions(+), 43 deletions(-) create mode 100644 doc/src/commentary/type-inference.rst create mode 100644 doc/src/references/rlp-inference-rules.rst diff --git a/doc/src/commentary/gm.rst b/doc/src/commentary/gm.rst index 4cf3d6a..d1ae166 100644 --- a/doc/src/commentary/gm.rst +++ b/doc/src/commentary/gm.rst @@ -112,5 +112,3 @@ The way around this is quite simple: simply offset the stack when w :end-before: -- << [ref/compileC] :caption: src/GM.hs - - diff --git a/doc/src/commentary/layout-lexing.rst b/doc/src/commentary/layout-lexing.rst index 4fbfd5e..2039b35 100644 --- a/doc/src/commentary/layout-lexing.rst +++ b/doc/src/commentary/layout-lexing.rst @@ -2,16 +2,21 @@ Lexing, Parsing, and Layouts ============================ The C-style languages of my previous experiences have all had quite trivial -lexical analysis stages, peaking in complexity when I streamed tokens lazily in -C. The task of tokenising a C-style language is very simple in description: you -ignore all whitespace and point out what you recognise. If you don't recognise -something, check if it's a literal or an identifier. Should it be neither, -return an error. +lexical analysis stages: you ignore all whitespace and point out the symbols you +recognise. If you don't recognise something, check if it's a literal or an +identifier. Should it be neither, return an error. -On paper, both lexing and parsing a Haskell-like language seem to pose a few +In contrast, both lexing and parsing a Haskell-like language poses a number of greater challenges. Listed by ascending intimidation factor, some of the potential roadblocks on my mind before making an attempt were: +* Context-sensitive keywords; Haskell allows for some words to be used as + identifiers in appropriate contexts, such as :code:`family`, :code:`role`, + :code:`as`. Reading a note_ found in `GHC's lexer`_, it appears that keywords + are only considered in bodies for which their use is relevant, e.g. + :code:`family` and :code:`role` in type declarations, :code:`as` after + :code:`case`; :code:`if`, :code:`then`, and :code:`else` in expressions, etc. + * Operators; Haskell has not only user-defined infix operators, but user-defined precedence levels and associativities. I recall using an algorithm that looked up infix, prefix, postfix, and even mixfix operators up in a global table to @@ -19,17 +24,9 @@ potential roadblocks on my mind before making an attempt were: stored in the table). I never modified the table at runtime, however this could be a very nice solution for Haskell. -* Context-sensitive keywords; Haskell allows for some words to be used as identifiers in - appropriate contexts, such as :code:`family`, :code:`role`, :code:`as`. - Reading a note_ found in `GHC's lexer`_, - it appears that keywords are only considered in bodies for which their use is - relevant, e.g. :code:`family` and :code:`role` in type declarations, - :code:`as` after :code:`case`; :code:`if`, :code:`then`, and :code:`else` in - expressions, etc. - * Whitespace sensitivity; While I was comfortable with the idea of a system - similar to Python's INDENT/DEDENT tokens, Haskell seemed to use whitespace to - section code in a way that *felt* different. + similar to Python's INDENT/DEDENT tokens, Haskell's layout system is based on + alignment and is very generous with line-folding. .. _note: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/coding-style#2-using-notes .. _GHC's lexer: https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Parser/Lexer.x#L1133 @@ -45,9 +42,9 @@ We will compare and contrast with Python's lexical analysis. Much to my dismay, Python uses newlines and indentation to separate statements and resolve scope instead of the traditional semicolons and braces found in C-style languages (we may generally refer to these C-style languages as *explicitly-sectioned*). -Internally during tokenisation, when the Python lexer begins a new line, they -compare the indentation of the new line with that of the previous and apply the -following rules: +Internally during tokenisation, when the Python lexer encounters a new line, the +indentation of the new line is compared with that of the previous and the +following rules are applied: 1. If the new line has greater indentation than the previous, insert an INDENT token and push the new line's indentation level onto the indentation stack @@ -60,44 +57,37 @@ following rules: 3. If the indentation is equal, insert a NEWLINE token to terminate the previous line, and leave it at that! -Parsing Python with the INDENT, DEDENT, and NEWLINE tokens is identical to -parsing a language with braces and semicolons. This is a solution pretty in line -with Python's philosophy of the "one correct answer" (TODO: this needs a -source). In developing our *layout* rules, we will follow in the pattern of -translating the whitespace-sensitive source language to an explicitly sectioned -language. +On the parser's end, the INDENT, DEDENT, and NEWLINE tokens are identical to +braces and semicolons. In developing our *layout* rules, we will follow in the +pattern of translating the whitespace-sensitive source language to an explicitly +sectioned language. But What About Haskell? *********************** -We saw that Python, the most notable example of an implicitly sectioned -language, is pretty simple to lex. Why then am I so afraid of Haskell's layouts? -To be frank, I'm far less scared after asking myself this -- however there are -certainly some new complexities that Python needn't concern. Haskell has -implicit line *continuation*: forms written over multiple lines; indentation -styles often seen in Haskell are somewhat esoteric compared to Python's -"s/[{};]//". +Parsing Haskell -- and thus rl' -- is only slightly more complex than Python, +but the design is certainly more sensitive. .. code-block:: haskell - -- line continuation + -- line folds something = this is a single expression -- an extremely common style found in haskell - data Python = Users - { are :: Crying - , right :: About - , now :: Sorry + data Some = Data + { is :: Presented + , in :: This + , silly :: Style } - -- another formatting oddity + -- another style oddity -- note that this is not a single -- continued line! `look at`, - -- `this`, and `alignment` are all - -- separate expressions! + -- `this odd`, and `alignment` are all + -- discrete items! anotherThing = do look at - this + this odd alignment But enough fear, lets actually think about implementation. Firstly, some @@ -233,3 +223,4 @@ References * `Haskell syntax reference `_ + diff --git a/doc/src/commentary/type-inference.rst b/doc/src/commentary/type-inference.rst new file mode 100644 index 0000000..fa369bb --- /dev/null +++ b/doc/src/commentary/type-inference.rst @@ -0,0 +1,5 @@ +Type Inference in rl' +===================== + +rl' implements type inference via the Hindley-Milner type system. + diff --git a/doc/src/references/rlp-inference-rules.rst b/doc/src/references/rlp-inference-rules.rst new file mode 100644 index 0000000..e9f7266 --- /dev/null +++ b/doc/src/references/rlp-inference-rules.rst @@ -0,0 +1,13 @@ +rl' Inference Rules +=================== + +.. rubric:: + [Var] + +.. math:: + \frac{x : \tau \in \Gamma} + {\Gamma \vdash x : \tau} + +.. rubric:: + [App] + -- 2.52.0 From fbef645746d68a654873ca129abf3575cf11aeec Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 09:39:06 -0700 Subject: [PATCH 102/192] checklist --- programming-language-checklist | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 programming-language-checklist diff --git a/programming-language-checklist b/programming-language-checklist new file mode 100644 index 0000000..cbc72ff --- /dev/null +++ b/programming-language-checklist @@ -0,0 +1,105 @@ +Programming Language Checklist +by Colin McMillen, Jason Reed, and Elly Fong-Jones, 2011-10-10. + +You appear to be advocating a new: +[x] functional [ ] imperative [ ] object-oriented [ ] procedural [ ] stack-based +[ ] "multi-paradigm" [x] lazy [ ] eager [x] statically-typed [ ] dynamically-typed +[x] pure [ ] impure [ ] non-hygienic [ ] visual [x] beginner-friendly +[ ] non-programmer-friendly [ ] completely incomprehensible +programming language. Your language will not work. Here is why it will not work. + +You appear to believe that: +[ ] Syntax is what makes programming difficult +[x] Garbage collection is free [x] Computers have infinite memory +[x] Nobody really needs: + [x] concurrency [x] a REPL [x] debugger support [x] IDE support [x] I/O + [x] to interact with code not written in your language +[ ] The entire world speaks 7-bit ASCII +[ ] Scaling up to large software projects will be easy +[ ] Convincing programmers to adopt a new language will be easy +[ ] Convincing programmers to adopt a language-specific IDE will be easy +[ ] Programmers love writing lots of boilerplate +[ ] Specifying behaviors as "undefined" means that programmers won't rely on them +[ ] "Spooky action at a distance" makes programming more fun + +Unfortunately, your language (has/lacks): +[x] comprehensible syntax [ ] semicolons [x] significant whitespace [ ] macros +[ ] implicit type conversion [ ] explicit casting [x] type inference +[ ] goto [ ] exceptions [x] closures [x] tail recursion [ ] coroutines +[ ] reflection [ ] subtyping [ ] multiple inheritance [x] operator overloading +[x] algebraic datatypes [x] recursive types [x] polymorphic types +[ ] covariant array typing [x] monads [ ] dependent types +[x] infix operators [x] nested comments [ ] multi-line strings [ ] regexes +[ ] call-by-value [x] call-by-name [ ] call-by-reference [ ] call-cc + +The following philosophical objections apply: +[ ] Programmers should not need to understand category theory to write "Hello, World!" +[ ] Programmers should not develop RSI from writing "Hello, World!" +[ ] The most significant program written in your language is its own compiler +[x] The most significant program written in your language isn't even its own compiler +[x] No language spec +[x] "The implementation is the spec" + [ ] The implementation is closed-source [ ] covered by patents [ ] not owned by you +[ ] Your type system is unsound [ ] Your language cannot be unambiguously parsed + [ ] a proof of same is attached + [ ] invoking this proof crashes the compiler +[x] The name of your language makes it impossible to find on Google +[x] Interpreted languages will never be as fast as C +[ ] Compiled languages will never be "extensible" +[ ] Writing a compiler that understands English is AI-complete +[ ] Your language relies on an optimization which has never been shown possible +[ ] There are less than 100 programmers on Earth smart enough to use your language +[ ] ____________________________ takes exponential time +[ ] ____________________________ is known to be undecidable + +Your implementation has the following flaws: +[ ] CPUs do not work that way +[ ] RAM does not work that way +[ ] VMs do not work that way +[ ] Compilers do not work that way +[ ] Compilers cannot work that way +[ ] Shift-reduce conflicts in parsing seem to be resolved using rand() +[ ] You require the compiler to be present at runtime +[ ] You require the language runtime to be present at compile-time +[ ] Your compiler errors are completely inscrutable +[ ] Dangerous behavior is only a warning +[ ] The compiler crashes if you look at it funny +[x] The VM crashes if you look at it funny +[x] You don't seem to understand basic optimization techniques +[x] You don't seem to understand basic systems programming +[ ] You don't seem to understand pointers +[ ] You don't seem to understand functions + +Additionally, your marketing has the following problems: +[x] Unsupported claims of increased productivity +[x] Unsupported claims of greater "ease of use" +[ ] Obviously rigged benchmarks + [ ] Graphics, simulation, or crypto benchmarks where your code just calls + handwritten assembly through your FFI + [ ] String-processing benchmarks where you just call PCRE + [ ] Matrix-math benchmarks where you just call BLAS +[x] Noone really believes that your language is faster than: + [x] assembly [x] C [x] FORTRAN [x] Java [x] Ruby [ ] Prolog +[ ] Rejection of orthodox programming-language theory without justification +[x] Rejection of orthodox systems programming without justification +[ ] Rejection of orthodox algorithmic theory without justification +[ ] Rejection of basic computer science without justification + +Taking the wider ecosystem into account, I would like to note that: +[x] Your complex sample code would be one line in: examples/ +[ ] We already have an unsafe imperative language +[ ] We already have a safe imperative OO language +[x] We already have a safe statically-typed eager functional language +[ ] You have reinvented Lisp but worse +[ ] You have reinvented Javascript but worse +[ ] You have reinvented Java but worse +[ ] You have reinvented C++ but worse +[ ] You have reinvented PHP but worse +[ ] You have reinvented PHP better, but that's still no justification +[ ] You have reinvented Brainfuck but non-ironically + +In conclusion, this is what I think of you: +[ ] You have some interesting ideas, but this won't fly. +[x] This is a bad language, and you should feel bad for inventing it. +[ ] Programming in this language is an adequate punishment for inventing it. + -- 2.52.0 From 7c474cc0641a3865fc955f8d94c4803dd7bd7f53 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 09:49:27 -0700 Subject: [PATCH 103/192] minor docs --- doc/src/references/rlp-inference-rules.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/src/references/rlp-inference-rules.rst b/doc/src/references/rlp-inference-rules.rst index e9f7266..9520d0f 100644 --- a/doc/src/references/rlp-inference-rules.rst +++ b/doc/src/references/rlp-inference-rules.rst @@ -11,3 +11,7 @@ rl' Inference Rules .. rubric:: [App] +.. math:: + \frac{\Gamma \vdash f : \alpha \to \beta \qquad \Gamma \vdash x : \alpha} + {\Gamma \vdash f x : \beta} + -- 2.52.0 From 0025d3306949e145d302ee1d5503019274f11ec9 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 10:14:44 -0700 Subject: [PATCH 104/192] stable enough for a demo hey? --- tst/Core/HindleyMilnerSpec.hs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tst/Core/HindleyMilnerSpec.hs b/tst/Core/HindleyMilnerSpec.hs index 7dbe178..97e4732 100644 --- a/tst/Core/HindleyMilnerSpec.hs +++ b/tst/Core/HindleyMilnerSpec.hs @@ -38,6 +38,18 @@ spec = do let e = [coreExpr|3|] in check' [] (TyCon "Bool") e `shouldSatisfy` isLeft + it "should infer `fix ((+#) 1)` :: Int" $ + let g = [ ("fix", ("a" :-> "a") :-> "a") + , ("+#", TyInt :-> TyInt :-> TyInt) ] + e = [coreExpr|fix ((+#) 1)|] + in infer' g e `shouldBe` Right TyInt + + it "should infer mutually recursively defined lists" $ + let g = [ ("cons", TyInt :-> TyCon "IntList" :-> TyCon "IntList") ] + e :: Expr' + e = [coreExpr|letrec { as = cons 1 bs; bs = cons 2 as } in as|] + in infer' g e `shouldBe` Right (TyCon "IntList") + infer' :: Context' -> Expr' -> Either [TypeError] Type infer' g e = case runErrorful $ infer g e of (Just t, _) -> Right t -- 2.52.0 From d52a366c1bfd6565a2957fbdc4c4b5dde5861123 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 11:03:51 -0700 Subject: [PATCH 105/192] small fixups --- src/Core/HindleyMilner.hs | 12 ++++++++++-- src/Core/Syntax.hs | 15 ++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 3699310..cf0dace 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -55,11 +55,14 @@ instance IsRlpcError TypeError where liftRlpcError = \case -- todo: use anti-parser instead of show TyErrCouldNotUnify t u -> Text - [ T.pack $ printf "Could not match type `%s' with `%s'." + [ T.pack $ printf "Could not match type `%s` with `%s`." (show t) (show u) , "Expected: " <> tshow t , "Got: " <> tshow u ] + TyErrUntypedVariable n -> Text + [ "Untyped (likely undefined) variable `" <> n <> "`" + ] TyErrRecursiveType t x -> Text [ T.pack $ printf "recursive type error lol" ] @@ -157,7 +160,12 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where Let Rec bs e -> do g' <- buildLetrecContext g bs go g' e - + Lam bs e -> case bs of + [x] -> do + tx <- uniqueVar + let g' = (x,tx) : g + te <- go g' e + pure (tx :-> te) -- TODO lambda, case buildLetrecContext :: Context' -> [Binding'] diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index fb9b720..f4785c6 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -5,6 +5,7 @@ Description : Core ASTs and the like {-# LANGUAGE PatternSynonyms, OverloadedStrings #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE DerivingStrategies, DerivingVia #-} module Core.Syntax ( Expr(..) , Type(..) @@ -45,6 +46,7 @@ import Data.HashMap.Strict qualified as H import Data.Hashable import Data.Text qualified as T import Data.Char +import GHC.Generics -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) import Lens.Micro.TH (makeLenses) @@ -127,7 +129,9 @@ data Program b = Program { _programScDefs :: [ScDef b] , _programTypeSigs :: H.HashMap b Type } - deriving (Show, Lift) + deriving (Show, Lift, Generic) + deriving (Semigroup, Monoid) + via Generically (Program b) makeLenses ''Program pure [] @@ -148,11 +152,12 @@ instance IsString Type where | otherwise = TyVar . fromString $ s where (c:_) = s -instance (Hashable b) => Semigroup (Program b) where - (<>) = undefined +-- instance (Hashable b) => Semigroup (Program b) where +-- p <> q = Program +-- { _programScDefs = _programScDefs p <> _programScDefs q } -instance (Hashable b) => Monoid (Program b) where - mempty = Program mempty mempty +-- instance (Hashable b) => Monoid (Program b) where +-- mempty = Program mempty mempty ---------------------------------------------------------------------------------- -- 2.52.0 From 170e4e36aee7344324f3fc8bbb27b857cab41a8d Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 24 Jan 2024 11:30:34 -0700 Subject: [PATCH 106/192] new tag syntax; preparing for Core patterns new tag syntax; preparing for data names --- CHANGELOG.md | 17 +++++++++++++++++ examples/factorial.hs | 4 ++-- examples/sumList.hs | 4 ++-- src/Core/Examples.hs | 14 +++++++------- src/Core/Lex.x | 5 +++++ src/Core/Parse.y | 3 ++- src/Core/Syntax.hs | 15 ++++++--------- src/GM.hs | 2 +- 8 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9921c0c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# unreleased + +* New tag syntax: + ```hs + case x of + { 1 -> something + ; 2 -> another + } + ``` + is now written as + ```hs + case x of + { <1> -> something + ; <2> -> another + } + ``` + diff --git a/examples/factorial.hs b/examples/factorial.hs index cc235ab..1080c7b 100644 --- a/examples/factorial.hs +++ b/examples/factorial.hs @@ -1,6 +1,6 @@ fac n = case (==#) n 0 of - { 1 -> 1 - ; 0 -> (*#) n (fac ((-#) n 1)) + { <1> -> 1 + ; <0> -> (*#) n (fac ((-#) n 1)) }; main = fac 3; diff --git a/examples/sumList.hs b/examples/sumList.hs index fd46a60..5193a67 100644 --- a/examples/sumList.hs +++ b/examples/sumList.hs @@ -2,8 +2,8 @@ nil = Pack{0 0}; cons x y = Pack{1 2} x y; list = cons 1 (cons 2 (cons 3 nil)); sum l = case l of - { 0 -> 0 - ; 1 x xs -> (+#) x (sum xs) + { <0> -> 0 + ; <1> x xs -> (+#) x (sum xs) }; main = sum list; diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index 2ca54e3..0b741e9 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -147,8 +147,8 @@ simple1 = [coreProg| caseBool1 :: Program' caseBool1 = [coreProg| _if c x y = case c of - { 1 -> x - ; 0 -> y + { <1> -> x + ; <0> -> y }; false = Pack{0 0}; @@ -160,8 +160,8 @@ caseBool1 = [coreProg| fac3 :: Program' fac3 = [coreProg| fac n = case (==#) n 0 of - { 1 -> 1 - ; 0 -> (*#) n (fac ((-#) n 1)) + { <1> -> 1 + ; <0> -> (*#) n (fac ((-#) n 1)) }; main = fac 3; @@ -175,8 +175,8 @@ sumList = [coreProg| cons x y = Pack{1 2} x y; list = cons 1 (cons 2 (cons 3 nil)); sum l = case l of - { 0 -> 0 - ; 1 x xs -> (+#) x (sum xs) + { <0> -> 0 + ; <1> x xs -> (+#) x (sum xs) }; main = sum list; |] @@ -192,7 +192,7 @@ idCase = [coreProg| id x = x; main = id (case Pack{1 0} of - { 1 -> (+#) 2 3 + { <1> -> (+#) 2 3 }) |] diff --git a/src/Core/Lex.x b/src/Core/Lex.x index f939258..ba62996 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -65,6 +65,8 @@ $white_no_nl = $white # $nl @decimal = $digit+ +@alttag = "<" $digit+ ">" + rlp :- <0> @@ -92,6 +94,8 @@ rlp :- "=" { constTok TokenEquals } "->" { constTok TokenArrow } + @alttag { lexWith ( TokenAltTag . read @Int . T.unpack + . T.drop 1 . T.init ) } @varname { lexWith TokenVarName } @conname { lexWith TokenConName } @varsym { lexWith TokenVarSym } @@ -135,6 +139,7 @@ data CoreToken = TokenLet | TokenConName Name | TokenVarSym Name | TokenConSym Name + | TokenAltTag Tag | TokenEquals | TokenLParen | TokenRParen diff --git a/src/Core/Parse.y b/src/Core/Parse.y index b8a0cf3..6d2e5ef 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -49,6 +49,7 @@ import Data.HashMap.Strict qualified as H varsym { Located _ _ _ (TokenVarSym $$) } conname { Located _ _ _ (TokenConName $$) } consym { Located _ _ _ (TokenConSym $$) } + alttag { Located _ _ _ (TokenAltTag $$) } word { Located _ _ _ (TokenWord $$) } 'λ' { Located _ _ _ TokenLambda } '->' { Located _ _ _ TokenArrow } @@ -149,7 +150,7 @@ Alters : Alter ';' Alters { $1 : $3 } | Alter { [$1] } Alter :: { Alter Name } -Alter : litint ParList '->' Expr { Alter (AltData $1) $2 $4 } +Alter : alttag ParList '->' Expr { Alter (AltTag $1) $2 $4 } Expr1 :: { Expr Name } Expr1 : litint { Lit $ IntL $1 } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index f4785c6..f48d2da 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -42,6 +42,7 @@ import Data.Pretty import Data.List (intersperse) import Data.Function ((&)) import Data.String +import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict qualified as H import Data.Hashable import Data.Text qualified as T @@ -105,7 +106,8 @@ data Rec = Rec | NonRec deriving (Show, Read, Eq, Lift) -data AltCon = AltData Tag +data AltCon = AltData Name + | AltTag Tag | AltLit Lit | Default deriving (Show, Read, Eq, Lift) @@ -127,7 +129,9 @@ data Module b = Module (Maybe (Name, [Name])) (Program b) data Program b = Program { _programScDefs :: [ScDef b] - , _programTypeSigs :: H.HashMap b Type + , _programTypeSigs :: HashMap b Type + -- map constructors to their tag and arity + , _programDataTags :: HashMap b (Tag, Int) } deriving (Show, Lift, Generic) deriving (Semigroup, Monoid) @@ -152,13 +156,6 @@ instance IsString Type where | otherwise = TyVar . fromString $ s where (c:_) = s --- instance (Hashable b) => Semigroup (Program b) where --- p <> q = Program --- { _programScDefs = _programScDefs p <> _programScDefs q } - --- instance (Hashable b) => Monoid (Program b) where --- mempty = Program mempty mempty - ---------------------------------------------------------------------------------- class HasRHS s t a b | s -> a, t -> b, s b -> t, t a -> s where diff --git a/src/GM.hs b/src/GM.hs index 8b91393..46bf3a9 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -724,7 +724,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileD g as = fmap (compileA g) as compileA :: Env -> Alter' -> (Tag, Code) - compileA g (Alter (AltData t) as e) = (t, [Split n] <> c <> [Slide n]) + compileA g (Alter (AltTag t) as e) = (t, [Split n] <> c <> [Slide n]) where n = length as binds = (NameKey <$> as) `zip` [0..] -- 2.52.0 From 4c99e44c04bcb2142387f1f8e12882b2b6a5d50c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 25 Jan 2024 11:15:09 -0700 Subject: [PATCH 107/192] temporary pragma system --- src/Core/Parse.y | 36 ++++++++++++++++++++++++++---------- src/Core/Syntax.hs | 4 ++++ src/Core2Core.hs | 15 ++++++--------- src/GM.hs | 3 ++- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 6d2e5ef..969d3e5 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -3,7 +3,7 @@ Module : Core.Parse Description : Parser for the Core language -} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings, ViewPatterns #-} module Core.Parse ( parseCore , parseCoreExpr @@ -23,7 +23,9 @@ import Compiler.RLPC import Lens.Micro import Data.Default.Class (def) import Data.Hashable (Hashable) +import Data.List.Extra import Data.Text.IO qualified as TIO +import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H } @@ -83,6 +85,15 @@ Program : ScTypeSig ';' Program { insTypeSig $1 $3 } | ScTypeSig OptSemi { singletonTypeSig $1 } | ScDef ';' Program { insScDef $1 $3 } | ScDef OptSemi { singletonScDef $1 } + | TLPragma ';' Program {% doTLPragma $1 $3 } + | TLPragma OptSemi {% doTLPragma $1 mempty } + +TLPragma :: { Pragma } + : '{-#' Words '#-}' { Pragma $2 } + +Words :: { [Text] } + : Words word { $1 `snoc` $2 } + | word { [$1] } OptSemi :: { () } OptSemi : ';' { () } @@ -150,22 +161,15 @@ Alters : Alter ';' Alters { $1 : $3 } | Alter { [$1] } Alter :: { Alter Name } -Alter : alttag ParList '->' Expr { Alter (AltTag $1) $2 $4 } +Alter : alttag ParList '->' Expr { Alter (AltTag $1) $2 $4 } + | Con ParList '->' Expr { Alter (AltData $1) $2 $4 } Expr1 :: { Expr Name } Expr1 : litint { Lit $ IntL $1 } | Id { Var $1 } | PackCon { $1 } - | ExprPragma { $1 } | '(' Expr ')' { $2 } -ExprPragma :: { Expr Name } -ExprPragma : '{-#' Words '#-}' {% exprPragma $2 } - -Words :: { [String] } -Words : word Words { T.unpack $1 : $2 } - | word { [T.unpack $1] } - PackCon :: { Expr Name } PackCon : pack '{' litint litint '}' { Con $3 $4 } @@ -230,5 +234,17 @@ happyBind m k = m >>= k happyPure :: a -> RLPC a happyPure a = pure a +doTLPragma :: Pragma -> Program' -> RLPC Program' +-- TODO: warn unrecognised pragma +doTLPragma (Pragma []) p = pure p + +doTLPragma (Pragma pr) p = case pr of + -- TODO: warn on overwrite + ["PackData", n, readt -> t, readt -> a] -> + pure $ p & programDataTags . at n ?~ (t,a) + +readt :: (Read a) => Text -> a +readt = read . T.unpack + } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index f48d2da..9717b61 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -25,9 +25,11 @@ module Core.Syntax , Module(..) , Program(..) , Program' + , Pragma(..) , unliftScDef , programScDefs , programTypeSigs + , programDataTags , Expr' , ScDef' , Alter' @@ -102,6 +104,8 @@ data Alter b = Alter AltCon [b] (Expr b) deriving instance (Eq b) => Eq (Alter b) +newtype Pragma = Pragma [T.Text] + data Rec = Rec | NonRec deriving (Show, Read, Eq, Lift) diff --git a/src/Core2Core.hs b/src/Core2Core.hs index 5088dab..c21bd92 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -15,7 +15,7 @@ import Data.Set (Set) import Data.Set qualified as S import Data.List import Control.Monad.Writer -import Control.Monad.State +import Control.Monad.State.Lazy import Control.Arrow ((>>>)) import Data.Text qualified as T import Numeric (showHex) @@ -28,19 +28,16 @@ core2core :: Program' -> Program' core2core p = undefined gmPrep :: Program' -> Program' -gmPrep p = p' & programScDefs %~ (<>caseScs) +gmPrep p = p & traverseOf rhss (floatNonStrictCases globals) + & runFloater + & \ (me,caseScs) -> me & programScDefs %~ (<>caseScs) where - rhss :: Applicative f => (Expr z -> f (Expr z)) -> Program z -> f (Program z) + rhss :: Traversal' (Program z) (Expr z) rhss = programScDefs . each . _rhs + globals = p ^.. programScDefs . each . _lhs . _1 & S.fromList - -- i kinda don't like that we're calling floatNonStrictCases twice tbh - p' = p & rhss %~ fst . runFloater . floatNonStrictCases globals - caseScs = (p ^.. rhss) - <&> snd . runFloater . floatNonStrictCases globals - & mconcat - -- | Auxilary type used in @floatNonSrictCases@ type Floater = StateT [Name] (Writer [ScDef']) diff --git a/src/GM.hs b/src/GM.hs index 46bf3a9..d5ad9f6 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -661,7 +661,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileC _ (Con t n) = [PushConstr t n] compileC _ (Case _ _) = - error "case expressions may not appear in non-strict contexts :/" + error "GM compiler found a non-strict case expression, which should\ + \ have been floated by Core2Core.gmPrep. This is bad!" compileC _ _ = error "yet to be implemented!" -- 2.52.0 From 4f39dd36f1f84b0e2f8fc11453962469f1ab8ad0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 25 Jan 2024 12:39:57 -0700 Subject: [PATCH 108/192] resolve named data in case exprs --- src/Core/Parse.y | 5 ++--- src/Core/Syntax.hs | 15 +++++++++++++++ src/Core/Utils.hs | 26 ++++++++------------------ src/Core2Core.hs | 32 +++++++++++++++++++++++++------- 4 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 969d3e5..7dbb6b5 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -85,8 +85,8 @@ Program : ScTypeSig ';' Program { insTypeSig $1 $3 } | ScTypeSig OptSemi { singletonTypeSig $1 } | ScDef ';' Program { insScDef $1 $3 } | ScDef OptSemi { singletonScDef $1 } - | TLPragma ';' Program {% doTLPragma $1 $3 } - | TLPragma OptSemi {% doTLPragma $1 mempty } + | TLPragma Program {% doTLPragma $1 $2 } + | TLPragma {% doTLPragma $1 mempty } TLPragma :: { Pragma } : '{-#' Words '#-}' { Pragma $2 } @@ -106,7 +106,6 @@ ScDefs :: { [ScDef Name] } ScDefs : ScDef ';' ScDefs { $1 : $3 } | ScDef ';' { [$1] } | ScDef { [$1] } - | {- epsilon -} { [] } ScDef :: { ScDef Name } ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 } diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 9717b61..83b4934 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -6,8 +6,13 @@ Description : Core ASTs and the like {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DerivingStrategies, DerivingVia #-} +-- for recursion-schemes +{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable + , TemplateHaskell, TypeFamilies #-} module Core.Syntax ( Expr(..) + , ExprF(..) + , ExprF'(..) , Type(..) , pattern TyInt , Lit(..) @@ -43,6 +48,8 @@ import Data.Coerce import Data.Pretty import Data.List (intersperse) import Data.Function ((&)) +import Data.Functor.Foldable +import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.String import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict qualified as H @@ -142,8 +149,11 @@ data Program b = Program via Generically (Program b) makeLenses ''Program +makeBaseFunctor ''Expr pure [] +type ExprF' = ExprF Name + type Program' = Program Name type Expr' = Expr Name type ScDef' = ScDef Name @@ -193,3 +203,8 @@ instance HasLHS (ScDef b) (ScDef b) (b, [b]) (b, [b]) where (\ (ScDef n as _) -> (n,as)) (\ (ScDef _ _ e) (n',as') -> (ScDef n' as' e)) +instance HasLHS (Binding b) (Binding b) b b where + _lhs = lens + (\ (k := _) -> k) + (\ (_ := e) k' -> k' := e) + diff --git a/src/Core/Utils.hs b/src/Core/Utils.hs index 1a47785..956a067 100644 --- a/src/Core/Utils.hs +++ b/src/Core/Utils.hs @@ -1,16 +1,10 @@ --- for recursion schemes -{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} --- for recursion schemes -{-# LANGUAGE TemplateHaskell, TypeFamilies #-} - module Core.Utils - ( bindersOf - , rhssOf + ( programRhss + , programGlobals , isAtomic -- , insertModule , extractProgram , freeVariables - , ExprF(..) ) where ---------------------------------------------------------------------------------- @@ -23,13 +17,11 @@ import Lens.Micro import GHC.Exts (IsList(..)) ---------------------------------------------------------------------------------- -bindersOf :: (IsList l, Item l ~ b) => [Binding b] -> l -bindersOf bs = fromList $ fmap f bs - where f (k := _) = k +programGlobals :: Traversal' (Program b) b +programGlobals = programScDefs . each . _lhs . _1 -rhssOf :: (IsList l, Item l ~ Expr b) => [Binding b] -> l -rhssOf = fromList . fmap f - where f (_ := v) = v +programRhss :: Traversal' (Program b) (Expr b) +programRhss = programScDefs . each . _rhs isAtomic :: Expr b -> Bool isAtomic (Var _) = True @@ -47,8 +39,6 @@ extractProgram (Module _ p) = p ---------------------------------------------------------------------------------- -makeBaseFunctor ''Expr - freeVariables :: Expr' -> Set Name freeVariables = cata go where @@ -57,8 +47,8 @@ freeVariables = cata go -- TODO: collect free vars in rhss of bs go (LetF _ bs e) = (e `S.union` esFree) `S.difference` ns where - es = rhssOf bs :: [Expr'] - ns = bindersOf bs + es = bs ^.. each . _rhs :: [Expr'] + ns = S.fromList $ bs ^.. each . _lhs -- TODO: this feels a little wrong. maybe a different scheme is -- appropriate esFree = foldMap id $ freeVariables <$> es diff --git a/src/Core2Core.hs b/src/Core2Core.hs index c21bd92..2036915 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase #-} module Core2Core ( core2core @@ -18,8 +19,9 @@ import Control.Monad.Writer import Control.Monad.State.Lazy import Control.Arrow ((>>>)) import Data.Text qualified as T +import Data.HashMap.Strict (HashMap) import Numeric (showHex) -import Lens.Micro +import Lens.Micro.Platform import Core.Syntax import Core.Utils ---------------------------------------------------------------------------------- @@ -28,19 +30,35 @@ core2core :: Program' -> Program' core2core p = undefined gmPrep :: Program' -> Program' -gmPrep p = p & traverseOf rhss (floatNonStrictCases globals) - & runFloater - & \ (me,caseScs) -> me & programScDefs %~ (<>caseScs) +gmPrep p = p & appFloater (floatNonStrictCases globals) + & tagData where - rhss :: Traversal' (Program z) (Expr z) - rhss = programScDefs . each . _rhs - globals = p ^.. programScDefs . each . _lhs . _1 & S.fromList +tagData :: Program' -> Program' +tagData p = let ?dt = p ^. programDataTags + in p & programRhss %~ cata go where + go :: (?dt :: HashMap Name (Tag, Int)) => ExprF' Expr' -> Expr' + go (CaseF e as) = Case e (tagAlts <$> as) + go x = embed x + + tagAlts :: (?dt :: HashMap Name (Tag, Int)) => Alter' -> Alter' + tagAlts (Alter (AltData c) bs e) = Alter (AltTag tag) bs e + where tag = case ?dt ^. at c of + Just (t,_) -> t + -- TODO: errorful + Nothing -> error $ "unknown constructor " <> show c + tagAlts x = x + -- | Auxilary type used in @floatNonSrictCases@ type Floater = StateT [Name] (Writer [ScDef']) +appFloater :: (Expr' -> Floater Expr') -> Program' -> Program' +appFloater fl p = p & traverseOf programRhss fl + & runFloater + & \ (me,floats) -> me & programScDefs %~ (<>floats) + runFloater :: Floater a -> (a, [ScDef']) runFloater = flip evalStateT ns >>> runWriter where -- 2.52.0 From eeeac9cc85291553c2d9c4e5edf0eb377b52102b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 25 Jan 2024 13:02:12 -0700 Subject: [PATCH 109/192] named constr tests --- src/Core/Examples.hs | 33 +++++++++++++++++++++++++++------ src/GM.hs | 6 +++++- tst/GMSpec.hs | 15 +++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index 0b741e9..f9f4468 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -4,12 +4,7 @@ Description : Core examples (may eventually be unit tests) -} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-} -module Core.Examples - ( fac3 - , sumList - , constDivZero - , idCase - ) where +module Core.Examples where ---------------------------------------------------------------------------------- import Core.Syntax import Core.TH @@ -196,6 +191,32 @@ idCase = [coreProg| }) |] +-- NOTE: the GM primitive (==#) returns an untyped constructor with tag 1 for +-- true, and 0 for false. See: GM.boxBool +namedBoolCase :: Program' +namedBoolCase = [coreProg| + {-# PackData True 1 0 #-} + {-# PackData False 0 0 #-} + main = case (==#) 1 1 of + { True -> 123 + ; False -> 456 + } + |] + +namedConsCase :: Program' +namedConsCase = [coreProg| + {-# PackData Nil 0 0 #-} + {-# PackData Cons 1 2 #-} + Nil = Pack{0 0}; + Cons = Pack{1 2}; + foldr f z l = case l of + { Nil -> z + ; Cons x xs -> f x (foldr f z xs) + }; + list = Cons 1 (Cons 2 (Cons 3 Nil)); + main = foldr (+#) 0 list + |] + -- corePrelude :: Module Name -- corePrelude = Module (Just ("Prelude", [])) $ -- -- non-primitive defs diff --git a/src/GM.hs b/src/GM.hs index d5ad9f6..065cb08 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -662,7 +662,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileC _ (Case _ _) = error "GM compiler found a non-strict case expression, which should\ - \ have been floated by Core2Core.gmPrep. This is bad!" + \ have been floated by Core2Core.gmPrep. This is a bug!" compileC _ _ = error "yet to be implemented!" @@ -731,6 +731,10 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil binds = (NameKey <$> as) `zip` [0..] g' = binds ++ argOffset n g c = compileE g' e + compileA _ (Alter _ as e) = error "GM.compileA found an untagged\ + \ constructor, which should have\ + \ been handled by Core2Core.gmPrep.\ + \ This is a bug!" inlineOp1 :: Env -> Instr -> Expr' -> Code inlineOp1 g i a = compileE g a <> [i] diff --git a/tst/GMSpec.hs b/tst/GMSpec.hs index dd5957a..cc5faf1 100644 --- a/tst/GMSpec.hs +++ b/tst/GMSpec.hs @@ -27,15 +27,22 @@ spec = do in coreRes `shouldBe` arithRes describe "test programs" $ do - it "fac 3" $ do + it "fac 3" $ resultOf Ex.fac3 `shouldBe` Just (NNum 6) - it "sum [1,2,3]" $ do + it "sum [1,2,3]" $ resultOf Ex.sumList `shouldBe` Just (NNum 6) - it "k 3 ((/#) 1 0)" $ do + it "k 3 ((/#) 1 0)" $ resultOf Ex.constDivZero `shouldBe` Just (NNum 3) - it "id (case ... of { ... })" $ do + it "id (case ... of { ... })" $ resultOf Ex.idCase `shouldBe` Just (NNum 5) + it "bool pattern matching with named constructors" $ + resultOf Ex.namedBoolCase `shouldBe` Just (NNum 123) + + it "list pattern matching with named constructors" $ + resultOf Ex.namedConsCase `shouldBe` Just (NNum 6) + + -- 2.52.0 From bb3f73836ce0f54eff35606cf196ce6423cb04c8 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 25 Jan 2024 13:18:04 -0700 Subject: [PATCH 110/192] nearing release :3 --- README.md | 61 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 99d6323..2f38469 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ $ rlpc -ddump-opts t.hs ### Potential Features Listed in order of importance. -- [ ] ADTs -- [ ] First-class functions +- [x] ADTs +- [x] First-class functions - [ ] Higher-kinded types - [ ] Typeclasses -- [ ] Parametric polymorphism -- [ ] Hindley-Milner type inference +- [x] Parametric polymorphism +- [x] Hindley-Milner type inference - [ ] Newtype coercion - [ ] Parallelism @@ -66,32 +66,59 @@ Listed in order of importance. - [ ] TCO - [ ] DCE - [ ] Frontend - - [ ] High-level language - - [ ] AST - - [ ] Lexer - - [ ] Parser + - [x] High-level language + - [x] AST + - [x] Lexer + - [x] Parser - [ ] Translation to the core language - [ ] Constraint solver - [ ] `do`-notation - [x] CLI - [ ] Documentation - - [ ] State transition rules + - [x] State transition rules - [ ] How does the evaluation model work? + - [ ] The Hindley-Milner type system - [ ] CLI usage - [ ] Tail call optimisation - - [x] Parsing rlp + - [ ] Parsing rlp - [ ] Tests - [x] Generic example programs - [ ] Parser -### December Release Plan -- [ ] Tests +### ~~December Release Plan~~ +- [x] Tests - [ ] Core lexer - [ ] Core parser - - [ ] Evaluation model + - [x] Evaluation model - [ ] Benchmarks -- [ ] Stable Core lexer -- [ ] Stable Core parser -- [ ] Stable evaluation model - - [ ] Garbage Collection +- [x] Stable Core lexer +- [x] Stable Core parser +- [x] Stable evaluation model + - [x] Garbage Collection - [ ] Stable documentation for the evaluation model + +### January Release Plan +- [ ] Beta rl' to Core +- [ ] UX improvements + - [ ] Actual compiler errors -- no more unexceptional `error` calls + - [ ] Better CLI dump flags + - [ ] Annotate the AST with token positions for errors + +### March Release Plan +- [ ] Tests + - [ ] rl' parser + - [ ] rl' lexer + +### Indefinite Release Plan + +This list is more concrete than the milestones, but likely further in the future +than the other release plans. + +- [ ] Stable rl' to Core +- [ ] Core polish + - [ ] Better, stable parser + - [ ] Better, stable lexer + - [ ] Less hacky handling of named data + - [ ] Less hacky pragmas +- [ ] GM to LLVM + -- 2.52.0 From 559fd49f2b2aab4cd2aa6a1ab32cd571973303f0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 25 Jan 2024 15:52:56 -0700 Subject: [PATCH 111/192] minor changes putting this on hold; implementing TTG first --- CHANGELOG.md | 2 ++ README.md | 1 + app/Main.hs | 2 +- rlp.cabal | 2 +- src/Compiler/RLPC.hs | 59 ++++++++++++++++++++------------------------ 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9921c0c..88e5ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,3 +15,5 @@ } ``` +# Release 1.0.0 + diff --git a/README.md b/README.md index 2f38469..1573d64 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ Listed in order of importance. - [ ] Actual compiler errors -- no more unexceptional `error` calls - [ ] Better CLI dump flags - [ ] Annotate the AST with token positions for errors +- [ ] More examples ### March Release Plan - [ ] Tests diff --git a/app/Main.hs b/app/Main.hs index f48824b..27377d0 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -63,7 +63,7 @@ options = RLPCOptions evaluatorReader :: ReadM Evaluator evaluatorReader = maybeReader $ \case "gm" -> Just EvaluatorGM - "tim" -> Just EvaluatorTI + "ti" -> Just EvaluatorTI _ -> Nothing mmany :: (Alternative f, Monoid m) => f m -> f m diff --git a/rlp.cabal b/rlp.cabal index a48324a..a487328 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -7,7 +7,7 @@ license: GPL-2.0-only -- license-file: LICENSE author: crumbtoo maintainer: crumb@disroot.org --- copyright: +copyright: Madeleine Sydney Ślaga category: Language build-type: Simple extra-doc-files: README.md diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 2993c67..474ecfc 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -28,14 +28,12 @@ module Compiler.RLPC , evalRLPCIO , evalRLPC , rlpcLogFile - , rlpcDebugOpts + , rlpcDFlags , rlpcEvaluator , rlpcInputFiles , DebugFlag(..) - , whenFlag - , flagDDumpEval - , flagDDumpOpts - , flagDDumpAST + , whenDFlag + , whenFFlag , def , liftErrorful ) @@ -43,6 +41,7 @@ module Compiler.RLPC ---------------------------------------------------------------------------------- import Control.Arrow ((>>>)) import Control.Exception +import Control.Monad import Control.Monad.Reader import Control.Monad.State (MonadState(state)) import Control.Monad.Errorful @@ -51,19 +50,19 @@ import Data.Functor.Identity import Data.Default.Class import Data.Foldable import GHC.Generics (Generic) +import Data.Maybe import Data.Hashable (Hashable) import Data.HashSet (HashSet) import Data.HashSet qualified as S import Data.Coerce -import Lens.Micro -import Lens.Micro.TH +import Lens.Micro.Platform import System.Exit ---------------------------------------------------------------------------------- newtype RLPCT m a = RLPCT { runRLPCT :: ReaderT RLPCOptions (ErrorfulT (MsgEnvelope RlpcError) m) a } - deriving (Functor, Applicative, Monad) + deriving (Functor, Applicative, Monad, MonadReader RLPCOptions) type RLPC = RLPCT Identity @@ -98,7 +97,8 @@ liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e) data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath - , _rlpcDebugOpts :: DebugOpts + , _rlpcDFlags :: HashSet DebugFlag + , _rlpcFFlags :: HashSet CompilerFlag , _rlpcEvaluator :: Evaluator , _rlpcHeapTrigger :: Int , _rlpcInputFiles :: [FilePath] @@ -113,38 +113,33 @@ data Evaluator = EvaluatorGM | EvaluatorTI instance Default RLPCOptions where def = RLPCOptions { _rlpcLogFile = Nothing - , _rlpcDebugOpts = mempty + , _rlpcDFlags = mempty + , _rlpcFFlags = mempty , _rlpcEvaluator = EvaluatorGM , _rlpcHeapTrigger = 200 , _rlpcInputFiles = [] } -type DebugOpts = HashSet DebugFlag +-- debug flags are passed with -dFLAG +type DebugFlag = String -data DebugFlag = DDumpEval - | DDumpOpts - | DDumpAST - deriving (Show, Eq, Generic) - -instance Hashable DebugFlag +type CompilerFlag = String makeLenses ''RLPCOptions pure [] -whenFlag :: (MonadReader s m) => SimpleGetter s Bool -> m () -> m () -whenFlag l m = asks (^. l) >>= \a -> if a then m else pure () +-- TODO: rewrite this with prisms once microlens-pro drops :3 +whenDFlag :: (Monad m) => DebugFlag -> RLPCT m () -> RLPCT m () +whenDFlag f m = do + -- mfw no `At` instance for HashSet + fs <- view rlpcDFlags + let a = S.member f fs + when a m --- there's probably a better way to write this. my current knowledge of lenses --- is too weak. -flagGetter :: DebugFlag -> SimpleGetter RLPCOptions Bool -flagGetter d = to $ \s -> s ^. rlpcDebugOpts & S.member d - -flagDDumpEval :: SimpleGetter RLPCOptions Bool -flagDDumpEval = flagGetter DDumpEval - -flagDDumpOpts :: SimpleGetter RLPCOptions Bool -flagDDumpOpts = flagGetter DDumpOpts - -flagDDumpAST :: SimpleGetter RLPCOptions Bool -flagDDumpAST = flagGetter DDumpAST +whenFFlag :: (Monad m) => CompilerFlag -> RLPCT m () -> RLPCT m () +whenFFlag f m = do + -- mfw no `At` instance for HashSet + fs <- view rlpcFFlags + let a = S.member f fs + when a m -- 2.52.0 From 6a6076f26e43e2e317a31c61d742f8349dc02ed6 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 26 Jan 2024 15:12:10 -0700 Subject: [PATCH 112/192] some --- README.md | 1 + rlp.cabal | 2 + src/Rlp/Lex.x | 11 +- src/Rlp/Parse.y | 80 +++++++------- src/Rlp/Parse/Associate.hs | 87 +--------------- src/Rlp/Parse/Types.hs | 117 ++++++++------------- src/Rlp/Syntax.hs | 208 ++++++++++++++++--------------------- 7 files changed, 190 insertions(+), 316 deletions(-) diff --git a/README.md b/README.md index 1573d64..4b010ec 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Listed in order of importance. - [ ] CLI usage - [ ] Tail call optimisation - [ ] Parsing rlp + - [ ] Trees That Grow - [ ] Tests - [x] Generic example programs - [ ] Parser diff --git a/rlp.cabal b/rlp.cabal index a487328..1ac0b54 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -75,6 +75,8 @@ library default-extensions: OverloadedStrings + TypeFamilies + LambdaCase executable rlpc import: warnings diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 6942b84..e4c78c3 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -193,13 +193,13 @@ readInt = T.foldr f 0 where constToken :: RlpToken -> LexerAction (Located RlpToken) constToken t inp l = do pos <- use (psInput . aiPos) - pure (Located (pos,l) t) + pure (Located (spanFromPos pos l) t) tokenWith :: (Text -> RlpToken) -> LexerAction (Located RlpToken) tokenWith tf inp l = do pos <- getPos let t = tf (T.take l $ inp ^. aiSource) - pure (Located (pos,l) t) + pure (Located (spanFromPos pos l) t) getPos :: P Position getPos = use (psInput . aiPos) @@ -207,7 +207,8 @@ getPos = use (psInput . aiPos) alexEOF :: P (Located RlpToken) alexEOF = do inp <- getInput - pure (Located undefined TokenEOF) + pos <- getPos + pure (Located (spanFromPos pos 0) TokenEOF) initParseState :: Text -> ParseState initParseState s = ParseState @@ -238,7 +239,7 @@ lexToken = do st <- use id -- traceM $ "st: " <> show st case alexScan inp c of - AlexEOF -> pure $ Located (inp ^. aiPos, 0) TokenEOF + AlexEOF -> pure $ Located (spanFromPos (inp^.aiPos) 0) TokenEOF AlexSkip inp' l -> do psInput .= inp' lexToken @@ -274,7 +275,7 @@ indentLevel = do insertToken :: RlpToken -> P (Located RlpToken) insertToken t = do pos <- use (psInput . aiPos) - pure (Located (pos, 0) t) + pure (Located (spanFromPos pos 0) t) popLayout :: P Layout popLayout = do diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 444a6d4..6cc0a49 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -9,13 +9,13 @@ import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types import Rlp.Parse.Associate -import Lens.Micro -import Lens.Micro.Mtl -import Lens.Micro.Platform () +import Lens.Micro.Platform import Data.List.Extra import Data.Fix import Data.Functor.Const +import Data.Functor import Data.Text qualified as T +import Data.Void } %name parseRlpProg StandaloneProgram @@ -26,12 +26,12 @@ import Data.Text qualified as T %tokentype { Located RlpToken } %token - varname { Located _ (TokenVarName $$) } - conname { Located _ (TokenConName $$) } - consym { Located _ (TokenConSym $$) } - varsym { Located _ (TokenVarSym $$) } + varname { Located _ (TokenVarName _) } + conname { Located _ (TokenConName _) } + consym { Located _ (TokenConSym _) } + varsym { Located _ (TokenVarSym _) } data { Located _ TokenData } - litint { Located _ (TokenLitInt $$) } + litint { Located _ (TokenLitInt _) } '=' { Located _ TokenEquals } '|' { Located _ TokenPipe } ';' { Located _ TokenSemicolon } @@ -51,7 +51,7 @@ import Data.Text qualified as T %% -StandaloneProgram :: { RlpProgram' } +StandaloneProgram :: { RlpProgram RlpcPs } StandaloneProgram : '{' Decls '}' {% mkProgram $2 } | VL DeclsV VR {% mkProgram $2 } @@ -62,12 +62,12 @@ VR :: { () } VR : vrbrace { () } | error { () } -Decls :: { [PartialDecl'] } +Decls :: { [Decl' RlpcPs] } Decls : Decl ';' Decls { $1 : $3 } | Decl ';' { [$1] } | Decl { [$1] } -DeclsV :: { [PartialDecl'] } +DeclsV :: { [Decl' RlpcPs] } DeclsV : Decl VS Decls { $1 : $3 } | Decl VS { [$1] } | Decl { [$1] } @@ -76,12 +76,12 @@ VS :: { Located RlpToken } VS : ';' { $1 } | vsemi { $1 } -Decl :: { PartialDecl' } +Decl :: { Decl' RlpcPs } : FunDecl { $1 } | DataDecl { $1 } | InfixDecl { $1 } -InfixDecl :: { PartialDecl' } +InfixDecl :: { Decl' RlpcPs } : InfixWord litint InfixOp {% mkInfixD $1 $2 $3 } InfixWord :: { Assoc } @@ -89,18 +89,18 @@ InfixWord :: { Assoc } | infixr { InfixR } | infix { Infix } -DataDecl :: { PartialDecl' } +DataDecl :: { Decl' RlpcPs } : data Con TyParams '=' DataCons { DataD $2 $3 $5 } -TyParams :: { [Name] } +TyParams :: { [PsName] } : {- epsilon -} { [] } | TyParams varname { $1 `snoc` $2 } -DataCons :: { [ConAlt] } +DataCons :: { [ConAlt RlpcPs] } : DataCons '|' DataCon { $1 `snoc` $3 } | DataCon { [$1] } -DataCon :: { ConAlt } +DataCon :: { ConAlt RlpcPs } : Con Type1s { ConAlt $1 $2 } Type1s :: { [Type] } @@ -116,22 +116,22 @@ Type :: { Type } : Type '->' Type { $1 :-> $3 } | Type1 { $1 } -FunDecl :: { PartialDecl' } -FunDecl : Var Params '=' Expr { FunD $1 $2 (Const $4) Nothing } +FunDecl :: { Decl' RlpcPs } +FunDecl : Var Params '=' Expr { FunD $1 $2 $4 Nothing } -Params :: { [Pat'] } +Params :: { [Pat' RlpcPs] } Params : {- epsilon -} { [] } | Params Pat1 { $1 `snoc` $2 } -Pat1 :: { Pat' } +Pat1 :: { Pat' RlpcPs } : Var { VarP $1 } | Lit { LitP $1 } -Expr :: { PartialExpr' } +Expr :: { RlpExpr' RlpcPs } : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } | Expr1 { $1 } -Expr1 :: { PartialExpr' } +Expr1 :: { RlpExpr' RlpcPs } : '(' Expr ')' { wrapFix . Par . unwrapFix $ $2 } | Lit { Fix . E $ LitEF $1 } | Var { Fix . E $ VarEF $1 } @@ -139,34 +139,43 @@ Expr1 :: { PartialExpr' } -- TODO: happy prefers left-associativity. doing such would require adjusting -- the code in Rlp.Parse.Associate to expect left-associative input rather than -- right. -InfixExpr :: { PartialExpr' } +InfixExpr :: { RlpExpr' RlpcPs } : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } -InfixOp :: { Name } +InfixOp :: { PsName } : consym { $1 } | varsym { $1 } -Lit :: { Lit' } -Lit : litint { IntL $1 } +-- TODO: microlens-pro save me microlens-pro (rewrite this with prisms) +Lit :: { Lit' RlpcPs } + : litint { $1 <&> (IntL . (\ (TokenLitInt n) -> n)) } -Var :: { VarId } -Var : varname { NameVar $1 } +Var :: { Located PsName } +Var : varname { mkPsName $1 } -Con :: { ConId } - : conname { NameCon $1 } +Con :: { Located PsName } + : conname { mkPsName $1 } { -mkProgram :: [PartialDecl'] -> P RlpProgram' +mkPsName :: Located RlpToken -> Located PsName +mkPsName = fmap $ \case + TokenVarName n -> n + TokenConName n -> n + TokenConSym n -> n + TokenVarSym n -> n + _ -> error "mkPsName: not an identifier" + +mkProgram :: [Decl' RlpcPs] -> P (RlpProgram RlpcPs) mkProgram ds = do pt <- use psOpTable pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError (Located ((l,c),s) t) = addFatal $ +parseError (Located (l,c,s) t) = addFatal $ errorMsg (SrcSpan l c s) RlpParErrUnexpectedToken -mkInfixD :: Assoc -> Int -> Name -> P PartialDecl' +mkInfixD :: Assoc -> Int -> PsName -> P (Decl' RlpcPs) mkInfixD a p n = do let opl :: Lens' ParseState (Maybe OpInfo) opl = psOpTable . at n @@ -176,6 +185,7 @@ mkInfixD a p n = do l = T.length n Nothing -> pure (Just (a,p)) ) - pure $ InfixD a p n + pos <- use (psInput . aiPos) + pure $ Located (spanFromPos pos 0) (InfixD' a p n) } diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs index 7446589..8dd89f2 100644 --- a/src/Rlp/Parse/Associate.hs +++ b/src/Rlp/Parse/Associate.hs @@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms, ViewPatterns, ImplicitParams #-} module Rlp.Parse.Associate + {-# WARNING "temporarily unimplemented" #-} ( associate ) where @@ -13,88 +14,6 @@ import Rlp.Parse.Types import Rlp.Syntax -------------------------------------------------------------------------------- -associate :: OpTable -> PartialDecl' -> Decl' RlpExpr -associate pt (FunD n as b w) = FunD n as b' w - where b' = let ?pt = pt in completeExpr (getConst b) -associate pt (TySigD ns t) = TySigD ns t -associate pt (DataD n as cs) = DataD n as cs -associate pt (InfixD a p n) = InfixD a p n - -completeExpr :: (?pt :: OpTable) => PartialExpr' -> RlpExpr' -completeExpr = cata completePartial - -completePartial :: (?pt :: OpTable) => PartialE -> RlpExpr' -completePartial (E e) = completeRlpExpr e -completePartial p@(B o l r) = completeB (build p) -completePartial (Par e) = completePartial e - -completeRlpExpr :: (?pt :: OpTable) => RlpExprF' RlpExpr' -> RlpExpr' -completeRlpExpr = embed - -completeB :: (?pt :: OpTable) => PartialE -> RlpExpr' -completeB p = case build p of - B o l r -> (o' `AppE` l') `AppE` r' - where - -- TODO: how do we know it's symbolic? - o' = VarE (SymVar o) - l' = completeB l - r' = completeB r - Par e -> completeB e - E e -> completeRlpExpr e - -build :: (?pt :: OpTable) => PartialE -> PartialE -build e = go id e (rightmost e) where - rightmost :: PartialE -> PartialE - rightmost (B _ _ r) = rightmost r - rightmost p@(E _) = p - rightmost p@(Par _) = p - - go :: (?pt :: OpTable) - => (PartialE -> PartialE) - -> PartialE -> PartialE -> PartialE - go f p@(WithInfo o _ r) = case r of - E _ -> mkHole o (f . f') - Par _ -> mkHole o (f . f') - B _ _ _ -> go (mkHole o (f . f')) r - where f' r' = p & pR .~ r' - go f _ = id - -mkHole :: (?pt :: OpTable) - => OpInfo - -> (PartialE -> PartialE) - -> PartialE - -> PartialE -mkHole _ hole p@(Par _) = hole p -mkHole _ hole p@(E _) = hole p -mkHole (a,d) hole p@(WithInfo (a',d') _ _) - | d' < d = above - | d' > d = below - | d == d' = case (a,a') of - -- left-associative operators of equal precedence are - -- associated left - (InfixL,InfixL) -> above - -- right-associative operators are handled similarly - (InfixR,InfixR) -> below - -- non-associative operators of equal precedence, or equal - -- precedence operators of different associativities are - -- invalid - (_, _) -> error "invalid expression" - where - above = p & pL %~ hole - below = hole p - -examplePrecTable :: OpTable -examplePrecTable = H.fromList - [ ("+", (InfixL,6)) - , ("*", (InfixL,7)) - , ("^", (InfixR,8)) - , (".", (InfixR,7)) - , ("~", (Infix, 9)) - , ("=", (Infix, 4)) - , ("&&", (Infix, 3)) - , ("||", (Infix, 2)) - , ("$", (InfixR,0)) - , ("&", (InfixL,0)) - ] - +associate = undefined +{-# WARNING associate "temporarily undefined" #-} diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index bddf0d9..794c28a 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -2,38 +2,24 @@ {-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-} {-# LANGUAGE LambdaCase #-} module Rlp.Parse.Types - ( LexerAction - , MsgEnvelope(..) - , RlpcError(..) - , AlexInput(..) - , Position(..) - , RlpToken(..) - , P(..) - , ParseState(..) - , psLayoutStack - , psLexState - , psInput - , psOpTable - , Layout(..) - , Located(..) - , OpTable - , OpInfo - , RlpParseError(..) - , PartialDecl' - , Partial(..) - , pL, pR - , PartialE - , pattern WithInfo - , opInfoOrDef - , PartialExpr' - , aiPrevChar - , aiSource - , aiBytes - , aiPos - , addFatal - , addWound - , addFatalHere - , addWoundHere + ( + -- * Trees That Grow + RlpcPs + + -- * Parser monad and state + , P(..), ParseState(..), Layout(..), OpTable, OpInfo + -- ** Lenses + , psLayoutStack, psLexState, psInput, psOpTable + + -- * Other parser types + , RlpToken(..), AlexInput(..), Position(..), spanFromPos, LexerAction + , Located(..), PsName + -- ** Lenses + , aiPrevChar, aiSource, aiBytes, aiPos, posLine, posColumn + + -- * Error handling + , MsgEnvelope(..), RlpcError(..), RlpParseError(..) + , addFatal, addWound, addFatalHere, addWoundHere ) where -------------------------------------------------------------------------------- @@ -49,12 +35,26 @@ import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes import Data.HashMap.Strict qualified as H +import Data.Void import Data.Word (Word8) import Lens.Micro.TH import Lens.Micro import Rlp.Syntax -------------------------------------------------------------------------------- +-- | Phantom type identifying rlpc's parser phase + +data RlpcPs + +type instance XRec RlpcPs f = Located (f RlpcPs) +type instance IdP RlpcPs = PsName + +type instance XInfixD RlpcPs = () + +type PsName = Text + +-------------------------------------------------------------------------------- + type LexerAction a = AlexInput -> Int -> P a data AlexInput = AlexInput @@ -106,7 +106,7 @@ data RlpToken | TokenLParen | TokenRParen -- 'virtual' control symbols, inserted by the lexer without any correlation - -- to a specific symbol + -- to a specific part of the input | TokenSemicolonV | TokenLBraceV | TokenRBraceV @@ -154,8 +154,14 @@ data Layout = Explicit | Implicit Int deriving (Show, Eq) -data Located a = Located (Position, Int) a - deriving (Show) +-- | Token wrapped with a span (line, column, length) +data Located a = Located !(Int, Int, Int) a + deriving (Show, Functor) + +spanFromPos :: Position -> Int -> (Int, Int, Int) +spanFromPos (l,c) s = (l,c,s) + +{-# INLINE spanFromPos #-} type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) @@ -171,47 +177,6 @@ data RlpParseError = RlpParErrOutOfBoundsPrecedence Int instance IsRlpcError RlpParseError where ---------------------------------------------------------------------------------- --- absolute psycho shit (partial ASTs) - -type PartialDecl' = Decl (Const PartialExpr') Name - -data Partial a = E (RlpExprF Name a) - | B Name (Partial a) (Partial a) - | Par (Partial a) - deriving (Show, Functor) - -pL :: Traversal' (Partial a) (Partial a) -pL k (B o l r) = (\l' -> B o l' r) <$> k l -pL _ x = pure x - -pR :: Traversal' (Partial a) (Partial a) -pR k (B o l r) = (\r' -> B o l r') <$> k r -pR _ x = pure x - -type PartialE = Partial RlpExpr' - --- i love you haskell -pattern WithInfo :: (?pt :: OpTable) => OpInfo -> PartialE -> PartialE -> PartialE -pattern WithInfo p l r <- B (opInfoOrDef -> p) l r - -opInfoOrDef :: (?pt :: OpTable) => Name -> OpInfo -opInfoOrDef c = fromMaybe (InfixL,9) $ H.lookup c ?pt - --- required to satisfy constraint on Fix's show instance -instance Show1 Partial where - liftShowsPrec :: forall a. (Int -> a -> ShowS) - -> ([a] -> ShowS) - -> Int -> Partial a -> ShowS - - liftShowsPrec sp sl p m = case m of - (E e) -> showsUnaryWith lshow "E" p e - (B f a b) -> showsTernaryWith showsPrec lshow lshow "B" p f a b - (Par e) -> showsUnaryWith lshow "Par" p e - where - lshow :: forall f. (Show1 f) => Int -> f a -> ShowS - lshow = liftShowsPrec sp sl - -type PartialExpr' = Fix Partial makeLenses ''AlexInput makeLenses ''ParseState diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index a79c496..76156c7 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -1,40 +1,28 @@ -- recursion-schemes -{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} --- recursion-schemes -{-# LANGUAGE TemplateHaskell, TypeFamilies #-} +{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable + , TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings, PatternSynonyms #-} +{-# LANGUAGE TypeFamilies, TypeFamilyDependencies #-} module Rlp.Syntax - ( RlpModule(..) - , RlpProgram(..) - , RlpProgram' - , rlpmodName - , rlpmodProgram - , RlpExpr(..) - , RlpExpr' - , RlpExprF(..) - , RlpExprF' - , Decl(..) - , Decl' - , Bind(..) - , Where - , Where' - , ConAlt(..) - , Type(..) - , pattern (:->) + ( + -- * AST + RlpProgram(..) + , Decl(..), Decl', RlpExpr(..), RlpExpr' + , Pat(..), Pat' , Assoc(..) - , VarId(..) - , ConId(..) - , Pat(..) - , Pat' - , Lit(..) - , Lit' - , Name + , Lit(..), Lit' + , Type(..) + , ConAlt(..) - -- TODO: ugh move this somewhere else later - , showsTernaryWith + -- * Pattern synonyms for unused extensions + , pattern InfixD' - -- * Convenience re-exports - , Text + -- * Trees That Grow extensions + , XRec, IdP + -- ** RlpExpr + , XLetE, XVarE, XConE, XLamE, XCaseE, XIfE, XAppE, XLitE, XXRlpExpr + -- ** Decl + , XFunD, XTySigD, XDataD, XInfixD, XXDecl ) where ---------------------------------------------------------------------------------- @@ -49,87 +37,91 @@ import Core.Syntax hiding (Lit) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- -data RlpModule b = RlpModule +data RlpModule p = RlpModule { _rlpmodName :: Text - , _rlpmodProgram :: RlpProgram b + , _rlpmodProgram :: RlpProgram p } -newtype RlpProgram b = RlpProgram [Decl RlpExpr b] - deriving Show +newtype RlpProgram p = RlpProgram [Decl p] -type RlpProgram' = RlpProgram Name +data Decl p = FunD (XFunD p) (IdP p) [Pat p] (RlpExpr p) (Maybe (Where p)) + | TySigD (XTySigD p) [IdP p] Type + | DataD (XDataD p) (IdP p) [IdP p] [ConAlt p] + | InfixD (XInfixD p) Assoc Int (IdP p) + | XDecl !(XXDecl p) --- | The @e@ parameter is used for partial results. When parsing an input, we --- first parse all top-level declarations in order to extract infix[lr] --- declarations. This process yields a @[Decl (Const Text) Name]@, where @Const --- Text@ stores the remaining unparsed function bodies. Once infixities are --- accounted for, we may complete the parsing task and get a proper @[Decl --- RlpExpr Name]@. +type family XFunD p +type family XTySigD p +type family XDataD p +type family XInfixD p +type family XXDecl p -data Decl e b = FunD VarId [Pat b] (e b) (Maybe (Where b)) - | TySigD [VarId] Type - | DataD ConId [Name] [ConAlt] - | InfixD Assoc Int Name - deriving Show +pattern InfixD' :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p +pattern InfixD' a p n = InfixD () a p n -type Decl' e = Decl e Name +type Decl' p = XRec p Decl data Assoc = InfixL | InfixR | Infix - deriving Show + deriving (Show) -data ConAlt = ConAlt ConId [Type] - deriving Show +data ConAlt p = ConAlt (IdP p) [Type] -data RlpExpr b = LetE [Bind b] (RlpExpr b) - | VarE VarId - | ConE ConId - | LamE [Pat b] (RlpExpr b) - | CaseE (RlpExpr b) [(Alt b, Where b)] - | IfE (RlpExpr b) (RlpExpr b) (RlpExpr b) - | AppE (RlpExpr b) (RlpExpr b) - | LitE (Lit b) - deriving Show +data RlpExpr p = LetE (XLetE p) [Bind p] (RlpExpr' p) + | VarE (XVarE p) (IdP p) + | LamE (XLamE p) [Pat p] (RlpExpr' p) + | CaseE (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] + | IfE (XIfE p) (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) + | AppE (XAppE p) (RlpExpr' p) (RlpExpr' p) + | LitE (XLitE p) (Lit p) + | ParE (XParE p) (RlpExpr' p) + | OAppE (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) + | XRlpExpr !(XXRlpExpr p) -type RlpExpr' = RlpExpr Name +type RlpExpr' p = XRec p RlpExpr -type Where b = [Bind b] -type Where' = [Bind Name] +class UnXRec p where + unXRec :: XRec p f -> f p + +class MapXRec p where + mapXRec :: (f p -> f p) -> XRec p f -> XRec p f + +type family XRec p (f :: * -> *) = (r :: *) | r -> p f + +type family XLetE p +type family XVarE p +type family XConE p +type family XLamE p +type family XCaseE p +type family XIfE p +type family XAppE p +type family XLitE p +type family XParE p +type family XOAppE p +type family XXRlpExpr p + +type family IdP p + +type Where p = [Bind p] -- do we want guards? -data Alt b = AltA (Pat b) (RlpExpr b) - deriving Show +data Alt p = AltA (Pat' p) (RlpExpr' p) -data Bind b = PatB (Pat b) (RlpExpr b) - | FunB VarId [Pat b] (RlpExpr b) - deriving Show +data Bind p = PatB (Pat' p) (RlpExpr' p) + | FunB (IdP p) [Pat' p] (RlpExpr' p) -data VarId = NameVar Text - | SymVar Text - deriving Show +data Pat p = VarP (IdP p) + | LitP (Lit' p) + | ConP (IdP p) [Pat' p] -instance IsString VarId where - -- TODO: use symvar if it's an operator - fromString = NameVar . T.pack +type Pat' p = XRec p Pat -data ConId = NameCon Text - | SymCon Text - deriving Show - -data Pat b = VarP VarId - | LitP (Lit b) - | ConP ConId [Pat b] - deriving Show - -type Pat' = Pat Name - -data Lit b = IntL Int +data Lit p = IntL Int | CharL Char - | ListL [RlpExpr b] - deriving Show + | ListL [RlpExpr' p] -type Lit' = Lit Name +type Lit' p = XRec p Lit -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens @@ -143,33 +135,17 @@ type Lit' = Lit Name makeBaseFunctor ''RlpExpr -deriving instance (Show b, Show a) => Show (RlpExprF b a) - -type RlpExprF' = RlpExprF Name - --- society if derivable Show1 -instance (Show b) => Show1 (RlpExprF b) where - liftShowsPrec sp _ p m = case m of - (LetEF bs e) -> showsBinaryWith showsPrec sp "LetEF" p bs e - (VarEF n) -> showsUnaryWith showsPrec "VarEF" p n - (ConEF n) -> showsUnaryWith showsPrec "ConEF" p n - (LamEF bs e) -> showsBinaryWith showsPrec sp "LamEF" p bs e - (CaseEF e as) -> showsBinaryWith sp showsPrec "CaseEF" p e as - (IfEF a b c) -> showsTernaryWith sp sp sp "IfEF" p a b c - (AppEF f x) -> showsBinaryWith sp sp "AppEF" p f x - (LitEF l) -> showsUnaryWith showsPrec "LitEF" p l - -showsTernaryWith :: (Int -> x -> ShowS) - -> (Int -> y -> ShowS) - -> (Int -> z -> ShowS) - -> String -> Int - -> x -> y -> z - -> ShowS -showsTernaryWith sa sb sc name p a b c = showParen (p > 10) - $ showString name - . showChar ' ' . sa 11 a - . showChar ' ' . sb 11 b - . showChar ' ' . sc 11 c +-- showsTernaryWith :: (Int -> x -> ShowS) +-- -> (Int -> y -> ShowS) +-- -> (Int -> z -> ShowS) +-- -> String -> Int +-- -> x -> y -> z +-- -> ShowS +-- showsTernaryWith sa sb sc name p a b c = showParen (p > 10) +-- $ showString name +-- . showChar ' ' . sa 11 a +-- . showChar ' ' . sb 11 b +-- . showChar ' ' . sc 11 c -------------------------------------------------------------------------------- -- 2.52.0 From 8d0f324c6340dbfa2890cc5030f3b672ee3ea672 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 26 Jan 2024 17:25:59 -0700 Subject: [PATCH 113/192] oh my god guys!!! `Located` is a lax semimonoidal endofunctor on the category Hask!!! ![abstractionjak](https://media.discordapp.net/attachments/1101767463579951154/1200248978642567168/3877820-20SoyBooru.png?ex=65c57df8&is=65b308f8&hm=67da3acb61861cab6156df014b397d78fb8815fa163f2e992474d545beb668ba&=&format=webp&quality=lossless&width=880&height=868) --- rlp.cabal | 1 + src/Compiler/RlpcError.hs | 1 + src/Rlp/Lex.x | 8 ++++---- src/Rlp/Parse.y | 24 ++++++++++++------------ src/Rlp/Parse/Types.hs | 37 +++++++++++++++++++++++++++++-------- src/Rlp/Syntax.hs | 12 ++++++++++++ 6 files changed, 59 insertions(+), 24 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 1ac0b54..61250c1 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -69,6 +69,7 @@ library , data-fix >= 0.3.2 && < 0.4 , utf8-string >= 1.0.2 && < 1.1 , extra >= 1.7.0 && < 2 + , semigroupoids hs-source-dirs: src default-language: GHC2021 diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index ae3751d..37edb40 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -48,6 +48,7 @@ data Severity = SevWarning data SrcSpan = SrcSpan !Int -- ^ Line !Int -- ^ Column + !Int -- ^ Absolute !Int -- ^ Length deriving Show diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index e4c78c3..a22a66f 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -164,10 +164,10 @@ alexGetByte inp = case inp ^. aiBytes of -- report the previous char & aiPrevChar .~ c -- update the position - & aiPos %~ \ (ln,col) -> + & aiPos %~ \ (ln,col,a) -> if c == '\n' - then (ln+1,1) - else (ln,col+1) + then (ln+1, 1, a+1) + else (ln, col+1, a+1) pure (b, inp') _ -> Just (head bs, inp') @@ -225,7 +225,7 @@ initAlexInput s = AlexInput { _aiPrevChar = '\0' , _aiSource = s , _aiBytes = [] - , _aiPos = (1,1) + , _aiPos = (1,1,0) } runP' :: P a -> Text -> (ParseState, [MsgEnvelope RlpParseError], Maybe a) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 6cc0a49..acb7fad 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -117,34 +117,34 @@ Type :: { Type } | Type1 { $1 } FunDecl :: { Decl' RlpcPs } -FunDecl : Var Params '=' Expr { FunD $1 $2 $4 Nothing } +FunDecl : Var Params '=' Expr { FunD undefined $2 $4 Nothing } Params :: { [Pat' RlpcPs] } Params : {- epsilon -} { [] } | Params Pat1 { $1 `snoc` $2 } Pat1 :: { Pat' RlpcPs } - : Var { VarP $1 } - | Lit { LitP $1 } + : Var { undefined } + | Lit { LitP <$> $1 } Expr :: { RlpExpr' RlpcPs } - : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } + : Expr1 varsym Expr { undefined } | Expr1 { $1 } Expr1 :: { RlpExpr' RlpcPs } - : '(' Expr ')' { wrapFix . Par . unwrapFix $ $2 } - | Lit { Fix . E $ LitEF $1 } - | Var { Fix . E $ VarEF $1 } + : '(' Expr ')' { fmap ParE' $2 } + | Lit { fmap LitE' $1 } + | Var { fmap VarE' $1 } -- TODO: happy prefers left-associativity. doing such would require adjusting -- the code in Rlp.Parse.Associate to expect left-associative input rather than -- right. InfixExpr :: { RlpExpr' RlpcPs } - : Expr1 varsym Expr { Fix $ B $2 (unFix $1) (unFix $3) } + : Expr1 varsym Expr { undefined } InfixOp :: { PsName } - : consym { $1 } - | varsym { $1 } + : consym { undefined } + | varsym { undefined } -- TODO: microlens-pro save me microlens-pro (rewrite this with prisms) Lit :: { Lit' RlpcPs } @@ -172,8 +172,8 @@ mkProgram ds = do pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError (Located (l,c,s) t) = addFatal $ - errorMsg (SrcSpan l c s) RlpParErrUnexpectedToken +parseError (Located (l,c,a,s) t) = addFatal $ + errorMsg (SrcSpan l c a s) RlpParErrUnexpectedToken mkInfixD :: Assoc -> Int -> PsName -> P (Decl' RlpcPs) mkInfixD a p n = do diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 794c28a..8fba710 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -34,6 +34,7 @@ import Data.Fix import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes +import Data.Functor.Apply import Data.HashMap.Strict qualified as H import Data.Void import Data.Word (Word8) @@ -50,6 +51,8 @@ type instance XRec RlpcPs f = Located (f RlpcPs) type instance IdP RlpcPs = PsName type instance XInfixD RlpcPs = () +type instance XVarE RlpcPs = () +type instance XLitE RlpcPs = () type PsName = Text @@ -66,8 +69,9 @@ data AlexInput = AlexInput deriving Show type Position = - ( Int -- line - , Int -- column + ( Int -- ^ line + , Int -- ^ column + , Int -- ^ Absolutely ) posLine :: Lens' Position Int @@ -76,6 +80,9 @@ posLine = _1 posColumn :: Lens' Position Int posColumn = _2 +posAbsolute :: Lens' Position Int +posAbsolute = _3 + data RlpToken -- literals = TokenLitInt Int @@ -154,12 +161,24 @@ data Layout = Explicit | Implicit Int deriving (Show, Eq) --- | Token wrapped with a span (line, column, length) -data Located a = Located !(Int, Int, Int) a +-- | Token wrapped with a span (line, column, absolute, length) +data Located a = Located !(Int, Int, Int, Int) a deriving (Show, Functor) -spanFromPos :: Position -> Int -> (Int, Int, Int) -spanFromPos (l,c) s = (l,c,s) +instance Apply Located where + liftF2 f (Located (la,ca,aa,sa) p) (Located (lb,cb,ab,sb) q) + = Located (l,c,a,s) (p `f` q) + where + l = min la lb + c = min ca cb + a = min aa ab + s = case aa `compare` ab of + EQ -> max sa sb + LT -> max sa (ab + sb) + GT -> max sb (aa + sa) + +spanFromPos :: Position -> Int -> (Int, Int, Int, Int) +spanFromPos (l,c,a) s = (l,c,a,s) {-# INLINE spanFromPos #-} @@ -186,8 +205,9 @@ addWoundHere l e = P $ \st -> let e' = MsgEnvelope { _msgSpan = let pos = psInput . aiPos in SrcSpan (st ^. pos . posLine) - (st ^. pos . posColumn) - l + (st ^. pos . posColumn) + (st ^. pos . posAbsolute) + l , _msgDiagnostic = e , _msgSeverity = SevError } @@ -199,6 +219,7 @@ addFatalHere l e = P $ \st -> { _msgSpan = let pos = psInput . aiPos in SrcSpan (st ^. pos . posLine) (st ^. pos . posColumn) + (st ^. pos . posAbsolute) l , _msgDiagnostic = e , _msgSeverity = SevError diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 76156c7..ced123b 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -15,7 +15,10 @@ module Rlp.Syntax , ConAlt(..) -- * Pattern synonyms for unused extensions + -- ** Decl , pattern InfixD' + -- ** RlpExpr + , pattern ParE', pattern VarE', pattern LitE' -- * Trees That Grow extensions , XRec, IdP @@ -103,6 +106,15 @@ type family XXRlpExpr p type family IdP p +pattern ParE' :: (XParE p ~ ()) => RlpExpr' p -> RlpExpr p +pattern ParE' e = ParE () e + +pattern LitE' :: (XLitE p ~ ()) => Lit p -> RlpExpr p +pattern LitE' e = LitE () e + +pattern VarE' :: (XVarE p ~ ()) => IdP p -> RlpExpr p +pattern VarE' e = VarE () e + type Where p = [Bind p] -- do we want guards? -- 2.52.0 From e00e4d34183d5aaf0675557152b209bdd30f5074 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 26 Jan 2024 17:53:05 -0700 Subject: [PATCH 114/192] it's also a comonad. lol. --- rlp.cabal | 1 + src/Rlp/Parse.y | 7 +++++-- src/Rlp/Parse/Types.hs | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 61250c1..6105295 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -70,6 +70,7 @@ library , utf8-string >= 1.0.2 && < 1.1 , extra >= 1.7.0 && < 2 , semigroupoids + , comonad hs-source-dirs: src default-language: GHC2021 diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index acb7fad..048617d 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -13,6 +13,9 @@ import Lens.Micro.Platform import Data.List.Extra import Data.Fix import Data.Functor.Const +import Data.Functor.Apply +import Data.Functor.Bind +import Control.Comonad import Data.Functor import Data.Text qualified as T import Data.Void @@ -125,14 +128,14 @@ Params : {- epsilon -} { [] } Pat1 :: { Pat' RlpcPs } : Var { undefined } - | Lit { LitP <$> $1 } + | Lit { LitP <<= $1 } Expr :: { RlpExpr' RlpcPs } : Expr1 varsym Expr { undefined } | Expr1 { $1 } Expr1 :: { RlpExpr' RlpcPs } - : '(' Expr ')' { fmap ParE' $2 } + : '(' Expr ')' { $1 .> $2 <. $3 } | Lit { fmap LitE' $1 } | Var { fmap VarE' $1 } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 8fba710..b8af882 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -27,6 +27,7 @@ import Core.Syntax (Name) import Control.Monad import Control.Monad.State.Strict import Control.Monad.Errorful +import Control.Comonad import Compiler.RlpcError import Data.Text (Text) import Data.Maybe @@ -35,6 +36,7 @@ import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes import Data.Functor.Apply +import Data.Functor.Bind import Data.HashMap.Strict qualified as H import Data.Void import Data.Word (Word8) @@ -177,6 +179,28 @@ instance Apply Located where LT -> max sa (ab + sb) GT -> max sb (aa + sa) +instance Bind Located where + Located sa a >>- k = Located (sa `spanAcross` sb) b + where + Located sb b = k a + +spanAcross :: (Int, Int, Int, Int) + -> (Int, Int, Int, Int) + -> (Int, Int, Int, Int) +spanAcross (la,ca,aa,sa) (lb,cb,ab,sb) = (l,c,a,s) + where + l = min la lb + c = min ca cb + a = min aa ab + s = case aa `compare` ab of + EQ -> max sa sb + LT -> max sa (ab + sb) + GT -> max sb (aa + sa) + +instance Comonad Located where + extract (Located _ a) = a + extend ck w@(Located p _) = Located p (ck w) + spanFromPos :: Position -> Int -> (Int, Int, Int, Int) spanFromPos (l,c,a) s = (l,c,a,s) -- 2.52.0 From c74c19264569e9776f198f77befe87a0b3da5da0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 26 Jan 2024 19:19:41 -0700 Subject: [PATCH 115/192] idk --- src/Rlp/Parse.y | 12 +++++++----- src/Rlp/Parse/Types.hs | 1 + src/Rlp/Syntax.hs | 12 +++++++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 048617d..9792878 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -17,6 +17,7 @@ import Data.Functor.Apply import Data.Functor.Bind import Control.Comonad import Data.Functor +import Data.Semigroup.Traversable import Data.Text qualified as T import Data.Void } @@ -104,23 +105,24 @@ DataCons :: { [ConAlt RlpcPs] } | DataCon { [$1] } DataCon :: { ConAlt RlpcPs } - : Con Type1s { ConAlt $1 $2 } + : Con Type1s { undefined } Type1s :: { [Type] } : {- epsilon -} { [] } | Type1s Type1 { $1 `snoc` $2 } Type1 :: { Type } - : '(' Type ')' { $2 } - | conname { TyCon $1 } - | varname { TyVar $1 } + : '(' Type ')' { undefined } + | conname { undefined } + | varname { undefined } Type :: { Type } : Type '->' Type { $1 :-> $3 } | Type1 { $1 } FunDecl :: { Decl' RlpcPs } -FunDecl : Var Params '=' Expr { FunD undefined $2 $4 Nothing } +FunDecl : Var Params '=' Expr { $4 =>> \e -> + FunD' (extract $1) $2 e Nothing } Params :: { [Pat' RlpcPs] } Params : {- epsilon -} { [] } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index b8af882..5a3e6d4 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -55,6 +55,7 @@ type instance IdP RlpcPs = PsName type instance XInfixD RlpcPs = () type instance XVarE RlpcPs = () type instance XLitE RlpcPs = () +type instance XFunD RlpcPs = () type PsName = Text diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index ced123b..69d5d0d 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -12,16 +12,17 @@ module Rlp.Syntax , Assoc(..) , Lit(..), Lit' , Type(..) + , pattern (:->) , ConAlt(..) -- * Pattern synonyms for unused extensions -- ** Decl - , pattern InfixD' + , pattern InfixD', pattern FunD' -- ** RlpExpr , pattern ParE', pattern VarE', pattern LitE' -- * Trees That Grow extensions - , XRec, IdP + , UnXRec(..), MapXRec(..), XRec, IdP -- ** RlpExpr , XLetE, XVarE, XConE, XLamE, XCaseE, XIfE, XAppE, XLitE, XXRlpExpr -- ** Decl @@ -47,7 +48,7 @@ data RlpModule p = RlpModule newtype RlpProgram p = RlpProgram [Decl p] -data Decl p = FunD (XFunD p) (IdP p) [Pat p] (RlpExpr p) (Maybe (Where p)) +data Decl p = FunD (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) | TySigD (XTySigD p) [IdP p] Type | DataD (XDataD p) (IdP p) [IdP p] [ConAlt p] | InfixD (XInfixD p) Assoc Int (IdP p) @@ -59,6 +60,11 @@ type family XDataD p type family XInfixD p type family XXDecl p +pattern FunD' :: (XFunD p ~ ()) + => IdP p -> [Pat' p] -> RlpExpr' p -> (Maybe (Where p)) + -> Decl p +pattern FunD' n as e wh = FunD () n as e wh + pattern InfixD' :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p pattern InfixD' a p n = InfixD () a p n -- 2.52.0 From 83dda869f8f2733b6743137202e9ba957715d6e9 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 28 Jan 2024 16:24:08 -0700 Subject: [PATCH 116/192] show --- rlp.cabal | 4 +-- src/Rlp/Parse.y | 11 +++++--- src/Rlp/Parse/Associate.hs | 2 +- src/Rlp/Parse/Types.hs | 39 ++++++++++++++++++++++++++-- src/Rlp/Syntax.hs | 52 ++++++++++++++++++++++++++++++++------ 5 files changed, 91 insertions(+), 17 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 6105295..dac6a5b 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -48,7 +48,7 @@ library build-tool-depends: happy:happy, alex:alex -- other-extensions: - build-depends: base ^>=4.18.0.0 + build-depends: base >=4.17 && <4.20 -- required for happy , array >= 0.5.5 && < 0.6 , containers >= 0.6.7 && < 0.7 @@ -85,7 +85,7 @@ executable rlpc main-is: Main.hs -- other-modules: -- other-extensions: - build-depends: base ^>=4.18.0.0 + build-depends: base >=4.17.0.0 && <4.20.0.0 , rlp , optparse-applicative >= 0.18.1 && < 0.19 , microlens >= 0.4.13 && < 0.5 diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 9792878..538b9ab 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -1,5 +1,5 @@ { -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase, ViewPatterns #-} module Rlp.Parse ( parseRlpProg ) @@ -86,7 +86,7 @@ Decl :: { Decl' RlpcPs } | InfixDecl { $1 } InfixDecl :: { Decl' RlpcPs } - : InfixWord litint InfixOp {% mkInfixD $1 $2 $3 } + : InfixWord litint InfixOp {% mkInfixD $1 (intOfToken $2) $3 } InfixWord :: { Assoc } : infixl { InfixL } @@ -94,11 +94,11 @@ InfixWord :: { Assoc } | infix { Infix } DataDecl :: { Decl' RlpcPs } - : data Con TyParams '=' DataCons { DataD $2 $3 $5 } + : data Con TyParams '=' DataCons { $1 =>> \_ -> DataD' (extract $2) $3 $5 } TyParams :: { [PsName] } : {- epsilon -} { [] } - | TyParams varname { $1 `snoc` $2 } + | TyParams varname { $1 `snoc` extract (mkPsName $2) } DataCons :: { [ConAlt RlpcPs] } : DataCons '|' DataCon { $1 `snoc` $3 } @@ -193,4 +193,7 @@ mkInfixD a p n = do pos <- use (psInput . aiPos) pure $ Located (spanFromPos pos 0) (InfixD' a p n) +intOfToken :: Located RlpToken -> Int +intOfToken (Located _ (TokenLitInt n)) = n + } diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs index 8dd89f2..99349d9 100644 --- a/src/Rlp/Parse/Associate.hs +++ b/src/Rlp/Parse/Associate.hs @@ -14,6 +14,6 @@ import Rlp.Parse.Types import Rlp.Syntax -------------------------------------------------------------------------------- -associate = undefined +associate x y = y {-# WARNING associate "temporarily undefined" #-} diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 5a3e6d4..c7cefb5 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -53,9 +53,22 @@ type instance XRec RlpcPs f = Located (f RlpcPs) type instance IdP RlpcPs = PsName type instance XInfixD RlpcPs = () -type instance XVarE RlpcPs = () -type instance XLitE RlpcPs = () type instance XFunD RlpcPs = () +type instance XDataD RlpcPs = () +type instance XTySigD RlpcPs = () +type instance XXDecl RlpcPs = () + +type instance XLetE RlpcPs = () +type instance XVarE RlpcPs = () +type instance XLamE RlpcPs = () +type instance XCaseE RlpcPs = () +type instance XIfE RlpcPs = () +type instance XAppE RlpcPs = () +type instance XLitE RlpcPs = () +type instance XParE RlpcPs = () +type instance XOAppE RlpcPs = () +type instance XXRlpExpr RlpcPs = () +type instance XLitE RlpcPs = () type PsName = Text @@ -198,6 +211,28 @@ spanAcross (la,ca,aa,sa) (lb,cb,ab,sb) = (l,c,a,s) LT -> max sa (ab + sb) GT -> max sb (aa + sa) +-- | A synonym for '(<<=)' with a different precedence for use with '(<~>)' in a +-- sort of, comonadic pseudo-applicative style. + +(<<~) :: (Comonad w) => (w a -> b) -> w a -> w b +(<<~) = (<<=) + +infixl 4 <<~ + +-- | Similar to '(<*>)', but with a cokleisli arrow. + +(<~>) :: (Comonad w, Bind w) => w (w a -> b) -> w a -> w b +mc <~> ma = mc >>- \f -> ma =>> f + +infixl 4 <~> + +-- f :: (w a -> w b -> c) +-- a :: w a +-- b :: w b + +-- result :: w c +-- result = f >~~ a <~> b + instance Comonad Located where extract (Located _ a) = a extend ck w@(Located p _) = Located p (ck w) diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 69d5d0d..3e8b9e5 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -3,6 +3,7 @@ , TemplateHaskell, TypeFamilies #-} {-# LANGUAGE OverloadedStrings, PatternSynonyms #-} {-# LANGUAGE TypeFamilies, TypeFamilyDependencies #-} +{-# LANGUAGE UndecidableInstances, ImpredicativeTypes #-} module Rlp.Syntax ( -- * AST @@ -17,14 +18,15 @@ module Rlp.Syntax -- * Pattern synonyms for unused extensions -- ** Decl - , pattern InfixD', pattern FunD' + , pattern InfixD', pattern FunD', pattern DataD' -- ** RlpExpr , pattern ParE', pattern VarE', pattern LitE' -- * Trees That Grow extensions , UnXRec(..), MapXRec(..), XRec, IdP -- ** RlpExpr - , XLetE, XVarE, XConE, XLamE, XCaseE, XIfE, XAppE, XLitE, XXRlpExpr + , XLetE, XVarE, XConE, XLamE, XCaseE, XIfE, XAppE, XLitE, XParE, XOAppE + , XXRlpExpr -- ** Decl , XFunD, XTySigD, XDataD, XInfixD, XXDecl ) @@ -37,7 +39,7 @@ import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes import Lens.Micro import Lens.Micro.TH -import Core.Syntax hiding (Lit) +import Core.Syntax hiding (Lit, Binding) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- @@ -46,7 +48,15 @@ data RlpModule p = RlpModule , _rlpmodProgram :: RlpProgram p } -newtype RlpProgram p = RlpProgram [Decl p] +-- | dear god. +type PhaseShow p = + ( Show (XRec p Pat), Show (XRec p RlpExpr) + , Show (XRec p Lit), Show (IdP p) + ) + +newtype RlpProgram p = RlpProgram [Decl' p] + +deriving instance (PhaseShow p, Show (XRec p Decl)) => Show (RlpProgram p) data Decl p = FunD (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) | TySigD (XTySigD p) [IdP p] Type @@ -54,6 +64,12 @@ data Decl p = FunD (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) | InfixD (XInfixD p) Assoc Int (IdP p) | XDecl !(XXDecl p) +deriving instance ( Show (XFunD p), Show (XTySigD p) + , Show (XDataD p), Show (XInfixD p) + , Show (XXDecl p), Show (IdP p) + , PhaseShow p + ) => Show (Decl p) + type family XFunD p type family XTySigD p type family XDataD p @@ -68,6 +84,9 @@ pattern FunD' n as e wh = FunD () n as e wh pattern InfixD' :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p pattern InfixD' a p n = InfixD () a p n +pattern DataD' :: (XDataD p ~ ()) => IdP p -> [IdP p] -> [ConAlt p] -> Decl p +pattern DataD' n as ds = DataD () n as ds + type Decl' p = XRec p Decl data Assoc = InfixL @@ -77,7 +96,9 @@ data Assoc = InfixL data ConAlt p = ConAlt (IdP p) [Type] -data RlpExpr p = LetE (XLetE p) [Bind p] (RlpExpr' p) +deriving instance (Show (IdP p)) => Show (ConAlt p) + +data RlpExpr p = LetE (XLetE p) [Binding p] (RlpExpr' p) | VarE (XVarE p) (IdP p) | LamE (XLamE p) [Pat p] (RlpExpr' p) | CaseE (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] @@ -88,6 +109,12 @@ data RlpExpr p = LetE (XLetE p) [Bind p] (RlpExpr' p) | OAppE (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) | XRlpExpr !(XXRlpExpr p) +deriving instance + ( Show (XLetE p), Show (XVarE p), Show (XLamE p), Show (XCaseE p) + , Show (XIfE p), Show (XAppE p), Show (XLitE p), Show (XParE p) + , Show (XOAppE p), Show (XXRlpExpr p), PhaseShow p) + => Show (RlpExpr p) + type RlpExpr' p = XRec p RlpExpr class UnXRec p where @@ -121,24 +148,33 @@ pattern LitE' e = LitE () e pattern VarE' :: (XVarE p ~ ()) => IdP p -> RlpExpr p pattern VarE' e = VarE () e -type Where p = [Bind p] +type Where p = [Binding p] -- do we want guards? data Alt p = AltA (Pat' p) (RlpExpr' p) -data Bind p = PatB (Pat' p) (RlpExpr' p) - | FunB (IdP p) [Pat' p] (RlpExpr' p) +deriving instance (PhaseShow p) => Show (Alt p) + +data Binding p = PatB (Pat' p) (RlpExpr' p) + | FunB (IdP p) [Pat' p] (RlpExpr' p) + +deriving instance (Show (XRec p Pat), Show (XRec p RlpExpr), Show (IdP p) + ) => Show (Binding p) data Pat p = VarP (IdP p) | LitP (Lit' p) | ConP (IdP p) [Pat' p] +deriving instance (PhaseShow p) => Show (Pat p) + type Pat' p = XRec p Pat data Lit p = IntL Int | CharL Char | ListL [RlpExpr' p] +deriving instance (PhaseShow p) => Show (Lit p) + type Lit' p = XRec p Lit -- instance HasLHS Alt Alt Pat Pat where -- 2.52.0 From fdaa2a1afdd1a98d860a4235d49d4b4a6f73019e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 28 Jan 2024 17:02:32 -0700 Subject: [PATCH 117/192] abandon ship --- src/Rlp/Parse.y | 12 ++++++------ src/Rlp/Parse/Types.hs | 2 ++ src/Rlp/Syntax.hs | 34 +++++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 538b9ab..6eb6a3e 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -107,17 +107,17 @@ DataCons :: { [ConAlt RlpcPs] } DataCon :: { ConAlt RlpcPs } : Con Type1s { undefined } -Type1s :: { [Type] } +Type1s :: { [RlpType RlpcPs] } : {- epsilon -} { [] } | Type1s Type1 { $1 `snoc` $2 } -Type1 :: { Type } - : '(' Type ')' { undefined } +Type1 :: { RlpType' RlpcPs } + : '(' Type ')' { $2 } | conname { undefined } | varname { undefined } -Type :: { Type } - : Type '->' Type { $1 :-> $3 } +Type :: { RlpType' RlpcPs } + : Type '->' Type { undefined } | Type1 { $1 } FunDecl :: { Decl' RlpcPs } @@ -147,7 +147,7 @@ Expr1 :: { RlpExpr' RlpcPs } InfixExpr :: { RlpExpr' RlpcPs } : Expr1 varsym Expr { undefined } -InfixOp :: { PsName } +InfixOp :: { Located PsName } : consym { undefined } | varsym { undefined } diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index c7cefb5..37c3aee 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -17,6 +17,8 @@ module Rlp.Parse.Types -- ** Lenses , aiPrevChar, aiSource, aiBytes, aiPos, posLine, posColumn + , (<<~), (<~>) + -- * Error handling , MsgEnvelope(..), RlpcError(..), RlpParseError(..) , addFatal, addWound, addFatalHere, addWoundHere diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 3e8b9e5..66d2d3b 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -12,8 +12,7 @@ module Rlp.Syntax , Pat(..), Pat' , Assoc(..) , Lit(..), Lit' - , Type(..) - , pattern (:->) + , RlpType(..), RlpType' , ConAlt(..) -- * Pattern synonyms for unused extensions @@ -21,6 +20,8 @@ module Rlp.Syntax , pattern InfixD', pattern FunD', pattern DataD' -- ** RlpExpr , pattern ParE', pattern VarE', pattern LitE' + -- ** RlpType + , pattern FunT', pattern AppT' -- * Trees That Grow extensions , UnXRec(..), MapXRec(..), XRec, IdP @@ -52,14 +53,37 @@ data RlpModule p = RlpModule type PhaseShow p = ( Show (XRec p Pat), Show (XRec p RlpExpr) , Show (XRec p Lit), Show (IdP p) + , Show (XRec p RlpType) ) newtype RlpProgram p = RlpProgram [Decl' p] deriving instance (PhaseShow p, Show (XRec p Decl)) => Show (RlpProgram p) +data RlpType p = FunT (XFunT p) + | AppT (XAppT p) (RlpType' p) (RlpType' p) + | VarT (XVarT p) (IdP p) + | ConT (XConT p) (IdP p) + +type RlpType' p = XRec p RlpType + +deriving instance (PhaseShow p, Show (XFunT p), Show (XAppT p), Show (XVarT p) + ,Show (XConT p)) + => Show (RlpType p) + +type family XFunT p +type family XAppT p +type family XVarT p +type family XConT p + +pattern FunT' :: (XFunT p ~ ()) => RlpType p +pattern FunT' = FunT () + +pattern AppT' :: (XAppT p ~ ()) => RlpType' p -> RlpType' p -> RlpType p +pattern AppT' s t = AppT () s t + data Decl p = FunD (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) - | TySigD (XTySigD p) [IdP p] Type + | TySigD (XTySigD p) [IdP p] (RlpType' p) | DataD (XDataD p) (IdP p) [IdP p] [ConAlt p] | InfixD (XInfixD p) Assoc Int (IdP p) | XDecl !(XXDecl p) @@ -94,9 +118,9 @@ data Assoc = InfixL | Infix deriving (Show) -data ConAlt p = ConAlt (IdP p) [Type] +data ConAlt p = ConAlt (IdP p) [RlpType' p] -deriving instance (Show (IdP p)) => Show (ConAlt p) +deriving instance (Show (IdP p), Show (XRec p RlpType)) => Show (ConAlt p) data RlpExpr p = LetE (XLetE p) [Binding p] (RlpExpr' p) | VarE (XVarE p) (IdP p) -- 2.52.0 From 7d42f9b64109737b9ebacc867ed845b350ff41f4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 28 Jan 2024 17:54:39 -0700 Subject: [PATCH 118/192] at long last more no more undefineds --- src/Rlp/Lex.x | 6 +- src/Rlp/Parse.y | 65 ++++++++++++---------- src/Rlp/Parse/Types.hs | 18 ------ src/Rlp/Syntax.hs | 121 +++++++++-------------------------------- 4 files changed, 65 insertions(+), 145 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index a22a66f..9229b8b 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -57,7 +57,7 @@ $asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:] |infixr|infixl|infix @reservedop = - "=" | \\ | "->" | "|" + "=" | \\ | "->" | "|" | "::" rlp :- @@ -187,8 +187,8 @@ pushLexState :: Int -> P () pushLexState n = psLexState %= (n:) readInt :: Text -> Int -readInt = T.foldr f 0 where - f c n = digitToInt c + 10*n +readInt = T.foldl f 0 where + f n c = 10*n + digitToInt c constToken :: RlpToken -> LexerAction (Located RlpToken) constToken t inp l = do diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 6eb6a3e..67e1b5d 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -38,6 +38,7 @@ import Data.Void litint { Located _ (TokenLitInt _) } '=' { Located _ TokenEquals } '|' { Located _ TokenPipe } + '::' { Located _ TokenHasType } ';' { Located _ TokenSemicolon } '(' { Located _ TokenLParen } ')' { Located _ TokenRParen } @@ -82,74 +83,75 @@ VS : ';' { $1 } Decl :: { Decl' RlpcPs } : FunDecl { $1 } + | TySigDecl { $1 } | DataDecl { $1 } | InfixDecl { $1 } -InfixDecl :: { Decl' RlpcPs } - : InfixWord litint InfixOp {% mkInfixD $1 (intOfToken $2) $3 } +TySigDecl :: { Decl' RlpcPs } + : Var '::' Type { (\e -> TySigD [extract e]) <<~ $1 <~> $3 } -InfixWord :: { Assoc } - : infixl { InfixL } - | infixr { InfixR } - | infix { Infix } +InfixDecl :: { Decl' RlpcPs } + : InfixWord litint InfixOp { $1 =>> \w -> + InfixD (extract $1) (extractInt $ extract $2) + (extract $3) } + +InfixWord :: { Located Assoc } + : infixl { $1 \$> InfixL } + | infixr { $1 \$> InfixR } + | infix { $1 \$> Infix } DataDecl :: { Decl' RlpcPs } - : data Con TyParams '=' DataCons { $1 =>> \_ -> DataD' (extract $2) $3 $5 } + : data Con TyParams '=' DataCons { $1 \$> DataD (extract $2) $3 $5 } TyParams :: { [PsName] } : {- epsilon -} { [] } - | TyParams varname { $1 `snoc` extract (mkPsName $2) } + | TyParams varname { $1 `snoc` (extractName . extract $ $2) } DataCons :: { [ConAlt RlpcPs] } : DataCons '|' DataCon { $1 `snoc` $3 } | DataCon { [$1] } DataCon :: { ConAlt RlpcPs } - : Con Type1s { undefined } + : Con Type1s { ConAlt (extract $1) $2 } -Type1s :: { [RlpType RlpcPs] } +Type1s :: { [RlpType' RlpcPs] } : {- epsilon -} { [] } | Type1s Type1 { $1 `snoc` $2 } Type1 :: { RlpType' RlpcPs } : '(' Type ')' { $2 } - | conname { undefined } - | varname { undefined } + | conname { fmap ConT (mkPsName $1) } + | varname { fmap VarT (mkPsName $1) } Type :: { RlpType' RlpcPs } - : Type '->' Type { undefined } + : Type '->' Type { FunT <<~ $1 <~> $3 } | Type1 { $1 } FunDecl :: { Decl' RlpcPs } FunDecl : Var Params '=' Expr { $4 =>> \e -> - FunD' (extract $1) $2 e Nothing } + FunD (extract $1) $2 e Nothing } Params :: { [Pat' RlpcPs] } Params : {- epsilon -} { [] } | Params Pat1 { $1 `snoc` $2 } Pat1 :: { Pat' RlpcPs } - : Var { undefined } + : Var { fmap VarP $1 } | Lit { LitP <<= $1 } Expr :: { RlpExpr' RlpcPs } - : Expr1 varsym Expr { undefined } + : Expr1 InfixOp Expr { $2 =>> \o -> + OAppE (extract o) $1 $3 } | Expr1 { $1 } Expr1 :: { RlpExpr' RlpcPs } : '(' Expr ')' { $1 .> $2 <. $3 } - | Lit { fmap LitE' $1 } - | Var { fmap VarE' $1 } - --- TODO: happy prefers left-associativity. doing such would require adjusting --- the code in Rlp.Parse.Associate to expect left-associative input rather than --- right. -InfixExpr :: { RlpExpr' RlpcPs } - : Expr1 varsym Expr { undefined } + | Lit { fmap LitE $1 } + | Var { fmap VarE $1 } InfixOp :: { Located PsName } - : consym { undefined } - | varsym { undefined } + : consym { mkPsName $1 } + | varsym { mkPsName $1 } -- TODO: microlens-pro save me microlens-pro (rewrite this with prisms) Lit :: { Lit' RlpcPs } @@ -164,13 +166,20 @@ Con :: { Located PsName } { mkPsName :: Located RlpToken -> Located PsName -mkPsName = fmap $ \case +mkPsName = fmap extractName + +extractName :: RlpToken -> PsName +extractName = \case TokenVarName n -> n TokenConName n -> n TokenConSym n -> n TokenVarSym n -> n _ -> error "mkPsName: not an identifier" +extractInt :: RlpToken -> Int +extractInt (TokenLitInt n) = n +extractInt _ = error "extractInt: ugh" + mkProgram :: [Decl' RlpcPs] -> P (RlpProgram RlpcPs) mkProgram ds = do pt <- use psOpTable @@ -191,7 +200,7 @@ mkInfixD a p n = do Nothing -> pure (Just (a,p)) ) pos <- use (psInput . aiPos) - pure $ Located (spanFromPos pos 0) (InfixD' a p n) + pure $ Located (spanFromPos pos 0) (InfixD a p n) intOfToken :: Located RlpToken -> Int intOfToken (Located _ (TokenLitInt n)) = n diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 37c3aee..9c91493 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -54,24 +54,6 @@ data RlpcPs type instance XRec RlpcPs f = Located (f RlpcPs) type instance IdP RlpcPs = PsName -type instance XInfixD RlpcPs = () -type instance XFunD RlpcPs = () -type instance XDataD RlpcPs = () -type instance XTySigD RlpcPs = () -type instance XXDecl RlpcPs = () - -type instance XLetE RlpcPs = () -type instance XVarE RlpcPs = () -type instance XLamE RlpcPs = () -type instance XCaseE RlpcPs = () -type instance XIfE RlpcPs = () -type instance XAppE RlpcPs = () -type instance XLitE RlpcPs = () -type instance XParE RlpcPs = () -type instance XOAppE RlpcPs = () -type instance XXRlpExpr RlpcPs = () -type instance XLitE RlpcPs = () - type PsName = Text -------------------------------------------------------------------------------- diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 66d2d3b..25b20e8 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -15,21 +15,8 @@ module Rlp.Syntax , RlpType(..), RlpType' , ConAlt(..) - -- * Pattern synonyms for unused extensions - -- ** Decl - , pattern InfixD', pattern FunD', pattern DataD' - -- ** RlpExpr - , pattern ParE', pattern VarE', pattern LitE' - -- ** RlpType - , pattern FunT', pattern AppT' - -- * Trees That Grow extensions , UnXRec(..), MapXRec(..), XRec, IdP - -- ** RlpExpr - , XLetE, XVarE, XConE, XLamE, XCaseE, XIfE, XAppE, XLitE, XParE, XOAppE - , XXRlpExpr - -- ** Decl - , XFunD, XTySigD, XDataD, XInfixD, XXDecl ) where ---------------------------------------------------------------------------------- @@ -38,9 +25,10 @@ import Data.Text qualified as T import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes +import Data.Kind (Type) import Lens.Micro import Lens.Micro.TH -import Core.Syntax hiding (Lit, Binding) +import Core.Syntax hiding (Lit, Type, Binding) import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- @@ -60,56 +48,23 @@ newtype RlpProgram p = RlpProgram [Decl' p] deriving instance (PhaseShow p, Show (XRec p Decl)) => Show (RlpProgram p) -data RlpType p = FunT (XFunT p) - | AppT (XAppT p) (RlpType' p) (RlpType' p) - | VarT (XVarT p) (IdP p) - | ConT (XConT p) (IdP p) +data RlpType p = FunConT + | FunT (RlpType' p) (RlpType' p) + | AppT (RlpType' p) (RlpType' p) + | VarT (IdP p) + | ConT (IdP p) type RlpType' p = XRec p RlpType -deriving instance (PhaseShow p, Show (XFunT p), Show (XAppT p), Show (XVarT p) - ,Show (XConT p)) +deriving instance (PhaseShow p) => Show (RlpType p) -type family XFunT p -type family XAppT p -type family XVarT p -type family XConT p +data Decl p = FunD (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) + | TySigD [IdP p] (RlpType' p) + | DataD (IdP p) [IdP p] [ConAlt p] + | InfixD Assoc Int (IdP p) -pattern FunT' :: (XFunT p ~ ()) => RlpType p -pattern FunT' = FunT () - -pattern AppT' :: (XAppT p ~ ()) => RlpType' p -> RlpType' p -> RlpType p -pattern AppT' s t = AppT () s t - -data Decl p = FunD (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) - | TySigD (XTySigD p) [IdP p] (RlpType' p) - | DataD (XDataD p) (IdP p) [IdP p] [ConAlt p] - | InfixD (XInfixD p) Assoc Int (IdP p) - | XDecl !(XXDecl p) - -deriving instance ( Show (XFunD p), Show (XTySigD p) - , Show (XDataD p), Show (XInfixD p) - , Show (XXDecl p), Show (IdP p) - , PhaseShow p - ) => Show (Decl p) - -type family XFunD p -type family XTySigD p -type family XDataD p -type family XInfixD p -type family XXDecl p - -pattern FunD' :: (XFunD p ~ ()) - => IdP p -> [Pat' p] -> RlpExpr' p -> (Maybe (Where p)) - -> Decl p -pattern FunD' n as e wh = FunD () n as e wh - -pattern InfixD' :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p -pattern InfixD' a p n = InfixD () a p n - -pattern DataD' :: (XDataD p ~ ()) => IdP p -> [IdP p] -> [ConAlt p] -> Decl p -pattern DataD' n as ds = DataD () n as ds +deriving instance (Show (IdP p), PhaseShow p) => Show (Decl p) type Decl' p = XRec p Decl @@ -122,22 +77,17 @@ data ConAlt p = ConAlt (IdP p) [RlpType' p] deriving instance (Show (IdP p), Show (XRec p RlpType)) => Show (ConAlt p) -data RlpExpr p = LetE (XLetE p) [Binding p] (RlpExpr' p) - | VarE (XVarE p) (IdP p) - | LamE (XLamE p) [Pat p] (RlpExpr' p) - | CaseE (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] - | IfE (XIfE p) (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) - | AppE (XAppE p) (RlpExpr' p) (RlpExpr' p) - | LitE (XLitE p) (Lit p) - | ParE (XParE p) (RlpExpr' p) - | OAppE (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) - | XRlpExpr !(XXRlpExpr p) +data RlpExpr p = LetE [Binding p] (RlpExpr' p) + | VarE (IdP p) + | LamE [Pat p] (RlpExpr' p) + | CaseE (RlpExpr' p) [(Alt p, Where p)] + | IfE (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) + | AppE (RlpExpr' p) (RlpExpr' p) + | LitE (Lit p) + | ParE (RlpExpr' p) + | OAppE (IdP p) (RlpExpr' p) (RlpExpr' p) -deriving instance - ( Show (XLetE p), Show (XVarE p), Show (XLamE p), Show (XCaseE p) - , Show (XIfE p), Show (XAppE p), Show (XLitE p), Show (XParE p) - , Show (XOAppE p), Show (XXRlpExpr p), PhaseShow p) - => Show (RlpExpr p) +deriving instance (PhaseShow p) => Show (RlpExpr p) type RlpExpr' p = XRec p RlpExpr @@ -145,33 +95,12 @@ class UnXRec p where unXRec :: XRec p f -> f p class MapXRec p where - mapXRec :: (f p -> f p) -> XRec p f -> XRec p f + mapXRec :: (f p -> f' p') -> XRec p f -> XRec p' f' -type family XRec p (f :: * -> *) = (r :: *) | r -> p f - -type family XLetE p -type family XVarE p -type family XConE p -type family XLamE p -type family XCaseE p -type family XIfE p -type family XAppE p -type family XLitE p -type family XParE p -type family XOAppE p -type family XXRlpExpr p +type family XRec p (f :: Type -> Type) = (r :: Type) | r -> p f type family IdP p -pattern ParE' :: (XParE p ~ ()) => RlpExpr' p -> RlpExpr p -pattern ParE' e = ParE () e - -pattern LitE' :: (XLitE p ~ ()) => Lit p -> RlpExpr p -pattern LitE' e = LitE () e - -pattern VarE' :: (XVarE p ~ ()) => IdP p -> RlpExpr p -pattern VarE' e = VarE () e - type Where p = [Binding p] -- do we want guards? -- 2.52.0 From ab979cb9346fd382de32e5757607b5fafa92e78c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 28 Jan 2024 19:33:05 -0700 Subject: [PATCH 119/192] i should've made a lisp man this sucks --- src/Rlp/Lex.x | 27 +++++++++++++++++++++++++++ src/Rlp/Parse.y | 23 +++++++++++++++++++++++ src/Rlp/Syntax.hs | 8 ++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 9229b8b..72f2cf0 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -10,6 +10,7 @@ module Rlp.Lex , lexStream , lexDebug , lexCont + , popLexState ) where import Codec.Binary.UTF8.String (encodeChar) @@ -73,6 +74,17 @@ $white_no_nl+ ; -- for the definition of `doBol` <0> \n { beginPush bol } + +{ + +} + +-- layout keywords +<0> +{ + "let" { constToken TokenLet `thenBeginPush` layout_let } +} + -- scan various identifiers and reserved words. order is important here! <0> { @@ -110,6 +122,14 @@ $white_no_nl+ ; () { doBol } } + +{ + \n { beginPush bol } + "{" { explicitLBrace } + "in" { constToken TokenIn `thenDo` (popLexState *> popLayout) } + () { doLayout } +} + { \n ; @@ -144,6 +164,12 @@ thenBegin act c inp l = do psLexState . _head .= c pure a +thenBeginPush :: LexerAction a -> Int -> LexerAction a +thenBeginPush act c inp l = do + a <- act inp l + pushLexState c + pure a + andBegin :: LexerAction a -> Int -> LexerAction a andBegin act c inp l = do psLexState . _head .= c @@ -342,6 +368,7 @@ explicitRBrace inp l = do doLayout :: LexerAction (Located RlpToken) doLayout _ _ = do i <- indentLevel + traceM $ "doLayout: i: " <> show i pushLayout (Implicit i) popLexState insertLBrace diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 67e1b5d..ae467e8 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -2,6 +2,7 @@ {-# LANGUAGE LambdaCase, ViewPatterns #-} module Rlp.Parse ( parseRlpProg + , parseRlpExpr ) where import Compiler.RlpcError @@ -23,6 +24,7 @@ import Data.Void } %name parseRlpProg StandaloneProgram +%name parseRlpExpr StandaloneExpr %monad { P } %lexer { lexCont } { Located _ TokenEOF } @@ -51,8 +53,12 @@ import Data.Void infixl { Located _ TokenInfixL } infixr { Located _ TokenInfixR } infix { Located _ TokenInfix } + let { Located _ TokenLet } + in { Located _ TokenIn } +%nonassoc '=' %right '->' +%right in %% @@ -60,6 +66,9 @@ StandaloneProgram :: { RlpProgram RlpcPs } StandaloneProgram : '{' Decls '}' {% mkProgram $2 } | VL DeclsV VR {% mkProgram $2 } +StandaloneExpr :: { RlpExpr RlpcPs } + : VL Expr VR { extract $2 } + VL :: { () } VL : vlbrace { () } @@ -143,6 +152,20 @@ Expr :: { RlpExpr' RlpcPs } : Expr1 InfixOp Expr { $2 =>> \o -> OAppE (extract o) $1 $3 } | Expr1 { $1 } + | LetExpr { $1 } + +LetExpr :: { RlpExpr' RlpcPs } + : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } + +layout1(p) : '{' layout_list1(';',p) '}' { $2 } + | VL layout_list1(VS,p) VR { $2 } + +layout_list1(sep,p) : p sep { [$1] } + | p { [$1] } + | layout_list1(sep,p) sep p { $1 `snoc` $3 } + +Binding :: { Binding' RlpcPs } + : Pat1 '=' Expr { PatB <<~ $1 <~> $3 } Expr1 :: { RlpExpr' RlpcPs } : '(' Expr ')' { $1 .> $2 <. $3 } diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 25b20e8..b2eee70 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -14,6 +14,7 @@ module Rlp.Syntax , Lit(..), Lit' , RlpType(..), RlpType' , ConAlt(..) + , Binding(..), Binding' -- * Trees That Grow extensions , UnXRec(..), MapXRec(..), XRec, IdP @@ -28,7 +29,7 @@ import Data.Functor.Classes import Data.Kind (Type) import Lens.Micro import Lens.Micro.TH -import Core.Syntax hiding (Lit, Type, Binding) +import Core.Syntax hiding (Lit, Type, Binding, Binding') import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- @@ -42,6 +43,7 @@ type PhaseShow p = ( Show (XRec p Pat), Show (XRec p RlpExpr) , Show (XRec p Lit), Show (IdP p) , Show (XRec p RlpType) + , Show (XRec p Binding) ) newtype RlpProgram p = RlpProgram [Decl' p] @@ -77,7 +79,7 @@ data ConAlt p = ConAlt (IdP p) [RlpType' p] deriving instance (Show (IdP p), Show (XRec p RlpType)) => Show (ConAlt p) -data RlpExpr p = LetE [Binding p] (RlpExpr' p) +data RlpExpr p = LetE [Binding' p] (RlpExpr' p) | VarE (IdP p) | LamE [Pat p] (RlpExpr' p) | CaseE (RlpExpr' p) [(Alt p, Where p)] @@ -111,6 +113,8 @@ deriving instance (PhaseShow p) => Show (Alt p) data Binding p = PatB (Pat' p) (RlpExpr' p) | FunB (IdP p) [Pat' p] (RlpExpr' p) +type Binding' p = XRec p Binding + deriving instance (Show (XRec p Pat), Show (XRec p RlpExpr), Show (IdP p) ) => Show (Binding p) -- 2.52.0 From fbea3d6f3de61c8e256df9883e5cc5473e403b39 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 28 Jan 2024 19:41:36 -0700 Subject: [PATCH 120/192] let layout --- Makefile_happysrcs | 2 +- src/Rlp/Parse.y | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile_happysrcs b/Makefile_happysrcs index 1d32855..f4041ee 100644 --- a/Makefile_happysrcs +++ b/Makefile_happysrcs @@ -1,5 +1,5 @@ HAPPY = happy -HAPPY_OPTS = -a -g -c +HAPPY_OPTS = -a -g -c -i/tmp/t.info ALEX = alex ALEX_OPTS = -g diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index ae467e8..b3999f8 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -160,8 +160,7 @@ LetExpr :: { RlpExpr' RlpcPs } layout1(p) : '{' layout_list1(';',p) '}' { $2 } | VL layout_list1(VS,p) VR { $2 } -layout_list1(sep,p) : p sep { [$1] } - | p { [$1] } +layout_list1(sep,p) : p { [$1] } | layout_list1(sep,p) sep p { $1 `snoc` $3 } Binding :: { Binding' RlpcPs } -- 2.52.0 From 6a41e123eace3659b0131b3f6fca9d222e34a882 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 13:01:01 -0700 Subject: [PATCH 121/192] ttg boilerplate --- rlp.cabal | 1 + src/Rlp/Parse/Types.hs | 16 ++++++ src/Rlp/Syntax.hs | 113 ++++++++++++++++++++++++++++++++++------- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index dac6a5b..b44fe23 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -71,6 +71,7 @@ library , extra >= 1.7.0 && < 2 , semigroupoids , comonad + , lens hs-source-dirs: src default-language: GHC2021 diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 9c91493..95d01e2 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -54,6 +54,22 @@ data RlpcPs type instance XRec RlpcPs f = Located (f RlpcPs) type instance IdP RlpcPs = PsName +type instance XFunD RlpcPs = () +type instance XDataD RlpcPs = () +type instance XInfixD RlpcPs = () +type instance XTySigD RlpcPs = () +type instance XXDeclD RlpcPs = () + +type instance XLetE RlpcPs = () +type instance XVarE RlpcPs = () +type instance XLamE RlpcPs = () +type instance XCaseE RlpcPs = () +type instance XIfE RlpcPs = () +type instance XAppE RlpcPs = () +type instance XLitE RlpcPs = () +type instance XParE RlpcPs = () +type instance XOAppE RlpcPs = () + type PsName = Text -------------------------------------------------------------------------------- diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index b2eee70..ecfb786 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -16,8 +16,20 @@ module Rlp.Syntax , ConAlt(..) , Binding(..), Binding' - -- * Trees That Grow extensions - , UnXRec(..), MapXRec(..), XRec, IdP + -- * Trees That Grow boilerplate + -- ** Extension points + , IdP, XRec, UnXRec(..), MapXRec(..) + -- *** Decl + , XFunD, XTySigD, XInfixD, XDataD, XXDeclD + -- *** RlpExpr + , XLetE, XVarE, XLamE, XCaseE, XIfE, XAppE, XLitE + , XParE, XOAppE + -- ** Pattern synonyms + -- *** Decl + , pattern FunD, pattern TySigD, pattern InfixD, pattern DataD + -- *** RlpExpr + , pattern LetE, pattern VarE, pattern LamE, pattern CaseE, pattern IfE + , pattern AppE, pattern LitE, pattern ParE, pattern OAppE ) where ---------------------------------------------------------------------------------- @@ -61,12 +73,39 @@ type RlpType' p = XRec p RlpType deriving instance (PhaseShow p) => Show (RlpType p) -data Decl p = FunD (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) - | TySigD [IdP p] (RlpType' p) - | DataD (IdP p) [IdP p] [ConAlt p] - | InfixD Assoc Int (IdP p) +data Decl p = FunD' (XFunD p) (IdP p) [Pat' p] (RlpExpr' p) (Maybe (Where p)) + | TySigD' (XTySigD p) [IdP p] (RlpType' p) + | DataD' (XDataD p) (IdP p) [IdP p] [ConAlt p] + | InfixD' (XInfixD p) Assoc Int (IdP p) + | XDeclD' !(XXDeclD p) -deriving instance (Show (IdP p), PhaseShow p) => Show (Decl p) +deriving instance + ( Show (XFunD p), Show (XTySigD p) + , Show (XDataD p), Show (XInfixD p) + , Show (XXDeclD p) + , PhaseShow p + ) + => Show (Decl p) + +type family XFunD p +type family XTySigD p +type family XDataD p +type family XInfixD p +type family XXDeclD p + +pattern FunD :: (XFunD p ~ ()) + => (IdP p) -> [Pat' p] -> (RlpExpr' p) -> (Maybe (Where p)) + -> Decl p +pattern TySigD :: (XTySigD p ~ ()) => [IdP p] -> (RlpType' p) -> Decl p +pattern DataD :: (XDataD p ~ ()) => (IdP p) -> [IdP p] -> [ConAlt p] -> Decl p +pattern InfixD :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p +pattern XDeclD :: (XXDeclD p ~ ()) => Decl p + +pattern FunD n as e wh = FunD' () n as e wh +pattern TySigD ns t = TySigD' () ns t +pattern DataD n as cs = DataD' () n as cs +pattern InfixD a p n = InfixD' () a p n +pattern XDeclD = XDeclD' () type Decl' p = XRec p Decl @@ -79,17 +118,57 @@ data ConAlt p = ConAlt (IdP p) [RlpType' p] deriving instance (Show (IdP p), Show (XRec p RlpType)) => Show (ConAlt p) -data RlpExpr p = LetE [Binding' p] (RlpExpr' p) - | VarE (IdP p) - | LamE [Pat p] (RlpExpr' p) - | CaseE (RlpExpr' p) [(Alt p, Where p)] - | IfE (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) - | AppE (RlpExpr' p) (RlpExpr' p) - | LitE (Lit p) - | ParE (RlpExpr' p) - | OAppE (IdP p) (RlpExpr' p) (RlpExpr' p) +data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) + | VarE' (XVarE p) (IdP p) + | LamE' (XLamE p) [Pat p] (RlpExpr' p) + | CaseE' (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] + | IfE' (XIfE p) (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) + | AppE' (XAppE p) (RlpExpr' p) (RlpExpr' p) + | LitE' (XLitE p) (Lit p) + | ParE' (XParE p) (RlpExpr' p) + | OAppE' (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) + | XRlpExprE' (XXRlpExprE p) -deriving instance (PhaseShow p) => Show (RlpExpr p) +type family XLetE p +type family XVarE p +type family XLamE p +type family XCaseE p +type family XIfE p +type family XAppE p +type family XLitE p +type family XParE p +type family XOAppE p +type family XXRlpExprE p + +pattern LetE :: (XLetE p ~ ()) => [Binding' p] -> RlpExpr' p -> RlpExpr p +pattern VarE :: (XVarE p ~ ()) => IdP p -> RlpExpr p +pattern LamE :: (XLamE p ~ ()) => [Pat p] -> RlpExpr' p -> RlpExpr p +pattern CaseE :: (XCaseE p ~ ()) => RlpExpr' p -> [(Alt p, Where p)] -> RlpExpr p +pattern IfE :: (XIfE p ~ ()) => RlpExpr' p -> RlpExpr' p -> RlpExpr' p -> RlpExpr p +pattern AppE :: (XAppE p ~ ()) => RlpExpr' p -> RlpExpr' p -> RlpExpr p +pattern LitE :: (XLitE p ~ ()) => Lit p -> RlpExpr p +pattern ParE :: (XParE p ~ ()) => RlpExpr' p -> RlpExpr p +pattern OAppE :: (XOAppE p ~ ()) => IdP p -> RlpExpr' p -> RlpExpr' p -> RlpExpr p +pattern XRlpExprE :: (XXRlpExprE p ~ ()) => RlpExpr p + +pattern LetE bs e = LetE' () bs e +pattern VarE n = VarE' () n +pattern LamE as e = LamE' () as e +pattern CaseE e as = CaseE' () e as +pattern IfE c a b = IfE' () c a b +pattern AppE f x = AppE' () f x +pattern LitE l = LitE' () l +pattern ParE e = ParE' () e +pattern OAppE n a b = OAppE' () n a b +pattern XRlpExprE = XRlpExprE' () + +deriving instance + ( Show (XLetE p), Show (XVarE p), Show (XLamE p) + , Show (XCaseE p), Show (XIfE p), Show (XAppE p) + , Show (XLitE p), Show (XParE p), Show (XOAppE p) + , Show (XXRlpExprE p) + , PhaseShow p + ) => Show (RlpExpr p) type RlpExpr' p = XRec p RlpExpr -- 2.52.0 From f0c652b8612ce939fafb74584f1d2386d0a937a3 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 13:03:07 -0700 Subject: [PATCH 122/192] fixup! ttg boilerplate --- src/Rlp/Syntax.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index ecfb786..2b5ce6b 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -127,7 +127,7 @@ data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) | LitE' (XLitE p) (Lit p) | ParE' (XParE p) (RlpExpr' p) | OAppE' (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) - | XRlpExprE' (XXRlpExprE p) + | XRlpExprE' !(XXRlpExprE p) type family XLetE p type family XVarE p -- 2.52.0 From e962bacd2e2294ecacc0a5bcab8bad2e2f2b8cff Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 13:04:23 -0700 Subject: [PATCH 123/192] fixup! ttg boilerplate --- src/Rlp/Syntax.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 2b5ce6b..9403e50 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -23,13 +23,14 @@ module Rlp.Syntax , XFunD, XTySigD, XInfixD, XDataD, XXDeclD -- *** RlpExpr , XLetE, XVarE, XLamE, XCaseE, XIfE, XAppE, XLitE - , XParE, XOAppE + , XParE, XOAppE, XXRlpExprE -- ** Pattern synonyms -- *** Decl , pattern FunD, pattern TySigD, pattern InfixD, pattern DataD -- *** RlpExpr , pattern LetE, pattern VarE, pattern LamE, pattern CaseE, pattern IfE , pattern AppE, pattern LitE, pattern ParE, pattern OAppE + , pattern XRlpExprE ) where ---------------------------------------------------------------------------------- -- 2.52.0 From ba099b7028c9e8fef271eac1d44d00238b57335a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 14:04:27 -0700 Subject: [PATCH 124/192] organisation and cleaning organisation and tidying --- rlp.cabal | 1 + src/Compiler/RlpcError.hs | 12 +++---- src/Compiler/Types.hs | 66 ++++++++++++++++++++++++++++++++++ src/Core/Lex.x | 3 +- src/Rlp/Parse.y | 4 +-- src/Rlp/Parse/Types.hs | 74 ++++----------------------------------- 6 files changed, 81 insertions(+), 79 deletions(-) create mode 100644 src/Compiler/Types.hs diff --git a/rlp.cabal b/rlp.cabal index b44fe23..d2b278b 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -37,6 +37,7 @@ library , Rlp.Parse.Associate , Rlp.Lex , Rlp.Parse.Types + , Compiler.Types other-modules: Data.Heap , Data.Pretty diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 37edb40..9530b2e 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -5,12 +5,14 @@ module Compiler.RlpcError , MsgEnvelope(..) , Severity(..) , RlpcError(..) - , SrcSpan(..) , msgSpan , msgDiagnostic , msgSeverity , liftRlpcErrors , errorMsg + -- * Located Comonad + , Located(..) + , SrcSpan(..) ) where ---------------------------------------------------------------------------------- @@ -20,6 +22,7 @@ import Data.Text qualified as T import GHC.Exts (IsString(..)) import Lens.Micro.Platform import Lens.Micro.Platform.Internal +import Compiler.Types ---------------------------------------------------------------------------------- data MsgEnvelope e = MsgEnvelope @@ -45,13 +48,6 @@ data Severity = SevWarning | SevError deriving Show -data SrcSpan = SrcSpan - !Int -- ^ Line - !Int -- ^ Column - !Int -- ^ Absolute - !Int -- ^ Length - deriving Show - makeLenses ''MsgEnvelope liftRlpcErrors :: (Functor m, IsRlpcError e) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs new file mode 100644 index 0000000..3a94275 --- /dev/null +++ b/src/Compiler/Types.hs @@ -0,0 +1,66 @@ +module Compiler.Types + ( SrcSpan(..) + , Located(..) + , (<<~), (<~>) + + -- * Re-exports + , Comonad + , Apply + , Bind + ) + where +-------------------------------------------------------------------------------- +import Control.Comonad +import Data.Functor.Apply +import Data.Functor.Bind +-------------------------------------------------------------------------------- + +-- | Token wrapped with a span (line, column, absolute, length) +data Located a = Located SrcSpan a + deriving (Show, Functor) + +instance Apply Located where + liftF2 f (Located sa p) (Located sb q) + = Located (sa <> sb) (p `f` q) + +instance Bind Located where + Located sa a >>- k = Located (sa <> sb) b + where + Located sb b = k a + +instance Comonad Located where + extract (Located _ a) = a + extend ck w@(Located p _) = Located p (ck w) + +data SrcSpan = SrcSpan + !Int -- ^ Line + !Int -- ^ Column + !Int -- ^ Absolute + !Int -- ^ Length + deriving Show + +instance Semigroup SrcSpan where + SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where + l = min la lb + c = min ca cb + a = min aa ab + s = case aa `compare` ab of + EQ -> max sa sb + LT -> max sa (ab + lb - aa) + GT -> max sb (aa + la - ab) + +-- | A synonym for '(<<=)' with a tighter precedence and left-associativity for +-- use with '(<~>)' in a sort of, comonadic pseudo-applicative style. + +(<<~) :: (Comonad w) => (w a -> b) -> w a -> w b +(<<~) = (<<=) + +infixl 4 <<~ + +-- | Similar to '(<*>)', but with a cokleisli arrow. + +(<~>) :: (Comonad w, Bind w) => w (w a -> b) -> w a -> w b +mc <~> ma = mc >>- \f -> ma =>> f + +infixl 4 <~> + diff --git a/src/Core/Lex.x b/src/Core/Lex.x index ba62996..99a67b1 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -22,7 +22,8 @@ import Data.Text qualified as T import Data.String (IsString(..)) import Core.Syntax import Compiler.RLPC -import Compiler.RlpcError +-- TODO: unify Located definitions +import Compiler.RlpcError hiding (Located(..)) import Lens.Micro import Lens.Micro.TH } diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index b3999f8..789c517 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -208,8 +208,8 @@ mkProgram ds = do pure $ RlpProgram (associate pt <$> ds) parseError :: Located RlpToken -> P a -parseError (Located (l,c,a,s) t) = addFatal $ - errorMsg (SrcSpan l c a s) RlpParErrUnexpectedToken +parseError (Located ss t) = addFatal $ + errorMsg ss RlpParErrUnexpectedToken mkInfixD :: Assoc -> Int -> PsName -> P (Decl' RlpcPs) mkInfixD a p n = do diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 95d01e2..903c574 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -29,7 +29,6 @@ import Core.Syntax (Name) import Control.Monad import Control.Monad.State.Strict import Control.Monad.Errorful -import Control.Comonad import Compiler.RlpcError import Data.Text (Text) import Data.Maybe @@ -37,14 +36,13 @@ import Data.Fix import Data.Functor.Foldable import Data.Functor.Const import Data.Functor.Classes -import Data.Functor.Apply -import Data.Functor.Bind import Data.HashMap.Strict qualified as H import Data.Void import Data.Word (Word8) import Lens.Micro.TH import Lens.Micro import Rlp.Syntax +import Compiler.Types -------------------------------------------------------------------------------- -- | Phantom type identifying rlpc's parser phase @@ -74,6 +72,11 @@ type PsName = Text -------------------------------------------------------------------------------- +spanFromPos :: Position -> Int -> SrcSpan +spanFromPos (l,c,a) s = SrcSpan l c a s + +{-# INLINE spanFromPos #-} + type LexerAction a = AlexInput -> Int -> P a data AlexInput = AlexInput @@ -177,71 +180,6 @@ data Layout = Explicit | Implicit Int deriving (Show, Eq) --- | Token wrapped with a span (line, column, absolute, length) -data Located a = Located !(Int, Int, Int, Int) a - deriving (Show, Functor) - -instance Apply Located where - liftF2 f (Located (la,ca,aa,sa) p) (Located (lb,cb,ab,sb) q) - = Located (l,c,a,s) (p `f` q) - where - l = min la lb - c = min ca cb - a = min aa ab - s = case aa `compare` ab of - EQ -> max sa sb - LT -> max sa (ab + sb) - GT -> max sb (aa + sa) - -instance Bind Located where - Located sa a >>- k = Located (sa `spanAcross` sb) b - where - Located sb b = k a - -spanAcross :: (Int, Int, Int, Int) - -> (Int, Int, Int, Int) - -> (Int, Int, Int, Int) -spanAcross (la,ca,aa,sa) (lb,cb,ab,sb) = (l,c,a,s) - where - l = min la lb - c = min ca cb - a = min aa ab - s = case aa `compare` ab of - EQ -> max sa sb - LT -> max sa (ab + sb) - GT -> max sb (aa + sa) - --- | A synonym for '(<<=)' with a different precedence for use with '(<~>)' in a --- sort of, comonadic pseudo-applicative style. - -(<<~) :: (Comonad w) => (w a -> b) -> w a -> w b -(<<~) = (<<=) - -infixl 4 <<~ - --- | Similar to '(<*>)', but with a cokleisli arrow. - -(<~>) :: (Comonad w, Bind w) => w (w a -> b) -> w a -> w b -mc <~> ma = mc >>- \f -> ma =>> f - -infixl 4 <~> - --- f :: (w a -> w b -> c) --- a :: w a --- b :: w b - --- result :: w c --- result = f >~~ a <~> b - -instance Comonad Located where - extract (Located _ a) = a - extend ck w@(Located p _) = Located p (ck w) - -spanFromPos :: Position -> Int -> (Int, Int, Int, Int) -spanFromPos (l,c,a) s = (l,c,a,s) - -{-# INLINE spanFromPos #-} - type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) -- 2.52.0 From 14df00039f4c68494b3104d93390c0d5fb1e52d8 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 15:56:45 -0700 Subject: [PATCH 125/192] error messages --- rlp.cabal | 1 + src/Compiler/RLPC.hs | 37 +++++++++++++++++++++++++-- src/Compiler/Types.hs | 12 +++++++++ src/Control/Monad/Errorful.hs | 6 ++--- src/Rlp/Lex.x | 29 ++++++--------------- src/Rlp/Parse.y | 20 ++++++++++++--- src/Rlp/Parse/Types.hs | 48 +++++++++++++++++++++++++++++++++-- 7 files changed, 122 insertions(+), 31 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index d2b278b..b813073 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -73,6 +73,7 @@ library , semigroupoids , comonad , lens + , text-ansi hs-source-dirs: src default-language: GHC2021 diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 474ecfc..48fdfab 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -46,6 +46,7 @@ import Control.Monad.Reader import Control.Monad.State (MonadState(state)) import Control.Monad.Errorful import Compiler.RlpcError +import Compiler.Types import Data.Functor.Identity import Data.Default.Class import Data.Foldable @@ -55,6 +56,10 @@ import Data.Hashable (Hashable) import Data.HashSet (HashSet) import Data.HashSet qualified as S import Data.Coerce +import Data.Text (Text) +import Data.Text qualified as T +import Text.ANSI qualified as Ansi +import Text.PrettyPrint hiding ((<>)) import Lens.Micro.Platform import System.Exit ---------------------------------------------------------------------------------- @@ -79,7 +84,9 @@ evalRLPCT :: (Monad m) => RLPCOptions -> RLPCT m a -> m (Maybe a, [MsgEnvelope RlpcError]) -evalRLPCT = undefined +evalRLPCT opt r = runRLPCT r + & flip runReaderT opt + & runErrorfulT evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a evalRLPCIO opt r = do @@ -90,7 +97,33 @@ evalRLPCIO opt r = do Nothing -> die "Failed, no code compiled." putRlpcErrs :: [MsgEnvelope RlpcError] -> IO () -putRlpcErrs = traverse_ print +putRlpcErrs = traverse_ (putStrLn . ('\n':) . render . prettyRlpcErr) + +prettyRlpcErr :: MsgEnvelope RlpcError -> Doc +prettyRlpcErr msg = header + $$ nest 2 bullets + $$ source + where + source = vcat $ zipWith (<+>) rule srclines + where + rule = repeat (ttext . Ansi.blue . Ansi.bold $ "|") + srclines = ["", "", ""] + filename = msgColour "" + pos = msgColour $ tshow (msg ^. msgSpan . srcspanLine) + <> ":" + <> tshow (msg ^. msgSpan . srcspanColumn) + + header = ttext $ filename <> msgColour ":" <> pos <> msgColour ": " + <> errorColour "error" <> msgColour ":" + + bullets = let Text ts = msg ^. msgDiagnostic + in vcat $ hang "•" 2 . ttext . msgColour <$> ts + + msgColour = Ansi.white . Ansi.bold + errorColour = Ansi.red . Ansi.bold + ttext = text . T.unpack + tshow :: (Show a) => a -> Text + tshow = T.pack . show liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 3a94275..79b7d8a 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -1,5 +1,6 @@ module Compiler.Types ( SrcSpan(..) + , srcspanLine, srcspanColumn, srcspanAbs, srcspanLen , Located(..) , (<<~), (<~>) @@ -13,6 +14,7 @@ module Compiler.Types import Control.Comonad import Data.Functor.Apply import Data.Functor.Bind +import Control.Lens hiding ((<<~)) -------------------------------------------------------------------------------- -- | Token wrapped with a span (line, column, absolute, length) @@ -39,6 +41,16 @@ data SrcSpan = SrcSpan !Int -- ^ Length deriving Show +tupling :: Iso' SrcSpan (Int, Int, Int, Int) +tupling = iso (\ (SrcSpan a b c d) -> (a,b,c,d)) + (\ (a,b,c,d) -> SrcSpan a b c d) + +srcspanLine, srcspanColumn, srcspanAbs, srcspanLen :: Lens' SrcSpan Int +srcspanLine = tupling . _1 +srcspanColumn = tupling . _2 +srcspanAbs = tupling . _3 +srcspanLen = tupling . _4 + instance Semigroup SrcSpan where SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where l = min la lb diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index 627dcf8..f767b99 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -3,9 +3,9 @@ {-# LANGUAGE TupleSections, PatternSynonyms #-} {-# LANGUAGE UndecidableInstances #-} module Control.Monad.Errorful - ( ErrorfulT - , runErrorfulT + ( ErrorfulT(..) , Errorful + , pattern Errorful , runErrorful , mapErrorful , MonadErrorful(..) @@ -67,7 +67,7 @@ mapErrorful f (ErrorfulT m) = ErrorfulT $ m & mapped . _2 . mapped %~ f -- when microlens-pro drops we can write this as --- mapErrorful f = coerced . mapped . _2 . mappd %~ f +-- mapErrorful f = coerced . mapped . _2 . mapped %~ f -- lol -------------------------------------------------------------------------------- diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 72f2cf0..adc30f5 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -11,6 +11,8 @@ module Rlp.Lex , lexDebug , lexCont , popLexState + , programInitState + , runP' ) where import Codec.Binary.UTF8.String (encodeChar) @@ -236,27 +238,9 @@ alexEOF = do pos <- getPos pure (Located (spanFromPos pos 0) TokenEOF) -initParseState :: Text -> ParseState -initParseState s = ParseState - { _psLayoutStack = [] - -- IMPORTANT: the initial state is `bol` to begin the top-level layout, - -- which then returns to state 0 which continues the normal lexing process. - , _psLexState = [layout_top,0] - , _psInput = initAlexInput s - , _psOpTable = mempty - } - -initAlexInput :: Text -> AlexInput -initAlexInput s = AlexInput - { _aiPrevChar = '\0' - , _aiSource = s - , _aiBytes = [] - , _aiPos = (1,1,0) - } - runP' :: P a -> Text -> (ParseState, [MsgEnvelope RlpParseError], Maybe a) runP' p s = runP p st where - st = initParseState s + st = initParseState [layout_top,0] s lexToken :: P (Located RlpToken) lexToken = do @@ -310,7 +294,7 @@ popLayout = do psLayoutStack %= (drop 1) case ctx of Just l -> pure l - Nothing -> error "uhh" + Nothing -> error "popLayout: layout stack empty! this is a bug." pushLayout :: Layout -> P () pushLayout l = do @@ -368,10 +352,13 @@ explicitRBrace inp l = do doLayout :: LexerAction (Located RlpToken) doLayout _ _ = do i <- indentLevel - traceM $ "doLayout: i: " <> show i + -- traceM $ "doLayout: i: " <> show i pushLayout (Implicit i) popLexState insertLBrace +programInitState :: Text -> ParseState +programInitState = initParseState [layout_top,0] + } diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 789c517..a885f59 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -2,10 +2,13 @@ {-# LANGUAGE LambdaCase, ViewPatterns #-} module Rlp.Parse ( parseRlpProg + , parseRlpProgR , parseRlpExpr + , parseRlpExprR ) where import Compiler.RlpcError +import Compiler.RLPC import Rlp.Lex import Rlp.Syntax import Rlp.Parse.Types @@ -19,6 +22,7 @@ import Data.Functor.Bind import Control.Comonad import Data.Functor import Data.Semigroup.Traversable +import Data.Text (Text) import Data.Text qualified as T import Data.Void } @@ -29,6 +33,7 @@ import Data.Void %monad { P } %lexer { lexCont } { Located _ TokenEOF } %error { parseError } +%errorhandlertype explist %tokentype { Located RlpToken } %token @@ -85,6 +90,7 @@ DeclsV :: { [Decl' RlpcPs] } DeclsV : Decl VS Decls { $1 : $3 } | Decl VS { [$1] } | Decl { [$1] } + | {- epsilon -} { [] } VS :: { Located RlpToken } VS : ';' { $1 } @@ -187,6 +193,13 @@ Con :: { Located PsName } { +parseRlpExprR = undefined + +parseRlpProgR :: (Monad m) => Text -> RLPCT m (RlpProgram RlpcPs) +parseRlpProgR s = liftErrorful $ pToErrorful parseRlpProg st + where + st = programInitState s + mkPsName :: Located RlpToken -> Located PsName mkPsName = fmap extractName @@ -207,9 +220,9 @@ mkProgram ds = do pt <- use psOpTable pure $ RlpProgram (associate pt <$> ds) -parseError :: Located RlpToken -> P a -parseError (Located ss t) = addFatal $ - errorMsg ss RlpParErrUnexpectedToken +parseError :: (Located RlpToken, [String]) -> P a +parseError ((Located ss t), exp) = addFatal $ + errorMsg ss (RlpParErrUnexpectedToken t exp) mkInfixD :: Assoc -> Int -> PsName -> P (Decl' RlpcPs) mkInfixD a p n = do @@ -228,3 +241,4 @@ intOfToken :: Located RlpToken -> Int intOfToken (Located _ (TokenLitInt n)) = n } + diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 903c574..77c6519 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -8,6 +8,8 @@ module Rlp.Parse.Types -- * Parser monad and state , P(..), ParseState(..), Layout(..), OpTable, OpInfo + , initParseState, initAlexInput + , pToErrorful -- ** Lenses , psLayoutStack, psLexState, psInput, psOpTable @@ -39,6 +41,7 @@ import Data.Functor.Classes import Data.HashMap.Strict qualified as H import Data.Void import Data.Word (Word8) +import Data.Text qualified as T import Lens.Micro.TH import Lens.Micro import Rlp.Syntax @@ -145,6 +148,11 @@ newtype P a = P { } deriving (Functor) +pToErrorful :: (Applicative m) + => P a -> ParseState -> ErrorfulT (MsgEnvelope RlpParseError) m a +pToErrorful p st = ErrorfulT $ pure (ma,es) where + (_,es,ma) = runP p st + instance Applicative P where pure a = P $ \st -> (st, [], pure a) liftA2 = liftM2 @@ -188,10 +196,28 @@ type OpInfo = (Assoc, Int) data RlpParseError = RlpParErrOutOfBoundsPrecedence Int | RlpParErrDuplicateInfixD Name | RlpParErrLexical - | RlpParErrUnexpectedToken - deriving (Eq, Ord, Show) + | RlpParErrUnexpectedToken RlpToken [String] + deriving (Show) instance IsRlpcError RlpParseError where + liftRlpcError = \case + RlpParErrOutOfBoundsPrecedence n -> + Text [ "Illegal precedence in infixity declaration" + , "rl' currently only allows precedences between 0 and 9." + ] + RlpParErrDuplicateInfixD s -> + Text [ "Conflicting infixity declarations for operator " + <> tshow s + ] + RlpParErrLexical -> + Text [ "Unknown lexical error :(" ] + RlpParErrUnexpectedToken t exp -> + Text [ "Unexpected token " <> tshow t + , "Expected: " <> tshow exp + ] + where + tshow :: (Show a) => a -> T.Text + tshow = T.pack . show ---------------------------------------------------------------------------------- @@ -224,3 +250,21 @@ addFatalHere l e = P $ \st -> } in (st, [e'], Nothing) +initParseState :: [Int] -> Text -> ParseState +initParseState ls s = ParseState + { _psLayoutStack = [] + -- IMPORTANT: the initial state is `bol` to begin the top-level layout, + -- which then returns to state 0 which continues the normal lexing process. + , _psLexState = ls + , _psInput = initAlexInput s + , _psOpTable = mempty + } + +initAlexInput :: Text -> AlexInput +initAlexInput s = AlexInput + { _aiPrevChar = '\0' + , _aiSource = s + , _aiBytes = [] + , _aiPos = (1,1,0) + } + -- 2.52.0 From ccf17faff802d845fd9edc830c565d59ed75f856 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 30 Jan 2024 16:19:03 -0700 Subject: [PATCH 126/192] driver progress --- app/Main.hs | 81 +++++++++++++++++++++----------------------- src/Compiler/RLPC.hs | 9 +++++ 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index 27377d0..0424aa2 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -55,11 +55,22 @@ options = RLPCOptions \triggering the garbage collector" <> value 50 ) + <*> option languageReader + ( long "language" + ) <*> some (argument str $ metavar "FILES...") where infixr 9 # f # x = f x +languageReader :: ReadM Language +languageReader = maybeReader $ \case + "rlp" -> Just LanguageRlp + "core" -> Just LanguageCore + +debugFlagReader :: ReadM DebugFlag +debugFlagReader = maybeReader $ Just + evaluatorReader :: ReadM Evaluator evaluatorReader = maybeReader $ \case "gm" -> Just EvaluatorGM @@ -69,80 +80,66 @@ evaluatorReader = maybeReader $ \case mmany :: (Alternative f, Monoid m) => f m -> f m mmany v = liftA2 (<>) v (mmany v) -debugFlagReader :: ReadM DebugFlag -debugFlagReader = maybeReader $ \case - "dump-eval" -> Just DDumpEval - "dump-opts" -> Just DDumpOpts - "dump-ast" -> Just DDumpAST - _ -> Nothing - ---------------------------------------------------------------------------------- --- temp -data CompilerError = CompilerError String - deriving Show - -instance Exception CompilerError - main :: IO () main = do opts <- execParser optParser - (_, es) <- evalRLPCIO opts driver - forM_ es $ \ (CompilerError e) -> print $ "warning: " <> e - pure () + void $ evalRLPCIO opts driver -driver :: RLPCIO CompilerError () +driver :: RLPCIO () driver = sequence_ [ dshowFlags , ddumpAST , ddumpEval ] -dshowFlags :: RLPCIO CompilerError () -dshowFlags = whenFlag flagDDumpOpts do +dshowFlags :: RLPCIO () +dshowFlags = whenDFlag "dump-flags" do ask >>= liftIO . print -ddumpAST :: RLPCIO CompilerError () -ddumpAST = whenFlag flagDDumpAST $ forFiles_ \o f -> do +ddumpAST :: RLPCIO () +ddumpAST = whenDFlag "dump-ast" $ forFiles_ \o f -> do liftIO $ withFile f ReadMode $ \h -> do s <- TIO.hGetContents h case parseProg o s of Right (a,_) -> hPutStrLn stderr $ show a Left e -> error "todo errors lol" -ddumpEval :: RLPCIO CompilerError () -ddumpEval = whenFlag flagDDumpEval do +ddumpEval :: RLPCIO () +ddumpEval = whenDFlag "dump-eval" do fs <- view rlpcInputFiles forM_ fs $ \f -> liftIO (TIO.readFile f) >>= doProg where - doProg :: Text -> RLPCIO CompilerError () - doProg s = ask >>= \o -> case parseProg o s of - -- TODO: error handling - Left e -> addFatal . CompilerError $ show e - Right (a,_) -> do - log <- view rlpcLogFile - dumpEval <- chooseEval - case log of - Just f -> liftIO $ withFile f WriteMode $ dumpEval a - Nothing -> liftIO $ dumpEval a stderr + doProg :: Text -> RLPCIO () + doProg = undefined + -- doProg s = ask >>= \o -> case parseProg o s of + -- -- TODO: error handling + -- Left e -> addFatal . CompilerError $ show e + -- Right (a,_) -> do + -- log <- view rlpcLogFile + -- dumpEval <- chooseEval + -- case log of + -- Just f -> liftIO $ withFile f WriteMode $ dumpEval a + -- Nothing -> liftIO $ dumpEval a stderr -- choose the appropriate model based on the compiler opts - chooseEval = do - ev <- view rlpcEvaluator - pure $ case ev of - EvaluatorGM -> v GM.hdbgProg - EvaluatorTI -> v TI.hdbgProg - where v f p h = f p h *> pure () + -- chooseEval = do + -- ev <- view rlpcEvaluator + -- pure $ case ev of + -- EvaluatorGM -> v GM.hdbgProg + -- EvaluatorTI -> v TI.hdbgProg + -- where v f p h = f p h *> pure () parseProg :: RLPCOptions -> Text - -> Either SrcError (Program', [SrcError]) + -> (Maybe Program', [MsgEnvelope RlpcError]) parseProg o = evalRLPC o . (lexCore >=> parseCoreProg) forFiles_ :: (Monad m) - => (RLPCOptions -> FilePath -> RLPCT e m a) - -> RLPCT e m () + => (RLPCOptions -> FilePath -> RLPCT m a) + -> RLPCT m () forFiles_ k = do fs <- view rlpcInputFiles o <- ask diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 48fdfab..a7919d6 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -23,6 +23,7 @@ module Compiler.RLPC , addWound , MonadErrorful , Severity(..) + , Language(..) , Evaluator(..) , evalRLPCT , evalRLPCIO @@ -45,6 +46,7 @@ import Control.Monad import Control.Monad.Reader import Control.Monad.State (MonadState(state)) import Control.Monad.Errorful +import Control.Monad.IO.Class import Compiler.RlpcError import Compiler.Types import Data.Functor.Identity @@ -73,6 +75,8 @@ type RLPC = RLPCT Identity type RLPCIO = RLPCT IO +instance (MonadIO m) => MonadIO (RLPCT m) where + evalRLPC :: RLPCOptions -> RLPC a -> (Maybe a, [MsgEnvelope RlpcError]) @@ -134,6 +138,7 @@ data RLPCOptions = RLPCOptions , _rlpcFFlags :: HashSet CompilerFlag , _rlpcEvaluator :: Evaluator , _rlpcHeapTrigger :: Int + , _rlpcLanguage :: Language , _rlpcInputFiles :: [FilePath] } deriving Show @@ -141,6 +146,9 @@ data RLPCOptions = RLPCOptions data Evaluator = EvaluatorGM | EvaluatorTI deriving Show +data Language = LanguageRlp | LanguageCore + deriving Show + ---------------------------------------------------------------------------------- instance Default RLPCOptions where @@ -151,6 +159,7 @@ instance Default RLPCOptions where , _rlpcEvaluator = EvaluatorGM , _rlpcHeapTrigger = 200 , _rlpcInputFiles = [] + , _rlpcLanguage = LanguageRlp } -- debug flags are passed with -dFLAG -- 2.52.0 From 1803a1e05849538d98a64cc004a9a062403cff2e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 09:05:58 -0700 Subject: [PATCH 127/192] formatting --- src/Core/Syntax.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 83b4934..b624e43 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -103,7 +103,7 @@ data Binding b = Binding b (Expr b) deriving instance (Eq b) => Eq (Binding b) infixl 1 := -pattern (:=) :: b -> (Expr b) -> (Binding b) +pattern (:=) :: b -> Expr b -> Binding b pattern k := v = Binding k v data Alter b = Alter AltCon [b] (Expr b) @@ -123,7 +123,7 @@ data AltCon = AltData Name | Default deriving (Show, Read, Eq, Lift) -data Lit = IntL Int +newtype Lit = IntL Int deriving (Show, Read, Eq, Lift) type Name = T.Text @@ -201,7 +201,7 @@ instance HasLHS (Alter b) (Alter b) (AltCon, [b]) (AltCon, [b]) where instance HasLHS (ScDef b) (ScDef b) (b, [b]) (b, [b]) where _lhs = lens (\ (ScDef n as _) -> (n,as)) - (\ (ScDef _ _ e) (n',as') -> (ScDef n' as' e)) + (\ (ScDef _ _ e) (n',as') -> ScDef n' as' e) instance HasLHS (Binding b) (Binding b) b b where _lhs = lens -- 2.52.0 From 46f0393a037690d70a4444474602d2d75090b88c Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 10:37:51 -0700 Subject: [PATCH 128/192] *R functions --- src/Compiler/RLPC.hs | 61 +++++++++++++++++++---------------- src/Control/Monad/Errorful.hs | 7 ++-- src/Core/HindleyMilner.hs | 2 +- src/Core/Lex.x | 8 +++-- src/Core/Parse.y | 8 +++-- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index a7919d6..f928f5d 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -11,32 +11,29 @@ errors and the family of RLPC monads. -- only used for mtl instances {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-} +{-# LANGUAGE BlockArguments #-} module Compiler.RLPC - ( RLPC - , RLPCT(..) - , RLPCIO - , RLPCOptions(RLPCOptions) - , IsRlpcError(..) - , RlpcError(..) - , MsgEnvelope(..) - , addFatal - , addWound - , MonadErrorful - , Severity(..) - , Language(..) - , Evaluator(..) - , evalRLPCT - , evalRLPCIO - , evalRLPC - , rlpcLogFile - , rlpcDFlags - , rlpcEvaluator - , rlpcInputFiles - , DebugFlag(..) - , whenDFlag - , whenFFlag - , def - , liftErrorful + ( + -- * Rlpc Monad transformer + RLPCT(RLPCT), + -- ** Special cases + RLPC, RLPCIO + -- ** Running + , runRLPCT + , evalRLPCT, evalRLPCIO, evalRLPC + -- * Rlpc options + , Language(..), Evaluator(..) + , DebugFlag(..), CompilerFlag(..) + -- ** Lenses + , rlpcLogFile, rlpcDFlags, rlpcEvaluator, rlpcInputFiles, rlpcLanguage + -- * Misc. MTL-style functions + , liftErrorful, hoistRlpcT + -- * Misc. Rlpc Monad -related types + , RLPCOptions(RLPCOptions), IsRlpcError(..), RlpcError(..) + , MsgEnvelope(..), Severity(..) + , whenDFlag, whenFFlag + -- * Convenient re-exports + , addFatal, addWound, def ) where ---------------------------------------------------------------------------------- @@ -71,6 +68,12 @@ newtype RLPCT m a = RLPCT { } deriving (Functor, Applicative, Monad, MonadReader RLPCOptions) +rlpc :: (IsRlpcError e, Monad m) + => (RLPCOptions -> (Maybe a, [MsgEnvelope e])) + -> RLPCT m a +rlpc f = RLPCT . ReaderT $ \opt -> + ErrorfulT . pure $ f opt & _2 . each . mapped %~ liftRlpcError + type RLPC = RLPCT Identity type RLPCIO = RLPCT IO @@ -84,8 +87,7 @@ evalRLPC opt r = runRLPCT r & flip runReaderT opt & runErrorful -evalRLPCT :: (Monad m) - => RLPCOptions +evalRLPCT :: RLPCOptions -> RLPCT m a -> m (Maybe a, [MsgEnvelope RlpcError]) evalRLPCT opt r = runRLPCT r @@ -132,6 +134,11 @@ prettyRlpcErr msg = header liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e) +hoistRlpcT :: (forall a. m a -> n a) + -> RLPCT m a -> RLPCT n a +hoistRlpcT f rma = RLPCT $ ReaderT $ \opt -> + ErrorfulT $ f $ evalRLPCT opt rma + data RLPCOptions = RLPCOptions { _rlpcLogFile :: Maybe FilePath , _rlpcDFlags :: HashSet DebugFlag diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index f767b99..f24042b 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -1,11 +1,11 @@ -{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE FunctionalDependencies #-} -{-# LANGUAGE TupleSections, PatternSynonyms #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE UndecidableInstances #-} module Control.Monad.Errorful ( ErrorfulT(..) , Errorful , pattern Errorful + , errorful , runErrorful , mapErrorful , MonadErrorful(..) @@ -28,6 +28,9 @@ type Errorful e = ErrorfulT e Identity pattern Errorful :: (Maybe a, [e]) -> Errorful e a pattern Errorful a = ErrorfulT (Identity a) +errorful :: (Applicative m) => (Maybe a, [e]) -> ErrorfulT e m a +errorful = ErrorfulT . pure + runErrorful :: Errorful e a -> (Maybe a, [e]) runErrorful m = coerce (runErrorfulT m) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index cf0dace..7dcc4c6 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -105,7 +105,7 @@ checkCoreProg p = scDefs where scname = sc ^. _lhs._1 -- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. -checkCoreProgR :: Program' -> RLPC Program' +checkCoreProgR :: (Applicative m) => Program' -> RLPCT m Program' checkCoreProgR p = undefined {-# WARNING checkCoreProgR "unimpl" #-} diff --git a/src/Core/Lex.x b/src/Core/Lex.x index 99a67b1..dba29c9 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -20,6 +20,7 @@ import Debug.Trace import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) +import Data.Functor.Identity import Core.Syntax import Compiler.RLPC -- TODO: unify Located definitions @@ -180,8 +181,11 @@ lexCore s = case m of where m = runAlex s lexStream -lexCoreR :: Text -> RLPC [Located CoreToken] -lexCoreR = lexCore +lexCoreR :: forall m. (Applicative m) => Text -> RLPCT m [Located CoreToken] +lexCoreR = hoistRlpcT generalise . lexCore + where + generalise :: forall a. Identity a -> m a + generalise (Identity a) = pure a -- | @lexCore@, but the tokens are stripped of location info. Useful for -- debugging diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 7dbb6b5..5f4dc38 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -17,6 +17,7 @@ module Core.Parse import Control.Monad ((>=>)) import Data.Foldable (foldl') +import Data.Functor.Identity import Core.Syntax import Core.Lex import Compiler.RLPC @@ -224,8 +225,11 @@ insScDef sc = programScDefs %~ (sc:) singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty -parseCoreProgR :: [Located CoreToken] -> RLPC Program' -parseCoreProgR = parseCoreProg +parseCoreProgR :: forall m. (Applicative m) => [Located CoreToken] -> RLPCT m Program' +parseCoreProgR = hoistRlpcT generalise . parseCoreProg + where + generalise :: forall a. Identity a -> m a + generalise (Identity a) = pure a happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b happyBind m k = m >>= k -- 2.52.0 From dda0e173580330f61ae3b9a42a3f6ecd2c11ea0f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 11:37:52 -0700 Subject: [PATCH 129/192] -ddump-ast --- app/CoreDriver.hs | 14 +++++++ app/Main.hs | 70 ++++++++++------------------------- app/RlpDriver.hs | 0 src/Compiler/RLPC.hs | 24 +++++++++--- src/Compiler/RlpcError.hs | 10 +++++ src/Control/Monad/Errorful.hs | 7 ++-- src/Core/Parse.y | 10 ++++- 7 files changed, 75 insertions(+), 60 deletions(-) create mode 100644 app/CoreDriver.hs create mode 100644 app/RlpDriver.hs diff --git a/app/CoreDriver.hs b/app/CoreDriver.hs new file mode 100644 index 0000000..ba546c9 --- /dev/null +++ b/app/CoreDriver.hs @@ -0,0 +1,14 @@ +module CoreDriver + ( driver + ) + where +-------------------------------------------------------------------------------- + +driver :: RLPCIO () +driver = undefined + +parseProg :: RLPCOptions + -> Text + -> (Maybe Program', [MsgEnvelope RlpcError]) +parseProg o = lexCoreR >=> parseCoreProgR + diff --git a/app/Main.hs b/app/Main.hs index 0424aa2..440789c 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -10,12 +10,16 @@ import Data.HashSet qualified as S import Data.Text (Text) import Data.Text qualified as T import Data.Text.IO qualified as TIO +import Data.List import System.IO import System.Exit (exitSuccess) import Core import TI import GM import Lens.Micro.Mtl + +import CoreDriver qualified +import RlpDriver qualified ---------------------------------------------------------------------------------- optParser :: ParserInfo RLPCOptions @@ -37,9 +41,15 @@ options = RLPCOptions {- -d -} <*> fmap S.fromList # many # option debugFlagReader ( short 'd' - <> help "dump evaluation logs" + <> help "pass debug flags" <> metavar "DEBUG FLAG" ) + {- -f -} + <*> fmap S.fromList # many # option compilerFlagReader + ( short 'f' + <> help "pass compilation flags" + <> metavar "COMPILATION FLAG" + ) {- --evaluator, -e -} <*> option evaluatorReader ( long "evaluator" @@ -57,6 +67,7 @@ options = RLPCOptions ) <*> option languageReader ( long "language" + <> short 'x' ) <*> some (argument str $ metavar "FILES...") where @@ -67,9 +78,13 @@ languageReader :: ReadM Language languageReader = maybeReader $ \case "rlp" -> Just LanguageRlp "core" -> Just LanguageCore + _ -> Nothing debugFlagReader :: ReadM DebugFlag -debugFlagReader = maybeReader $ Just +debugFlagReader = str + +compilerFlagReader :: ReadM CompilerFlag +compilerFlagReader = str evaluatorReader :: ReadM Evaluator evaluatorReader = maybeReader $ \case @@ -88,54 +103,9 @@ main = do void $ evalRLPCIO opts driver driver :: RLPCIO () -driver = sequence_ - [ dshowFlags - , ddumpAST - , ddumpEval - ] - -dshowFlags :: RLPCIO () -dshowFlags = whenDFlag "dump-flags" do - ask >>= liftIO . print - -ddumpAST :: RLPCIO () -ddumpAST = whenDFlag "dump-ast" $ forFiles_ \o f -> do - liftIO $ withFile f ReadMode $ \h -> do - s <- TIO.hGetContents h - case parseProg o s of - Right (a,_) -> hPutStrLn stderr $ show a - Left e -> error "todo errors lol" - -ddumpEval :: RLPCIO () -ddumpEval = whenDFlag "dump-eval" do - fs <- view rlpcInputFiles - forM_ fs $ \f -> liftIO (TIO.readFile f) >>= doProg - - where - doProg :: Text -> RLPCIO () - doProg = undefined - -- doProg s = ask >>= \o -> case parseProg o s of - -- -- TODO: error handling - -- Left e -> addFatal . CompilerError $ show e - -- Right (a,_) -> do - -- log <- view rlpcLogFile - -- dumpEval <- chooseEval - -- case log of - -- Just f -> liftIO $ withFile f WriteMode $ dumpEval a - -- Nothing -> liftIO $ dumpEval a stderr - - -- choose the appropriate model based on the compiler opts - -- chooseEval = do - -- ev <- view rlpcEvaluator - -- pure $ case ev of - -- EvaluatorGM -> v GM.hdbgProg - -- EvaluatorTI -> v TI.hdbgProg - -- where v f p h = f p h *> pure () - -parseProg :: RLPCOptions - -> Text - -> (Maybe Program', [MsgEnvelope RlpcError]) -parseProg o = evalRLPC o . (lexCore >=> parseCoreProg) +driver = view rlpcLanguage >>= \case + LanguageCore -> CoreDriver.driver + LanguageRlp -> RlpDriver.driver forFiles_ :: (Monad m) => (RLPCOptions -> FilePath -> RLPCT m a) diff --git a/app/RlpDriver.hs b/app/RlpDriver.hs new file mode 100644 index 0000000..e69de29 diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index f928f5d..90ee262 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -11,7 +11,7 @@ errors and the family of RLPC monads. -- only used for mtl instances {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-} -{-# LANGUAGE BlockArguments #-} +{-# LANGUAGE BlockArguments, ViewPatterns #-} module Compiler.RLPC ( -- * Rlpc Monad transformer @@ -31,6 +31,7 @@ module Compiler.RLPC -- * Misc. Rlpc Monad -related types , RLPCOptions(RLPCOptions), IsRlpcError(..), RlpcError(..) , MsgEnvelope(..), Severity(..) + , addDebugMsg , whenDFlag, whenFFlag -- * Convenient re-exports , addFatal, addWound, def @@ -60,13 +61,15 @@ import Data.Text qualified as T import Text.ANSI qualified as Ansi import Text.PrettyPrint hiding ((<>)) import Lens.Micro.Platform +import Lens.Micro.Platform.Internal import System.Exit ---------------------------------------------------------------------------------- newtype RLPCT m a = RLPCT { runRLPCT :: ReaderT RLPCOptions (ErrorfulT (MsgEnvelope RlpcError) m) a } - deriving (Functor, Applicative, Monad, MonadReader RLPCOptions) + deriving ( Functor, Applicative, Monad + , MonadReader RLPCOptions, MonadErrorful (MsgEnvelope RlpcError)) rlpc :: (IsRlpcError e, Monad m) => (RLPCOptions -> (Maybe a, [MsgEnvelope e])) @@ -103,10 +106,18 @@ evalRLPCIO opt r = do Nothing -> die "Failed, no code compiled." putRlpcErrs :: [MsgEnvelope RlpcError] -> IO () -putRlpcErrs = traverse_ (putStrLn . ('\n':) . render . prettyRlpcErr) +putRlpcErrs = traverse_ (putStrLn . ('\n':) . prettyRlpcMsg) -prettyRlpcErr :: MsgEnvelope RlpcError -> Doc -prettyRlpcErr msg = header +prettyRlpcMsg :: MsgEnvelope RlpcError -> String +prettyRlpcMsg m@(view msgSeverity -> SevDebug) = prettyRlpcDebugMsg m +prettyRlpcMsg m = render $ docRlpcErr m + +prettyRlpcDebugMsg :: MsgEnvelope RlpcError -> String +prettyRlpcDebugMsg (view msgDiagnostic -> Text ts) = + T.unpack . foldMap (`T.snoc` '\n') $ ts + +docRlpcErr :: MsgEnvelope RlpcError -> Doc +docRlpcErr msg = header $$ nest 2 bullets $$ source where @@ -177,6 +188,9 @@ type CompilerFlag = String makeLenses ''RLPCOptions pure [] +addDebugMsg :: (Monad m, IsText e) => e -> RLPCT m () +addDebugMsg e = addWound . debugMsg $ Text [e ^. unpacked . packed] + -- TODO: rewrite this with prisms once microlens-pro drops :3 whenDFlag :: (Monad m) => DebugFlag -> RLPCT m () -> RLPCT m () whenDFlag f m = do diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index 9530b2e..f44b1ca 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -10,6 +10,7 @@ module Compiler.RlpcError , msgSeverity , liftRlpcErrors , errorMsg + , debugMsg -- * Located Comonad , Located(..) , SrcSpan(..) @@ -46,6 +47,7 @@ instance IsRlpcError RlpcError where data Severity = SevWarning | SevError + | SevDebug deriving Show makeLenses ''MsgEnvelope @@ -65,3 +67,11 @@ errorMsg s e = MsgEnvelope , _msgSeverity = SevError } +debugMsg :: e -> MsgEnvelope e +debugMsg e = MsgEnvelope + -- TODO: not pretty, but it is a debug message after all + { _msgSpan = SrcSpan 0 0 0 0 + , _msgDiagnostic = e + , _msgSeverity = SevDebug + } + diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index f24042b..0d70585 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -13,6 +13,7 @@ module Control.Monad.Errorful where ---------------------------------------------------------------------------------- import Control.Monad.State.Strict +import Control.Monad.Reader import Control.Monad.Trans import Data.Functor.Identity import Data.Coerce @@ -76,7 +77,7 @@ mapErrorful f (ErrorfulT m) = ErrorfulT $ -------------------------------------------------------------------------------- -- daily dose of n^2 instances -instance (Monad m, MonadErrorful e m) => MonadErrorful e (StateT s m) where - addWound = undefined - addFatal = undefined +instance (Monad m, MonadErrorful e m) => MonadErrorful e (ReaderT r m) where + addWound = lift . addWound + addFatal = lift . addFatal diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 5f4dc38..d89f60f 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -21,6 +21,7 @@ import Data.Functor.Identity import Core.Syntax import Core.Lex import Compiler.RLPC +import Control.Monad import Lens.Micro import Data.Default.Class (def) import Data.Hashable (Hashable) @@ -225,12 +226,17 @@ insScDef sc = programScDefs %~ (sc:) singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty -parseCoreProgR :: forall m. (Applicative m) => [Located CoreToken] -> RLPCT m Program' -parseCoreProgR = hoistRlpcT generalise . parseCoreProg +parseCoreProgR :: forall m. (Monad m) => [Located CoreToken] -> RLPCT m Program' +parseCoreProgR = ddumpast <=< (hoistRlpcT generalise . parseCoreProg) where generalise :: forall a. Identity a -> m a generalise (Identity a) = pure a + ddumpast :: Program' -> RLPCT m Program' + ddumpast p = do + whenDFlag "dump-ast" $ (addDebugMsg . show $ p) + pure p + happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b happyBind m k = m >>= k -- 2.52.0 From 7a6518583f251a3e94276b6128515535a67e66ac Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 11:57:37 -0700 Subject: [PATCH 130/192] debug tags --- src/Compiler/RLPC.hs | 111 +++++++++++++++++++++----------------- src/Compiler/RlpcError.hs | 8 +-- src/Core/Parse.y | 2 +- 3 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 90ee262..f7ed654 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -97,51 +97,6 @@ evalRLPCT opt r = runRLPCT r & flip runReaderT opt & runErrorfulT -evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a -evalRLPCIO opt r = do - (ma,es) <- evalRLPCT opt r - putRlpcErrs es - case ma of - Just x -> pure x - Nothing -> die "Failed, no code compiled." - -putRlpcErrs :: [MsgEnvelope RlpcError] -> IO () -putRlpcErrs = traverse_ (putStrLn . ('\n':) . prettyRlpcMsg) - -prettyRlpcMsg :: MsgEnvelope RlpcError -> String -prettyRlpcMsg m@(view msgSeverity -> SevDebug) = prettyRlpcDebugMsg m -prettyRlpcMsg m = render $ docRlpcErr m - -prettyRlpcDebugMsg :: MsgEnvelope RlpcError -> String -prettyRlpcDebugMsg (view msgDiagnostic -> Text ts) = - T.unpack . foldMap (`T.snoc` '\n') $ ts - -docRlpcErr :: MsgEnvelope RlpcError -> Doc -docRlpcErr msg = header - $$ nest 2 bullets - $$ source - where - source = vcat $ zipWith (<+>) rule srclines - where - rule = repeat (ttext . Ansi.blue . Ansi.bold $ "|") - srclines = ["", "", ""] - filename = msgColour "" - pos = msgColour $ tshow (msg ^. msgSpan . srcspanLine) - <> ":" - <> tshow (msg ^. msgSpan . srcspanColumn) - - header = ttext $ filename <> msgColour ":" <> pos <> msgColour ": " - <> errorColour "error" <> msgColour ":" - - bullets = let Text ts = msg ^. msgDiagnostic - in vcat $ hang "•" 2 . ttext . msgColour <$> ts - - msgColour = Ansi.white . Ansi.bold - errorColour = Ansi.red . Ansi.bold - ttext = text . T.unpack - tshow :: (Show a) => a -> Text - tshow = T.pack . show - liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e) @@ -181,15 +136,15 @@ instance Default RLPCOptions where } -- debug flags are passed with -dFLAG -type DebugFlag = String +type DebugFlag = Text -type CompilerFlag = String +type CompilerFlag = Text makeLenses ''RLPCOptions pure [] -addDebugMsg :: (Monad m, IsText e) => e -> RLPCT m () -addDebugMsg e = addWound . debugMsg $ Text [e ^. unpacked . packed] +addDebugMsg :: (Monad m, IsText e) => Text -> e -> RLPCT m () +addDebugMsg tag e = addWound . debugMsg tag $ Text [e ^. unpacked . packed] -- TODO: rewrite this with prisms once microlens-pro drops :3 whenDFlag :: (Monad m) => DebugFlag -> RLPCT m () -> RLPCT m () @@ -206,3 +161,61 @@ whenFFlag f m = do let a = S.member f fs when a m +-------------------------------------------------------------------------------- + +evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a +evalRLPCIO opt r = do + (ma,es) <- evalRLPCT opt r + putRlpcErrs opt es + case ma of + Just x -> pure x + Nothing -> die "Failed, no code compiled." + +putRlpcErrs :: RLPCOptions -> [MsgEnvelope RlpcError] -> IO () +putRlpcErrs opts = filter byTag + >>> traverse_ (putStrLn . ('\n':) . prettyRlpcMsg) + where + dflags = opts ^. rlpcDFlags + + byTag :: MsgEnvelope RlpcError -> Bool + byTag (view msgSeverity -> SevDebug t) = + t `S.member` dflags + +prettyRlpcMsg :: MsgEnvelope RlpcError -> String +prettyRlpcMsg m@(view msgSeverity -> SevDebug _) = prettyRlpcDebugMsg m +prettyRlpcMsg m = render $ docRlpcErr m + +prettyRlpcDebugMsg :: MsgEnvelope RlpcError -> String +prettyRlpcDebugMsg msg = + T.unpack . foldMap mkLine $ ts + where + mkLine s = tag <> ": " <> s <> "\n" + Text ts = msg ^. msgDiagnostic + SevDebug tag = msg ^. msgSeverity + +docRlpcErr :: MsgEnvelope RlpcError -> Doc +docRlpcErr msg = header + $$ nest 2 bullets + $$ source + where + source = vcat $ zipWith (<+>) rule srclines + where + rule = repeat (ttext . Ansi.blue . Ansi.bold $ "|") + srclines = ["", "", ""] + filename = msgColour "" + pos = msgColour $ tshow (msg ^. msgSpan . srcspanLine) + <> ":" + <> tshow (msg ^. msgSpan . srcspanColumn) + + header = ttext $ filename <> msgColour ":" <> pos <> msgColour ": " + <> errorColour "error" <> msgColour ":" + + bullets = let Text ts = msg ^. msgDiagnostic + in vcat $ hang "•" 2 . ttext . msgColour <$> ts + + msgColour = Ansi.white . Ansi.bold + errorColour = Ansi.red . Ansi.bold + ttext = text . T.unpack + tshow :: (Show a) => a -> Text + tshow = T.pack . show + diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index f44b1ca..a590a85 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -47,7 +47,7 @@ instance IsRlpcError RlpcError where data Severity = SevWarning | SevError - | SevDebug + | SevDebug Text deriving Show makeLenses ''MsgEnvelope @@ -67,11 +67,11 @@ errorMsg s e = MsgEnvelope , _msgSeverity = SevError } -debugMsg :: e -> MsgEnvelope e -debugMsg e = MsgEnvelope +debugMsg :: Text -> e -> MsgEnvelope e +debugMsg tag e = MsgEnvelope -- TODO: not pretty, but it is a debug message after all { _msgSpan = SrcSpan 0 0 0 0 , _msgDiagnostic = e - , _msgSeverity = SevDebug + , _msgSeverity = SevDebug tag } diff --git a/src/Core/Parse.y b/src/Core/Parse.y index d89f60f..20ee3eb 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -234,7 +234,7 @@ parseCoreProgR = ddumpast <=< (hoistRlpcT generalise . parseCoreProg) ddumpast :: Program' -> RLPCT m Program' ddumpast p = do - whenDFlag "dump-ast" $ (addDebugMsg . show $ p) + addDebugMsg "dump-ast" . show $ p pure p happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b -- 2.52.0 From ff5a5af9bc3de4f2d0cc12304fed4abe118e347b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 12:14:43 -0700 Subject: [PATCH 131/192] -ddump-eval --- src/Compiler/RLPC.hs | 4 ++-- src/GM.hs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index f7ed654..54719a9 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -187,9 +187,9 @@ prettyRlpcMsg m = render $ docRlpcErr m prettyRlpcDebugMsg :: MsgEnvelope RlpcError -> String prettyRlpcDebugMsg msg = - T.unpack . foldMap mkLine $ ts + T.unpack . foldMap mkLine $ [ t' | t <- ts, t' <- T.lines t ] where - mkLine s = tag <> ": " <> s <> "\n" + mkLine s = "-d" <> tag <> ": " <> s <> "\n" Text ts = msg ^. msgDiagnostic SevDebug tag = msg ^. msgSeverity diff --git a/src/GM.hs b/src/GM.hs index 065cb08..216672d 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -8,6 +8,7 @@ Description : The G-Machine module GM ( hdbgProg , evalProg + , evalProgR , Node(..) , gmEvalProg , finalStateOf @@ -34,6 +35,7 @@ import System.IO (Handle, hPutStrLn) import Data.String (IsString) import Data.Heap import Debug.Trace +import Compiler.RLPC import Core2Core import Core ---------------------------------------------------------------------------------- @@ -156,6 +158,21 @@ hdbgProg p hio = do [resAddr] = final ^. gmStack res = hLookupUnsafe resAddr h +evalProgR :: (Monad m) => Program' -> RLPCT m (Node, Stats) +evalProgR p = do + (renderOut . showState) `traverse_` states + renderOut . showStats $ sts + pure (res, sts) + where + renderOut r = addDebugMsg "dump-eval" $ render r ++ "\n" + states = eval . compile $ p + final = last states + + sts = final ^. gmStats + -- the address of the result should be the one and only stack entry + [resAddr] = final ^. gmStack + res = hLookupUnsafe resAddr (final ^. gmHeap) + eval :: GmState -> [GmState] eval st = st : rest where -- 2.52.0 From 77f2f900d8bfe373aded590a23f7abbc705994e5 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 15:24:16 -0700 Subject: [PATCH 132/192] core driver --- README.md | 2 +- app/CoreDriver.hs | 15 +++++++++------ app/Main.hs | 8 -------- app/RlpDriver.hs | 11 +++++++++++ rlp.cabal | 8 ++++---- src/Compiler/RLPC.hs | 17 +++++++++++++++++ 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 4b010ec..ef70c2d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ $ cabal test --test-show-details=direct $ rlpc -ddump-eval examples/factorial.hs # Compile and evaluate t.hs, with evaluation info dumped to t.log $ rlpc -ddump-eval -l t.log t.hs -# Print the raw structure describing the compiler options and die +# Print the raw structure describing the compiler options # (option parsing still must succeed in order to print) $ rlpc -ddump-opts t.hs ``` diff --git a/app/CoreDriver.hs b/app/CoreDriver.hs index ba546c9..56ec299 100644 --- a/app/CoreDriver.hs +++ b/app/CoreDriver.hs @@ -3,12 +3,15 @@ module CoreDriver ) where -------------------------------------------------------------------------------- +import Compiler.RLPC +import Control.Monad + +import Core.Lex +import Core.Parse +import GM +-------------------------------------------------------------------------------- driver :: RLPCIO () -driver = undefined - -parseProg :: RLPCOptions - -> Text - -> (Maybe Program', [MsgEnvelope RlpcError]) -parseProg o = lexCoreR >=> parseCoreProgR +driver = forFiles_ $ \f -> + withSource f (lexCoreR >=> parseCoreProgR >=> evalProgR) diff --git a/app/Main.hs b/app/Main.hs index 440789c..ea31543 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -107,11 +107,3 @@ driver = view rlpcLanguage >>= \case LanguageCore -> CoreDriver.driver LanguageRlp -> RlpDriver.driver -forFiles_ :: (Monad m) - => (RLPCOptions -> FilePath -> RLPCT m a) - -> RLPCT m () -forFiles_ k = do - fs <- view rlpcInputFiles - o <- ask - forM_ fs (k o) - diff --git a/app/RlpDriver.hs b/app/RlpDriver.hs index e69de29..3df1b24 100644 --- a/app/RlpDriver.hs +++ b/app/RlpDriver.hs @@ -0,0 +1,11 @@ +module RlpDriver + ( driver + ) + where +-------------------------------------------------------------------------------- +import Compiler.RLPC +-------------------------------------------------------------------------------- + +driver :: RLPCIO () +driver = undefined + diff --git a/rlp.cabal b/rlp.cabal index b813073..daad383 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -38,8 +38,7 @@ library , Rlp.Lex , Rlp.Parse.Types , Compiler.Types - - other-modules: Data.Heap + , Data.Heap , Data.Pretty , Core.Parse , Core.Lex @@ -86,8 +85,9 @@ library executable rlpc import: warnings main-is: Main.hs - -- other-modules: - -- other-extensions: + other-modules: RlpDriver + , CoreDriver + build-depends: base >=4.17.0.0 && <4.20.0.0 , rlp , optparse-applicative >= 0.18.1 && < 0.19 diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 54719a9..5468223 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -33,6 +33,8 @@ module Compiler.RLPC , MsgEnvelope(..), Severity(..) , addDebugMsg , whenDFlag, whenFFlag + -- * Misc. Utilities + , forFiles_, withSource -- * Convenient re-exports , addFatal, addWound, def ) @@ -58,6 +60,7 @@ import Data.HashSet qualified as S import Data.Coerce import Data.Text (Text) import Data.Text qualified as T +import Data.Text.IO qualified as T import Text.ANSI qualified as Ansi import Text.PrettyPrint hiding ((<>)) import Lens.Micro.Platform @@ -219,3 +222,17 @@ docRlpcErr msg = header tshow :: (Show a) => a -> Text tshow = T.pack . show +-------------------------------------------------------------------------------- + +forFiles_ :: (Monad m) + => (FilePath -> RLPCT m a) + -> RLPCT m () +forFiles_ k = do + fs <- view rlpcInputFiles + forM_ fs k + +-- TODO: catch any exceptions, i.e. non-existent files should be handled by the +-- compiler +withSource :: (MonadIO m) => FilePath -> (Text -> RLPCT m a) -> RLPCT m a +withSource f k = liftIO (T.readFile f) >>= k + -- 2.52.0 From c9d1ca51f5d2375da11cbf2c7976b2db06d1b637 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 1 Feb 2024 18:15:40 -0700 Subject: [PATCH 133/192] XRec fix --- README.md | 12 +++++------ app/Main.hs | 2 ++ rlp.cabal | 1 + src/Rlp/Parse/Types.hs | 2 +- src/Rlp/Syntax.hs | 48 ++++++++++++++++++++++++------------------ src/Rlp2Core.hs | 40 +++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 src/Rlp2Core.hs diff --git a/README.md b/README.md index ef70c2d..2fa2b72 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,8 @@ Listed in order of importance. - [x] Garbage Collection - [ ] Emitter - [ ] Code-gen (target yet to be decided) - - [ ] Core language emitter - - [ ] Core linter (Type-checker) - - [ ] Core2Core pass + - [x] Core linter (Type-checker) + - [ ] Core2Core pass (optimisations and misc. preprocessing) - [x] GM prep - [x] Non-strict case-floating - [ ] Let-floating @@ -101,9 +100,10 @@ Listed in order of importance. ### January Release Plan - [ ] Beta rl' to Core - [ ] UX improvements - - [ ] Actual compiler errors -- no more unexceptional `error` calls - - [ ] Better CLI dump flags - - [ ] Annotate the AST with token positions for errors + - [x] Actual compiler errors -- no more unexceptional `error` calls + - [x] Better CLI dump flags + - [ ] Annotate the AST with token positions for errors (NOTE: As of Feb. 1, + this has been done, but the locational info is not yet used in error messages) - [ ] More examples ### March Release Plan diff --git a/app/Main.hs b/app/Main.hs index ea31543..524b590 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -68,6 +68,8 @@ options = RLPCOptions <*> option languageReader ( long "language" <> short 'x' + <> metavar "rlp|core" + <> help "the language to be compiled -- see README" ) <*> some (argument str $ metavar "FILES...") where diff --git a/rlp.cabal b/rlp.cabal index daad383..5e1b05d 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -43,6 +43,7 @@ library , Core.Parse , Core.Lex , Core2Core + , Rlp2Core , Control.Monad.Utils build-tool-depends: happy:happy, alex:alex diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 77c6519..ce53274 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -52,7 +52,7 @@ import Compiler.Types data RlpcPs -type instance XRec RlpcPs f = Located (f RlpcPs) +type instance XRec RlpcPs a = Located a type instance IdP RlpcPs = PsName type instance XFunD RlpcPs = () diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 9403e50..16ffe2e 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -8,6 +8,7 @@ module Rlp.Syntax ( -- * AST RlpProgram(..) + , progDecls , Decl(..), Decl', RlpExpr(..), RlpExpr' , Pat(..), Pat' , Assoc(..) @@ -53,15 +54,20 @@ data RlpModule p = RlpModule -- | dear god. type PhaseShow p = - ( Show (XRec p Pat), Show (XRec p RlpExpr) - , Show (XRec p Lit), Show (IdP p) - , Show (XRec p RlpType) - , Show (XRec p Binding) + ( Show (XRec p (Pat p)), Show (XRec p (RlpExpr p)) + , Show (XRec p (Lit p)), Show (IdP p) + , Show (XRec p (RlpType p)) + , Show (XRec p (Binding p)) ) newtype RlpProgram p = RlpProgram [Decl' p] -deriving instance (PhaseShow p, Show (XRec p Decl)) => Show (RlpProgram p) +progDecls :: Lens' (RlpProgram p) [Decl' p] +progDecls = lens + (\ (RlpProgram ds) -> ds) + (const RlpProgram) + +deriving instance (PhaseShow p, Show (XRec p (Decl p))) => Show (RlpProgram p) data RlpType p = FunConT | FunT (RlpType' p) (RlpType' p) @@ -69,7 +75,7 @@ data RlpType p = FunConT | VarT (IdP p) | ConT (IdP p) -type RlpType' p = XRec p RlpType +type RlpType' p = XRec p (RlpType p) deriving instance (PhaseShow p) => Show (RlpType p) @@ -95,11 +101,11 @@ type family XInfixD p type family XXDeclD p pattern FunD :: (XFunD p ~ ()) - => (IdP p) -> [Pat' p] -> (RlpExpr' p) -> (Maybe (Where p)) + => IdP p -> [Pat' p] -> RlpExpr' p -> Maybe (Where p) -> Decl p -pattern TySigD :: (XTySigD p ~ ()) => [IdP p] -> (RlpType' p) -> Decl p -pattern DataD :: (XDataD p ~ ()) => (IdP p) -> [IdP p] -> [ConAlt p] -> Decl p -pattern InfixD :: (XInfixD p ~ ()) => Assoc -> Int -> (IdP p) -> Decl p +pattern TySigD :: (XTySigD p ~ ()) => [IdP p] -> RlpType' p -> Decl p +pattern DataD :: (XDataD p ~ ()) => IdP p -> [IdP p] -> [ConAlt p] -> Decl p +pattern InfixD :: (XInfixD p ~ ()) => Assoc -> Int -> IdP p -> Decl p pattern XDeclD :: (XXDeclD p ~ ()) => Decl p pattern FunD n as e wh = FunD' () n as e wh @@ -108,7 +114,7 @@ pattern DataD n as cs = DataD' () n as cs pattern InfixD a p n = InfixD' () a p n pattern XDeclD = XDeclD' () -type Decl' p = XRec p Decl +type Decl' p = XRec p (Decl p) data Assoc = InfixL | InfixR @@ -117,7 +123,7 @@ data Assoc = InfixL data ConAlt p = ConAlt (IdP p) [RlpType' p] -deriving instance (Show (IdP p), Show (XRec p RlpType)) => Show (ConAlt p) +deriving instance (Show (IdP p), Show (XRec p (RlpType p))) => Show (ConAlt p) data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) | VarE' (XVarE p) (IdP p) @@ -171,15 +177,15 @@ deriving instance , PhaseShow p ) => Show (RlpExpr p) -type RlpExpr' p = XRec p RlpExpr +type RlpExpr' p = XRec p (RlpExpr p) class UnXRec p where - unXRec :: XRec p f -> f p + unXRec :: XRec p a -> a class MapXRec p where - mapXRec :: (f p -> f' p') -> XRec p f -> XRec p' f' + mapXRec :: (a -> b) -> XRec p a -> XRec p b -type family XRec p (f :: Type -> Type) = (r :: Type) | r -> p f +type family XRec p a = (r :: Type) | r -> p a type family IdP p @@ -193,9 +199,9 @@ deriving instance (PhaseShow p) => Show (Alt p) data Binding p = PatB (Pat' p) (RlpExpr' p) | FunB (IdP p) [Pat' p] (RlpExpr' p) -type Binding' p = XRec p Binding +type Binding' p = XRec p (Binding p) -deriving instance (Show (XRec p Pat), Show (XRec p RlpExpr), Show (IdP p) +deriving instance (Show (XRec p (Pat p)), Show (XRec p (RlpExpr p)), Show (IdP p) ) => Show (Binding p) data Pat p = VarP (IdP p) @@ -204,7 +210,7 @@ data Pat p = VarP (IdP p) deriving instance (PhaseShow p) => Show (Pat p) -type Pat' p = XRec p Pat +type Pat' p = XRec p (Pat p) data Lit p = IntL Int | CharL Char @@ -212,7 +218,7 @@ data Lit p = IntL Int deriving instance (PhaseShow p) => Show (Lit p) -type Lit' p = XRec p Lit +type Lit' p = XRec p (Lit p) -- instance HasLHS Alt Alt Pat Pat where -- _lhs = lens @@ -224,7 +230,7 @@ type Lit' p = XRec p Lit -- (\ (AltA _ e) -> e) -- (\ (AltA p _) e' -> AltA p e') -makeBaseFunctor ''RlpExpr +-- makeBaseFunctor ''RlpExpr -- showsTernaryWith :: (Int -> x -> ShowS) -- -> (Int -> y -> ShowS) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs new file mode 100644 index 0000000..c17ff64 --- /dev/null +++ b/src/Rlp2Core.hs @@ -0,0 +1,40 @@ +module Rlp2Core + ( rlpProgToCore + ) + where +-------------------------------------------------------------------------------- +import Control.Monad +import Control.Monad.Writer.CPS +import Lens.Micro +import Lens.Micro.Internal +import Data.Text (Text) +import Data.Text qualified as T +import Data.HashMap.Strict qualified as H + +import Core.Syntax as Core +import Rlp.Syntax as Rlp +import Rlp.Parse.Types (RlpcPs) +-------------------------------------------------------------------------------- + +rlpProgToCore :: RlpProgram RlpcPs -> Program' +rlpProgToCore = foldMapOf (progDecls . each) declToCore + +declToCore :: Decl' RlpcPs -> Program' + +declToCore = undefined + +-- declToCore (TySigD ns t) = +-- mempty & programTypeSigs .~ H.fromList [ (n, typeToCore t) | n <- ns ] + +typeToCore :: RlpType RlpcPs -> Type +typeToCore = undefined +-- typeToCore FunConT = TyFun +-- typeToCore (FunT s t) = typeToCore s :-> typeToCore t +-- typeToCore (AppT s t) = TyApp (typeToCore s) (typeToCore t) +-- typeToCore (ConT n) = TyCon (dsNameToName n) +-- typeToCore (VarT x) = TyVar (dsNameToName x) + +-- | Forwards-compatiblity if IdP RlpDs is changed +dsNameToName :: IdP RlpcPs -> Name +dsNameToName = id + -- 2.52.0 From 38d1044f5da18763f0971721c8b53e944692d3d4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 2 Feb 2024 15:10:04 -0700 Subject: [PATCH 134/192] rlp2core base --- src/Rlp/Parse/Types.hs | 7 ++++++ src/Rlp/Syntax.hs | 49 +++++++++++++++++++++++++++++++++++++----- src/Rlp2Core.hs | 19 +++++++--------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index ce53274..93ca70f 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -31,6 +31,7 @@ import Core.Syntax (Name) import Control.Monad import Control.Monad.State.Strict import Control.Monad.Errorful +import Control.Comonad (extract) import Compiler.RlpcError import Data.Text (Text) import Data.Maybe @@ -73,6 +74,12 @@ type instance XOAppE RlpcPs = () type PsName = Text +instance MapXRec RlpcPs where + mapXRec = fmap + +instance UnXRec RlpcPs where + unXRec = extract + -------------------------------------------------------------------------------- spanFromPos :: Position -> Int -> SrcSpan diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 16ffe2e..4eeed20 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -1,7 +1,7 @@ -- recursion-schemes {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable , TemplateHaskell, TypeFamilies #-} -{-# LANGUAGE OverloadedStrings, PatternSynonyms #-} +{-# LANGUAGE OverloadedStrings, PatternSynonyms, ViewPatterns #-} {-# LANGUAGE TypeFamilies, TypeFamilyDependencies #-} {-# LANGUAGE UndecidableInstances, ImpredicativeTypes #-} module Rlp.Syntax @@ -28,10 +28,14 @@ module Rlp.Syntax -- ** Pattern synonyms -- *** Decl , pattern FunD, pattern TySigD, pattern InfixD, pattern DataD + , pattern FunD'', pattern TySigD'', pattern InfixD'', pattern DataD'' -- *** RlpExpr , pattern LetE, pattern VarE, pattern LamE, pattern CaseE, pattern IfE , pattern AppE, pattern LitE, pattern ParE, pattern OAppE , pattern XRlpExprE + -- *** RlpType + , pattern FunConT'', pattern FunT'', pattern AppT'', pattern VarT'' + , pattern ConT'' ) where ---------------------------------------------------------------------------------- @@ -40,6 +44,7 @@ import Data.Text qualified as T import Data.String (IsString(..)) import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes +import Data.Functor.Identity import Data.Kind (Type) import Lens.Micro import Lens.Micro.TH @@ -77,6 +82,18 @@ data RlpType p = FunConT type RlpType' p = XRec p (RlpType p) +pattern FunConT'' :: (UnXRec p) => RlpType' p +pattern FunT'' :: (UnXRec p) => RlpType' p -> RlpType' p -> RlpType' p +pattern AppT'' :: (UnXRec p) => RlpType' p -> RlpType' p -> RlpType' p +pattern VarT'' :: (UnXRec p) => IdP p -> RlpType' p +pattern ConT'' :: (UnXRec p) => IdP p -> RlpType' p + +pattern FunConT'' <- (unXRec -> FunConT) +pattern FunT'' s t <- (unXRec -> FunT s t) +pattern AppT'' s t <- (unXRec -> AppT s t) +pattern VarT'' n <- (unXRec -> VarT n) +pattern ConT'' n <- (unXRec -> ConT n) + deriving instance (PhaseShow p) => Show (RlpType p) @@ -109,10 +126,25 @@ pattern InfixD :: (XInfixD p ~ ()) => Assoc -> Int -> IdP p -> Decl p pattern XDeclD :: (XXDeclD p ~ ()) => Decl p pattern FunD n as e wh = FunD' () n as e wh -pattern TySigD ns t = TySigD' () ns t -pattern DataD n as cs = DataD' () n as cs -pattern InfixD a p n = InfixD' () a p n -pattern XDeclD = XDeclD' () +pattern TySigD ns t = TySigD' () ns t +pattern DataD n as cs = DataD' () n as cs +pattern InfixD a p n = InfixD' () a p n +pattern XDeclD = XDeclD' () + +pattern FunD'' :: (UnXRec p) + => IdP p -> [Pat' p] -> RlpExpr' p -> Maybe (Where p) + -> Decl' p +pattern TySigD'' :: (UnXRec p) + => [IdP p] -> RlpType' p -> Decl' p +pattern DataD'' :: (UnXRec p) + => IdP p -> [IdP p] -> [ConAlt p] -> Decl' p +pattern InfixD'' :: (UnXRec p) + => Assoc -> Int -> IdP p -> Decl' p + +pattern FunD'' n as e wh <- (unXRec -> FunD' _ n as e wh) +pattern TySigD'' ns t <- (unXRec -> TySigD' _ ns t) +pattern DataD'' n as ds <- (unXRec -> DataD' _ n as ds) +pattern InfixD'' a p n <- (unXRec -> InfixD' _ a p n) type Decl' p = XRec p (Decl p) @@ -185,6 +217,8 @@ class UnXRec p where class MapXRec p where mapXRec :: (a -> b) -> XRec p a -> XRec p b +-- old definition: +-- type family XRec p (f :: Type -> Type) = (r :: Type) | r -> p f type family XRec p a = (r :: Type) | r -> p a type family IdP p @@ -248,3 +282,8 @@ type Lit' p = XRec p (Lit p) makeLenses ''RlpModule +-------------------------------------------------------------------------------- + +-- stripLocation :: (UnXRec p) => XRec p a -> f NoLocated +-- stripLocation p = undefined + diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index c17ff64..5210806 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -21,18 +21,15 @@ rlpProgToCore = foldMapOf (progDecls . each) declToCore declToCore :: Decl' RlpcPs -> Program' -declToCore = undefined +declToCore (TySigD'' ns t) = + mempty & programTypeSigs .~ H.fromList [ (n, typeToCore t) | n <- ns ] --- declToCore (TySigD ns t) = --- mempty & programTypeSigs .~ H.fromList [ (n, typeToCore t) | n <- ns ] - -typeToCore :: RlpType RlpcPs -> Type -typeToCore = undefined --- typeToCore FunConT = TyFun --- typeToCore (FunT s t) = typeToCore s :-> typeToCore t --- typeToCore (AppT s t) = TyApp (typeToCore s) (typeToCore t) --- typeToCore (ConT n) = TyCon (dsNameToName n) --- typeToCore (VarT x) = TyVar (dsNameToName x) +typeToCore :: RlpType' RlpcPs -> Type +typeToCore FunConT'' = TyFun +typeToCore (FunT'' s t) = typeToCore s :-> typeToCore t +typeToCore (AppT'' s t) = TyApp (typeToCore s) (typeToCore t) +typeToCore (ConT'' n) = TyCon (dsNameToName n) +typeToCore (VarT'' x) = TyVar (dsNameToName x) -- | Forwards-compatiblity if IdP RlpDs is changed dsNameToName :: IdP RlpcPs -> Name -- 2.52.0 From 21d13ea73ba078c34d516bc63bd81c8b2b742bab Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 2 Feb 2024 19:15:39 -0700 Subject: [PATCH 135/192] ccoool --- src/Core/Syntax.hs | 11 +++++++++-- src/Rlp2Core.hs | 27 +++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index b624e43..cad53be 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -59,8 +59,9 @@ import Data.Char import GHC.Generics -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) -import Lens.Micro.TH (makeLenses) -import Lens.Micro +-- import Lens.Micro.TH (makeLenses) +-- import Lens.Micro +import Control.Lens ---------------------------------------------------------------------------------- data Expr b = Var Name @@ -152,6 +153,12 @@ makeLenses ''Program makeBaseFunctor ''Expr pure [] +-- this is a weird optic, stronger than Lens and Prism, but weaker than Iso. +programTypeSigsP :: (Hashable b) => Prism' (Program b) (HashMap b Type) +programTypeSigsP = prism + (\b -> mempty & programTypeSigs .~ b) + (Right . view programTypeSigs) + type ExprF' = ExprF Name type Program' = Program Name diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 5210806..a4974d9 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -5,24 +5,47 @@ module Rlp2Core -------------------------------------------------------------------------------- import Control.Monad import Control.Monad.Writer.CPS +import Control.Arrow +import Control.Applicative import Lens.Micro import Lens.Micro.Internal import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H +import Data.Monoid (Endo(..)) +import Data.Foldable import Core.Syntax as Core import Rlp.Syntax as Rlp import Rlp.Parse.Types (RlpcPs) -------------------------------------------------------------------------------- +-- the rl' program is desugared by desugaring each declaration as a separate +-- program, and taking the monoidal product of the lot :3 + rlpProgToCore :: RlpProgram RlpcPs -> Program' rlpProgToCore = foldMapOf (progDecls . each) declToCore declToCore :: Decl' RlpcPs -> Program' -declToCore (TySigD'' ns t) = - mempty & programTypeSigs .~ H.fromList [ (n, typeToCore t) | n <- ns ] +declToCore (TySigD'' ns t) = mempty & + programTypeSigs .~ H.fromList [ (n, typeToCore t) | n <- ns ] + +declToCore (DataD'' n as ds) = fold . getZipList $ + constructorToCore t' <$> ZipList [0..] <*> ZipList ds + where + -- create the appropriate type from the declared constructor and its + -- arguments + t' = foldl TyApp (TyCon n) (TyVar . dsNameToName <$> as) + +declToCore (FunD'' n as e wh) = mempty & + +constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' +constructorToCore t tag (ConAlt cn as) = + mempty & programTypeSigs . at cn ?~ foldr (:->) t as' + & programDataTags . at cn ?~ (tag, length as) + where + as' = typeToCore <$> as typeToCore :: RlpType' RlpcPs -> Type typeToCore FunConT'' = TyFun -- 2.52.0 From 0fc82f3fa8c1076f2bcb6e196457557ccde96bec Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 4 Feb 2024 18:59:48 -0700 Subject: [PATCH 136/192] something --- src/Rlp/Syntax.hs | 25 ++++++++++++++++++++++--- src/Rlp/TH.hs | 6 ++++++ src/Rlp2Core.hs | 18 ++++++++++++++---- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 src/Rlp/TH.hs diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 4eeed20..a3dd30c 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -11,6 +11,7 @@ module Rlp.Syntax , progDecls , Decl(..), Decl', RlpExpr(..), RlpExpr' , Pat(..), Pat' + , Alt(..) , Assoc(..) , Lit(..), Lit' , RlpType(..), RlpType' @@ -19,7 +20,7 @@ module Rlp.Syntax -- * Trees That Grow boilerplate -- ** Extension points - , IdP, XRec, UnXRec(..), MapXRec(..) + , IdP, IdP', XRec, UnXRec(..), MapXRec(..) -- *** Decl , XFunD, XTySigD, XInfixD, XDataD, XXDeclD -- *** RlpExpr @@ -36,6 +37,10 @@ module Rlp.Syntax -- *** RlpType , pattern FunConT'', pattern FunT'', pattern AppT'', pattern VarT'' , pattern ConT'' + -- *** Pat + , pattern VarP'', pattern LitP'', pattern ConP'' + -- ** NoLocated + , NoLocated ) where ---------------------------------------------------------------------------------- @@ -223,6 +228,8 @@ type family XRec p a = (r :: Type) | r -> p a type family IdP p +type IdP' p = XRec p (IdP p) + type Where p = [Binding p] -- do we want guards? @@ -242,6 +249,14 @@ data Pat p = VarP (IdP p) | LitP (Lit' p) | ConP (IdP p) [Pat' p] +pattern VarP'' :: (UnXRec p) => IdP p -> Pat' p +pattern LitP'' :: (UnXRec p) => Lit' p -> Pat' p +pattern ConP'' :: (UnXRec p) => IdP p -> [Pat' p] -> Pat' p + +pattern VarP'' n <- (unXRec -> VarP n) +pattern LitP'' l <- (unXRec -> LitP l) +pattern ConP'' c as <- (unXRec -> ConP c as) + deriving instance (PhaseShow p) => Show (Pat p) type Pat' p = XRec p (Pat p) @@ -284,6 +299,10 @@ makeLenses ''RlpModule -------------------------------------------------------------------------------- --- stripLocation :: (UnXRec p) => XRec p a -> f NoLocated --- stripLocation p = undefined +data NoLocated + +type instance XRec NoLocated a = Identity a + +stripLocation :: (UnXRec p) => XRec p a -> f NoLocated +stripLocation p = undefined diff --git a/src/Rlp/TH.hs b/src/Rlp/TH.hs new file mode 100644 index 0000000..5f62fe7 --- /dev/null +++ b/src/Rlp/TH.hs @@ -0,0 +1,6 @@ +module Rlp.TH + ( rlpProg + , rlpExpr + ) + where + diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index a4974d9..082b23e 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -7,17 +7,20 @@ import Control.Monad import Control.Monad.Writer.CPS import Control.Arrow import Control.Applicative -import Lens.Micro -import Lens.Micro.Internal +import Control.Comonad +-- import Lens.Micro +-- import Lens.Micro.Internal +import Control.Lens import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Monoid (Endo(..)) import Data.Foldable +import Data.Functor.Bind import Core.Syntax as Core import Rlp.Syntax as Rlp -import Rlp.Parse.Types (RlpcPs) +import Rlp.Parse.Types (RlpcPs, PsName) -------------------------------------------------------------------------------- -- the rl' program is desugared by desugaring each declaration as a separate @@ -38,7 +41,14 @@ declToCore (DataD'' n as ds) = fold . getZipList $ -- arguments t' = foldl TyApp (TyCon n) (TyVar . dsNameToName <$> as) -declToCore (FunD'' n as e wh) = mempty & +declToCore fd@(FunD'' n as e wh) = undefined + +caseify :: IdP' RlpcPs -> RlpExpr' RlpcPs -> Pat' RlpcPs + -> (RlpExpr RlpcPs, Pat RlpcPs) +caseify x e p = (e', p') where + p' = VarP (extract x) + e' = CaseE (VarE <$> x) [(alt, [])] + alt = AltA p e constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = -- 2.52.0 From b84992787cb5fc300dd533122021c5e44ee8f4bc Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 4 Feb 2024 19:19:37 -0700 Subject: [PATCH 137/192] rlp TH --- rlp.cabal | 1 + src/Compiler/Types.hs | 5 +++-- src/Rlp/Parse.y | 5 ++++- src/Rlp/Parse/Types.hs | 14 ++++++++++++++ src/Rlp/Syntax.hs | 3 ++- src/Rlp/TH.hs | 30 ++++++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 5e1b05d..5719560 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -37,6 +37,7 @@ library , Rlp.Parse.Associate , Rlp.Lex , Rlp.Parse.Types + , Rlp.TH , Compiler.Types , Data.Heap , Data.Pretty diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 79b7d8a..5814b58 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -15,11 +15,12 @@ import Control.Comonad import Data.Functor.Apply import Data.Functor.Bind import Control.Lens hiding ((<<~)) +import Language.Haskell.TH.Syntax (Lift) -------------------------------------------------------------------------------- -- | Token wrapped with a span (line, column, absolute, length) data Located a = Located SrcSpan a - deriving (Show, Functor) + deriving (Show, Lift, Functor) instance Apply Located where liftF2 f (Located sa p) (Located sb q) @@ -39,7 +40,7 @@ data SrcSpan = SrcSpan !Int -- ^ Column !Int -- ^ Absolute !Int -- ^ Length - deriving Show + deriving (Show, Lift) tupling :: Iso' SrcSpan (Int, Int, Int, Int) tupling = iso (\ (SrcSpan a b c d) -> (a,b,c,d)) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index a885f59..398d7a3 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -193,7 +193,10 @@ Con :: { Located PsName } { -parseRlpExprR = undefined +parseRlpExprR :: (Monad m) => Text -> RLPCT m (RlpExpr RlpcPs) +parseRlpExprR s = liftErrorful $ pToErrorful parseRlpExpr st + where + st = programInitState s parseRlpProgR :: (Monad m) => Text -> RLPCT m (RlpProgram RlpcPs) parseRlpProgR s = liftErrorful $ pToErrorful parseRlpProg st diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 93ca70f..e253fdd 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -33,6 +33,7 @@ import Control.Monad.State.Strict import Control.Monad.Errorful import Control.Comonad (extract) import Compiler.RlpcError +import Language.Haskell.TH.Syntax (Lift) import Data.Text (Text) import Data.Maybe import Data.Fix @@ -71,6 +72,7 @@ type instance XAppE RlpcPs = () type instance XLitE RlpcPs = () type instance XParE RlpcPs = () type instance XOAppE RlpcPs = () +type instance XXRlpExprE RlpcPs = () type PsName = Text @@ -275,3 +277,15 @@ initAlexInput s = AlexInput , _aiPos = (1,1,0) } +-------------------------------------------------------------------------------- + +deriving instance Lift (RlpProgram RlpcPs) +deriving instance Lift (Decl RlpcPs) +deriving instance Lift (Pat RlpcPs) +deriving instance Lift (Lit RlpcPs) +deriving instance Lift (RlpExpr RlpcPs) +deriving instance Lift (Binding RlpcPs) +deriving instance Lift (RlpType RlpcPs) +deriving instance Lift (Alt RlpcPs) +deriving instance Lift (ConAlt RlpcPs) + diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index a3dd30c..56dbcd8 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -51,6 +51,7 @@ import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes import Data.Functor.Identity import Data.Kind (Type) +import Language.Haskell.TH.Syntax (Lift) import Lens.Micro import Lens.Micro.TH import Core.Syntax hiding (Lit, Type, Binding, Binding') @@ -156,7 +157,7 @@ type Decl' p = XRec p (Decl p) data Assoc = InfixL | InfixR | Infix - deriving (Show) + deriving (Show, Lift) data ConAlt p = ConAlt (IdP p) [RlpType' p] diff --git a/src/Rlp/TH.hs b/src/Rlp/TH.hs index 5f62fe7..eb4d44c 100644 --- a/src/Rlp/TH.hs +++ b/src/Rlp/TH.hs @@ -3,4 +3,34 @@ module Rlp.TH , rlpExpr ) where +-------------------------------------------------------------------------------- +import Language.Haskell.TH +import Language.Haskell.TH.Syntax +import Language.Haskell.TH.Quote +import Data.Text (Text) +import Data.Text qualified as T +import Control.Monad.IO.Class +import Control.Monad + +import Compiler.RLPC +import Rlp.Parse +-------------------------------------------------------------------------------- + +rlpProg :: QuasiQuoter +rlpProg = mkqq parseRlpProgR + +rlpExpr :: QuasiQuoter +rlpExpr = mkqq parseRlpExprR + +mkq :: (Lift a) => (Text -> RLPCIO a) -> String -> Q Exp +mkq parse = evalAndParse >=> lift where + evalAndParse = liftIO . evalRLPCIO def . parse . T.pack + +mkqq :: (Lift a) => (Text -> RLPCIO a) -> QuasiQuoter +mkqq p = QuasiQuoter + { quoteExp = mkq p + , quotePat = error "rlp quasiquotes may only be used in expressions" + , quoteType = error "rlp quasiquotes may only be used in expressions" + , quoteDec = error "rlp quasiquotes may only be used in expressions" + } -- 2.52.0 From 4f9f00dfee3c2dcdc09cef73656a70d25139cb90 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Sun, 4 Feb 2024 20:52:23 -0700 Subject: [PATCH 138/192] sc --- src/Compiler/Types.hs | 5 +++++ src/Rlp2Core.hs | 26 ++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 5814b58..09c60f1 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -2,6 +2,7 @@ module Compiler.Types ( SrcSpan(..) , srcspanLine, srcspanColumn, srcspanAbs, srcspanLen , Located(..) + , nolo , (<<~), (<~>) -- * Re-exports @@ -52,6 +53,10 @@ srcspanColumn = tupling . _2 srcspanAbs = tupling . _3 srcspanLen = tupling . _4 +-- | debug tool +nolo :: a -> Located a +nolo = Located (SrcSpan 0 0 0 0) + instance Semigroup SrcSpan where SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where l = min la lb diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 082b23e..791946e 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -11,6 +11,7 @@ import Control.Comonad -- import Lens.Micro -- import Lens.Micro.Internal import Control.Lens +import Data.List (mapAccumL) import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H @@ -19,6 +20,7 @@ import Data.Foldable import Data.Functor.Bind import Core.Syntax as Core +import Compiler.Types import Rlp.Syntax as Rlp import Rlp.Parse.Types (RlpcPs, PsName) -------------------------------------------------------------------------------- @@ -41,14 +43,26 @@ declToCore (DataD'' n as ds) = fold . getZipList $ -- arguments t' = foldl TyApp (TyCon n) (TyVar . dsNameToName <$> as) -declToCore fd@(FunD'' n as e wh) = undefined +-- TODO: where-binds +declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e''] + where + n' = dsNameToName n + (e',as') = mapAccumL caseify (extract e) (names `zip` as) + e'' = exprToCore e' + names = [ nolo $ "$x_" <> tshow n | n <- [0..] ] + tshow = T.pack . show -caseify :: IdP' RlpcPs -> RlpExpr' RlpcPs -> Pat' RlpcPs - -> (RlpExpr RlpcPs, Pat RlpcPs) -caseify x e p = (e', p') where - p' = VarP (extract x) +-- mapAccumL :: Traversable t => (s -> a -> (s, b)) -> s -> t a -> (s, t b) + +caseify :: RlpExpr RlpcPs -> (IdP' RlpcPs, Pat' RlpcPs) + -> (RlpExpr RlpcPs, Name) +caseify e (x,p) = (e', x') where + x' = dsNameToName (extract x) e' = CaseE (VarE <$> x) [(alt, [])] - alt = AltA p e + alt = AltA p (nolo e) + +exprToCore :: RlpExpr RlpcPs -> Expr' +exprToCore = undefined constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = -- 2.52.0 From bd55efc5edf3a31240ead5ec269fb2e69ccf4748 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 10:52:01 -0700 Subject: [PATCH 139/192] expandableAlt --- .ghci | 9 +++++++++ rlp.cabal | 1 + src/Compiler/Types.hs | 4 ++++ src/Rlp/Syntax.hs | 18 +++++------------ src/Rlp2Core.hs | 47 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 63 insertions(+), 16 deletions(-) diff --git a/.ghci b/.ghci index 4d96080..21ffd96 100644 --- a/.ghci +++ b/.ghci @@ -1,5 +1,9 @@ +-- repl extensions :set -XOverloadedStrings +-------------------------------------------------------------------------------- + +-- happy/alex: override :r to rebuild parsers :set -package process :{ @@ -16,3 +20,8 @@ _reload_and_make _ = do :def! r _reload_and_make +-------------------------------------------------------------------------------- + +-- import rlpc quasiquoters +:m + Core.TH Rlp.TH + diff --git a/rlp.cabal b/rlp.cabal index 5719560..2f0d553 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -75,6 +75,7 @@ library , comonad , lens , text-ansi + , microlens-pro ^>=0.2.0 hs-source-dirs: src default-language: GHC2021 diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 09c60f1..5352850 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -2,6 +2,7 @@ module Compiler.Types ( SrcSpan(..) , srcspanLine, srcspanColumn, srcspanAbs, srcspanLen , Located(..) + , locating , nolo , (<<~), (<~>) @@ -57,6 +58,9 @@ srcspanLen = tupling . _4 nolo :: a -> Located a nolo = Located (SrcSpan 0 0 0 0) +locating :: Lens (Located a) (Located b) a b +locating = lens extract ($>) + instance Semigroup SrcSpan where SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where l = min la lb diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 56dbcd8..f44e989 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -18,6 +18,8 @@ module Rlp.Syntax , ConAlt(..) , Binding(..), Binding' + , _VarP, _LitP, _ConP + -- * Trees That Grow boilerplate -- ** Extension points , IdP, IdP', XRec, UnXRec(..), MapXRec(..) @@ -39,8 +41,6 @@ module Rlp.Syntax , pattern ConT'' -- *** Pat , pattern VarP'', pattern LitP'', pattern ConP'' - -- ** NoLocated - , NoLocated ) where ---------------------------------------------------------------------------------- @@ -52,8 +52,8 @@ import Data.Functor.Classes import Data.Functor.Identity import Data.Kind (Type) import Language.Haskell.TH.Syntax (Lift) -import Lens.Micro -import Lens.Micro.TH +import Lens.Micro.Pro +import Lens.Micro.Pro.TH import Core.Syntax hiding (Lit, Type, Binding, Binding') import Core (HasRHS(..), HasLHS(..)) ---------------------------------------------------------------------------------- @@ -297,13 +297,5 @@ type Lit' p = XRec p (Lit p) -------------------------------------------------------------------------------- makeLenses ''RlpModule - --------------------------------------------------------------------------------- - -data NoLocated - -type instance XRec NoLocated a = Identity a - -stripLocation :: (UnXRec p) => XRec p a -> f NoLocated -stripLocation p = undefined +makePrisms ''Pat diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 791946e..c0a59e8 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -52,8 +52,6 @@ declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e''] names = [ nolo $ "$x_" <> tshow n | n <- [0..] ] tshow = T.pack . show --- mapAccumL :: Traversable t => (s -> a -> (s, b)) -> s -> t a -> (s, t b) - caseify :: RlpExpr RlpcPs -> (IdP' RlpcPs, Pat' RlpcPs) -> (RlpExpr RlpcPs, Name) caseify e (x,p) = (e', x') where @@ -62,7 +60,50 @@ caseify e (x,p) = (e', x') where alt = AltA p (nolo e) exprToCore :: RlpExpr RlpcPs -> Expr' -exprToCore = undefined + +exprToCore (VarE n) = Var (dsNameToName n) + +exprToCore (CaseE e as) = undefined + +-- >>> pat1 = nolo $ ConP "C" [nolo $ ConP "P" []] +-- >>> expandableAlt "name" (AltA pat1 (nolo $ VarE "e")) +-- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") +-- +-- >>> pat2 = nolo $ ConP "C" [nolo $ VarP "p", nolo $ ConP "P" []] +-- >>> expandableAlt "name" (AltA pat2 (nolo $ VarE "e")) +-- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "p"),Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") +expandableAlt :: IdP RlpcPs -> Alt RlpcPs + -> Maybe (Pat RlpcPs, Pat RlpcPs, RlpExpr RlpcPs) +expandableAlt n (AltA c@(ConP'' cn as) e) = do + p <- nestedPat + let c' = ConP cn as' + pure (c', p, extract e) + where + l :: Lens' [Pat RlpcPs] (Maybe (Pat RlpcPs)) + l = atFound (has _ConP) + nestedPat = (unXRec <$> as) ^. l + as' = (unXRec <$> as) & l ?~ VarP n + & fmap nolo + +-- this is an illegal lens, and we're using it illegally. it's convenient :3 +-- TODO: adhere to the holy laws of the Lens Herself +atFound :: forall a. (a -> Bool) -> Lens' [a] (Maybe a) +atFound p = lens (find p) alter where + alter :: [a] -> Maybe a -> [a] + alter l Nothing = deleteFound l + alter l (Just x') = setFound x' l + + deleteFound :: [a] -> [a] + deleteFound [] = [] + deleteFound (x:xs) + | p x = xs + | otherwise = x : deleteFound xs + + setFound :: a -> [a] -> [a] + setFound _ [] = [] + setFound x' (x:xs) + | p x = x' : xs + | otherwise = x : setFound x' xs constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = -- 2.52.0 From 0c98bca174b58ac2a42d3e786ca03907c9654bb8 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 11:04:17 -0700 Subject: [PATCH 140/192] expandableAlt --- src/Rlp2Core.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index c0a59e8..ee9e0e0 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -74,13 +74,13 @@ exprToCore (CaseE e as) = undefined -- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "p"),Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") expandableAlt :: IdP RlpcPs -> Alt RlpcPs -> Maybe (Pat RlpcPs, Pat RlpcPs, RlpExpr RlpcPs) -expandableAlt n (AltA c@(ConP'' cn as) e) = do - p <- nestedPat - let c' = ConP cn as' - pure (c', p, extract e) +expandableAlt n (AltA c@(ConP'' cn as) e) = + nestedPat <&> (c', , extract e) where l :: Lens' [Pat RlpcPs] (Maybe (Pat RlpcPs)) l = atFound (has _ConP) + + c' = ConP cn as' nestedPat = (unXRec <$> as) ^. l as' = (unXRec <$> as) & l ?~ VarP n & fmap nolo -- 2.52.0 From 57f5206b16ac42bc35e5ab2a6f44a31cacdc76c4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 12:08:37 -0700 Subject: [PATCH 141/192] fix layout_let --- src/Rlp/Lex.x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index adc30f5..6552fdc 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -127,7 +127,7 @@ $white_no_nl+ ; { \n { beginPush bol } - "{" { explicitLBrace } + "{" { explicitLBrace `thenDo` popLexState } "in" { constToken TokenIn `thenDo` (popLexState *> popLayout) } () { doLayout } } -- 2.52.0 From 15884336f18d7077f3ef468d44aaeb7f53b5f405 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 13:04:36 -0700 Subject: [PATCH 142/192] parse case exprs --- src/Compiler/Types.hs | 9 ++++++++- src/Rlp/Lex.x | 15 +++++++++------ src/Rlp/Parse.y | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 5352850..7329844 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -4,7 +4,7 @@ module Compiler.Types , Located(..) , locating , nolo - , (<<~), (<~>) + , (<<~), (<~>), (<#>) -- * Re-exports , Comonad @@ -86,3 +86,10 @@ mc <~> ma = mc >>- \f -> ma =>> f infixl 4 <~> +-- this is getting silly + +(<#>) :: (Functor f) => f (a -> b) -> a -> f b +fab <#> a = fmap ($ a) fab + +infixl 4 <#> + diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 6552fdc..4222694 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -85,6 +85,7 @@ $white_no_nl+ ; <0> { "let" { constToken TokenLet `thenBeginPush` layout_let } + "of" { constToken TokenOf `thenBeginPush` layout_of } } -- scan various identifiers and reserved words. order is important here! @@ -124,18 +125,19 @@ $white_no_nl+ ; () { doBol } } - + { \n { beginPush bol } "{" { explicitLBrace `thenDo` popLexState } - "in" { constToken TokenIn `thenDo` (popLexState *> popLayout) } - () { doLayout } } - + +{ + "in" { constToken TokenIn `thenDo` (popLexState *> popLayout) } +} + + { - \n ; - "{" { explicitLBrace `thenDo` popLexState } () { doLayout } } @@ -157,6 +159,7 @@ lexReservedOp = \case "=" -> TokenEquals "::" -> TokenHasType "|" -> TokenPipe + "->" -> TokenArrow -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 398d7a3..5623a70 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -25,6 +25,7 @@ import Data.Semigroup.Traversable import Data.Text (Text) import Data.Text qualified as T import Data.Void +import Compiler.Types } %name parseRlpProg StandaloneProgram @@ -42,6 +43,8 @@ import Data.Void consym { Located _ (TokenConSym _) } varsym { Located _ (TokenVarSym _) } data { Located _ TokenData } + case { Located _ TokenCase } + of { Located _ TokenOf } litint { Located _ (TokenLitInt _) } '=' { Located _ TokenEquals } '|' { Located _ TokenPipe } @@ -150,6 +153,9 @@ Params :: { [Pat' RlpcPs] } Params : {- epsilon -} { [] } | Params Pat1 { $1 `snoc` $2 } +Pat :: { Pat' RlpcPs } + : Pat1 { $1 } + Pat1 :: { Pat' RlpcPs } : Var { fmap VarP $1 } | Lit { LitP <<= $1 } @@ -157,20 +163,43 @@ Pat1 :: { Pat' RlpcPs } Expr :: { RlpExpr' RlpcPs } : Expr1 InfixOp Expr { $2 =>> \o -> OAppE (extract o) $1 $3 } - | Expr1 { $1 } | LetExpr { $1 } + | CaseExpr { $1 } + | Expr1 { $1 } LetExpr :: { RlpExpr' RlpcPs } : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } +CaseExpr :: { RlpExpr' RlpcPs } + : case Expr of layout0(CaseAlt) + { CaseE <<~ $2 <#> $4 } + +-- TODO: where-binds +CaseAlt :: { (Alt RlpcPs, Where RlpcPs) } + : Alt { ($1, []) } + +Alt :: { Alt RlpcPs } + : Pat '->' Expr { AltA $1 $3 } + +-- layout0(p : β) :: [β] +layout0(p) : '{' layout_list0(';',p) '}' { $2 } + | VL layout_list0(VS,p) VR { $2 } + +-- layout_list0(sep : α, p : β) :: [β] +layout_list0(sep,p) : p { [$1] } + | layout_list1(sep,p) sep p { $1 `snoc` $3 } + | {- epsilon -} { [] } + +-- layout1(p : β) :: [β] layout1(p) : '{' layout_list1(';',p) '}' { $2 } | VL layout_list1(VS,p) VR { $2 } +-- layout_list1(sep : α, p : β) :: [β] layout_list1(sep,p) : p { [$1] } | layout_list1(sep,p) sep p { $1 `snoc` $3 } Binding :: { Binding' RlpcPs } - : Pat1 '=' Expr { PatB <<~ $1 <~> $3 } + : Pat '=' Expr { PatB <<~ $1 <~> $3 } Expr1 :: { RlpExpr' RlpcPs } : '(' Expr ')' { $1 .> $2 <. $3 } -- 2.52.0 From 2895e3cb480c75223586175c266fa71cedcfdbf7 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 13:39:01 -0700 Subject: [PATCH 143/192] case unrolling --- .ghci | 3 --- rlp.cabal | 1 + src/Core/Syntax.hs | 2 +- src/Rlp/Parse.y | 12 ++++++++++-- src/Rlp/Syntax.hs | 2 +- src/Rlp2Core.hs | 28 +++++++++++++++++++++++----- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/.ghci b/.ghci index 21ffd96..75be915 100644 --- a/.ghci +++ b/.ghci @@ -22,6 +22,3 @@ _reload_and_make _ = do -------------------------------------------------------------------------------- --- import rlpc quasiquoters -:m + Core.TH Rlp.TH - diff --git a/rlp.cabal b/rlp.cabal index 2f0d553..a2bcd50 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -84,6 +84,7 @@ library OverloadedStrings TypeFamilies LambdaCase + ViewPatterns executable rlpc import: warnings diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index cad53be..7b71f91 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -121,7 +121,7 @@ data Rec = Rec data AltCon = AltData Name | AltTag Tag | AltLit Lit - | Default + | AltDefault deriving (Show, Read, Eq, Lift) newtype Lit = IntL Int diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 5623a70..c48ff38 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -154,11 +154,19 @@ Params : {- epsilon -} { [] } | Params Pat1 { $1 `snoc` $2 } Pat :: { Pat' RlpcPs } - : Pat1 { $1 } + : Con Pat1s { $1 =>> \cn -> + ConP (extract $1) $2 } + | Pat1 { $1 } + +Pat1s :: { [Pat' RlpcPs] } + : Pat1s Pat1 { $1 `snoc` $2 } + | Pat1 { [$1] } Pat1 :: { Pat' RlpcPs } - : Var { fmap VarP $1 } + : Con { fmap (`ConP` []) $1 } + | Var { fmap VarP $1 } | Lit { LitP <<= $1 } + | '(' Pat ')' { $1 .> $2 <. $3 } Expr :: { RlpExpr' RlpcPs } : Expr1 InfixOp Expr { $2 =>> \o -> diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index f44e989..771ee3b 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -11,7 +11,7 @@ module Rlp.Syntax , progDecls , Decl(..), Decl', RlpExpr(..), RlpExpr' , Pat(..), Pat' - , Alt(..) + , Alt(..), Where , Assoc(..) , Lit(..), Lit' , RlpType(..), RlpType' diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index ee9e0e0..f079ebf 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -18,6 +18,7 @@ import Data.HashMap.Strict qualified as H import Data.Monoid (Endo(..)) import Data.Foldable import Data.Functor.Bind +import Debug.Trace import Core.Syntax as Core import Compiler.Types @@ -63,7 +64,23 @@ exprToCore :: RlpExpr RlpcPs -> Expr' exprToCore (VarE n) = Var (dsNameToName n) -exprToCore (CaseE e as) = undefined +exprToCore (CaseE (unXRec -> e) as) = Case (exprToCore e) (caseAltToCore <$> as) + +-- TODO: where-binds +caseAltToCore :: (Alt RlpcPs, Where RlpcPs) -> Alter' +caseAltToCore (AltA (VarP'' x) e, wh) = + Alter AltDefault [] (exprToCore $ unXRec e) +caseAltToCore (AltA rootPat@(ConP'' cn as) e, wh) = + case firstNestedPat of + -- this case matches a nested pattern, which must be unrolled: + Just (c,p) -> undefined + -- no nested patterns! direct translation: + Nothing -> Alter (AltData cn) as' e' + where + as' = (\ (VarP'' x) -> dsNameToName x) <$> traceShowId as + e' = exprToCore (unXRec e) + where + firstNestedPat = expandableAlt "NAME" . unXRec $ rootPat -- >>> pat1 = nolo $ ConP "C" [nolo $ ConP "P" []] -- >>> expandableAlt "name" (AltA pat1 (nolo $ VarE "e")) @@ -72,10 +89,10 @@ exprToCore (CaseE e as) = undefined -- >>> pat2 = nolo $ ConP "C" [nolo $ VarP "p", nolo $ ConP "P" []] -- >>> expandableAlt "name" (AltA pat2 (nolo $ VarE "e")) -- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "p"),Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") -expandableAlt :: IdP RlpcPs -> Alt RlpcPs - -> Maybe (Pat RlpcPs, Pat RlpcPs, RlpExpr RlpcPs) -expandableAlt n (AltA c@(ConP'' cn as) e) = - nestedPat <&> (c', , extract e) +expandableAlt :: IdP RlpcPs -> Pat RlpcPs + -> Maybe (Pat RlpcPs, Pat RlpcPs) +expandableAlt n c@(ConP cn as) = + nestedPat <&> (c',) where l :: Lens' [Pat RlpcPs] (Maybe (Pat RlpcPs)) l = atFound (has _ConP) @@ -84,6 +101,7 @@ expandableAlt n (AltA c@(ConP'' cn as) e) = nestedPat = (unXRec <$> as) ^. l as' = (unXRec <$> as) & l ?~ VarP n & fmap nolo +expandableAlt _ _ = Nothing -- this is an illegal lens, and we're using it illegally. it's convenient :3 -- TODO: adhere to the holy laws of the Lens Herself -- 2.52.0 From 12d261ede112150a7ae03e9916ab759f2544cc9e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 6 Feb 2024 18:49:41 -0700 Subject: [PATCH 144/192] rose --- rlp.cabal | 2 ++ src/Rlp2Core.hs | 77 ++++++++++++++++--------------------------------- 2 files changed, 27 insertions(+), 52 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index a2bcd50..4707cd3 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -76,6 +76,8 @@ library , lens , text-ansi , microlens-pro ^>=0.2.0 + , effectful-core ^>=2.3.0.0 + , deriving-compat ^>=0.6.0 hs-source-dirs: src default-language: GHC2021 diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index f079ebf..2d34a1e 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE DeriveTraversable #-} module Rlp2Core ( rlpProgToCore ) @@ -17,8 +19,14 @@ import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Monoid (Endo(..)) import Data.Foldable +import Data.Fix +import Data.Maybe (fromJust) import Data.Functor.Bind import Debug.Trace +import Effectful.State.Static.Local +import Effectful +import Control.Monad.Utils (mapAccumLM) +import Text.Show.Deriving import Core.Syntax as Core import Compiler.Types @@ -26,6 +34,12 @@ import Rlp.Syntax as Rlp import Rlp.Parse.Types (RlpcPs, PsName) -------------------------------------------------------------------------------- +data Branch a = Branch Name [Either Name (Name, Branch a)] + deriving (Show, Functor, Foldable, Traversable) +type Rose = Fix Branch + +deriveShow1 ''Branch + -- the rl' program is desugared by desugaring each declaration as a separate -- program, and taking the monoidal product of the lot :3 @@ -68,60 +82,19 @@ exprToCore (CaseE (unXRec -> e) as) = Case (exprToCore e) (caseAltToCore <$> as) -- TODO: where-binds caseAltToCore :: (Alt RlpcPs, Where RlpcPs) -> Alter' -caseAltToCore (AltA (VarP'' x) e, wh) = - Alter AltDefault [] (exprToCore $ unXRec e) -caseAltToCore (AltA rootPat@(ConP'' cn as) e, wh) = - case firstNestedPat of - -- this case matches a nested pattern, which must be unrolled: - Just (c,p) -> undefined - -- no nested patterns! direct translation: - Nothing -> Alter (AltData cn) as' e' - where - as' = (\ (VarP'' x) -> dsNameToName x) <$> traceShowId as - e' = exprToCore (unXRec e) - where - firstNestedPat = expandableAlt "NAME" . unXRec $ rootPat +caseAltToCore = undefined --- >>> pat1 = nolo $ ConP "C" [nolo $ ConP "P" []] --- >>> expandableAlt "name" (AltA pat1 (nolo $ VarE "e")) --- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") --- --- >>> pat2 = nolo $ ConP "C" [nolo $ VarP "p", nolo $ ConP "P" []] --- >>> expandableAlt "name" (AltA pat2 (nolo $ VarE "e")) --- Just (ConP "C" [Located (SrcSpan 0 0 0 0) (VarP "p"),Located (SrcSpan 0 0 0 0) (VarP "name")],ConP "P" [],VarE' () "e") -expandableAlt :: IdP RlpcPs -> Pat RlpcPs - -> Maybe (Pat RlpcPs, Pat RlpcPs) -expandableAlt n c@(ConP cn as) = - nestedPat <&> (c',) - where - l :: Lens' [Pat RlpcPs] (Maybe (Pat RlpcPs)) - l = atFound (has _ConP) +conToRose :: forall es. (State [IdP RlpcPs] :> es) => Pat RlpcPs -> Eff es Rose +conToRose (ConP cn as) = Fix . Branch cn <$> patToBranch `traverse` as + where + patToBranch :: Pat' RlpcPs -> Eff es (Either Name (Name, Branch (Fix Branch))) + patToBranch (VarP'' x) = pure $ Left (dsNameToName x) + patToBranch p@(ConP'' _ _) = + Right <$> liftA2 (,) getName br + where + br = unwrapFix <$> conToRose (unXRec p) - c' = ConP cn as' - nestedPat = (unXRec <$> as) ^. l - as' = (unXRec <$> as) & l ?~ VarP n - & fmap nolo -expandableAlt _ _ = Nothing - --- this is an illegal lens, and we're using it illegally. it's convenient :3 --- TODO: adhere to the holy laws of the Lens Herself -atFound :: forall a. (a -> Bool) -> Lens' [a] (Maybe a) -atFound p = lens (find p) alter where - alter :: [a] -> Maybe a -> [a] - alter l Nothing = deleteFound l - alter l (Just x') = setFound x' l - - deleteFound :: [a] -> [a] - deleteFound [] = [] - deleteFound (x:xs) - | p x = xs - | otherwise = x : deleteFound xs - - setFound :: a -> [a] -> [a] - setFound _ [] = [] - setFound x' (x:xs) - | p x = x' : xs - | otherwise = x : setFound x' xs + getName = state $ fromJust . uncons @[IdP RlpcPs] constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = -- 2.52.0 From 868b63e6ef205ec410bfcc635e241baaa89c5e32 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 11:08:17 -0700 Subject: [PATCH 145/192] her light cuts deep time and time again ('her' of course referring to the field of computer science) --- src/Rlp2Core.hs | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 2d34a1e..2edfcb3 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -7,6 +7,7 @@ module Rlp2Core -------------------------------------------------------------------------------- import Control.Monad import Control.Monad.Writer.CPS +import Control.Monad.Utils (mapAccumLM) import Control.Arrow import Control.Applicative import Control.Comonad @@ -25,7 +26,6 @@ import Data.Functor.Bind import Debug.Trace import Effectful.State.Static.Local import Effectful -import Control.Monad.Utils (mapAccumLM) import Text.Show.Deriving import Core.Syntax as Core @@ -34,8 +34,18 @@ import Rlp.Syntax as Rlp import Rlp.Parse.Types (RlpcPs, PsName) -------------------------------------------------------------------------------- -data Branch a = Branch Name [Either Name (Name, Branch a)] +type Tree a = Either Name (Name, Branch a) + +-- | Rose tree branch representing "nested" "patterns" in the Core language. That +-- is, a constructor with children that are either a normal binder (Left (Given) +-- name) or an indirection to another pattern (Right (Generated name) (Pattern)) + +data Branch a = Branch Name [Tree a] deriving (Show, Functor, Foldable, Traversable) + +-- | The actual rose tree. +-- @type Rose = 'Data.Fix.Fix' 'Branch'@ + type Rose = Fix Branch deriveShow1 ''Branch @@ -84,18 +94,45 @@ exprToCore (CaseE (unXRec -> e) as) = Case (exprToCore e) (caseAltToCore <$> as) caseAltToCore :: (Alt RlpcPs, Where RlpcPs) -> Alter' caseAltToCore = undefined +-- roseToCore :: Rose -> Expr' -> Alter' +-- roseToCore (unFix -> Branch cn as) = alter +-- where +-- alter :: Alter' +-- alter = Alter (AltData cn) (treeToCore <$> as) (Var "expr") +-- -- foldFix :: Functor f => (f a -> a) -> Fix f -> a +-- treeToCore :: Tree Rose -> Expr' -> Expr' +-- treeToCore (Left n) = id +-- treeToCore (Right (n,cs)) = \e -> Case (Var n) [_] + conToRose :: forall es. (State [IdP RlpcPs] :> es) => Pat RlpcPs -> Eff es Rose -conToRose (ConP cn as) = Fix . Branch cn <$> patToBranch `traverse` as +conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as where - patToBranch :: Pat' RlpcPs -> Eff es (Either Name (Name, Branch (Fix Branch))) - patToBranch (VarP'' x) = pure $ Left (dsNameToName x) - patToBranch p@(ConP'' _ _) = + patToForrest :: Pat' RlpcPs -> Eff es (Tree Rose) + patToForrest (VarP'' x) = pure $ Left (dsNameToName x) + patToForrest p@(ConP'' _ _) = Right <$> liftA2 (,) getName br where br = unwrapFix <$> conToRose (unXRec p) getName = state $ fromJust . uncons @[IdP RlpcPs] +test :: Expr' -> Branch Alter' -> Alter' +test e (Branch cn as) = Alter (AltData cn) myBinds e' + where + (e', myBinds) = mapAccumL f e as + + f :: Expr' -> Tree Alter' -> (Expr', Name) + f e (Left n) = (e, dsNameToName n) + f e (Right (n,cs)) = (e', dsNameToName n) where + e' = Case (Var $ dsNameToName n) [test e cs] + +runNames = runPureEff . evalState nameSupply + +-- | debug tool + +nameSupply :: [IdP RlpcPs] +nameSupply = [ T.pack $ "$x_" <> show n | n <- [0..] ] + constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = mempty & programTypeSigs . at cn ?~ foldr (:->) t as' -- 2.52.0 From d6529d50ff5b04b8e50c6efa90215fecc96a91db Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 11:19:36 -0700 Subject: [PATCH 146/192] tidying --- rlp.cabal | 1 + src/Rlp2Core.hs | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 4707cd3..c082198 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -87,6 +87,7 @@ library TypeFamilies LambdaCase ViewPatterns + DataKinds executable rlpc import: warnings diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 2edfcb3..4ba95df 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -116,19 +116,24 @@ conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as getName = state $ fromJust . uncons @[IdP RlpcPs] -test :: Expr' -> Branch Alter' -> Alter' -test e (Branch cn as) = Alter (AltData cn) myBinds e' +branchToCore :: Expr' -> Branch Alter' -> Alter' +branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' where + -- gather binders for the /current/ pattern, and build an expression + -- matching subpatterns (e', myBinds) = mapAccumL f e as f :: Expr' -> Tree Alter' -> (Expr', Name) f e (Left n) = (e, dsNameToName n) f e (Right (n,cs)) = (e', dsNameToName n) where - e' = Case (Var $ dsNameToName n) [test e cs] + e' = Case (Var $ dsNameToName n) [branchToCore e cs] +-- | debug helper + +runNames :: Eff '[State [PsName]] c -> c runNames = runPureEff . evalState nameSupply --- | debug tool +-- | debug helper nameSupply :: [IdP RlpcPs] nameSupply = [ T.pack $ "$x_" <> show n | n <- [0..] ] -- 2.52.0 From 71170d6d428da5fe54def54f7453d67043007c25 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 11:43:33 -0700 Subject: [PATCH 147/192] NameSupply effect --- src/Rlp2Core.hs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 4ba95df..5fd15c6 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -25,6 +25,7 @@ import Data.Maybe (fromJust) import Data.Functor.Bind import Debug.Trace import Effectful.State.Static.Local +import Effectful.Labeled import Effectful import Text.Show.Deriving @@ -73,7 +74,7 @@ declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e''] where n' = dsNameToName n (e',as') = mapAccumL caseify (extract e) (names `zip` as) - e'' = exprToCore e' + e'' = runPureEff . runNameSupply n $ exprToCore e' names = [ nolo $ "$x_" <> tshow n | n <- [0..] ] tshow = T.pack . show @@ -84,11 +85,13 @@ caseify e (x,p) = (e', x') where e' = CaseE (VarE <$> x) [(alt, [])] alt = AltA p (nolo e) -exprToCore :: RlpExpr RlpcPs -> Expr' +type NameSupply = Labeled "expr-name-supply" (State [IdP RlpcPs]) -exprToCore (VarE n) = Var (dsNameToName n) +exprToCore :: (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' -exprToCore (CaseE (unXRec -> e) as) = Case (exprToCore e) (caseAltToCore <$> as) +exprToCore (VarE n) = pure $ Var (dsNameToName n) + +exprToCore (CaseE (unXRec -> e) as) = undefined -- TODO: where-binds caseAltToCore :: (Alt RlpcPs, Where RlpcPs) -> Alter' @@ -128,10 +131,9 @@ branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' f e (Right (n,cs)) = (e', dsNameToName n) where e' = Case (Var $ dsNameToName n) [branchToCore e cs] --- | debug helper - -runNames :: Eff '[State [PsName]] c -> c -runNames = runPureEff . evalState nameSupply +runNameSupply :: IdP RlpcPs -> Eff (NameSupply ': es) a -> Eff es a +runNameSupply n = runLabeled @"expr-name-supply" (evalState ns) where + ns = [ "$" <> n <> "_" <> T.pack (show k) | k <- [0..] ] -- | debug helper -- 2.52.0 From 77d27dccde2e0f893e190c990d4eb43f5aca331b Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 12:09:16 -0700 Subject: [PATCH 148/192] tidy --- src/Rlp2Core.hs | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 5fd15c6..7fa52df 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -21,7 +21,7 @@ import Data.HashMap.Strict qualified as H import Data.Monoid (Endo(..)) import Data.Foldable import Data.Fix -import Data.Maybe (fromJust) +import Data.Maybe (fromJust, fromMaybe) import Data.Functor.Bind import Debug.Trace import Effectful.State.Static.Local @@ -73,19 +73,23 @@ declToCore (DataD'' n as ds) = fold . getZipList $ declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e''] where n' = dsNameToName n - (e',as') = mapAccumL caseify (extract e) (names `zip` as) + -- e : verbatim function body + -- e' : function body w/ case-exprs matching pattern arguments + -- e'' : exprToCore e' + (e',as') = mapAccumL patArgsToCase (extract e) (names `zip` as) e'' = runPureEff . runNameSupply n $ exprToCore e' names = [ nolo $ "$x_" <> tshow n | n <- [0..] ] tshow = T.pack . show -caseify :: RlpExpr RlpcPs -> (IdP' RlpcPs, Pat' RlpcPs) +patArgsToCase :: RlpExpr RlpcPs -> (IdP' RlpcPs, Pat' RlpcPs) -> (RlpExpr RlpcPs, Name) -caseify e (x,p) = (e', x') where +patArgsToCase e (x,p) = (e', x') where x' = dsNameToName (extract x) e' = CaseE (VarE <$> x) [(alt, [])] alt = AltA p (nolo e) -type NameSupply = Labeled "expr-name-supply" (State [IdP RlpcPs]) +type NameSupply = Labeled NameSupplyLabel (State [IdP RlpcPs]) +type NameSupplyLabel = "expr-name-supply" exprToCore :: (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' @@ -94,31 +98,22 @@ exprToCore (VarE n) = pure $ Var (dsNameToName n) exprToCore (CaseE (unXRec -> e) as) = undefined -- TODO: where-binds -caseAltToCore :: (Alt RlpcPs, Where RlpcPs) -> Alter' -caseAltToCore = undefined +caseAltToCore :: (NameSupply :> es) + => (Alt RlpcPs, Where RlpcPs) -> Eff es Alter' +caseAltToCore (AltA (extract -> p) e, wh) = undefined + where + --- roseToCore :: Rose -> Expr' -> Alter' --- roseToCore (unFix -> Branch cn as) = alter --- where --- alter :: Alter' --- alter = Alter (AltData cn) (treeToCore <$> as) (Var "expr") --- -- foldFix :: Functor f => (f a -> a) -> Fix f -> a --- treeToCore :: Tree Rose -> Expr' -> Expr' --- treeToCore (Left n) = id --- treeToCore (Right (n,cs)) = \e -> Case (Var n) [_] - -conToRose :: forall es. (State [IdP RlpcPs] :> es) => Pat RlpcPs -> Eff es Rose +conToRose :: forall es. (NameSupply :> es) => Pat RlpcPs -> Eff es Rose conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as where patToForrest :: Pat' RlpcPs -> Eff es (Tree Rose) patToForrest (VarP'' x) = pure $ Left (dsNameToName x) patToForrest p@(ConP'' _ _) = - Right <$> liftA2 (,) getName br + Right <$> liftA2 (,) uniqueName br where br = unwrapFix <$> conToRose (unXRec p) - getName = state $ fromJust . uncons @[IdP RlpcPs] - branchToCore :: Expr' -> Branch Alter' -> Alter' branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' where @@ -132,7 +127,7 @@ branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' e' = Case (Var $ dsNameToName n) [branchToCore e cs] runNameSupply :: IdP RlpcPs -> Eff (NameSupply ': es) a -> Eff es a -runNameSupply n = runLabeled @"expr-name-supply" (evalState ns) where +runNameSupply n = runLabeled @NameSupplyLabel (evalState ns) where ns = [ "$" <> n <> "_" <> T.pack (show k) | k <- [0..] ] -- | debug helper @@ -140,6 +135,13 @@ runNameSupply n = runLabeled @"expr-name-supply" (evalState ns) where nameSupply :: [IdP RlpcPs] nameSupply = [ T.pack $ "$x_" <> show n | n <- [0..] ] +uniqueName :: (NameSupply :> es) => Eff es (IdP RlpcPs) +uniqueName = labeled @NameSupplyLabel @(State [IdP RlpcPs]) $ + state @[IdP RlpcPs] (fromMaybe err . uncons) + where + err = error "NameSupply ran out of names! This shound never happen.\ + \ The caller of runNameSupply is responsible." + constructorToCore :: Type -> Tag -> ConAlt RlpcPs -> Program' constructorToCore t tag (ConAlt cn as) = mempty & programTypeSigs . at cn ?~ foldr (:->) t as' -- 2.52.0 From 719d5a40890da35adab022982038bba96e1f58c2 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 14:26:47 -0700 Subject: [PATCH 149/192] fix incomplete byTag --- src/Compiler/RLPC.hs | 1 + src/Rlp2Core.hs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index 5468223..c75ac95 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -183,6 +183,7 @@ putRlpcErrs opts = filter byTag byTag :: MsgEnvelope RlpcError -> Bool byTag (view msgSeverity -> SevDebug t) = t `S.member` dflags + byTag _ = True prettyRlpcMsg :: MsgEnvelope RlpcError -> String prettyRlpcMsg m@(view msgSeverity -> SevDebug _) = prettyRlpcDebugMsg m diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 7fa52df..4e4d279 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -95,14 +95,16 @@ exprToCore :: (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' exprToCore (VarE n) = pure $ Var (dsNameToName n) -exprToCore (CaseE (unXRec -> e) as) = undefined +exprToCore (CaseE (unXRec -> e) as) = do + e' <- exprToCore e + Case e' <$> caseAltToCore `traverse` as -- TODO: where-binds caseAltToCore :: (NameSupply :> es) => (Alt RlpcPs, Where RlpcPs) -> Eff es Alter' -caseAltToCore (AltA (extract -> p) e, wh) = undefined - where - +caseAltToCore (AltA (unXRec -> p) e, wh) = do + e' <- exprToCore . unXRec $ e + conToRose p <&> foldFix (branchToCore e') conToRose :: forall es. (NameSupply :> es) => Pat RlpcPs -> Eff es Rose conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as -- 2.52.0 From 98bed8480786ce17e5ac6be24bf544719d95baf1 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 15:18:47 -0700 Subject: [PATCH 150/192] desugar --- src/Rlp/Parse.y | 12 ++++++++++-- src/Rlp2Core.hs | 14 +++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index c48ff38..51eaf4c 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -143,7 +143,11 @@ Type1 :: { RlpType' RlpcPs } Type :: { RlpType' RlpcPs } : Type '->' Type { FunT <<~ $1 <~> $3 } - | Type1 { $1 } + | TypeApp { $1 } + +TypeApp :: { RlpType' RlpcPs } + : Type1 { $1 } + | TypeApp Type1 { AppT <<~ $1 <~> $2 } FunDecl :: { Decl' RlpcPs } FunDecl : Var Params '=' Expr { $4 =>> \e -> @@ -173,7 +177,11 @@ Expr :: { RlpExpr' RlpcPs } OAppE (extract o) $1 $3 } | LetExpr { $1 } | CaseExpr { $1 } - | Expr1 { $1 } + | ExprApp { $1 } + +ExprApp :: { RlpExpr' RlpcPs } + : Expr1 { $1 } + | ExprApp Expr1 { AppE <<~ $1 <~> $2 } LetExpr :: { RlpExpr' RlpcPs } : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 4e4d279..017c2d6 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -1,7 +1,8 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveTraversable #-} module Rlp2Core - ( rlpProgToCore + ( desugarRlpProg + , desugarRlpExpr ) where -------------------------------------------------------------------------------- @@ -23,6 +24,7 @@ import Data.Foldable import Data.Fix import Data.Maybe (fromJust, fromMaybe) import Data.Functor.Bind +import Data.Function (on) import Debug.Trace import Effectful.State.Static.Local import Effectful.Labeled @@ -51,6 +53,14 @@ type Rose = Fix Branch deriveShow1 ''Branch +-------------------------------------------------------------------------------- + +desugarRlpProg :: RlpProgram RlpcPs -> Program' +desugarRlpProg = rlpProgToCore + +desugarRlpExpr :: RlpExpr RlpcPs -> Expr' +desugarRlpExpr = runPureEff . runNameSupply "anon" . exprToCore + -- the rl' program is desugared by desugaring each declaration as a separate -- program, and taking the monoidal product of the lot :3 @@ -95,6 +105,8 @@ exprToCore :: (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' exprToCore (VarE n) = pure $ Var (dsNameToName n) +exprToCore (AppE a b) = (liftA2 App `on` exprToCore . unXRec) a b + exprToCore (CaseE (unXRec -> e) as) = do e' <- exprToCore e Case e' <$> caseAltToCore `traverse` as -- 2.52.0 From 2a51daf356818f012921a6e62640985d83cbb44f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 15:19:03 -0700 Subject: [PATCH 151/192] WIP associate postproc corecursive --- src/Rlp/Parse/Associate.hs | 21 +++++++++++++---- src/Rlp/Syntax.hs | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs index 99349d9..fa7c33b 100644 --- a/src/Rlp/Parse/Associate.hs +++ b/src/Rlp/Parse/Associate.hs @@ -1,7 +1,4 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PatternSynonyms, ViewPatterns, ImplicitParams #-} module Rlp.Parse.Associate - {-# WARNING "temporarily unimplemented" #-} ( associate ) where @@ -14,6 +11,20 @@ import Rlp.Parse.Types import Rlp.Syntax -------------------------------------------------------------------------------- -associate x y = y -{-# WARNING associate "temporarily undefined" #-} +associate :: OpTable -> RlpExpr' RlpcPs -> RlpExpr' RlpcPs +associate pt e = undefined + +examplePrecTable :: OpTable +examplePrecTable = H.fromList + [ ("+", (InfixL,6)) + , ("*", (InfixL,7)) + , ("^", (InfixR,8)) + , (".", (InfixR,7)) + , ("~", (Infix, 9)) + , ("=", (Infix, 4)) + , ("&&", (Infix, 3)) + , ("||", (Infix, 2)) + , ("$", (InfixR,0)) + , ("&", (InfixL,0)) + ] diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 771ee3b..5630794 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -47,10 +47,12 @@ module Rlp.Syntax import Data.Text (Text) import Data.Text qualified as T import Data.String (IsString(..)) +import Data.Functor.Foldable import Data.Functor.Foldable.TH (makeBaseFunctor) import Data.Functor.Classes import Data.Functor.Identity import Data.Kind (Type) +import GHC.Generics import Language.Haskell.TH.Syntax (Lift) import Lens.Micro.Pro import Lens.Micro.Pro.TH @@ -173,6 +175,7 @@ data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) | ParE' (XParE p) (RlpExpr' p) | OAppE' (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) | XRlpExprE' !(XXRlpExprE p) + deriving (Generic) type family XLetE p type family XVarE p @@ -220,6 +223,9 @@ type RlpExpr' p = XRec p (RlpExpr p) class UnXRec p where unXRec :: XRec p a -> a +class WrapXRec p where + wrapXRec :: a -> XRec p a + class MapXRec p where mapXRec :: (a -> b) -> XRec p a -> XRec p b @@ -299,3 +305,45 @@ type Lit' p = XRec p (Lit p) makeLenses ''RlpModule makePrisms ''Pat +-------------------------------------------------------------------------------- + +data RlpExprF p a = LetE'F (XLetE p) [Binding' p] a + | VarE'F (XVarE p) (IdP p) + | LamE'F (XLamE p) [Pat p] a + | CaseE'F (XCaseE p) a [(Alt p, Where p)] + | IfE'F (XIfE p) a a a + | AppE'F (XAppE p) a a + | LitE'F (XLitE p) (Lit p) + | ParE'F (XParE p) a + | OAppE'F (XOAppE p) (IdP p) a a + | XRlpExprE'F !(XXRlpExprE p) + deriving (Functor, Foldable, Traversable, Generic) + +type instance Base (RlpExpr p) = RlpExprF p + +instance (UnXRec p) => Recursive (RlpExpr p) where + project = \case + LetE' xx bs e -> LetE'F xx bs (unXRec e) + VarE' xx n -> VarE'F xx n + LamE' xx ps e -> LamE'F xx ps (unXRec e) + CaseE' xx e as -> CaseE'F xx (unXRec e) as + IfE' xx a b c -> IfE'F xx (unXRec a) (unXRec b) (unXRec c) + AppE' xx f x -> AppE'F xx (unXRec f) (unXRec x) + LitE' xx l -> LitE'F xx l + ParE' xx e -> ParE'F xx (unXRec e) + OAppE' xx f a b -> OAppE'F xx f (unXRec a) (unXRec b) + XRlpExprE' xx -> XRlpExprE'F xx + +instance (WrapXRec p) => Corecursive (RlpExpr p) where + embed = \case + LetE'F xx bs e -> LetE' xx bs (wrapXRec e) + VarE'F xx n -> VarE' xx n + LamE'F xx ps e -> LamE' xx ps (wrapXRec e) + CaseE'F xx e as -> CaseE' xx (wrapXRec e) as + IfE'F xx a b c -> IfE' xx (wrapXRec a) (wrapXRec b) (wrapXRec c) + AppE'F xx f x -> AppE' xx (wrapXRec f) (wrapXRec x) + LitE'F xx l -> LitE' xx l + ParE'F xx e -> ParE' xx (wrapXRec e) + OAppE'F xx f a b -> OAppE' xx f (wrapXRec a) (wrapXRec b) + XRlpExprE'F xx -> XRlpExprE' xx + -- 2.52.0 From 80425a274cd9e80e2f5bbb34f69094814379a028 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 18:52:19 -0700 Subject: [PATCH 152/192] sigh i'm gonna have to nuke the ast again in a month --- src/Compiler/Types.hs | 8 ++++---- src/Rlp/Parse.y | 24 +++++++++++++++++++----- src/Rlp/Parse/Associate.hs | 11 +++++++++-- src/Rlp/Parse/Types.hs | 5 +++-- src/Rlp/Syntax.hs | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 7329844..28e4ab4 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -1,8 +1,9 @@ +{-# LANGUAGE TemplateHaskell #-} module Compiler.Types ( SrcSpan(..) , srcspanLine, srcspanColumn, srcspanAbs, srcspanLen , Located(..) - , locating + , _Located , nolo , (<<~), (<~>), (<#>) @@ -58,9 +59,6 @@ srcspanLen = tupling . _4 nolo :: a -> Located a nolo = Located (SrcSpan 0 0 0 0) -locating :: Lens (Located a) (Located b) a b -locating = lens extract ($>) - instance Semigroup SrcSpan where SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where l = min la lb @@ -93,3 +91,5 @@ fab <#> a = fmap ($ a) fab infixl 4 <#> +makePrisms ''Located + diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 51eaf4c..26363e5 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -173,15 +173,22 @@ Pat1 :: { Pat' RlpcPs } | '(' Pat ')' { $1 .> $2 <. $3 } Expr :: { RlpExpr' RlpcPs } - : Expr1 InfixOp Expr { $2 =>> \o -> - OAppE (extract o) $1 $3 } + -- infixities delayed till next release :( + -- : Expr1 InfixOp Expr { $2 =>> \o -> + -- OAppE (extract o) $1 $3 } + : TempInfixExpr { $1 } | LetExpr { $1 } | CaseExpr { $1 } - | ExprApp { $1 } + | AppExpr { $1 } -ExprApp :: { RlpExpr' RlpcPs } +TempInfixExpr :: { RlpExpr' RlpcPs } +TempInfixExpr : Expr1 InfixOp TempInfixExpr {% tempInfixExprErr $1 $3 } + | Expr1 InfixOp Expr1 { $2 =>> \o -> + OAppE (extract o) $1 $3 } + +AppExpr :: { RlpExpr' RlpcPs } : Expr1 { $1 } - | ExprApp Expr1 { AppE <<~ $1 <~> $2 } + | AppExpr Expr1 { AppE <<~ $1 <~> $2 } LetExpr :: { RlpExpr' RlpcPs } : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } @@ -288,5 +295,12 @@ mkInfixD a p n = do intOfToken :: Located RlpToken -> Int intOfToken (Located _ (TokenLitInt n)) = n +tempInfixExprErr :: RlpExpr' RlpcPs -> RlpExpr' RlpcPs -> P a +tempInfixExprErr (Located a _) (Located b _) = + addFatal $ errorMsg (a <> b) $ RlpParErrOther + [ "The rl' frontend is currently in beta. Support for infix expressions is minimal, sorry! :(" + , "In the mean time, don't mix any infix operators." + ] + } diff --git a/src/Rlp/Parse/Associate.hs b/src/Rlp/Parse/Associate.hs index fa7c33b..6757705 100644 --- a/src/Rlp/Parse/Associate.hs +++ b/src/Rlp/Parse/Associate.hs @@ -1,18 +1,25 @@ module Rlp.Parse.Associate + {-# WARNING "unimplemented" #-} ( associate ) where -------------------------------------------------------------------------------- import Data.HashMap.Strict qualified as H import Data.Functor.Foldable +import Data.Functor.Foldable.TH import Data.Functor.Const +import Data.Functor +import Data.Text qualified as T +import Text.Printf import Lens.Micro import Rlp.Parse.Types import Rlp.Syntax -------------------------------------------------------------------------------- -associate :: OpTable -> RlpExpr' RlpcPs -> RlpExpr' RlpcPs -associate pt e = undefined +associate :: OpTable -> Decl' RlpcPs -> Decl' RlpcPs +associate _ p = p + +{-# WARNING associate "unimplemented" #-} examplePrecTable :: OpTable examplePrecTable = H.fromList diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index e253fdd..244b7e1 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -200,12 +200,11 @@ data Layout = Explicit type OpTable = H.HashMap Name OpInfo type OpInfo = (Assoc, Int) --- data WithLocation a = WithLocation [String] a - data RlpParseError = RlpParErrOutOfBoundsPrecedence Int | RlpParErrDuplicateInfixD Name | RlpParErrLexical | RlpParErrUnexpectedToken RlpToken [String] + | RlpParErrOther [Text] deriving (Show) instance IsRlpcError RlpParseError where @@ -224,6 +223,8 @@ instance IsRlpcError RlpParseError where Text [ "Unexpected token " <> tshow t , "Expected: " <> tshow exp ] + RlpParErrOther ts -> + Text ts where tshow :: (Show a) => a -> T.Text tshow = T.pack . show diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 5630794..55146e0 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -9,7 +9,7 @@ module Rlp.Syntax -- * AST RlpProgram(..) , progDecls - , Decl(..), Decl', RlpExpr(..), RlpExpr' + , Decl(..), Decl', RlpExpr(..), RlpExpr', RlpExprF(..) , Pat(..), Pat' , Alt(..), Where , Assoc(..) -- 2.52.0 From ec5f85f428bb4243d31bc131a8321ae0a4b79608 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 19:11:04 -0700 Subject: [PATCH 153/192] remove old files --- src/Core/Lex.x.old | 315 ------------------------------------------- src/Core/Parse.y.old | 159 ---------------------- 2 files changed, 474 deletions(-) delete mode 100644 src/Core/Lex.x.old delete mode 100644 src/Core/Parse.y.old diff --git a/src/Core/Lex.x.old b/src/Core/Lex.x.old deleted file mode 100644 index 0aebd64..0000000 --- a/src/Core/Lex.x.old +++ /dev/null @@ -1,315 +0,0 @@ -{ --- TODO: layout semicolons are not inserted at EOf. -{-# LANGUAGE TemplateHaskell #-} -module Core.Lex - ( lexCore - , lexCore' - , CoreToken(..) - , ParseError(..) - , Located(..) - , AlexPosn(..) - ) - where -import Data.Char (chr) -import Debug.Trace -import Core.Syntax -import Compiler.RLPC -import Lens.Micro -import Lens.Micro.TH -} - -%wrapper "monadUserState" - -$whitechar = [ \t\n\r\f\v] -$special = [\(\)\,\;\[\]\{\}] - -$digit = 0-9 - -$ascsymbol = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~] -$unisymbol = [] -- TODO -$symbol = [$ascsymbol $unisymbol] # [$special \_\:\"\'] - -$large = [A-Z \xc0-\xd6 \xd8-\xde] -$small = [a-z \xdf-\xf6 \xf8-\xff \_] -$alpha = [$small $large] - -$graphic = [$small $large $symbol $digit $special \:\"\'] - -$octit = 0-7 -$hexit = [0-9 A-F a-f] -$namechar = [$alpha $digit \' \#] -$symchar = [$symbol \:] -$nl = [\n\r] -$white_no_nl = $white # $nl - -@reservedid = - case|data|do|import|in|let|letrec|module|of|where - -@reservedop = - "=" | \\ | "->" - -@varname = $small $namechar* -@conname = $large $namechar* -@varsym = $symbol $symchar* -@consym = \: $symchar* - -@decimal = $digit+ - -rlp :- - --- everywhere: skip whitespace -$white_no_nl+ { skip } - --- TODO: `--` could begin an operator -"--"[^$nl]* { skip } -"--"\-*[^$symbol].* { skip } - -"{-" { nestedComment } - --- syntactic symbols -<0> -{ - "(" { constTok TokenLParen } - ")" { constTok TokenRParen } - "{" { lbrace } - "}" { rbrace } - ";" { constTok TokenSemicolon } - "," { constTok TokenComma } -} - --- keywords --- see commentary on the layout system -<0> -{ - "let" { constTok TokenLet `andBegin` layout } - "letrec" { constTok TokenLetrec `andBegin` layout } - "of" { constTok TokenOf `andBegin` layout } - "case" { constTok TokenCase } - "module" { constTok TokenModule } - "in" { letin } - "where" { constTok TokenWhere `andBegin` layout } -} - --- reserved symbols -<0> -{ - "=" { constTok TokenEquals } - "->" { constTok TokenArrow } -} - --- identifiers -<0> -{ - -- TODO: qualified names - @varname { lexWith TokenVarName } - @conname { lexWith TokenConName } - @varsym { lexWith TokenVarSym } -} - --- literals -<0> -{ - @decimal { lexWith (TokenLitInt . read @Int) } -} - -<0> \n { begin bol } - - -{ - $white { skip } - \n { skip } - () { topLevelOff `andBegin` 0 } -} - - -{ - \n { skip } - () { doBol `andBegin` 0 } -} - - -{ - $white { skip } - \{ { lbrace `andBegin` 0 } - () { noBrace `andBegin` 0 } -} - -{ -data Located a = Located Int Int Int a - deriving Show - -constTok :: t -> AlexInput -> Int -> Alex (Located t) -constTok t (AlexPn _ y x,_,_,_) l = pure $ Located y x l t - -data CoreToken = TokenLet - | TokenLetrec - | TokenIn - | TokenModule - | TokenWhere - | TokenComma - | TokenCase - | TokenOf - | TokenLambda - | TokenArrow - | TokenLitInt Int - | TokenVarName Name - | TokenConName Name - | TokenVarSym Name - | TokenConSym Name - | TokenEquals - | TokenLParen - | TokenRParen - | TokenLBrace - | TokenRBrace - | TokenLBraceV -- virtual brace inserted by layout - | TokenRBraceV -- virtual brace inserted by layout - | TokenIndent Int - | TokenDedent Int - | TokenSemicolon - | TokenEOF - deriving Show - -data LayoutContext = Layout Int - | NoLayout - deriving Show - -data AlexUserState = AlexUserState - { _ausContext :: [LayoutContext] - } - -ausContext :: Lens' AlexUserState [LayoutContext] -ausContext f (AlexUserState ctx) - = fmap - (\a -> AlexUserState a) (f ctx) -{-# INLINE ausContext #-} - -pushContext :: LayoutContext -> Alex () -pushContext c = do - st <- alexGetUserState - alexSetUserState $ st { _ausContext = c : _ausContext st } - -popContext :: Alex () -popContext = do - st <- alexGetUserState - alexSetUserState $ st { _ausContext = drop 1 (_ausContext st) } - -getContext :: Alex [LayoutContext] -getContext = do - st <- alexGetUserState - pure $ _ausContext st - -type Lexer = AlexInput -> Int -> Alex (Located CoreToken) - -alexInitUserState :: AlexUserState -alexInitUserState = AlexUserState [] - -nestedComment :: Lexer -nestedComment _ _ = undefined - -lexStream :: Alex [Located CoreToken] -lexStream = do - l <- alexMonadScan - case l of - Located _ _ _ TokenEOF -> pure [l] - _ -> (l:) <$> lexStream - --- | The main lexer driver. -lexCore :: String -> RLPC ParseError [Located CoreToken] -lexCore s = case m of - Left e -> addFatal err - where err = SrcError - { _errSpan = (0,0,0) -- TODO: location - , _errSeverity = Error - , _errDiagnostic = ParErrLexical e - } - Right ts -> pure ts - where - m = runAlex s (alexSetStartCode initial *> lexStream) - --- | @lexCore@, but the tokens are stripped of location info. Useful for --- debugging -lexCore' :: String -> RLPC ParseError [CoreToken] -lexCore' s = fmap f <$> lexCore s - where f (Located _ _ _ t) = t - -data ParseError = ParErrLexical String - | ParErrParse - deriving Show - -lexWith :: (String -> CoreToken) -> Lexer -lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ take l s) - -lexToken :: Alex (Located CoreToken) -lexToken = alexMonadScan - -getSrcCol :: Alex Int -getSrcCol = Alex $ \ st -> - let AlexPn _ _ col = alex_pos st - in Right (st, col) - -lbrace :: Lexer -lbrace (AlexPn _ y x,_,_,_) l = do - pushContext NoLayout - pure $ Located y x l TokenLBrace - -rbrace :: Lexer -rbrace (AlexPn _ y x,_,_,_) l = do - popContext - pure $ Located y x l TokenRBrace - -insRBraceV :: AlexPosn -> Alex (Located CoreToken) -insRBraceV (AlexPn _ y x) = do - popContext - pure $ Located y x 0 TokenRBraceV - -insSemi :: AlexPosn -> Alex (Located CoreToken) -insSemi (AlexPn _ y x) = do - pure $ Located y x 0 TokenSemicolon - -modifyUst :: (AlexUserState -> AlexUserState) -> Alex () -modifyUst f = do - st <- alexGetUserState - alexSetUserState $ f st - -getUst :: Alex AlexUserState -getUst = alexGetUserState - -newLayoutContext :: Lexer -newLayoutContext (p,_,_,_) _ = do - undefined - -noBrace :: Lexer -noBrace (AlexPn _ y x,_,_,_) l = do - col <- getSrcCol - pushContext (Layout col) - pure $ Located y x l TokenLBraceV - -getOffside :: Alex Ordering -getOffside = do - ctx <- getContext - m <- getSrcCol - case ctx of - Layout n : _ -> pure $ m `compare` n - _ -> pure GT - -doBol :: Lexer -doBol (p,c,_,s) _ = do - off <- getOffside - case off of - LT -> insRBraceV p - EQ -> insSemi p - _ -> lexToken - -letin :: Lexer -letin (AlexPn _ y x,_,_,_) l = do - popContext - pure $ Located y x l TokenIn - -topLevelOff :: Lexer -topLevelOff = noBrace - -alexEOF :: Alex (Located CoreToken) -alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> - Right (st, Located y x 0 TokenEOF) - -} diff --git a/src/Core/Parse.y.old b/src/Core/Parse.y.old deleted file mode 100644 index bacd40e..0000000 --- a/src/Core/Parse.y.old +++ /dev/null @@ -1,159 +0,0 @@ -{ -module Core.Parse - ( parseCore - , parseCoreExpr - , parseCoreProg - , module Core.Lex -- temp convenience - , parseTmp - , SrcError - , ParseError - , Module - ) - where - -import Control.Monad ((>=>)) -import Data.Foldable (foldl') -import Core.Syntax -import Core.Lex -import Compiler.RLPC -import Data.Default.Class (def) -} - -%name parseCore Module -%name parseCoreExpr StandaloneExpr -%name parseCoreProg StandaloneProgram -%tokentype { Located CoreToken } -%error { parseError } -%monad { RLPC ParseError } - -%token - let { Located _ _ _ TokenLet } - letrec { Located _ _ _ TokenLetrec } - module { Located _ _ _ TokenModule } - where { Located _ _ _ TokenWhere } - ',' { Located _ _ _ TokenComma } - in { Located _ _ _ TokenIn } - litint { Located _ _ _ (TokenLitInt $$) } - varname { Located _ _ _ (TokenVarName $$) } - varsym { Located _ _ _ (TokenVarSym $$) } - conname { Located _ _ _ (TokenConName $$) } - consym { Located _ _ _ (TokenConSym $$) } - 'λ' { Located _ _ _ TokenLambda } - '->' { Located _ _ _ TokenArrow } - '=' { Located _ _ _ TokenEquals } - '(' { Located _ _ _ TokenLParen } - ')' { Located _ _ _ TokenRParen } - '{' { Located _ _ _ TokenLBrace } - '}' { Located _ _ _ TokenRBrace } - vl { Located _ _ _ TokenLBraceV } - vr { Located _ _ _ TokenRBraceV } - ';' { Located _ _ _ TokenSemicolon } - eof { Located _ _ _ TokenEOF } - -%% - -Module :: { Module } -Module : module conname where Program Eof { Module (Just ($2, [])) $4 } - | Program Eof { Module Nothing $1 } - -Eof :: { () } -Eof : eof { () } - | error { () } - -StandaloneProgram :: { Program } -StandaloneProgram : Program eof { $1 } - -Program :: { Program } -Program : VOpen ScDefs VClose { Program $2 } - | '{' ScDefs '}' { Program $2 } - -VOpen :: { () } -VOpen : vl { () } - -VClose :: { () } -VClose : vr { () } - | error { () } - -ScDefs :: { [ScDef] } -ScDefs : ScDef ';' ScDefs { $1 : $3 } - | {- epsilon -} { [] } - -ScDef :: { ScDef } -ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 } - -ParList :: { [Name] } -ParList : Var ParList { $1 : $2 } - | {- epsilon -} { [] } - -StandaloneExpr :: { Expr } -StandaloneExpr : Expr eof { $1 } - -Expr :: { Expr } -Expr : LetExpr { $1 } - | 'λ' Binders '->' Expr { Lam $2 $4 } - | Application { $1 } - | Expr1 { $1 } - -LetExpr :: { Expr } -LetExpr : let VOpen Bindings VClose in Expr { Let NonRec $3 $6 } - | letrec VOpen Bindings VClose in Expr { Let Rec $3 $6 } - | let '{' Bindings '}' in Expr { Let NonRec $3 $6 } - | letrec '{' Bindings '}' in Expr { Let Rec $3 $6 } - -Binders :: { [Name] } -Binders : Var Binders { $1 : $2 } - | Var { [$1] } - -Application :: { Expr } -Application : Expr1 AppArgs { foldl' App $1 $2 } - --- TODO: Application can probably be written as a single rule, without AppArgs -AppArgs :: { [Expr] } -AppArgs : Expr1 AppArgs { $1 : $2 } - | Expr1 { [$1] } - -Expr1 :: { Expr } -Expr1 : litint { IntE $1 } - | Id { Var $1 } - | '(' Expr ')' { $2 } - -Bindings :: { [Binding] } -Bindings : Binding ';' Bindings { $1 : $3 } - | Binding ';' { [$1] } - | Binding { [$1] } - -Binding :: { Binding } -Binding : Var '=' Expr { $1 := $3 } - -Id :: { Name } -Id : Var { $1 } - | Con { $1 } - -Var :: { Name } -Var : '(' varsym ')' { $2 } - | varname { $1 } - -Con :: { Name } -Con : '(' consym ')' { $2 } - | conname { $1 } - -{ -parseError :: [Located CoreToken] -> RLPC ParseError a -parseError (Located y x l _ : _) = addFatal err - where err = SrcError - { _errSpan = (y,x,l) - , _errSeverity = Error - , _errDiagnostic = ParErrParse - } - -parseTmp :: IO Module -parseTmp = do - s <- readFile "/tmp/t.hs" - case parse s of - Left e -> error (show e) - Right (ts,_) -> pure ts - where - parse = evalRLPC def . (lexCore >=> parseCore) - -} - -- 2.52.0 From 96b73eced042f794a3483302db0081b0b342091e Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 19:12:48 -0700 Subject: [PATCH 154/192] remove old files --- src/Data/Pretty.hs | 73 ++++------------------------------------------ 1 file changed, 5 insertions(+), 68 deletions(-) diff --git a/src/Data/Pretty.hs b/src/Data/Pretty.hs index 83958a9..b00bfb1 100644 --- a/src/Data/Pretty.hs +++ b/src/Data/Pretty.hs @@ -1,14 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} module Data.Pretty ( Pretty(..) - , ISeq(..) - , precPretty - , prettyPrint - , prettyShow - , iShow - , iBracket - , withPrec - , bracketPrec ) where ---------------------------------------------------------------------------------- @@ -16,65 +8,10 @@ import Data.String (IsString(..)) ---------------------------------------------------------------------------------- class Pretty a where - pretty :: a -> ISeq - prettyPrec :: a -> Int -> ISeq + -- pretty :: a -> ISeq + -- prettyPrec :: a -> Int -> ISeq - {-# MINIMAL pretty | prettyPrec #-} - pretty a = prettyPrec a 0 - prettyPrec a _ = iBracket (pretty a) + -- {-# MINIMAL pretty | prettyPrec #-} + -- pretty a = prettyPrec a 0 + -- prettyPrec a _ = iBracket (pretty a) -precPretty :: (Pretty a) => Int -> a -> ISeq -precPretty = flip prettyPrec - -prettyPrint :: (Pretty a) => a -> IO () -prettyPrint = putStr . squash . pretty - -prettyShow :: (Pretty a) => a -> String -prettyShow = squash . pretty - -data ISeq where - INil :: ISeq - IStr :: String -> ISeq - IAppend :: ISeq -> ISeq -> ISeq - IIndent :: ISeq -> ISeq - IBreak :: ISeq - -instance IsString ISeq where - fromString = IStr - -instance Semigroup ISeq where - (<>) = IAppend - -instance Monoid ISeq where - mempty = INil - -squash :: ISeq -> String -squash a = flatten 0 [(a,0)] - -flatten :: Int -> [(ISeq, Int)] -> String -flatten _ [] = "" -flatten c ((INil, i) : ss) = flatten c ss -flatten c ((IStr s, i) : ss) = s ++ flatten (c + length s) ss -flatten c ((IAppend r s, i) : ss) = flatten c ((r,i) : (s,i) : ss) -flatten _ ((IBreak, i) : ss) = '\n' : replicate i ' ' ++ flatten i ss -flatten c ((IIndent s, i) : ss) = flatten c ((s,c) : ss) - -iBracket :: ISeq -> ISeq -iBracket s = IStr "(" <> s <> IStr ")" - -withPrec :: Int -> ISeq -> Int -> ISeq -withPrec n s p - | p > n = iBracket s - | otherwise = s - -bracketPrec :: Int -> Int -> ISeq -> ISeq -bracketPrec n p s = withPrec n s p - -iShow :: (Show a) => a -> ISeq -iShow = IStr . show - ----------------------------------------------------------------------------------- - -instance (Pretty a) => Pretty (Maybe a) where - prettyPrec (Just a) p = prettyPrec a p - prettyPrec Nothing p = "" -- 2.52.0 From c6f9c615b4a311d43e63ffbaa9da595c1557c669 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 21:38:01 -0700 Subject: [PATCH 155/192] fix top-level layout --- src/Rlp/Lex.x | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 4222694..3c07c24 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -125,6 +125,12 @@ $white_no_nl+ ; () { doBol } } + +{ + \n ; + "{" { explicitLBrace `thenDo` popLexState } +} + { \n { beginPush bol } @@ -153,6 +159,7 @@ lexReservedName = \case "infix" -> TokenInfix "infixl" -> TokenInfixL "infixr" -> TokenInfixR + s -> error (show s) lexReservedOp :: Text -> RlpToken lexReservedOp = \case @@ -160,6 +167,7 @@ lexReservedOp = \case "::" -> TokenHasType "|" -> TokenPipe "->" -> TokenArrow + s -> error (show s) -- | @andBegin@, with the subtle difference that the start code is set -- /after/ the action @@ -325,7 +333,7 @@ doBol :: LexerAction (Located RlpToken) doBol inp l = do off <- cmpLayout i <- indentLevel - traceM $ "i: " <> show i + -- traceM $ "i: " <> show i -- important that we pop the lex state lest we find our lexer diverging popLexState case off of -- 2.52.0 From bb2a07d2e922e9c1ec7a1f12b7ca044a352abb84 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Wed, 7 Feb 2024 23:45:38 -0700 Subject: [PATCH 156/192] define datatags --- src/Core/Examples.hs | 2 -- src/Core2Core.hs | 26 ++++++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index f9f4468..ee1fe25 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -207,8 +207,6 @@ namedConsCase :: Program' namedConsCase = [coreProg| {-# PackData Nil 0 0 #-} {-# PackData Cons 1 2 #-} - Nil = Pack{0 0}; - Cons = Pack{1 2}; foldr f z l = case l of { Nil -> z ; Cons x xs -> f x (foldr f z xs) diff --git a/src/Core2Core.hs b/src/Core2Core.hs index 2036915..7717aa7 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -1,5 +1,4 @@ {-# LANGUAGE ImplicitParams #-} -{-# LANGUAGE LambdaCase #-} module Core2Core ( core2core , gmPrep @@ -15,13 +14,15 @@ import Data.Maybe (fromJust) import Data.Set (Set) import Data.Set qualified as S import Data.List +import Data.Foldable import Control.Monad.Writer import Control.Monad.State.Lazy import Control.Arrow ((>>>)) import Data.Text qualified as T import Data.HashMap.Strict (HashMap) import Numeric (showHex) -import Lens.Micro.Platform +-- import Lens.Micro.Platform +import Control.Lens import Core.Syntax import Core.Utils ---------------------------------------------------------------------------------- @@ -29,13 +30,28 @@ import Core.Utils core2core :: Program' -> Program' core2core p = undefined +-- | G-machine preprocessing. + gmPrep :: Program' -> Program' gmPrep p = p & appFloater (floatNonStrictCases globals) & tagData + & defineData where globals = p ^.. programScDefs . each . _lhs . _1 & S.fromList +-- | Define concrete supercombinators for all datatags defined via pragmas (or +-- desugaring) + +defineData :: Program' -> Program' +defineData p = p & programScDefs <>~ defs + where + -- defs = ifoldMap' _ (p ^. programDataTags) + defs = p ^. programDataTags + . to (ifoldMap (\k (t,a) -> [ScDef k [] (Con t a)])) + +-- | Substitute all pattern matches on named constructors for matches on tags + tagData :: Program' -> Program' tagData p = let ?dt = p ^. programDataTags in p & programRhss %~ cata go where @@ -59,6 +75,7 @@ appFloater fl p = p & traverseOf programRhss fl & runFloater & \ (me,floats) -> me & programScDefs %~ (<>floats) +-- TODO: move NameSupply from Rlp2Core into a common module to share here runFloater :: Floater a -> (a, [ScDef']) runFloater = flip evalStateT ns >>> runWriter where @@ -88,7 +105,7 @@ floatNonStrictCases g = goE altBodies = (\(Alter _ _ b) -> b) <$> as tell [sc] goE e - traverse goE altBodies + traverse_ goE altBodies pure e' goC (f :$ x) = (:$) <$> goC f <*> goC x goC (Let r bs e) = Let r <$> bs' <*> goE e @@ -97,7 +114,7 @@ floatNonStrictCases g = goE goC (Var k) = pure (Var k) goC (Con t as) = pure (Con t as) - name = state (fromJust . uncons) + name = state (fromJust . Data.List.uncons) -- extract the right-hand sides of a list of bindings, traverse each -- one, and return the original list of bindings @@ -105,6 +122,7 @@ floatNonStrictCases g = goE travBs c bs = bs ^.. each . _rhs & traverse goC & const (pure bs) + -- ^ ??? what the fuck? -- when provided with a case expr, floatCase will float the case into a -- supercombinator of its free variables. the sc is returned along with an -- 2.52.0 From af5463f8f00baf3e4579d4fd3aa7a091cab99bb1 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 00:36:23 -0700 Subject: [PATCH 157/192] diagram --- rlpc.drawio | 253 ++++++++++++++++++++++++++++++++++++++++++++++++ rlpc.drawio.svg | 4 + 2 files changed, 257 insertions(+) create mode 100644 rlpc.drawio create mode 100644 rlpc.drawio.svg diff --git a/rlpc.drawio b/rlpc.drawio new file mode 100644 index 0000000..d68b067 --- /dev/null +++ b/rlpc.drawio @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rlpc.drawio.svg b/rlpc.drawio.svg new file mode 100644 index 0000000..31dd37b --- /dev/null +++ b/rlpc.drawio.svg @@ -0,0 +1,4 @@ + + + +
rl' source code
RLPC
Parser
Rlp.Parse
(src/Rlp/Parse.y)
Rlp.Lex

(src/Rlp/Lex.x)
RlpToken
Rlp.Parse.Associate
RlpProgram' RlpcPs

(lexer & parser threaded w/ CPS)

Desugarer
Rlp2Core
Evaluation Model
GM
TM
TIM
STG
Preprocessing
Core2Core
tagData
defineData
liftNonStrictCases
Some target
Program'
Program'
[Instr]
Core Parser
Core.Lex
Core.Parse
CoreToken
Core Type-checker
(currently unimplemented)
Type-checker
RlpProgram' RlpcPs
RlpProgram' RlpcTc
Core.HindleyMilner
Program'
Program'
Core source code
???
\ No newline at end of file -- 2.52.0 From 357da257959da236a668ba2b387475ceedab5c02 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 00:36:31 -0700 Subject: [PATCH 158/192] diagram --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2fa2b72..b58a698 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ `rlp` (ruelang') will be a lazily-evaluated purely-functional language heavily imitating Haskell. +### Architecture + +![rlpc architecture diagram](/rlpc.drawio.svg) + ### Build Info * rlp is built using [Cabal](https://www.haskell.org/ghcup/) * rlp's documentation is built using [Sphinx](https://www.sphinx-doc.org/en/master/) -- 2.52.0 From 1079fc7c9bdb4f9dc12f5fea59cfef85a1926af0 Mon Sep 17 00:00:00 2001 From: crumb <95563276+crumbtoo@users.noreply.github.com> Date: Thu, 8 Feb 2024 00:58:58 -0700 Subject: [PATCH 159/192] Update README.md --- README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b58a698..6087d89 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,14 @@ Listed in order of importance. ### Milestones (This list is incomplete.) +Items are marked off not as they are 100% implemented, but rather once I +consider them stable enough that completion is soley a matter of getting +around to it -- no tough design decisions, theorising, etc. remain. For +example, as of writing this, the rl' frontend parser is not fully featured, +yet it is marked off on this list; finishing it would require cranking out +the remaining grammatical rules, and no work on complex tasks like layout +parsing remains. + - [ ] Backend - [x] Core language - [x] AST @@ -73,7 +81,7 @@ Listed in order of importance. - [x] AST - [x] Lexer - [x] Parser - - [ ] Translation to the core language + - [x] Translation to the core language - [ ] Constraint solver - [ ] `do`-notation - [x] CLI @@ -101,13 +109,14 @@ Listed in order of importance. - [x] Garbage Collection - [ ] Stable documentation for the evaluation model -### January Release Plan -- [ ] Beta rl' to Core -- [ ] UX improvements +### February Release Plan +- [x] Beta rl' to Core +- [x] UX improvements - [x] Actual compiler errors -- no more unexceptional `error` calls - [x] Better CLI dump flags - - [ ] Annotate the AST with token positions for errors (NOTE: As of Feb. 1, + - [x] Annotate the AST with token positions for errors (NOTE: As of Feb. 1, this has been done, but the locational info is not yet used in error messages) +- [x] Compiler architecture diagram - [ ] More examples ### March Release Plan @@ -120,11 +129,16 @@ Listed in order of importance. This list is more concrete than the milestones, but likely further in the future than the other release plans. +- [ ] Overall codebase cleaning + - [ ] Complete all TODOs + - [ ] Replace mtl with effectful +- [ ] rl' type-checker +- [ ] Ditch TTG in favour of a simpler AST focusing on extendability via Fix, Free, + Cofree, etc. rather than boilerplate-heavy type families - [ ] Stable rl' to Core - [ ] Core polish - [ ] Better, stable parser - [ ] Better, stable lexer - [ ] Less hacky handling of named data - [ ] Less hacky pragmas -- [ ] GM to LLVM - +- [ ] Choose a target. LLVM, JS, C, and WASM are currently top contenders -- 2.52.0 From 6c943af4a1e9628e8c66961f466c56df32d10e98 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 09:26:53 -0700 Subject: [PATCH 160/192] ppr debug flags ddump-parsed --- README.md | 33 ++++++++++++++----- app/CoreDriver.hs | 7 ++++ app/Main.hs | 41 +++++++++++++++++++---- app/RlpDriver.hs | 10 +++++- rlp.cabal | 6 ++-- src/Compiler/RLPC.hs | 23 ++++++++++--- src/Compiler/RlpcError.hs | 4 +-- src/Control/Monad/Errorful.hs | 6 ++-- src/Core/Parse.y | 2 +- src/Core/Syntax.hs | 61 ++++++++++++++++++++++++++++++++++- src/Core2Core.hs | 14 ++++++-- src/Data/Pretty.hs | 48 +++++++++++++++++++++++---- src/Rlp/Parse.y | 8 +++-- src/Rlp2Core.hs | 22 ++++++++++++- 14 files changed, 244 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 6087d89..ee49f51 100644 --- a/README.md +++ b/README.md @@ -22,21 +22,38 @@ $ cabal test --test-show-details=direct ``` ### Use + +#### TLDR + ```sh -# Compile and evaluate examples/factorial.hs, with evaluation info dumped to stderr -$ rlpc -ddump-eval examples/factorial.hs -# Compile and evaluate t.hs, with evaluation info dumped to t.log -$ rlpc -ddump-eval -l t.log t.hs -# Print the raw structure describing the compiler options -# (option parsing still must succeed in order to print) -$ rlpc -ddump-opts t.hs +# Compile and evaluate examples/factorial.cr, with evaluation info dumped to stderr +$ rlpc -ddump-eval examples/factorial.cr +# Compile and evaluate t.cr, with evaluation info dumped to t.log +$ rlpc -ddump-eval -l t.log t.cr +# Compile and evaluate t.rl, dumping the desugared Core +$ rlpc -ddump-desugared t.rl ``` +#### Options + +```sh +Usage: rlpc [-l|--log FILE] [-d DEBUG FLAG] [-f COMPILATION FLAG] + [-e|--evaluator gm|ti] [--heap-trigger INT] [-x|--language rlp|core] + FILES... +``` + +Available debug flags include: +* `-ddump-desugared`: dump Core generated from rl' +* `-ddump-parsed-core`: dump raw Core AST +* `-ddump-parsed`: dump raw rl' AST +* `-ddump-eval`: dump evaluation logs +* `-dALL`: disable debug message filtering. enables **all** debug messages + ### Potential Features Listed in order of importance. - [x] ADTs - [x] First-class functions -- [ ] Higher-kinded types +- [x] Higher-kinded types - [ ] Typeclasses - [x] Parametric polymorphism - [x] Hindley-Milner type inference diff --git a/app/CoreDriver.hs b/app/CoreDriver.hs index 56ec299..2ded66e 100644 --- a/app/CoreDriver.hs +++ b/app/CoreDriver.hs @@ -5,6 +5,8 @@ module CoreDriver -------------------------------------------------------------------------------- import Compiler.RLPC import Control.Monad +import Data.Text qualified as T +import Lens.Micro.Platform import Core.Lex import Core.Parse @@ -15,3 +17,8 @@ driver :: RLPCIO () driver = forFiles_ $ \f -> withSource f (lexCoreR >=> parseCoreProgR >=> evalProgR) +driverSource :: T.Text -> RLPCIO () +driverSource = lexCoreR >=> parseCoreProgR >=> evalProgR >=> printRes + where + printRes = liftIO . print . view _1 + diff --git a/app/Main.hs b/app/Main.hs index 524b590..5571352 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,7 +1,9 @@ {-# LANGUAGE BlockArguments, LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} module Main where ---------------------------------------------------------------------------------- import Compiler.RLPC +import Compiler.RlpcError import Control.Exception import Options.Applicative hiding (ParseError) import Control.Monad @@ -11,12 +13,13 @@ import Data.Text (Text) import Data.Text qualified as T import Data.Text.IO qualified as TIO import Data.List +import Data.Maybe (listToMaybe) import System.IO import System.Exit (exitSuccess) import Core import TI import GM -import Lens.Micro.Mtl +import Lens.Micro.Platform import CoreDriver qualified import RlpDriver qualified @@ -65,7 +68,7 @@ options = RLPCOptions \triggering the garbage collector" <> value 50 ) - <*> option languageReader + <*> optional # option languageReader ( long "language" <> short 'x' <> metavar "rlp|core" @@ -80,6 +83,8 @@ languageReader :: ReadM Language languageReader = maybeReader $ \case "rlp" -> Just LanguageRlp "core" -> Just LanguageCore + "rl" -> Just LanguageRlp + "cr" -> Just LanguageCore _ -> Nothing debugFlagReader :: ReadM DebugFlag @@ -102,10 +107,34 @@ mmany v = liftA2 (<>) v (mmany v) main :: IO () main = do opts <- execParser optParser - void $ evalRLPCIO opts driver + void $ evalRLPCIO opts dispatch + +dispatch :: RLPCIO () +dispatch = getLang >>= \case + Just LanguageCore -> CoreDriver.driver + Just LanguageRlp -> RlpDriver.driver + Nothing -> addFatal err + where + -- TODO: why didn't i make the srcspan optional LOL + err = errorMsg (SrcSpan 0 0 0 0) $ Text + [ "Could not determine source language from filetype." + , "Possible Solutions:\n\ + \ Suffix the file with `.cr' for Core, or `.rl' for rl'\n\ + \ Specify a language with `rlpc -x core' or `rlpc -x rlp'" + ] + where + getLang = liftA2 (<|>) + (view rlpcLanguage) + -- TODO: we only check the first file lol + ((listToMaybe >=> inferLanguage) <$> view rlpcInputFiles) + driver :: RLPCIO () -driver = view rlpcLanguage >>= \case - LanguageCore -> CoreDriver.driver - LanguageRlp -> RlpDriver.driver +driver = undefined + +inferLanguage :: FilePath -> Maybe Language +inferLanguage fp + | ".rl" `isSuffixOf` fp = Just LanguageRlp + | ".cr" `isSuffixOf` fp = Just LanguageCore + | otherwise = Nothing diff --git a/app/RlpDriver.hs b/app/RlpDriver.hs index 3df1b24..89ad8d7 100644 --- a/app/RlpDriver.hs +++ b/app/RlpDriver.hs @@ -1,11 +1,19 @@ +{-# LANGUAGE OverloadedStrings #-} module RlpDriver ( driver ) where -------------------------------------------------------------------------------- import Compiler.RLPC +import Control.Monad + +import Rlp.Lex +import Rlp.Parse +import Rlp2Core +import GM -------------------------------------------------------------------------------- driver :: RLPCIO () -driver = undefined +driver = forFiles_ $ \f -> + withSource f (parseRlpProgR >=> desugarRlpProgR >=> evalProgR) diff --git a/rlp.cabal b/rlp.cabal index c082198..1f18e4d 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -88,6 +88,9 @@ library LambdaCase ViewPatterns DataKinds + DerivingVia + StandaloneDeriving + DerivingStrategies executable rlpc import: warnings @@ -98,8 +101,7 @@ executable rlpc build-depends: base >=4.17.0.0 && <4.20.0.0 , rlp , optparse-applicative >= 0.18.1 && < 0.19 - , microlens >= 0.4.13 && < 0.5 - , microlens-mtl >= 0.2.0 && < 0.3 + , microlens-platform , mtl >= 2.3.1 && < 2.4 , unordered-containers >= 0.2.20 && < 0.3 , text >= 2.0.2 && < 2.1 diff --git a/src/Compiler/RLPC.hs b/src/Compiler/RLPC.hs index c75ac95..ec4b8bf 100644 --- a/src/Compiler/RLPC.hs +++ b/src/Compiler/RLPC.hs @@ -10,7 +10,6 @@ errors and the family of RLPC monads. {-# LANGUAGE TemplateHaskell #-} -- only used for mtl instances {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-} {-# LANGUAGE BlockArguments, ViewPatterns #-} module Compiler.RLPC ( @@ -18,6 +17,7 @@ module Compiler.RLPC RLPCT(RLPCT), -- ** Special cases RLPC, RLPCIO + , liftIO -- ** Running , runRLPCT , evalRLPCT, evalRLPCIO, evalRLPC @@ -61,6 +61,7 @@ import Data.Coerce import Data.Text (Text) import Data.Text qualified as T import Data.Text.IO qualified as T +import System.IO import Text.ANSI qualified as Ansi import Text.PrettyPrint hiding ((<>)) import Lens.Micro.Platform @@ -84,7 +85,11 @@ type RLPC = RLPCT Identity type RLPCIO = RLPCT IO +instance MonadTrans RLPCT where + lift = RLPCT . lift . lift + instance (MonadIO m) => MonadIO (RLPCT m) where + liftIO = lift . liftIO evalRLPC :: RLPCOptions -> RLPC a @@ -114,7 +119,7 @@ data RLPCOptions = RLPCOptions , _rlpcFFlags :: HashSet CompilerFlag , _rlpcEvaluator :: Evaluator , _rlpcHeapTrigger :: Int - , _rlpcLanguage :: Language + , _rlpcLanguage :: Maybe Language , _rlpcInputFiles :: [FilePath] } deriving Show @@ -135,7 +140,7 @@ instance Default RLPCOptions where , _rlpcEvaluator = EvaluatorGM , _rlpcHeapTrigger = 200 , _rlpcInputFiles = [] - , _rlpcLanguage = LanguageRlp + , _rlpcLanguage = Nothing } -- debug flags are passed with -dFLAG @@ -175,10 +180,18 @@ evalRLPCIO opt r = do Nothing -> die "Failed, no code compiled." putRlpcErrs :: RLPCOptions -> [MsgEnvelope RlpcError] -> IO () -putRlpcErrs opts = filter byTag - >>> traverse_ (putStrLn . ('\n':) . prettyRlpcMsg) +putRlpcErrs opt es = case opt ^. rlpcLogFile of + Just lf -> withFile lf WriteMode putter + Nothing -> putter stderr + where + putter h = hPutStrLn h `traverse_` renderRlpcErrs opt es + +renderRlpcErrs :: RLPCOptions -> [MsgEnvelope RlpcError] -> [String] +renderRlpcErrs opts = (if don'tBother then id else filter byTag) + >>> fmap prettyRlpcMsg where dflags = opts ^. rlpcDFlags + don'tBother = "ALL" `S.member` (opts ^. rlpcDFlags) byTag :: MsgEnvelope RlpcError -> Bool byTag (view msgSeverity -> SevDebug t) = diff --git a/src/Compiler/RlpcError.hs b/src/Compiler/RlpcError.hs index a590a85..a8ef710 100644 --- a/src/Compiler/RlpcError.hs +++ b/src/Compiler/RlpcError.hs @@ -34,7 +34,7 @@ data MsgEnvelope e = MsgEnvelope deriving (Functor, Show) newtype RlpcError = Text [Text] - deriving Show + deriving Show instance IsString RlpcError where fromString = Text . pure . T.pack @@ -47,7 +47,7 @@ instance IsRlpcError RlpcError where data Severity = SevWarning | SevError - | SevDebug Text + | SevDebug Text -- ^ Tag deriving Show makeLenses ''MsgEnvelope diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index 0d70585..f788aaf 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -50,7 +50,7 @@ instance (MonadIO m) => MonadIO (ErrorfulT e m) where liftIO = lift . liftIO instance (Functor m) => Functor (ErrorfulT e m) where - fmap f (ErrorfulT m) = ErrorfulT (m & mapped . _1 . _Just %~ f) + fmap f (ErrorfulT m) = ErrorfulT (m <&> _1 . _Just %~ f) instance (Applicative m) => Applicative (ErrorfulT e m) where pure a = ErrorfulT . pure $ (Just a, []) @@ -63,12 +63,12 @@ instance (Monad m) => Monad (ErrorfulT e m) where ErrorfulT m >>= k = ErrorfulT $ do (a,es) <- m case a of - Just x -> runErrorfulT (k x) + Just x -> runErrorfulT (k x) <&> _2 %~ (es<>) Nothing -> pure (Nothing, es) mapErrorful :: (Functor m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a mapErrorful f (ErrorfulT m) = ErrorfulT $ - m & mapped . _2 . mapped %~ f + m <&> _2 . mapped %~ f -- when microlens-pro drops we can write this as -- mapErrorful f = coerced . mapped . _2 . mapped %~ f diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 20ee3eb..467216d 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -234,7 +234,7 @@ parseCoreProgR = ddumpast <=< (hoistRlpcT generalise . parseCoreProg) ddumpast :: Program' -> RLPCT m Program' ddumpast p = do - addDebugMsg "dump-ast" . show $ p + addDebugMsg "dump-parsed-core" . show $ p pure p happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 7b71f91..f95163e 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -41,6 +41,7 @@ module Core.Syntax , Binding' , HasRHS(_rhs) , HasLHS(_lhs) + , Pretty(pretty) ) where ---------------------------------------------------------------------------------- @@ -56,7 +57,7 @@ import Data.HashMap.Strict qualified as H import Data.Hashable import Data.Text qualified as T import Data.Char -import GHC.Generics +import GHC.Generics (Generic, Generically(..)) -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) -- import Lens.Micro.TH (makeLenses) @@ -215,3 +216,61 @@ instance HasLHS (Binding b) (Binding b) b b where (\ (k := _) -> k) (\ (_ := e) k' -> k' := e) +-------------------------------------------------------------------------------- + +-- TODO: print type sigs with corresponding scdefs +-- TODO: emit pragmas for datatags +instance (Pretty b) => Pretty (Program b) where + pretty = vsepOf (programScDefs . each . to pretty) + +instance (Pretty b) => Pretty (ScDef b) where + pretty sc = hsep [name, as, "=", hang empty 1 e] + where + name = ttext $ sc ^. _lhs . _1 + as = sc & hsepOf (_lhs . _2 . each . to ttext) + e = pretty $ sc ^. _rhs + +instance (Pretty b) => Pretty (Expr b) where + prettyPrec _ (Var n) = ttext n + prettyPrec _ (Con t a) = "Pack{" <> (ttext t <+> ttext a) <> "}" + prettyPrec _ (Lam bs e) = hsep ["λ", hsep (prettyPrec 1 <$> bs), "->", pretty e] + prettyPrec _ (Let r bs e) = hsep [word, explicitLayout bs] + $$ hsep ["in", pretty e] + where word = if r == Rec then "letrec" else "let" + prettyPrec p (App f x) = maybeParens (p>0) $ + prettyPrec 0 f <+> prettyPrec 1 x + prettyPrec _ (Lit l) = pretty l + prettyPrec p (Case e as) = maybeParens (p>0) $ + "case" <+> pretty e <+> "of" + $$ nest 2 (explicitLayout as) + +{- + +x = pretty $ desugarRlpProg [rlpProg| + main = 3 + data B = T | F +|] + +-} + +instance (Pretty b) => Pretty (Alter b) where + pretty (Alter c as e) = + hsep [pretty c, hsep (pretty <$> as), "->", pretty e] + +instance Pretty AltCon where + pretty (AltData n) = ttext n + pretty (AltLit l) = pretty l + pretty (AltTag t) = ttext t + pretty AltDefault = "_" + +instance Pretty Lit where + pretty (IntL n) = ttext n + +instance (Pretty b) => Pretty (Binding b) where + pretty (k := v) = hsep [pretty k, "=", pretty v] + +explicitLayout :: (Pretty a) => [a] -> Doc +explicitLayout as = vcat inner <+> "}" where + inner = zipWith (<+>) delims (pretty <$> as) + delims = "{" : repeat ";" + diff --git a/src/Core2Core.hs b/src/Core2Core.hs index 7717aa7..a187a63 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -21,16 +21,27 @@ import Control.Arrow ((>>>)) import Data.Text qualified as T import Data.HashMap.Strict (HashMap) import Numeric (showHex) + +import Data.Pretty +import Compiler.RLPC -- import Lens.Micro.Platform import Control.Lens import Core.Syntax import Core.Utils ---------------------------------------------------------------------------------- +-- | General optimisations + core2core :: Program' -> Program' core2core p = undefined --- | G-machine preprocessing. +gmPrepR :: (Monad m) => Program' -> RLPCT m Program' +gmPrepR p = do + let p' = gmPrep p + addDebugMsg "dump-gm-preprocessed" $ render . pretty $ p' + pure p' + +-- | G-machine-specific preprocessing. gmPrep :: Program' -> Program' gmPrep p = p & appFloater (floatNonStrictCases globals) @@ -46,7 +57,6 @@ gmPrep p = p & appFloater (floatNonStrictCases globals) defineData :: Program' -> Program' defineData p = p & programScDefs <>~ defs where - -- defs = ifoldMap' _ (p ^. programDataTags) defs = p ^. programDataTags . to (ifoldMap (\k (t,a) -> [ScDef k [] (Con t a)])) diff --git a/src/Data/Pretty.hs b/src/Data/Pretty.hs index b00bfb1..f5b1b4d 100644 --- a/src/Data/Pretty.hs +++ b/src/Data/Pretty.hs @@ -1,17 +1,51 @@ -{-# LANGUAGE OverloadedStrings #-} module Data.Pretty ( Pretty(..) + , ttext + -- * Pretty-printing lens combinators + , hsepOf, vsepOf + , module Text.PrettyPrint + , maybeParens ) where ---------------------------------------------------------------------------------- -import Data.String (IsString(..)) +import Text.PrettyPrint hiding ((<>)) +import Text.PrettyPrint.HughesPJ hiding ((<>)) +import Data.String (IsString(..)) +import Data.Text.Lens +import Data.Monoid +import Data.Text qualified as T +import Control.Lens ---------------------------------------------------------------------------------- class Pretty a where - -- pretty :: a -> ISeq - -- prettyPrec :: a -> Int -> ISeq + pretty :: a -> Doc + prettyPrec :: Int -> a -> Doc - -- {-# MINIMAL pretty | prettyPrec #-} - -- pretty a = prettyPrec a 0 - -- prettyPrec a _ = iBracket (pretty a) + {-# MINIMAL pretty | prettyPrec #-} + pretty = prettyPrec 0 + prettyPrec a _ = pretty a + +instance Pretty String where + pretty = Text.PrettyPrint.text + +instance Pretty T.Text where + pretty = Text.PrettyPrint.text . view unpacked + +newtype Showing a = Showing a + +instance (Show a) => Pretty (Showing a) where + prettyPrec p (Showing a) = fromString $ showsPrec p a "" + +deriving via Showing Int instance Pretty Int + +-------------------------------------------------------------------------------- + +ttext :: Pretty t => t -> Doc +ttext = pretty + +hsepOf :: Getting (Endo Doc) s Doc -> s -> Doc +hsepOf l = foldrOf l (<+>) mempty + +vsepOf :: Getting (Endo Doc) s Doc -> s -> Doc +vsepOf l = foldrOf l ($+$) mempty diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 26363e5..6f8aeb2 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -228,6 +228,7 @@ Expr1 :: { RlpExpr' RlpcPs } : '(' Expr ')' { $1 .> $2 <. $3 } | Lit { fmap LitE $1 } | Var { fmap VarE $1 } + | Con { fmap VarE $1 } InfixOp :: { Located PsName } : consym { mkPsName $1 } @@ -251,8 +252,11 @@ parseRlpExprR s = liftErrorful $ pToErrorful parseRlpExpr st st = programInitState s parseRlpProgR :: (Monad m) => Text -> RLPCT m (RlpProgram RlpcPs) -parseRlpProgR s = liftErrorful $ pToErrorful parseRlpProg st - where +parseRlpProgR s = do + a <- liftErrorful $ pToErrorful parseRlpProg st + addDebugMsg @_ @String "dump-parsed" $ show a + pure a + where st = programInitState s mkPsName :: Located RlpToken -> Located PsName diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 017c2d6..887f40c 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -1,7 +1,8 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveTraversable #-} module Rlp2Core - ( desugarRlpProg + ( desugarRlpProgR + , desugarRlpProg , desugarRlpExpr ) where @@ -15,6 +16,7 @@ import Control.Comonad -- import Lens.Micro -- import Lens.Micro.Internal import Control.Lens +import Compiler.RLPC import Data.List (mapAccumL) import Data.Text (Text) import Data.Text qualified as T @@ -26,6 +28,7 @@ import Data.Maybe (fromJust, fromMaybe) import Data.Functor.Bind import Data.Function (on) import Debug.Trace + import Effectful.State.Static.Local import Effectful.Labeled import Effectful @@ -33,6 +36,7 @@ import Text.Show.Deriving import Core.Syntax as Core import Compiler.Types +import Data.Pretty (render, pretty) import Rlp.Syntax as Rlp import Rlp.Parse.Types (RlpcPs, PsName) -------------------------------------------------------------------------------- @@ -55,6 +59,12 @@ deriveShow1 ''Branch -------------------------------------------------------------------------------- +desugarRlpProgR :: forall m. (Monad m) => RlpProgram RlpcPs -> RLPCT m Program' +desugarRlpProgR p = do + let p' = desugarRlpProg p + addDebugMsg "dump-desugared" $ render (pretty p') + pure p' + desugarRlpProg :: RlpProgram RlpcPs -> Program' desugarRlpProg = rlpProgToCore @@ -107,10 +117,19 @@ exprToCore (VarE n) = pure $ Var (dsNameToName n) exprToCore (AppE a b) = (liftA2 App `on` exprToCore . unXRec) a b +exprToCore (OAppE f a b) = (liftA2 mkApp `on` exprToCore . unXRec) a b + where + mkApp s t = (Var f `App` s) `App` t + exprToCore (CaseE (unXRec -> e) as) = do e' <- exprToCore e Case e' <$> caseAltToCore `traverse` as +exprToCore (LitE l) = litToCore l + +litToCore :: (NameSupply :> es) => Rlp.Lit RlpcPs -> Eff es Expr' +litToCore (Rlp.IntL n) = pure . Lit $ Core.IntL n + -- TODO: where-binds caseAltToCore :: (NameSupply :> es) => (Alt RlpcPs, Where RlpcPs) -> Eff es Alter' @@ -127,6 +146,7 @@ conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as Right <$> liftA2 (,) uniqueName br where br = unwrapFix <$> conToRose (unXRec p) +conToRose _ = error "conToRose: not a ConP!" branchToCore :: Expr' -> Branch Alter' -> Alter' branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' -- 2.52.0 From fba46296db5aabb475df321f166770b0c311f7da Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 11:40:13 -0700 Subject: [PATCH 161/192] ppr typesigs --- rlp.cabal | 1 + src/Core/Syntax.hs | 36 +++++++++++++++++++++++++++++++++--- src/Data/Pretty.hs | 9 +++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/rlp.cabal b/rlp.cabal index 1f18e4d..7ed9477 100644 --- a/rlp.cabal +++ b/rlp.cabal @@ -78,6 +78,7 @@ library , microlens-pro ^>=0.2.0 , effectful-core ^>=2.3.0.0 , deriving-compat ^>=0.6.0 + , these >=0.2 && <2.0 hs-source-dirs: src default-language: GHC2021 diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index f95163e..ebc6dca 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -57,6 +57,8 @@ import Data.HashMap.Strict qualified as H import Data.Hashable import Data.Text qualified as T import Data.Char +import Data.These +import Data.Bifoldable (bifoldr) import GHC.Generics (Generic, Generically(..)) -- Lift instances for the Core quasiquoters import Language.Haskell.TH.Syntax (Lift) @@ -220,11 +222,39 @@ instance HasLHS (Binding b) (Binding b) b b where -- TODO: print type sigs with corresponding scdefs -- TODO: emit pragmas for datatags -instance (Pretty b) => Pretty (Program b) where - pretty = vsepOf (programScDefs . each . to pretty) +instance (Hashable b, Pretty b) => Pretty (Program b) where + -- pretty = vsepOf (programScDefs . each . to pretty) + pretty = vlinesOf (programJoinedDefs . to prettyGroup) where + programJoinedDefs :: Fold (Program b) (These (b, Type) (ScDef b)) + programJoinedDefs = folding $ \p -> + foldMapOf programTypeSigs thing1 p + `u` foldMapOf programScDefs thing2 p + where u = H.unionWith unionThese + + thing1 = ifoldMap @b @(HashMap b) + (\n t -> H.singleton n (This (n,t))) + thing2 = foldMap $ \sc -> + H.singleton (sc ^. _lhs . _1) (That sc) + + prettyGroup :: These (b, Type) (ScDef b) -> Doc + prettyGroup = bifoldr ($$) ($$) mempty . bimap prettyTySig pretty + + prettyTySig (n,t) = hsep [ttext n, "::", pretty t] + + unionThese :: forall a b. These a b -> These a b -> These a b + unionThese (This a) (That b) = These a b + unionThese (That b) (This a) = These a b + unionThese (These a b) _ = These a b + +instance Pretty Type where + prettyPrec _ (TyVar n) = ttext n + prettyPrec _ TyFun = "(->)" + prettyPrec _ (TyCon n) = ttext n + prettyPrec p (TyApp f x) = maybeParens (p>0) $ + prettyPrec 0 f <+> prettyPrec 1 x instance (Pretty b) => Pretty (ScDef b) where - pretty sc = hsep [name, as, "=", hang empty 1 e] + pretty sc = hsep [name, as, "=", hang empty 1 e, ";"] where name = ttext $ sc ^. _lhs . _1 as = sc & hsepOf (_lhs . _2 . each . to ttext) diff --git a/src/Data/Pretty.hs b/src/Data/Pretty.hs index f5b1b4d..f16c319 100644 --- a/src/Data/Pretty.hs +++ b/src/Data/Pretty.hs @@ -3,6 +3,8 @@ module Data.Pretty , ttext -- * Pretty-printing lens combinators , hsepOf, vsepOf + , vcatOf + , vlinesOf , module Text.PrettyPrint , maybeParens ) @@ -49,3 +51,10 @@ hsepOf l = foldrOf l (<+>) mempty vsepOf :: Getting (Endo Doc) s Doc -> s -> Doc vsepOf l = foldrOf l ($+$) mempty +vcatOf :: Getting (Endo Doc) s Doc -> s -> Doc +vcatOf l = foldrOf l ($$) mempty + +vlinesOf :: Getting (Endo Doc) s Doc -> s -> Doc +vlinesOf l = foldrOf l (\a b -> a $+$ "" $+$ b) mempty +-- hack(?) to separate chunks with a blankline + -- 2.52.0 From 1c3286f04752bc2c04a0c0cb1a6e9b7b19a79487 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 12:12:57 -0700 Subject: [PATCH 162/192] ppr datatags --- src/Core/Syntax.hs | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index ebc6dca..ad8b67d 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -145,8 +145,8 @@ data Module b = Module (Maybe (Name, [Name])) (Program b) data Program b = Program { _programScDefs :: [ScDef b] , _programTypeSigs :: HashMap b Type - -- map constructors to their tag and arity , _programDataTags :: HashMap b (Tag, Int) + -- ^ map constructors to their tag and arity } deriving (Show, Lift, Generic) deriving (Semigroup, Monoid) @@ -223,28 +223,33 @@ instance HasLHS (Binding b) (Binding b) b b where -- TODO: print type sigs with corresponding scdefs -- TODO: emit pragmas for datatags instance (Hashable b, Pretty b) => Pretty (Program b) where - -- pretty = vsepOf (programScDefs . each . to pretty) - pretty = vlinesOf (programJoinedDefs . to prettyGroup) where - programJoinedDefs :: Fold (Program b) (These (b, Type) (ScDef b)) - programJoinedDefs = folding $ \p -> - foldMapOf programTypeSigs thing1 p - `u` foldMapOf programScDefs thing2 p - where u = H.unionWith unionThese + pretty p = ifoldrOf (programDataTags . ifolded) cataDataTag mempty p + $+$ vlinesOf (programJoinedDefs . to prettyGroup) p + where + programJoinedDefs :: Fold (Program b) (These (b, Type) (ScDef b)) + programJoinedDefs = folding $ \p -> + foldMapOf programTypeSigs thisTs p + `u` foldMapOf programScDefs thatSc p + where u = H.unionWith unionThese - thing1 = ifoldMap @b @(HashMap b) - (\n t -> H.singleton n (This (n,t))) - thing2 = foldMap $ \sc -> - H.singleton (sc ^. _lhs . _1) (That sc) + thisTs = ifoldMap @b @(HashMap b) + (\n t -> H.singleton n (This (n,t))) + thatSc = foldMap $ \sc -> + H.singleton (sc ^. _lhs . _1) (That sc) - prettyGroup :: These (b, Type) (ScDef b) -> Doc - prettyGroup = bifoldr ($$) ($$) mempty . bimap prettyTySig pretty + prettyGroup :: These (b, Type) (ScDef b) -> Doc + prettyGroup = bifoldr ($$) ($$) mempty . bimap prettyTySig pretty - prettyTySig (n,t) = hsep [ttext n, "::", pretty t] + prettyTySig (n,t) = hsep [ttext n, "::", pretty t] - unionThese :: forall a b. These a b -> These a b -> These a b - unionThese (This a) (That b) = These a b - unionThese (That b) (This a) = These a b - unionThese (These a b) _ = These a b + unionThese (This a) (That b) = These a b + unionThese (That b) (This a) = These a b + unionThese (These a b) _ = These a b + + cataDataTag n (t,a) acc = prettyDataTag n t a $+$ acc + + prettyDataTag n t a = + hsep ["{-#", "PackData", ttext n, ttext t, ttext a, "#-}"] instance Pretty Type where prettyPrec _ (TyVar n) = ttext n -- 2.52.0 From 8a94288e5a1f00d4d9312ab6f143e0413bf814f4 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 12:13:40 -0700 Subject: [PATCH 163/192] remove unnecessary comment --- src/Core/Syntax.hs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index ad8b67d..4bd3773 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -279,15 +279,6 @@ instance (Pretty b) => Pretty (Expr b) where "case" <+> pretty e <+> "of" $$ nest 2 (explicitLayout as) -{- - -x = pretty $ desugarRlpProg [rlpProg| - main = 3 - data B = T | F -|] - --} - instance (Pretty b) => Pretty (Alter b) where pretty (Alter c as e) = hsep [pretty c, hsep (pretty <$> as), "->", pretty e] -- 2.52.0 From d2e301fad7d12b3415350327d8996ae227bb745d Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 14:00:43 -0700 Subject: [PATCH 164/192] tidying --- src/Core/Syntax.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 4bd3773..9cb25d7 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -5,10 +5,8 @@ Description : Core ASTs and the like {-# LANGUAGE PatternSynonyms, OverloadedStrings #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE DerivingStrategies, DerivingVia #-} -- for recursion-schemes -{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable - , TemplateHaskell, TypeFamilies #-} +{-# LANGUAGE DeriveTraversable, TypeFamilies #-} module Core.Syntax ( Expr(..) , ExprF(..) -- 2.52.0 From 055fbfd40c57be13954de3976d56293ec1a50ffb Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 14:02:03 -0700 Subject: [PATCH 165/192] .hs -> .cr update examples --- examples/{constDivZero.hs => constDivZero.cr} | 0 examples/{factorial.hs => factorial.cr} | 0 examples/sumList.cr | 12 ++++++++++++ examples/sumList.hs | 9 --------- 4 files changed, 12 insertions(+), 9 deletions(-) rename examples/{constDivZero.hs => constDivZero.cr} (100%) rename examples/{factorial.hs => factorial.cr} (100%) create mode 100644 examples/sumList.cr delete mode 100644 examples/sumList.hs diff --git a/examples/constDivZero.hs b/examples/constDivZero.cr similarity index 100% rename from examples/constDivZero.hs rename to examples/constDivZero.cr diff --git a/examples/factorial.hs b/examples/factorial.cr similarity index 100% rename from examples/factorial.hs rename to examples/factorial.cr diff --git a/examples/sumList.cr b/examples/sumList.cr new file mode 100644 index 0000000..00b3659 --- /dev/null +++ b/examples/sumList.cr @@ -0,0 +1,12 @@ +{-# PackData Nil 0 0 #-} +{-# PackData Cons 1 2 #-} + +foldr f z l = case l of + { Nil -> z + ; Cons x xs -> f x (foldr f z xs) + }; + +list = Cons 1 (Cons 2 (Cons 3 Nil)); + +main = foldr (+#) 0 list; + diff --git a/examples/sumList.hs b/examples/sumList.hs deleted file mode 100644 index 5193a67..0000000 --- a/examples/sumList.hs +++ /dev/null @@ -1,9 +0,0 @@ -nil = Pack{0 0}; -cons x y = Pack{1 2} x y; -list = cons 1 (cons 2 (cons 3 nil)); -sum l = case l of - { <0> -> 0 - ; <1> x xs -> (+#) x (sum xs) - }; -main = sum list; - -- 2.52.0 From 5fdba5b862d73bf3b2b692df943f7ac0b132c412 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 16:29:23 -0700 Subject: [PATCH 166/192] fix evil parser bug (it was a fucking typo) --- src/Core/Syntax.hs | 6 ++++-- src/Rlp/Parse.y | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index 9cb25d7..ae16db0 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -253,8 +253,10 @@ instance Pretty Type where prettyPrec _ (TyVar n) = ttext n prettyPrec _ TyFun = "(->)" prettyPrec _ (TyCon n) = ttext n - prettyPrec p (TyApp f x) = maybeParens (p>0) $ - prettyPrec 0 f <+> prettyPrec 1 x + prettyPrec p (a :-> b) = maybeParens (p>0) $ + hsep [prettyPrec 1 a, "->", prettyPrec 0 b] + prettyPrec p (TyApp f x) = maybeParens (p>1) $ + prettyPrec 1 f <+> prettyPrec 2 x instance (Pretty b) => Pretty (ScDef b) where pretty sc = hsep [name, as, "=", hang empty 1 e, ";"] diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 6f8aeb2..d8c0ff4 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -90,10 +90,9 @@ Decls : Decl ';' Decls { $1 : $3 } | Decl { [$1] } DeclsV :: { [Decl' RlpcPs] } -DeclsV : Decl VS Decls { $1 : $3 } +DeclsV : Decl VS DeclsV { $1 : $3 } | Decl VS { [$1] } | Decl { [$1] } - | {- epsilon -} { [] } VS :: { Located RlpToken } VS : ';' { $1 } -- 2.52.0 From 1d8eddc63f8d05a85829713dc10900ffc5c220e2 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 16:42:37 -0700 Subject: [PATCH 167/192] fix evil lexer bug (it was actually quite subtle unlike prev.) --- src/Rlp/Lex.x | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 3c07c24..f5e7e34 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -335,16 +335,17 @@ doBol inp l = do i <- indentLevel -- traceM $ "i: " <> show i -- important that we pop the lex state lest we find our lexer diverging - popLexState case off of -- the line is aligned with the previous. it therefore belongs to the -- same list - EQ -> insertSemicolon + EQ -> popLexState *> insertSemicolon -- the line is indented further than the previous, so we assume it is a -- line continuation. ignore it and move on! - GT -> lexToken + GT -> popLexState *> lexToken -- the line is indented less than the previous, pop the layout stack and - -- insert a closing brace. + -- insert a closing brace. make VERY good note of the fact that we do not + -- pop the lex state! this means doBol is called until indentation is EQ + -- GT. so if multiple layouts are closed at once, this catches that. LT -> popLayout >> insertRBrace thenDo :: LexerAction a -> P b -> LexerAction a -- 2.52.0 From 6dd581a25f668607b790aa90c03616c7bbc01d13 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 16:42:57 -0700 Subject: [PATCH 168/192] examples --- examples/{ => Core}/sumList.cr | 0 examples/constDivZero.cr | 3 --- examples/factorial.cr | 7 ------- examples/rlp/SumList.rl | 11 +++++++++++ 4 files changed, 11 insertions(+), 10 deletions(-) rename examples/{ => Core}/sumList.cr (100%) delete mode 100644 examples/constDivZero.cr delete mode 100644 examples/factorial.cr create mode 100644 examples/rlp/SumList.rl diff --git a/examples/sumList.cr b/examples/Core/sumList.cr similarity index 100% rename from examples/sumList.cr rename to examples/Core/sumList.cr diff --git a/examples/constDivZero.cr b/examples/constDivZero.cr deleted file mode 100644 index da116f5..0000000 --- a/examples/constDivZero.cr +++ /dev/null @@ -1,3 +0,0 @@ -k x y = x; -main = k 3 ((/#) 1 0); - diff --git a/examples/factorial.cr b/examples/factorial.cr deleted file mode 100644 index 1080c7b..0000000 --- a/examples/factorial.cr +++ /dev/null @@ -1,7 +0,0 @@ -fac n = case (==#) n 0 of - { <1> -> 1 - ; <0> -> (*#) n (fac ((-#) n 1)) - }; - -main = fac 3; - diff --git a/examples/rlp/SumList.rl b/examples/rlp/SumList.rl new file mode 100644 index 0000000..9386c2f --- /dev/null +++ b/examples/rlp/SumList.rl @@ -0,0 +1,11 @@ +data List a = Nil | Cons a (List a) + +foldr :: (a -> b -> b) -> b -> List a -> b +foldr f z l = case l of + Nil -> z + Cons a as -> f a (foldr f z as) + +list = Cons 1 (Cons 2 (Cons 3 Nil)) + +main = foldr f 0 list + -- 2.52.0 From a2b4bd2afc24c2f473ef98a914c2e31315849e95 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 16:43:02 -0700 Subject: [PATCH 169/192] examples --- examples/Core/constDivZero.cr | 3 +++ examples/Core/factorial.cr | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 examples/Core/constDivZero.cr create mode 100644 examples/Core/factorial.cr diff --git a/examples/Core/constDivZero.cr b/examples/Core/constDivZero.cr new file mode 100644 index 0000000..da116f5 --- /dev/null +++ b/examples/Core/constDivZero.cr @@ -0,0 +1,3 @@ +k x y = x; +main = k 3 ((/#) 1 0); + diff --git a/examples/Core/factorial.cr b/examples/Core/factorial.cr new file mode 100644 index 0000000..1080c7b --- /dev/null +++ b/examples/Core/factorial.cr @@ -0,0 +1,7 @@ +fac n = case (==#) n 0 of + { <1> -> 1 + ; <0> -> (*#) n (fac ((-#) n 1)) + }; + +main = fac 3; + -- 2.52.0 From 17058d3f8cd7b3a749a6f8a1513509bd94c2f9fc Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Thu, 8 Feb 2024 18:40:46 -0700 Subject: [PATCH 170/192] letrec + typechecking core --- src/Control/Monad/Errorful.hs | 4 ++++ src/Core/HindleyMilner.hs | 20 +++++++++++------- src/Rlp/Lex.x | 2 ++ src/Rlp/Parse.y | 4 +++- src/Rlp/Parse/Types.hs | 2 ++ src/Rlp/Syntax.hs | 39 +++++++++++++++++++++-------------- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/Control/Monad/Errorful.hs b/src/Control/Monad/Errorful.hs index f788aaf..1d46e91 100644 --- a/src/Control/Monad/Errorful.hs +++ b/src/Control/Monad/Errorful.hs @@ -8,6 +8,7 @@ module Control.Monad.Errorful , errorful , runErrorful , mapErrorful + , hoistErrorfulT , MonadErrorful(..) ) where @@ -74,6 +75,9 @@ mapErrorful f (ErrorfulT m) = ErrorfulT $ -- mapErrorful f = coerced . mapped . _2 . mapped %~ f -- lol +hoistErrorfulT :: (forall a. m a -> n a) -> ErrorfulT e m a -> ErrorfulT e n a +hoistErrorfulT nt (ErrorfulT m) = ErrorfulT (nt m) + -------------------------------------------------------------------------------- -- daily dose of n^2 instances diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 7dcc4c6..9fa3208 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -22,9 +22,13 @@ import Data.Maybe (fromMaybe) import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Foldable (traverse_) +import Data.Functor +import Data.Functor.Identity import Compiler.RLPC +import Compiler.Types +import Compiler.RlpcError import Control.Monad (foldM, void, forM) -import Control.Monad.Errorful (Errorful, addFatal) +import Control.Monad.Errorful import Control.Monad.State import Control.Monad.Utils (mapAccumLM) import Text.Printf @@ -38,8 +42,6 @@ type Context b = [(b, Type)] -- | Unannotated typing context, AKA our beloved Γ. type Context' = Context Name --- TODO: Errorful monad? - -- | Type error enum. data TypeError -- | Two types could not be unified @@ -93,7 +95,7 @@ check g t1 e = do -- in the mean time all top-level binders must have a type annotation. checkCoreProg :: Program' -> HMError () checkCoreProg p = scDefs - & traverse_ k + & traverse_ k where scDefs = p ^. programScDefs g = gatherTypeSigs p @@ -105,10 +107,14 @@ checkCoreProg p = scDefs where scname = sc ^. _lhs._1 -- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks. -checkCoreProgR :: (Applicative m) => Program' -> RLPCT m Program' -checkCoreProgR p = undefined +checkCoreProgR :: forall m. (Monad m) => Program' -> RLPCT m Program' +checkCoreProgR p = (hoistRlpcT generalise . liftE . checkCoreProg $ p) + $> p + where + liftE = liftErrorful . mapErrorful (errorMsg (SrcSpan 0 0 0 0)) -{-# WARNING checkCoreProgR "unimpl" #-} + generalise :: forall a. Identity a -> m a + generalise (Identity a) = pure a -- | Infer the type of an expression under some context. -- diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index f5e7e34..7b2e75b 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -85,6 +85,7 @@ $white_no_nl+ ; <0> { "let" { constToken TokenLet `thenBeginPush` layout_let } + "letrec" { constToken TokenLet `thenBeginPush` layout_let } "of" { constToken TokenOf `thenBeginPush` layout_of } } @@ -155,6 +156,7 @@ lexReservedName = \case "case" -> TokenCase "of" -> TokenOf "let" -> TokenLet + "letrec" -> TokenLetrec "in" -> TokenIn "infix" -> TokenInfix "infixl" -> TokenInfixL diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index d8c0ff4..652fccc 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -62,6 +62,7 @@ import Compiler.Types infixr { Located _ TokenInfixR } infix { Located _ TokenInfix } let { Located _ TokenLet } + letrec { Located _ TokenLetrec } in { Located _ TokenIn } %nonassoc '=' @@ -190,7 +191,8 @@ AppExpr :: { RlpExpr' RlpcPs } | AppExpr Expr1 { AppE <<~ $1 <~> $2 } LetExpr :: { RlpExpr' RlpcPs } - : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } + : let layout1(Binding) in Expr { $1 \$> LetE $2 $4 } + | letrec layout1(Binding) in Expr { $1 \$> LetrecE $2 $4 } CaseExpr :: { RlpExpr' RlpcPs } : case Expr of layout0(CaseAlt) diff --git a/src/Rlp/Parse/Types.hs b/src/Rlp/Parse/Types.hs index 244b7e1..1f71d2b 100644 --- a/src/Rlp/Parse/Types.hs +++ b/src/Rlp/Parse/Types.hs @@ -64,6 +64,7 @@ type instance XTySigD RlpcPs = () type instance XXDeclD RlpcPs = () type instance XLetE RlpcPs = () +type instance XLetrecE RlpcPs = () type instance XVarE RlpcPs = () type instance XLamE RlpcPs = () type instance XCaseE RlpcPs = () @@ -127,6 +128,7 @@ data RlpToken | TokenCase | TokenOf | TokenLet + | TokenLetrec | TokenIn | TokenInfixL | TokenInfixR diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 55146e0..6ef26fb 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -26,15 +26,15 @@ module Rlp.Syntax -- *** Decl , XFunD, XTySigD, XInfixD, XDataD, XXDeclD -- *** RlpExpr - , XLetE, XVarE, XLamE, XCaseE, XIfE, XAppE, XLitE + , XLetE, XLetrecE, XVarE, XLamE, XCaseE, XIfE, XAppE, XLitE , XParE, XOAppE, XXRlpExprE -- ** Pattern synonyms -- *** Decl , pattern FunD, pattern TySigD, pattern InfixD, pattern DataD , pattern FunD'', pattern TySigD'', pattern InfixD'', pattern DataD'' -- *** RlpExpr - , pattern LetE, pattern VarE, pattern LamE, pattern CaseE, pattern IfE - , pattern AppE, pattern LitE, pattern ParE, pattern OAppE + , pattern LetE, pattern LetrecE, pattern VarE, pattern LamE, pattern CaseE + , pattern IfE , pattern AppE, pattern LitE, pattern ParE, pattern OAppE , pattern XRlpExprE -- *** RlpType , pattern FunConT'', pattern FunT'', pattern AppT'', pattern VarT'' @@ -165,19 +165,21 @@ data ConAlt p = ConAlt (IdP p) [RlpType' p] deriving instance (Show (IdP p), Show (XRec p (RlpType p))) => Show (ConAlt p) -data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) - | VarE' (XVarE p) (IdP p) - | LamE' (XLamE p) [Pat p] (RlpExpr' p) - | CaseE' (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] - | IfE' (XIfE p) (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) - | AppE' (XAppE p) (RlpExpr' p) (RlpExpr' p) - | LitE' (XLitE p) (Lit p) - | ParE' (XParE p) (RlpExpr' p) - | OAppE' (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) +data RlpExpr p = LetE' (XLetE p) [Binding' p] (RlpExpr' p) + | LetrecE' (XLetrecE p) [Binding' p] (RlpExpr' p) + | VarE' (XVarE p) (IdP p) + | LamE' (XLamE p) [Pat p] (RlpExpr' p) + | CaseE' (XCaseE p) (RlpExpr' p) [(Alt p, Where p)] + | IfE' (XIfE p) (RlpExpr' p) (RlpExpr' p) (RlpExpr' p) + | AppE' (XAppE p) (RlpExpr' p) (RlpExpr' p) + | LitE' (XLitE p) (Lit p) + | ParE' (XParE p) (RlpExpr' p) + | OAppE' (XOAppE p) (IdP p) (RlpExpr' p) (RlpExpr' p) | XRlpExprE' !(XXRlpExprE p) deriving (Generic) type family XLetE p +type family XLetrecE p type family XVarE p type family XLamE p type family XCaseE p @@ -189,6 +191,7 @@ type family XOAppE p type family XXRlpExprE p pattern LetE :: (XLetE p ~ ()) => [Binding' p] -> RlpExpr' p -> RlpExpr p +pattern LetrecE :: (XLetrecE p ~ ()) => [Binding' p] -> RlpExpr' p -> RlpExpr p pattern VarE :: (XVarE p ~ ()) => IdP p -> RlpExpr p pattern LamE :: (XLamE p ~ ()) => [Pat p] -> RlpExpr' p -> RlpExpr p pattern CaseE :: (XCaseE p ~ ()) => RlpExpr' p -> [(Alt p, Where p)] -> RlpExpr p @@ -200,6 +203,7 @@ pattern OAppE :: (XOAppE p ~ ()) => IdP p -> RlpExpr' p -> RlpExpr' p -> RlpExpr pattern XRlpExprE :: (XXRlpExprE p ~ ()) => RlpExpr p pattern LetE bs e = LetE' () bs e +pattern LetrecE bs e = LetrecE' () bs e pattern VarE n = VarE' () n pattern LamE as e = LamE' () as e pattern CaseE e as = CaseE' () e as @@ -211,10 +215,10 @@ pattern OAppE n a b = OAppE' () n a b pattern XRlpExprE = XRlpExprE' () deriving instance - ( Show (XLetE p), Show (XVarE p), Show (XLamE p) - , Show (XCaseE p), Show (XIfE p), Show (XAppE p) - , Show (XLitE p), Show (XParE p), Show (XOAppE p) - , Show (XXRlpExprE p) + ( Show (XLetE p), Show (XLetrecE p), Show (XVarE p) + , Show (XLamE p), Show (XCaseE p), Show (XIfE p) + , Show (XAppE p), Show (XLitE p), Show (XParE p) + , Show (XOAppE p), Show (XXRlpExprE p) , PhaseShow p ) => Show (RlpExpr p) @@ -308,6 +312,7 @@ makePrisms ''Pat -------------------------------------------------------------------------------- data RlpExprF p a = LetE'F (XLetE p) [Binding' p] a + | LetrecE'F (XLetrecE p) [Binding' p] a | VarE'F (XVarE p) (IdP p) | LamE'F (XLamE p) [Pat p] a | CaseE'F (XCaseE p) a [(Alt p, Where p)] @@ -324,6 +329,7 @@ type instance Base (RlpExpr p) = RlpExprF p instance (UnXRec p) => Recursive (RlpExpr p) where project = \case LetE' xx bs e -> LetE'F xx bs (unXRec e) + LetrecE' xx bs e -> LetrecE'F xx bs (unXRec e) VarE' xx n -> VarE'F xx n LamE' xx ps e -> LamE'F xx ps (unXRec e) CaseE' xx e as -> CaseE'F xx (unXRec e) as @@ -337,6 +343,7 @@ instance (UnXRec p) => Recursive (RlpExpr p) where instance (WrapXRec p) => Corecursive (RlpExpr p) where embed = \case LetE'F xx bs e -> LetE' xx bs (wrapXRec e) + LetrecE'F xx bs e -> LetrecE' xx bs (wrapXRec e) VarE'F xx n -> VarE' xx n LamE'F xx ps e -> LamE' xx ps (wrapXRec e) CaseE'F xx e as -> CaseE' xx (wrapXRec e) as -- 2.52.0 From 4b8c55d2d86fb89ff927a8a2c7d3a642cd376ded Mon Sep 17 00:00:00 2001 From: crumb <95563276+crumbtoo@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:44:32 -0700 Subject: [PATCH 171/192] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ee49f51..460fced 100644 --- a/README.md +++ b/README.md @@ -159,3 +159,4 @@ than the other release plans. - [ ] Less hacky handling of named data - [ ] Less hacky pragmas - [ ] Choose a target. LLVM, JS, C, and WASM are currently top contenders +- [ ] https://proglangdesign.net/wiki/challenges -- 2.52.0 From 2492660da49dc17424c18416e555c34a3b3fb6aa Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 14:46:50 -0700 Subject: [PATCH 172/192] Rlp2Core: simple let binds --- src/Compiler/Types.hs | 4 ++++ src/Core/Syntax.hs | 4 ++-- src/Rlp/Lex.x | 2 +- src/Rlp/Syntax.hs | 7 +++++++ src/Rlp2Core.hs | 44 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/Compiler/Types.hs b/src/Compiler/Types.hs index 28e4ab4..607a0db 100644 --- a/src/Compiler/Types.hs +++ b/src/Compiler/Types.hs @@ -4,6 +4,7 @@ module Compiler.Types , srcspanLine, srcspanColumn, srcspanAbs, srcspanLen , Located(..) , _Located + , located , nolo , (<<~), (<~>), (<#>) @@ -25,6 +26,9 @@ import Language.Haskell.TH.Syntax (Lift) data Located a = Located SrcSpan a deriving (Show, Lift, Functor) +located :: Lens (Located a) (Located b) a b +located = lens extract ($>) + instance Apply Located where liftF2 f (Located sa p) (Located sb q) = Located (sa <> sb) (p `f` q) diff --git a/src/Core/Syntax.hs b/src/Core/Syntax.hs index ae16db0..c7bc9ee 100644 --- a/src/Core/Syntax.hs +++ b/src/Core/Syntax.hs @@ -270,14 +270,14 @@ instance (Pretty b) => Pretty (Expr b) where prettyPrec _ (Con t a) = "Pack{" <> (ttext t <+> ttext a) <> "}" prettyPrec _ (Lam bs e) = hsep ["λ", hsep (prettyPrec 1 <$> bs), "->", pretty e] prettyPrec _ (Let r bs e) = hsep [word, explicitLayout bs] - $$ hsep ["in", pretty e] + $+$ hsep ["in", pretty e] where word = if r == Rec then "letrec" else "let" prettyPrec p (App f x) = maybeParens (p>0) $ prettyPrec 0 f <+> prettyPrec 1 x prettyPrec _ (Lit l) = pretty l prettyPrec p (Case e as) = maybeParens (p>0) $ "case" <+> pretty e <+> "of" - $$ nest 2 (explicitLayout as) + $+$ nest 2 (explicitLayout as) instance (Pretty b) => Pretty (Alter b) where pretty (Alter c as e) = diff --git a/src/Rlp/Lex.x b/src/Rlp/Lex.x index 7b2e75b..d046499 100644 --- a/src/Rlp/Lex.x +++ b/src/Rlp/Lex.x @@ -85,7 +85,7 @@ $white_no_nl+ ; <0> { "let" { constToken TokenLet `thenBeginPush` layout_let } - "letrec" { constToken TokenLet `thenBeginPush` layout_let } + "letrec" { constToken TokenLetrec `thenBeginPush` layout_let } "of" { constToken TokenOf `thenBeginPush` layout_of } } diff --git a/src/Rlp/Syntax.hs b/src/Rlp/Syntax.hs index 6ef26fb..8b49edc 100644 --- a/src/Rlp/Syntax.hs +++ b/src/Rlp/Syntax.hs @@ -18,6 +18,7 @@ module Rlp.Syntax , ConAlt(..) , Binding(..), Binding' + , _PatB, _FunB , _VarP, _LitP, _ConP -- * Trees That Grow boilerplate @@ -41,6 +42,8 @@ module Rlp.Syntax , pattern ConT'' -- *** Pat , pattern VarP'', pattern LitP'', pattern ConP'' + -- *** Binding + , pattern PatB'' ) where ---------------------------------------------------------------------------------- @@ -253,6 +256,9 @@ data Binding p = PatB (Pat' p) (RlpExpr' p) type Binding' p = XRec p (Binding p) +pattern PatB'' :: (UnXRec p) => Pat' p -> RlpExpr' p -> Binding' p +pattern PatB'' p e <- (unXRec -> PatB p e) + deriving instance (Show (XRec p (Pat p)), Show (XRec p (RlpExpr p)), Show (IdP p) ) => Show (Binding p) @@ -308,6 +314,7 @@ type Lit' p = XRec p (Lit p) makeLenses ''RlpModule makePrisms ''Pat +makePrisms ''Binding -------------------------------------------------------------------------------- diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 887f40c..9740c10 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -17,11 +17,12 @@ import Control.Comonad -- import Lens.Micro.Internal import Control.Lens import Compiler.RLPC -import Data.List (mapAccumL) +import Data.List (mapAccumL, partition) import Data.Text (Text) import Data.Text qualified as T import Data.HashMap.Strict qualified as H import Data.Monoid (Endo(..)) +import Data.Either (partitionEithers) import Data.Foldable import Data.Fix import Data.Maybe (fromJust, fromMaybe) @@ -111,7 +112,7 @@ patArgsToCase e (x,p) = (e', x') where type NameSupply = Labeled NameSupplyLabel (State [IdP RlpcPs]) type NameSupplyLabel = "expr-name-supply" -exprToCore :: (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' +exprToCore :: forall es. (NameSupply :> es) => RlpExpr RlpcPs -> Eff es Expr' exprToCore (VarE n) = pure $ Var (dsNameToName n) @@ -125,11 +126,44 @@ exprToCore (CaseE (unXRec -> e) as) = do e' <- exprToCore e Case e' <$> caseAltToCore `traverse` as +exprToCore (LetE bs e) = letToCore NonRec bs e +exprToCore (LetrecE bs e) = letToCore Rec bs e + exprToCore (LitE l) = litToCore l +letToCore :: forall es. (NameSupply :> es) + => Rec -> [Rlp.Binding' RlpcPs] -> RlpExpr' RlpcPs -> Eff es Expr' +letToCore r bs e = do + (bs',as) <- getParts + e' <- caseify as (unXRec e) + pure $ Let r bs' e' + where + -- partition & map the list of binders into: + -- bs' : the let-binds that may be directly translated to Core + -- let-binds (we do exactly that). this is all the binders that + -- are a simple variable rather than a pattern match. + -- and as : the let-binds that may **not** be directly translated to + -- Core let-exprs. they get turned into case alternates. + getParts = traverse f bs <&> partitionEithers + + f :: Rlp.Binding' RlpcPs + -> Eff es (Either Core.Binding' (Alt RlpcPs)) + f (PatB'' (VarP'' n) e) = Left . (n :=) <$> exprToCore (unXRec e) + f (PatB'' p e) = undefined + + varPatB :: Traversal' (Rlp.Binding' RlpcPs) (IdP RlpcPs) + varPatB = located . _PatB . _1 . located . _VarP + litToCore :: (NameSupply :> es) => Rlp.Lit RlpcPs -> Eff es Expr' litToCore (Rlp.IntL n) = pure . Lit $ Core.IntL n +caseify :: (NameSupply :> es) => [Alt RlpcPs] -> RlpExpr RlpcPs -> Eff es Expr' +caseify as ee = do + ee' <- exprToCore ee + foldrM go ee' as + where + go a e = Case e . pure <$> altToCore a + -- TODO: where-binds caseAltToCore :: (NameSupply :> es) => (Alt RlpcPs, Where RlpcPs) -> Eff es Alter' @@ -137,6 +171,12 @@ caseAltToCore (AltA (unXRec -> p) e, wh) = do e' <- exprToCore . unXRec $ e conToRose p <&> foldFix (branchToCore e') +altToCore :: (NameSupply :> es) + => Alt RlpcPs -> Eff es Alter' +altToCore (AltA (unXRec -> p) e) = do + e' <- exprToCore . unXRec $ e + conToRose p <&> foldFix (branchToCore e') + conToRose :: forall es. (NameSupply :> es) => Pat RlpcPs -> Eff es Rose conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as where -- 2.52.0 From c37e8bdf153708479a9ff7dddaef2fc369b781d9 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 17:04:33 -0700 Subject: [PATCH 173/192] Rlp2Core: pattern let binds --- src/Control/Monad/Utils.hs | 11 ++++++++++ src/Rlp2Core.hs | 41 ++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/Control/Monad/Utils.hs b/src/Control/Monad/Utils.hs index 6cc5521..60681e3 100644 --- a/src/Control/Monad/Utils.hs +++ b/src/Control/Monad/Utils.hs @@ -1,10 +1,13 @@ module Control.Monad.Utils ( mapAccumLM + , Kendo(..) ) where ---------------------------------------------------------------------------------- import Data.Tuple (swap) +import Data.Coerce import Control.Monad.State +import Control.Monad ---------------------------------------------------------------------------------- -- | Monadic variant of @mapAccumL@ @@ -19,3 +22,11 @@ mapAccumLM k s t = swap <$> runStateT (traverse k' t) s k' :: a -> StateT s m b k' a = StateT $ fmap swap <$> flip k a +newtype Kendo m a = Kendo { appKendo :: a -> m a } + +instance (Monad m) => Semigroup (Kendo m a) where + Kendo f <> Kendo g = Kendo (f <=< g) + +instance (Monad m) => Monoid (Kendo m a) where + mempty = Kendo pure + diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 9740c10..142f752 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -9,7 +9,7 @@ module Rlp2Core -------------------------------------------------------------------------------- import Control.Monad import Control.Monad.Writer.CPS -import Control.Monad.Utils (mapAccumLM) +import Control.Monad.Utils import Control.Arrow import Control.Applicative import Control.Comonad @@ -135,8 +135,10 @@ letToCore :: forall es. (NameSupply :> es) => Rec -> [Rlp.Binding' RlpcPs] -> RlpExpr' RlpcPs -> Eff es Expr' letToCore r bs e = do (bs',as) <- getParts - e' <- caseify as (unXRec e) - pure $ Let r bs' e' + e' <- appKendo (foldMap Kendo as) <=< exprToCore $ unXRec e + if null bs' + then pure e' + else pure $ Let r bs' e' where -- partition & map the list of binders into: -- bs' : the let-binds that may be directly translated to Core @@ -147,22 +149,27 @@ letToCore r bs e = do getParts = traverse f bs <&> partitionEithers f :: Rlp.Binding' RlpcPs - -> Eff es (Either Core.Binding' (Alt RlpcPs)) + -> Eff es (Either Core.Binding' (Expr' -> Eff es Expr')) f (PatB'' (VarP'' n) e) = Left . (n :=) <$> exprToCore (unXRec e) - f (PatB'' p e) = undefined - - varPatB :: Traversal' (Rlp.Binding' RlpcPs) (IdP RlpcPs) - varPatB = located . _PatB . _1 . located . _VarP + f (PatB'' p e) = pure $ Right (caseify p e) litToCore :: (NameSupply :> es) => Rlp.Lit RlpcPs -> Eff es Expr' litToCore (Rlp.IntL n) = pure . Lit $ Core.IntL n -caseify :: (NameSupply :> es) => [Alt RlpcPs] -> RlpExpr RlpcPs -> Eff es Expr' -caseify as ee = do - ee' <- exprToCore ee - foldrM go ee' as +{- +let C x = y +in e + +case y of + C x -> e + -} + +caseify :: (NameSupply :> es) + => Pat' RlpcPs -> RlpExpr' RlpcPs -> Expr' -> Eff es Expr' +caseify p (unXRec -> e) i = + Case <$> exprToCore e <*> ((:[]) <$> alt) where - go a e = Case e . pure <$> altToCore a + alt = conToRose (unXRec p) <&> foldFix (branchToCore i) -- TODO: where-binds caseAltToCore :: (NameSupply :> es) @@ -173,8 +180,12 @@ caseAltToCore (AltA (unXRec -> p) e, wh) = do altToCore :: (NameSupply :> es) => Alt RlpcPs -> Eff es Alter' -altToCore (AltA (unXRec -> p) e) = do - e' <- exprToCore . unXRec $ e +altToCore (AltA p e) = altToCore' p e + +altToCore' :: (NameSupply :> es) + => Pat' RlpcPs -> RlpExpr' RlpcPs -> Eff es Alter' +altToCore' (unXRec -> p) (unXRec -> e) = do + e' <- exprToCore e conToRose p <&> foldFix (branchToCore e') conToRose :: forall es. (NameSupply :> es) => Pat RlpcPs -> Eff es Rose -- 2.52.0 From 50a4d0010cd4c158e7b68845f7862fc8e09b77f2 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 17:44:17 -0700 Subject: [PATCH 174/192] small core fixes --- src/Compiler/JustRun.hs | 28 +++++++++-------- src/Core/Examples.hs | 21 +++++++------ src/Core/Lex.x | 17 +++++------ src/Core/Parse.y | 68 ++++++++++++++++++++--------------------- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs index 6a0d4ca..23cdc9e 100644 --- a/src/Compiler/JustRun.hs +++ b/src/Compiler/JustRun.hs @@ -8,9 +8,9 @@ that use Prelude types such as @Either@ and @String@ rather than more complex types such as @RLPC@ or @Text@. -} module Compiler.JustRun - ( justLexSrc - , justParseSrc - , justTypeCheckSrc + ( justLexCore + , justParseCore + , justTypeCheckCore ) where ---------------------------------------------------------------------------------- @@ -21,24 +21,26 @@ import Core.Syntax (Program') import Compiler.RLPC import Control.Arrow ((>>>)) import Control.Monad ((>=>)) +import Control.Comonad +import Control.Lens import Data.Text qualified as T import Data.Function ((&)) import GM ---------------------------------------------------------------------------------- -justLexSrc :: String -> Either [MsgEnvelope RlpcError] [CoreToken] -justLexSrc s = lexCoreR (T.pack s) - & fmap (map $ \ (Located _ _ _ t) -> t) - & rlpcToEither +justLexCore :: String -> Either [MsgEnvelope RlpcError] [CoreToken] +justLexCore s = lexCoreR (T.pack s) + & mapped . each %~ extract + & rlpcToEither -justParseSrc :: String -> Either [MsgEnvelope RlpcError] Program' -justParseSrc s = parse (T.pack s) - & rlpcToEither +justParseCore :: String -> Either [MsgEnvelope RlpcError] Program' +justParseCore s = parse (T.pack s) + & rlpcToEither where parse = lexCoreR >=> parseCoreProgR -justTypeCheckSrc :: String -> Either [MsgEnvelope RlpcError] Program' -justTypeCheckSrc s = typechk (T.pack s) - & rlpcToEither +justTypeCheckCore :: String -> Either [MsgEnvelope RlpcError] Program' +justTypeCheckCore s = typechk (T.pack s) + & rlpcToEither where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR rlpcToEither :: RLPC a -> Either [MsgEnvelope RlpcError] a diff --git a/src/Core/Examples.hs b/src/Core/Examples.hs index ee1fe25..b13abe5 100644 --- a/src/Core/Examples.hs +++ b/src/Core/Examples.hs @@ -76,12 +76,12 @@ negExample3 = [coreProg| arithExample1 :: Program' arithExample1 = [coreProg| - main = (+#) 3 (negate# 2); + main = +# 3 (negate# 2); |] arithExample2 :: Program' arithExample2 = [coreProg| - main = negate# ((+#) 2 ((*#) 5 3)); + main = negate# (+# 2 (*# 5 3)); |] ifExample1 :: Program' @@ -96,7 +96,7 @@ ifExample2 = [coreProg| facExample :: Program' facExample = [coreProg| - fac n = if# ((==#) n 0) 1 ((*#) n (fac ((-#) n 1))); + fac n = if# (==# n 0) 1 (*# n (fac (-# n 1))); main = fac 3; |] @@ -149,14 +149,14 @@ caseBool1 = [coreProg| false = Pack{0 0}; true = Pack{1 0}; - main = _if false ((+#) 2 3) ((*#) 4 5); + main = _if false (+# 2 3) (*# 4 5); |] fac3 :: Program' fac3 = [coreProg| - fac n = case (==#) n 0 of + fac n = case ==# n 0 of { <1> -> 1 - ; <0> -> (*#) n (fac ((-#) n 1)) + ; <0> -> *# n (fac (-# n 1)) }; main = fac 3; @@ -171,7 +171,7 @@ sumList = [coreProg| list = cons 1 (cons 2 (cons 3 nil)); sum l = case l of { <0> -> 0 - ; <1> x xs -> (+#) x (sum xs) + ; <1> x xs -> +# x (sum xs) }; main = sum list; |] @@ -179,7 +179,7 @@ sumList = [coreProg| constDivZero :: Program' constDivZero = [coreProg| k x y = x; - main = k 3 ((/#) 1 0); + main = k 3 (/# 1 0); |] idCase :: Program' @@ -187,7 +187,7 @@ idCase = [coreProg| id x = x; main = id (case Pack{1 0} of - { <1> -> (+#) 2 3 + { <1> -> +# 2 3 }) |] @@ -197,7 +197,7 @@ namedBoolCase :: Program' namedBoolCase = [coreProg| {-# PackData True 1 0 #-} {-# PackData False 0 0 #-} - main = case (==#) 1 1 of + main = case ==# 1 1 of { True -> 123 ; False -> 456 } @@ -243,3 +243,4 @@ namedConsCase = [coreProg| -- ] --} + diff --git a/src/Core/Lex.x b/src/Core/Lex.x index dba29c9..f62fb8d 100644 --- a/src/Core/Lex.x +++ b/src/Core/Lex.x @@ -23,8 +23,9 @@ import Data.String (IsString(..)) import Data.Functor.Identity import Core.Syntax import Compiler.RLPC +import Compiler.Types -- TODO: unify Located definitions -import Compiler.RlpcError hiding (Located(..)) +import Compiler.RlpcError import Lens.Micro import Lens.Micro.TH } @@ -120,11 +121,9 @@ rlp :- } { -data Located a = Located Int Int Int a - deriving Show constTok :: t -> AlexInput -> Int -> Alex (Located t) -constTok t (AlexPn _ y x,_,_,_) l = pure $ Located y x l t +constTok t (AlexPn _ y x,_,_,_) l = pure $ nolo t data CoreToken = TokenLet | TokenLetrec @@ -171,7 +170,7 @@ data SrcErrorType = SrcErrLexical String type Lexer = AlexInput -> Int -> Alex (Located CoreToken) lexWith :: (Text -> CoreToken) -> Lexer -lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s) +lexWith f (AlexPn _ y x,_,_,s) l = pure . nolo . f . T.take l $ s -- | The main lexer driver. lexCore :: Text -> RLPC [Located CoreToken] @@ -191,14 +190,14 @@ lexCoreR = hoistRlpcT generalise . lexCore -- debugging lexCore' :: Text -> RLPC [CoreToken] lexCore' s = fmap f <$> lexCore s - where f (Located _ _ _ t) = t + where f (Located _ t) = t lexStream :: Alex [Located CoreToken] lexStream = do l <- alexMonadScan case l of - Located _ _ _ TokenEOF -> pure [l] - _ -> (l:) <$> lexStream + Located _ TokenEOF -> pure [l] + _ -> (l:) <$> lexStream data ParseError = ParErrLexical String | ParErrParse @@ -214,7 +213,7 @@ instance IsRlpcError ParseError where alexEOF :: Alex (Located CoreToken) alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) -> - Right (st, Located y x 0 TokenEOF) + Right (st, nolo $ TokenEOF) } diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 467216d..3d119cf 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -40,34 +40,34 @@ import Data.HashMap.Strict qualified as H %monad { RLPC } { happyBind } { happyPure } %token - let { Located _ _ _ TokenLet } - letrec { Located _ _ _ TokenLetrec } - module { Located _ _ _ TokenModule } - where { Located _ _ _ TokenWhere } - case { Located _ _ _ TokenCase } - of { Located _ _ _ TokenOf } - pack { Located _ _ _ TokenPack } -- temp - in { Located _ _ _ TokenIn } - litint { Located _ _ _ (TokenLitInt $$) } - varname { Located _ _ _ (TokenVarName $$) } - varsym { Located _ _ _ (TokenVarSym $$) } - conname { Located _ _ _ (TokenConName $$) } - consym { Located _ _ _ (TokenConSym $$) } - alttag { Located _ _ _ (TokenAltTag $$) } - word { Located _ _ _ (TokenWord $$) } - 'λ' { Located _ _ _ TokenLambda } - '->' { Located _ _ _ TokenArrow } - '=' { Located _ _ _ TokenEquals } - '@' { Located _ _ _ TokenTypeApp } - '(' { Located _ _ _ TokenLParen } - ')' { Located _ _ _ TokenRParen } - '{' { Located _ _ _ TokenLBrace } - '}' { Located _ _ _ TokenRBrace } - '{-#' { Located _ _ _ TokenLPragma } - '#-}' { Located _ _ _ TokenRPragma } - ';' { Located _ _ _ TokenSemicolon } - '::' { Located _ _ _ TokenHasType } - eof { Located _ _ _ TokenEOF } + let { Located _ TokenLet } + letrec { Located _ TokenLetrec } + module { Located _ TokenModule } + where { Located _ TokenWhere } + case { Located _ TokenCase } + of { Located _ TokenOf } + pack { Located _ TokenPack } -- temp + in { Located _ TokenIn } + litint { Located _ (TokenLitInt $$) } + varname { Located _ (TokenVarName $$) } + varsym { Located _ (TokenVarSym $$) } + conname { Located _ (TokenConName $$) } + consym { Located _ (TokenConSym $$) } + alttag { Located _ (TokenAltTag $$) } + word { Located _ (TokenWord $$) } + 'λ' { Located _ TokenLambda } + '->' { Located _ TokenArrow } + '=' { Located _ TokenEquals } + '@' { Located _ TokenTypeApp } + '(' { Located _ TokenLParen } + ')' { Located _ TokenRParen } + '{' { Located _ TokenLBrace } + '}' { Located _ TokenRBrace } + '{-#' { Located _ TokenLPragma } + '#-}' { Located _ TokenRPragma } + ';' { Located _ TokenSemicolon } + '::' { Located _ TokenHasType } + eof { Located _ TokenEOF } %% @@ -187,18 +187,18 @@ Id : Var { $1 } | Con { $1 } Var :: { Name } -Var : '(' varsym ')' { $2 } - | varname { $1 } +Var : varname { $1 } + | varsym { $1 } Con :: { Name } -Con : '(' consym ')' { $2 } - | conname { $1 } +Con : conname { $1 } + | consym { $1 } { parseError :: [Located CoreToken] -> RLPC a -parseError (Located y x l t : _) = - error $ show y <> ":" <> show x +parseError (Located _ t : _) = + error $ "" <> ":" <> "" <> ": parse error at token `" <> show t <> "'" {-# WARNING parseError "unimpl" #-} -- 2.52.0 From 615a6f1b07898526945d2fe5d6662b96b79ec959 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 17:56:38 -0700 Subject: [PATCH 175/192] update examples --- examples/Core/constDivZero.cr | 2 +- examples/Core/factorial.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Core/constDivZero.cr b/examples/Core/constDivZero.cr index da116f5..f25e208 100644 --- a/examples/Core/constDivZero.cr +++ b/examples/Core/constDivZero.cr @@ -1,3 +1,3 @@ k x y = x; -main = k 3 ((/#) 1 0); +main = k 3 (/# 1 0); diff --git a/examples/Core/factorial.cr b/examples/Core/factorial.cr index 1080c7b..305e9d8 100644 --- a/examples/Core/factorial.cr +++ b/examples/Core/factorial.cr @@ -1,6 +1,6 @@ fac n = case (==#) n 0 of { <1> -> 1 - ; <0> -> (*#) n (fac ((-#) n 1)) + ; <0> -> *# n (fac (-# n 1)) }; main = fac 3; -- 2.52.0 From 58838b9527f13e94d3fa36f08bf19ce7f86a4104 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 18:07:08 -0700 Subject: [PATCH 176/192] formatting --- src/GM.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GM.hs b/src/GM.hs index 216672d..15e7e14 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -739,7 +739,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileE g e = compileC g e ++ [Eval] compileD :: Env -> [Alter'] -> [(Tag, Code)] - compileD g as = fmap (compileA g) as + compileD g = fmap (compileA g) compileA :: Env -> Alter' -> (Tag, Code) compileA g (Alter (AltTag t) as e) = (t, [Split n] <> c <> [Slide n]) -- 2.52.0 From 17d764c2ec9eefd75d1b21f91b9f1298239b2c1f Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 18:31:37 -0700 Subject: [PATCH 177/192] typed coreExpr quoter --- src/Control/Monad/Utils.hs | 5 +++++ src/Core/HindleyMilner.hs | 10 +++++++--- src/Core/Parse.y | 8 +++++--- src/Core/TH.hs | 19 ++++++++++++------- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Control/Monad/Utils.hs b/src/Control/Monad/Utils.hs index 60681e3..d09e91a 100644 --- a/src/Control/Monad/Utils.hs +++ b/src/Control/Monad/Utils.hs @@ -1,11 +1,13 @@ module Control.Monad.Utils ( mapAccumLM , Kendo(..) + , generalise ) where ---------------------------------------------------------------------------------- import Data.Tuple (swap) import Data.Coerce +import Data.Functor.Identity import Control.Monad.State import Control.Monad ---------------------------------------------------------------------------------- @@ -30,3 +32,6 @@ instance (Monad m) => Semigroup (Kendo m a) where instance (Monad m) => Monoid (Kendo m a) where mempty = Kendo pure +generalise :: (Monad m) => Identity a -> m a +generalise (Identity a) = pure a + diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index 9fa3208..d47689b 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -10,6 +10,7 @@ module Core.HindleyMilner , check , checkCoreProg , checkCoreProgR + , checkCoreExprR , TypeError(..) , HMError ) @@ -30,7 +31,7 @@ import Compiler.RlpcError import Control.Monad (foldM, void, forM) import Control.Monad.Errorful import Control.Monad.State -import Control.Monad.Utils (mapAccumLM) +import Control.Monad.Utils (mapAccumLM, generalise) import Text.Printf import Core.Syntax ---------------------------------------------------------------------------------- @@ -113,8 +114,11 @@ checkCoreProgR p = (hoistRlpcT generalise . liftE . checkCoreProg $ p) where liftE = liftErrorful . mapErrorful (errorMsg (SrcSpan 0 0 0 0)) - generalise :: forall a. Identity a -> m a - generalise (Identity a) = pure a +checkCoreExprR :: (Monad m) => Context' -> Expr' -> RLPCT m Expr' +checkCoreExprR g e = (hoistRlpcT generalise . liftE . infer g $ e) + $> e + where + liftE = liftErrorful . mapErrorful (errorMsg (SrcSpan 0 0 0 0)) -- | Infer the type of an expression under some context. -- diff --git a/src/Core/Parse.y b/src/Core/Parse.y index 3d119cf..fcb6e2c 100644 --- a/src/Core/Parse.y +++ b/src/Core/Parse.y @@ -7,6 +7,7 @@ Description : Parser for the Core language module Core.Parse ( parseCore , parseCoreExpr + , parseCoreExprR , parseCoreProg , parseCoreProgR , module Core.Lex -- temp convenience @@ -16,6 +17,7 @@ module Core.Parse where import Control.Monad ((>=>)) +import Control.Monad.Utils (generalise) import Data.Foldable (foldl') import Data.Functor.Identity import Core.Syntax @@ -226,12 +228,12 @@ insScDef sc = programScDefs %~ (sc:) singletonScDef :: (Hashable b) => ScDef b -> Program b singletonScDef sc = insScDef sc mempty +parseCoreExprR :: (Monad m) => [Located CoreToken] -> RLPCT m Expr' +parseCoreExprR = hoistRlpcT generalise . parseCoreExpr + parseCoreProgR :: forall m. (Monad m) => [Located CoreToken] -> RLPCT m Program' parseCoreProgR = ddumpast <=< (hoistRlpcT generalise . parseCoreProg) where - generalise :: forall a. Identity a -> m a - generalise (Identity a) = pure a - ddumpast :: Program' -> RLPCT m Program' ddumpast p = do addDebugMsg "dump-parsed-core" . show $ p diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 8031314..36a3e3f 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -5,6 +5,7 @@ Description : Core quasiquoters module Core.TH ( coreExpr , coreProg + , coreExprT , coreProgT ) where @@ -22,20 +23,26 @@ import Data.Text qualified as T import Core.Parse import Core.Lex import Core.Syntax -import Core.HindleyMilner (checkCoreProgR) +import Core.HindleyMilner (checkCoreProgR, checkCoreExprR) ---------------------------------------------------------------------------------- coreProg :: QuasiQuoter coreProg = mkqq $ lexCoreR >=> parseCoreProgR coreExpr :: QuasiQuoter -coreExpr = mkqq $ lexCoreR >=> parseCoreExpr +coreExpr = mkqq $ lexCoreR >=> parseCoreExprR -- | Type-checked @coreProg@ coreProgT :: QuasiQuoter coreProgT = mkqq $ lexCoreR >=> parseCoreProgR >=> checkCoreProgR -mkqq :: (Lift a) => (Text -> RLPC a) -> QuasiQuoter +coreExprT :: QuasiQuoter +coreExprT = mkqq $ lexCoreR >=> parseCoreExprR >=> checkCoreExprR g + where + g = [ ("+#", TyCon "Int#" :-> TyCon "Int#" :-> TyCon "Int#") + ] + +mkqq :: (Lift a) => (Text -> RLPCIO a) -> QuasiQuoter mkqq p = QuasiQuoter { quoteExp = mkq p , quotePat = error "core quasiquotes may only be used in expressions" @@ -43,8 +50,6 @@ mkqq p = QuasiQuoter , quoteDec = error "core quasiquotes may only be used in expressions" } -mkq :: (Lift a) => (Text -> RLPC a) -> String -> Q Exp -mkq parse s = case evalRLPC def (parse $ T.pack s) of - (Just a, _) -> lift a - (Nothing, _) -> error "todo: aaahhbbhjhbdjhabsjh" +mkq :: (Lift a) => (Text -> RLPCIO a) -> String -> Q Exp +mkq parse s = liftIO $ evalRLPCIO def (parse $ T.pack s) >>= lift -- 2.52.0 From f53d42bf844ed2b3daa77cc6550a5139c3bf9baf Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Fri, 9 Feb 2024 19:07:34 -0700 Subject: [PATCH 178/192] typechecking things --- src/Core/HindleyMilner.hs | 21 ++++++--------------- src/Core/TH.hs | 2 ++ src/Data/Pretty.hs | 5 +++++ 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Core/HindleyMilner.hs b/src/Core/HindleyMilner.hs index d47689b..17d7118 100644 --- a/src/Core/HindleyMilner.hs +++ b/src/Core/HindleyMilner.hs @@ -21,6 +21,7 @@ import Lens.Micro.Mtl import Lens.Micro.Platform import Data.Maybe (fromMaybe) import Data.Text qualified as T +import Data.Pretty (rpretty) import Data.HashMap.Strict qualified as H import Data.Foldable (traverse_) import Data.Functor @@ -59,26 +60,22 @@ instance IsRlpcError TypeError where -- todo: use anti-parser instead of show TyErrCouldNotUnify t u -> Text [ T.pack $ printf "Could not match type `%s` with `%s`." - (show t) (show u) - , "Expected: " <> tshow t - , "Got: " <> tshow u + (rpretty @String t) (rpretty @String u) + , "Expected: " <> rpretty t + , "Got: " <> rpretty u ] TyErrUntypedVariable n -> Text [ "Untyped (likely undefined) variable `" <> n <> "`" ] TyErrRecursiveType t x -> Text - [ T.pack $ printf "recursive type error lol" + [ T.pack $ printf "Recursive type: `%s' occurs in `%s'" + (rpretty @String t) (rpretty @String x) ] - where tshow = T.pack . show - -- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may -- throw any number of fatal or nonfatal errors. Run with @runErrorful@. type HMError = Errorful TypeError --- TODO: better errors. Errorful-esque, with cummulative errors instead of --- instantly dying. - -- | Assert that an expression unifies with a given type -- -- >>> let e = [coreProg|3|] @@ -281,9 +278,3 @@ demoContext = , ("False", TyCon "Bool") ] -pprintType :: Type -> String -pprintType (s :-> t) = "(" <> pprintType s <> " -> " <> pprintType t <> ")" -pprintType TyFun = "(->)" -pprintType (TyVar x) = x ^. unpacked -pprintType (TyCon t) = t ^. unpacked - diff --git a/src/Core/TH.hs b/src/Core/TH.hs index 36a3e3f..71f6a7a 100644 --- a/src/Core/TH.hs +++ b/src/Core/TH.hs @@ -40,6 +40,8 @@ coreExprT :: QuasiQuoter coreExprT = mkqq $ lexCoreR >=> parseCoreExprR >=> checkCoreExprR g where g = [ ("+#", TyCon "Int#" :-> TyCon "Int#" :-> TyCon "Int#") + , ("id", TyCon "a" :-> TyCon "a") + , ("fix", (TyCon "a" :-> TyCon "a") :-> TyCon "a") ] mkqq :: (Lift a) => (Text -> RLPCIO a) -> QuasiQuoter diff --git a/src/Data/Pretty.hs b/src/Data/Pretty.hs index f16c319..77337d7 100644 --- a/src/Data/Pretty.hs +++ b/src/Data/Pretty.hs @@ -1,5 +1,6 @@ module Data.Pretty ( Pretty(..) + , rpretty , ttext -- * Pretty-printing lens combinators , hsepOf, vsepOf @@ -12,6 +13,7 @@ module Data.Pretty ---------------------------------------------------------------------------------- import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint.HughesPJ hiding ((<>)) +import Text.Printf import Data.String (IsString(..)) import Data.Text.Lens import Data.Monoid @@ -27,6 +29,9 @@ class Pretty a where pretty = prettyPrec 0 prettyPrec a _ = pretty a +rpretty :: (IsString s, Pretty a) => a -> s +rpretty = fromString . render . pretty + instance Pretty String where pretty = Text.PrettyPrint.text -- 2.52.0 From dfad80b163e2fdee17a2b07f4117d3d391884f26 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 12 Feb 2024 07:34:16 -0700 Subject: [PATCH 179/192] lt --- src/GM.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/GM.hs b/src/GM.hs index 15e7e14..3feb86b 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -89,7 +89,7 @@ data Instr = Unwind -- arith | Neg | Add | Sub | Mul | Div -- comparison - | Equals + | Equals | Lesser | Pack Tag Int -- Pack Tag Arity | CaseJump [(Tag, Code)] | Split Int @@ -212,6 +212,7 @@ step st = case head (st ^. gmCode) of Mul -> mulI Div -> divI Equals -> equalsI + Lesser -> lesserI Split n -> splitI n Pack t n -> packI t n CaseJump as -> caseJumpI as @@ -411,8 +412,9 @@ step st = case head (st ^. gmCode) of mulI = primitive2 boxInt unboxInt (*) st divI = primitive2 boxInt unboxInt div st - equalsI :: GmState + lesserI, equalsI :: GmState equalsI = primitive2 boxBool unboxInt (==) st + lesserI = primitive2 boxBool unboxInt (<) st splitI :: Int -> GmState splitI n = st @@ -595,6 +597,7 @@ compiledPrims = , binop "*#" Mul , binop "/#" Div , binop "==#" Equals + , binop "<#" Lesser ] where unop k i = (k, 1, [Push 0, Eval, i, Update 1, Pop 1, Unwind]) @@ -733,6 +736,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileE g ("*#" :$ a :$ b) = inlineOp2 g Mul a b compileE g ("/#" :$ a :$ b) = inlineOp2 g Div a b compileE g ("==#" :$ a :$ b) = inlineOp2 g Equals a b + compileE g ("<#" :$ a :$ b) = inlineOp2 g Lesser a b compileE g (Case e as) = compileE g e <> [CaseJump (compileD g as)] -- 2.52.0 From 941f228c6c87ec4d2dfa978c0749e9738e27ece0 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 12 Feb 2024 07:44:10 -0700 Subject: [PATCH 180/192] decent state! --- examples/rlp/SumList.rl | 2 +- src/Rlp/Parse.y | 1 + src/Rlp2Core.hs | 27 +++++++++------------------ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/examples/rlp/SumList.rl b/examples/rlp/SumList.rl index 9386c2f..4f9a49e 100644 --- a/examples/rlp/SumList.rl +++ b/examples/rlp/SumList.rl @@ -7,5 +7,5 @@ foldr f z l = case l of list = Cons 1 (Cons 2 (Cons 3 Nil)) -main = foldr f 0 list +main = foldr (+#) 0 list diff --git a/src/Rlp/Parse.y b/src/Rlp/Parse.y index 652fccc..4b86aea 100644 --- a/src/Rlp/Parse.y +++ b/src/Rlp/Parse.y @@ -241,6 +241,7 @@ Lit :: { Lit' RlpcPs } Var :: { Located PsName } Var : varname { mkPsName $1 } + | varsym { mkPsName $1 } Con :: { Located PsName } : conname { mkPsName $1 } diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 142f752..70ac008 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -28,6 +28,7 @@ import Data.Fix import Data.Maybe (fromJust, fromMaybe) import Data.Functor.Bind import Data.Function (on) +import GHC.Stack import Debug.Trace import Effectful.State.Static.Local @@ -91,23 +92,13 @@ declToCore (DataD'' n as ds) = fold . getZipList $ t' = foldl TyApp (TyCon n) (TyVar . dsNameToName <$> as) -- TODO: where-binds -declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e''] +declToCore fd@(FunD'' n as e _) = mempty & programScDefs .~ [ScDef n' as' e'] where n' = dsNameToName n - -- e : verbatim function body - -- e' : function body w/ case-exprs matching pattern arguments - -- e'' : exprToCore e' - (e',as') = mapAccumL patArgsToCase (extract e) (names `zip` as) - e'' = runPureEff . runNameSupply n $ exprToCore e' - names = [ nolo $ "$x_" <> tshow n | n <- [0..] ] - tshow = T.pack . show - -patArgsToCase :: RlpExpr RlpcPs -> (IdP' RlpcPs, Pat' RlpcPs) - -> (RlpExpr RlpcPs, Name) -patArgsToCase e (x,p) = (e', x') where - x' = dsNameToName (extract x) - e' = CaseE (VarE <$> x) [(alt, [])] - alt = AltA p (nolo e) + e' = runPureEff . runNameSupply n . exprToCore . unXRec $ e + as' = as <&> \case + (unXRec -> VarP k) -> dsNameToName k + _ -> error "no patargs yet" type NameSupply = Labeled NameSupplyLabel (State [IdP RlpcPs]) type NameSupplyLabel = "expr-name-supply" @@ -172,7 +163,7 @@ caseify p (unXRec -> e) i = alt = conToRose (unXRec p) <&> foldFix (branchToCore i) -- TODO: where-binds -caseAltToCore :: (NameSupply :> es) +caseAltToCore :: (HasCallStack, NameSupply :> es) => (Alt RlpcPs, Where RlpcPs) -> Eff es Alter' caseAltToCore (AltA (unXRec -> p) e, wh) = do e' <- exprToCore . unXRec $ e @@ -188,7 +179,7 @@ altToCore' (unXRec -> p) (unXRec -> e) = do e' <- exprToCore e conToRose p <&> foldFix (branchToCore e') -conToRose :: forall es. (NameSupply :> es) => Pat RlpcPs -> Eff es Rose +conToRose :: forall es. (HasCallStack, NameSupply :> es) => Pat RlpcPs -> Eff es Rose conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as where patToForrest :: Pat' RlpcPs -> Eff es (Tree Rose) @@ -197,7 +188,7 @@ conToRose (ConP cn as) = Fix . Branch cn <$> patToForrest `traverse` as Right <$> liftA2 (,) uniqueName br where br = unwrapFix <$> conToRose (unXRec p) -conToRose _ = error "conToRose: not a ConP!" +conToRose s = error $ "conToRose: not a ConP!: " <> show s branchToCore :: Expr' -> Branch Alter' -> Alter' branchToCore e (Branch cn as) = Alter (AltData cn) myBinds e' -- 2.52.0 From 8ac301aa4823d44169e8ae697cf2ad7ea1feb8ef Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 12 Feb 2024 09:47:16 -0700 Subject: [PATCH 181/192] constants for bool tags --- src/GM.hs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/GM.hs b/src/GM.hs index 3feb86b..84da355 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -40,6 +40,12 @@ import Core2Core import Core ---------------------------------------------------------------------------------- +tag_Bool_True :: Int +tag_Bool_True = 1 + +tag_Bool_False :: Int +tag_Bool_False = 0 + {-} hdbgProg = undefined @@ -195,24 +201,24 @@ isFinal st = null $ st ^. gmCode step :: GmState -> GmState step st = case head (st ^. gmCode) of - Unwind -> unwindI + Unwind -> unwindI PushGlobal n -> pushGlobalI n PushConstr t n -> pushConstrI t n PushInt n -> pushIntI n Push n -> pushI n - MkAp -> mkApI + MkAp -> mkApI Slide n -> slideI n Pop n -> popI n Update n -> updateI n Alloc n -> allocI n - Eval -> evalI - Neg -> negI - Add -> addI - Sub -> subI - Mul -> mulI - Div -> divI - Equals -> equalsI - Lesser -> lesserI + Eval -> evalI + Neg -> negI + Add -> addI + Sub -> subI + Mul -> mulI + Div -> divI + Equals -> equalsI + Lesser -> lesserI Split n -> splitI n Pack t n -> packI t n CaseJump as -> caseJumpI as @@ -556,12 +562,13 @@ boxBool st p = st where h = st ^. gmHeap (h',a) = alloc h (NConstr p' []) - p' = if p then 1 else 0 + p' = if p then tag_Bool_True else tag_Bool_False unboxBool :: Addr -> GmState -> Bool unboxBool a st = case hLookup a h of - Just (NConstr 1 []) -> True - Just (NConstr 0 []) -> False + Just (NConstr t []) + | t == tag_Bool_True -> True + | t == tag_Bool_False -> False Just _ -> error "unboxInt received a non-int" Nothing -> error "unboxInt received an invalid address" where h = st ^. gmHeap -- 2.52.0 From af42d4fbd60d9eb824a4443455ba11d238a987b6 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 12 Feb 2024 11:09:01 -0700 Subject: [PATCH 182/192] print# gm primitive --- src/Data/Heap.hs | 18 +++++++++++++++++- src/GM.hs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Data/Heap.hs b/src/Data/Heap.hs index 2fa28de..878cab6 100644 --- a/src/Data/Heap.hs +++ b/src/Data/Heap.hs @@ -27,6 +27,7 @@ import Debug.Trace import Data.Map.Strict qualified as M import Data.List (intersect) import GHC.Stack (HasCallStack) +import Control.Lens ---------------------------------------------------------------------------------- data Heap a = Heap [Addr] (Map Addr a) @@ -34,6 +35,21 @@ data Heap a = Heap [Addr] (Map Addr a) type Addr = Int +type instance Index (Heap a) = Addr +type instance IxValue (Heap a) = a + +instance Ixed (Heap a) where + ix a k (Heap as m) = Heap as <$> M.alterF k' a m where + k' (Just v) = Just <$> k v + k' Nothing = pure Nothing + +instance At (Heap a) where + at ma k (Heap as m) = Heap as <$> M.alterF k ma m + +instance FoldableWithIndex Addr Heap where + ifoldr fi z (Heap _ m) = ifoldr fi z m + ifoldMap iam (Heap _ m) = ifoldMap iam m + instance Semigroup (Heap a) where Heap ua ma <> Heap ub mb = Heap u m where @@ -54,7 +70,7 @@ instance Foldable Heap where length (Heap _ m) = M.size m instance Traversable Heap where - traverse t (Heap u m) = Heap u <$> (traverse t m) + traverse t (Heap u m) = Heap u <$> traverse t m ---------------------------------------------------------------------------------- diff --git a/src/GM.hs b/src/GM.hs index 84da355..7e272f5 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -32,6 +32,11 @@ import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint.HughesPJ (maybeParens) import Data.Foldable (traverse_) import System.IO (Handle, hPutStrLn) +-- TODO: an actual output system +-- TODO: an actual output system +-- TODO: an actual output system +-- TODO: an actual output system +import System.IO.Unsafe (unsafePerformIO) import Data.String (IsString) import Data.Heap import Debug.Trace @@ -40,6 +45,9 @@ import Core2Core import Core ---------------------------------------------------------------------------------- +tag_Unit_unit :: Int +tag_Unit_unit = 0 + tag_Bool_True :: Int tag_Bool_True = 1 @@ -99,6 +107,7 @@ data Instr = Unwind | Pack Tag Int -- Pack Tag Arity | CaseJump [(Tag, Code)] | Split Int + | Print | Halt deriving (Show, Eq) @@ -222,9 +231,33 @@ step st = case head (st ^. gmCode) of Split n -> splitI n Pack t n -> packI t n CaseJump as -> caseJumpI as + Print -> printI Halt -> haltI where + printI :: GmState + printI = case hLookupUnsafe a h of + NNum n -> (evilTempPrinter `seq` st) + & gmCode .~ i + & gmStack .~ s + where + -- TODO: an actual output system + -- TODO: an actual output system + -- TODO: an actual output system + -- TODO: an actual output system + evilTempPrinter = unsafePerformIO (print n) + NConstr _ as -> st + & gmCode .~ i' ++ i + & gmStack .~ s' + where + i' = mconcat $ replicate n [Eval,Print] + n = length as + s' = as ++ s + where + h = st ^. gmHeap + (a:s) = st ^. gmStack + Print : i = st ^. gmCode + -- nuke the state haltI :: GmState haltI = error "halt#" @@ -605,6 +638,8 @@ compiledPrims = , binop "/#" Div , binop "==#" Equals , binop "<#" Lesser + , ("print#", 1, [ Push 0, Eval, Print, Pack tag_Unit_unit 0, Update 1, Pop 1 + , Unwind]) ] where unop k i = (k, 1, [Push 0, Eval, i, Update 1, Pop 1, Unwind]) -- 2.52.0 From 7b271e5265e7eecafec8bdb8d9c3559507b6549a Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Mon, 12 Feb 2024 11:52:48 -0700 Subject: [PATCH 183/192] bind VarP after pats --- src/Rlp2Core.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Rlp2Core.hs b/src/Rlp2Core.hs index 70ac008..b938b74 100644 --- a/src/Rlp2Core.hs +++ b/src/Rlp2Core.hs @@ -125,11 +125,11 @@ exprToCore (LitE l) = litToCore l letToCore :: forall es. (NameSupply :> es) => Rec -> [Rlp.Binding' RlpcPs] -> RlpExpr' RlpcPs -> Eff es Expr' letToCore r bs e = do + -- TODO: preserve binder order. (bs',as) <- getParts - e' <- appKendo (foldMap Kendo as) <=< exprToCore $ unXRec e - if null bs' - then pure e' - else pure $ Let r bs' e' + let insbs | null bs' = pure + | otherwise = pure . Let r bs' + appKendo (foldMap Kendo (as `snoc` insbs)) <=< exprToCore $ unXRec e where -- partition & map the list of binders into: -- bs' : the let-binds that may be directly translated to Core -- 2.52.0 From de16bf12df9e5d06f661e063fa73d20e5f506e9d Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 10:42:17 -0700 Subject: [PATCH 184/192] fix: tag nested data names --- src/Core2Core.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core2Core.hs b/src/Core2Core.hs index a187a63..d1bcfe3 100644 --- a/src/Core2Core.hs +++ b/src/Core2Core.hs @@ -70,7 +70,7 @@ tagData p = let ?dt = p ^. programDataTags go x = embed x tagAlts :: (?dt :: HashMap Name (Tag, Int)) => Alter' -> Alter' - tagAlts (Alter (AltData c) bs e) = Alter (AltTag tag) bs e + tagAlts (Alter (AltData c) bs e) = Alter (AltTag tag) bs (cata go e) where tag = case ?dt ^. at c of Just (t,_) -> t -- TODO: errorful -- 2.52.0 From bb41d3c1963a428842d6fee81e29935a86545237 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 10:42:45 -0700 Subject: [PATCH 185/192] gte gm prim --- src/GM.hs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/GM.hs b/src/GM.hs index 7e272f5..511ff9f 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -103,7 +103,7 @@ data Instr = Unwind -- arith | Neg | Add | Sub | Mul | Div -- comparison - | Equals | Lesser + | Equals | Lesser | GreaterEq | Pack Tag Int -- Pack Tag Arity | CaseJump [(Tag, Code)] | Split Int @@ -228,6 +228,7 @@ step st = case head (st ^. gmCode) of Div -> divI Equals -> equalsI Lesser -> lesserI + GreaterEq -> greaterEqI Split n -> splitI n Pack t n -> packI t n CaseJump as -> caseJumpI as @@ -451,9 +452,10 @@ step st = case head (st ^. gmCode) of mulI = primitive2 boxInt unboxInt (*) st divI = primitive2 boxInt unboxInt div st - lesserI, equalsI :: GmState + lesserI, greaterEqI, equalsI :: GmState equalsI = primitive2 boxBool unboxInt (==) st lesserI = primitive2 boxBool unboxInt (<) st + greaterEqI = primitive2 boxBool unboxInt (>=) st splitI :: Int -> GmState splitI n = st @@ -638,6 +640,7 @@ compiledPrims = , binop "/#" Div , binop "==#" Equals , binop "<#" Lesser + , binop ">=#" GreaterEq , ("print#", 1, [ Push 0, Eval, Print, Pack tag_Unit_unit 0, Update 1, Pop 1 , Unwind]) ] @@ -743,7 +746,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil mconcat binders <> compileE g' e <> [Slide d] where d = length bs - (g',binders) = mapAccumL compileBinder (argOffset d g) addressed + (g',binders) = mapAccumL compileBinder (argOffset (d-1) g) addressed -- kinda gross. revisit this addressed = bs `zip` reverse [0 .. d-1] @@ -779,6 +782,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileE g ("/#" :$ a :$ b) = inlineOp2 g Div a b compileE g ("==#" :$ a :$ b) = inlineOp2 g Equals a b compileE g ("<#" :$ a :$ b) = inlineOp2 g Lesser a b + compileE g (">=#" :$ a :$ b) = inlineOp2 g GreaterEq a b compileE g (Case e as) = compileE g e <> [CaseJump (compileD g as)] -- 2.52.0 From cd2a283493b32c117189f4315e601a9514a58ebd Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 11:48:03 -0700 Subject: [PATCH 186/192] more nightmare GM fixes --- src/GM.hs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/GM.hs b/src/GM.hs index 511ff9f..942e661 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -11,6 +11,7 @@ module GM , evalProgR , Node(..) , gmEvalProg + , Stats(..) , finalStateOf , resultOf , resultOfExpr @@ -642,7 +643,7 @@ compiledPrims = , binop "<#" Lesser , binop ">=#" GreaterEq , ("print#", 1, [ Push 0, Eval, Print, Pack tag_Unit_unit 0, Update 1, Pop 1 - , Unwind]) + , Unwind ]) ] where unop k i = (k, 1, [Push 0, Eval, i, Update 1, Pop 1, Unwind]) @@ -743,17 +744,16 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileE _ (Lit l) = compileEL l compileE g (Let NonRec bs e) = -- we use compileE instead of compileC - mconcat binders <> compileE g' e <> [Slide d] + mconcat binders <> compileE (trc g') e <> [Slide d] where + trc = traceWith (\s -> "compileE.g': "<>show s) d = length bs - (g',binders) = mapAccumL compileBinder (argOffset (d-1) g) addressed - -- kinda gross. revisit this - addressed = bs `zip` reverse [0 .. d-1] + (g',binders) = mapAccumL compileBinder g bs - compileBinder :: Env -> (Binding', Int) -> (Env, Code) - compileBinder m (k := v, a) = (m',c) + compileBinder :: Env -> Binding' -> (Env, Code) + compileBinder m (k := v) = (m',c) where - m' = (NameKey k, a) : m + m' = (NameKey k, 0) : argOffset 1 m -- make note that we use m rather than m'! c = compileC m v @@ -796,7 +796,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil where n = length as binds = (NameKey <$> as) `zip` [0..] - g' = binds ++ argOffset n g + g' = traceWith (\s -> "compileA.g': "<>show s) $ + binds ++ argOffset n g c = compileE g' e compileA _ (Alter _ as e) = error "GM.compileA found an untagged\ \ constructor, which should have\ -- 2.52.0 From 81b019e659b1b66b25eda2fd16b670896a66b415 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 11:50:10 -0700 Subject: [PATCH 187/192] QuickSort example works i'm gonig to cry --- examples/rlp/QuickSort.rl | 40 +++++++++++++++++++++++++++++++++++++++ src/Compiler/JustRun.hs | 11 ++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 examples/rlp/QuickSort.rl diff --git a/examples/rlp/QuickSort.rl b/examples/rlp/QuickSort.rl new file mode 100644 index 0000000..1d45c1f --- /dev/null +++ b/examples/rlp/QuickSort.rl @@ -0,0 +1,40 @@ +data List a = Nil | Cons a (List a) + +data Bool = False | True + +filter :: (a -> Bool) -> List a -> List a +filter p l = case l of + Nil -> Nil + Cons a as -> + case p a of + True -> Cons a (filter p as) + False -> filter p as + +append :: List a -> List a -> List a +append p q = case p of + Nil -> q + Cons a as -> Cons a (append as q) + +qsort :: List Int# -> List Int# +qsort l = case l of + Nil -> Nil + Cons a as -> + let lesser = filter (>=# a) as + greater = filter (<# a) as + in append (append (qsort lesser) (Cons a Nil)) (qsort greater) + +list = Cons 9 (Cons 2 (Cons 3 (Cons 2 + (Cons 5 (Cons 2 (Cons 12 (Cons 89 Nil))))))) + +list2 = Cons 2 (Cons 3 Nil) + +lt :: Int# -> Int# -> Bool +lt a = (>=# a) + +gte :: Int# -> Int# -> Bool +gte a = (<# a) + +id x = x + +main = print# (qsort list) + diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs index 23cdc9e..8046603 100644 --- a/src/Compiler/JustRun.hs +++ b/src/Compiler/JustRun.hs @@ -11,6 +11,7 @@ module Compiler.JustRun ( justLexCore , justParseCore , justTypeCheckCore + , justHdbg ) where ---------------------------------------------------------------------------------- @@ -20,14 +21,22 @@ import Core.HindleyMilner import Core.Syntax (Program') import Compiler.RLPC import Control.Arrow ((>>>)) -import Control.Monad ((>=>)) +import Control.Monad ((>=>), void) import Control.Comonad import Control.Lens import Data.Text qualified as T import Data.Function ((&)) +import System.IO import GM +import Rlp.Parse +import Rlp2Core ---------------------------------------------------------------------------------- +justHdbg :: String -> IO (Node, Stats) +justHdbg s = do + p <- evalRLPCIO def (parseRlpProgR >=> desugarRlpProgR $ T.pack s) + withFile "/tmp/t.log" WriteMode $ hdbgProg p + justLexCore :: String -> Either [MsgEnvelope RlpcError] [CoreToken] justLexCore s = lexCoreR (T.pack s) & mapped . each %~ extract -- 2.52.0 From 968832bfaf30d49c41014327283febcece630c46 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 11:51:10 -0700 Subject: [PATCH 188/192] remove debug code --- examples/rlp/QuickSort.rl | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/examples/rlp/QuickSort.rl b/examples/rlp/QuickSort.rl index 1d45c1f..4d65229 100644 --- a/examples/rlp/QuickSort.rl +++ b/examples/rlp/QuickSort.rl @@ -26,15 +26,5 @@ qsort l = case l of list = Cons 9 (Cons 2 (Cons 3 (Cons 2 (Cons 5 (Cons 2 (Cons 12 (Cons 89 Nil))))))) -list2 = Cons 2 (Cons 3 Nil) - -lt :: Int# -> Int# -> Bool -lt a = (>=# a) - -gte :: Int# -> Int# -> Bool -gte a = (<# a) - -id x = x - main = print# (qsort list) -- 2.52.0 From 8267548fabc713bb6eca2ff9cc79dcdb72a18709 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 12:01:46 -0700 Subject: [PATCH 189/192] remove debug tracers --- examples/rlp/QuickSort.rl | 1 + src/GM.hs | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/rlp/QuickSort.rl b/examples/rlp/QuickSort.rl index 4d65229..c374aa6 100644 --- a/examples/rlp/QuickSort.rl +++ b/examples/rlp/QuickSort.rl @@ -23,6 +23,7 @@ qsort l = case l of greater = filter (<# a) as in append (append (qsort lesser) (Cons a Nil)) (qsort greater) +list :: List Int# list = Cons 9 (Cons 2 (Cons 3 (Cons 2 (Cons 5 (Cons 2 (Cons 12 (Cons 89 Nil))))))) diff --git a/src/GM.hs b/src/GM.hs index 942e661..5809f16 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -744,9 +744,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil compileE _ (Lit l) = compileEL l compileE g (Let NonRec bs e) = -- we use compileE instead of compileC - mconcat binders <> compileE (trc g') e <> [Slide d] + mconcat binders <> compileE g' e <> [Slide d] where - trc = traceWith (\s -> "compileE.g': "<>show s) d = length bs (g',binders) = mapAccumL compileBinder g bs @@ -796,8 +795,7 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil where n = length as binds = (NameKey <$> as) `zip` [0..] - g' = traceWith (\s -> "compileA.g': "<>show s) $ - binds ++ argOffset n g + g' = binds ++ argOffset n g c = compileE g' e compileA _ (Alter _ as e) = error "GM.compileA found an untagged\ \ constructor, which should have\ -- 2.52.0 From 4c9ceb74d14e3f2956b3be2aa91b5cfc289b87be Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 12:52:06 -0700 Subject: [PATCH 190/192] ready? --- examples/rlp/SumList.rl | 2 +- src/Compiler/JustRun.hs | 2 +- src/GM.hs | 7 +++++-- tst/Arith.hs | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/rlp/SumList.rl b/examples/rlp/SumList.rl index 4f9a49e..92cd410 100644 --- a/examples/rlp/SumList.rl +++ b/examples/rlp/SumList.rl @@ -7,5 +7,5 @@ foldr f z l = case l of list = Cons 1 (Cons 2 (Cons 3 Nil)) -main = foldr (+#) 0 list +main = print# (foldr (+#) 0 list) diff --git a/src/Compiler/JustRun.hs b/src/Compiler/JustRun.hs index 8046603..055062a 100644 --- a/src/Compiler/JustRun.hs +++ b/src/Compiler/JustRun.hs @@ -32,7 +32,7 @@ import Rlp.Parse import Rlp2Core ---------------------------------------------------------------------------------- -justHdbg :: String -> IO (Node, Stats) +justHdbg :: String -> IO GmState justHdbg s = do p <- evalRLPCIO def (parseRlpProgR >=> desugarRlpProgR $ T.pack s) withFile "/tmp/t.log" WriteMode $ hdbgProg p diff --git a/src/GM.hs b/src/GM.hs index 5809f16..d4493cf 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -9,7 +9,10 @@ module GM ( hdbgProg , evalProg , evalProgR + , GmState(..) + , gmCode, gmStack, gmDump, gmHeap, gmEnv, gmStats , Node(..) + , showState , gmEvalProg , Stats(..) , finalStateOf @@ -153,7 +156,7 @@ evalProg p = res <&> (,sts) resAddr = final ^. gmStack ^? _head res = resAddr >>= flip hLookup h -hdbgProg :: Program' -> Handle -> IO (Node, Stats) +hdbgProg :: Program' -> Handle -> IO GmState hdbgProg p hio = do (renderOut . showState) `traverse_` states -- TODO: i'd like the statistics to be at the top of the file, but `sts` @@ -161,7 +164,7 @@ hdbgProg p hio = do -- *can't* get partial logs in the case of a crash. this is in opposition to -- the above traversal which *will* produce partial logs. i love laziness :3 renderOut . showStats $ sts - pure (res, sts) + pure final where renderOut r = hPutStrLn hio $ render r ++ "\n" diff --git a/tst/Arith.hs b/tst/Arith.hs index 2c168c4..2bfb7ed 100644 --- a/tst/Arith.hs +++ b/tst/Arith.hs @@ -41,6 +41,7 @@ evalArith (a ::* b) = evalArith a * evalArith b evalArith (a ::- b) = evalArith a - evalArith b instance Arbitrary ArithExpr where + -- TODO: implement shrink arbitrary = gen 4 where gen :: Int -> Gen ArithExpr -- 2.52.0 From c57da862ae1afe60ce8685b00d88a45d07185097 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 12:57:01 -0700 Subject: [PATCH 191/192] update readme --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 460fced..616061b 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,14 @@ $ cabal test --test-show-details=direct #### TLDR ```sh -# Compile and evaluate examples/factorial.cr, with evaluation info dumped to stderr -$ rlpc -ddump-eval examples/factorial.cr +# Compile and evaluate examples/rlp/QuickSort.rl +$ rlpc examples/QuickSort.rl # Compile and evaluate t.cr, with evaluation info dumped to t.log $ rlpc -ddump-eval -l t.log t.cr # Compile and evaluate t.rl, dumping the desugared Core $ rlpc -ddump-desugared t.rl +# Compile and evaluate t.rl with all compiler messages enabled +$ rlpc -dALL t.rl ``` #### Options @@ -126,7 +128,7 @@ parsing remains. - [x] Garbage Collection - [ ] Stable documentation for the evaluation model -### February Release Plan +### ~~February Release Plan~~ - [x] Beta rl' to Core - [x] UX improvements - [x] Actual compiler errors -- no more unexceptional `error` calls @@ -134,12 +136,14 @@ parsing remains. - [x] Annotate the AST with token positions for errors (NOTE: As of Feb. 1, this has been done, but the locational info is not yet used in error messages) - [x] Compiler architecture diagram -- [ ] More examples +- [x] More examples ### March Release Plan - [ ] Tests - [ ] rl' parser - [ ] rl' lexer +- [ ] Ditch TTG in favour of a simpler AST focusing on extendability via Fix, Free, + Cofree, etc. rather than boilerplate-heavy type families ### Indefinite Release Plan @@ -150,8 +154,6 @@ than the other release plans. - [ ] Complete all TODOs - [ ] Replace mtl with effectful - [ ] rl' type-checker -- [ ] Ditch TTG in favour of a simpler AST focusing on extendability via Fix, Free, - Cofree, etc. rather than boilerplate-heavy type families - [ ] Stable rl' to Core - [ ] Core polish - [ ] Better, stable parser @@ -160,3 +162,4 @@ than the other release plans. - [ ] Less hacky pragmas - [ ] Choose a target. LLVM, JS, C, and WASM are currently top contenders - [ ] https://proglangdesign.net/wiki/challenges + -- 2.52.0 From ccc71a751c550f3a7c91eba3877e8061514c1140 Mon Sep 17 00:00:00 2001 From: crumbtoo Date: Tue, 13 Feb 2024 13:20:39 -0700 Subject: [PATCH 192/192] remove bad, incorrct, outdated docs --- doc/src/commentary/gm.rst | 49 +-------- doc/src/commentary/layout-lexing.rst | 153 --------------------------- src/GM.hs | 2 + 3 files changed, 7 insertions(+), 197 deletions(-) diff --git a/doc/src/commentary/gm.rst b/doc/src/commentary/gm.rst index d1ae166..e471c95 100644 --- a/doc/src/commentary/gm.rst +++ b/doc/src/commentary/gm.rst @@ -63,52 +63,13 @@ an assembly target. The goal of our new G-Machine is to compile a *linear sequence of instructions* which, **when executed**, build up a graph representing the code. -************************** -Trees and Vines, in Theory -************************** - -Rather than instantiating an expression at runtime -- traversing the AST and -building a graph -- we want to compile all expressions at compile-time, -generating a linear sequence of instructions which may be executed to build the -graph. - -************************** -Evaluation: Slurping Vines -************************** - -WIP. - -Laziness --------- - -WIP. - -* Instead of :code:`Slide (n+1); Unwind`, do :code:`Update n; Pop n; Unwind` - -**************************** -Compilation: Squashing Trees -**************************** - -WIP. - -Notice that we do not keep a (local) environment at run-time. The environment -only exists at compile-time to map local names to stack indices. When compiling -a supercombinator, the arguments are enumerated from zero (the top of the -stack), and passed to :code:`compileR` as an environment. +************* +The G-Machine +************* .. literalinclude:: /../../src/GM.hs :dedent: - :start-after: -- >> [ref/compileSc] - :end-before: -- << [ref/compileSc] - :caption: src/GM.hs - -Of course, variables being indexed relative to the top of the stack means that -they will become inaccurate the moment we push or pop the stack a single time. -The way around this is quite simple: simply offset the stack when w - -.. literalinclude:: /../../src/GM.hs - :dedent: - :start-after: -- >> [ref/compileC] - :end-before: -- << [ref/compileC] + :start-after: -- >> [ref/Instr] + :end-before: -- << [ref/Instr] :caption: src/GM.hs diff --git a/doc/src/commentary/layout-lexing.rst b/doc/src/commentary/layout-lexing.rst index 2039b35..e000c3a 100644 --- a/doc/src/commentary/layout-lexing.rst +++ b/doc/src/commentary/layout-lexing.rst @@ -62,159 +62,6 @@ braces and semicolons. In developing our *layout* rules, we will follow in the pattern of translating the whitespace-sensitive source language to an explicitly sectioned language. -But What About Haskell? -*********************** - -Parsing Haskell -- and thus rl' -- is only slightly more complex than Python, -but the design is certainly more sensitive. - -.. code-block:: haskell - - -- line folds - something = this is a - single expression - - -- an extremely common style found in haskell - data Some = Data - { is :: Presented - , in :: This - , silly :: Style - } - - -- another style oddity - -- note that this is not a single - -- continued line! `look at`, - -- `this odd`, and `alignment` are all - -- discrete items! - anotherThing = do look at - this odd - alignment - -But enough fear, lets actually think about implementation. Firstly, some -formality: what do we mean when we say layout? We will define layout as the -rules we apply to an implicitly-sectioned language in order to yield one that is -explicitly-sectioned. We will also define indentation of a lexeme as the column -number of its first character. - -Thankfully for us, our entry point is quite clear; layouts only appear after a -select few keywords, (with a minor exception; TODO: elaborate) being :code:`let` -(followed by supercombinators), :code:`where` (followed by supercombinators), -:code:`do` (followed by expressions), and :code:`of` (followed by alternatives) -(TODO: all of these terms need linked glossary entries). In order to manage the -cascade of layout contexts, our lexer will record a stack for which each element -is either :math:`\varnothing`, denoting an explicit layout written with braces -and semicolons, or a :math:`\langle n \rangle`, denoting an implicitly laid-out -layout where the start of each item belonging to the layout is indented -:math:`n` columns. - -.. code-block:: haskell - - -- layout stack: [] - module M where -- layout stack: [∅] - - f x = let -- layout keyword; remember indentation of next token - y = w * w -- layout stack: [∅, <10>] - w = x + x - -- layout ends here - in do -- layout keyword; next token is a brace! - { -- layout stack: [∅] - print y; - print x; - } - -Finally, we also need the concept of "virtual" brace tokens, which as far as -we're concerned at this moment are exactly like normal brace tokens, except -implicitly inserted by the compiler. With the presented ideas in mind, we may -begin to introduce a small set of informal rules describing the lexer's handling -of layouts, the first being: - -1. If a layout keyword is followed by the token '{', push :math:`\varnothing` - onto the layout context stack. Otherwise, push :math:`\langle n \rangle` onto - the layout context stack where :math:`n` is the indentation of the token - following the layout keyword. Additionally, the lexer is to insert a virtual - opening brace after the token representing the layout keyword. - -Consider the following observations from that previous code sample: - -* Function definitions should belong to a layout, each of which may start at - column 1. - -* A layout can enclose multiple bodies, as seen in the :code:`let`-bindings and - the :code:`do`-expression. - -* Semicolons should *terminate* items, rather than *separate* them. - -Our current focus is the semicolons. In an implicit layout, items are on -separate lines each aligned with the previous. A naïve implementation would be -to insert the semicolon token when the EOL is reached, but this proves unideal -when you consider the alignment requirement. In our implementation, our lexer -will wait until the first token on a new line is reached, then compare -indentation and insert a semicolon if appropriate. This comparison -- the -nondescript measurement of "more, less, or equal indentation" rather than a -numeric value -- is referred to as *offside* by myself internally and the -Haskell report describing layouts. We informally formalise this rule as follows: - -2. When the first token on a line is preceeded only by whitespace, if the - token's first grapheme resides on a column number :math:`m` equal to the - indentation level of the enclosing context -- i.e. the :math:`\langle n - \rangle` on top of the layout stack. Should no such context exist on the - stack, assume :math:`m > n`. - -We have an idea of how to begin layouts, delimit the enclosed items, and last -we'll need to end layouts. This is where the distinction between virtual and -non-virtual brace tokens comes into play. The lexer needs only partial concern -towards closing layouts; the complete responsibility is shared with the parser. -This will be elaborated on in the next section. For now, we will be content with -naïvely inserting a virtual closing brace when a token is indented right of the -layout. - -3. Under the same conditions as rule 2., when :math:`m < n` the lexer shall - insert a virtual closing brace and pop the layout stack. - -This rule covers some cases including the top-level, however, consider -tokenising the :code:`in` in a :code:`let`-expression. If our lexical analysis -framework only allows for lexing a single token at a time, we cannot return both -a virtual right-brace and a :code:`in`. Under this model, the lexer may simply -pop the layout stack and return the :code:`in` token. As we'll see in the next -section, as long as the lexer keeps track of its own context (i.e. the stack), -the parser will cope just fine without the virtual end-brace. - -Parsing Lonely Braces -********************* - -When viewed in the abstract, parsing and tokenising are near-identical tasks yet -the two are very often decomposed into discrete systems with very different -implementations. Lexers operate on streams of text and tokens, while parsers -are typically far less linear, using a parse stack or recursing top-down. A -big reason for this separation is state management: the parser aims to be as -context-free as possible, while the lexer tends to burden the necessary -statefulness. Still, the nature of a stream-oriented lexer makes backtracking -difficult and quite inelegant. - -However, simply declaring a parse error to be not an error at all -counterintuitively proves to be an elegant solution our layout problem which -minimises backtracking and state in both the lexer and the parser. Consider the -following definitions found in rlp's BNF: - -.. productionlist:: rlp - VOpen : `vopen` - VClose : `vclose` | `error` - -A parse error is recovered and treated as a closing brace. Another point of note -in the BNF is the difference between virtual and non-virtual braces (TODO: i -don't like that the BNF is formatted without newlines :/): - -.. productionlist:: rlp - LetExpr : `let` VOpen Bindings VClose `in` Expr | `let` `{` Bindings `}` `in` Expr - -This ensures that non-virtual braces are closed explicitly. - -This set of rules is adequete enough to satisfy our basic concerns about line -continations and layout lists. For a more pedantic description of the layout -system, see `chapter 10 -`_ of the -2010 Haskell Report, which I heavily referenced here. - References ---------- diff --git a/src/GM.hs b/src/GM.hs index d4493cf..c815e83 100644 --- a/src/GM.hs +++ b/src/GM.hs @@ -93,6 +93,7 @@ data Key = NameKey Name | ConstrKey Tag Int deriving (Show, Eq) +-- >> [ref/Instr] data Instr = Unwind | PushGlobal Name | PushConstr Tag Int @@ -114,6 +115,7 @@ data Instr = Unwind | Print | Halt deriving (Show, Eq) +-- << [ref/Instr] data Node = NNum Int | NAp Addr Addr -- 2.52.0