mirror of
https://github.com/github/semantic.git
synced 2024-12-29 18:06:14 +03:00
Merge branch 'master' into imports,-graphed
This commit is contained in:
commit
2e228604cf
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -13,18 +13,9 @@
|
||||
[submodule "vendor/effects"]
|
||||
path = vendor/effects
|
||||
url = https://github.com/joshvera/effects.git
|
||||
[submodule "languages/c/vendor/tree-sitter-c"]
|
||||
path = languages/c/vendor/tree-sitter-c
|
||||
url = https://github.com/tree-sitter/tree-sitter-c.git
|
||||
[submodule "languages/javascript/vendor/tree-sitter-javascript"]
|
||||
path = languages/javascript/vendor/tree-sitter-javascript
|
||||
url = https://github.com/tree-sitter/tree-sitter-javascript.git
|
||||
[submodule "vendor/haskell-tree-sitter"]
|
||||
path = vendor/haskell-tree-sitter
|
||||
url = https://github.com/tree-sitter/haskell-tree-sitter.git
|
||||
[submodule "vendor/freer-cofreer"]
|
||||
path = vendor/freer-cofreer
|
||||
url = https://github.com/robrix/freer-cofreer.git
|
||||
[submodule "vendor/ghc-mod"]
|
||||
path = vendor/ghc-mod
|
||||
url = https://github.com/joshvera/ghc-mod
|
||||
|
@ -225,6 +225,8 @@ language_extensions:
|
||||
- FlexibleContexts
|
||||
- FlexibleInstances
|
||||
- MultiParamTypeClasses
|
||||
- StandaloneDeriving
|
||||
- DataKinds
|
||||
- OverloadedStrings
|
||||
- RecordWildCards
|
||||
- StrictData
|
||||
|
@ -74,6 +74,7 @@ library
|
||||
, Data.Patch
|
||||
, Data.Range
|
||||
, Data.Record
|
||||
, Data.Semigroup.App
|
||||
, Data.Source
|
||||
, Data.Span
|
||||
, Data.SplitDiff
|
||||
@ -183,14 +184,17 @@ library
|
||||
, tree-sitter-ruby
|
||||
, tree-sitter-typescript
|
||||
default-language: Haskell2010
|
||||
default-extensions: DeriveFoldable
|
||||
default-extensions: DataKinds
|
||||
, DeriveFoldable
|
||||
, DeriveFunctor
|
||||
, DeriveGeneric
|
||||
, DeriveTraversable
|
||||
, FlexibleContexts
|
||||
, FlexibleInstances
|
||||
, MultiParamTypeClasses
|
||||
, OverloadedStrings
|
||||
, RecordWildCards
|
||||
, StandaloneDeriving
|
||||
, StrictData
|
||||
ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-name-shadowing -O -j
|
||||
ghc-prof-options: -fprof-auto
|
||||
@ -212,6 +216,7 @@ test-suite test
|
||||
main-is: Spec.hs
|
||||
other-modules: Assigning.Assignment.Spec
|
||||
, Analysis.Go.Spec
|
||||
, Analysis.PHP.Spec
|
||||
, Analysis.Python.Spec
|
||||
, Analysis.Ruby.Spec
|
||||
, Analysis.TypeScript.Spec
|
||||
@ -258,7 +263,15 @@ test-suite test
|
||||
, these
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N -j
|
||||
default-language: Haskell2010
|
||||
default-extensions: DeriveFunctor, DeriveGeneric, FlexibleContexts, FlexibleInstances, OverloadedStrings, RecordWildCards
|
||||
default-extensions: DataKinds
|
||||
, DeriveFunctor
|
||||
, DeriveGeneric
|
||||
, FlexibleContexts
|
||||
, FlexibleInstances
|
||||
, MultiParamTypeClasses
|
||||
, OverloadedStrings
|
||||
, RecordWildCards
|
||||
, StandaloneDeriving
|
||||
|
||||
test-suite doctests
|
||||
type: exitcode-stdio-1.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.Abstract.Caching
|
||||
( type Caching
|
||||
) where
|
||||
@ -14,7 +14,7 @@ import Prologue
|
||||
-- | The effects necessary for caching analyses.
|
||||
type CachingEffects term value effects
|
||||
= Fresh -- For 'MonadFresh'.
|
||||
': NonDetEff -- For 'Alternative' and 'MonadNonDet'.
|
||||
': NonDet -- For 'Alternative' and 'MonadNonDet'.
|
||||
': Reader (CacheFor term value) -- The in-cache used as an oracle while converging on a result.
|
||||
': State (CacheFor term value) -- The out-cache used to record results in each iteration of convergence.
|
||||
': effects
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.Abstract.Collecting
|
||||
( type Collecting
|
||||
) where
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators #-}
|
||||
module Analysis.Abstract.Dead
|
||||
( type DeadCode
|
||||
) where
|
||||
|
@ -1,22 +1,71 @@
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.Abstract.Evaluating
|
||||
( type Evaluating
|
||||
, findValue
|
||||
, findEnv
|
||||
, findHeap
|
||||
, require
|
||||
, load
|
||||
) where
|
||||
|
||||
import Control.Abstract.Evaluator
|
||||
import Control.Monad.Effect
|
||||
import Control.Monad.Effect.Fail
|
||||
import Control.Monad.Effect.Reader
|
||||
import Control.Monad.Effect.State
|
||||
import Control.Monad.Effect.Resumable
|
||||
import Data.Abstract.Configuration
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Environment (Environment)
|
||||
import Data.Abstract.Heap (Heap(..))
|
||||
import qualified Data.Abstract.Exports as Export
|
||||
import Data.Abstract.Exports (Exports)
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.Module
|
||||
import Data.Abstract.ModuleTable
|
||||
import Data.Abstract.Value
|
||||
import qualified Data.IntMap as IntMap
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
import Prologue hiding (throwError)
|
||||
import qualified Data.ByteString.Char8 as BC
|
||||
import qualified Data.Map.Monoidal as Monoidal
|
||||
|
||||
-- | Require/import another module by name and return it's environment and value.
|
||||
--
|
||||
-- Looks up the term's name in the cache of evaluated modules first, returns if found, otherwise loads/evaluates the module.
|
||||
require :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
require name = getModuleTable >>= maybe (load name) pure . moduleTableLookup name
|
||||
|
||||
-- | Load another module by name and return it's environment and value.
|
||||
--
|
||||
-- Always loads/evaluates.
|
||||
load :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
load name = askModuleTable >>= maybe notFound evalAndCache . moduleTableLookup name
|
||||
where
|
||||
notFound = fail ("cannot load module: " <> show name)
|
||||
evalAndCache :: (MonadAnalysis term value m, MonadValue value m) => [Module term] -> m (EnvironmentFor value, value)
|
||||
evalAndCache [] = (,) <$> pure mempty <*> unit
|
||||
evalAndCache [x] = evalAndCache' x
|
||||
evalAndCache (x:xs) = do
|
||||
(env, _) <- evalAndCache' x
|
||||
(env', v') <- evalAndCache xs
|
||||
pure (env <> env', v')
|
||||
|
||||
evalAndCache' :: (MonadAnalysis term value m) => Module term -> m (EnvironmentFor value, value)
|
||||
evalAndCache' x = do
|
||||
v <- evaluateModule x
|
||||
env <- filterEnv <$> getExports <*> getEnv
|
||||
modifyModuleTable (moduleTableInsert name (env, v))
|
||||
pure (env, v)
|
||||
|
||||
-- TODO: If the set of exports is empty because no exports have been
|
||||
-- defined, do we export all terms, or no terms? This behavior varies across
|
||||
-- languages. We need better semantics rather than doing it ad-hoc.
|
||||
filterEnv :: Exports l a -> Environment l a -> Environment l a
|
||||
filterEnv ports env
|
||||
| Export.null ports = env
|
||||
| otherwise = Export.toEnvironment ports <> Env.overwrite (Export.aliases ports) env
|
||||
|
||||
-- | An analysis evaluating @term@s to @value@s with a list of @effects@ using 'Evaluatable', and producing incremental results of type @a@.
|
||||
newtype Evaluating term value effects a = Evaluating (Eff effects a)
|
||||
@ -24,21 +73,41 @@ newtype Evaluating term value effects a = Evaluating (Eff effects a)
|
||||
|
||||
deriving instance Member Fail effects => MonadFail (Evaluating term value effects)
|
||||
deriving instance Member Fresh effects => MonadFresh (Evaluating term value effects)
|
||||
deriving instance Member NonDetEff effects => Alternative (Evaluating term value effects)
|
||||
deriving instance Member NonDetEff effects => MonadNonDet (Evaluating term value effects)
|
||||
deriving instance Member NonDet effects => Alternative (Evaluating term value effects)
|
||||
deriving instance Member NonDet effects => MonadNonDet (Evaluating term value effects)
|
||||
|
||||
-- | Effects necessary for evaluating (whether concrete or abstract).
|
||||
type EvaluatingEffects term value
|
||||
= '[ Fail -- Failure with an error message
|
||||
= '[ Resumable Prelude.String value
|
||||
, Fail -- Failure with an error message
|
||||
, Reader [Module term] -- The stack of currently-evaluating modules.
|
||||
, State (EnvironmentFor value) -- Environments (both local and global)
|
||||
, State (HeapFor value) -- The heap
|
||||
, Reader (ModuleTable [Module term]) -- Cache of unevaluated modules
|
||||
, State (ModuleTable (EnvironmentFor value)) -- Cache of evaluated modules
|
||||
, Reader (ModuleTable [Module term]) -- Cache of unevaluated modules
|
||||
, State (ModuleTable (EnvironmentFor value, value)) -- Cache of evaluated modules
|
||||
, State (ExportsFor value) -- Exports (used to filter environments when they are imported)
|
||||
, State (IntMap.IntMap term) -- For jumps
|
||||
]
|
||||
|
||||
-- | Find the value in the 'Final' result of running.
|
||||
findValue :: forall value term effects . (effects ~ RequiredEffects term value (Evaluating term value effects))
|
||||
=> Final effects value -> Either Prelude.String (Either Prelude.String value)
|
||||
findValue (((((v, _), _), _), _), _) = v
|
||||
|
||||
-- | Find the 'Environment' in the 'Final' result of running.
|
||||
findEnv :: forall value term effects . (effects ~ RequiredEffects term value (Evaluating term value effects))
|
||||
=> Final effects value -> EnvironmentFor value
|
||||
findEnv (((((_, env), _), _), _), _) = env
|
||||
|
||||
-- | Find the 'Heap' in the 'Final' result of running.
|
||||
findHeap :: forall value term effects . (effects ~ RequiredEffects term value (Evaluating term value effects))
|
||||
=> Final effects value -> Monoidal.Map (LocationFor value) (CellFor value)
|
||||
findHeap (((((_, _), Heap heap), _), _), _) = heap
|
||||
|
||||
|
||||
instance Members '[Resumable Prelude.String value] effects => MonadThrow Prelude.String value (Evaluating term value effects) where
|
||||
throwException = raise . throwError
|
||||
|
||||
instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where
|
||||
label term = do
|
||||
m <- raise get
|
||||
@ -66,7 +135,7 @@ instance Member (State (HeapFor value)) effects => MonadHeap value (Evaluating t
|
||||
getHeap = raise get
|
||||
putHeap = raise . put
|
||||
|
||||
instance Members '[Reader (ModuleTable [Module term]), State (ModuleTable (EnvironmentFor value))] effects => MonadModuleTable term value (Evaluating term value effects) where
|
||||
instance Members '[Reader (ModuleTable [Module term]), State (ModuleTable (EnvironmentFor value, value))] effects => MonadModuleTable term value (Evaluating term value effects) where
|
||||
getModuleTable = raise get
|
||||
putModuleTable = raise . put
|
||||
|
||||
@ -89,7 +158,7 @@ instance ( Evaluatable (Base term)
|
||||
=> MonadAnalysis term value (Evaluating term value effects) where
|
||||
type RequiredEffects term value (Evaluating term value effects) = EvaluatingEffects term value
|
||||
|
||||
analyzeTerm = eval
|
||||
analyzeTerm term = resumeException @value (eval term) (\yield exc -> string (BC.pack exc) >>= yield)
|
||||
|
||||
analyzeModule m = pushModule (subterm <$> m) (subtermValue (moduleBody m))
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.Abstract.Tracing
|
||||
( type Tracing
|
||||
) where
|
||||
|
@ -10,7 +10,6 @@ import qualified Algebra.Graph as G
|
||||
import Algebra.Graph.Class
|
||||
import Algebra.Graph.Export.Dot
|
||||
import Data.Abstract.FreeVariables
|
||||
import Data.Set (member)
|
||||
import qualified Data.Syntax as Syntax
|
||||
import qualified Data.Syntax.Declaration as Declaration
|
||||
import Data.Term
|
||||
@ -21,7 +20,7 @@ newtype CallGraph = CallGraph { unCallGraph :: G.Graph Name }
|
||||
deriving (Eq, Graph, Show)
|
||||
|
||||
-- | Build the 'CallGraph' for a 'Term' recursively.
|
||||
buildCallGraph :: (CallGraphAlgebra syntax, FreeVariables1 syntax, Functor syntax) => Term syntax ann -> Set Name -> CallGraph
|
||||
buildCallGraph :: (CallGraphAlgebra syntax, FreeVariables1 syntax, Functor syntax) => Term syntax ann -> [Name] -> CallGraph
|
||||
buildCallGraph = foldSubterms callGraphAlgebra
|
||||
|
||||
|
||||
@ -35,7 +34,7 @@ renderCallGraph = export (defaultStyle friendlyName) . unCallGraph
|
||||
-- This typeclass employs the Advanced Overlap techniques designed by Oleg Kiselyov & Simon Peyton Jones: https://wiki.haskell.org/GHC/AdvancedOverlap.
|
||||
class CallGraphAlgebra syntax where
|
||||
-- | A 'SubtermAlgebra' computing the 'CallGraph' for a piece of @syntax@.
|
||||
callGraphAlgebra :: FreeVariables term => syntax (Subterm term (Set Name -> CallGraph)) -> Set Name -> CallGraph
|
||||
callGraphAlgebra :: FreeVariables term => syntax (Subterm term ([Name] -> CallGraph)) -> [Name] -> CallGraph
|
||||
|
||||
instance (CallGraphAlgebraStrategy syntax ~ strategy, CallGraphAlgebraWithStrategy strategy syntax) => CallGraphAlgebra syntax where
|
||||
callGraphAlgebra = callGraphAlgebraWithStrategy (Proxy :: Proxy strategy)
|
||||
@ -43,7 +42,7 @@ instance (CallGraphAlgebraStrategy syntax ~ strategy, CallGraphAlgebraWithStrate
|
||||
|
||||
-- | Types whose contribution to a 'CallGraph' is customized. If an instance’s definition is not being used, ensure that the type is mapped to 'Custom' in the 'CallGraphAlgebraStrategy'.
|
||||
class CustomCallGraphAlgebra syntax where
|
||||
customCallGraphAlgebra :: FreeVariables term => syntax (Subterm term (Set Name -> CallGraph)) -> Set Name -> CallGraph
|
||||
customCallGraphAlgebra :: FreeVariables term => syntax (Subterm term ([Name] -> CallGraph)) -> [Name] -> CallGraph
|
||||
|
||||
-- | 'Declaration.Function's produce a vertex for their name, with edges to any free variables in their body.
|
||||
instance CustomCallGraphAlgebra Declaration.Function where
|
||||
@ -56,8 +55,8 @@ instance CustomCallGraphAlgebra Declaration.Method where
|
||||
-- | 'Syntax.Identifier's produce a vertex iff it’s unbound in the 'Set'.
|
||||
instance CustomCallGraphAlgebra Syntax.Identifier where
|
||||
customCallGraphAlgebra (Syntax.Identifier name) bound
|
||||
| name `member` bound = empty
|
||||
| otherwise = vertex name
|
||||
| name `elem` bound = empty
|
||||
| otherwise = vertex name
|
||||
|
||||
instance Apply CallGraphAlgebra syntaxes => CustomCallGraphAlgebra (Union syntaxes) where
|
||||
customCallGraphAlgebra = Prologue.apply (Proxy :: Proxy CallGraphAlgebra) callGraphAlgebra
|
||||
@ -68,7 +67,7 @@ instance CallGraphAlgebra syntax => CustomCallGraphAlgebra (TermF syntax a) wher
|
||||
|
||||
-- | The mechanism selecting 'Default'/'Custom' implementations for 'callGraphAlgebra' depending on the @syntax@ type.
|
||||
class CallGraphAlgebraWithStrategy (strategy :: Strategy) syntax where
|
||||
callGraphAlgebraWithStrategy :: FreeVariables term => proxy strategy -> syntax (Subterm term (Set Name -> CallGraph)) -> Set Name -> CallGraph
|
||||
callGraphAlgebraWithStrategy :: FreeVariables term => proxy strategy -> syntax (Subterm term ([Name] -> CallGraph)) -> [Name] -> CallGraph
|
||||
|
||||
-- | The 'Default' definition of 'callGraphAlgebra' combines all of the 'CallGraph's within the @syntax@ 'Monoid'ally.
|
||||
instance Foldable syntax => CallGraphAlgebraWithStrategy 'Default syntax where
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.ConstructorName
|
||||
( ConstructorName(..)
|
||||
, ConstructorLabel(..)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeOperators, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
|
||||
{-# LANGUAGE TypeOperators, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
|
||||
module Analysis.Declaration
|
||||
( Declaration(..)
|
||||
, HasDeclaration
|
||||
|
@ -1,17 +1,17 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Analysis.IdentifierName
|
||||
( IdentifierName(..)
|
||||
, IdentifierLabel(..)
|
||||
, identifierLabel
|
||||
) where
|
||||
|
||||
import Data.Abstract.FreeVariables
|
||||
import Data.Aeson
|
||||
import Data.JSON.Fields
|
||||
import Data.Term
|
||||
import Data.Text.Encoding (decodeUtf8)
|
||||
import Prologue
|
||||
import Data.Abstract.FreeVariables
|
||||
import Data.Aeson
|
||||
import Data.JSON.Fields
|
||||
import qualified Data.Syntax
|
||||
import Data.Term
|
||||
import Data.Text.Encoding (decodeUtf8)
|
||||
import Prologue
|
||||
|
||||
-- | Compute a 'IdentifierLabel' label for a 'Term'.
|
||||
identifierLabel :: IdentifierName syntax => TermF syntax a b -> Maybe IdentifierLabel
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
|
||||
{-# LANGUAGE ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
|
||||
module Analysis.ModuleDef
|
||||
( ModuleDef(..)
|
||||
, HasModuleDef
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# OPTIONS_GHC -Wno-redundant-constraints #-} -- For runAnalysis
|
||||
module Control.Abstract.Analysis
|
||||
( MonadAnalysis(..)
|
||||
@ -6,8 +6,6 @@ module Control.Abstract.Analysis
|
||||
, evaluateModule
|
||||
, withModules
|
||||
, evaluateModules
|
||||
, require
|
||||
, load
|
||||
, liftAnalyze
|
||||
, runAnalysis
|
||||
, module X
|
||||
@ -23,13 +21,8 @@ import qualified Control.Monad.Effect as Effect
|
||||
import Control.Monad.Effect.Fail as X
|
||||
import Control.Monad.Effect.Reader as X
|
||||
import Control.Monad.Effect.State as X
|
||||
import Data.Abstract.Environment (Environment)
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Exports (Exports)
|
||||
import qualified Data.Abstract.Exports as Export
|
||||
import Data.Abstract.Module
|
||||
import Data.Abstract.ModuleTable as ModuleTable
|
||||
import Data.Abstract.Value
|
||||
import Data.Coerce
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
@ -72,43 +65,6 @@ evaluateModules [] = fail "evaluateModules: empty list"
|
||||
evaluateModules (m:ms) = withModules ms (evaluateModule m)
|
||||
|
||||
|
||||
-- | Require/import another term/file and return an Effect.
|
||||
--
|
||||
-- Looks up the term's name in the cache of evaluated modules first, returns a value if found, otherwise loads/evaluates the module.
|
||||
require :: ( MonadAnalysis term value m
|
||||
, Ord (LocationFor value)
|
||||
)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value)
|
||||
require name = getModuleTable >>= maybe (load name) pure . moduleTableLookup name
|
||||
|
||||
-- | Load another term/file and return an Effect.
|
||||
--
|
||||
-- Always loads/evaluates.
|
||||
load :: ( MonadAnalysis term value m
|
||||
, Ord (LocationFor value)
|
||||
)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value)
|
||||
load name = askModuleTable >>= maybe notFound evalAndCache . moduleTableLookup name
|
||||
where
|
||||
notFound = fail ("cannot load module: " <> show name)
|
||||
evalAndCache :: (MonadAnalysis term value m, Ord (LocationFor value)) => [Module term] -> m (EnvironmentFor value)
|
||||
evalAndCache [] = pure mempty
|
||||
evalAndCache (x:xs) = do
|
||||
void $ evaluateModule x
|
||||
env <- filterEnv <$> getExports <*> getEnv
|
||||
modifyModuleTable (moduleTableInsert name env)
|
||||
(env <>) <$> evalAndCache xs
|
||||
|
||||
-- TODO: If the set of exports is empty because no exports have been
|
||||
-- defined, do we export all terms, or no terms? This behavior varies across
|
||||
-- languages. We need better semantics rather than doing it ad-hoc.
|
||||
filterEnv :: (Ord l) => Exports l a -> Environment l a -> Environment l a
|
||||
filterEnv ports env
|
||||
| Export.null ports = env
|
||||
| otherwise = Export.toEnvironment ports <> Env.overwrite (Export.aliases ports) env
|
||||
|
||||
-- | Lift a 'SubtermAlgebra' for an underlying analysis into a containing analysis. Use this when defining an analysis which can be composed onto other analyses to ensure that a call to 'analyzeTerm' occurs in the inner analysis and not the outer one.
|
||||
liftAnalyze :: ( Coercible ( m term value (effects :: [* -> *]) value) (t m term value effects value)
|
||||
, Coercible (t m term value effects value) ( m term value effects value)
|
||||
|
@ -13,6 +13,7 @@ module Control.Abstract.Evaluator
|
||||
, MonadModuleTable(..)
|
||||
, modifyModuleTable
|
||||
, MonadControl(..)
|
||||
, MonadThrow(..)
|
||||
) where
|
||||
|
||||
import Data.Abstract.Address
|
||||
@ -129,9 +130,9 @@ assign address = modifyHeap . heapInsert address
|
||||
-- | A 'Monad' abstracting tables of modules available for import.
|
||||
class Monad m => MonadModuleTable term value m | m -> term, m -> value where
|
||||
-- | Retrieve the table of evaluated modules.
|
||||
getModuleTable :: m (ModuleTable (EnvironmentFor value))
|
||||
getModuleTable :: m (ModuleTable (EnvironmentFor value, value))
|
||||
-- | Set the table of evaluated modules.
|
||||
putModuleTable :: ModuleTable (EnvironmentFor value) -> m ()
|
||||
putModuleTable :: ModuleTable (EnvironmentFor value, value) -> m ()
|
||||
|
||||
-- | Retrieve the table of unevaluated modules.
|
||||
askModuleTable :: m (ModuleTable [Module term])
|
||||
@ -139,7 +140,7 @@ class Monad m => MonadModuleTable term value m | m -> term, m -> value where
|
||||
localModuleTable :: (ModuleTable [Module term] -> ModuleTable [Module term]) -> m a -> m a
|
||||
|
||||
-- | Update the evaluated module table.
|
||||
modifyModuleTable :: MonadModuleTable term value m => (ModuleTable (EnvironmentFor value) -> ModuleTable (EnvironmentFor value)) -> m ()
|
||||
modifyModuleTable :: MonadModuleTable term value m => (ModuleTable (EnvironmentFor value, value) -> ModuleTable (EnvironmentFor value, value)) -> m ()
|
||||
modifyModuleTable f = do
|
||||
table <- getModuleTable
|
||||
putModuleTable $! f table
|
||||
@ -153,3 +154,6 @@ class Monad m => MonadControl term m where
|
||||
label :: term -> m Label
|
||||
-- | “Jump” to a previously-allocated 'Label' (retrieving the @term@ at which it points, which can then be evaluated in e.g. a 'MonadAnalysis' instance).
|
||||
goto :: Label -> m term
|
||||
|
||||
class Monad m => MonadThrow exc v m | m -> exc where
|
||||
throwException :: exc -> m v
|
||||
|
@ -80,6 +80,15 @@ class (Monad m, Show value) => MonadValue value m where
|
||||
-- | Construct an array of zero or more values.
|
||||
array :: [value] -> m value
|
||||
|
||||
-- | Construct a key-value pair for use in a hash.
|
||||
kvPair :: value -> value -> m value
|
||||
|
||||
-- | Extract the contents of a key-value pair as a tuple.
|
||||
asPair :: value -> m (value, value)
|
||||
|
||||
-- | Construct a hash out of pairs.
|
||||
hash :: [(value, value)] -> m value
|
||||
|
||||
-- | Extract a 'ByteString' from a given value.
|
||||
asString :: value -> m ByteString
|
||||
|
||||
@ -87,10 +96,20 @@ class (Monad m, Show value) => MonadValue value m where
|
||||
ifthenelse :: value -> m a -> m a -> m a
|
||||
|
||||
-- | Build a class value from a name and environment.
|
||||
klass :: Name -> EnvironmentFor value -> m value
|
||||
klass :: Name -- ^ The new class's identifier
|
||||
-> [value] -- ^ A list of superclasses
|
||||
-> EnvironmentFor value -- ^ The environment to capture
|
||||
-> m value
|
||||
|
||||
-- | Extract the environment from a class.
|
||||
objectEnvironment :: value -> m (EnvironmentFor value)
|
||||
-- | Build a namespace value from a name and environment stack
|
||||
--
|
||||
-- Namespaces model closures with monoidal environments.
|
||||
namespace :: Name -- ^ The namespace's identifier
|
||||
-> EnvironmentFor value -- ^ The environment to mappend
|
||||
-> m value
|
||||
|
||||
-- | Extract the environment from any scoped object (e.g. classes, namespaces, etc).
|
||||
scopedEnvironment :: value -> m (EnvironmentFor value)
|
||||
|
||||
-- | Evaluate an abstraction (a binder like a lambda or method definition).
|
||||
abstract :: (FreeVariables term, MonadControl term m) => [Name] -> Subterm term (m value) -> m value
|
||||
@ -152,11 +171,32 @@ instance ( Monad m
|
||||
multiple = pure . injValue . Value.Tuple
|
||||
array = pure . injValue . Value.Array
|
||||
|
||||
klass n = pure . injValue . Class n
|
||||
kvPair k = pure . injValue . Value.KVPair k
|
||||
|
||||
objectEnvironment o
|
||||
asPair k
|
||||
| Just (Value.KVPair k v) <- prjValue k = pure (k, v)
|
||||
| otherwise = fail ("expected key-value pair, got " <> show k)
|
||||
|
||||
hash = pure . injValue . Value.Hash . fmap (injValue . uncurry Value.KVPair)
|
||||
|
||||
klass n [] env = pure . injValue $ Class n env
|
||||
klass n supers env = do
|
||||
product <- mconcat <$> traverse scopedEnvironment supers
|
||||
pure . injValue $ Class n (Env.push product <> env)
|
||||
|
||||
|
||||
namespace n env = do
|
||||
maybeAddr <- lookupEnv n
|
||||
env' <- maybe (pure mempty) (asNamespaceEnv <=< deref) maybeAddr
|
||||
pure (injValue (Namespace n (env' <> env)))
|
||||
where asNamespaceEnv v
|
||||
| Just (Namespace _ env') <- prjValue v = pure env'
|
||||
| otherwise = fail ("expected " <> show v <> " to be a namespace")
|
||||
|
||||
scopedEnvironment o
|
||||
| Just (Class _ env) <- prjValue o = pure env
|
||||
| otherwise = fail ("non-object type passed to objectEnvironment: " <> show o)
|
||||
| Just (Namespace _ env) <- prjValue o = pure env
|
||||
| otherwise = fail ("object type passed to scopedEnvironment doesn't have an environment: " <> show o)
|
||||
|
||||
asString v
|
||||
| Just (Value.String n) <- prjValue v = pure n
|
||||
@ -226,7 +266,7 @@ instance ( Monad m
|
||||
|
||||
abstract names (Subterm body _) = do
|
||||
l <- label body
|
||||
injValue . Closure names l . Env.bind (foldr Set.delete (freeVariables body) names) <$> getEnv
|
||||
injValue . Closure names l . Env.bind (foldr Set.delete (Set.fromList (freeVariables body)) names) <$> getEnv
|
||||
|
||||
apply op params = do
|
||||
Closure names label env <- maybe (fail ("expected a closure, got: " <> show op)) pure (prjValue op)
|
||||
@ -260,11 +300,16 @@ instance (Alternative m, MonadEnvironment Type m, MonadFail m, MonadFresh m, Mon
|
||||
rational _ = pure Type.Rational
|
||||
multiple = pure . Type.Product
|
||||
array = pure . Type.Array
|
||||
klass _ _ = pure Object
|
||||
hash = pure . Type.Hash
|
||||
kvPair k v = pure (Product [k, v])
|
||||
|
||||
objectEnvironment _ = pure mempty
|
||||
klass _ _ _ = pure Object
|
||||
namespace _ _ = pure Type.Unit
|
||||
|
||||
scopedEnvironment _ = pure mempty
|
||||
|
||||
asString _ = fail "Must evaluate to Value to use asString"
|
||||
asPair _ = fail "Must evaluate to Value to use asPair"
|
||||
|
||||
ifthenelse cond if' else' = unify cond Bool *> (if' <|> else')
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances, ScopedTypeVariables #-}
|
||||
module Control.Effect where
|
||||
|
||||
import qualified Control.Monad.Effect as Effect
|
||||
import Control.Monad.Effect as Effect
|
||||
import Control.Monad.Effect.Fail
|
||||
import Control.Monad.Effect.Internal
|
||||
import Control.Monad.Effect.NonDetEff
|
||||
import Control.Monad.Effect.NonDet
|
||||
import Control.Monad.Effect.Reader
|
||||
import Control.Monad.Effect.State
|
||||
import Control.Monad.Effect.Writer
|
||||
import Control.Monad.Effect.Resumable
|
||||
import Data.Semigroup.Reducer
|
||||
import Prologue
|
||||
|
||||
@ -58,12 +58,18 @@ instance Monoid w => RunEffect (Writer w) a where
|
||||
type Result (Writer w) a = (a, w)
|
||||
runEffect = runWriter
|
||||
|
||||
-- | 'NonDetEff' effects are interpreted into a nondeterministic set of result values.
|
||||
instance Ord a => RunEffect NonDetEff a where
|
||||
type Result NonDetEff a = Set a
|
||||
runEffect = relay (pure . unit) (\ m k -> case m of
|
||||
MZero -> pure mempty
|
||||
MPlus -> mappend <$> k True <*> k False)
|
||||
-- | 'NonDet' effects are interpreted into a nondeterministic set of result values.
|
||||
instance Ord a => RunEffect NonDet a where
|
||||
type Result NonDet a = Set a
|
||||
runEffect = runNonDet unit
|
||||
|
||||
-- | 'Resumable' effects are interpreted into 'Either' s.t. failures are in 'Left' and successful results are in 'Right'.
|
||||
instance RunEffect (Resumable exc v) a where
|
||||
type Result (Resumable exc v) a = Either exc a
|
||||
runEffect = runError
|
||||
|
||||
resumeException :: forall v m exc e a. (Effectful m, Resumable exc v :< e) => m e a -> ((v -> m e a) -> exc -> m e a) -> m e a
|
||||
resumeException m handle = raise (resumeError (lower m) (\yield -> lower . handle (raise . yield)))
|
||||
|
||||
|
||||
-- | Types wrapping 'Eff' actions.
|
||||
|
@ -1,11 +1,11 @@
|
||||
{-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Control.Effect.NonDet
|
||||
( MonadNonDet(..)
|
||||
, NonDetEff
|
||||
, NonDet
|
||||
) where
|
||||
|
||||
import Control.Monad.Effect.Internal
|
||||
import Control.Monad.Effect.NonDetEff
|
||||
import Control.Monad.Effect.NonDet as NonDet
|
||||
import Prologue
|
||||
|
||||
-- | 'Monad's offering local isolation of nondeterminism effects.
|
||||
@ -16,8 +16,6 @@ class (Alternative m, Monad m) => MonadNonDet m where
|
||||
-> m a -- ^ The computation to run locally-nondeterministically.
|
||||
-> m b -- ^ A _deterministic_ computation producing the 'Monoid'al accumulation of the _locally-nondeterministic_ result values.
|
||||
|
||||
-- | Effect stacks containing 'NonDetEff' offer a 'MonadNonDet' instance which implements 'gather' by interpreting the requests for nondeterminism locally, without removing 'NonDetEff' from the stack—i.e. the _capacity_ for nondeterminism is still present in the effect stack, but any local nondeterminism has been applied.
|
||||
instance (NonDetEff :< fs) => MonadNonDet (Eff fs) where
|
||||
gather f = interpose (pure . f) (\ m k -> case m of
|
||||
MZero -> pure mempty
|
||||
MPlus -> mappend <$> k True <*> k False)
|
||||
-- | Effect stacks containing 'NonDet' offer a 'MonadNonDet' instance which implements 'gather' by interpreting the requests for nondeterminism locally, without removing 'NonDet' from the stack—i.e. the _capacity_ for nondeterminism is still present in the effect stack, but any local nondeterminism has been applied.
|
||||
instance (NonDet :< fs) => MonadNonDet (Eff fs) where
|
||||
gather = NonDet.gather
|
||||
|
@ -16,8 +16,8 @@ import Data.Abstract.Value
|
||||
import Data.Functor.Classes
|
||||
import Data.Proxy
|
||||
import Data.Semigroup.Foldable
|
||||
import Data.Semigroup.App
|
||||
import Data.Term
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
|
||||
|
||||
@ -28,10 +28,11 @@ class Evaluatable constr where
|
||||
, MonadAnalysis term value m
|
||||
, MonadValue value m
|
||||
, Show (LocationFor value)
|
||||
, MonadThrow Prelude.String value m
|
||||
)
|
||||
=> SubtermAlgebra constr term (m value)
|
||||
default eval :: (MonadFail m, Show1 constr) => SubtermAlgebra constr term (m value)
|
||||
eval expr = fail $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr ""
|
||||
default eval :: (MonadThrow Prelude.String value m, Show1 constr) => SubtermAlgebra constr term (m value)
|
||||
eval expr = throwException $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr ""
|
||||
|
||||
-- | If we can evaluate any syntax which can occur in a 'Union', we can evaluate the 'Union'.
|
||||
instance Apply Evaluatable fs => Evaluatable (Union fs) where
|
||||
@ -51,14 +52,4 @@ instance Evaluatable s => Evaluatable (TermF s a) where
|
||||
-- 3. Only the last statement’s return value is returned.
|
||||
instance Evaluatable [] where
|
||||
-- 'nonEmpty' and 'foldMap1' enable us to return the last statement’s result instead of 'unit' for non-empty lists.
|
||||
eval = maybe unit (runImperative . foldMap1 (Imperative . subtermValue)) . nonEmpty
|
||||
|
||||
-- | A 'Semigroup' providing an imperative context which extends the local environment with new bindings.
|
||||
newtype Imperative m a = Imperative { runImperative :: m a }
|
||||
|
||||
instance MonadEnvironment value m => Semigroup (Imperative m a) where
|
||||
Imperative a <> Imperative b = Imperative (a *> b)
|
||||
|
||||
instance (MonadEnvironment value m, MonadValue value m) => Monoid (Imperative m value) where
|
||||
mempty = Imperative unit
|
||||
mappend = (<>)
|
||||
eval = maybe unit (runApp . foldMap1 (App . subtermValue)) . nonEmpty
|
||||
|
@ -5,7 +5,6 @@ import Prologue
|
||||
import Data.Term
|
||||
import Data.ByteString (intercalate)
|
||||
import qualified Data.List.NonEmpty as NonEmpty
|
||||
import Data.Abstract.Path
|
||||
|
||||
-- | The type of variable names.
|
||||
type Name = NonEmpty ByteString
|
||||
@ -18,10 +17,6 @@ name x = x :| []
|
||||
qualifiedName :: [ByteString] -> Name
|
||||
qualifiedName = NonEmpty.fromList
|
||||
|
||||
-- | Construct a qualified 'Name' from a `/` delimited path.
|
||||
pathToQualifiedName :: ByteString -> Name
|
||||
pathToQualifiedName = qualifiedName . splitOnPathSeparator
|
||||
|
||||
-- | User friendly 'ByteString' of a qualified 'Name'.
|
||||
friendlyName :: Name -> ByteString
|
||||
friendlyName xs = intercalate "." (NonEmpty.toList xs)
|
||||
@ -35,7 +30,7 @@ type Label = Int
|
||||
-- | Types which can contain unbound variables.
|
||||
class FreeVariables term where
|
||||
-- | The set of free variables in the given value.
|
||||
freeVariables :: term -> Set Name
|
||||
freeVariables :: term -> [Name]
|
||||
|
||||
|
||||
-- | A lifting of 'FreeVariables' to type constructors of kind @* -> *@.
|
||||
@ -43,24 +38,19 @@ class FreeVariables term where
|
||||
-- 'Foldable' types requiring no additional semantics to the set of free variables (e.g. types which do not bind any variables) can use (and even derive, with @-XDeriveAnyClass@) the default implementation.
|
||||
class FreeVariables1 syntax where
|
||||
-- | Lift a function mapping each element to its set of free variables through a containing structure, collecting the results into a single set.
|
||||
liftFreeVariables :: (a -> Set Name) -> syntax a -> Set Name
|
||||
default liftFreeVariables :: (Foldable syntax) => (a -> Set Name) -> syntax a -> Set Name
|
||||
liftFreeVariables :: (a -> [Name]) -> syntax a -> [Name]
|
||||
default liftFreeVariables :: (Foldable syntax) => (a -> [Name]) -> syntax a -> [Name]
|
||||
liftFreeVariables = foldMap
|
||||
|
||||
-- | Lift the 'freeVariables' method through a containing structure.
|
||||
freeVariables1 :: (FreeVariables1 t, FreeVariables a) => t a -> Set Name
|
||||
freeVariables1 :: (FreeVariables1 t, FreeVariables a) => t a -> [Name]
|
||||
freeVariables1 = liftFreeVariables freeVariables
|
||||
|
||||
freeVariable :: FreeVariables term => term -> Name
|
||||
freeVariable term = case toList (freeVariables term) of
|
||||
freeVariable term = case freeVariables term of
|
||||
[n] -> n
|
||||
xs -> Prelude.fail ("expected single free variable, but got: " <> show xs)
|
||||
|
||||
-- TODO: Need a dedicated concept of qualified names outside of freevariables (a
|
||||
-- Set) b/c you can have something like `a.a.b.a`
|
||||
-- qualifiedName :: FreeVariables term => term -> Name
|
||||
-- qualifiedName term = let names = toList (freeVariables term) in B.intercalate "." names
|
||||
|
||||
instance (FreeVariables1 syntax, Functor syntax) => FreeVariables (Term syntax ann) where
|
||||
freeVariables = cata (liftFreeVariables id)
|
||||
|
||||
|
@ -3,17 +3,12 @@ module Data.Abstract.Path where
|
||||
import Prologue
|
||||
import qualified Data.ByteString.Char8 as BC
|
||||
import qualified Data.ByteString as B
|
||||
import Data.Char (ord)
|
||||
|
||||
-- | Split a 'ByteString' path on `/`, stripping quotes and any `./` prefix.
|
||||
splitOnPathSeparator :: ByteString -> [ByteString]
|
||||
splitOnPathSeparator = splitOnPathSeparator' id
|
||||
|
||||
splitOnPathSeparator' :: (ByteString -> ByteString) -> ByteString -> [ByteString]
|
||||
splitOnPathSeparator' f = BC.split '/' . f . dropRelativePrefix . stripQuotes
|
||||
splitOnPathSeparator = BC.split '/'
|
||||
|
||||
stripQuotes :: ByteString -> ByteString
|
||||
stripQuotes = B.filter (/= fromIntegral (ord '\"'))
|
||||
stripQuotes = B.filter (`B.notElem` "\'\"")
|
||||
|
||||
dropRelativePrefix :: ByteString -> ByteString
|
||||
dropRelativePrefix = BC.dropWhile (== '/') . BC.dropWhile (== '.')
|
||||
|
@ -9,18 +9,19 @@ type TName = Int
|
||||
|
||||
-- | A datatype representing primitive types and combinations thereof.
|
||||
data Type
|
||||
= Int -- ^ Primitive int type.
|
||||
| Bool -- ^ Primitive boolean type.
|
||||
| String -- ^ Primitive string type.
|
||||
| Symbol -- ^ Type of unique symbols.
|
||||
| Unit -- ^ The unit type.
|
||||
| Float -- ^ Floating-point type.
|
||||
| Rational -- ^ Rational type.
|
||||
| Type :-> Type -- ^ Binary function types.
|
||||
| Var TName -- ^ A type variable.
|
||||
| Product [Type] -- ^ N-ary products.
|
||||
| Array [Type] -- ^ Arrays. Note that this is heterogenous.
|
||||
| Object -- ^ Objects. Once we have some notion of inheritance we'll need to store a superclass.
|
||||
= Int -- ^ Primitive int type.
|
||||
| Bool -- ^ Primitive boolean type.
|
||||
| String -- ^ Primitive string type.
|
||||
| Symbol -- ^ Type of unique symbols.
|
||||
| Unit -- ^ The unit type.
|
||||
| Float -- ^ Floating-point type.
|
||||
| Rational -- ^ Rational type.
|
||||
| Type :-> Type -- ^ Binary function types.
|
||||
| Var TName -- ^ A type variable.
|
||||
| Product [Type] -- ^ N-ary products.
|
||||
| Array [Type] -- ^ Arrays. Note that this is heterogenous.
|
||||
| Hash [(Type, Type)] -- ^ Heterogenous key-value maps.
|
||||
| Object -- ^ Objects. Once we have some notion of inheritance we'll need to store a superclass.
|
||||
deriving (Eq, Ord, Show)
|
||||
|
||||
-- TODO: À la carte representation of types.
|
||||
|
@ -21,9 +21,12 @@ type ValueConstructors
|
||||
, Class
|
||||
, Closure
|
||||
, Float
|
||||
, Hash
|
||||
, Integer
|
||||
, String
|
||||
, KVPair
|
||||
, Namespace
|
||||
, Rational
|
||||
, String
|
||||
, Symbol
|
||||
, Tuple
|
||||
, Unit
|
||||
@ -145,6 +148,35 @@ instance Eq1 Class where liftEq = genericLiftEq
|
||||
instance Ord1 Class where liftCompare = genericLiftCompare
|
||||
instance Show1 Class where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
data Namespace value = Namespace
|
||||
{ namespaceName :: Name
|
||||
, namespaceScope :: Environment Precise value
|
||||
} deriving (Eq, Generic1, Ord, Show)
|
||||
|
||||
instance Eq1 Namespace where liftEq = genericLiftEq
|
||||
instance Ord1 Namespace where liftCompare = genericLiftCompare
|
||||
instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
data KVPair value = KVPair value value
|
||||
deriving (Eq, Generic1, Ord, Show)
|
||||
|
||||
instance Eq1 KVPair where liftEq = genericLiftEq
|
||||
instance Ord1 KVPair where liftCompare = genericLiftCompare
|
||||
instance Show1 KVPair where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
-- You would think this would be a @Map value value@ or a @[(value, value)].
|
||||
-- You would be incorrect, as we can't derive a Generic1 instance for the above,
|
||||
-- and in addition a 'Map' representation would lose information given hash literals
|
||||
-- that assigned multiple values to one given key. Instead, this holds KVPair
|
||||
-- values. The smart constructor for hashes in MonadValue ensures that these are
|
||||
-- only populated with pairs.
|
||||
newtype Hash value = Hash [value]
|
||||
deriving (Eq, Generic1, Ord, Show)
|
||||
|
||||
instance Eq1 Hash where liftEq = genericLiftEq
|
||||
instance Ord1 Hash where liftCompare = genericLiftCompare
|
||||
instance Show1 Hash where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
-- | The environment for an abstract value type.
|
||||
type EnvironmentFor v = Environment (LocationFor v) v
|
||||
|
||||
|
39
src/Data/Semigroup/App.hs
Normal file
39
src/Data/Semigroup/App.hs
Normal file
@ -0,0 +1,39 @@
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
module Data.Semigroup.App
|
||||
( App(..)
|
||||
, AppMerge(..)
|
||||
) where
|
||||
|
||||
import Control.Applicative
|
||||
import Data.Semigroup
|
||||
|
||||
-- $setup
|
||||
-- >>> import Test.QuickCheck
|
||||
-- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary ; shrink = map App . shrink . runApp
|
||||
-- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary ; shrink = map AppMerge . shrink . runAppMerge
|
||||
|
||||
-- | 'Semigroup' under '*>'.
|
||||
newtype App f a = App { runApp :: f a }
|
||||
deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable)
|
||||
|
||||
-- $ Associativity:
|
||||
-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: App Maybe Integer)
|
||||
instance Applicative f => Semigroup (App f a) where
|
||||
App a <> App b = App (a *> b)
|
||||
|
||||
|
||||
-- | 'Semigroup' and 'Monoid' under '<*>' and '<>'.
|
||||
newtype AppMerge f a = AppMerge { runAppMerge :: f a }
|
||||
deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable)
|
||||
|
||||
-- $ Associativity:
|
||||
-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: AppMerge Maybe String)
|
||||
instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where
|
||||
AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b)
|
||||
|
||||
-- $ Identity:
|
||||
-- prop> \ a -> mempty <> a == (a :: AppMerge Maybe String)
|
||||
-- prop> \ a -> a <> mempty == (a :: AppMerge Maybe String)
|
||||
instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where
|
||||
mempty = AppMerge (pure mempty)
|
||||
mappend = (<>)
|
@ -7,7 +7,6 @@ import Data.Abstract.Evaluatable
|
||||
import Data.AST
|
||||
import Data.Range
|
||||
import Data.Record
|
||||
import qualified Data.Set as Set
|
||||
import Data.Span
|
||||
import Data.Term
|
||||
import Diffing.Algorithm hiding (Empty)
|
||||
@ -111,7 +110,7 @@ instance Evaluatable Identifier where
|
||||
eval (Identifier name) = lookupWith deref name >>= maybe (fail ("free variable: " <> show (friendlyName name))) pure
|
||||
|
||||
instance FreeVariables1 Identifier where
|
||||
liftFreeVariables _ (Identifier x) = Set.singleton x
|
||||
liftFreeVariables _ (Identifier x) = pure x
|
||||
|
||||
|
||||
newtype Program a = Program [a]
|
||||
|
@ -1,6 +1,7 @@
|
||||
{-# LANGUAGE DeriveAnyClass, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances #-}
|
||||
module Data.Syntax.Declaration where
|
||||
|
||||
import Analysis.Abstract.Evaluating
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Evaluatable
|
||||
import Diffing.Algorithm
|
||||
@ -146,10 +147,11 @@ instance Show1 Class where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Class where
|
||||
eval Class{..} = do
|
||||
let name = freeVariable (subterm classIdentifier)
|
||||
supers <- traverse subtermValue classSuperclasses
|
||||
(v, addr) <- letrec name $ do
|
||||
void $ subtermValue classBody
|
||||
classEnv <- Env.head <$> getEnv
|
||||
klass name classEnv
|
||||
klass name supers classEnv
|
||||
v <$ modifyEnv (Env.insert name addr)
|
||||
|
||||
data Module a = Module { moduleIdentifier :: !a, moduleScope :: ![a] }
|
||||
@ -243,7 +245,7 @@ instance Show1 QualifiedExportFrom where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable QualifiedExportFrom where
|
||||
eval (QualifiedExportFrom from exportSymbols) = do
|
||||
let moduleName = freeVariable (subterm from)
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
-- Look up addresses in importedEnv and insert the aliases with addresses into the exports.
|
||||
for_ exportSymbols $ \(name, alias) -> do
|
||||
let address = Env.lookup name importedEnv
|
||||
@ -276,7 +278,7 @@ instance Show1 QualifiedImport where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable QualifiedImport where
|
||||
eval (QualifiedImport from alias xs) = do
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
modifyEnv (mappend (Env.overwrite (renames importedEnv) importedEnv))
|
||||
unit
|
||||
where
|
||||
@ -299,7 +301,7 @@ instance Show1 Import where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Import where
|
||||
eval (Import from xs _) = do
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
modifyEnv (mappend (renamed importedEnv))
|
||||
unit
|
||||
where
|
||||
|
@ -193,7 +193,7 @@ instance Show1 MemberAccess where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable MemberAccess where
|
||||
eval (fmap subtermValue -> MemberAccess mem acc) = do
|
||||
lhs <- mem >>= objectEnvironment
|
||||
lhs <- mem >>= scopedEnvironment
|
||||
localEnv (mappend lhs) acc
|
||||
|
||||
-- | Subscript (e.g a[1])
|
||||
|
@ -1,6 +1,7 @@
|
||||
{-# LANGUAGE DataKinds, DeriveAnyClass, DeriveGeneric, MultiParamTypeClasses, TypeApplications #-}
|
||||
{-# LANGUAGE DataKinds, DeriveAnyClass, DeriveGeneric, MultiParamTypeClasses, TypeApplications, ViewPatterns #-}
|
||||
module Data.Syntax.Literal where
|
||||
|
||||
import Control.Arrow ((>>>))
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.ByteString.Char8 (readInteger, unpack)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
@ -8,7 +9,7 @@ import Data.Monoid (Endo (..), appEndo)
|
||||
import Data.Scientific (Scientific)
|
||||
import Diffing.Algorithm
|
||||
import Prelude hiding (Float, fail)
|
||||
import Prologue hiding (Set)
|
||||
import Prologue hiding (Set, hash)
|
||||
import Text.Read (readMaybe)
|
||||
|
||||
-- Boolean
|
||||
@ -215,9 +216,8 @@ instance Eq1 Hash where liftEq = genericLiftEq
|
||||
instance Ord1 Hash where liftCompare = genericLiftCompare
|
||||
instance Show1 Hash where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
-- TODO: Implement Eval instance for Hash
|
||||
instance Evaluatable Hash
|
||||
|
||||
instance Evaluatable Hash where
|
||||
eval = hashElements >>> traverse (subtermValue >=> asPair) >=> hash
|
||||
|
||||
data KeyValue a = KeyValue { key :: !a, value :: !a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)
|
||||
@ -226,9 +226,9 @@ instance Eq1 KeyValue where liftEq = genericLiftEq
|
||||
instance Ord1 KeyValue where liftCompare = genericLiftCompare
|
||||
instance Show1 KeyValue where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
-- TODO: Implement Eval instance for KeyValue
|
||||
instance Evaluatable KeyValue
|
||||
|
||||
instance Evaluatable KeyValue where
|
||||
eval (fmap subtermValue -> KeyValue{..}) =
|
||||
join (kvPair <$> key <*> value)
|
||||
|
||||
newtype Tuple a = Tuple { tupleContents :: [a] }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeOperators #-}
|
||||
{-# LANGUAGE RankNTypes, TypeFamilies, TypeOperators #-}
|
||||
module Data.Term
|
||||
( Term(..)
|
||||
, termIn
|
||||
|
@ -393,7 +393,7 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
|
||||
namedImport = inj <$> (flip Declaration.QualifiedImport <$> packageIdentifier <*> importFromPath <*> pure [])
|
||||
-- `import "lib/Math"`
|
||||
plainImport = inj <$> (symbol InterpretedStringLiteral >>= \loc -> do
|
||||
names <- splitOnPathSeparator <$> source
|
||||
names <- toName <$> source
|
||||
let from = makeTerm loc (Syntax.Identifier (qualifiedName names))
|
||||
let alias = makeTerm loc (Syntax.Identifier (name (last names))) -- Go takes `import "lib/Math"` and uses `Math` as the qualified name (e.g. `Math.Sin()`)
|
||||
Declaration.QualifiedImport <$> pure from <*> pure alias <*> pure [])
|
||||
@ -403,7 +403,11 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
|
||||
underscore = makeTerm <$> symbol BlankIdentifier <*> (Literal.TextElement <$> source)
|
||||
importSpec = makeTerm' <$> symbol ImportSpec <*> children (sideEffectImport <|> dotImport <|> namedImport <|> plainImport)
|
||||
importSpecList = makeTerm <$> symbol ImportSpecList <*> children (manyTerm (importSpec <|> comment))
|
||||
importFromPath = makeTerm <$> symbol InterpretedStringLiteral <*> (Syntax.Identifier <$> (pathToQualifiedName <$> source))
|
||||
importFromPath = makeTerm <$> symbol InterpretedStringLiteral <*> (Syntax.Identifier <$> (toQualifiedName <$> source))
|
||||
|
||||
toQualifiedName = qualifiedName . toName
|
||||
toName = splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
|
||||
indexExpression :: Assignment
|
||||
indexExpression = makeTerm <$> symbol IndexExpression <*> children (Expression.Subscript <$> expression <*> manyTerm expression)
|
||||
|
@ -1,393 +1,529 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveAnyClass, ViewPatterns #-}
|
||||
module Language.PHP.Syntax where
|
||||
|
||||
import Prologue hiding (Text)
|
||||
import Analysis.Abstract.Evaluating
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Path
|
||||
import Diffing.Algorithm
|
||||
import Prelude hiding (fail)
|
||||
import Prologue hiding (Text)
|
||||
|
||||
|
||||
newtype Text a = Text ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Text where liftEq = genericLiftEq
|
||||
instance Ord1 Text where liftCompare = genericLiftCompare
|
||||
instance Show1 Text where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Text
|
||||
|
||||
|
||||
newtype VariableName a = VariableName a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 VariableName where liftEq = genericLiftEq
|
||||
instance Ord1 VariableName where liftCompare = genericLiftCompare
|
||||
instance Show1 VariableName where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable VariableName
|
||||
|
||||
newtype RequireOnce a = RequireOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
-- TODO: Variables defined in an included file take on scope of the source line
|
||||
-- on which the inclusion occurs in the including file. However, functions and
|
||||
-- classes defined in the included file are always in global scope.
|
||||
|
||||
instance Eq1 RequireOnce where liftEq = genericLiftEq
|
||||
instance Ord1 RequireOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 RequireOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
-- TODO: If inclusion occurs inside a function definition within the including
|
||||
-- file, the complete contents of the included file are treated as though it
|
||||
-- were defined inside that function.
|
||||
|
||||
doInclude :: (MonadValue value m, MonadAnalysis term value m) => Subterm t (m value) -> m value
|
||||
doInclude path = do
|
||||
name <- toQualifiedName <$> (subtermValue path >>= asString)
|
||||
(importedEnv, v) <- isolate (load name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
pure v
|
||||
|
||||
doIncludeOnce :: (MonadValue value m, MonadAnalysis term value m) => Subterm t (m value) -> m value
|
||||
doIncludeOnce path = do
|
||||
name <- toQualifiedName <$> (subtermValue path >>= asString)
|
||||
(importedEnv, v) <- isolate (require name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
pure v
|
||||
|
||||
toQualifiedName :: ByteString -> Name
|
||||
toQualifiedName = qualifiedName . splitOnPathSeparator . dropExtension . dropRelativePrefix . stripQuotes
|
||||
|
||||
newtype Require a = Require a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Require where liftEq = genericLiftEq
|
||||
instance Ord1 Require where liftCompare = genericLiftCompare
|
||||
instance Show1 Require where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Require where
|
||||
eval (Require path) = doInclude path
|
||||
|
||||
|
||||
newtype RequireOnce a = RequireOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 RequireOnce where liftEq = genericLiftEq
|
||||
instance Ord1 RequireOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 RequireOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable RequireOnce where
|
||||
eval (RequireOnce path) = doIncludeOnce path
|
||||
|
||||
|
||||
newtype Include a = Include a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Include where liftEq = genericLiftEq
|
||||
instance Ord1 Include where liftCompare = genericLiftCompare
|
||||
instance Show1 Include where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Include where
|
||||
eval (Include path) = doInclude path
|
||||
|
||||
|
||||
newtype IncludeOnce a = IncludeOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 IncludeOnce where liftEq = genericLiftEq
|
||||
instance Ord1 IncludeOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 IncludeOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable IncludeOnce where
|
||||
eval (IncludeOnce path) = doIncludeOnce path
|
||||
|
||||
|
||||
newtype ArrayElement a = ArrayElement a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ArrayElement where liftEq = genericLiftEq
|
||||
instance Ord1 ArrayElement where liftCompare = genericLiftCompare
|
||||
instance Show1 ArrayElement where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ArrayElement
|
||||
|
||||
newtype GlobalDeclaration a = GlobalDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 GlobalDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 GlobalDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 GlobalDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable GlobalDeclaration
|
||||
|
||||
newtype SimpleVariable a = SimpleVariable a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 SimpleVariable where liftEq = genericLiftEq
|
||||
instance Ord1 SimpleVariable where liftCompare = genericLiftCompare
|
||||
instance Show1 SimpleVariable where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable SimpleVariable
|
||||
|
||||
|
||||
-- | TODO: Unify with TypeScript's PredefinedType
|
||||
newtype CastType a = CastType { _castType :: ByteString }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 CastType where liftEq = genericLiftEq
|
||||
instance Ord1 CastType where liftCompare = genericLiftCompare
|
||||
instance Show1 CastType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable CastType
|
||||
|
||||
newtype ErrorControl a = ErrorControl a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ErrorControl where liftEq = genericLiftEq
|
||||
instance Ord1 ErrorControl where liftCompare = genericLiftCompare
|
||||
instance Show1 ErrorControl where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ErrorControl
|
||||
|
||||
newtype Clone a = Clone a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Clone where liftEq = genericLiftEq
|
||||
instance Ord1 Clone where liftCompare = genericLiftCompare
|
||||
instance Show1 Clone where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Clone
|
||||
|
||||
newtype ShellCommand a = ShellCommand ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ShellCommand where liftEq = genericLiftEq
|
||||
instance Ord1 ShellCommand where liftCompare = genericLiftCompare
|
||||
instance Show1 ShellCommand where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ShellCommand
|
||||
|
||||
-- | TODO: Combine with TypeScript update expression.
|
||||
newtype Update a = Update { _updateSubject :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Update where liftEq = genericLiftEq
|
||||
instance Ord1 Update where liftCompare = genericLiftCompare
|
||||
instance Show1 Update where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Update
|
||||
|
||||
newtype NewVariable a = NewVariable [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NewVariable where liftEq = genericLiftEq
|
||||
instance Ord1 NewVariable where liftCompare = genericLiftCompare
|
||||
instance Show1 NewVariable where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NewVariable
|
||||
|
||||
newtype RelativeScope a = RelativeScope ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 RelativeScope where liftEq = genericLiftEq
|
||||
instance Ord1 RelativeScope where liftCompare = genericLiftCompare
|
||||
instance Show1 RelativeScope where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable RelativeScope
|
||||
|
||||
data QualifiedName a = QualifiedName a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
data QualifiedName a = QualifiedName !a !a
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 QualifiedName where liftEq = genericLiftEq
|
||||
instance Ord1 QualifiedName where liftCompare = genericLiftCompare
|
||||
instance Show1 QualifiedName where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable QualifiedName where
|
||||
eval (fmap subtermValue -> QualifiedName name iden) = do
|
||||
lhs <- name >>= scopedEnvironment
|
||||
localEnv (mappend lhs) iden
|
||||
|
||||
|
||||
newtype NamespaceName a = NamespaceName [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceName where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceName where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceName where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable NamespaceName where
|
||||
eval (NamespaceName xs) = go xs
|
||||
where
|
||||
go [] = fail "nonempty NamespaceName not allowed"
|
||||
go [x] = subtermValue x
|
||||
go (x:xs) = do
|
||||
env <- subtermValue x >>= scopedEnvironment
|
||||
localEnv (mappend env) (go xs)
|
||||
|
||||
newtype ConstDeclaration a = ConstDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ConstDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ConstDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ConstDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ConstDeclaration
|
||||
|
||||
data ClassConstDeclaration a = ClassConstDeclaration a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassConstDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ClassConstDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassConstDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassConstDeclaration
|
||||
|
||||
newtype ClassInterfaceClause a = ClassInterfaceClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassInterfaceClause where liftEq = genericLiftEq
|
||||
instance Ord1 ClassInterfaceClause where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassInterfaceClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassInterfaceClause
|
||||
|
||||
newtype ClassBaseClause a = ClassBaseClause a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassBaseClause where liftEq = genericLiftEq
|
||||
instance Ord1 ClassBaseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassBaseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassBaseClause
|
||||
|
||||
|
||||
newtype UseClause a = UseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 UseClause where liftEq = genericLiftEq
|
||||
instance Ord1 UseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 UseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable UseClause
|
||||
|
||||
newtype ReturnType a = ReturnType a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ReturnType where liftEq = genericLiftEq
|
||||
instance Ord1 ReturnType where liftCompare = genericLiftCompare
|
||||
instance Show1 ReturnType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ReturnType
|
||||
|
||||
newtype TypeDeclaration a = TypeDeclaration a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TypeDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 TypeDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 TypeDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TypeDeclaration
|
||||
|
||||
newtype BaseTypeDeclaration a = BaseTypeDeclaration a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 BaseTypeDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 BaseTypeDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 BaseTypeDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable BaseTypeDeclaration
|
||||
|
||||
newtype ScalarType a = ScalarType ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ScalarType where liftEq = genericLiftEq
|
||||
instance Ord1 ScalarType where liftCompare = genericLiftCompare
|
||||
instance Show1 ScalarType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ScalarType
|
||||
|
||||
newtype EmptyIntrinsic a = EmptyIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 EmptyIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 EmptyIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 EmptyIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable EmptyIntrinsic
|
||||
|
||||
newtype ExitIntrinsic a = ExitIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ExitIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 ExitIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 ExitIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ExitIntrinsic
|
||||
|
||||
newtype IssetIntrinsic a = IssetIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 IssetIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 IssetIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 IssetIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable IssetIntrinsic
|
||||
|
||||
newtype EvalIntrinsic a = EvalIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 EvalIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 EvalIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 EvalIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable EvalIntrinsic
|
||||
|
||||
newtype PrintIntrinsic a = PrintIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PrintIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 PrintIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 PrintIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PrintIntrinsic
|
||||
|
||||
newtype NamespaceAliasingClause a = NamespaceAliasingClause a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceAliasingClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceAliasingClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceAliasingClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceAliasingClause
|
||||
|
||||
newtype NamespaceUseDeclaration a = NamespaceUseDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseDeclaration
|
||||
|
||||
newtype NamespaceUseClause a = NamespaceUseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseClause
|
||||
|
||||
newtype NamespaceUseGroupClause a = NamespaceUseGroupClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseGroupClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseGroupClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseGroupClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseGroupClause
|
||||
|
||||
data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a}
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Namespace where liftEq = genericLiftEq
|
||||
instance Ord1 Namespace where liftCompare = genericLiftCompare
|
||||
instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Namespace where
|
||||
eval Namespace{..} = go names
|
||||
where
|
||||
names = freeVariables (subterm namespaceName)
|
||||
go [] = fail "expected at least one free variable in namespaceName, found none"
|
||||
-- The last name creates a closure over the namespace body.
|
||||
go [name] = letrec' name $ \addr ->
|
||||
subtermValue namespaceBody *> makeNamespace name addr
|
||||
-- Each namespace name creates a closure over the subsequent namespace closures
|
||||
go (name:xs) = letrec' name $ \addr ->
|
||||
go xs <* makeNamespace name addr
|
||||
|
||||
-- Make a namespace closure capturing the current environment.
|
||||
makeNamespace name addr = do
|
||||
namespaceEnv <- Env.head <$> getEnv
|
||||
v <- namespace name namespaceEnv
|
||||
v <$ assign addr v
|
||||
|
||||
-- Lookup/alloc a name passing the address to a body evaluated in a new local environment.
|
||||
letrec' name body = do
|
||||
addr <- lookupOrAlloc name
|
||||
v <- localEnv id (body addr)
|
||||
v <$ modifyEnv (insert name addr)
|
||||
|
||||
data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 TraitDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitDeclaration
|
||||
|
||||
data AliasAs a = AliasAs { aliasAsName :: a, aliasAsModifier :: a, aliasAsClause :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 AliasAs where liftEq = genericLiftEq
|
||||
instance Ord1 AliasAs where liftCompare = genericLiftCompare
|
||||
instance Show1 AliasAs where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable AliasAs
|
||||
|
||||
data InsteadOf a = InsteadOf a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InsteadOf where liftEq = genericLiftEq
|
||||
instance Ord1 InsteadOf where liftCompare = genericLiftCompare
|
||||
instance Show1 InsteadOf where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InsteadOf
|
||||
|
||||
newtype TraitUseSpecification a = TraitUseSpecification [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitUseSpecification where liftEq = genericLiftEq
|
||||
instance Ord1 TraitUseSpecification where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitUseSpecification where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitUseSpecification
|
||||
|
||||
data TraitUseClause a = TraitUseClause [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitUseClause where liftEq = genericLiftEq
|
||||
instance Ord1 TraitUseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitUseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitUseClause
|
||||
|
||||
data DestructorDeclaration a = DestructorDeclaration [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 DestructorDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 DestructorDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 DestructorDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable DestructorDeclaration
|
||||
|
||||
newtype Static a = Static ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Static where liftEq = genericLiftEq
|
||||
instance Ord1 Static where liftCompare = genericLiftCompare
|
||||
instance Show1 Static where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Static
|
||||
|
||||
newtype ClassModifier a = ClassModifier ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassModifier where liftEq = genericLiftEq
|
||||
instance Ord1 ClassModifier where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassModifier where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassModifier
|
||||
|
||||
data ConstructorDeclaration a = ConstructorDeclaration [a] [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ConstructorDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ConstructorDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ConstructorDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ConstructorDeclaration
|
||||
|
||||
data PropertyDeclaration a = PropertyDeclaration a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PropertyDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 PropertyDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 PropertyDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PropertyDeclaration
|
||||
|
||||
data PropertyModifier a = PropertyModifier a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PropertyModifier where liftEq = genericLiftEq
|
||||
instance Ord1 PropertyModifier where liftCompare = genericLiftCompare
|
||||
instance Show1 PropertyModifier where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PropertyModifier
|
||||
|
||||
data InterfaceDeclaration a = InterfaceDeclaration a a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InterfaceDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 InterfaceDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 InterfaceDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InterfaceDeclaration
|
||||
|
||||
newtype InterfaceBaseClause a = InterfaceBaseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InterfaceBaseClause where liftEq = genericLiftEq
|
||||
instance Ord1 InterfaceBaseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 InterfaceBaseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InterfaceBaseClause
|
||||
|
||||
newtype Echo a = Echo a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Echo where liftEq = genericLiftEq
|
||||
instance Ord1 Echo where liftCompare = genericLiftCompare
|
||||
instance Show1 Echo where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Echo
|
||||
|
||||
newtype Unset a = Unset a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Unset where liftEq = genericLiftEq
|
||||
instance Ord1 Unset where liftCompare = genericLiftCompare
|
||||
instance Show1 Unset where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Unset
|
||||
|
||||
data Declare a = Declare a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Declare where liftEq = genericLiftEq
|
||||
instance Ord1 Declare where liftCompare = genericLiftCompare
|
||||
instance Show1 Declare where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Declare
|
||||
|
||||
newtype DeclareDirective a = DeclareDirective a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 DeclareDirective where liftEq = genericLiftEq
|
||||
instance Ord1 DeclareDirective where liftCompare = genericLiftCompare
|
||||
instance Show1 DeclareDirective where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable DeclareDirective
|
||||
|
||||
newtype LabeledStatement a = LabeledStatement { _labeledStatementIdentifier :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 LabeledStatement where liftEq = genericLiftEq
|
||||
instance Ord1 LabeledStatement where liftCompare = genericLiftCompare
|
||||
instance Show1 LabeledStatement where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable LabeledStatement
|
||||
|
@ -340,12 +340,9 @@ yield = makeTerm <$> symbol Yield <*> (Statement.Yield <$> children (term ( expr
|
||||
-- Identifiers and qualified identifiers (e.g. `a.b.c`) from things like DottedName and Attribute
|
||||
identifier :: Assignment
|
||||
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> (name <$> source))
|
||||
<|> makeQualifiedIdentifier <$> symbol Attribute <*> children (attribute <|> identifierPair)
|
||||
<|> makeQualifiedIdentifier <$> symbol DottedName <*> children (some identifier')
|
||||
<|> symbol DottedName *> children identifier
|
||||
where
|
||||
attribute = (\a b -> a <> [b]) <$> (symbol Attribute *> children (attribute <|> identifierPair)) <*> identifier'
|
||||
identifierPair = (\a b -> [a, b]) <$> identifier' <*> identifier'
|
||||
identifier' = (symbol Identifier <|> symbol Identifier') *> source
|
||||
makeQualifiedIdentifier loc xs = makeTerm loc (Syntax.Identifier (qualifiedName xs))
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
module Language.Ruby.Syntax where
|
||||
|
||||
import Analysis.Abstract.Evaluating
|
||||
import Control.Monad (unless)
|
||||
import Control.Abstract.Value (MonadValue)
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.ModuleTable
|
||||
import Data.Abstract.Path
|
||||
import Data.Abstract.Value (LocationFor)
|
||||
import Data.Abstract.Value (EnvironmentFor)
|
||||
import Diffing.Algorithm
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
@ -19,10 +21,22 @@ instance Show1 Require where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Require where
|
||||
eval (Require _ x) = do
|
||||
name <- pathToQualifiedName <$> (subtermValue x >>= asString)
|
||||
importedEnv <- isolate (require name)
|
||||
name <- toName <$> (subtermValue x >>= asString)
|
||||
(importedEnv, v) <- isolate (doRequire name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
unit
|
||||
pure v -- Returns True if the file was loaded, False if it was already loaded. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-require
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
doRequire :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
doRequire name = do
|
||||
moduleTable <- getModuleTable
|
||||
case moduleTableLookup name moduleTable of
|
||||
Nothing -> (,) <$> (fst <$> load name) <*> boolean True
|
||||
Just (env, _) -> (,) <$> pure env <*> boolean False
|
||||
|
||||
|
||||
newtype Load a = Load { loadArgs :: [a] }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)
|
||||
@ -41,12 +55,12 @@ instance Evaluatable Load where
|
||||
doLoad path shouldWrap
|
||||
eval (Load _) = fail "invalid argument supplied to load, path is required"
|
||||
|
||||
doLoad :: (MonadAnalysis term value m, MonadValue value m, Ord (LocationFor value)) => ByteString -> Bool -> m value
|
||||
doLoad :: (MonadAnalysis term value m, MonadValue value m) => ByteString -> Bool -> m value
|
||||
doLoad path shouldWrap = do
|
||||
let name = pathToQualifiedName path
|
||||
importedEnv <- isolate (load name)
|
||||
(importedEnv, _) <- isolate (load (toName path))
|
||||
unless shouldWrap $ modifyEnv (mappend importedEnv)
|
||||
unit
|
||||
where pathToQualifiedName = qualifiedName . splitOnPathSeparator' dropExtension
|
||||
boolean Prelude.True -- load always returns true. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-load
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropExtension . dropRelativePrefix . stripQuotes
|
||||
|
||||
-- TODO: autoload
|
||||
|
@ -9,6 +9,7 @@ module Language.TypeScript.Assignment
|
||||
import Assigning.Assignment hiding (Assignment, Error)
|
||||
import qualified Assigning.Assignment as Assignment
|
||||
import Data.Abstract.FreeVariables
|
||||
import Data.Abstract.Path
|
||||
import Data.Record
|
||||
import Data.Syntax (emptyTerm, handleError, parseError, infixContext, makeTerm, makeTerm', makeTerm'', makeTerm1, contextualize, postContextualize)
|
||||
import qualified Data.Syntax as Syntax
|
||||
@ -672,7 +673,9 @@ importStatement = makeImportTerm <$> symbol Grammar.ImportStatement <*> childr
|
||||
makeNameAliasPair from Nothing = (from, from)
|
||||
|
||||
fromClause :: Assignment
|
||||
fromClause = makeTerm <$> symbol Grammar.String <*> (Syntax.Identifier <$> (pathToQualifiedName <$> source))
|
||||
fromClause = makeTerm <$> symbol Grammar.String <*> (Syntax.Identifier <$> (toName <$> source))
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
debuggerStatement :: Assignment
|
||||
debuggerStatement = makeTerm <$> symbol Grammar.DebuggerStatement <*> (TypeScript.Syntax.Debugger <$ source)
|
||||
|
@ -10,64 +10,48 @@ module Prologue
|
||||
import Data.Bifunctor.Join as X
|
||||
import Data.Bits as X
|
||||
import Data.ByteString as X (ByteString)
|
||||
import Data.Functor.Both as X (Both, runBothWith, both)
|
||||
import Data.Functor.Both as X (Both, both, runBothWith)
|
||||
import Data.IntMap as X (IntMap)
|
||||
import Data.IntSet as X (IntSet)
|
||||
import Data.Ix as X (Ix(..))
|
||||
import Data.Ix as X (Ix (..))
|
||||
import Data.List.NonEmpty as X (NonEmpty (..), nonEmpty, some1)
|
||||
import Data.Map as X (Map)
|
||||
import Data.Monoid (Alt(..))
|
||||
import Data.Maybe as X
|
||||
import Data.Monoid (Alt (..))
|
||||
import Data.Sequence as X (Seq)
|
||||
import Data.Set as X (Set)
|
||||
import Data.Text as X (Text)
|
||||
import Data.These as X
|
||||
import Data.Union as X
|
||||
import Data.List.NonEmpty as X (
|
||||
NonEmpty(..)
|
||||
, nonEmpty
|
||||
, some1
|
||||
)
|
||||
|
||||
import Debug.Trace as X
|
||||
|
||||
import Control.Exception as X hiding (
|
||||
evaluate
|
||||
, throw
|
||||
, throwIO
|
||||
, throwTo
|
||||
, assert
|
||||
, Handler(..)
|
||||
)
|
||||
import Control.Exception as X hiding (Handler (..), assert, evaluate, throw, throwIO, throwTo)
|
||||
|
||||
-- Typeclasses
|
||||
import Control.Applicative as X
|
||||
import Control.Arrow as X ((&&&), (***))
|
||||
import Control.Monad as X hiding (fail, return, unless, when)
|
||||
import Control.Monad.Except as X (MonadError(..))
|
||||
import Control.Monad.Fail as X (MonadFail(..))
|
||||
import Control.Monad.Except as X (MonadError (..))
|
||||
import Control.Monad.Fail as X (MonadFail (..))
|
||||
import Data.Algebra as X
|
||||
import Data.Align.Generic as X (GAlign)
|
||||
import Data.Bifoldable as X
|
||||
import Data.Bifunctor as X (Bifunctor(..))
|
||||
import Data.Bifunctor as X (Bifunctor (..))
|
||||
import Data.Bitraversable as X
|
||||
import Data.Foldable as X hiding (product , sum)
|
||||
import Data.Functor as X (($>), void)
|
||||
import Data.Foldable as X hiding (product, sum)
|
||||
import Data.Function as X (fix, on, (&))
|
||||
import Data.Functor as X (void, ($>))
|
||||
import Data.Functor.Classes as X
|
||||
import Data.Functor.Classes.Generic as X
|
||||
import Data.Functor.Foldable as X (Base, Recursive(..), Corecursive(..))
|
||||
import Data.Functor.Foldable as X (Base, Corecursive (..), Recursive (..))
|
||||
import Data.Hashable as X (Hashable, hash, hashUsing, hashWithSalt)
|
||||
import Data.Mergeable as X (Mergeable)
|
||||
import Data.Monoid as X (Monoid(..), First(..), Last(..))
|
||||
import Data.Proxy as X (Proxy(..))
|
||||
import Data.Semigroup as X (Semigroup(..))
|
||||
import Data.Monoid as X (First (..), Last (..), Monoid (..))
|
||||
import Data.Proxy as X (Proxy (..))
|
||||
import Data.Semigroup as X (Semigroup (..))
|
||||
import Data.Traversable as X
|
||||
import Data.Typeable as X (Typeable)
|
||||
import Data.Hashable as X (
|
||||
Hashable
|
||||
, hash
|
||||
, hashWithSalt
|
||||
, hashUsing
|
||||
)
|
||||
|
||||
-- Generics
|
||||
import GHC.Generics as X hiding (moduleName)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Rendering.Imports
|
||||
( renderToImports
|
||||
, ImportSummary(..)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
{-# LANGUAGE RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||
module Rendering.Symbol
|
||||
( renderSymbolTerms
|
||||
, renderToSymbols
|
||||
|
@ -5,7 +5,7 @@ module Semantic.Util where
|
||||
|
||||
import Analysis.Abstract.Caching
|
||||
import Analysis.Abstract.Dead
|
||||
import Analysis.Abstract.Evaluating
|
||||
import Analysis.Abstract.Evaluating as X
|
||||
import Analysis.Abstract.Tracing
|
||||
import Analysis.Declaration
|
||||
import Control.Abstract.Analysis
|
||||
@ -50,6 +50,10 @@ typecheckPythonFile path = runAnalysis @(Caching Evaluating Python.Term Type) .
|
||||
tracePythonFile path = runAnalysis @(Tracing [] Evaluating Python.Term Value) . evaluateModule <$> parseFile pythonParser Nothing path
|
||||
evaluateDeadTracePythonFile path = runAnalysis @(DeadCode (Tracing [] Evaluating) Python.Term Value) . evaluateModule <$> parseFile pythonParser Nothing path
|
||||
|
||||
-- PHP
|
||||
evaluatePHPFile = evaluateFile phpParser
|
||||
evaluatePHPFiles = evaluateFiles phpParser
|
||||
|
||||
-- TypeScript
|
||||
typecheckTypeScriptFile path = runAnalysis @(Caching Evaluating TypeScript.Term Type) . evaluateModule <$> parseFile typescriptParser Nothing path
|
||||
evaluateTypeScriptFile = evaluateFile typescriptParser
|
||||
|
@ -1,8 +1,9 @@
|
||||
{-# LANGUAGE OverloadedLists, TypeApplications #-}
|
||||
{-# LANGUAGE OverloadedLists #-}
|
||||
module Analysis.Go.Spec (spec) where
|
||||
|
||||
import Data.Abstract.Value
|
||||
import Data.Map
|
||||
import Data.Either
|
||||
|
||||
import SpecHelpers
|
||||
|
||||
@ -11,32 +12,27 @@ spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "evalutes Go" $ do
|
||||
it "imports and wildcard imports" $ do
|
||||
env <- evaluate "main.go"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["foo", "New"], addr 0)
|
||||
, (qualifiedName ["Rab"], addr 1)
|
||||
, (qualifiedName ["Bar"], addr 2)
|
||||
, (qualifiedName ["main"], addr 3)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main.go"
|
||||
env `shouldBe` [ (qualifiedName ["foo", "New"], addr 0)
|
||||
, (qualifiedName ["Rab"], addr 1)
|
||||
, (qualifiedName ["Bar"], addr 2)
|
||||
, (qualifiedName ["main"], addr 3)
|
||||
]
|
||||
|
||||
it "imports with aliases (and side effects only)" $ do
|
||||
env <- evaluate "main1.go"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["f", "New"], addr 0)
|
||||
, (qualifiedName ["main"], addr 3) -- addr 3 is due to side effects of
|
||||
-- eval'ing `import _ "./bar"` which
|
||||
-- used addr 1 & 2.
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main1.go"
|
||||
env `shouldBe` [ (qualifiedName ["f", "New"], addr 0)
|
||||
, (qualifiedName ["main"], addr 3) -- addr 3 is due to side effects of
|
||||
-- eval'ing `import _ "./bar"` which
|
||||
-- used addr 1 & 2.
|
||||
]
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/go/analysis/"
|
||||
evaluate entry = snd . fst . fst . fst . fst <$>
|
||||
evaluateFiles goParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "foo/foo.go"
|
||||
, fixtures <> "bar/bar.go"
|
||||
, fixtures <> "bar/rab.go"
|
||||
]
|
||||
evaluate entry = evaluateFiles goParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "foo/foo.go"
|
||||
, fixtures <> "bar/bar.go"
|
||||
, fixtures <> "bar/rab.go"
|
||||
]
|
||||
|
45
test/Analysis/PHP/Spec.hs
Normal file
45
test/Analysis/PHP/Spec.hs
Normal file
@ -0,0 +1,45 @@
|
||||
{-# LANGUAGE OverloadedLists #-}
|
||||
module Analysis.PHP.Spec (spec) where
|
||||
|
||||
import Data.Abstract.Value
|
||||
import Data.Map
|
||||
import Data.Map.Monoidal as Map
|
||||
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "PHP" $ do
|
||||
it "evaluates include and require" $ do
|
||||
env <- findEnv <$> evaluate "main.php"
|
||||
env `shouldBe` [ (name "foo", addr 0)
|
||||
, (name "bar", addr 1) ]
|
||||
|
||||
it "evaluates include_once and require_once" $ do
|
||||
env <- findEnv <$> evaluate "main_once.php"
|
||||
env `shouldBe` [ (name "foo", addr 0)
|
||||
, (name "bar", addr 1) ]
|
||||
|
||||
it "evaluates namespaces" $ do
|
||||
res <- evaluate "namespaces.php"
|
||||
findEnv res `shouldBe` [ (name "NS1", addr 0)
|
||||
, (name "Foo", addr 6) ]
|
||||
|
||||
let heap = findHeap res
|
||||
Map.lookup (Precise 0) heap `shouldBe` ns "NS1" [ (name "Sub1", addr 1)
|
||||
, (name "b", addr 4)
|
||||
, (name "c", addr 5)
|
||||
]
|
||||
Map.lookup (Precise 1) heap `shouldBe` ns "Sub1" [ (name "Sub2", addr 2) ]
|
||||
Map.lookup (Precise 2) heap `shouldBe` ns "Sub2" [ (name "f", addr 3) ]
|
||||
|
||||
where
|
||||
ns n = Just . Latest . Just . injValue . Namespace (name n)
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/php/analysis/"
|
||||
evaluate entry = evaluateFiles phpParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "foo.php"
|
||||
, fixtures <> "bar.php"
|
||||
]
|
@ -11,34 +11,35 @@ spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "evalutes Python" $ do
|
||||
it "imports" $ do
|
||||
env <- evaluate "main.py"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["a", "foo"], addr 0)
|
||||
, (qualifiedName ["b", "c", "baz"], addr 1)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main.py"
|
||||
env `shouldBe` [ (qualifiedName ["a", "foo"], addr 0)
|
||||
, (qualifiedName ["b", "c", "baz"], addr 1)
|
||||
]
|
||||
|
||||
it "imports with aliases" $ do
|
||||
env <- evaluate "main1.py"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["b", "foo"], addr 0)
|
||||
, (qualifiedName ["e", "baz"], addr 1)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main1.py"
|
||||
env `shouldBe` [ (qualifiedName ["b", "foo"], addr 0)
|
||||
, (qualifiedName ["e", "baz"], addr 1)
|
||||
]
|
||||
|
||||
it "imports using 'from' syntax" $ do
|
||||
env <- evaluate "main2.py"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["foo"], addr 0)
|
||||
, (qualifiedName ["bar"], addr 1)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main2.py"
|
||||
env `shouldBe` [ (qualifiedName ["foo"], addr 0)
|
||||
, (qualifiedName ["bar"], addr 1)
|
||||
]
|
||||
|
||||
it "subclasses" $ do
|
||||
v <- findValue <$> evaluate "subclass.py"
|
||||
v `shouldBe` Right (Right (injValue (String "\"bar\"")))
|
||||
|
||||
it "handles multiple inheritance left-to-right" $ do
|
||||
v <- findValue <$> evaluate "multiple_inheritance.py"
|
||||
v `shouldBe` Right (Right (injValue (String "\"foo!\"")))
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/python/analysis/"
|
||||
evaluate entry = snd . fst . fst . fst . fst <$>
|
||||
evaluateFiles pythonParser
|
||||
evaluate entry = evaluateFiles pythonParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "a.py"
|
||||
, fixtures <> "b/c.py"
|
||||
|
@ -12,26 +12,26 @@ spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "evalutes Ruby" $ do
|
||||
it "require_relative" $ do
|
||||
env <- evaluate "main.rb"
|
||||
let expectedEnv = [ (qualifiedName ["foo"], addr 0) ]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main.rb"
|
||||
env `shouldBe` [ (qualifiedName ["foo"], addr 0) ]
|
||||
|
||||
it "load" $ do
|
||||
env <- evaluate "load.rb"
|
||||
let expectedEnv = [ (qualifiedName ["foo"], addr 0) ]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "load.rb"
|
||||
env `shouldBe` [ (qualifiedName ["foo"], addr 0) ]
|
||||
|
||||
it "load wrap" $ do
|
||||
res <- evaluate' "load-wrap.rb"
|
||||
fst res `shouldBe` Left "free variable: \"foo\""
|
||||
snd res `shouldBe` []
|
||||
res <- evaluate "load-wrap.rb"
|
||||
findValue res `shouldBe` Left "free variable: \"foo\""
|
||||
findEnv res `shouldBe` []
|
||||
|
||||
it "subclass" $ do
|
||||
v <- findValue <$> evaluate "subclass.rb"
|
||||
v `shouldBe` Right (Right (injValue (String "\"<bar>\"")))
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/ruby/analysis/"
|
||||
evaluate entry = snd <$> evaluate' entry
|
||||
evaluate' entry = fst . fst . fst . fst <$>
|
||||
evaluateFiles rubyParser
|
||||
evaluate entry = evaluateFiles rubyParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "foo.rb"
|
||||
]
|
||||
|
@ -11,38 +11,31 @@ spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "evalutes TypeScript" $ do
|
||||
it "imports with aliased symbols" $ do
|
||||
env <- evaluate "main.ts"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["bar"], addr 0)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main.ts"
|
||||
env `shouldBe` [ (qualifiedName ["bar"], addr 0) ]
|
||||
|
||||
it "imports with qualified names" $ do
|
||||
env <- evaluate "main1.ts"
|
||||
let expectedEnv =
|
||||
[ (qualifiedName ["b", "baz"], addr 0)
|
||||
, (qualifiedName ["b", "foo"], addr 2)
|
||||
, (qualifiedName ["z", "baz"], addr 0)
|
||||
, (qualifiedName ["z", "foo"], addr 2)
|
||||
]
|
||||
env `shouldBe` expectedEnv
|
||||
env <- findEnv <$> evaluate "main1.ts"
|
||||
env `shouldBe` [ (qualifiedName ["b", "baz"], addr 0)
|
||||
, (qualifiedName ["b", "foo"], addr 2)
|
||||
, (qualifiedName ["z", "baz"], addr 0)
|
||||
, (qualifiedName ["z", "foo"], addr 2)
|
||||
]
|
||||
|
||||
it "side effect only imports" $ do
|
||||
env <- evaluate "main2.ts"
|
||||
env <- findEnv <$> evaluate "main2.ts"
|
||||
env `shouldBe` mempty
|
||||
|
||||
it "fails exporting symbols not defined in the module" $ do
|
||||
env <- fst <$> evaluate' "bad-export.ts"
|
||||
env `shouldBe` Left "module \"foo\" does not export \"pip\""
|
||||
v <- findValue <$> evaluate "bad-export.ts"
|
||||
v `shouldBe` Left "module \"foo\" does not export \"pip\""
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/typescript/analysis/"
|
||||
evaluate entry = snd <$> evaluate' entry
|
||||
evaluate' entry = fst . fst . fst . fst <$>
|
||||
evaluateFiles typescriptParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "a.ts"
|
||||
, fixtures <> "foo.ts"
|
||||
, fixtures <> "pip.ts"
|
||||
]
|
||||
evaluate entry = evaluateFiles typescriptParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "a.ts"
|
||||
, fixtures <> "foo.ts"
|
||||
, fixtures <> "pip.ts"
|
||||
]
|
||||
|
@ -156,7 +156,7 @@ instance Listable1 f => Listable2 (FreeF f) where
|
||||
instance (Listable1 f, Listable a) => Listable1 (FreeF f a) where
|
||||
liftTiers = liftTiers2 tiers
|
||||
|
||||
instance (Functor f, Listable1 f) => Listable1 (Free.Free f) where
|
||||
instance Listable1 f => Listable1 (Free.Free f) where
|
||||
liftTiers pureTiers = go
|
||||
where go = liftCons1 (liftTiers2 pureTiers go) free
|
||||
free (FreeF.Free f) = Free.Free f
|
||||
|
@ -12,13 +12,16 @@ main = do
|
||||
|
||||
extensions :: [String]
|
||||
extensions =
|
||||
[ "DeriveFoldable"
|
||||
[ "DataKinds"
|
||||
, "DeriveFoldable"
|
||||
, "DeriveFunctor"
|
||||
, "DeriveGeneric"
|
||||
, "DeriveTraversable"
|
||||
, "FlexibleContexts"
|
||||
, "FlexibleInstances"
|
||||
, "MultiParamTypeClasses"
|
||||
, "OverloadedStrings"
|
||||
, "RecordWildCards"
|
||||
, "StandaloneDeriving"
|
||||
, "StrictData"
|
||||
]
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Main where
|
||||
|
||||
import qualified Analysis.Go.Spec
|
||||
import qualified Analysis.PHP.Spec
|
||||
import qualified Analysis.Python.Spec
|
||||
import qualified Analysis.Ruby.Spec
|
||||
import qualified Analysis.TypeScript.Spec
|
||||
@ -27,6 +28,7 @@ main = hspec $ do
|
||||
describe "Semantic.Stat" Semantic.Stat.Spec.spec
|
||||
parallel $ do
|
||||
describe "Analysis.Go" Analysis.Go.Spec.spec
|
||||
describe "Analysis.PHP" Analysis.PHP.Spec.spec
|
||||
describe "Analysis.Python" Analysis.Python.Spec.spec
|
||||
describe "Analysis.Ruby" Analysis.Ruby.Spec.spec
|
||||
describe "Analysis.TypeScript" Analysis.TypeScript.Spec.spec
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE DataKinds, GADTs, ScopedTypeVariables, TypeFamilies, TypeOperators, TypeApplications #-}
|
||||
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeFamilies, TypeOperators, TypeApplications #-}
|
||||
module SpecHelpers (
|
||||
module X
|
||||
, diffFilePaths
|
||||
@ -9,6 +9,7 @@ module SpecHelpers (
|
||||
, Verbatim(..)
|
||||
, ) where
|
||||
|
||||
import Analysis.Abstract.Evaluating as X (findValue, findEnv, findHeap)
|
||||
import Data.Abstract.Address as X
|
||||
import Data.Abstract.FreeVariables as X hiding (dropExtension)
|
||||
import Data.Abstract.Heap as X
|
||||
@ -34,6 +35,7 @@ import Data.Functor.Both as X (Both, runBothWith, both)
|
||||
import Data.Maybe as X
|
||||
import Data.Monoid as X (Monoid(..), First(..), Last(..))
|
||||
import Data.Semigroup as X (Semigroup(..))
|
||||
import Control.Monad as X
|
||||
|
||||
import Test.Hspec as X (Spec, SpecWith, context, describe, it, xit, parallel, pendingWith, around, runIO)
|
||||
import Test.Hspec.Expectations.Pretty as X
|
||||
@ -43,6 +45,7 @@ import Test.LeanCheck as X
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Semantic.IO as IO
|
||||
|
||||
|
||||
-- | Returns an s-expression formatted diff for the specified FilePath pair.
|
||||
diffFilePaths :: Both FilePath -> IO ByteString
|
||||
diffFilePaths paths = readFilePair paths >>= runTask . diffBlobPair SExpressionDiffRenderer
|
||||
|
4
test/fixtures/php/analysis/bar.php
vendored
Normal file
4
test/fixtures/php/analysis/bar.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
function bar() {
|
||||
return 1;
|
||||
}
|
4
test/fixtures/php/analysis/foo.php
vendored
Normal file
4
test/fixtures/php/analysis/foo.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
function foo() {
|
||||
return 1;
|
||||
}
|
6
test/fixtures/php/analysis/main.php
vendored
Normal file
6
test/fixtures/php/analysis/main.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
include 'foo.php';
|
||||
require 'bar.php';
|
||||
|
||||
foo();
|
||||
bar();
|
6
test/fixtures/php/analysis/main_once.php
vendored
Normal file
6
test/fixtures/php/analysis/main_once.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
include_once 'foo.php';
|
||||
require_once 'bar.php';
|
||||
|
||||
foo();
|
||||
bar();
|
28
test/fixtures/php/analysis/namespaces.php
vendored
Normal file
28
test/fixtures/php/analysis/namespaces.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace NS1\Sub1\Sub2
|
||||
{
|
||||
function f() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace NS1
|
||||
{
|
||||
function b() {
|
||||
return "hi";
|
||||
}
|
||||
}
|
||||
namespace NS1
|
||||
{
|
||||
function c() {
|
||||
return "x";
|
||||
}
|
||||
}
|
||||
|
||||
namespace Foo
|
||||
{
|
||||
\NS1\Sub1\Sub2\f();
|
||||
\NS1\b();
|
||||
\NS1\c();
|
||||
}
|
12
test/fixtures/python/analysis/multiple_inheritance.py
vendored
Normal file
12
test/fixtures/python/analysis/multiple_inheritance.py
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
class Foo:
|
||||
def dang(self):
|
||||
return "foo!"
|
||||
|
||||
class Bar:
|
||||
def dang(self):
|
||||
return "bar!"
|
||||
|
||||
|
||||
class Baz(Foo, Bar): pass
|
||||
|
||||
Baz.dang()
|
9
test/fixtures/python/analysis/subclass.py
vendored
Normal file
9
test/fixtures/python/analysis/subclass.py
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
class Foo():
|
||||
def dang():
|
||||
return "foo"
|
||||
|
||||
class Bar():
|
||||
def dang():
|
||||
return "bar"
|
||||
|
||||
Bar.dang()
|
4
test/fixtures/python/call.diffA-B.txt
vendored
4
test/fixtures/python/call.diffA-B.txt
vendored
@ -14,6 +14,8 @@
|
||||
{+(Identifier)+}
|
||||
(Empty))
|
||||
{+(Call
|
||||
{+(Identifier)+}
|
||||
{+(MemberAccess
|
||||
{+(Identifier)+}
|
||||
{+(Identifier)+})+}
|
||||
{+(Integer)+}
|
||||
{+(Empty)+})+})
|
||||
|
4
test/fixtures/python/call.diffB-A.txt
vendored
4
test/fixtures/python/call.diffB-A.txt
vendored
@ -14,6 +14,8 @@
|
||||
{+(Identifier)+}
|
||||
(Empty))
|
||||
{-(Call
|
||||
{-(Identifier)-}
|
||||
{-(MemberAccess
|
||||
{-(Identifier)-}
|
||||
{-(Identifier)-})-}
|
||||
{-(Integer)-}
|
||||
{-(Empty)-})-})
|
||||
|
4
test/fixtures/python/call.parseB.txt
vendored
4
test/fixtures/python/call.parseB.txt
vendored
@ -12,6 +12,8 @@
|
||||
(Identifier)
|
||||
(Empty))
|
||||
(Call
|
||||
(Identifier)
|
||||
(MemberAccess
|
||||
(Identifier)
|
||||
(Identifier))
|
||||
(Integer)
|
||||
(Empty)))
|
||||
|
24
test/fixtures/python/import-graph/main.json
vendored
24
test/fixtures/python/import-graph/main.json
vendored
@ -269,8 +269,10 @@
|
||||
22
|
||||
]
|
||||
},
|
||||
"symbol": "os.getcwd",
|
||||
"targets": []
|
||||
"symbol": "getcwd",
|
||||
"targets": [
|
||||
"os"
|
||||
]
|
||||
},
|
||||
{
|
||||
"span": {
|
||||
@ -283,8 +285,10 @@
|
||||
31
|
||||
]
|
||||
},
|
||||
"symbol": "np.array",
|
||||
"targets": []
|
||||
"symbol": "array",
|
||||
"targets": [
|
||||
"np"
|
||||
]
|
||||
},
|
||||
{
|
||||
"span": {
|
||||
@ -297,8 +301,10 @@
|
||||
20
|
||||
]
|
||||
},
|
||||
"symbol": "x.sum",
|
||||
"targets": []
|
||||
"symbol": "sum",
|
||||
"targets": [
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"span": {
|
||||
@ -311,8 +317,10 @@
|
||||
19
|
||||
]
|
||||
},
|
||||
"symbol": "x.sum",
|
||||
"targets": []
|
||||
"symbol": "sum",
|
||||
"targets": [
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"span": {
|
||||
|
8
test/fixtures/python/with.diffA-B.txt
vendored
8
test/fixtures/python/with.diffA-B.txt
vendored
@ -25,7 +25,9 @@
|
||||
{+(Let
|
||||
{+(Empty)+}
|
||||
{+(Call
|
||||
{+(Identifier)+}
|
||||
{+(MemberAccess
|
||||
{+(Identifier)+}
|
||||
{+(Identifier)+})+}
|
||||
{+(Identifier)+}
|
||||
{+(TextElement)+}
|
||||
{+(Identifier)+}
|
||||
@ -34,7 +36,9 @@
|
||||
{+(Let
|
||||
{+(Empty)+}
|
||||
{+(Call
|
||||
{+(Identifier)+}
|
||||
{+(MemberAccess
|
||||
{+(Identifier)+}
|
||||
{+(Identifier)+})+}
|
||||
{+(Identifier)+}
|
||||
{+(TextElement)+}
|
||||
{+(Identifier)+}
|
||||
|
8
test/fixtures/python/with.diffB-A.txt
vendored
8
test/fixtures/python/with.diffB-A.txt
vendored
@ -25,7 +25,9 @@
|
||||
{-(Let
|
||||
{-(Empty)-}
|
||||
{-(Call
|
||||
{-(Identifier)-}
|
||||
{-(MemberAccess
|
||||
{-(Identifier)-}
|
||||
{-(Identifier)-})-}
|
||||
{-(Identifier)-}
|
||||
{-(TextElement)-}
|
||||
{-(Identifier)-}
|
||||
@ -34,7 +36,9 @@
|
||||
{-(Let
|
||||
{-(Empty)-}
|
||||
{-(Call
|
||||
{-(Identifier)-}
|
||||
{-(MemberAccess
|
||||
{-(Identifier)-}
|
||||
{-(Identifier)-})-}
|
||||
{-(Identifier)-}
|
||||
{-(TextElement)-}
|
||||
{-(Identifier)-}
|
||||
|
8
test/fixtures/python/with.parseB.txt
vendored
8
test/fixtures/python/with.parseB.txt
vendored
@ -12,7 +12,9 @@
|
||||
(Let
|
||||
(Empty)
|
||||
(Call
|
||||
(Identifier)
|
||||
(MemberAccess
|
||||
(Identifier)
|
||||
(Identifier))
|
||||
(Identifier)
|
||||
(TextElement)
|
||||
(Identifier)
|
||||
@ -21,7 +23,9 @@
|
||||
(Let
|
||||
(Empty)
|
||||
(Call
|
||||
(Identifier)
|
||||
(MemberAccess
|
||||
(Identifier)
|
||||
(Identifier))
|
||||
(Identifier)
|
||||
(TextElement)
|
||||
(Identifier)
|
||||
|
13
test/fixtures/ruby/analysis/subclass.rb
vendored
Normal file
13
test/fixtures/ruby/analysis/subclass.rb
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
class Foo
|
||||
def inspect
|
||||
"<foo>"
|
||||
end
|
||||
end
|
||||
|
||||
class Bar < Foo
|
||||
def inspect
|
||||
"<bar>"
|
||||
end
|
||||
end
|
||||
|
||||
Bar.inspect()
|
2
vendor/effects
vendored
2
vendor/effects
vendored
@ -1 +1 @@
|
||||
Subproject commit 6aaaa39f18f38628a91d3ffd155c7f4099131d9e
|
||||
Subproject commit 7d4525db7b6a12c0a34da5f70a97db137c144c60
|
1
vendor/ghc-mod
vendored
1
vendor/ghc-mod
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 7fb380dae0ae877a24ac8258fcd193cd6256a171
|
Loading…
Reference in New Issue
Block a user