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 -> P.text "\\" <> args <+> P.text "->" <+> pretty body
116 (ps,body) = collectLambdas (Location.none $ Lambda p e)
117 args = P.sep (map Pattern.prettyParens ps)
118 App _ _ -> P.hang func 2 (P.sep args)
119 where func:args = map prettyParens (collectApps (Location.none expr))
120 MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
122 iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
124 P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
125 , P.text "in" <+> pretty e ]
127 P.hang pexpr 2 (P.vcat (map pretty' pats))
129 pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
130 pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
131 Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
132 Data "[]" [] -> P.text "[]"
134 | Help.isTuple name -> P.parens (commaCat (map pretty es))
135 | otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
136 Access e x -> prettyParens e <> P.text "." <> variable x
137 Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
138 Insert (Location.L _ (Remove e y)) x v ->
139 P.braces (pretty e <+> P.text "-" <+> variable y <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
141 P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
144 P.braces $ P.hang (pretty e <+> P.text "|")
146 (commaSep $ map field fs)
148 field (k,v) = variable k <+> P.text "<-" <+> pretty v
151 P.braces $ P.nest 2 (commaSep $ map field fs)
153 field (x,e) = variable x <+> P.equals <+> pretty e
155 Markdown _ _ _ -> P.text "[markdown| ... |]"
157 PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
159 PortOut _ _ signal -> pretty signal
161instance Pretty ParseDef where
164 TypeAnnotation name tipe ->
165 variable name <+> P.colon <+> pretty tipe
167 pretty pattern <+> P.equals <+> pretty expr
169instance Pretty Def where
170 pretty (Definition pattern expr maybeTipe) =
171 P.vcat [ annotation, definition ]
173 definition = pretty pattern <+> P.equals <+> pretty expr
174 annotation = case maybeTipe of
176 Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
178collectApps :: LExpr' def -> [LExpr' def]
179collectApps lexpr@(Location.L _ expr) =
181 App a b -> collectApps a ++ [b]
184collectLambdas :: LExpr' def -> ([Pattern.Pattern], LExpr' def)
185collectLambdas lexpr@(Location.L _ expr) =
187 Lambda pattern body -> (pattern : ps, body')
188 where (ps, body') = collectLambdas body
191prettyParens :: (Pretty def) => LExpr' def -> Doc
192prettyParens (Location.L _ expr) = parensIf needed (pretty expr)
202 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