packages feed

dhscanner-ast 1.5.0 → 1.6.0

raw patch · 2 files changed

+469/−468 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Ast: [paramAnnotations] :: Param -> [Exp]
- Ast: Param :: ParamName -> Maybe Var -> Word -> Param
+ Ast: Param :: ParamName -> Maybe Var -> Word -> [Exp] -> Param

Files

dhscanner-ast.cabal view
@@ -22,7 +22,7 @@     and models both of them as plain sequential code blocks. Every file has exactly one ast that represents it.     Non Haskell parogrammers note: The ast is /immutable/ (like everything else in Haskell ...) -version:            1.5.0+version:            1.6.0 license:            GPL-3.0-only license-file:       LICENSE author:             OrenGitHub
src/Ast.hs view
@@ -1,467 +1,468 @@--- |
---
--- * The [abstract ayntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) ( ast )
---   aims to be a data structure able to:
---
---     * represent /multiple/ ( native ) ast kinds
---     * from /various/ programming languages
---
--- * Its main purpose is to serve as the:
---
---     * first step for /static code analysis/ 
---     * part of the [dhscanner](https://github.com/OrenGitHub/dhscanner) framework for
---       CI\/CD SAST security checks 🔒
---
--- * As part of the [dhscanner](https://github.com/OrenGitHub/dhscanner) framework:
---
---     * targets mostly languages used for /cloud native applications/ ☁️
---     * Python, Ruby 💎, Php, Javascript, Typescript, Java ☕️, C# and Golang.
---
--- * Typical flow:
---
---     * a file is parsed with the corresponding native parser of the language it's written in
---
---         * see [Python's native parser](https://docs.python.org/3/library/ast.html), for example
---         * native parsers hosted on independent micro services
---
---     * the native ast is dumped (as JSON, or plain text)
---
---     * dumped content is sent to a [Happy](https://haskell-happy.readthedocs.io/en/latest/) +
---       [Alex](https://haskell-alex.readthedocs.io/en/latest/) Haskell parser
---
---     * the Haskell parser organizes the natively parsed content into an ast
---
--- * Geared towards static code analysis, the ast design abstracts away details that are normally ignored anyway
---
---     * for example, it does not distinguish between `try` and `catch` blocks
---
---     * it models both of them as plain sequential code blocks.
---
--- * Every file has exactly one ast ( 'Root' ) that represents it
---
--- * Non Haskell parogrammers note:
---
---     * The ast is /immutable/ ( like everything else in Haskell ... )
---
-
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Ast
-
-where
-
-import Data.Aeson
-import GHC.Generics
-import Data.Map ( Map )
-
--- project imports
-import Location
-import qualified Token
-
--- |
--- * every file has /exactly one/ root 🌱
---
--- * classes, functions and methods are organized as /statements/
---
-data Root
-   = Root
-     {
-         filename :: FilePath,
-         stmts :: [ Stmt ]
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Exp
-   = ExpInt ExpIntContent
-   | ExpStr ExpStrContent
-   | ExpVar ExpVarContent
-   | ExpBool ExpBoolContent
-   | ExpNull ExpNullContent
-   | ExpCall ExpCallContent
-   | ExpBinop ExpBinopContent
-   | ExpKwArg ExpKwArgContent
-   | ExpAssign ExpAssignContent
-   | ExpLambda ExpLambdaContent
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Stmt
-   = StmtExp Exp
-   | StmtIf StmtIfContent
-   | StmtTry StmtTryContent
-   | StmtFunc StmtFuncContent
-   | StmtBlock StmtBlockContent
-   | StmtBreak StmtBreakContent
-   | StmtClass StmtClassContent
-   | StmtWhile StmtWhileContent
-   | StmtImport StmtImportContent
-   | StmtMethod StmtMethodContent
-   | StmtAssign StmtAssignContent
-   | StmtReturn StmtReturnContent
-   | StmtVardec StmtVardecContent
-   | StmtContinue StmtContinueContent
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- * used by:
---
---       * 'StmtFuncContent'
---       * 'StmtMethodContent'
---       * 'ExpLambdaContent'
---
--- * note:
---
---       * `self` param in python methods has 'paramSerialIdx' = 0
---       * `self` param in python methods is /ignored/ when assigning the serial index to /other/ params
---       * see the example code below
---
--- ==== __Example:__
---
--- * params enumeration for python methods
---
--- @
--- class Person:
---     # paramSerialIdx = 1 -----------------------+
---     # paramSerialIdx = 0 ------------+          |
---     # paramSerialIdx = 0 ------+     |          |
---     #                          |     |          |
---     def some_arbitrary_method(self, name: str, age: int) -> None:
---         pass
--- @
-data Param
-   = Param
-     {
-         paramName :: Token.ParamName,
-         paramNominalType :: Maybe Var,
-         paramSerialIdx :: Word -- ^ ( /zero/-based, ignores `self` in python methods when enumerating /other/ params )
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data DataMember
-   = DataMember
-     {
-         dataMemberName :: Token.MemberName,
-         dataMemberNominalType :: Maybe Var,
-         dataMemberInitValue :: Maybe Exp,
-         dataMemberAnnotations :: [ Exp ]
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data DataMembers
-   = DataMembers
-     {
-         actualDataMembers :: Map Token.MemberName DataMember
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtMethodContent
-   = StmtMethodContent
-     {
-         stmtMethodReturnType :: Maybe Var,
-         stmtMethodName :: Token.MethodName,
-         stmtMethodParams :: [ Param ],
-         stmtMethodBody :: [ Stmt ],
-         stmtMethodAnnotations :: [ Exp ],
-         stmtMethodLocation :: Location,
-         hostingClassName :: Token.ClassName,
-         hostingClassSupers :: [ Token.SuperName ],
-         hostingClassAnnotations :: [ Exp ]
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Methods
-   = Methods
-     {
-         actualMethods :: Map Token.MethodName StmtMethodContent
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtClassContent
-   = StmtClassContent
-     {
-         stmtClassName :: Token.ClassName,
-         stmtClassSupers :: [ Token.SuperName ],
-         stmtClassDataMembers :: DataMembers,
-         stmtClassMethods :: Methods
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtFuncContent
-   = StmtFuncContent
-     {
-         stmtFuncReturnType :: Maybe Var,
-         stmtFuncName :: Token.FuncName,
-         stmtFuncParams :: [ Param ],
-         stmtFuncBody :: [ Stmt ],
-         stmtFuncAnnotations :: [ Exp ],
-         stmtFuncLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtVardecContent
-   = StmtVardecContent
-     {
-         stmtVardecName :: Token.VarName,
-         stmtVardecNominalType :: Maybe Var,
-         stmtVardecInitValue :: Maybe Exp,
-         stmtVardecLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpIntContent
-   = ExpIntContent
-     {
-         expIntValue :: Token.ConstInt
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpStrContent
-   = ExpStrContent
-     {
-         expStrValue :: Token.ConstStr
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpBoolContent
-   = ExpBoolContent
-     {
-         expBoolValue :: Token.ConstBool
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpNullContent
-   = ExpNullContent
-     {
-         expNullValue :: Token.ConstNull
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Operator
-   = EQ
-   | NEQ
-   | PLUS
-   | MINUS
-   | TIMES
-   | DIVIDE
-   | PERCENT
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpLambdaContent
-   = ExpLambdaContent
-     {
-         expLambdaParams :: [ Param ],
-         expLambdaBody :: [ Stmt ],
-         expLambdaLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpKwArgContent
-   = ExpKwArgContent
-     {
-         expKwArgName :: String,
-         expKwArgValue :: Exp,
-         expKwArgLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpBinopContent
-   = ExpBinopContent
-     {
-         expBinopLeft :: Exp,
-         expBinopRight :: Exp,
-         expBinopOperator :: Operator,
-         expBinopLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpAssignContent
-   = ExpAssignContent
-     {
-         expAssignLhs :: Var,
-         expAssignRhs :: Exp,
-         expAssignLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpVarContent
-   = ExpVarContent
-     {
-         actualExpVar :: Var
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtAssignContent
-   = StmtAssignContent
-     {
-         stmtAssignLhs :: Var,
-         stmtAssignRhs :: Exp
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtTryContent
-   = StmtTryContent
-     {
-         stmtTryPart :: [ Stmt ],
-         stmtCatchPart :: [ Stmt ],
-         stmtTryLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtBreakContent
-   = StmtBreakContent
-     {
-         stmtBreakLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtBlockContent
-   = StmtBlockContent
-     {
-         stmtBlockContent :: [ Stmt ],
-         stmtBlockLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- ==== __Examples:__
--- 
--- * Simple source import
---
--- @
--- # stmtImportSource is (ImportSource (ImportThirdPartyContent "json")) <--- because json is /not/ an existing dir in the repo
--- # stmtImportSpecific is Nothing 
--- # stmtImportAlias is Nothing
--- import json
--- @
---
--- * Specifying a specific name from source
---
--- @
--- # stmtImportSource is (ImportSource (ImportThirdPartyContent "urllib.parse")) <--- because urllib/parse is /not/ an existing dir in the repo
--- # stmtImportSpecific is Just (ImportSpecific "urljoin")
--- # stmtImportAlias is Nothing
--- from urllib.parse import urljoin
--- @
---
--- * Specifying an alias for a source import
---
--- @
--- # stmtImportSource is (ImportSource (ImportThirdPartyContent "networkx")) <--- because networkx is /not/ an existing dir in the repo
--- # stmtImportFromSource is Nothing
--- # stmtImportAlias is Just (ImportAlias "nx")
--- import networkx as nx
--- @
---
-data StmtImportContent
-   = StmtImportContent
-     {
-         stmtImportSource :: ImportSource,
-         stmtImportSpecific :: Maybe ImportSpecific,
-         stmtImportAlias :: Maybe ImportAlias,
-         stmtImportLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ImportSource
-   = ImportLocal ImportLocalContent
-   | ImportThirdParty ImportThirdPartyContent
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- | Filename or directory
-data ImportLocalContent
-   = ImportLocalFile FilePath
-   | ImportLocalDir FilePath
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- Names that do not exist as directories in the repo
--- are classified by default as being "third party"
-newtype ImportThirdPartyContent = ImportThirdPartyContent String
-    deriving stock ( Show, Eq, Ord, Generic )
-    deriving anyclass ( ToJSON, FromJSON )
-
--- | See `StmtImportContent`
-newtype ImportSpecific = ImportSpecific String
-    deriving stock ( Show, Eq, Ord, Generic )
-    deriving anyclass ( ToJSON, FromJSON )
-
--- | See `StmtImportContent`
-newtype ImportAlias = ImportAlias String
-    deriving stock ( Show, Eq, Ord, Generic )
-    deriving anyclass ( ToJSON, FromJSON )
-
-data StmtContinueContent
-   = StmtContinueContent
-     {
-         stmtContinueLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtIfContent
-   = StmtIfContent
-     {
-         stmtIfCond :: Exp,
-         stmtIfBody :: [ Stmt ],
-         stmtElseBody :: [ Stmt ],
-         stmtIfLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtWhileContent
-   = StmtWhileContent
-     {
-         stmtWhileCond :: Exp,
-         stmtWhileBody :: [ Stmt ],
-         stmtWhileLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data StmtReturnContent
-   = StmtReturnContent
-     {
-         stmtReturnValue :: Maybe Exp,
-         stmtReturnLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ExpCallContent
-   = ExpCallContent
-     {
-         callee :: Exp,
-         args :: [ Exp ],
-         expCallLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data VarFieldContent
-   = VarFieldContent
-     {
-         varFieldLhs :: Exp,
-         varFieldName :: Token.FieldName,
-         varFieldLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data VarSimpleContent
-   = VarSimpleContent
-     {
-         varName :: Token.VarName
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data VarSubscriptContent
-   = VarSubscriptContent
-     {
-         varSubscriptLhs :: Exp,
-         varSubscriptIdx :: Exp,
-         varSubscriptLocation :: Location
-     }
-     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Var
-   = VarSimple VarSimpleContent
-   | VarField VarFieldContent
-   | VarSubscript VarSubscriptContent
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+-- |+--+-- * The [abstract ayntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) ( ast )+--   aims to be a data structure able to:+--+--     * represent /multiple/ ( native ) ast kinds+--     * from /various/ programming languages+--+-- * Its main purpose is to serve as the:+--+--     * first step for /static code analysis/ +--     * part of the [dhscanner](https://github.com/OrenGitHub/dhscanner) framework for+--       CI\/CD SAST security checks 🔒+--+-- * As part of the [dhscanner](https://github.com/OrenGitHub/dhscanner) framework:+--+--     * targets mostly languages used for /cloud native applications/ ☁️+--     * Python, Ruby 💎, Php, Javascript, Typescript, Java ☕️, C# and Golang.+--+-- * Typical flow:+--+--     * a file is parsed with the corresponding native parser of the language it's written in+--+--         * see [Python's native parser](https://docs.python.org/3/library/ast.html), for example+--         * native parsers hosted on independent micro services+--+--     * the native ast is dumped (as JSON, or plain text)+--+--     * dumped content is sent to a [Happy](https://haskell-happy.readthedocs.io/en/latest/) ++--       [Alex](https://haskell-alex.readthedocs.io/en/latest/) Haskell parser+--+--     * the Haskell parser organizes the natively parsed content into an ast+--+-- * Geared towards static code analysis, the ast design abstracts away details that are normally ignored anyway+--+--     * for example, it does not distinguish between `try` and `catch` blocks+--+--     * it models both of them as plain sequential code blocks.+--+-- * Every file has exactly one ast ( 'Root' ) that represents it+--+-- * Non Haskell parogrammers note:+--+--     * The ast is /immutable/ ( like everything else in Haskell ... )+--++{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE OverloadedStrings #-}++module Ast++where++import Data.Aeson+import GHC.Generics+import Data.Map ( Map )++-- project imports+import Location+import qualified Token++-- |+-- * every file has /exactly one/ root 🌱+--+-- * classes, functions and methods are organized as /statements/+--+data Root+   = Root+     {+         filename :: FilePath,+         stmts :: [ Stmt ]+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data Exp+   = ExpInt ExpIntContent+   | ExpStr ExpStrContent+   | ExpVar ExpVarContent+   | ExpBool ExpBoolContent+   | ExpNull ExpNullContent+   | ExpCall ExpCallContent+   | ExpBinop ExpBinopContent+   | ExpKwArg ExpKwArgContent+   | ExpAssign ExpAssignContent+   | ExpLambda ExpLambdaContent+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data Stmt+   = StmtExp Exp+   | StmtIf StmtIfContent+   | StmtTry StmtTryContent+   | StmtFunc StmtFuncContent+   | StmtBlock StmtBlockContent+   | StmtBreak StmtBreakContent+   | StmtClass StmtClassContent+   | StmtWhile StmtWhileContent+   | StmtImport StmtImportContent+   | StmtMethod StmtMethodContent+   | StmtAssign StmtAssignContent+   | StmtReturn StmtReturnContent+   | StmtVardec StmtVardecContent+   | StmtContinue StmtContinueContent+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++-- |+--+-- * used by:+--+--       * 'StmtFuncContent'+--       * 'StmtMethodContent'+--       * 'ExpLambdaContent'+--+-- * note:+--+--       * `self` param in python methods has 'paramSerialIdx' = 0+--       * `self` param in python methods is /ignored/ when assigning the serial index to /other/ params+--       * see the example code below+--+-- ==== __Example:__+--+-- * params enumeration for python methods+--+-- @+-- class Person:+--     # paramSerialIdx = 1 -----------------------++--     # paramSerialIdx = 0 ------------+          |+--     # paramSerialIdx = 0 ------+     |          |+--     #                          |     |          |+--     def some_arbitrary_method(self, name: str, age: int) -> None:+--         pass+-- @+data Param+   = Param+     {+         paramName :: Token.ParamName,+         paramNominalType :: Maybe Var,+         paramSerialIdx :: Word, -- ^ ( /zero/-based, ignores `self` in python methods when enumerating /other/ params )+         paramAnnotations :: [ Exp ] -- ^ ( for example, Java Spring: `@RequestParam` )+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data DataMember+   = DataMember+     {+         dataMemberName :: Token.MemberName,+         dataMemberNominalType :: Maybe Var,+         dataMemberInitValue :: Maybe Exp,+         dataMemberAnnotations :: [ Exp ]+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data DataMembers+   = DataMembers+     {+         actualDataMembers :: Map Token.MemberName DataMember+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtMethodContent+   = StmtMethodContent+     {+         stmtMethodReturnType :: Maybe Var,+         stmtMethodName :: Token.MethodName,+         stmtMethodParams :: [ Param ],+         stmtMethodBody :: [ Stmt ],+         stmtMethodAnnotations :: [ Exp ],+         stmtMethodLocation :: Location,+         hostingClassName :: Token.ClassName,+         hostingClassSupers :: [ Token.SuperName ],+         hostingClassAnnotations :: [ Exp ]+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data Methods+   = Methods+     {+         actualMethods :: Map Token.MethodName StmtMethodContent+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtClassContent+   = StmtClassContent+     {+         stmtClassName :: Token.ClassName,+         stmtClassSupers :: [ Token.SuperName ],+         stmtClassDataMembers :: DataMembers,+         stmtClassMethods :: Methods+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtFuncContent+   = StmtFuncContent+     {+         stmtFuncReturnType :: Maybe Var,+         stmtFuncName :: Token.FuncName,+         stmtFuncParams :: [ Param ],+         stmtFuncBody :: [ Stmt ],+         stmtFuncAnnotations :: [ Exp ],+         stmtFuncLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtVardecContent+   = StmtVardecContent+     {+         stmtVardecName :: Token.VarName,+         stmtVardecNominalType :: Maybe Var,+         stmtVardecInitValue :: Maybe Exp,+         stmtVardecLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpIntContent+   = ExpIntContent+     {+         expIntValue :: Token.ConstInt+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpStrContent+   = ExpStrContent+     {+         expStrValue :: Token.ConstStr+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpBoolContent+   = ExpBoolContent+     {+         expBoolValue :: Token.ConstBool+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpNullContent+   = ExpNullContent+     {+         expNullValue :: Token.ConstNull+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data Operator+   = EQ+   | NEQ+   | PLUS+   | MINUS+   | TIMES+   | DIVIDE+   | PERCENT+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpLambdaContent+   = ExpLambdaContent+     {+         expLambdaParams :: [ Param ],+         expLambdaBody :: [ Stmt ],+         expLambdaLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpKwArgContent+   = ExpKwArgContent+     {+         expKwArgName :: String,+         expKwArgValue :: Exp,+         expKwArgLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpBinopContent+   = ExpBinopContent+     {+         expBinopLeft :: Exp,+         expBinopRight :: Exp,+         expBinopOperator :: Operator,+         expBinopLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpAssignContent+   = ExpAssignContent+     {+         expAssignLhs :: Var,+         expAssignRhs :: Exp,+         expAssignLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpVarContent+   = ExpVarContent+     {+         actualExpVar :: Var+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtAssignContent+   = StmtAssignContent+     {+         stmtAssignLhs :: Var,+         stmtAssignRhs :: Exp+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtTryContent+   = StmtTryContent+     {+         stmtTryPart :: [ Stmt ],+         stmtCatchPart :: [ Stmt ],+         stmtTryLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtBreakContent+   = StmtBreakContent+     {+         stmtBreakLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtBlockContent+   = StmtBlockContent+     {+         stmtBlockContent :: [ Stmt ],+         stmtBlockLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++-- |+-- ==== __Examples:__+-- +-- * Simple source import+--+-- @+-- # stmtImportSource is (ImportSource (ImportThirdPartyContent "json")) <--- because json is /not/ an existing dir in the repo+-- # stmtImportSpecific is Nothing +-- # stmtImportAlias is Nothing+-- import json+-- @+--+-- * Specifying a specific name from source+--+-- @+-- # stmtImportSource is (ImportSource (ImportThirdPartyContent "urllib.parse")) <--- because urllib/parse is /not/ an existing dir in the repo+-- # stmtImportSpecific is Just (ImportSpecific "urljoin")+-- # stmtImportAlias is Nothing+-- from urllib.parse import urljoin+-- @+--+-- * Specifying an alias for a source import+--+-- @+-- # stmtImportSource is (ImportSource (ImportThirdPartyContent "networkx")) <--- because networkx is /not/ an existing dir in the repo+-- # stmtImportFromSource is Nothing+-- # stmtImportAlias is Just (ImportAlias "nx")+-- import networkx as nx+-- @+--+data StmtImportContent+   = StmtImportContent+     {+         stmtImportSource :: ImportSource,+         stmtImportSpecific :: Maybe ImportSpecific,+         stmtImportAlias :: Maybe ImportAlias,+         stmtImportLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ImportSource+   = ImportLocal ImportLocalContent+   | ImportThirdParty ImportThirdPartyContent+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++-- | Filename or directory+data ImportLocalContent+   = ImportLocalFile FilePath+   | ImportLocalDir FilePath+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++-- |+-- Names that do not exist as directories in the repo+-- are classified by default as being "third party"+newtype ImportThirdPartyContent = ImportThirdPartyContent String+    deriving stock ( Show, Eq, Ord, Generic )+    deriving anyclass ( ToJSON, FromJSON )++-- | See `StmtImportContent`+newtype ImportSpecific = ImportSpecific String+    deriving stock ( Show, Eq, Ord, Generic )+    deriving anyclass ( ToJSON, FromJSON )++-- | See `StmtImportContent`+newtype ImportAlias = ImportAlias String+    deriving stock ( Show, Eq, Ord, Generic )+    deriving anyclass ( ToJSON, FromJSON )++data StmtContinueContent+   = StmtContinueContent+     {+         stmtContinueLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtIfContent+   = StmtIfContent+     {+         stmtIfCond :: Exp,+         stmtIfBody :: [ Stmt ],+         stmtElseBody :: [ Stmt ],+         stmtIfLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtWhileContent+   = StmtWhileContent+     {+         stmtWhileCond :: Exp,+         stmtWhileBody :: [ Stmt ],+         stmtWhileLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data StmtReturnContent+   = StmtReturnContent+     {+         stmtReturnValue :: Maybe Exp,+         stmtReturnLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data ExpCallContent+   = ExpCallContent+     {+         callee :: Exp,+         args :: [ Exp ],+         expCallLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data VarFieldContent+   = VarFieldContent+     {+         varFieldLhs :: Exp,+         varFieldName :: Token.FieldName,+         varFieldLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data VarSimpleContent+   = VarSimpleContent+     {+         varName :: Token.VarName+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data VarSubscriptContent+   = VarSubscriptContent+     {+         varSubscriptLhs :: Exp,+         varSubscriptIdx :: Exp,+         varSubscriptLocation :: Location+     }+     deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )++data Var+   = VarSimple VarSimpleContent+   | VarField VarFieldContent+   | VarSubscript VarSubscriptContent+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )