Added purpleflow
This commit is contained in:
parent
8819e10d9e
commit
a45a4e94b3
10
purpleflow/.gitignore
vendored
Normal file
10
purpleflow/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/bower_components/
|
||||
/node_modules/
|
||||
/.pulp-cache/
|
||||
/output/
|
||||
/generated-docs/
|
||||
/.psc-package/
|
||||
/.psc*
|
||||
/.purs*
|
||||
/.psa*
|
||||
/.spago
|
105
purpleflow/packages.dhall
Normal file
105
purpleflow/packages.dhall
Normal file
|
@ -0,0 +1,105 @@
|
|||
{-
|
||||
Welcome to your new Dhall package-set!
|
||||
|
||||
Below are instructions for how to edit this file for most use
|
||||
cases, so that you don't need to know Dhall to use it.
|
||||
|
||||
## Use Cases
|
||||
|
||||
Most will want to do one or both of these options:
|
||||
1. Override/Patch a package's dependency
|
||||
2. Add a package not already in the default package set
|
||||
|
||||
This file will continue to work whether you use one or both options.
|
||||
Instructions for each option are explained below.
|
||||
|
||||
### Overriding/Patching a package
|
||||
|
||||
Purpose:
|
||||
- Change a package's dependency to a newer/older release than the
|
||||
default package set's release
|
||||
- Use your own modified version of some dependency that may
|
||||
include new API, changed API, removed API by
|
||||
using your custom git repo of the library rather than
|
||||
the package set's repo
|
||||
|
||||
Syntax:
|
||||
where `entityName` is one of the following:
|
||||
- dependencies
|
||||
- repo
|
||||
- version
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with packageName.entityName = "new value"
|
||||
-------------------------------
|
||||
|
||||
Example:
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with halogen.version = "master"
|
||||
with halogen.repo = "https://example.com/path/to/git/repo.git"
|
||||
|
||||
with halogen-vdom.version = "v4.0.0"
|
||||
with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies
|
||||
-------------------------------
|
||||
|
||||
### Additions
|
||||
|
||||
Purpose:
|
||||
- Add packages that aren't already included in the default package set
|
||||
|
||||
Syntax:
|
||||
where `<version>` is:
|
||||
- a tag (i.e. "v4.0.0")
|
||||
- a branch (i.e. "master")
|
||||
- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977")
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with new-package-name =
|
||||
{ dependencies =
|
||||
[ "dependency1"
|
||||
, "dependency2"
|
||||
]
|
||||
, repo =
|
||||
"https://example.com/path/to/git/repo.git"
|
||||
, version =
|
||||
"<version>"
|
||||
}
|
||||
-------------------------------
|
||||
|
||||
Example:
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with benchotron =
|
||||
{ dependencies =
|
||||
[ "arrays"
|
||||
, "exists"
|
||||
, "profunctor"
|
||||
, "strings"
|
||||
, "quickcheck"
|
||||
, "lcg"
|
||||
, "transformers"
|
||||
, "foldable-traversable"
|
||||
, "exceptions"
|
||||
, "node-fs"
|
||||
, "node-buffer"
|
||||
, "node-readline"
|
||||
, "datetime"
|
||||
, "now"
|
||||
]
|
||||
, repo =
|
||||
"https://github.com/hdgarrood/purescript-benchotron.git"
|
||||
, version =
|
||||
"v7.0.0"
|
||||
}
|
||||
-------------------------------
|
||||
-}
|
||||
let upstream =
|
||||
https://github.com/purescript/package-sets/releases/download/psc-0.15.4-20220808/packages.dhall
|
||||
sha256:60eee64b04ca0013fae3e02a69fc3b176105c6baa2f31865c67cd5f881a412fd
|
||||
|
||||
in upstream
|
147
purpleflow/packages/core/src/Data/AST.purs
Normal file
147
purpleflow/packages/core/src/Data/AST.purs
Normal file
|
@ -0,0 +1,147 @@
|
|||
module PF.Core.Data.Ast where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Error.Class (class MonadThrow, throwError)
|
||||
import Control.Monad.RWS (modify)
|
||||
import Control.Monad.State (class MonadState)
|
||||
import Data.HashMap (HashMap)
|
||||
import Data.HashMap as HashMap
|
||||
import Data.Maybe (Maybe(..), maybe)
|
||||
import PF.Core.Data.Cst as Cst
|
||||
import Safe.Coerce (coerce)
|
||||
|
||||
newtype VarId = VarId Int
|
||||
newtype DBIndex = DBIndex Int
|
||||
newtype DBLevel = DBLevel Int
|
||||
newtype DBDepth = DBDepth Int
|
||||
|
||||
type Expression = Expression_
|
||||
|
||||
type VarInfo =
|
||||
{ id :: VarId
|
||||
}
|
||||
|
||||
data Expression_
|
||||
= Lambda VarInfo Expression
|
||||
| Var VarInfo DBIndex
|
||||
| Let VarInfo Expression Expression
|
||||
| Call Expression Expression
|
||||
| Pi
|
||||
{ domain :: Expression
|
||||
, codomain :: Expression
|
||||
, var :: Maybe VarInfo
|
||||
}
|
||||
| Annotate
|
||||
{ value :: Expression
|
||||
, type_ :: Expression
|
||||
}
|
||||
| Type
|
||||
|
||||
type DesugarContext =
|
||||
{ scope ::
|
||||
HashMap Cst.VarName
|
||||
{ id :: VarId
|
||||
, level :: DBLevel
|
||||
}
|
||||
, depth :: DBDepth
|
||||
}
|
||||
|
||||
-- | For depth n
|
||||
-- | 0 => n - 0
|
||||
-- | 1 => n - 1
|
||||
-- | ...
|
||||
-- | n - 1 => 1
|
||||
-- | n - 0=> 0
|
||||
levelToIndex :: DBDepth -> DBLevel -> DBIndex
|
||||
levelToIndex (DBDepth depth) (DBLevel level) =
|
||||
DBIndex (depth - level)
|
||||
|
||||
-- | Inverse of levelToIndex
|
||||
indexToLevel :: DBDepth -> DBIndex -> DBLevel
|
||||
indexToLevel (DBDepth depth) (DBIndex index) =
|
||||
DBLevel (depth - index)
|
||||
|
||||
increaseDepth :: DBDepth -> DBDepth
|
||||
increaseDepth (DBDepth a) = DBDepth (a + 1)
|
||||
|
||||
depthToLevel :: DBDepth -> DBLevel
|
||||
depthToLevel = coerce
|
||||
|
||||
type DesugarState = Int
|
||||
|
||||
genId :: forall m. MonadState DesugarState m => m VarId
|
||||
genId = modify ((+) 1) # map coerce
|
||||
|
||||
data DesugarError = VarNotFound Cst.VarName
|
||||
|
||||
fromCST
|
||||
:: forall m
|
||||
. MonadState DesugarState m
|
||||
=> MonadThrow DesugarError m
|
||||
=> DesugarContext
|
||||
-> Cst.Expression
|
||||
-> m Expression
|
||||
fromCST context = case _ of
|
||||
Cst.Type -> pure Type
|
||||
|
||||
Cst.Call f a -> ado
|
||||
f <- fromCST context f
|
||||
a <- fromCST context a
|
||||
in Call f a
|
||||
|
||||
Cst.Annotate { value, type_ } -> ado
|
||||
value <- fromCST context value
|
||||
type_ <- fromCST context type_
|
||||
in Annotate { value, type_ }
|
||||
|
||||
Cst.Var name -> case HashMap.lookup name context.scope of
|
||||
Just { id, level } -> do
|
||||
let index = levelToIndex context.depth level
|
||||
pure $ Var { id } index
|
||||
Nothing -> throwError (VarNotFound name)
|
||||
|
||||
Cst.Lambda arg body -> do
|
||||
id <- genId
|
||||
let extended = extendContext arg id context
|
||||
|
||||
body <- fromCST extended body
|
||||
|
||||
pure $ Lambda { id } body
|
||||
|
||||
Cst.Let var value body -> do
|
||||
id <- genId
|
||||
let extended = extendContext var id context
|
||||
|
||||
value <- fromCST context value
|
||||
body <- fromCST extended body
|
||||
|
||||
pure $ Let { id } value body
|
||||
|
||||
Cst.Pi { var, domain, codomain } -> do
|
||||
id <- genId
|
||||
|
||||
let
|
||||
extended = var # maybe context
|
||||
\var -> extendContext var id context
|
||||
|
||||
domain <- fromCST context domain
|
||||
codomain <- fromCST extended codomain
|
||||
|
||||
pure $ Pi
|
||||
{ domain
|
||||
, codomain
|
||||
, var: var $> { id }
|
||||
}
|
||||
|
||||
where
|
||||
extendContext :: Cst.VarName -> VarId -> DesugarContext -> DesugarContext
|
||||
extendContext var id context = do
|
||||
let depth = increaseDepth context.depth
|
||||
{ depth: depth
|
||||
, scope: HashMap.insert var
|
||||
{ id
|
||||
, level: depthToLevel depth
|
||||
}
|
||||
context.scope
|
||||
}
|
77
purpleflow/packages/core/src/Data/CST.purs
Normal file
77
purpleflow/packages/core/src/Data/CST.purs
Normal file
|
@ -0,0 +1,77 @@
|
|||
module PF.Core.Data.Cst where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Array as Array
|
||||
import Data.CodePoint.Unicode (isAlpha)
|
||||
import Data.Hashable (class Hashable)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Profunctor (dimap)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import PF.ParsingCodec.Parser as PC
|
||||
import Safe.Coerce (coerce)
|
||||
|
||||
newtype VarName = VarName String
|
||||
|
||||
data Expression
|
||||
= Lambda VarName Expression
|
||||
| Var VarName
|
||||
| Let VarName Expression Expression
|
||||
| Call Expression Expression
|
||||
| Pi
|
||||
{ domain :: Expression
|
||||
, codomain :: Expression
|
||||
, var :: Maybe VarName
|
||||
}
|
||||
| Annotate
|
||||
{ value :: Expression
|
||||
, type_ :: Expression
|
||||
}
|
||||
| Type
|
||||
|
||||
-- Explicit syntax:
|
||||
{-
|
||||
- foo
|
||||
- lam x -> ...
|
||||
- let a = b in c
|
||||
- f[a]
|
||||
- pi x : ty -> body
|
||||
- x :: y ???
|
||||
- *
|
||||
-}
|
||||
varName :: PC.ParsingCodec VarName VarName
|
||||
varName = dimap coerce coerce $ PC.takeWhile isAlpha
|
||||
|
||||
codec_
|
||||
:: PC.ParsingCodec Expression Expression
|
||||
-> PC.ParsingCodec Expression Expression
|
||||
codec_ codec =
|
||||
Array.fold
|
||||
[ cType
|
||||
, cLambda
|
||||
]
|
||||
where
|
||||
cType = PC.string "*" `PC.withConstantR` Type
|
||||
cLambda = PC.dimapMaybe
|
||||
translateL
|
||||
translateR
|
||||
( PC.tuple
|
||||
( PC.surround
|
||||
(PC.string "\\")
|
||||
varName
|
||||
(PC.string "->")
|
||||
)
|
||||
codec
|
||||
)
|
||||
where
|
||||
translateR (var /\ expr) = Lambda var expr
|
||||
translateL = case _ of
|
||||
Lambda var expr -> Just (var /\ expr)
|
||||
_ -> Nothing
|
||||
|
||||
---------- Typeclass instances
|
||||
derive instance Eq VarName
|
||||
derive newtype instance Hashable VarName
|
||||
|
||||
derive instance Eq Expression
|
||||
|
189
purpleflow/packages/parsing-codec/src/Parser.purs
Normal file
189
purpleflow/packages/parsing-codec/src/Parser.purs
Normal file
|
@ -0,0 +1,189 @@
|
|||
module PF.ParsingCodec.Parser where
|
||||
|
||||
import Prelude hiding ((*>), (<*))
|
||||
|
||||
import Control.Alternative (guard, (<|>))
|
||||
import Control.Lazy (class Lazy)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Profunctor (class Profunctor)
|
||||
import Data.String as String
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
|
||||
data ParsingCodec i o = ParsingCodec
|
||||
(String -> Maybe (String /\ o))
|
||||
(i -> Maybe String)
|
||||
|
||||
string :: String -> ParsingCodec Unit String
|
||||
string target = ParsingCodec decode encode
|
||||
where
|
||||
encode _ = Just target
|
||||
decode input = do
|
||||
let
|
||||
{ before, after } = String.splitAt
|
||||
(String.length target)
|
||||
input
|
||||
|
||||
guard (target == before)
|
||||
pure (after /\ target)
|
||||
|
||||
takeWhile :: (String.CodePoint -> Boolean) -> ParsingCodec String String
|
||||
takeWhile predicate = ParsingCodec decode encode
|
||||
where
|
||||
encode = Just
|
||||
decode input = do
|
||||
let before = String.takeWhile predicate input
|
||||
let after = String.drop (String.length before) input
|
||||
pure (after /\ before)
|
||||
|
||||
ws :: ParsingCodec Unit String
|
||||
ws = ParsingCodec decode encode
|
||||
where
|
||||
encode _ = Just " "
|
||||
decode input = do
|
||||
let
|
||||
spaces = String.takeWhile
|
||||
(_ == String.codePointFromChar ' ')
|
||||
input
|
||||
|
||||
let after = String.drop (String.length spaces) input
|
||||
pure (after /\ spaces)
|
||||
|
||||
dimapMaybe
|
||||
:: forall i o a b
|
||||
. (a -> Maybe i)
|
||||
-> (o -> b)
|
||||
-> ParsingCodec i o
|
||||
-> ParsingCodec a b
|
||||
dimapMaybe mapI mapO (ParsingCodec decode encode) = ParsingCodec
|
||||
(\input -> decode input <#> map mapO)
|
||||
(mapI >=> encode)
|
||||
|
||||
wss :: ParsingCodec Unit String
|
||||
wss = ParsingCodec decode encode
|
||||
where
|
||||
encode _ = Just ""
|
||||
decode input = do
|
||||
let
|
||||
spaces = String.takeWhile
|
||||
(_ == String.codePointFromChar ' ')
|
||||
input
|
||||
|
||||
guard (spaces /= "")
|
||||
|
||||
let after = String.drop (String.length spaces) input
|
||||
pure (after /\ spaces)
|
||||
|
||||
tuple
|
||||
:: forall a b c d
|
||||
. ParsingCodec a b
|
||||
-> ParsingCodec c d
|
||||
-> ParsingCodec (a /\ c) (b /\ d)
|
||||
tuple (ParsingCodec decodeL encodeL) (ParsingCodec decodeR encodeR) = ParsingCodec decode encode
|
||||
where
|
||||
encode (inputL /\ inputR) = ado
|
||||
a <- encodeL inputL
|
||||
b <- encodeR inputR
|
||||
in (a <> b)
|
||||
|
||||
decode input = do
|
||||
input /\ left <- decodeL input
|
||||
remaining /\ right <- decodeR input
|
||||
pure $ remaining /\ (left /\ right)
|
||||
|
||||
ignoreLeft
|
||||
:: forall a b c
|
||||
. ParsingCodec Unit a
|
||||
-> ParsingCodec b c
|
||||
-> ParsingCodec b c
|
||||
ignoreLeft (ParsingCodec decodeL encodeL) (ParsingCodec decodeR encodeR) = ParsingCodec decode encode
|
||||
where
|
||||
encode input = ado
|
||||
a <- encodeL unit
|
||||
b <- encodeR input
|
||||
in a <> b
|
||||
|
||||
decode input = do
|
||||
input /\ _ <- decodeL input
|
||||
remaining /\ right <- decodeR input
|
||||
pure $ remaining /\ right
|
||||
|
||||
ignoreRight
|
||||
:: forall a b c
|
||||
. ParsingCodec b c
|
||||
-> ParsingCodec Unit a
|
||||
-> ParsingCodec b c
|
||||
ignoreRight (ParsingCodec decodeL encodeL) (ParsingCodec decodeR encodeR) = ParsingCodec decode encode
|
||||
where
|
||||
encode input = ado
|
||||
a <- encodeL input
|
||||
b <- encodeR unit
|
||||
in a <> b
|
||||
|
||||
decode input = do
|
||||
input /\ left <- decodeL input
|
||||
remaining /\ _ <- decodeR input
|
||||
pure $ remaining /\ left
|
||||
|
||||
infixl 4 ignoreRight as <*
|
||||
infixl 4 ignoreLeft as *>
|
||||
|
||||
surround
|
||||
:: forall l r i o
|
||||
. ParsingCodec Unit l
|
||||
-> ParsingCodec i o
|
||||
-> ParsingCodec Unit r
|
||||
-> ParsingCodec i o
|
||||
surround left middle right = left *> middle <* right
|
||||
|
||||
withConstantL
|
||||
:: forall o c
|
||||
. Eq c
|
||||
=> c
|
||||
-> ParsingCodec Unit o
|
||||
-> ParsingCodec c c
|
||||
withConstantL inner (ParsingCodec decode encode) = ParsingCodec
|
||||
decode'
|
||||
encode'
|
||||
where
|
||||
decode' input = decode input <#> map (const inner)
|
||||
encode' output = do
|
||||
guard (output == inner)
|
||||
encode unit
|
||||
|
||||
withConstantR
|
||||
:: forall o c
|
||||
. Eq c
|
||||
=> ParsingCodec Unit o
|
||||
-> c
|
||||
-> ParsingCodec c c
|
||||
withConstantR = flip withConstantL
|
||||
|
||||
infixl 4 withConstantL as <$
|
||||
infixl 4 withConstantR as $>
|
||||
|
||||
decode :: forall i o. ParsingCodec i o -> (String -> Maybe (String /\ o))
|
||||
decode (ParsingCodec r _) = r
|
||||
|
||||
encode :: forall i o. ParsingCodec i o -> (i -> Maybe String)
|
||||
encode (ParsingCodec _ l) = l
|
||||
|
||||
---------- Typeclass instances
|
||||
instance Profunctor ParsingCodec where
|
||||
dimap mapI mapO (ParsingCodec decode encode) = ParsingCodec
|
||||
(\input -> decode input <#> map mapO)
|
||||
(mapI >>> encode)
|
||||
|
||||
instance Semigroup (ParsingCodec i o) where
|
||||
append (ParsingCodec d e) (ParsingCodec d' e') =
|
||||
ParsingCodec decode encode
|
||||
where
|
||||
decode i = d i <|> d' i
|
||||
encode o = e o <|> e' o
|
||||
|
||||
instance Monoid (ParsingCodec s r) where
|
||||
mempty = ParsingCodec (const Nothing) (const Nothing)
|
||||
|
||||
instance Lazy (ParsingCodec i o) where
|
||||
defer mkCodec = ParsingCodec
|
||||
(\i -> decode (mkCodec unit) i)
|
||||
(\o -> encode (mkCodec unit) o)
|
15
purpleflow/spago.dhall
Normal file
15
purpleflow/spago.dhall
Normal file
|
@ -0,0 +1,15 @@
|
|||
{ name = "purpleflow"
|
||||
, dependencies =
|
||||
[ "codec"
|
||||
, "console"
|
||||
, "effect"
|
||||
, "prelude"
|
||||
, "run"
|
||||
, "strings"
|
||||
, "transformers"
|
||||
, "unicode"
|
||||
, "unordered-collections"
|
||||
]
|
||||
, packages = ./packages.dhall
|
||||
, sources = [ "packages/**/*.purs", "test/**/*.purs" ]
|
||||
}
|
4
purpleflow/todo
Normal file
4
purpleflow/todo
Normal file
|
@ -0,0 +1,4 @@
|
|||
**Ast related stuff**
|
||||
- [ ] Define base ast
|
||||
- [ ] Write basic parser
|
||||
- [ ] Write logic for annoatating scopes and stuff
|
Loading…
Reference in a new issue