2014-01-04 10:39:38 +00:00
|
|
|
{-# OPTIONS_GHC -Wall #-}
|
2014-01-20 22:25:59 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
{-| The Abstract Syntax Tree (AST) for expressions comes in a couple formats.
|
|
|
|
The first is the fully general version and is labeled with a prime (Expr').
|
|
|
|
The others are specialized versions of the AST that represent specific phases
|
|
|
|
of the compilation process. I expect there to be more phases as we begin to
|
|
|
|
enrich the AST with more information.
|
|
|
|
-}
|
2014-01-20 22:25:59 +00:00
|
|
|
module SourceSyntax.Expression where
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2013-07-07 10:56:34 +00:00
|
|
|
import SourceSyntax.PrettyPrint
|
2013-07-07 16:13:40 +00:00
|
|
|
import Text.PrettyPrint as P
|
2013-06-14 01:00:24 +00:00
|
|
|
import qualified SourceSyntax.Helpers as Help
|
2014-02-09 23:17:33 +00:00
|
|
|
import qualified SourceSyntax.Annotation as Annotation
|
2013-06-14 01:00:24 +00:00
|
|
|
import qualified SourceSyntax.Pattern as Pattern
|
2014-01-04 10:39:38 +00:00
|
|
|
import qualified SourceSyntax.Type as SrcType
|
2013-06-14 01:00:24 +00:00
|
|
|
import qualified SourceSyntax.Literal as Literal
|
2014-02-09 23:17:33 +00:00
|
|
|
import qualified SourceSyntax.Variable as Variable
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
---- GENERAL AST ----
|
|
|
|
|
|
|
|
{-| This is a fully general Abstract Syntax Tree (AST) for expressions. It has
|
|
|
|
"type holes" that allow us to enrich the AST with additional information as we
|
2014-02-09 23:17:33 +00:00
|
|
|
move through the compilation process. The type holes are used to represent:
|
|
|
|
|
|
|
|
ann: Annotations for arbitrary expressions. Allows you to add information
|
|
|
|
to the AST like position in source code or inferred types.
|
|
|
|
|
|
|
|
def: Definition style. The source syntax separates type annotations and
|
|
|
|
definitions, but after parsing we check that they are well formed and
|
|
|
|
collapse them.
|
2014-01-03 07:18:42 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
var: Representation of variables. Starts as strings, but is later enriched
|
|
|
|
with information about what module a variable came from.
|
2014-01-03 07:18:42 +00:00
|
|
|
|
|
|
|
-}
|
2014-02-09 23:17:33 +00:00
|
|
|
type GeneralExpr annotation definition variable =
|
|
|
|
Annotation.Annotated annotation (GeneralExpr' annotation definition variable)
|
|
|
|
|
|
|
|
data GeneralExpr' ann def var
|
2013-06-14 03:25:00 +00:00
|
|
|
= Literal Literal.Literal
|
2014-02-09 23:17:33 +00:00
|
|
|
| Var var
|
|
|
|
| Range (GeneralExpr ann def var) (GeneralExpr ann def var)
|
|
|
|
| ExplicitList [GeneralExpr ann def var]
|
|
|
|
| Binop String (GeneralExpr ann def var) (GeneralExpr ann def var)
|
|
|
|
| Lambda Pattern.Pattern (GeneralExpr ann def var)
|
|
|
|
| App (GeneralExpr ann def var) (GeneralExpr ann def var)
|
|
|
|
| MultiIf [(GeneralExpr ann def var,GeneralExpr ann def var)]
|
|
|
|
| Let [def] (GeneralExpr ann def var)
|
|
|
|
| Case (GeneralExpr ann def var) [(Pattern.Pattern, GeneralExpr ann def var)]
|
|
|
|
| Data String [GeneralExpr ann def var]
|
|
|
|
| Access (GeneralExpr ann def var) String
|
|
|
|
| Remove (GeneralExpr ann def var) String
|
|
|
|
| Insert (GeneralExpr ann def var) String (GeneralExpr ann def var)
|
|
|
|
| Modify (GeneralExpr ann def var) [(String, GeneralExpr ann def var)]
|
|
|
|
| Record [(String, GeneralExpr ann def var)]
|
|
|
|
| Markdown String String [GeneralExpr ann def var]
|
2014-01-04 10:39:38 +00:00
|
|
|
-- for type checking and code gen only
|
2014-01-13 18:24:17 +00:00
|
|
|
| PortIn String SrcType.Type
|
2014-02-09 23:17:33 +00:00
|
|
|
| PortOut String SrcType.Type (GeneralExpr ann def var)
|
|
|
|
deriving (Show)
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
|
|
|
|
---- SPECIALIZED ASTs ----
|
|
|
|
|
|
|
|
{-| Expressions created by the parser. These use a split representation of type
|
|
|
|
annotations and definitions, which is how they appear in source code and how
|
|
|
|
they are parsed.
|
|
|
|
-}
|
2014-02-09 23:17:33 +00:00
|
|
|
type ParseExpr = GeneralExpr Annotation.Region ParseDef Variable.Raw
|
|
|
|
type ParseExpr' = GeneralExpr' Annotation.Region ParseDef Variable.Raw
|
2014-01-03 07:18:42 +00:00
|
|
|
|
|
|
|
data ParseDef
|
2014-02-09 23:17:33 +00:00
|
|
|
= Def Pattern.Pattern ParseExpr
|
2014-01-04 10:39:38 +00:00
|
|
|
| TypeAnnotation String SrcType.Type
|
2014-02-09 23:17:33 +00:00
|
|
|
deriving (Show)
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
{-| "Normal" expressions. When the compiler checks that type annotations and
|
|
|
|
ports are all paired with definitions in the appropriate order, it collapses
|
|
|
|
them into a Def that is easier to work with in later phases of compilation.
|
2014-01-03 07:18:42 +00:00
|
|
|
-}
|
2014-02-09 23:17:33 +00:00
|
|
|
type Expr = GeneralExpr Annotation.Region Def Variable.Raw
|
|
|
|
type Expr' = GeneralExpr' Annotation.Region Def Variable.Raw
|
2014-01-14 15:02:23 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
data Def = Definition Pattern.Pattern Expr (Maybe SrcType.Type)
|
2014-01-04 10:39:38 +00:00
|
|
|
deriving (Show)
|
2014-01-03 07:18:42 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2014-01-14 15:02:23 +00:00
|
|
|
---- UTILITIES ----
|
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
rawVar :: String -> GeneralExpr' ann def Variable.Raw
|
|
|
|
rawVar x = Var (Variable.Raw x)
|
|
|
|
|
|
|
|
tuple :: [GeneralExpr ann def var] -> GeneralExpr' ann def var
|
2013-07-14 17:52:50 +00:00
|
|
|
tuple es = Data ("_Tuple" ++ show (length es)) es
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
delist :: GeneralExpr ann def var -> [GeneralExpr ann def var]
|
|
|
|
delist (Annotation.A _ (Data "::" [h,t])) = h : delist t
|
2013-06-14 01:00:24 +00:00
|
|
|
delist _ = []
|
|
|
|
|
2014-01-04 10:39:38 +00:00
|
|
|
saveEnvName :: String
|
2013-07-19 15:45:16 +00:00
|
|
|
saveEnvName = "_save_the_environment!!!"
|
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
dummyLet :: (Pretty def) => [def] -> GeneralExpr Annotation.Region def Variable.Raw
|
2013-07-16 19:37:48 +00:00
|
|
|
dummyLet defs =
|
2014-02-09 23:17:33 +00:00
|
|
|
Annotation.none $ Let defs (Annotation.none $ rawVar saveEnvName)
|
2013-07-16 19:37:48 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
instance (Pretty def, Pretty var) => Pretty (GeneralExpr' ann def var) where
|
2013-07-07 10:56:34 +00:00
|
|
|
pretty expr =
|
|
|
|
case expr of
|
|
|
|
Literal lit -> pretty lit
|
2014-02-09 23:17:33 +00:00
|
|
|
|
|
|
|
Var x -> pretty x
|
|
|
|
|
2013-07-07 16:13:40 +00:00
|
|
|
Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-07 16:13:40 +00:00
|
|
|
ExplicitList es -> P.brackets (commaCat (map pretty es))
|
2014-02-09 23:17:33 +00:00
|
|
|
|
|
|
|
Binop "-" (Annotation.A _ (Literal (Literal.IntNum 0))) e ->
|
2013-09-02 05:51:04 +00:00
|
|
|
P.text "-" <> prettyParens e
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-25 13:55:55 +00:00
|
|
|
Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
|
2014-02-09 23:17:33 +00:00
|
|
|
where
|
|
|
|
op' = if Help.isOp op then op else "`" ++ op ++ "`"
|
|
|
|
|
2014-01-14 15:27:06 +00:00
|
|
|
Lambda p e -> P.text "\\" <> args <+> P.text "->" <+> pretty body
|
|
|
|
where
|
2014-02-09 23:17:33 +00:00
|
|
|
(ps,body) = collectLambdas (Annotation.A undefined $ Lambda p e)
|
2014-01-14 15:27:06 +00:00
|
|
|
args = P.sep (map Pattern.prettyParens ps)
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-07 16:13:40 +00:00
|
|
|
App _ _ -> P.hang func 2 (P.sep args)
|
2014-02-09 23:17:33 +00:00
|
|
|
where
|
|
|
|
func:args = map prettyParens (collectApps (Annotation.A undefined expr))
|
|
|
|
|
|
|
|
MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
|
2013-07-07 10:56:34 +00:00
|
|
|
where
|
2013-07-07 16:13:40 +00:00
|
|
|
iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-07 10:56:34 +00:00
|
|
|
Let defs e ->
|
2013-07-07 16:13:40 +00:00
|
|
|
P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
|
|
|
|
, P.text "in" <+> pretty e ]
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-07 10:56:34 +00:00
|
|
|
Case e pats ->
|
2013-07-07 16:13:40 +00:00
|
|
|
P.hang pexpr 2 (P.vcat (map pretty' pats))
|
2013-07-07 10:56:34 +00:00
|
|
|
where
|
2013-07-07 16:13:40 +00:00
|
|
|
pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
|
2014-01-04 10:39:38 +00:00
|
|
|
pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-07-07 16:13:40 +00:00
|
|
|
Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
|
|
|
|
Data "[]" [] -> P.text "[]"
|
2014-01-14 15:13:18 +00:00
|
|
|
Data name es
|
|
|
|
| Help.isTuple name -> P.parens (commaCat (map pretty es))
|
|
|
|
| otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-08-14 07:44:29 +00:00
|
|
|
Access e x -> prettyParens e <> P.text "." <> variable x
|
2014-02-09 23:17:33 +00:00
|
|
|
|
2013-08-14 07:44:29 +00:00
|
|
|
Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
|
2014-02-09 23:17:33 +00:00
|
|
|
|
|
|
|
Insert (Annotation.A _ (Remove e y)) x v ->
|
|
|
|
P.braces $ P.hsep [ pretty e, P.text "-", variable y, P.text "|"
|
|
|
|
, variable x, P.equals, pretty v ]
|
|
|
|
|
2013-07-07 10:56:34 +00:00
|
|
|
Insert e x v ->
|
2014-01-03 07:18:42 +00:00
|
|
|
P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
|
2013-07-07 10:56:34 +00:00
|
|
|
|
|
|
|
Modify e fs ->
|
2013-07-07 16:13:40 +00:00
|
|
|
P.braces $ P.hang (pretty e <+> P.text "|")
|
|
|
|
4
|
2013-07-19 15:45:16 +00:00
|
|
|
(commaSep $ map field fs)
|
2013-07-07 10:56:34 +00:00
|
|
|
where
|
2014-01-04 10:39:38 +00:00
|
|
|
field (k,v) = variable k <+> P.text "<-" <+> pretty v
|
2013-07-07 10:56:34 +00:00
|
|
|
|
|
|
|
Record fs ->
|
2013-07-19 15:45:16 +00:00
|
|
|
P.braces $ P.nest 2 (commaSep $ map field fs)
|
2013-07-07 10:56:34 +00:00
|
|
|
where
|
2014-01-03 07:18:42 +00:00
|
|
|
field (x,e) = variable x <+> P.equals <+> pretty e
|
2013-07-07 10:56:34 +00:00
|
|
|
|
2013-10-25 15:36:30 +00:00
|
|
|
Markdown _ _ _ -> P.text "[markdown| ... |]"
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-01-13 18:24:17 +00:00
|
|
|
PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
|
2014-01-04 10:39:38 +00:00
|
|
|
|
|
|
|
PortOut _ _ signal -> pretty signal
|
|
|
|
|
2014-01-03 07:18:42 +00:00
|
|
|
instance Pretty ParseDef where
|
2013-07-07 10:56:34 +00:00
|
|
|
pretty def =
|
|
|
|
case def of
|
|
|
|
TypeAnnotation name tipe ->
|
2014-01-03 07:18:42 +00:00
|
|
|
variable name <+> P.colon <+> pretty tipe
|
2013-07-07 10:56:34 +00:00
|
|
|
Def pattern expr ->
|
2014-01-03 07:18:42 +00:00
|
|
|
pretty pattern <+> P.equals <+> pretty expr
|
|
|
|
|
|
|
|
instance Pretty Def where
|
|
|
|
pretty (Definition pattern expr maybeTipe) =
|
|
|
|
P.vcat [ annotation, definition ]
|
|
|
|
where
|
|
|
|
definition = pretty pattern <+> P.equals <+> pretty expr
|
|
|
|
annotation = case maybeTipe of
|
|
|
|
Nothing -> P.empty
|
|
|
|
Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
collectApps :: GeneralExpr ann def var -> [GeneralExpr ann def var]
|
|
|
|
collectApps annExpr@(Annotation.A _ expr) =
|
2013-07-07 10:56:34 +00:00
|
|
|
case expr of
|
|
|
|
App a b -> collectApps a ++ [b]
|
2014-02-09 23:17:33 +00:00
|
|
|
_ -> [annExpr]
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
collectLambdas :: GeneralExpr ann def var -> ([Pattern.Pattern], GeneralExpr ann def var)
|
|
|
|
collectLambdas lexpr@(Annotation.A _ expr) =
|
2013-07-07 10:56:34 +00:00
|
|
|
case expr of
|
2014-02-09 23:17:33 +00:00
|
|
|
Lambda pattern body ->
|
|
|
|
let (ps, body') = collectLambdas body
|
|
|
|
in (pattern : ps, body')
|
|
|
|
|
2013-07-07 10:56:34 +00:00
|
|
|
_ -> ([], lexpr)
|
2013-06-14 01:00:24 +00:00
|
|
|
|
2014-02-09 23:17:33 +00:00
|
|
|
prettyParens :: (Pretty def, Pretty var) => GeneralExpr ann def var -> Doc
|
|
|
|
prettyParens (Annotation.A _ expr) = parensIf needed (pretty expr)
|
2013-07-07 10:56:34 +00:00
|
|
|
where
|
|
|
|
needed =
|
|
|
|
case expr of
|
|
|
|
Binop _ _ _ -> True
|
|
|
|
Lambda _ _ -> True
|
|
|
|
App _ _ -> True
|
|
|
|
MultiIf _ -> True
|
|
|
|
Let _ _ -> True
|
|
|
|
Case _ _ -> True
|
2014-01-04 10:39:38 +00:00
|
|
|
Data name (_:_) -> name /= "::"
|
2013-07-07 10:56:34 +00:00
|
|
|
_ -> False
|