Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 43b65ee

Browse files
author
Patrick Thomson
committed
Merge remote-tracking branch 'origin/master' into build-semantic-core-in-travis
2 parents 470f469 + 5d86878 commit 43b65ee

File tree

12 files changed

+538
-60
lines changed

12 files changed

+538
-60
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
.docsets
44
.stack-work
55
.stack-work-profiling
6+
stack.yaml
7+
stack.yaml.lock
68
profiles
79
/tags
810

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ cabal new-test
108108
cabal new-run semantic -- --help
109109
```
110110

111-
`semantic` requires GHC 8.6.4. We recommend using [`ghcup`][ghcup] to sandbox GHC versions. Our version bounds are based on [Stackage][stackage] LTS versions. The current LTS version is 13.13; `stack` build should also work if you prefer.
111+
`semantic` requires GHC 8.6.4. We recommend using [`ghcup`][ghcup] to sandbox GHC versions. Our version bounds are based on [Stackage][stackage] LTS versions. The current LTS version is 13.13; `stack` build should also work if you prefer, there is an unofficial [`stack.yaml`](https://gist.github.com/jkachmar/f200caee83280f1f25e9cfa2dd2b16bb).
112112

113113
[nix]: https://www.haskell.org/cabal/users-guide/nix-local-build-overview.html
114114
[stackage]: https://stackage.org

docs/core-grammar.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Semantic Core grammar
2+
3+
This is an EBNF grammar for the (experimental) core IR language.
4+
5+
```
6+
expr ::= expr '.' expr
7+
| expr ' '+ expr
8+
| '{' expr (';' expr)* ';'? '}'
9+
| 'if' expr 'then' expr 'else' expr
10+
| ('lexical' | 'import' | 'load') expr
11+
| lit
12+
| 'let'? lvalue '=' expr
13+
| '(' expr ')'
14+
15+
lvalue ::= ident
16+
| parens expr
17+
18+
lit ::= '#true'
19+
| '#false'
20+
| 'unit'
21+
| 'frame'
22+
| lambda
23+
| ident
24+
25+
lambda ::= ('λ' | '\') ident ('->' | '→') expr
26+
27+
ident ::= [A-z_] ([A-z0-9_])*
28+
| '#{' [^{}]+ '}'
29+
| '"' [^"]+ '"'
30+
```

semantic-core/semantic-core.cabal

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,29 @@ library
2626
, Analysis.Typecheck
2727
, Control.Effect.Readline
2828
, Data.Core
29+
, Data.Core.Parser
30+
, Data.Core.Pretty
2931
, Data.File
3032
, Data.Loc
3133
, Data.Name
3234
, Data.Stack
3335
-- other-modules:
3436
-- other-extensions:
35-
build-depends: algebraic-graphs ^>= 0.3
36-
, base >= 4.11 && < 5
37-
, containers ^>= 0.6
38-
, directory ^>= 1.3
39-
, filepath ^>= 1.4
40-
, fused-effects ^>= 0.4
41-
, haskeline ^>= 0.7.5
42-
, prettyprinter ^>= 1.2.1
43-
, semigroupoids ^>= 5.3
44-
, transformers ^>= 0.5.6
37+
build-depends: algebraic-graphs ^>= 0.3
38+
, base >= 4.11 && < 5
39+
, containers ^>= 0.6
40+
, directory ^>= 1.3
41+
, filepath ^>= 1.4
42+
, fused-effects ^>= 0.4
43+
, haskeline ^>= 0.7.5
44+
, parsers ^>= 0.12.10
45+
, prettyprinter ^>= 1.2.1
46+
, prettyprinter-ansi-terminal ^>= 1.1.1
47+
, recursion-schemes ^>= 5.1
48+
, semigroupoids ^>= 5.3
49+
, transformers ^>= 0.5.6
50+
, trifecta ^>= 2
51+
, unordered-containers ^>= 0.2.10
4552
hs-source-dirs: src
4653
default-language: Haskell2010
4754
ghc-options: -Weverything -Wno-missing-local-signatures -Wno-missing-import-lists -Wno-implicit-prelude -Wno-safe -Wno-unsafe -Wno-name-shadowing -Wno-monomorphism-restriction -Wno-missed-specialisations -Wno-all-missed-specialisations
@@ -57,3 +64,17 @@ test-suite doctest
5764
, semantic-core
5865
hs-source-dirs: test
5966
default-language: Haskell2010
67+
68+
test-suite spec
69+
type: exitcode-stdio-1.0
70+
main-is: Spec.hs
71+
other-modules: Generators
72+
build-depends: base
73+
, semantic-core
74+
, hedgehog >= 0.6 && <1
75+
, tasty >= 1.2 && <2
76+
, tasty-hedgehog >= 0.2 && <1
77+
, tasty-hunit >= 0.10 && <1
78+
, trifecta
79+
hs-source-dirs: test
80+
default-language: Haskell2010

semantic-core/src/Analysis/Eval.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ prog6 =
119119
]
120120
]
121121
, File (Loc "main" (locSpan (fromJust here))) $ block
122-
[ Load (String "dep")
122+
[ Load (Var (Path "dep"))
123123
, Let (User "thing") := Var (Path "dep") :. Var (User "var")
124124
]
125125
]

semantic-core/src/Data/Core.hs

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
{-# LANGUAGE DeriveTraversable, FlexibleContexts, LambdaCase, OverloadedStrings, RecordWildCards #-}
1+
{-# LANGUAGE DeriveTraversable, FlexibleContexts, LambdaCase, OverloadedStrings, RecordWildCards, TemplateHaskell, TypeFamilies #-}
22
module Data.Core
33
( Core(..)
4+
, CoreF(..)
45
, Edge(..)
5-
, showCore
66
, lams
77
, ($$*)
88
, unapply
99
, unapplies
1010
, block
1111
, ann
1212
, annWith
13+
, stripAnnotations
1314
) where
1415

1516
import Control.Applicative (Alternative (..))
17+
import Data.Functor.Foldable hiding (ListF(..))
18+
import Data.Functor.Foldable.TH
1619
import Data.Foldable (foldl')
1720
import Data.Loc
1821
import Data.Name
1922
import Data.Stack
20-
import Data.Text.Prettyprint.Doc (Pretty (..), (<+>), vsep)
21-
import qualified Data.Text.Prettyprint.Doc as Pretty
22-
import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty
2323
import GHC.Stack
2424

25+
data Edge = Lexical | Import
26+
deriving (Eq, Ord, Show)
27+
2528
data Core
2629
= Var Name
2730
| Let Name
@@ -50,52 +53,16 @@ infixr 1 :>>
5053
infix 3 :=
5154
infixl 4 :.
5255

53-
data Edge = Lexical | Import
54-
deriving (Eq, Ord, Show)
56+
makeBaseFunctor ''Core
5557

56-
instance Pretty Edge where
57-
pretty = pretty . show
58+
infixl 2 :$$
59+
infixr 1 :>>$
60+
infix 3 :=$
61+
infixl 4 :.$
5862

5963
instance Semigroup Core where
6064
(<>) = (:>>)
6165

62-
softsemi :: Pretty.Doc a
63-
softsemi = Pretty.flatAlt mempty ";"
64-
65-
showCore :: Core -> String
66-
showCore = Pretty.renderString . Pretty.layoutPretty Pretty.defaultLayoutOptions . pretty
67-
68-
instance Pretty Core where
69-
pretty = \case
70-
Var a -> pretty a
71-
Let a -> "let" <+> pretty a
72-
a :>> b -> vsep [pretty a <> softsemi, pretty b]
73-
74-
Lam x f -> vsep [ Pretty.nest 2 $ vsep [ "λ" <> pretty x <+> "-> {"
75-
, pretty f
76-
]
77-
, "}"
78-
]
79-
80-
f :$ x -> pretty f <> "." <> pretty x
81-
Unit -> Pretty.parens mempty
82-
Bool b -> pretty b
83-
If c x y -> Pretty.sep [ "if" <+> pretty c
84-
, "then" <+> pretty x
85-
, "else" <+> pretty y
86-
]
87-
88-
String s -> pretty (show s)
89-
90-
Frame -> Pretty.braces mempty
91-
92-
Load p -> "load" <+> pretty p
93-
Edge e n -> pretty e <+> pretty n
94-
a :. b -> "push" <+> Pretty.parens (pretty a) <+> Pretty.brackets (pretty b)
95-
var := x -> pretty var <+> "=" <+> pretty x
96-
Ann (Loc p s) c -> pretty c <> Pretty.brackets (pretty p <> ":" <> pretty s)
97-
98-
9966
lams :: Foldable t => t Name -> Core -> Core
10067
lams names body = foldr Lam body names
10168

@@ -124,3 +91,8 @@ ann = annWith callStack
12491

12592
annWith :: CallStack -> Core -> Core
12693
annWith callStack c = maybe c (flip Ann c) (stackLoc callStack)
94+
95+
stripAnnotations :: Core -> Core
96+
stripAnnotations = cata go where
97+
go (AnnF _ item) = item
98+
go item = embed item
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
module Data.Core.Parser
2+
( module Text.Trifecta
3+
, core
4+
, lit
5+
, expr
6+
, lvalue
7+
) where
8+
9+
-- Consult @doc/grammar.md@ for an EBNF grammar.
10+
11+
import Control.Applicative
12+
import qualified Data.Char as Char
13+
import Data.Core
14+
import Data.Name
15+
import Data.Semigroup
16+
import Data.String
17+
import qualified Text.Parser.Token as Token
18+
import qualified Text.Parser.Token.Highlight as Highlight
19+
import Text.Trifecta hiding (ident)
20+
21+
-- * Identifier styles and derived parsers
22+
23+
validIdentifierStart :: Char -> Bool
24+
validIdentifierStart c = not (Char.isDigit c) && isSimpleCharacter c
25+
26+
coreIdents :: TokenParsing m => IdentifierStyle m
27+
coreIdents = Token.IdentifierStyle
28+
{ _styleName = "core"
29+
, _styleStart = satisfy validIdentifierStart
30+
, _styleLetter = satisfy isSimpleCharacter
31+
, _styleReserved = reservedNames
32+
, _styleHighlight = Highlight.Identifier
33+
, _styleReservedHighlight = Highlight.ReservedIdentifier
34+
}
35+
36+
reserved :: (TokenParsing m, Monad m) => String -> m ()
37+
reserved = Token.reserve coreIdents
38+
39+
identifier :: (TokenParsing m, Monad m, IsString s) => m s
40+
identifier = choice [quote, plain] <?> "identifier" where
41+
plain = Token.ident coreIdents
42+
quote = between (string "#{") (symbol "}") (fromString <$> some (noneOf "{}"))
43+
44+
-- * Parsers (corresponding to EBNF)
45+
46+
core :: (TokenParsing m, Monad m) => m Core
47+
core = expr
48+
49+
expr :: (TokenParsing m, Monad m) => m Core
50+
expr = atom `chainl1` go where
51+
go = choice [ (:.) <$ dot
52+
, (:$) <$ notFollowedBy dot
53+
]
54+
55+
atom :: (TokenParsing m, Monad m) => m Core
56+
atom = choice
57+
[ comp
58+
, ifthenelse
59+
, edge
60+
, lit
61+
, ident
62+
, assign
63+
, parens expr
64+
]
65+
66+
comp :: (TokenParsing m, Monad m) => m Core
67+
comp = braces (sconcat <$> sepEndByNonEmpty expr semi) <?> "compound statement"
68+
69+
ifthenelse :: (TokenParsing m, Monad m) => m Core
70+
ifthenelse = If
71+
<$ reserved "if" <*> core
72+
<* reserved "then" <*> core
73+
<* reserved "else" <*> core
74+
<?> "if-then-else statement"
75+
76+
assign :: (TokenParsing m, Monad m) => m Core
77+
assign = (:=) <$> try (lvalue <* symbolic '=') <*> core <?> "assignment"
78+
79+
edge :: (TokenParsing m, Monad m) => m Core
80+
edge = kw <*> expr where kw = choice [ Edge Lexical <$ reserved "lexical"
81+
, Edge Import <$ reserved "import"
82+
, Load <$ reserved "load"
83+
]
84+
85+
lvalue :: (TokenParsing m, Monad m) => m Core
86+
lvalue = choice
87+
[ Let <$ reserved "let" <*> name
88+
, ident
89+
, parens expr
90+
]
91+
92+
-- * Literals
93+
94+
name :: (TokenParsing m, Monad m) => m Name
95+
name = choice [regular, strpath] <?> "name" where
96+
regular = User <$> identifier
97+
strpath = Path <$> between (symbolic '"') (symbolic '"') (some $ noneOf "\"")
98+
99+
lit :: (TokenParsing m, Monad m) => m Core
100+
lit = let x `given` n = x <$ reserved n in choice
101+
[ Bool True `given` "#true"
102+
, Bool False `given` "#false"
103+
, Unit `given` "#unit"
104+
, Frame `given` "#frame"
105+
, lambda
106+
] <?> "literal"
107+
108+
lambda :: (TokenParsing m, Monad m) => m Core
109+
lambda = Lam <$ lambduh <*> name <* arrow <*> core <?> "lambda" where
110+
lambduh = symbolic 'λ' <|> symbolic '\\'
111+
arrow = symbol "" <|> symbol "->"
112+
113+
ident :: (Monad m, TokenParsing m) => m Core
114+
ident = Var <$> name <?> "identifier"
115+

0 commit comments

Comments
 (0)