1{-# OPTIONS_GHC -Wall #-}
2module SourceSyntax.Expression where
3{-| The Abstract Syntax Tree (AST) for expressions comes in a couple formats.
4The first is the fully general version and is labeled with a prime (Expr').
5The others are specialized versions of the AST that represent specific phases
6of the compilation process. I expect there to be more phases as we begin to
7enrich the AST with more information.
11import SourceSyntax.PrettyPrint
12import Text.PrettyPrint as P
13import qualified SourceSyntax.Helpers as Help
14import qualified SourceSyntax.Location as Location
15import qualified SourceSyntax.Pattern as Pattern
16import qualified SourceSyntax.Type as SrcType
17import qualified SourceSyntax.Literal as Literal
21{-| This is a located expression, meaning it is tagged with info about where it
22came from in the source code. Expr' is defined in terms of LExpr' so that the
23location information does not need to be an extra field on every constructor.
25type LExpr' def = Location.Located (Expr' def)
27{-| This is a fully general Abstract Syntax Tree (AST) for expressions. It has
28"type holes" that allow us to enrich the AST with additional information as we
29move through the compilation process. The type holes let us show these
30structural changes in the types. The only type hole right now is:
32 def: Parsing allows two kinds of definitions (type annotations or definitions),
33 but later checks will see that they are well formed and combine them.
37 = Literal Literal.Literal
39 | Range (LExpr' def) (LExpr' def)
40 | ExplicitList [LExpr' def]
41 | Binop String (LExpr' def) (LExpr' def)
42 | Lambda Pattern.Pattern (LExpr' def)
43 | App (LExpr' def) (LExpr' def)
44 | MultiIf [(LExpr' def,LExpr' def)]
45 | Let [def] (LExpr' def)
46 | Case (LExpr' def) [(Pattern.Pattern, LExpr' def)]
47 | Data String [LExpr' def]
48 | Access (LExpr' def) String
49 | Remove (LExpr' def) String
50 | Insert (LExpr' def) String (LExpr' def)
51 | Modify (LExpr' def) [(String, LExpr' def)]
52 | Record [(String, LExpr' def)]
53 | Markdown String String [LExpr' def]
54 -- for type checking and code gen only
55 | PortIn String SrcType.Type
56 | PortOut String SrcType.Type (LExpr' def)
59---- SPECIALIZED ASTs ----
61{-| Expressions created by the parser. These use a split representation of type
62annotations and definitions, which is how they appear in source code and how
65type ParseExpr = Expr' ParseDef
66type LParseExpr = LExpr' ParseDef
69 = Def Pattern.Pattern LParseExpr
70 | TypeAnnotation String SrcType.Type
73{-| "Normal" expressions. When the compiler checks that type annotations and
74ports are all paired with definitions in the appropriate order, it collapses
75them into a Def that is easier to work with in later phases of compilation.
77type LExpr = LExpr' Def
80data Def = Definition Pattern.Pattern LExpr (Maybe SrcType.Type)
86tuple :: [LExpr' def] -> Expr' def
87tuple es = Data ("_Tuple" ++ show (length es)) es
89delist :: LExpr' def -> [LExpr' def]
90delist (Location.L _ (Data "::" [h,t])) = h : delist t
94saveEnvName = "_save_the_environment!!!"
96dummyLet :: Pretty def => [def] -> LExpr' def
98 Location.none $ Let defs (Location.none $ Var saveEnvName)
100instance Pretty def => Show (Expr' def) where
101 show = render . pretty
103instance Pretty def => Pretty (Expr' def) where
106 Literal lit -> pretty lit
108 Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
109 ExplicitList es -> P.brackets (commaCat (map pretty es))
110 Binop "-" (Location.L _ (Literal (Literal.IntNum 0))) e ->
111 P.text "-" <> prettyParens e
112 Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
113 where op' = if Help.isOp op then op else "`" ++ op ++ "`"
114 Lambda p e -> let (ps,body) = collectLambdas (Location.none $ Lambda p e)
115 in P.text "\\" <> P.sep ps <+> P.text "->" <+> pretty body
116 App _ _ -> P.hang func 2 (P.sep args)
117 where func:args = map prettyParens (collectApps (Location.none expr))
118 MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
120 iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
122 P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
123 , P.text "in" <+> pretty e ]
125 P.hang pexpr 2 (P.vcat (map pretty' pats))
127 pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
128 pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
129 Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
130 Data "[]" [] -> P.text "[]"
131 Data name es -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
132 Access e x -> prettyParens e <> P.text "." <> variable x
133 Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
134 Insert (Location.L _ (Remove e y)) x v ->
135 P.braces (pretty e <+> P.text "-" <+> variable y <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
137 P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
140 P.braces $ P.hang (pretty e <+> P.text "|")
142 (commaSep $ map field fs)
144 field (k,v) = variable k <+> P.text "<-" <+> pretty v
147 P.braces $ P.nest 2 (commaSep $ map field fs)
149 field (x,e) = variable x <+> P.equals <+> pretty e
151 Markdown _ _ _ -> P.text "[markdown| ... |]"
153 PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
155 PortOut _ _ signal -> pretty signal
157instance Pretty ParseDef where
160 TypeAnnotation name tipe ->
161 variable name <+> P.colon <+> pretty tipe
163 pretty pattern <+> P.equals <+> pretty expr
165instance Pretty Def where
166 pretty (Definition pattern expr maybeTipe) =
167 P.vcat [ annotation, definition ]
169 definition = pretty pattern <+> P.equals <+> pretty expr
170 annotation = case maybeTipe of
172 Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
174collectApps :: LExpr' def -> [LExpr' def]
175collectApps lexpr@(Location.L _ expr) =
177 App a b -> collectApps a ++ [b]
180collectLambdas :: LExpr' def -> ([Doc], LExpr' def)
181collectLambdas lexpr@(Location.L _ expr) =
183 Lambda pattern body ->
184 let (ps, body') = collectLambdas body
185 in (pretty pattern : ps, body')
188prettyParens :: (Pretty def) => LExpr' def -> Doc
189prettyParens (Location.L _ expr) = parensIf needed (pretty expr)
199 Data name (_:_) -> name /= "::"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list