1{-# OPTIONS_GHC -Wall #-}
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.
9module SourceSyntax.Expression where
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)
57 | GLShader String String Literal.GLShaderTipe
60---- SPECIALIZED ASTs ----
62{-| Expressions created by the parser. These use a split representation of type
63annotations and definitions, which is how they appear in source code and how
66type ParseExpr = Expr' ParseDef
67type LParseExpr = LExpr' ParseDef
70 = Def Pattern.Pattern LParseExpr
71 | TypeAnnotation String SrcType.Type
74{-| "Normal" expressions. When the compiler checks that type annotations and
75ports are all paired with definitions in the appropriate order, it collapses
76them into a Def that is easier to work with in later phases of compilation.
78type LExpr = LExpr' Def
81data Def = Definition Pattern.Pattern LExpr (Maybe SrcType.Type)
87tuple :: [LExpr' def] -> Expr' def
88tuple es = Data ("_Tuple" ++ show (length es)) es
90delist :: LExpr' def -> [LExpr' def]
91delist (Location.L _ (Data "::" [h,t])) = h : delist t
95saveEnvName = "_save_the_environment!!!"
97dummyLet :: Pretty def => [def] -> LExpr' def
99 Location.none $ Let defs (Location.none $ Var saveEnvName)
101instance Pretty def => Show (Expr' def) where
102 show = render . pretty
104instance Pretty def => Pretty (Expr' def) where
107 Literal lit -> pretty lit
109 Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
110 ExplicitList es -> P.brackets (commaCat (map pretty es))
111 Binop "-" (Location.L _ (Literal (Literal.IntNum 0))) e ->
112 P.text "-" <> prettyParens e
113 Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
114 where op' = if Help.isOp op then op else "`" ++ op ++ "`"
115 Lambda p e -> P.text "\\" <> args <+> P.text "->" <+> pretty body
117 (ps,body) = collectLambdas (Location.none $ Lambda p e)
118 args = P.sep (map Pattern.prettyParens ps)
119 App _ _ -> P.hang func 2 (P.sep args)
120 where func:args = map prettyParens (collectApps (Location.none expr))
121 MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
123 iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
125 P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
126 , P.text "in" <+> pretty e ]
128 P.hang pexpr 2 (P.vcat (map pretty' pats))
130 pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
131 pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
132 Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
133 Data "[]" [] -> P.text "[]"
135 | Help.isTuple name -> P.parens (commaCat (map pretty es))
136 | otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
137 Access e x -> prettyParens e <> P.text "." <> variable x
138 Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
139 Insert (Location.L _ (Remove e y)) x v ->
140 P.braces (pretty e <+> P.text "-" <+> variable y <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
142 P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
145 P.braces $ P.hang (pretty e <+> P.text "|")
147 (commaSep $ map field fs)
149 field (k,v) = variable k <+> P.text "<-" <+> pretty v
152 P.braces $ P.nest 2 (commaSep $ map field fs)
154 field (x,e) = variable x <+> P.equals <+> pretty e
156 Markdown _ _ _ -> P.text "[markdown| ... |]"
158 GLShader _ _ _ -> P.text "[glShader| ... |]"
160 PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
162 PortOut _ _ signal -> pretty signal
164instance Pretty ParseDef where
167 TypeAnnotation name tipe ->
168 variable name <+> P.colon <+> pretty tipe
170 pretty pattern <+> P.equals <+> pretty expr
172instance Pretty Def where
173 pretty (Definition pattern expr maybeTipe) =
174 P.vcat [ annotation, definition ]
176 definition = pretty pattern <+> P.equals <+> pretty expr
177 annotation = case maybeTipe of
179 Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
181collectApps :: LExpr' def -> [LExpr' def]
182collectApps lexpr@(Location.L _ expr) =
184 App a b -> collectApps a ++ [b]
187collectLambdas :: LExpr' def -> ([Pattern.Pattern], LExpr' def)
188collectLambdas lexpr@(Location.L _ expr) =
190 Lambda pattern body -> (pattern : ps, body')
191 where (ps, body') = collectLambdas body
194prettyParens :: (Pretty def) => LExpr' def -> Doc
195prettyParens (Location.L _ expr) = parensIf needed (pretty expr)
205 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