{-# LANGUAGE DeriveAnyClass, DerivingVia, DuplicateRecordFields, TupleSections #-} {-# OPTIONS_GHC -Wno-missing-export-lists #-} module Language.TypeScript.Syntax.TypeScript where import Prologue import Control.Abstract hiding (Import) import Data.Abstract.Evaluatable as Evaluatable import Data.Abstract.ScopeGraph (AccessControl (..)) import Data.JSON.Fields import qualified Data.Map.Strict as Map import Data.Semigroup.App import Data.Semigroup.Foldable import qualified Data.Text as T import Diffing.Algorithm import qualified Data.Abstract.ScopeGraph as ScopeGraph -- | ShorthandPropertyIdentifier used in object patterns such as var baz = { foo } to mean var baz = { foo: foo } newtype ShorthandPropertyIdentifier a = ShorthandPropertyIdentifier { contents :: T.Text } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ShorthandPropertyIdentifier instance Evaluatable ShorthandPropertyIdentifier data Union a = Union { unionLeft :: !a, unionRight :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Union instance Evaluatable Language.TypeScript.Syntax.TypeScript.Union data Intersection a = Intersection { intersectionLeft :: !a, intersectionRight :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Intersection instance Evaluatable Intersection data AmbientFunction a = AmbientFunction { ambientFunctionContext :: ![a], ambientFunctionIdentifier :: !a, ambientFunctionParameters :: ![a] } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically AmbientFunction instance Evaluatable AmbientFunction newtype Tuple a = Tuple { tupleElements :: [a] } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Tuple -- This is a tuple type, not a tuple value, so we can't lean on the shared Tuple value instance Evaluatable Tuple data Constructor a = Constructor { constructorTypeParameters :: !a, constructorFormalParameters :: ![a], constructorType :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Constructor instance Evaluatable Language.TypeScript.Syntax.TypeScript.Constructor newtype Annotation a = Annotation { annotationType :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Annotation instance Evaluatable Annotation newtype Decorator a = Decorator { decoratorTerm :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Decorator instance Evaluatable Decorator newtype ComputedPropertyName a = ComputedPropertyName { propertyName :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ComputedPropertyName instance Evaluatable ComputedPropertyName newtype Constraint a = Constraint { constraintType :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Constraint instance Evaluatable Constraint data NestedIdentifier a = NestedIdentifier { left :: !a, right :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically NestedIdentifier instance Evaluatable NestedIdentifier newtype AmbientDeclaration a = AmbientDeclaration { ambientDeclarationBody :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically AmbientDeclaration instance Evaluatable AmbientDeclaration where eval eval _ (AmbientDeclaration body) = eval body data EnumDeclaration a = EnumDeclaration { enumDeclarationIdentifier :: !a, enumDeclarationBody :: ![a] } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically EnumDeclaration instance Evaluatable EnumDeclaration instance Declarations a => Declarations (EnumDeclaration a) where declaredName EnumDeclaration{..} = declaredName enumDeclarationIdentifier newtype ExtendsClause a = ExtendsClause { extendsClauses :: [a] } deriving (Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ExtendsClause instance Declarations1 ExtendsClause where liftDeclaredName _ (ExtendsClause []) = Nothing liftDeclaredName declaredName (ExtendsClause (x : _)) = declaredName x -- TODO: ExtendsClause shouldn't evaluate to an address in the heap? instance Evaluatable ExtendsClause where eval eval _ ExtendsClause{..} = do -- Evaluate subterms traverse_ eval extendsClauses unit data PropertySignature a = PropertySignature { modifiers :: [a], propertySignaturePropertyName :: a, propertySignatureAccessControl :: AccessControl } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically PropertySignature instance Evaluatable PropertySignature data CallSignature a = CallSignature { callSignatureTypeParameters :: !a, callSignatureParameters :: ![a], callSignatureType :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically CallSignature instance Evaluatable CallSignature -- | Todo: Move type params and type to context data ConstructSignature a = ConstructSignature { constructSignatureTypeParameters :: !a, constructSignatureParameters :: ![a], constructSignatureType :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ConstructSignature instance Evaluatable ConstructSignature data IndexSignature a = IndexSignature { subject :: a, subjectType :: a, typeAnnotation :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically IndexSignature instance Evaluatable IndexSignature data AbstractMethodSignature a = AbstractMethodSignature { abstractMethodSignatureContext :: ![a], abstractMethodSignatureName :: a, abstractMethodSignatureParameters :: [a], abstractMethodAccessControl :: AccessControl } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically AbstractMethodSignature instance Evaluatable AbstractMethodSignature data ForOf a = ForOf { forOfBinding :: !a, forOfSubject :: !a, forOfBody :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ForOf instance Evaluatable ForOf data LabeledStatement a = LabeledStatement { labeledStatementIdentifier :: !a, labeledStatementSubject :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically LabeledStatement instance Evaluatable LabeledStatement newtype Update a = Update { updateSubject :: a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Update instance Evaluatable Update data Module a = Module { moduleIdentifier :: !a, moduleStatements :: ![a] } deriving (Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically Module declareModule :: ( AbstractValue term address value m , Carrier sig m , Declarations term , Member (Allocator address) sig , Member (Deref value) sig , Member (Object address value) sig , Member (Reader (CurrentFrame address)) sig , Member (Reader (CurrentScope address)) sig , Member (Reader Span) sig , Member (Resumable (BaseError (EvalError term address value))) sig , Member (State (Heap address address value)) sig , Member (State (ScopeGraph address)) sig , Member Fresh sig , Member (Reader ModuleInfo) sig , Member (Resumable (BaseError (AddressError address value))) sig , Member (Resumable (BaseError (HeapError address))) sig , Member (Resumable (BaseError (ScopeError address))) sig , Member (Unit value) sig , Ord address ) => (term -> Evaluator term address value m value) -> term -> [term] -> Evaluator term address value m value declareModule eval identifier statements = do (name, relation) <- case declaredName identifier of Just name -> pure (name, Default) _ -> gensym >>= \name -> pure (name, Gensym) span <- ask @Span currentScope' <- currentScope let declaration = Declaration name moduleBody = maybe unit (runApp . foldMap1 (App . eval)) (nonEmpty statements) maybeSlot <- maybeLookupDeclaration declaration case maybeSlot of Just slot -> do moduleVal <- deref slot maybeFrame <- scopedEnvironment moduleVal case maybeFrame of Just moduleFrame -> do withScopeAndFrame moduleFrame moduleBody Nothing -> throwEvalError (DerefError moduleVal) Nothing -> do let edges = Map.singleton Lexical [ currentScope' ] childScope <- newScope edges declare (Declaration name) relation Public span ScopeGraph.Module (Just childScope) currentFrame' <- currentFrame let frameEdges = Map.singleton Lexical (Map.singleton currentScope' currentFrame') childFrame <- newFrame childScope frameEdges withScopeAndFrame childFrame (void moduleBody) moduleSlot <- lookupSlot (Declaration name) assign moduleSlot =<< namespace name childFrame unit instance Evaluatable Module where eval eval _ Module{..} = declareModule eval moduleIdentifier moduleStatements instance Declarations1 Module where liftDeclaredName declaredName = declaredName . moduleIdentifier data InternalModule a = InternalModule { internalModuleIdentifier :: !a, internalModuleStatements :: ![a] } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically InternalModule instance Evaluatable InternalModule where eval eval _ InternalModule{..} = declareModule eval internalModuleIdentifier internalModuleStatements instance Declarations a => Declarations (InternalModule a) where declaredName InternalModule{..} = declaredName internalModuleIdentifier data ClassHeritage a = ClassHeritage { classHeritageExtendsClause :: !a, implementsClause :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically ClassHeritage instance Evaluatable ClassHeritage data AbstractClass a = AbstractClass { abstractClassIdentifier :: !a, abstractClassTypeParameters :: !a, classHeritage :: ![a], classBody :: !a } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, NFData1, Ord, Show, ToJSONFields1, Traversable) deriving (Eq1, Show1, Ord1) via Generically AbstractClass instance Declarations a => Declarations (AbstractClass a) where declaredName AbstractClass{..} = declaredName abstractClassIdentifier instance Evaluatable AbstractClass where eval eval _ AbstractClass{..} = do span <- ask @Span currentScope' <- currentScope superScopes <- for classHeritage $ \superclass -> do name <- maybeM (throwNoNameError superclass) (declaredName superclass) scope <- associatedScope (Declaration name) slot <- lookupSlot (Declaration name) superclassFrame <- scopedEnvironment =<< deref slot pure $ case (scope, superclassFrame) of (Just scope, Just frame) -> Just (scope, frame) _ -> Nothing let superclassEdges = (Superclass, ) . pure . fst <$> catMaybes superScopes current = (Lexical, ) <$> pure (pure currentScope') edges = Map.fromList (superclassEdges <> current) classScope <- newScope edges name <- declareMaybeName (declaredName abstractClassIdentifier) Default Public span ScopeGraph.AbstractClass (Just classScope) let frameEdges = Map.singleton Superclass (Map.fromList (catMaybes superScopes)) childFrame <- newFrame classScope frameEdges withScopeAndFrame childFrame $ do void $ eval classBody classSlot <- lookupSlot (Declaration name) assign classSlot =<< klass (Declaration name) childFrame unit data MetaProperty a = MetaProperty deriving (Diffable, Eq, Foldable, Functor, Generic1, Ord, Show, Traversable, FreeVariables1, Declarations1, ToJSONFields1, Hashable1, NFData1) deriving (Eq1, Show1, Ord1) via Generically MetaProperty instance Evaluatable MetaProperty