packages feed

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 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 ()