@@ -0,0 +1,191 @@
1+{-# OPTIONS_GHC -Wall #-}
3+{-| The Abstract Syntax Tree (AST) for expressions comes in a couple formats.
4+The first is the fully general version and is labeled with a prime (Expr').
5+The others are specialized versions of the AST that represent specific phases
6+of the compilation process. I expect there to be more phases as we begin to
7+enrich the AST with more information.
9+module AST.Expression.General where
11+import SourceSyntax.PrettyPrint
12+import Text.PrettyPrint as P
13+import AST.Type (Type)
14+import qualified AST.Variable as Var
15+import qualified SourceSyntax.Helpers as Help
16+import qualified SourceSyntax.Annotation as Annotation
17+import qualified SourceSyntax.Pattern as Pattern
18+import qualified SourceSyntax.Literal as Literal
22+{-| This is a fully general Abstract Syntax Tree (AST) for expressions. It has
23+"type holes" that allow us to enrich the AST with additional information as we
24+move through the compilation process. The type holes are used to represent:
26+ ann: Annotations for arbitrary expressions. Allows you to add information
27+ to the AST like position in source code or inferred types.
29+ def: Definition style. The source syntax separates type annotations and
30+ definitions, but after parsing we check that they are well formed and
33+ var: Representation of variables. Starts as strings, but is later enriched
34+ with information about what module a variable came from.
37+type Expr annotation definition variable =
38+ Annotation.Annotated annotation (Expr' annotation definition variable)
40+data Expr' ann def var
41+ = Literal Literal.Literal
43+ | Range (Expr ann def var) (Expr ann def var)
44+ | ExplicitList [Expr ann def var]
45+ | Binop var (Expr ann def var) (Expr ann def var)
46+ | Lambda (Pattern.Pattern var) (Expr ann def var)
47+ | App (Expr ann def var) (Expr ann def var)
48+ | MultiIf [(Expr ann def var,Expr ann def var)]
49+ | Let [def] (Expr ann def var)
50+ | Case (Expr ann def var) [(Pattern.Pattern var, Expr ann def var)]
51+ | Data String [Expr ann def var]
52+ | Access (Expr ann def var) String
53+ | Remove (Expr ann def var) String
54+ | Insert (Expr ann def var) String (Expr ann def var)
55+ | Modify (Expr ann def var) [(String, Expr ann def var)]
56+ | Record [(String, Expr ann def var)]
57+ | Markdown String String [Expr ann def var]
58+ -- for type checking and code gen only
59+ | PortIn String (Type var)
60+ | PortOut String (Type var) (Expr ann def var)
66+rawVar :: String -> Expr' ann def Var.Raw
67+rawVar x = Var (Var.Raw x)
69+localVar :: String -> Expr' ann def Var.Canonical
70+localVar x = Var (Var.Canonical Var.Local x)
72+tuple :: [Expr ann def var] -> Expr' ann def var
73+tuple es = Data ("_Tuple" ++ show (length es)) es
75+delist :: Expr ann def var -> [Expr ann def var]
76+delist (Annotation.A _ (Data "::" [h,t])) = h : delist t
80+saveEnvName = "_save_the_environment!!!"
82+dummyLet :: (Pretty def) => [def] -> Expr Annotation.Region def Var.Canonical
84+ Annotation.none $ Let defs (Annotation.none $ localVar saveEnvName)
86+instance (Pretty def, Pretty var, Var.ToString var) => Pretty (Expr' ann def var) where
89+ Literal lit -> pretty lit
93+ Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
95+ ExplicitList es -> P.brackets (commaCat (map pretty es))
97+ Binop op (Annotation.A _ (Literal (Literal.IntNum 0))) e
98+ | Var.toString op == "-" ->
99+ P.text "-" <> prettyParens e
101+ Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op'', prettyParens e2 ]
103+ op' = Var.toString op
104+ op'' = if Help.isOp op' then op' else "`" ++ op' ++ "`"
106+ Lambda p e -> P.text "\\" <> args <+> P.text "->" <+> pretty body
108+ (ps,body) = collectLambdas (Annotation.A undefined $ Lambda p e)
109+ args = P.sep (map Pattern.prettyParens ps)
111+ App _ _ -> P.hang func 2 (P.sep args)
113+ func:args = map prettyParens (collectApps (Annotation.A undefined expr))
115+ MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
117+ iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
120+ P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
121+ , P.text "in" <+> pretty e ]
124+ P.hang pexpr 2 (P.vcat (map pretty' pats))
126+ pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
127+ pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
129+ Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
130+ Data "[]" [] -> P.text "[]"
132+ | Help.isTuple name -> P.parens (commaCat (map pretty es))
133+ | otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
135+ Access e x -> prettyParens e <> P.text "." <> variable x
137+ Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
139+ Insert (Annotation.A _ (Remove e y)) x v ->
140+ P.braces $ P.hsep [ pretty e, P.text "-", variable y, P.text "|"
141+ , variable x, P.equals, pretty v ]
144+ P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
147+ P.braces $ P.hang (pretty e <+> P.text "|")
149+ (commaSep $ map field fs)
151+ field (k,v) = variable k <+> P.text "<-" <+> pretty v
154+ P.braces $ P.nest 2 (commaSep $ map field fs)
156+ field (x,e) = variable x <+> P.equals <+> pretty e
158+ Markdown _ _ _ -> P.text "[markdown| ... |]"
160+ PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
162+ PortOut _ _ signal -> pretty signal
164+collectApps :: Expr ann def var -> [Expr ann def var]
165+collectApps annExpr@(Annotation.A _ expr) =
167+ App a b -> collectApps a ++ [b]
170+collectLambdas :: Expr ann def var -> ([Pattern.Pattern var], Expr ann def var)
171+collectLambdas lexpr@(Annotation.A _ expr) =
173+ Lambda pattern body ->
174+ let (ps, body') = collectLambdas body
175+ in (pattern : ps, body')
179+prettyParens :: (Pretty def, Pretty var, Var.ToString var) => Expr ann def var -> Doc
180+prettyParens (Annotation.A _ expr) = parensIf needed (pretty expr)
190+ Data name (_:_) -> name /= "::"