language-ecmascript-analysis (empty) → 0.9
raw patch · 6 files changed
+339/−0 lines, 6 filesdep +HUnitdep +basedep +containerssetup-changed
Dependencies added: HUnit, base, containers, language-ecmascript, mtl, parsec, test-framework, test-framework-hunit, uniplate
Files
- LICENSE +28/−0
- Setup.hs +2/−0
- language-ecmascript-analysis.cabal +61/−0
- src/Language/ECMAScript3/Analysis/LabelSet.hs +88/−0
- src/Language/ECMAScript3/Analysis/LexicalEnvironment.hs +157/−0
- test/TestMain.hs +3/−0
+ LICENSE view
@@ -0,0 +1,28 @@+Copyright (c) 2007--2012, Brown University, 2008-2012 Claudiu Saftoiu,+2012 Stevens Institute of Technology.+All Rights Reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution.+ * Neither the name of Brown University, Stevens Institute of Technology+ nor the names of its contributors may be used to endorse or promote+ products derived from this software without specific prior written + permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ language-ecmascript-analysis.cabal view
@@ -0,0 +1,61 @@+-- Initial language-ecmascript-analysis.cabal generated by cabal init. For+-- further documentation, see http://haskell.org/cabal/users-guide/++name: language-ecmascript-analysis+version: 0.9+cabal-version: >= 1.10+copyright: (c) 2007-2012 Brown University, (c) 2008-2010 Claudiu Saftoiu,+ (c) 2012-2013 Stevens Institute of Technology+synopsis: JavaScript analysis library+description: Includes a label set analysis and a lexical environment analysis+license: BSD3+license-file: LICENSE+author: Andrey Chudnov, Arjun Guha, Spiridon Aristides Eliopoulos,+ Joe Gibbs Politz, Claudiu Saftoiu+maintainer: Andrey Chudnov <oss@chudnov.com>+homepage: http://github.com/jswebtools/language-ecmascript-analysis+bug-reports: http://github.com/jswebtools/language-ecmascript-analysis/issues+category: Language+build-type: Simple+stability: experimental+Tested-with: GHC==7.6.3++source-repository head+ type: git+ location: git://github.com/jswebtools/language-ecmascript-analysis.git++source-repository this+ type: git+ location: git://github.com/jswebtools/language-ecmascript-analysis.git+ tag: 0.9++Library+ Build-Depends: base >= 4 && < 5+ , language-ecmascript >= 0.15 && < 1.0+ , uniplate >= 1.6 && < 1.7+ , parsec >= 3 && < 4+ , containers >= 0.1 && < 0.6+ hs-source-dirs: + src+ exposed-modules: + Language.ECMAScript3.Analysis.LexicalEnvironment+ Language.ECMAScript3.Analysis.LabelSet+ Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts+ ghc-options: + -fwarn-incomplete-patterns+ default-language: Haskell2010 ++Test-Suite test+ hs-source-dirs: test+ Type: exitcode-stdio-1.0+ Main-Is: TestMain.hs+ Build-Depends: base >= 4 && < 5,+ uniplate >= 1.6 && <1.7,+ language-ecmascript >= 0.15 && < 1.0,+ HUnit,+ test-framework >= 0.8 && < 0.9,+ test-framework-hunit >= 0.3.0 && < 0.4,+ mtl+ Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts+ Default-Language: Haskell2010+ ghc-options: -fwarn-incomplete-patterns
+ src/Language/ECMAScript3/Analysis/LabelSet.hs view
@@ -0,0 +1,88 @@+-- | Label-set analysis which annotates all the statements in the script+-- with their label sets according to ECMAScript specification,+-- section 12.12. The result of this analysis are useful for building+-- control-flow graphs.++module Language.ECMAScript3.Analysis.LabelSet (annotateLabelSets + ,Label(..)) where++import Language.ECMAScript3.Syntax+import Language.ECMAScript3.Syntax.Annotations+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Generics.Uniplate.Data+import Data.Data (Data)+import Control.Applicative+import Data.Typeable (Typeable)++-- | Labels are either strings (identifiers) or /empty/ (see 12.12 of+-- the spec)+data Label = Label String+ | EmptyLabel+ deriving (Ord, Eq, Show, Data, Typeable)++-- | Annotates statements with their label sets; example use:+--+-- >>> let jsa = reannotate (\a -> (a, Set.empty))+-- >>> in annotateLabelSets jsa snd (\labs (a, ls) -> (a, labs `Set.union` ls))+annotateLabelSets :: Data a =>+ (a -> Set Label) -- ^ annotation read function+ -> (Set Label -> a -> a) -- ^ annotation write function+ -> JavaScript a -- ^ the script to annotate+ -> JavaScript a+annotateLabelSets r w = transformBi (annotateFuncStmtBodies r w)+ . transformBi (annotateFuncExprBodies r w)+ . descendBi (annotateStatement r w)++annotateFuncStmtBodies :: Data a => + (a -> Set Label)+ -> (Set Label -> a -> a) + -> Statement a+ -> Statement a+annotateFuncStmtBodies r w s = case s of+ FunctionStmt a name params body -> + let newbody = map (descend (annotateStatement r w)) body+ in FunctionStmt a name params newbody+ _ -> s+ +annotateFuncExprBodies :: Data a => + (a -> Set Label)+ -> (Set Label -> a -> a) + -> Expression a + -> Expression a+annotateFuncExprBodies r w e = case e of+ FuncExpr a mname params body -> + let newbody = map (descend (annotateStatement r w)) body+ in FuncExpr a mname params newbody+ _ -> e++-- | 12.12 ECMA262: the production /Identifier/ : /Statement/ is+-- evaluated by adding /Identifier/ to the label ser of /Statement/+-- and then evluating /Statement/. If the /LabelledStatement/ itsef+-- has a non-empty label set, these labels are also added to the label+-- set of /Statement/ before evaluating it. ... Prior to evaluation of+-- a /LabelledStatement/, the contained /Statement/ is regarded as+-- possessing an empty label set, unless it is an /IterationStatement/+-- or a /SwitchStatement/, in which case it is regarded as possessing+-- a label set consisting of the single element, @empty@.+annotateStatement :: Data a => + (a -> Set Label)+ -> (Set Label -> a -> a)+ -> Statement a + -> Statement a+annotateStatement r w s = case s of+ LabelledStmt ann lab stmt -> + let labelset = Set.insert (id2Label lab) (r ann) + newstmt = annotateStatement r w $ w labelset <$> stmt+ in LabelledStmt ann lab newstmt+ SwitchStmt {} -> + let labelset = Set.insert EmptyLabel (r $ getAnnotation s)+ in descend (annotateStatement r w) (w labelset <$> s)+ _ | isIterationStmt s ->+ let labelset = Set.insert EmptyLabel (r $ getAnnotation s)+ in descend (annotateStatement r w) (w labelset <$> s)+ _ -> descend (annotateStatement r w) s++id2Label :: Id a -> Label+id2Label = Label . unId+
+ src/Language/ECMAScript3/Analysis/LexicalEnvironment.hs view
@@ -0,0 +1,157 @@+-- | A lexical environment analysis of ECMAScript programs++module Language.ECMAScript3.Analysis.LexicalEnvironment+ ( env+ , localVars+ , EnvTree (..)+ ) where++import Data.List+import Data.Maybe+import qualified Data.Map as M+import Data.Map (Map)+import qualified Data.Set as S+import Data.Set (Set)+import Text.ParserCombinators.Parsec.Pos (SourcePos)++import Language.ECMAScript3.Syntax++-- | Intermediate data structure that contains locally declared names and+-- all references to identifers.+data Partial = Partial {+ partialLocals :: M.Map String SourcePos,+ partialReferences :: M.Map String SourcePos,+ partialNested :: [Partial]+}++empty :: Partial+empty = Partial M.empty M.empty []++ref :: Id SourcePos -> Partial+ref (Id p v) = Partial M.empty (M.singleton v p) []++decl :: Id SourcePos -> Partial+decl (Id p v) = Partial (M.singleton v p) M.empty []++nest :: Partial -> Partial+nest partial = Partial M.empty M.empty [partial]++-- Combine partial results from the same lexical scope.+unions :: [Partial] -> Partial+unions ps = Partial (M.unions (map partialLocals ps))+ (M.unions (map partialReferences ps))+ (concatMap partialNested ps)++javascript :: JavaScript SourcePos -> Partial+javascript (Script _ ss) = unions (map stmt ss)+++lvalue :: LValue SourcePos -> Partial+lvalue lv = case lv of+ LVar p x -> ref (Id p x)+ LDot _ e _ -> expr e+ LBracket _ e1 e2 -> unions [expr e1, expr e2]++expr :: Expression SourcePos -> Partial+expr e = case e of+ StringLit _ _ -> empty+ RegexpLit {} -> empty+ NumLit _ _ -> empty+ IntLit _ _ -> empty+ BoolLit _ _ -> empty+ NullLit _ -> empty+ ArrayLit _ es -> unions (map expr es)+ ObjectLit _ props -> unions (map (expr.snd) props)+ ThisRef _ -> empty+ VarRef _ id -> empty+ DotRef _ e _ -> expr e+ BracketRef _ e1 e2 -> unions [expr e1, expr e2]+ NewExpr _ e1 es -> unions [expr e1, unions $ map expr es]+ PrefixExpr _ _ e -> expr e+ InfixExpr _ _ e1 e2 -> unions [expr e1, expr e2]+ CondExpr _ e1 e2 e3 -> unions [expr e1, expr e2, expr e3]+ AssignExpr _ _ lv e -> unions [lvalue lv, expr e]+ UnaryAssignExpr _ _ lv -> lvalue lv+ ListExpr _ es -> unions (map expr es)+ CallExpr _ e es -> unions [expr e, unions $ map expr es]+ FuncExpr _ _ args ss -> nest $ unions [unions $ map decl args+ ,unions $ map stmt ss]++caseClause :: CaseClause SourcePos -> Partial+caseClause cc = case cc of+ CaseClause _ e ss -> unions [expr e, unions $ map stmt ss]+ CaseDefault _ ss -> unions $ map stmt ss++-- TODO: Verify that this is a declaration and not a reference.+catchClause :: CatchClause SourcePos -> Partial+catchClause (CatchClause _ id s) = unions [decl id, stmt s]++varDecl :: VarDecl SourcePos -> Partial+varDecl (VarDecl _ id Nothing) = decl id+varDecl (VarDecl _ id (Just e)) = unions [decl id, expr e]+ +forInit :: ForInit SourcePos -> Partial+forInit fi = case fi of+ NoInit -> empty+ VarInit ds -> unions $ map varDecl ds+ ExprInit e -> expr e ++forInInit :: ForInInit SourcePos -> Partial+forInInit (ForInVar id) = decl id+forInInit (ForInLVal lv) = lvalue lv+ +stmt :: Statement SourcePos -> Partial+stmt s = case s of+ BlockStmt _ ss -> unions $ map stmt ss+ EmptyStmt _ -> empty+ ExprStmt _ e -> expr e+ IfStmt _ e s1 s2 -> unions [expr e, stmt s1, stmt s2]+ IfSingleStmt _ e s -> unions [expr e, stmt s]+ SwitchStmt _ e cases -> unions [expr e, unions $ map caseClause cases]+ WhileStmt _ e s -> unions [expr e, stmt s]+ DoWhileStmt _ s e -> unions [stmt s, expr e]+ BreakStmt _ _ -> empty+ ContinueStmt _ _ -> empty+ LabelledStmt _ _ s -> stmt s+ ForInStmt _ fii e s -> unions [forInInit fii, expr e, stmt s]+ ForStmt _ fi me1 me2 s -> + unions [forInit fi, maybe empty expr me1, maybe empty expr me2, stmt s]+ TryStmt _ s mcatch ms ->+ unions [stmt s, maybe empty catchClause mcatch, maybe empty stmt ms]+ ThrowStmt _ e -> expr e+ ReturnStmt _ me -> maybe empty expr me+ WithStmt _ e s -> unions [expr e, stmt s]+ VarDeclStmt _ decls -> unions $ map varDecl decls+ FunctionStmt _ fnId args ss ->+ unions [decl fnId, nest $ unions [unions $ map decl args,+ unions $ map stmt ss]]++-- |The statically-determinate lexical structure of a JavaScript program.+data EnvTree = EnvTree (M.Map String SourcePos) [EnvTree]++-- A 'Partial' specifies identifier references in addition to identifier+-- declarations. We descend into a 'Partial', pushing enclosing declarations+-- in to remove references to identifiers declared in the enclosing scope.+-- Any referencs to identifiers not declared in either the current or the+-- enclosing scope are local definitions of global variables.+makeEnvTree :: Map String SourcePos -- ^enclosing environment+ -> Partial -- ^local environment and references+ -> (EnvTree,Map String SourcePos) + -- ^environment and global definitions+makeEnvTree enclosing (Partial locals references nested) = (tree,globals) where+ nestedResults = map (makeEnvTree (locals `M.union` enclosing)) nested+ tree = EnvTree locals (map fst nestedResults)+ globals' = (references `M.difference` locals) `M.difference` enclosing+ globals = M.unions (globals':map snd nestedResults)++env :: Map String SourcePos -- ^browser/testing environment+ -> [Statement SourcePos] + -> (EnvTree,Map String SourcePos)+env globals program = makeEnvTree globals (unions $ map stmt program)+++localVars :: [Statement SourcePos]+ -> [(String, SourcePos)]+localVars body = M.toList locals where+ Partial locals _ _ = unions $ map stmt body+
+ test/TestMain.hs view
@@ -0,0 +1,3 @@+module Main where++main = return ()